u32_t u32;
message m;
- r= ds_retrieve_u32("amddev", &u32);
+ r= ds_retrieve_label_num("amddev", &u32);
if (r != OK)
{
#if 0
- printf("tell_dev: ds_retrieve_u32 failed for 'amddev': %d\n",
+ printf("tell_dev: ds_retrieve_label_num failed for 'amddev': %d\n",
r);
#endif
return;
memset(e1000_table, 0, sizeof(e1000_table));
/* Perform calibration. */
- if((r = micro_delay_calibrate()) != OK)
+ if((r = tsc_calibrate()) != OK)
{
- panic("e1000", "rmicro_delay_calibrate failed", r);
+ panic("e1000", "tsc_calibrate failed", r);
}
/* Try to notify inet that we are present (again) */
if ((r = ds_retrieve_u32("inet", &tasknr)) == OK)
memset(fxp_table, 0, ft);
- if((r=micro_delay_calibrate()) != OK)
- panic("FXP","rmicro_delay_calibrate failed", r);
+ if((r=tsc_calibrate()) != OK)
+ panic("FXP","tsc_calibrate failed", r);
/* Try to notify inet that we are present (again) */
- r= ds_retrieve_u32("inet", &tasknr);
+ r= ds_retrieve_label_num("inet", &tasknr);
if (r == OK)
notify(tasknr);
else if (r != ESRCH)
- printf("fxp: ds_retrieve_u32 failed for 'inet': %d\n", r);
+ printf("fxp: ds_retrieve_label_num failed for 'inet': %d\n", r);
return(OK);
}
u32_t u32;
message m;
- r= ds_retrieve_u32("amddev", &u32);
+ r= ds_retrieve_label_num("amddev", &u32);
if (r != OK)
{
#if 0
printf(
- "fxp`tell_dev: ds_retrieve_u32 failed for 'amddev': %d\n",
+ "fxp`tell_dev: ds_retrieve_label_num failed for 'amddev': %d\n",
r);
#endif
return;
/* Try to notify INET that we are present (again). If INET cannot
* be found, assume this is the first time we started and INET is
* not yet alive. */
- r = ds_retrieve_u32("inet", &inet_proc_nr);
+ r = ds_retrieve_label_num("inet", &inet_proc_nr);
if (r == OK)
notify(inet_proc_nr);
else if (r != ESRCH)
- printf("orinoco: ds_retrieve_u32 failed for 'inet': %d\n", r);
+ printf("orinoco: ds_retrieve_label_num failed for 'inet': %d\n", r);
return(OK);
}
* be found, assume this is the first time we started and INET is
* not yet alive.
*/
- r= ds_retrieve_u32("inet", &inet_proc_nr);
+ r= ds_retrieve_label_num("inet", &inet_proc_nr);
if (r == OK)
notify(inet_proc_nr);
else if (r != ESRCH)
- printf("rtl8139: ds_retrieve_u32 failed for 'inet': %d\n", r);
+ printf("rtl8139: ds_retrieve_label_num failed for 'inet': %d\n", r);
return(OK);
}
u32_t u32;
message m;
- r= ds_retrieve_u32("amddev", &u32);
+ r= ds_retrieve_label_num("amddev", &u32);
if (r != OK)
{
#if 0
printf(
- "rtl8139`tell_dev: ds_retrieve_u32 failed for 'amddev': %d\n",
+ "rtl8139`tell_dev: ds_retrieve_label_num failed for 'amddev': %d\n",
r);
#endif
return;
(progname=strrchr(env_argv[0],'/')) ? progname++
: (progname=env_argv[0]);
- if((r=micro_delay_calibrate()) != OK)
- panic("ti1225", "micro_delay_calibrate failed", r);
+ if((r=tsc_calibrate()) != OK)
+ panic("ti1225", "tsc_calibrate failed", r);
debug= 0;
while (c= getopt(env_argc, env_argv, "d?"), c != -1)
# define SYS_VTIMER (KERNEL_CALL + 45) /* sys_vtimer() */
# define SYS_RUNCTL (KERNEL_CALL + 46) /* sys_runctl() */
+# define SYS_SAFEMAP (KERNEL_CALL + 47) /* sys_safemap() */
+# define SYS_SAFEREVMAP (KERNEL_CALL + 48) /* sys_saferevmap() sys_saferevmap2() */
+# define SYS_SAFEUNMAP (KERNEL_CALL + 49) /* sys_safeunmap() */
-#define NR_SYS_CALLS 47 /* number of system calls */
+#define NR_SYS_CALLS 50 /* number of system calls */
#define SYS_CALL_MASK_SIZE BITMAP_CHUNKS(NR_SYS_CALLS)
/* Field names for SYS_MEMSET. */
#define VSCP_VEC_ADDR m2_p1 /* start of vector */
#define VSCP_VEC_SIZE m2_l2 /* elements in vector */
+/* Field names for SYS_SAFEMAPs */
+#define SMAP_EP m2_i1
+#define SMAP_GID m2_i2
+#define SMAP_OFFSET m2_i3
+#define SMAP_SEG m2_p1
+#define SMAP_ADDRESS m2_l1
+#define SMAP_BYTES m2_l2
+#define SMAP_FLAG m2_s1
+
/* Field names for SYS_SPROF, _CPROF, _PROFBUF. */
#define PROF_ACTION m7_i1 /* start/stop/reset/get */
#define PROF_MEM_SIZE m7_i2 /* available memory for data */
#define SVMCTL_PF_WHO m1_i1 /* GET_PAGEFAULT reply: process ep */
#define SVMCTL_PF_I386_CR2 m1_i2 /* GET_PAGEFAULT reply: CR2 */
#define SVMCTL_PF_I386_ERR m1_i3 /* GET_PAGEFAULT reply: error code */
-#define SVMCTL_MRG_ADDR m1_p1 /* MEMREQ_GET reply: address */
-#define SVMCTL_MRG_LEN m1_i1 /* MEMREQ_GET reply: length */
-#define SVMCTL_MRG_WRITE m1_i2 /* MEMREQ_GET reply: writeflag */
-#define SVMCTL_MRG_EP m1_i3 /* MEMREQ_GET reply: process */
-#define SVMCTL_MRG_REQUESTOR m1_p2 /* MEMREQ_GET reply: requestor */
+#define SVMCTL_MRG_TARGET m2_i1 /* MEMREQ_GET reply: target process */
+#define SVMCTL_MRG_ADDR m2_i2 /* MEMREQ_GET reply: address */
+#define SVMCTL_MRG_LENGTH m2_i3 /* MEMREQ_GET reply: length */
+#define SVMCTL_MRG_FLAG m2_s1 /* MEMREQ_GET reply: flag */
+#define SVMCTL_MRG_EP2 m2_l1 /* MEMREQ_GET reply: source process */
+#define SVMCTL_MRG_ADDR2 m2_l2 /* MEMREQ_GET reply: source address */
+#define SVMCTL_MRG_REQUESTOR m2_p1 /* MEMREQ_GET reply: requestor */
#define SVMCTL_MAP_VIR_ADDR m1_p1
/* Reply message for VMCTL_KERN_PHYSMAP */
#define DS_RQ_BASE 0x800
-#define DS_PUBLISH (DS_RQ_BASE + 0) /* publish information */
-#define DS_SUBSCRIBE (DS_RQ_BASE + 1) /* subscribe to information */
-#define DS_RETRIEVE (DS_RQ_BASE + 2) /* retrieve information by name */
-#define DS_CHECK (DS_RQ_BASE + 3) /* retrieve updated information */
-
-/* DS field names: DS_SUBSCRIBE, DS_PUBLISH, DS_RETRIEVE */
-# define DS_KEY_GRANT m2_p1 /* key for the information */
-# define DS_KEY_LEN m2_i1 /* length of key incl. '\0' */
+#define DS_PUBLISH (DS_RQ_BASE + 0) /* publish data */
+#define DS_RETRIEVE (DS_RQ_BASE + 1) /* retrieve data by name */
+#define DS_SUBSCRIBE (DS_RQ_BASE + 2) /* subscribe to data updates */
+#define DS_CHECK (DS_RQ_BASE + 3) /* retrieve updated data */
+#define DS_DELETE (DS_RQ_BASE + 4) /* delete data */
+#define DS_SNAPSHOT (DS_RQ_BASE + 5) /* take a snapshot */
+#define DS_RETRIEVE_LABEL (DS_RQ_BASE + 6) /* retrieve label's name */
+
+/* DS field names */
+# define DS_KEY_GRANT m2_i1 /* key for the data */
+# define DS_KEY_LEN m2_s1 /* length of key incl. '\0' */
# define DS_FLAGS m2_i2 /* flags provided by caller */
-/* DS_PUBLISH, DS_RETRIEVE */
# define DS_VAL m2_l1 /* data (u32, char *, etc.) */
# define DS_VAL_LEN m2_l2 /* data length */
+# define DS_NR_SNAPSHOT m2_i3 /* number of snapshot */
+# define DS_STRING m2_i3 /* inline string */
/*===========================================================================*
* Miscellaneous messages used by TTY *
#define CLICK_SHIFT 12 /* log2 of CLICK_SIZE */
#endif
+/* Click alignment macros. */
+#define CLICK_FLOOR(n) (((vir_bytes)(n) / CLICK_SIZE) * CLICK_SIZE)
+#define CLICK_CEIL(n) CLICK_FLOOR((vir_bytes)(n) + CLICK_SIZE-1)
+
/* Sizes of memory tables. The boot monitor distinguishes three memory areas,
* namely low mem below 1M, 1M-16M, and mem after 16M. More chunks are needed
* for DOS MINIX.
#include <minix/types.h>
-/* DS Flag values. */
-#define DS_IN_USE 0x0001 /* Internal use only. */
-#define DS_PUBLIC 0x0002 /* Publically retrievable value. */
-#define DS_INITIAL 0x0004 /* On subscription, send initial contents. */
+/* Flags. */
+#define DSF_IN_USE 0x001 /* entry is in use */
+#define DSF_PRIV_RETRIEVE 0x002 /* only owner can retrieve */
+#define DSF_PRIV_OVERWRITE 0x004 /* only owner can overwrite */
+#define DSF_PRIV_SNAPSHOT 0x004 /* only owner can take a snapshot */
+#define DSF_PRIV_SUBSCRIBE 0x008 /* only owner can subscribe */
+#define DSF_TYPE_U32 0x010 /* u32 data type */
+#define DSF_TYPE_STR 0x020 /* string data type */
+#define DSF_TYPE_MEM 0x040 /* memory range data type */
+#define DSF_TYPE_MAP 0x080 /* mapped memory range data type */
+#define DSF_TYPE_LABEL 0x100 /* label data type */
-/* These type flags are mutually exclusive. Give as args to ds_subscribe. */
-#define DS_TYPE_U32 0x0100
-#define DS_TYPE_STR 0x0200
-#define DS_TYPE_MASK 0xff00 /* All type info. */
+#define DSF_MASK_TYPE 0xFF0 /* mask for type flags. */
+#define DSF_MASK_INTERNAL 0xFFF /* mask for internal flags. */
+
+#define DSF_OVERWRITE 0x01000 /* overwrite if entry exists */
+#define DSF_INITIAL 0x02000 /* check subscriptions immediately */
+
+#define DSMF_MAP_MAPPED 0x10000 /* map mapped memory range */
+#define DSMF_COPY_MAPPED 0x20000 /* copy mapped memory range */
+#define DSMF_COPY_SNAPSHOT 0x40000 /* copy snapshot */
/* DS constants. */
-#define DS_MAX_KEYLEN 80 /* Max length for a key, including '\0'. */
-#define DS_MAX_VALLEN 100 /* Max legnth for a str value, incl '\0'. */
+#define DS_MAX_KEYLEN 80 /* Max length of a key, including '\0'. */
+#define DS_MAX_STRLEN 16 /* Max length of string, including '\0'. */
/* ds.c */
-_PROTOTYPE( int ds_subscribe, (char *name_regexp, int type, int flags));
-/* publish/update item */
-_PROTOTYPE( int ds_publish_u32, (char *name, u32_t val));
-_PROTOTYPE( int ds_publish_str, (char *name, char *val));
+/* U32 */
+_PROTOTYPE( int ds_publish_u32, (const char *name, u32_t val, int flags));
+_PROTOTYPE( int ds_retrieve_u32, (const char *name, u32_t *val));
+_PROTOTYPE( int ds_delete_u32, (const char *ds_name));
+
+/* STRING */
+_PROTOTYPE( int ds_publish_str, (const char *name, char *val, int flags));
+_PROTOTYPE( int ds_retrieve_str, (const char *name, char *val, size_t len));
+_PROTOTYPE( int ds_delete_str, (const char *ds_name));
+
+/* MEM */
+_PROTOTYPE( int ds_publish_mem, (const char *ds_name, void *vaddr,
+ size_t length, int flags));
+_PROTOTYPE( int ds_retrieve_mem, (const char *ds_name, char *vaddr,
+ size_t *length));
+_PROTOTYPE( int ds_delete_mem, (const char *ds_name));
+
+/* MAP */
+_PROTOTYPE( int ds_publish_map, (const char *ds_name, void *vaddr,
+ size_t length, int flags));
+_PROTOTYPE( int ds_snapshot_map, (const char *ds_name, int *nr_snapshot));
+_PROTOTYPE( int ds_retrieve_map, (const char *ds_name, char *vaddr,
+ size_t *length, int nr_snapshot, int flags));
+_PROTOTYPE( int ds_delete_map, (const char *ds_name));
-/* retrieve item by name + type */
-_PROTOTYPE( int ds_retrieve_u32, (char *name, u32_t *val) );
-_PROTOTYPE( int ds_retrieve_str, (char *name, char *val, size_t len));
+/* LABEL */
+_PROTOTYPE( int ds_publish_label, (const char *ds_name, u32_t value,int flags));
+_PROTOTYPE( int ds_retrieve_label_name, (char *ds_name, u32_t num));
+_PROTOTYPE( int ds_retrieve_label_num, (const char *ds_name, u32_t *value));
+_PROTOTYPE( int ds_delete_label, (const char *ds_name));
-/* retrieve updates for item */
-_PROTOTYPE( int ds_check_u32, (char *n, size_t namelen, u32_t *val));
-_PROTOTYPE( int ds_check_str, (char *n, size_t namelen, char *v, size_t vlen));
+/* Subscribe and check. */
+_PROTOTYPE( int ds_subscribe, (const char *regex, int flags));
+_PROTOTYPE( int ds_check, (char *ds_name, int *type));
#endif /* _MINIX_DS_H */
size_t v_bytes; /* no. of bytes */
};
+/* Types on VM invocation. */
+#define VMPTYPE_NONE 0
+#define VMPTYPE_CHECK 1
+#define VMPTYPE_COWMAP 2
+#define VMPTYPE_SMAP 3
+#define VMPTYPE_SUNMAP 4
+
/* Invalid grant number. */
#define GRANT_INVALID -1
#define GRANT_VALID(g) ((g) > GRANT_INVALID)
/* Operations: any combination is ok. */
#define CPF_READ 0x000001 /* Granted process may read. */
#define CPF_WRITE 0x000002 /* Granted process may write. */
+#define CPF_MAP 0x000004 /* Granted process may map. */
/* Internal flags. */
#define CPF_USED 0x000100 /* Grant slot in use. */
_PROTOTYPE( int sys_vmctl_get_pagefault_i386, (endpoint_t *who, u32_t *cr2, u32_t *err));
_PROTOTYPE( int sys_vmctl_get_cr3_i386, (endpoint_t who, u32_t *cr3) );
_PROTOTYPE( int sys_vmctl_get_memreq, (endpoint_t *who, vir_bytes *mem,
- vir_bytes *len, int *wrflag, endpoint_t *) );
+ vir_bytes *len, int *wrflag, endpoint_t *who_s, vir_bytes *mem_s,
+ endpoint_t *) );
_PROTOTYPE( int sys_vmctl_enable_paging, (struct mem_map *));
_PROTOTYPE( int sys_readbios, (phys_bytes address, void *buf, size_t size));
_PROTOTYPE(int sys_memset, (unsigned long pattern,
phys_bytes base, phys_bytes bytes));
+/* Grant-based map functions. */
+_PROTOTYPE(int sys_safemap, (endpoint_t grantor, cp_grant_id_t grant,
+ vir_bytes grant_offset, vir_bytes my_address, size_t bytes, int my_seg,
+ int writable));
+_PROTOTYPE(int sys_saferevmap_gid, (cp_grant_id_t grant));
+_PROTOTYPE(int sys_saferevmap_addr, (vir_bytes addr));
+_PROTOTYPE(int sys_safeunmap, (int my_seg, vir_bytes my_address));
+
_PROTOTYPE(int sys_umap, (endpoint_t proc_ep, int seg, vir_bytes vir_addr,
vir_bytes bytes, phys_bytes *phys_addr));
_PROTOTYPE(int sys_umap_data_fb, (endpoint_t proc_ep, vir_bytes vir_addr,
_PROTOTYPE( int getuptime, (clock_t *ticks));
_PROTOTYPE( int getuptime2, (clock_t *ticks, time_t *boottime));
_PROTOTYPE( int tickdelay, (clock_t ticks));
-_PROTOTYPE( int micro_delay_calibrate, (void));
+_PROTOTYPE( int tsc_calibrate, (void));
_PROTOTYPE( u32_t sys_hz, (void));
_PROTOTYPE( double getidle, (void));
_PROTOTYPE( void util_stacktrace, (void));
_PROTOTYPE( void util_nstrcat, (char *str, unsigned long n) );
_PROTOTYPE( void util_stacktrace_strcat, (char *));
_PROTOTYPE( int micro_delay, (u32_t micros));
+_PROTOTYPE( u32_t tsc_64_to_micros, (u64_t tsc));
+_PROTOTYPE( u32_t tsc_to_micros, (u32_t low, u32_t high));
_PROTOTYPE( u32_t micros_to_ticks, (u32_t micros));
_PROTOTYPE( void ser_putc, (char c));
_PROTOTYPE( void get_randomness, (struct k_randomness *, int));
#define SI_PROC_TAB 2 /* copy of entire process table */
#define SI_DMAP_TAB 3 /* get device <-> driver mappings */
#define SI_MEM_ALLOC 4 /* get memory allocation data */
-#define SI_DATA_STORE 5 /* get copy of data store */
-#define SI_LOADINFO 6 /* get copy of load average structure */
-#define SI_KPROC_TAB 7 /* copy of kernel process table */
-#define SI_CALL_STATS 8 /* system call statistics */
-#define SI_PCI_INFO 9 /* get kernel info via PM */
-#define SI_PROCPUB_TAB 10 /* copy of public entries of process table */
+#define SI_DATA_STORE 5 /* get copy of data store mappings */
+#define SI_SUBSCRIPTION 6 /* get copy of data store subscriptions */
+#define SI_LOADINFO 7 /* get copy of load average structure */
+#define SI_KPROC_TAB 8 /* copy of kernel process table */
+#define SI_CALL_STATS 9 /* system call statistics */
+#define SI_PCI_INFO 10 /* get kernel info via PM */
+#define SI_PROCPUB_TAB 11 /* copy of public entries of process table */
/* NULL must be defined in <unistd.h> according to POSIX Sec. 2.7.1. */
#define NULL ((void *)0)
util_stacktrace_strcat(caller->p_vmrequest.stacktrace);
#endif
- caller->p_vmrequest.writeflag = 1;
- caller->p_vmrequest.start = linaddr;
- caller->p_vmrequest.length = len;
- caller->p_vmrequest.who = target->p_endpoint;
+ caller->p_vmrequest.req_type = VMPTYPE_CHECK;
+ caller->p_vmrequest.target = target->p_endpoint;
+ caller->p_vmrequest.params.check.start = linaddr;
+ caller->p_vmrequest.params.check.length = len;
+ caller->p_vmrequest.params.check.writeflag = 1;
caller->p_vmrequest.type = type;
/* Connect caller on vmrequest wait queue. */
/* Click-round kernel. */
if(kinfo.data_base % CLICK_SIZE)
minix_panic("kinfo.data_base not aligned", NO_NUM);
- kinfo.data_size = ((kinfo.data_size+CLICK_SIZE-1)/CLICK_SIZE) * CLICK_SIZE;
-
- /* Click-round kernel. */
- if(kinfo.data_base % CLICK_SIZE)
- minix_panic("kinfo.data_base not aligned", NO_NUM);
- kinfo.data_size = ((kinfo.data_size+CLICK_SIZE-1)/CLICK_SIZE) * CLICK_SIZE;
+ kinfo.data_size = (phys_bytes) (CLICK_CEIL(kinfo.data_size));
/* Build gdt and idt pointers in GDT where the BIOS expects them. */
dtp= (struct desctableptr_s *) &gdt[GDT_INDEX];
/* Convert addresses to clicks and build process memory map */
text_base = e_hdr.a_syms >> CLICK_SHIFT;
- text_clicks = (e_hdr.a_text + CLICK_SIZE-1) >> CLICK_SHIFT;
- data_clicks = (e_hdr.a_data+e_hdr.a_bss + CLICK_SIZE-1) >> CLICK_SHIFT;
- st_clicks= (e_hdr.a_total + CLICK_SIZE-1) >> CLICK_SHIFT;
+ text_clicks = (vir_clicks) (CLICK_CEIL(e_hdr.a_text) >> CLICK_SHIFT);
+ data_clicks = (vir_clicks) (CLICK_CEIL(e_hdr.a_data
+ + e_hdr.a_bss) >> CLICK_SHIFT);
+ st_clicks = (vir_clicks) (CLICK_CEIL(e_hdr.a_total) >> CLICK_SHIFT);
if (!(e_hdr.a_flags & A_SEP))
{
- data_clicks= (e_hdr.a_text+e_hdr.a_data+e_hdr.a_bss +
- CLICK_SIZE-1) >> CLICK_SHIFT;
+ data_clicks = (vir_clicks) (CLICK_CEIL(e_hdr.a_text +
+ e_hdr.a_data + e_hdr.a_bss) >> CLICK_SHIFT);
text_clicks = 0; /* common I&D */
}
rp->p_memmap[T].mem_phys = text_base;
* memory that isn't present, VM has to fix it. Until it has asked
* what needs to be done and fixed it, save necessary state here.
*
- * The requester gets a copy of its request message in reqmsg and gets
+ * The requestor gets a copy of its request message in reqmsg and gets
* VMREQUEST set.
*/
struct {
#define VMSTYPE_SYS_NONE 0
#define VMSTYPE_KERNELCALL 1
#define VMSTYPE_DELIVERMSG 2
+#define VMSTYPE_MAP 3
+
int type; /* suspended operation */
union {
/* VMSTYPE_SYS_MESSAGE */
} saved;
/* Parameters of request to VM */
- vir_bytes start, length; /* memory range */
- u8_t writeflag; /* nonzero for write access */
- endpoint_t who;
-
+ int req_type;
+ endpoint_t target;
+ union {
+ struct {
+ vir_bytes start, length; /* memory range */
+ u8_t writeflag; /* nonzero for write access */
+ } check;
+ struct {
+ char writeflag;
+ endpoint_t ep_s;
+ vir_bytes vir_s, vir_d;
+ vir_bytes length;
+ } map;
+ } params;
/* VM result when available */
int vmresult;
_PROTOTYPE( char *rtsflagstr, (int flags) );
_PROTOTYPE( char *miscflagstr, (int flags) );
+/* system/do_safemap.c */
+_PROTOTYPE( int map_invoke_vm, (int req_type,
+ endpoint_t end_d, int seg_d, vir_bytes off_d,
+ endpoint_t end_s, int seg_s, vir_bytes off_s,
+ size_t size, int flag));
+
/* system/do_safecopy.c */
_PROTOTYPE( int verify_grant, (endpoint_t, endpoint_t, cp_grant_id_t, vir_bytes,
int, vir_bytes, vir_bytes *, endpoint_t *));
map(SYS_SAFECOPYTO, do_safecopy); /* copy with pre-granted permission */
map(SYS_VSAFECOPY, do_vsafecopy); /* vectored safecopy */
+ /* Mapping. */
+ map(SYS_SAFEMAP, do_safemap); /* map pages from other process */
+ map(SYS_SAFEREVMAP, do_saferevmap); /* grantor revokes the map grant */
+ map(SYS_SAFEUNMAP, do_safeunmap); /* requestor unmaps the mapped pages */
+
/* Clock functionality. */
map(SYS_TIMES, do_times); /* get uptime and process times */
map(SYS_SETALARM, do_setalarm); /* schedule a synchronous alarm */
}
rc->p_priv = sp; /* assign new slot */
rc->p_priv->s_proc_nr = proc_nr(rc); /* set association */
-
- /* Clear some fields */
- sp->s_asyntab= -1;
- sp->s_asynsize= 0;
return(OK);
}
if (priv(rc)->s_flags & SYS_PROC)
{
if (priv(rc)->s_asynsize) {
+#if 0
kprintf("clear_endpoint: clearing s_asynsize of %s / %d\n",
rc->p_name, rc->p_endpoint);
proc_stacktrace(rc);
+#endif
}
priv(rc)->s_asynsize= 0;
}
_PROTOTYPE( int do_readbios, (message *m_ptr) );
_PROTOTYPE( int do_mapdma, (message *m_ptr) );
+_PROTOTYPE( int do_safemap, (message *m_ptr) );
+_PROTOTYPE( int do_saferevmap, (message *m_ptr) );
+_PROTOTYPE( int do_safeunmap, (message *m_ptr) );
+
_PROTOTYPE( int do_sprofile, (message *m_ptr) );
#if ! SPROFILE
#define do_sprofile do_unused
$(SYSTEM)(do_privctl.o) \
$(SYSTEM)(do_segctl.o) \
$(SYSTEM)(do_safecopy.o) \
+ $(SYSTEM)(do_safemap.o) \
$(SYSTEM)(do_sysctl.o) \
$(SYSTEM)(do_getksig.o) \
$(SYSTEM)(do_endksig.o) \
$(SYSTEM)(do_safecopy.o): do_safecopy.c
$(CC) do_safecopy.c
+$(SYSTEM)(do_safemap.o): do_safemap.c
+ $(CC) do_safemap.c
+
$(SYSTEM)(do_sysctl.o): do_sysctl.c
$(CC) do_sysctl.c
return EINVAL;
}
- /* memory becomes readonly */
- if (priv(rpp)->s_asynsize > 0) {
- printf("kernel: process with waiting asynsend table can't fork\n");
- return EINVAL;
- }
-
map_ptr= (struct mem_map *) m_ptr->PR_MEM_PTR;
/* Copy parent 'proc' struct to child. And reinitialize some fields. */
priv(rp)->s_notify_pending.chunk[i] = 0; /* - notifications */
priv(rp)->s_int_pending = 0; /* - interrupts */
sigemptyset(&priv(rp)->s_sig_pending); /* - signals */
+ priv(rp)->s_asyntab= -1; /* - asynsends */
+ priv(rp)->s_asynsize= 0;
/* Set defaults for privilege bitmaps. */
priv(rp)->s_flags= DEF_SYS_F; /* privilege flags */
#define MEM_TOP 0xFFFFFFFFUL
+#define USE_COW_SAFECOPY 0
+
FORWARD _PROTOTYPE(int safecopy, (endpoint_t, endpoint_t, cp_grant_id_t, int, int, size_t, vir_bytes, vir_bytes, int));
#define HASGRANTTABLE(gr) \
{
static struct vir_addr v_src, v_dst;
static vir_bytes v_offset;
- int r;
endpoint_t new_granter, *src, *dst;
struct proc *granter_p;
+ vir_bytes size;
+ int r;
/* See if there is a reasonable grant table. */
if(!(granter_p = endpoint_lookup(granter))) return EINVAL;
}
/* Do the regular copy. */
- return virtual_copy_vmcheck(&v_src, &v_dst, bytes);
+#if USE_COW_SAFECOPY
+ if(v_offset % CLICK_SIZE != addr % CLICK_SIZE || bytes < CLICK_SIZE) {
+ /* Give up on COW immediately when offsets are not aligned
+ * or we are copying less than a page.
+ */
+ return virtual_copy_vmcheck(&v_src, &v_dst, bytes);
+ }
+ if((size = v_offset % CLICK_SIZE) != 0) {
+ /* Normal copy for everything before the first page boundary. */
+ size = CLICK_SIZE - size;
+ r = virtual_copy_vmcheck(&v_src, &v_dst, size);
+ if(r != OK)
+ return r;
+ v_src.offset += size;
+ v_dst.offset += size;
+ bytes -= size;
+ }
+ if((size = bytes / CLICK_SIZE) != 0) {
+ /* Use COW optimization when copying entire pages. */
+ size *= CLICK_SIZE;
+ r = map_invoke_vm(VMPTYPE_COWMAP,
+ v_dst.proc_nr_e, v_dst.segment, v_dst.offset,
+ v_src.proc_nr_e, v_src.segment, v_src.offset,
+ size, 0);
+ if(r != OK)
+ return r;
+ v_src.offset += size;
+ v_dst.offset += size;
+ bytes -= size;
+ }
+ if(bytes != 0) {
+ /* Normal copy for everything after the last page boundary. */
+ r = virtual_copy_vmcheck(&v_src, &v_dst, bytes);
+ if(r != OK)
+ return r;
+ }
+
+ return OK;
+#else
+ return virtual_copy_vmcheck(&v_src, &v_dst, bytes);
+#endif
}
/*===========================================================================*
--- /dev/null
+/* The kernel call implemented in this file:
+ * m_type: SYS_SAFEMAP or SYS_SAFEREVMAP or SYS_SAFEUNMAP
+ *
+ * The parameters for this kernel call are:
+ * SMAP_EP endpoint of the grantor
+ * SMAP_GID grant id
+ * SMAP_OFFSET offset of the grant space
+ * SMAP_SEG segment
+ * SMAP_ADDRESS address
+ * SMAP_BYTES bytes to be copied
+ * SMAP_FLAG access, writable map or not?
+ */
+
+#include <minix/type.h>
+#include <minix/safecopies.h>
+
+#include "../system.h"
+#include "../vm.h"
+
+
+struct map_info_s {
+ int flag;
+
+ /* Grantor. */
+ endpoint_t grantor;
+ int gid;
+ vir_bytes offset;
+ vir_bytes address_Dseg; /* seg always is D */
+
+ /* Grantee. */
+ endpoint_t grantee;
+ int seg;
+ vir_bytes address;
+
+ /* Length. */
+ vir_bytes bytes;
+};
+
+#define MAX_MAP_INFO 20
+static struct map_info_s map_info[MAX_MAP_INFO];
+
+/*===========================================================================*
+ * add_info *
+ *===========================================================================*/
+static int add_info(endpoint_t grantor, endpoint_t grantee, int gid,
+ vir_bytes offset, vir_bytes address_Dseg,
+ int seg, vir_bytes address, vir_bytes bytes)
+{
+ int i;
+
+ for(i = 0; i < MAX_MAP_INFO; i++) {
+ if(map_info[i].flag == 0)
+ break;
+ }
+ if(i == MAX_MAP_INFO)
+ return EBUSY;
+
+ map_info[i].flag = 1;
+ map_info[i].grantor = grantor;
+ map_info[i].grantee = grantee;
+ map_info[i].gid = gid;
+ map_info[i].address_Dseg = address_Dseg;
+ map_info[i].offset = offset;
+ map_info[i].seg = seg;
+ map_info[i].address = address;
+ map_info[i].bytes = bytes;
+
+ return OK;
+}
+
+/*===========================================================================*
+ * get_revoke_info *
+ *===========================================================================*/
+static struct map_info_s *get_revoke_info(endpoint_t grantor, int flag, int arg)
+{
+ int i;
+ for(i = 0; i < MAX_MAP_INFO; i++) {
+ if(map_info[i].flag == 1
+ && map_info[i].grantor == grantor
+ && (flag ? (map_info[i].gid == arg)
+ : (map_info[i].address_Dseg == arg)))
+ return &map_info[i];
+ }
+
+ return NULL;
+}
+
+/*===========================================================================*
+ * get_unmap_info *
+ *===========================================================================*/
+static struct map_info_s *get_unmap_info(endpoint_t grantee, int seg,
+ vir_bytes address)
+{
+ int i;
+ for(i = 0; i < MAX_MAP_INFO; i++) {
+ if(map_info[i].flag == 1
+ && map_info[i].grantee == grantee
+ && map_info[i].seg == seg
+ && map_info[i].address == address)
+ return &map_info[i];
+ }
+
+ return NULL;
+}
+
+/*===========================================================================*
+ * clear_info *
+ *===========================================================================*/
+static int clear_info(struct map_info_s *p)
+{
+ p->flag = 0;
+
+ return 0;
+}
+
+/*===========================================================================*
+ * map_invoke_vm *
+ *===========================================================================*/
+PUBLIC int map_invoke_vm(int req_type, /* VMPTYPE_... COWMAP, SMAP, SUNMAP */
+ endpoint_t end_d, int seg_d, vir_bytes off_d,
+ endpoint_t end_s, int seg_s, vir_bytes off_s,
+ size_t size, int flag)
+{
+ struct proc *caller, *src, *dst;
+ vir_bytes lin_src, lin_dst;
+
+ src = endpoint_lookup(end_s);
+ dst = endpoint_lookup(end_d);
+ caller = endpoint_lookup(who_e);
+
+ lin_src = umap_local(src, seg_s, off_s, size);
+ lin_dst = umap_local(dst, seg_d, off_d, size);
+ if(lin_src == 0 || lin_dst == 0) {
+ kprintf("map_invoke_vm: error in umap_local.\n");
+ return EINVAL;
+ }
+
+ /* Make sure the linear addresses are both page aligned. */
+ if(lin_src % CLICK_SIZE != 0
+ || lin_dst % CLICK_SIZE != 0) {
+ kprintf("map_invoke_vm: linear addresses not page aligned.\n");
+ return EINVAL;
+ }
+
+ vmassert(!RTS_ISSET(caller, RTS_VMREQUEST));
+ vmassert(!RTS_ISSET(caller, RTS_VMREQTARGET));
+ vmassert(!RTS_ISSET(dst, RTS_VMREQUEST));
+ vmassert(!RTS_ISSET(dst, RTS_VMREQTARGET));
+ RTS_LOCK_SET(caller, RTS_VMREQUEST);
+ RTS_LOCK_SET(dst, RTS_VMREQTARGET);
+
+ /* Map to the destination. */
+ caller->p_vmrequest.req_type = req_type;
+ caller->p_vmrequest.target = end_d; /* destination proc */
+ caller->p_vmrequest.params.map.vir_d = lin_dst; /* destination addr */
+ caller->p_vmrequest.params.map.ep_s = end_s; /* source process */
+ caller->p_vmrequest.params.map.vir_s = lin_src; /* source address */
+ caller->p_vmrequest.params.map.length = size;
+ caller->p_vmrequest.params.map.writeflag = flag;
+
+ caller->p_vmrequest.type = VMSTYPE_MAP;
+
+ /* Connect caller on vmrequest wait queue. */
+ if(!(caller->p_vmrequest.nextrequestor = vmrequest))
+ lock_notify(SYSTEM, VM_PROC_NR);
+ vmrequest = caller;
+
+ return OK;
+}
+
+/*===========================================================================*
+ * do_safemap *
+ *===========================================================================*/
+PUBLIC int do_safemap(m_ptr)
+register message *m_ptr;
+{
+ endpoint_t grantor = m_ptr->SMAP_EP;
+ cp_grant_id_t gid = m_ptr->SMAP_GID;
+ vir_bytes offset = m_ptr->SMAP_OFFSET;
+ int seg = (int)m_ptr->SMAP_SEG;
+ vir_bytes address = m_ptr->SMAP_ADDRESS;
+ vir_bytes bytes = m_ptr->SMAP_BYTES;
+ int flag = m_ptr->SMAP_FLAG;
+
+ vir_bytes offset_result;
+ endpoint_t new_grantor;
+ int r;
+ int access = CPF_MAP | CPF_READ;
+
+ /* Check the grant. We currently support safemap with both direct and
+ * indirect grants, as verify_grant() stores the original grantor
+ * transparently in new_grantor below. However, we maintain the original
+ * semantics associated to indirect grants only here at safemap time.
+ * After the mapping has been set up, if a process part of the chain
+ * of trust crashes or exits without revoking the mapping, the mapping
+ * can no longer be manually or automatically revoked for any of the
+ * processes lower in the chain. This solution reduces complexity but
+ * could be improved if we make the assumption that only one process in
+ * the chain of trust can effectively map the original memory region.
+ */
+ if(flag != 0)
+ access |= CPF_WRITE;
+ r = verify_grant(grantor, who_e, gid, bytes, access,
+ offset, &offset_result, &new_grantor);
+ if(r != OK) {
+ kprintf("verify_grant for gid %d from %d to %d failed: %d\n",
+ gid, grantor, who_e, r);
+ return r;
+ }
+
+ /* Add map info. */
+ r = add_info(new_grantor, who_e, gid, offset, offset_result, seg,
+ address, bytes);
+ if(r != OK)
+ return r;
+
+ /* Invoke VM. */
+ return map_invoke_vm(VMPTYPE_SMAP,
+ who_e, seg, address, new_grantor, D, offset_result, bytes,flag);
+}
+
+/*===========================================================================*
+ * safeunmap *
+ *===========================================================================*/
+PRIVATE int safeunmap(struct map_info_s *p)
+{
+ vir_bytes offset_result;
+ endpoint_t new_grantor;
+ int r;
+
+ r = verify_grant(p->grantor, p->grantee, p->gid, p->bytes, CPF_MAP,
+ p->offset, &offset_result, &new_grantor);
+ if(r != OK) {
+ kprintf("safeunmap: error in verify_grant.\n");
+ return r;
+ }
+
+ r = map_invoke_vm(VMPTYPE_SUNMAP,
+ p->grantee, p->seg, p->address,
+ new_grantor, D, offset_result,
+ p->bytes, 0);
+ clear_info(p);
+ if(r != OK) {
+ kprintf("safeunmap: error in map_invoke_vm.\n");
+ return r;
+ }
+ return OK;
+}
+
+/*===========================================================================*
+ * do_saferevmap *
+ *===========================================================================*/
+PUBLIC int do_saferevmap(m_ptr)
+register message *m_ptr;
+{
+ struct map_info_s *p;
+ int flag = m_ptr->SMAP_FLAG;
+ int arg = m_ptr->SMAP_GID; /* gid or address_Dseg */
+ int r;
+
+ while((p = get_revoke_info(who_e, flag, arg)) != NULL) {
+ if((r = safeunmap(p)) != OK)
+ return r;
+ }
+ return OK;
+}
+
+/*===========================================================================*
+ * do_safeunmap *
+ *===========================================================================*/
+PUBLIC int do_safeunmap(m_ptr)
+register message *m_ptr;
+{
+ vir_bytes address = m_ptr->SMAP_ADDRESS;
+ int seg = (int)m_ptr->SMAP_SEG;
+ struct map_info_s *p;
+ int r;
+
+ while((p = get_unmap_info(who_e, seg, address)) != NULL) {
+ if((r = safeunmap(p)) != OK)
+ return r;
+ }
+ return OK;
+}
+
#endif
/* Reply with request fields. */
- m_ptr->SVMCTL_MRG_ADDR = (char *) rp->p_vmrequest.start;
- m_ptr->SVMCTL_MRG_LEN = rp->p_vmrequest.length;
- m_ptr->SVMCTL_MRG_WRITE = rp->p_vmrequest.writeflag;
- m_ptr->SVMCTL_MRG_EP = rp->p_vmrequest.who;
- m_ptr->SVMCTL_MRG_REQUESTOR = (void *) rp->p_endpoint;
+ switch(rp->p_vmrequest.req_type) {
+ case VMPTYPE_CHECK:
+ m_ptr->SVMCTL_MRG_TARGET =
+ rp->p_vmrequest.target;
+ m_ptr->SVMCTL_MRG_ADDR =
+ rp->p_vmrequest.params.check.start;
+ m_ptr->SVMCTL_MRG_LENGTH =
+ rp->p_vmrequest.params.check.length;
+ m_ptr->SVMCTL_MRG_FLAG =
+ rp->p_vmrequest.params.check.writeflag;
+ m_ptr->SVMCTL_MRG_REQUESTOR =
+ (void *) rp->p_endpoint;
+ break;
+ case VMPTYPE_COWMAP:
+ case VMPTYPE_SMAP:
+ case VMPTYPE_SUNMAP:
+ m_ptr->SVMCTL_MRG_TARGET =
+ rp->p_vmrequest.target;
+ m_ptr->SVMCTL_MRG_ADDR =
+ rp->p_vmrequest.params.map.vir_d;
+ m_ptr->SVMCTL_MRG_EP2 =
+ rp->p_vmrequest.params.map.ep_s;
+ m_ptr->SVMCTL_MRG_ADDR2 =
+ rp->p_vmrequest.params.map.vir_s;
+ m_ptr->SVMCTL_MRG_LENGTH =
+ rp->p_vmrequest.params.map.length;
+ m_ptr->SVMCTL_MRG_FLAG =
+ rp->p_vmrequest.params.map.writeflag;
+ m_ptr->SVMCTL_MRG_REQUESTOR =
+ (void *) rp->p_endpoint;
+ break;
+ default:
+ minix_panic("VMREQUEST wrong type", NO_NUM);
+ }
+
rp->p_vmrequest.vmresult = VMSUSPEND;
/* Remove from request chain. */
vmrequest = vmrequest->p_vmrequest.nextrequestor;
- return OK;
+ return rp->p_vmrequest.req_type;
case VMCTL_MEMREQ_REPLY:
vmassert(RTS_ISSET(p, RTS_VMREQUEST));
vmassert(p->p_vmrequest.vmresult == VMSUSPEND);
- okendpt(p->p_vmrequest.who, &proc_nr);
+ okendpt(p->p_vmrequest.target, &proc_nr);
target = proc_addr(proc_nr);
p->p_vmrequest.vmresult = m_ptr->SVMCTL_VALUE;
vmassert(p->p_vmrequest.vmresult != VMSUSPEND);
p->p_vmrequest.start + p->p_vmrequest.length,
p->p_vmrequest.writeflag, p->p_vmrequest.stacktrace);
printf("type %d\n", p->p_vmrequest.type);
+#endif
vmassert(RTS_ISSET(target, RTS_VMREQTARGET));
RTS_LOCK_UNSET(target, RTS_VMREQTARGET);
-#endif
- if(p->p_vmrequest.type == VMSTYPE_KERNELCALL) {
+ switch(p->p_vmrequest.type) {
+ case VMSTYPE_KERNELCALL:
/* Put on restart chain. */
p->p_vmrequest.nextrestart = vmrestart;
vmrestart = p;
- } else if(p->p_vmrequest.type == VMSTYPE_DELIVERMSG) {
+ break;
+ case VMSTYPE_DELIVERMSG:
vmassert(p->p_misc_flags & MF_DELIVERMSG);
vmassert(p == target);
vmassert(RTS_ISSET(p, RTS_VMREQUEST));
RTS_LOCK_UNSET(p, RTS_VMREQUEST);
- } else {
+ break;
+ case VMSTYPE_MAP:
+ vmassert(RTS_ISSET(p, RTS_VMREQUEST));
+ RTS_LOCK_UNSET(p, RTS_VMREQUEST);
+ break;
+ default:
#if DEBUG_VMASSERT
printf("suspended with stack: %s\n",
p->p_vmrequest.stacktrace);
makefiles: Makefile
Makedepend-ack Makedepend-gnu:
- sh generate.sh . obj-ack/ obj-gnu
+ sh ./generate.sh . obj-ack obj-gnu
Makefile: Makefile.in Makedepend-ack Makedepend-gnu
- sh generate.sh . obj-ack/ obj-gnu
+ sh ./generate.sh . obj-ack obj-gnu
@echo
@echo *Attention*
@echo Makefile is regenerated... rerun command to see changes
@echo
all-ack: makefiles
- mkdir -p obj-ack//./ansi
+ mkdir -p obj-ack/./ansi
cd ansi && $(MAKE) $@
- mkdir -p obj-ack//./curses
+ mkdir -p obj-ack/./curses
cd curses && $(MAKE) $@
- mkdir -p obj-ack//./dummy
+ mkdir -p obj-ack/./dummy
cd dummy && $(MAKE) $@
- mkdir -p obj-ack//./editline
+ mkdir -p obj-ack/./editline
cd editline && $(MAKE) $@
- mkdir -p obj-ack//./end
+ mkdir -p obj-ack/./end
cd end && $(MAKE) $@
- mkdir -p obj-ack//./ip
+ mkdir -p obj-ack/./ip
cd ip && $(MAKE) $@
- mkdir -p obj-ack//./math
+ mkdir -p obj-ack/./math
cd math && $(MAKE) $@
- mkdir -p obj-ack//./other
+ mkdir -p obj-ack/./other
cd other && $(MAKE) $@
- mkdir -p obj-ack//./posix
+ mkdir -p obj-ack/./posix
cd posix && $(MAKE) $@
- mkdir -p obj-ack//./regex
+ mkdir -p obj-ack/./regex
cd regex && $(MAKE) $@
- mkdir -p obj-ack//./stdio
+ mkdir -p obj-ack/./stdio
cd stdio && $(MAKE) $@
- mkdir -p obj-ack//./stdtime
+ mkdir -p obj-ack/./stdtime
cd stdtime && $(MAKE) $@
- mkdir -p obj-ack//./syscall
+ mkdir -p obj-ack/./syscall
cd syscall && $(MAKE) $@
- mkdir -p obj-ack//./syslib
+ mkdir -p obj-ack/./syslib
cd syslib && $(MAKE) $@
- mkdir -p obj-ack//./util
+ mkdir -p obj-ack/./util
cd util && $(MAKE) $@
- mkdir -p obj-ack//./sysutil
+ mkdir -p obj-ack/./sysutil
cd sysutil && $(MAKE) $@
- mkdir -p obj-ack//./sysvipc
+ mkdir -p obj-ack/./sysvipc
cd sysvipc && $(MAKE) $@
- mkdir -p obj-ack//./timers
+ mkdir -p obj-ack/./timers
cd timers && $(MAKE) $@
- mkdir -p obj-ack//./i386
+ mkdir -p obj-ack/./i386
cd i386 && $(MAKE) $@
- mkdir -p obj-ack//./ack
+ mkdir -p obj-ack/./ack
cd ack && $(MAKE) $@
- mkdir -p obj-ack//./gnu
+ mkdir -p obj-ack/./gnu
cd gnu && $(MAKE) $@
all-gnu: makefiles
makefiles: gnu/Makefile
ansi/Makefile: ansi/Makefile.in
- cd ansi && sh ../generate.sh ./ansi ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd ansi && sh .././generate.sh ./ansi ../obj-ack ../obj-gnu && $(MAKE) makefiles
curses/Makefile: curses/Makefile.in
- cd curses && sh ../generate.sh ./curses ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd curses && sh .././generate.sh ./curses ../obj-ack ../obj-gnu && $(MAKE) makefiles
dummy/Makefile: dummy/Makefile.in
- cd dummy && sh ../generate.sh ./dummy ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd dummy && sh .././generate.sh ./dummy ../obj-ack ../obj-gnu && $(MAKE) makefiles
editline/Makefile: editline/Makefile.in
- cd editline && sh ../generate.sh ./editline ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd editline && sh .././generate.sh ./editline ../obj-ack ../obj-gnu && $(MAKE) makefiles
end/Makefile: end/Makefile.in
- cd end && sh ../generate.sh ./end ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd end && sh .././generate.sh ./end ../obj-ack ../obj-gnu && $(MAKE) makefiles
ip/Makefile: ip/Makefile.in
- cd ip && sh ../generate.sh ./ip ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd ip && sh .././generate.sh ./ip ../obj-ack ../obj-gnu && $(MAKE) makefiles
math/Makefile: math/Makefile.in
- cd math && sh ../generate.sh ./math ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd math && sh .././generate.sh ./math ../obj-ack ../obj-gnu && $(MAKE) makefiles
other/Makefile: other/Makefile.in
- cd other && sh ../generate.sh ./other ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd other && sh .././generate.sh ./other ../obj-ack ../obj-gnu && $(MAKE) makefiles
posix/Makefile: posix/Makefile.in
- cd posix && sh ../generate.sh ./posix ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd posix && sh .././generate.sh ./posix ../obj-ack ../obj-gnu && $(MAKE) makefiles
regex/Makefile: regex/Makefile.in
- cd regex && sh ../generate.sh ./regex ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd regex && sh .././generate.sh ./regex ../obj-ack ../obj-gnu && $(MAKE) makefiles
stdio/Makefile: stdio/Makefile.in
- cd stdio && sh ../generate.sh ./stdio ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd stdio && sh .././generate.sh ./stdio ../obj-ack ../obj-gnu && $(MAKE) makefiles
stdtime/Makefile: stdtime/Makefile.in
- cd stdtime && sh ../generate.sh ./stdtime ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd stdtime && sh .././generate.sh ./stdtime ../obj-ack ../obj-gnu && $(MAKE) makefiles
syscall/Makefile: syscall/Makefile.in
- cd syscall && sh ../generate.sh ./syscall ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd syscall && sh .././generate.sh ./syscall ../obj-ack ../obj-gnu && $(MAKE) makefiles
syslib/Makefile: syslib/Makefile.in
- cd syslib && sh ../generate.sh ./syslib ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd syslib && sh .././generate.sh ./syslib ../obj-ack ../obj-gnu && $(MAKE) makefiles
util/Makefile: util/Makefile.in
- cd util && sh ../generate.sh ./util ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd util && sh .././generate.sh ./util ../obj-ack ../obj-gnu && $(MAKE) makefiles
sysutil/Makefile: sysutil/Makefile.in
- cd sysutil && sh ../generate.sh ./sysutil ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd sysutil && sh .././generate.sh ./sysutil ../obj-ack ../obj-gnu && $(MAKE) makefiles
sysvipc/Makefile: sysvipc/Makefile.in
- cd sysvipc && sh ../generate.sh ./sysvipc ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd sysvipc && sh .././generate.sh ./sysvipc ../obj-ack ../obj-gnu && $(MAKE) makefiles
timers/Makefile: timers/Makefile.in
- cd timers && sh ../generate.sh ./timers ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd timers && sh .././generate.sh ./timers ../obj-ack ../obj-gnu && $(MAKE) makefiles
i386/Makefile: i386/Makefile.in
- cd i386 && sh ../generate.sh ./i386 ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd i386 && sh .././generate.sh ./i386 ../obj-ack ../obj-gnu && $(MAKE) makefiles
ack/Makefile: ack/Makefile.in
- cd ack && sh ../generate.sh ./ack ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd ack && sh .././generate.sh ./ack ../obj-ack ../obj-gnu && $(MAKE) makefiles
gnu/Makefile: gnu/Makefile.in
- cd gnu && sh ../generate.sh ./gnu ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+ cd gnu && sh .././generate.sh ./gnu ../obj-ack ../obj-gnu && $(MAKE) makefiles
clean::
- rm -f obj-ack//./*
+ rm -f obj-ack/./*
rm -f obj-gnu/./*
install: install-ack
install-ack: all-ack
- cp obj-ack//*.[ao] /usr/lib/i386
+ cp obj-ack/*.[ao] /usr/lib/i386
install-gnu: all-gnu
cp obj-gnu/*.[ao] /usr/gnu/lib
sys_readbios.c \
sys_runctl.c \
sys_safecopy.c \
+ sys_safemap.c \
sys_sysctl.c \
sys_vsafecopy.c \
sys_profbuf.c \
#include "syslib.h"
-#define GRANTBAD -1001
+static message m;
-int
-ds_subscribe(ds_name_regexp, type, flags)
-char *ds_name_regexp;
-int type;
-int flags;
+PRIVATE int do_invoke_ds(int type, const char *ds_name)
{
- int r;
- message m;
- cp_grant_id_t g;
- size_t len;
-
- len = strlen(ds_name_regexp)+1;
- g = cpf_grant_direct(DS_PROC_NR,
- (vir_bytes) ds_name_regexp, len, CPF_READ);
-
- if(!GRANT_VALID(g))
- return GRANTBAD;
-
- flags &= DS_INITIAL;
+ cp_grant_id_t g_key;
+ size_t len_key;
+ int access, r;
+
+ if(type == DS_CHECK || type == DS_RETRIEVE_LABEL) {
+ len_key = DS_MAX_KEYLEN;
+ access = CPF_WRITE;
+ } else {
+ len_key = strlen(ds_name)+1;
+ access = CPF_READ;
+ }
- m.DS_KEY_GRANT = (char *) g;
- m.DS_KEY_LEN = len;
- m.DS_FLAGS = flags | (type & DS_TYPE_MASK);
+ /* Grant for key. */
+ g_key = cpf_grant_direct(DS_PROC_NR, (vir_bytes) ds_name,
+ len_key, access);
+ if(!GRANT_VALID(g_key))
+ return errno;
- r = _taskcall(DS_PROC_NR, DS_SUBSCRIBE, &m);
+ m.DS_KEY_GRANT = g_key;
+ m.DS_KEY_LEN = len_key;
- cpf_revoke(g);
+ r = _taskcall(DS_PROC_NR, type, &m);
+ cpf_revoke(g_key);
return r;
}
-int ds_publish_u32(ds_name, value)
-char *ds_name;
-u32_t value;
+int ds_publish_label(const char *ds_name, u32_t value, int flags)
{
- int r;
- message m;
- cp_grant_id_t g;
- size_t len;
-
- len = strlen(ds_name)+1;
- g = cpf_grant_direct(DS_PROC_NR,
- (vir_bytes) ds_name, len, CPF_READ);
-
- if(!GRANT_VALID(g))
- return GRANTBAD;
-
- m.DS_KEY_GRANT = (char *) g;
- m.DS_KEY_LEN = len;
- m.DS_FLAGS = DS_TYPE_U32;
m.DS_VAL = value;
- m.DS_VAL_LEN = sizeof(value);
-
- r = _taskcall(DS_PROC_NR, DS_PUBLISH, &m);
+ m.DS_FLAGS = DSF_TYPE_LABEL | flags;
+ return do_invoke_ds(DS_PUBLISH, ds_name);
+}
- cpf_revoke(g);
+int ds_publish_u32(const char *ds_name, u32_t value, int flags)
+{
+ m.DS_VAL = value;
+ m.DS_FLAGS = DSF_TYPE_U32 | flags;
+ return do_invoke_ds(DS_PUBLISH, ds_name);
+}
- return r;
+int ds_publish_str(const char *ds_name, char *value, int flags)
+{
+ if(strlen(value) >= DS_MAX_STRLEN)
+ return EINVAL;
+ strcpy((char *)(&m.DS_STRING), value);
+ m.DS_FLAGS = DSF_TYPE_STR | flags;
+ return do_invoke_ds(DS_PUBLISH, ds_name);
}
-int ds_publish_str(ds_name, value)
-char *ds_name;
-char *value;
+int ds_publish_mem(const char *ds_name, void *vaddr, size_t length, int flags)
{
+ cp_grant_id_t gid;
int r;
- message m;
- cp_grant_id_t g_key, g_str;
- size_t len_key, len_str;
- /* Grant for key. */
- len_key = strlen(ds_name)+1;
- g_key = cpf_grant_direct(DS_PROC_NR,
- (vir_bytes) ds_name, len_key, CPF_READ);
- if(!GRANT_VALID(g_key))
- return GRANTBAD;
+ /* Grant for memory range. */
+ gid = cpf_grant_direct(DS_PROC_NR, (vir_bytes)vaddr, length, CPF_READ);
+ if(!GRANT_VALID(gid))
+ return errno;
- /* Grant for value. */
- len_str = strlen(value)+1;
- g_str = cpf_grant_direct(DS_PROC_NR,
- (vir_bytes) value, len_str, CPF_READ);
+ m.DS_VAL = gid;
+ m.DS_VAL_LEN = length;
+ m.DS_FLAGS = DSF_TYPE_MEM | flags;
- if(!GRANT_VALID(g_str)) {
- cpf_revoke(g_key);
- return GRANTBAD;
- }
-
- m.DS_KEY_GRANT = (char *) g_key;
- m.DS_KEY_LEN = len_key;
- m.DS_FLAGS = DS_TYPE_STR;
- m.DS_VAL = g_str;
- m.DS_VAL_LEN = len_str;
-
- r = _taskcall(DS_PROC_NR, DS_PUBLISH, &m);
-
- cpf_revoke(g_key);
- cpf_revoke(g_str);
+ r = do_invoke_ds(DS_PUBLISH, ds_name);
+ cpf_revoke(gid);
return r;
}
-int ds_retrieve_u32(ds_name, value)
-char *ds_name;
-u32_t *value;
+int ds_publish_map(const char *ds_name, void *vaddr, size_t length, int flags)
{
+ cp_grant_id_t gid;
int r;
- message m;
- cp_grant_id_t g_key;
- size_t len_key;
- /* Grant for key. */
- len_key = strlen(ds_name)+1;
- g_key = cpf_grant_direct(DS_PROC_NR,
- (vir_bytes) ds_name, len_key, CPF_READ);
- if(!GRANT_VALID(g_key))
- return GRANTBAD;
-
- /* Do request. */
- m.DS_KEY_GRANT = (char *) g_key;
- m.DS_KEY_LEN = len_key;
- m.DS_FLAGS = DS_TYPE_U32;
+ if(((vir_bytes)vaddr % CLICK_SIZE != 0) || (length % CLICK_SIZE != 0))
+ return EINVAL;
- r = _taskcall(DS_PROC_NR, DS_RETRIEVE, &m);
+ /* Grant for mapped memory range. */
+ gid = cpf_grant_direct(DS_PROC_NR, (vir_bytes)vaddr, length,
+ CPF_READ | CPF_MAP);
+ if(!GRANT_VALID(gid))
+ return errno;
- cpf_revoke(g_key);
+ m.DS_VAL = gid;
+ m.DS_VAL_LEN = length;
+ m.DS_FLAGS = DSF_TYPE_MAP | flags;
- if(r == OK) {
- /* Assign u32 value. */
- *value = m.DS_VAL;
- }
+ r = do_invoke_ds(DS_PUBLISH, ds_name);
+ cpf_revoke(gid);
return r;
}
-int ds_retrieve_str(ds_name, value, len_str)
-char *ds_name;
-char *value;
-size_t len_str;
+int ds_snapshot_map(const char *ds_name, int *nr_snapshot)
{
int r;
- message m;
- cp_grant_id_t g_key, g_str;
- size_t len_key;
+ r = do_invoke_ds(DS_SNAPSHOT, ds_name);
+ *nr_snapshot = m.DS_NR_SNAPSHOT;
+ return r;
+}
- /* Grant for key. */
- len_key = strlen(ds_name)+1;
- g_key = cpf_grant_direct(DS_PROC_NR,
- (vir_bytes) ds_name, len_key, CPF_READ);
- if(!GRANT_VALID(g_key))
- return GRANTBAD;
+int ds_retrieve_label_name(char *ds_name, u32_t num)
+{
+ int r;
+ m.DS_VAL = num;
+ r = do_invoke_ds(DS_RETRIEVE_LABEL, ds_name);
+ return r;
+}
- /* Grant for value. */
- g_str = cpf_grant_direct(DS_PROC_NR,
- (vir_bytes) value, len_str, CPF_WRITE);
+int ds_retrieve_label_num(const char *ds_name, u32_t *value)
+{
+ int r;
+ m.DS_FLAGS = DSF_TYPE_LABEL;
+ r = do_invoke_ds(DS_RETRIEVE, ds_name);
+ *value = m.DS_VAL;
+ return r;
+}
- if(!GRANT_VALID(g_str)) {
- cpf_revoke(g_key);
- return GRANTBAD;
- }
+int ds_retrieve_u32(const char *ds_name, u32_t *value)
+{
+ int r;
+ m.DS_FLAGS = DSF_TYPE_U32;
+ r = do_invoke_ds(DS_RETRIEVE, ds_name);
+ *value = m.DS_VAL;
+ return r;
+}
- /* Do request. */
+int ds_retrieve_str(const char *ds_name, char *value, size_t len_str)
+{
+ int r;
+ m.DS_FLAGS = DSF_TYPE_STR;
+ r = do_invoke_ds(DS_RETRIEVE, ds_name);
+ strncpy(value, (char *)(&m.DS_STRING), DS_MAX_STRLEN);
+ value[DS_MAX_STRLEN - 1] = '\0';
+ return r;
+}
- m.DS_KEY_GRANT = (char *) g_key;
- m.DS_KEY_LEN = len_key;
- m.DS_FLAGS = DS_TYPE_STR;
- m.DS_VAL = g_str;
- m.DS_VAL_LEN = len_str;
+int ds_retrieve_mem(const char *ds_name, char *vaddr, size_t *length)
+{
+ cp_grant_id_t gid;
+ int r;
- r = _taskcall(DS_PROC_NR, DS_RETRIEVE, &m);
+ /* Grant for memory range. */
+ gid = cpf_grant_direct(DS_PROC_NR, (vir_bytes)vaddr, *length, CPF_WRITE);
+ if(!GRANT_VALID(gid))
+ return errno;
- cpf_revoke(g_key);
- cpf_revoke(g_str);
+ m.DS_VAL = gid;
+ m.DS_VAL_LEN = *length;
+ m.DS_FLAGS = DSF_TYPE_MEM;
+ r = do_invoke_ds(DS_RETRIEVE, ds_name);
+ *length = m.DS_VAL_LEN;
+ cpf_revoke(gid);
return r;
}
-int ds_check_str(ds_key, len_key, value, len_str)
-char *ds_key;
-size_t len_key;
-char *value;
-size_t len_str;
+int ds_retrieve_map(const char *ds_name, char *vaddr, size_t *length,
+ int nr_snapshot, int flags)
{
+ cp_grant_id_t gid;
int r;
- message m;
- cp_grant_id_t g_key, g_str;
-
- if(len_key < 1 || len_str < 1) return -1002;
-
- /* Grant for key. */
- g_key = cpf_grant_direct(DS_PROC_NR,
- (vir_bytes) ds_key, len_key, CPF_WRITE);
- if(!GRANT_VALID(g_key))
- return GRANTBAD;
-
- /* Grant for value. */
- g_str = cpf_grant_direct(DS_PROC_NR,
- (vir_bytes) value, len_str, CPF_WRITE);
- if(!GRANT_VALID(g_str)) {
- cpf_revoke(g_key);
- return GRANTBAD;
+ /* Map a mapped memory range. */
+ if(flags & DSMF_MAP_MAPPED) {
+ /* Request DS to grant. */
+ m.DS_FLAGS = DSF_TYPE_MAP | DSMF_MAP_MAPPED;
+ r = do_invoke_ds(DS_RETRIEVE, ds_name);
+ if(r != OK)
+ return r;
+
+ /* Do the safemap. */
+ if(*length > m.DS_VAL_LEN)
+ *length = m.DS_VAL_LEN;
+ *length = (size_t) CLICK_FLOOR(*length);
+ r = sys_safemap(DS_PROC_NR, m.DS_VAL, 0,
+ (vir_bytes)vaddr, *length, D, 0);
+
+ /* Copy mapped memory range or a snapshot. */
+ } else if(flags & (DSMF_COPY_MAPPED|DSMF_COPY_SNAPSHOT)) {
+ /* Grant for memory range first. */
+ gid = cpf_grant_direct(DS_PROC_NR, (vir_bytes)vaddr,
+ *length, CPF_WRITE);
+ if(!GRANT_VALID(gid))
+ return errno;
+
+ m.DS_VAL = gid;
+ m.DS_VAL_LEN = *length;
+ if(flags & DSMF_COPY_MAPPED) {
+ m.DS_FLAGS = DSF_TYPE_MAP | DSMF_COPY_MAPPED;
+ }
+ else {
+ m.DS_NR_SNAPSHOT = nr_snapshot;
+ m.DS_FLAGS = DSF_TYPE_MAP | DSMF_COPY_SNAPSHOT;
+ }
+ r = do_invoke_ds(DS_RETRIEVE, ds_name);
+ *length = m.DS_VAL_LEN;
+ cpf_revoke(gid);
+ }
+ else {
+ return EINVAL;
}
-
- /* Do request. */
-
- m.DS_KEY_GRANT = (char *) g_key;
- m.DS_KEY_LEN = len_key;
- m.DS_FLAGS = DS_TYPE_STR;
- m.DS_VAL = g_str;
- m.DS_VAL_LEN = len_str;
-
- r = _taskcall(DS_PROC_NR, DS_CHECK, &m);
-
- cpf_revoke(g_key);
- cpf_revoke(g_str);
-
- ds_key[len_key-1] = '\0';
- value[len_str-1] = '\0';
return r;
}
-int ds_check_u32(ds_key, len_key, value)
-char *ds_key;
-size_t len_key;
-u32_t *value;
+int ds_delete_u32(const char *ds_name)
{
- int r;
- message m;
- cp_grant_id_t g_key;
-
- if(len_key < 1) return -1;
-
- /* Grant for key. */
- g_key = cpf_grant_direct(DS_PROC_NR,
- (vir_bytes) ds_key, len_key, CPF_WRITE);
- if(!GRANT_VALID(g_key))
- return GRANTBAD;
+ m.DS_FLAGS = DSF_TYPE_U32;
+ return do_invoke_ds(DS_DELETE, ds_name);
+}
- /* Do request. */
- m.DS_KEY_GRANT = (char *) g_key;
- m.DS_KEY_LEN = len_key;
- m.DS_FLAGS = DS_TYPE_U32;
+int ds_delete_str(const char *ds_name)
+{
+ m.DS_FLAGS = DSF_TYPE_STR;
+ return do_invoke_ds(DS_DELETE, ds_name);
+}
- r = _taskcall(DS_PROC_NR, DS_CHECK, &m);
+int ds_delete_mem(const char *ds_name)
+{
+ m.DS_FLAGS = DSF_TYPE_MEM;
+ return do_invoke_ds(DS_DELETE, ds_name);
+}
- cpf_revoke(g_key);
+int ds_delete_map(const char *ds_name)
+{
+ m.DS_FLAGS = DSF_TYPE_MAP;
+ return do_invoke_ds(DS_DELETE, ds_name);
+}
- ds_key[len_key-1] = '\0';
+int ds_delete_label(const char *ds_name)
+{
+ m.DS_FLAGS = DSF_TYPE_LABEL;
+ return do_invoke_ds(DS_DELETE, ds_name);
+}
- /* Assign u32 value. */
- *value = m.DS_VAL;
+int ds_subscribe(const char *regexp, int flags)
+{
+ m.DS_FLAGS = flags;
+ return do_invoke_ds(DS_SUBSCRIBE, regexp);
+}
+int ds_check(char *ds_key, int *type)
+{
+ int r;
+ r = do_invoke_ds(DS_CHECK, ds_key);
+ *type = m.DS_FLAGS;
return r;
}
-
if (pci_procnr == ANY)
{
- r= ds_retrieve_u32("pci", &u32);
+ r= ds_retrieve_label_num("pci", &u32);
if (r != 0)
{
panic("syslib/" __FILE__,
size_t len;
message m;
- r= ds_retrieve_u32("pci", &u32);
+ r= ds_retrieve_label_num("pci", &u32);
if (r != 0)
- panic("syslib/" __FILE__, "pci_init1: ds_retrieve_u32 failed for 'pci'", r);
+ panic("syslib/" __FILE__, "pci_init1: ds_retrieve_label_num failed for 'pci'", r);
pci_procnr= u32;
m.m_type= BUSC_PCI_INIT;
if (pci_procnr == ANY)
{
- r= ds_retrieve_u32("pci", &u32);
+ r= ds_retrieve_label_num("pci", &u32);
if (r != 0)
{
panic("syslib/" __FILE__,
- "pci_set_acl: ds_retrieve_u32 failed for 'pci'",
+ "pci_set_acl: ds_retrieve_label_num failed for 'pci'",
r);
}
pci_procnr = u32;
#include <string.h>
#define ACCESS_CHECK(a) { \
- if((a) & ~(CPF_READ|CPF_WRITE)) { \
+ if((a) & ~(CPF_READ|CPF_WRITE|CPF_MAP)) { \
errno = EINVAL; \
return -1; \
} \
} \
}
+#define CLICK_ALIGNMENT_CHECK(addr, bytes) { \
+ if(((vir_bytes)(addr) % CLICK_SIZE != 0) \
+ || ((vir_bytes)(bytes) % CLICK_SIZE != 0)) { \
+ return EINVAL; \
+ } \
+ }
+
#define NR_STATIC_GRANTS 2
PRIVATE cp_grant_t static_grants[NR_STATIC_GRANTS];
PRIVATE cp_grant_t *grants = NULL;
cpf_revoke(cp_grant_id_t g)
{
/* Revoke previously granted access, identified by grant id. */
+ int r;
GID_CHECK_USED(g);
+ /* If this grant is for memory mapping, revoke the mapping first. */
+ if(grants[g].cp_flags & CPF_MAP) {
+ r = sys_saferevmap_gid(g);
+ if(r != 0)
+ return r;
+ }
+
/* Make grant invalid by setting flags to 0, clearing CPF_USED.
* This invalidates the grant.
*/
GID_CHECK(gid);
ACCESS_CHECK(access);
+ /* Check click alignment in case of memory mapping grant. */
+ if(access & CPF_MAP) {
+ CLICK_ALIGNMENT_CHECK(addr, bytes);
+ }
+
+ /* Fill in new slot data. */
grants[gid].cp_flags = access | CPF_DIRECT | CPF_USED | CPF_VALID;
grants[gid].cp_u.cp_direct.cp_who_to = who;
grants[gid].cp_u.cp_direct.cp_start = addr;
GID_CHECK(gid);
ACCESS_CHECK(access);
+ /* Check click alignment in case of memory mapping grant. */
+ if(access & CPF_MAP) {
+ CLICK_ALIGNMENT_CHECK(addr, bytes);
+ }
+
/* Fill in new slot data. */
grants[gid].cp_flags = CPF_USED | CPF_MAGIC | CPF_VALID | access;
grants[gid].cp_u.cp_magic.cp_who_to = who_to;
--- /dev/null
+
+#include "syslib.h"
+
+#include <minix/safecopies.h>
+
+/*===========================================================================*
+ * sys_safemap *
+ *===========================================================================*/
+PUBLIC int sys_safemap(endpoint_t grantor, cp_grant_id_t grant,
+ vir_bytes grant_offset, vir_bytes my_address,
+ size_t bytes, int my_seg, int writable)
+{
+/* Map a block of data for which the other process has previously
+ * granted permission.
+ */
+
+ message copy_mess;
+
+ copy_mess.SMAP_EP = grantor;
+ copy_mess.SMAP_GID = grant;
+ copy_mess.SMAP_OFFSET = grant_offset;
+ copy_mess.SMAP_SEG = (void*) my_seg;
+ copy_mess.SMAP_ADDRESS = my_address;
+ copy_mess.SMAP_BYTES = bytes;
+ copy_mess.SMAP_FLAG = writable;
+
+ return(_taskcall(SYSTASK, SYS_SAFEMAP, ©_mess));
+
+}
+
+/*===========================================================================*
+ * sys_saferevmap_gid *
+ *===========================================================================*/
+PUBLIC int sys_saferevmap_gid(cp_grant_id_t grant)
+{
+/* Grantor revokes safemap by grant id. */
+ message copy_mess;
+
+ copy_mess.SMAP_FLAG = 1;
+ copy_mess.SMAP_GID = grant;
+
+ return(_taskcall(SYSTASK, SYS_SAFEREVMAP, ©_mess));
+}
+
+/*===========================================================================*
+ * sys_saferevmap_addr *
+ *===========================================================================*/
+PUBLIC int sys_saferevmap_addr(vir_bytes addr)
+{
+/* Grantor revokes safemap by address. */
+ message copy_mess;
+
+ copy_mess.SMAP_FLAG = 0;
+ copy_mess.SMAP_GID = addr;
+
+ return(_taskcall(SYSTASK, SYS_SAFEREVMAP, ©_mess));
+}
+
+/*===========================================================================*
+ * sys_safeunmap *
+ *===========================================================================*/
+PUBLIC int sys_safeunmap(int my_seg, vir_bytes my_address)
+{
+/* Requestor unmaps safemap. */
+ message copy_mess;
+
+ copy_mess.SMAP_SEG = (void*) my_seg;
+ copy_mess.SMAP_ADDRESS = my_address;
+
+ return(_taskcall(SYSTASK, SYS_SAFEUNMAP, ©_mess));
+}
+
}
PUBLIC int sys_vmctl_get_memreq(endpoint_t *who, vir_bytes *mem,
- vir_bytes *len, int *wrflag, endpoint_t *requestor)
+ vir_bytes *len, int *wrflag, endpoint_t *who_s, vir_bytes *mem_s,
+ endpoint_t *requestor)
{
message m;
int r;
m.SVMCTL_WHO = SELF;
m.SVMCTL_PARAM = VMCTL_MEMREQ_GET;
r = _taskcall(SYSTASK, SYS_VMCTL, &m);
- if(r == OK) {
- *who = m.SVMCTL_MRG_EP;
- *mem = (vir_bytes) m.SVMCTL_MRG_ADDR;
- *len = m.SVMCTL_MRG_LEN;
- *wrflag = m.SVMCTL_MRG_WRITE;
+ if(r >= 0) {
+ *who = m.SVMCTL_MRG_TARGET;
+ *mem = m.SVMCTL_MRG_ADDR;
+ *len = m.SVMCTL_MRG_LENGTH;
+ *wrflag = m.SVMCTL_MRG_FLAG;
+ *who_s = m.SVMCTL_MRG_EP2;
+ *mem_s = m.SVMCTL_MRG_ADDR2;
*requestor = (endpoint_t) m.SVMCTL_MRG_REQUESTOR;
}
return r;
env_panic.c \
env_prefix.c \
fkey_ctl.c \
- micro_delay.c \
+ tsc_util.c \
report.c \
taskcall.c \
read_tsc.s \
#define CALIBRATE \
if(!calibrated) { \
int r; \
- if((r=micro_delay_calibrate()) != OK) \
- panic(__FILE__, "micro_delay: calibrate failed\n", r); \
+ if((r=tsc_calibrate()) != OK) \
+ panic(__FILE__, "calibrate failed\n", r); \
}
static u32_t calib_tsc, Hz = 0;
static int calibrated = 0;
int
-micro_delay_calibrate(void)
+tsc_calibrate(void)
{
u64_t start, end, diff;
struct tms tms;
diff = sub64(end, start);
if(ex64hi(diff) != 0)
panic(__FILE__,
- "micro_delay_calibrate: CALIBRATE_TICKS too high "
+ "tsc_calibrate: CALIBRATE_TICKS too high "
"for TSC frequency\n", NO_NUM);
calib_tsc = ex64lo(diff);
#if 0
- printf("micro_delay_calibrate: "
+ printf("tsc_calibrate: "
"%lu cycles/%d ticks of %d Hz; %lu cycles/s\n",
calib_tsc, CALIBRATE_TICKS(Hz), Hz,
div64u(mul64u(calib_tsc, Hz), CALIBRATE_TICKS(Hz)));
return OK;
}
+u32_t tsc_64_to_micros(u64_t tsc)
+{
+ return tsc_to_micros(ex64lo(tsc), ex64hi(tsc));
+}
+
+u32_t tsc_to_micros(u32_t low, u32_t high)
+{
+ u32_t micros;
+
+ if(high) {
+ return 0;
+ }
+ CALIBRATE;
+
+ micros = (div64u(mul64u(low, MICROHZ * CALIBRATE_TICKS(Hz)),
+ calib_tsc)/Hz);
+
+ return micros;
+}
+
#include <sys/types.h>
#include <limits.h>
#include <errno.h>
+#include <regex.h>
#include <minix/callnr.h>
#include <minix/config.h>
#include <minix/type.h>
#include <minix/const.h>
#include <minix/com.h>
+#include <minix/ds.h>
#include <minix/syslib.h>
#include <minix/sysutil.h>
#include <minix/keymap.h>
#include "proto.h"
#include "glo.h"
-#include "store.h"
case DS_RETRIEVE:
result = do_retrieve(&m);
break;
+ case DS_RETRIEVE_LABEL:
+ result = do_retrieve_label(&m);
+ break;
+ case DS_DELETE:
+ result = do_delete(&m);
+ break;
case DS_SUBSCRIBE:
result = do_subscribe(&m);
break;
case DS_CHECK:
result = do_check(&m);
break;
+ case DS_SNAPSHOT:
+ result = do_snapshot(&m);
+ break;
case GETSYSINFO:
result = do_getsysinfo(&m);
break;
/* store.c */
_PROTOTYPE(int do_publish, (message *m_ptr));
_PROTOTYPE(int do_retrieve, (message *m_ptr));
+_PROTOTYPE(int do_retrieve_label, (message *m_ptr));
_PROTOTYPE(int do_subscribe, (message *m_ptr));
_PROTOTYPE(int do_check, (message *m_ptr));
+_PROTOTYPE(int do_delete, (message *m_ptr));
+_PROTOTYPE(int do_snapshot, (message *m_ptr));
_PROTOTYPE(int do_getsysinfo, (message *m_ptr));
_PROTOTYPE(int sef_cb_init_fresh, (int type, sef_init_info_t *info));
_PROTOTYPE(int map_service, (struct rprocpub *rpub));
-/* Implementation of the Data Store. */
-
#include "inc.h"
+#include "store.h"
/* Allocate space for the data store. */
PRIVATE struct data_store ds_store[NR_DS_KEYS];
PRIVATE struct subscription ds_subs[NR_DS_SUBS];
-PRIVATE int nr_in_use;
-PRIVATE _PROTOTYPE(int find_key, (char *key, struct data_store **dsp, int t));
-PRIVATE _PROTOTYPE(int set_owner, (struct data_store *dsp, int auth));
-PRIVATE _PROTOTYPE(int is_authorized, (struct data_store *dsp, int auth));
-PRIVATE _PROTOTYPE(void check_subscribers, (struct data_store *dsp));
+/*===========================================================================*
+ * alloc_data_slot *
+ *===========================================================================*/
+PRIVATE struct data_store *alloc_data_slot(void)
+{
+/* Allocate a new data slot. */
+ int i;
+
+ for (i = 0; i < NR_DS_KEYS; i++) {
+ if (!(ds_store[i].flags & DSF_IN_USE))
+ return &ds_store[i];
+ }
+
+ return NULL;
+}
+
+/*===========================================================================*
+ * alloc_sub_slot *
+ *===========================================================================*/
+PRIVATE struct subscription *alloc_sub_slot(void)
+{
+/* Allocate a new subscription slot. */
+ int i;
+
+ for (i = 0; i < NR_DS_SUBS; i++) {
+ if (!(ds_subs[i].flags & DSF_IN_USE))
+ return &ds_subs[i];
+ }
+
+ return NULL;
+}
+
+/*===========================================================================*
+ * lookup_entry *
+ *===========================================================================*/
+PRIVATE struct data_store *lookup_entry(const char *key_name, int type)
+{
+/* Lookup an existing entry by key and type. */
+ int i;
+
+ for (i = 0; i < NR_DS_KEYS; i++) {
+ if ((ds_store[i].flags & DSF_IN_USE) /* used */
+ && (ds_store[i].flags & type) /* same type*/
+ && !strcmp(ds_store[i].key, key_name)) /* same key*/
+ return &ds_store[i];
+ }
+ return NULL;
+}
+
+/*===========================================================================*
+ * lookup_label_entry *
+ *===========================================================================*/
+PRIVATE struct data_store *lookup_label_entry(unsigned num)
+{
+/* Lookup an existing label entry by num. */
+ int i;
+
+ for (i = 0; i < NR_DS_KEYS; i++) {
+ if ((ds_store[i].flags & DSF_IN_USE)
+ && (ds_store[i].flags & DSF_TYPE_LABEL)
+ && (ds_store[i].u.u32 == num))
+ return &ds_store[i];
+ }
+
+ return NULL;
+}
+
+/*===========================================================================*
+ * lookup_sub *
+ *===========================================================================*/
+PRIVATE struct subscription *lookup_sub(const char *owner)
+{
+/* Lookup an existing subscription given its owner. */
+ int i;
+
+ for (i = 0; i < NR_DS_SUBS; i++) {
+ if ((ds_subs[i].flags & DSF_IN_USE) /* used */
+ && !strcmp(ds_subs[i].owner, owner)) /* same key*/
+ return &ds_subs[i];
+ }
+
+ return NULL;
+}
+
+/*===========================================================================*
+ * ds_getprocname *
+ *===========================================================================*/
+PRIVATE char *ds_getprocname(endpoint_t e)
+{
+/* Get a process name given its endpoint. */
+ struct data_store *dsp;
+
+ static char *first_proc_name = "ds";
+ endpoint_t first_proc_ep = DS_PROC_NR;
+
+ if(e == first_proc_ep)
+ return first_proc_name;
+
+ if((dsp = lookup_label_entry(e)) != NULL)
+ return dsp->key;
+
+ return NULL;
+}
+
+/*===========================================================================*
+ * ds_getprocep *
+ *===========================================================================*/
+PRIVATE endpoint_t ds_getprocep(char *s)
+{
+/* Get a process endpoint given its name. */
+ struct data_store *dsp;
+
+ if((dsp = lookup_entry(s, DSF_TYPE_LABEL)) != NULL)
+ return dsp->u.u32;
+ return -1;
+}
+
+/*===========================================================================*
+ * check_auth *
+ *===========================================================================*/
+PRIVATE int check_auth(struct data_store *p, endpoint_t ep, int perm)
+{
+/* Check authorization for a given type of permission. */
+ if(!(p->flags & perm))
+ return 1;
+
+ return !strcmp(p->owner, ds_getprocname(ep));
+}
+
+/*===========================================================================*
+ * get_key_name *
+ *===========================================================================*/
+PRIVATE int get_key_name(message *m_ptr, char *key_name)
+{
+/* Get key name given an input message. */
+ int r;
+
+ if (m_ptr->DS_KEY_LEN > DS_MAX_KEYLEN || m_ptr->DS_KEY_LEN < 2) {
+ printf("DS: bogus key length (%d) from %d\n", m_ptr->DS_KEY_LEN,
+ m_ptr->m_source);
+ return EINVAL;
+ }
+
+ /* Copy name from caller. */
+ r = sys_safecopyfrom(m_ptr->m_source,
+ (cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0,
+ (vir_bytes) key_name, m_ptr->DS_KEY_LEN, D);
+ if(r != OK) {
+ printf("DS: publish: copy failed from %d: %d\n", m_ptr->m_source, r);
+ return r;
+ }
+
+ key_name[DS_MAX_KEYLEN-1] = '\0';
+
+ return OK;
+}
+
+/*===========================================================================*
+ * check_snapshot_index *
+ *===========================================================================*/
+PRIVATE int check_snapshot_index(struct data_store *dsp, int index)
+{
+/* See if the given snapshot index is valid. */
+ int min;
+
+ min = dsp->u.map.sindex < NR_DS_SNAPSHOT
+ ? 0
+ : dsp->u.map.sindex - NR_DS_SNAPSHOT + 1;
+
+ return (index >= min && index <= dsp->u.map.sindex) ? 0 : 1;
+}
+
+/*===========================================================================*
+ * check_sub_match *
+ *===========================================================================*/
+PRIVATE int check_sub_match(struct subscription *subp,
+ struct data_store *dsp, endpoint_t ep)
+{
+/* Check if an entry matches a subscription. Return 1 in case of match. */
+ return (check_auth(dsp, ep, DSF_PRIV_SUBSCRIBE)
+ && regexec(&subp->regex, dsp->key, 0, NULL, 0) == 0)
+ ? 1 : 0;
+}
+
+/*===========================================================================*
+ * update_subscribers *
+ *===========================================================================*/
+PRIVATE void update_subscribers(struct data_store *dsp, int set)
+{
+/* If set = 1, set bit in the sub bitmap of any subscription matching the given
+ * entry, otherwise clear it. In both cases, notify the subscriber.
+ */
+ int i;
+ int nr = dsp - ds_store;
+ endpoint_t ep;
+
+ for(i = 0; i < NR_DS_SUBS; i++) {
+ if(!(ds_subs[i].flags & DSF_IN_USE))
+ continue;
+ if(!(ds_subs[i].flags & dsp->flags & DSF_MASK_TYPE))
+ continue;
+
+ ep = ds_getprocep(ds_subs[i].owner);
+ if(!check_sub_match(&ds_subs[i], dsp, ep))
+ continue;
+
+ if(set == 1) {
+ SET_BIT(ds_subs[i].old_subs, nr);
+ } else {
+ UNSET_BIT(ds_subs[i].old_subs, nr);
+ }
+ notify(ep);
+ }
+}
/*===========================================================================*
* sef_cb_init_fresh *
/* Reset data store: data and subscriptions. */
for(i = 0; i < NR_DS_KEYS; i++) {
- int b;
- ds_store[i].ds_flags = 0;
- for(b = 0; b < BITMAP_CHUNKS(NR_DS_SUBS); b++) {
- ds_store[i].ds_old_subs[b] = 0;
- }
+ ds_store[i].flags = 0;
+ }
+ for(i = 0; i < NR_DS_SUBS; i++) {
+ ds_subs[i].flags = 0;
}
- for(i = 0; i < NR_DS_SUBS; i++)
- ds_subs[i].sub_flags = 0;
/* Map all the services in the boot image. */
if((r = sys_safecopyfrom(RS_PROC_NR, info->rproctab_gid, 0,
/* Map a new service by registering its label. */
struct data_store *dsp;
- dsp = &ds_store[nr_in_use]; /* new slot found */
- strcpy(dsp->ds_key, rpub->label);
- dsp->ds_flags = DS_IN_USE | DS_TYPE_U32; /* initialize slot */
- nr_in_use++;
+ /* Allocate a new data slot. */
+ if((dsp = alloc_data_slot()) == NULL) {
+ return ENOMEM;
+ }
- dsp->ds_val.ds_val_u32 = (u32_t) rpub->endpoint; /* store data */
+ /* Set attributes. */
+ strcpy(dsp->key, rpub->label);
+ dsp->u.u32 = (u32_t) rpub->endpoint;
+ strcpy(dsp->owner, ds_getprocname(DS_PROC_NR));
+ dsp->flags = DSF_IN_USE | DSF_TYPE_LABEL;
- /* If anyone has a matching subscription, update them. */
- check_subscribers(dsp);
+ /* Update subscribers having a matching subscription. */
+ update_subscribers(dsp, 1);
return(OK);
}
-PRIVATE int set_owner(dsp, auth)
-struct data_store *dsp; /* data store structure */
-int auth;
-{
- return(TRUE);
-}
-
-
-PRIVATE int is_authorized(dsp, ap)
-struct data_store *dsp; /* data store structure */
-int ap; /* authorization value */
-{
- /* Authorize the caller. */
- return(TRUE);
-}
-
-
-PRIVATE int find_key(key_name, dsp, type)
-char *key_name; /* key to look up */
-struct data_store **dsp; /* store pointer here */
-int type; /* type info */
-{
- register int i;
-
- *dsp = NULL;
- for (i=0; i<NR_DS_KEYS; i++) {
- if ((ds_store[i].ds_flags & DS_IN_USE) /* valid slot? */
- && ((ds_store[i].ds_flags & type) == type) /* right type? */
- && !strcmp(ds_store[i].ds_key, key_name)) { /* matching name? */
- *dsp = &ds_store[i];
- return(TRUE); /* report success */
- }
- }
- return(FALSE); /* report not found */
-}
-
-
-PUBLIC int do_publish(m_ptr)
-message *m_ptr; /* request message */
+/*===========================================================================*
+ * do_publish *
+ *===========================================================================*/
+PUBLIC int do_publish(message *m_ptr)
{
struct data_store *dsp;
char key_name[DS_MAX_KEYLEN];
- int r, type;
+ int flags = m_ptr->DS_FLAGS;
+ size_t length;
+ int nr, r;
- /* Store (key,value)-pair. First see if key already exists. If so,
- * check if the caller is allowed to overwrite the value. Otherwise
- * find a new slot and store the new value.
- */
- if (m_ptr->DS_KEY_LEN > DS_MAX_KEYLEN || m_ptr->DS_KEY_LEN < 2) {
- printf("DS: bogus key length (%d) from %d\n", m_ptr->DS_KEY_LEN,
- m_ptr->m_source);
+ /* MAP should not be overwritten. */
+ if((flags & DSF_TYPE_MAP) && (flags & DSF_OVERWRITE))
return EINVAL;
- }
-
- /* Check type info. */
- type = m_ptr->DS_FLAGS & DS_TYPE_MASK;
- if(type != DS_TYPE_U32 && type != DS_TYPE_STR) {
- printf("DS: bogus type code %lx from %d\n", type, m_ptr->m_source);
- return EINVAL;
- }
- /* Copy name from caller. */
- if ((r=sys_safecopyfrom(m_ptr->m_source,
- (cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0,
- (vir_bytes) key_name, m_ptr->DS_KEY_LEN, D)) != OK) {
- printf("DS: publish: copy failed from %d: %d\n", m_ptr->m_source, r);
+ /* Get key name. */
+ if((r = get_key_name(m_ptr, key_name)) != OK)
return r;
+
+ /* Lookup the entry. */
+ dsp = lookup_entry(key_name, flags & DSF_MASK_TYPE);
+ /* If type is LABEL, also try to lookup the entry by num. */
+ if((flags & DSF_TYPE_LABEL) && (dsp == NULL))
+ dsp = lookup_label_entry(m_ptr->DS_VAL);
+
+ if(dsp == NULL) {
+ /* The entry doesn't exist, allocate a new data slot. */
+ if((dsp = alloc_data_slot()) == NULL)
+ return ENOMEM;
+ } else if (flags & DSF_OVERWRITE) {
+ /* Overwrite. */
+ if(!check_auth(dsp, m_ptr->m_source, DSF_PRIV_OVERWRITE))
+ return EPERM;
+ } else {
+ /* Don't overwrite and return error. */
+ return EEXIST;
}
- /* Make sure name is 0-terminated. */
- key_name[DS_MAX_KEYLEN-1] = '\0';
+ /* Store! */
+ switch(flags & DSF_MASK_TYPE) {
+ case DSF_TYPE_U32:
+ case DSF_TYPE_LABEL:
+ dsp->u.u32 = m_ptr->DS_VAL;
+ break;
+ case DSF_TYPE_STR:
+ strncpy(dsp->u.string, (char *)(&m_ptr->DS_STRING), DS_MAX_STRLEN);
+ dsp->u.string[DS_MAX_KEYLEN - 1] = '\0';
+ break;
+ case DSF_TYPE_MEM:
+ length = m_ptr->DS_VAL_LEN;
+ /* Allocate a new data buffer if necessary. */
+ if(!(dsp->flags & DSF_IN_USE)) {
+ if((dsp->u.mem.data = malloc(length)) == NULL)
+ return ENOMEM;
+ dsp->u.mem.reallen = length;
+ } else if(length > dsp->u.mem.reallen) {
+ free(dsp->u.mem.data);
+ if((dsp->u.mem.data = malloc(length)) == NULL)
+ return ENOMEM;
+ dsp->u.mem.reallen = length;
+ }
- /* See if it already exists. */
- if (!find_key(key_name, &dsp, type)) { /* look up key */
- if (nr_in_use >= NR_DS_KEYS) {
- return(EAGAIN); /* store is full */
- } else {
- dsp = &ds_store[nr_in_use]; /* new slot found */
- strcpy(dsp->ds_key, key_name);
- dsp->ds_flags = DS_IN_USE | m_ptr->DS_FLAGS; /* initialize slot */
- nr_in_use ++;
- }
+ /* Copy the memory range. */
+ r = sys_safecopyfrom(m_ptr->m_source, m_ptr->DS_VAL, 0,
+ (vir_bytes) dsp->u.mem.data, length, D);
+ if(r != OK) {
+ printf("DS: publish: memory map/copy failed from %d: %d\n",
+ m_ptr->m_source, r);
+ free(dsp->u.mem.data);
+ return r;
+ }
+ dsp->u.mem.length = length;
+ break;
+ case DSF_TYPE_MAP:
+ /* Allocate buffer, the address should be aligned by CLICK_SIZE. */
+ length = m_ptr->DS_VAL_LEN;
+ if((dsp->u.map.realpointer = malloc(length + CLICK_SIZE)) == NULL)
+ return ENOMEM;
+ dsp->u.map.data = (void*) CLICK_CEIL(dsp->u.map.realpointer);
+
+ /* Map memory. */
+ r = sys_safemap(m_ptr->m_source, m_ptr->DS_VAL, 0,
+ (vir_bytes) dsp->u.map.data, length, D, 0);
+ if(r != OK) {
+ printf("DS: publish: memory map/copy failed from %d: %d\n",
+ m_ptr->m_source, r);
+ free(dsp->u.map.realpointer);
+ return r;
+ }
+ dsp->u.map.length = length;
+ dsp->u.map.sindex = -1;
+ break;
+ default:
+ return EINVAL;
}
- /* At this point we have a data store pointer and know the caller is
- * authorize to write to it. Set all fields as requested.
- */
- switch(type) {
- case DS_TYPE_U32:
- dsp->ds_val.ds_val_u32 = (u32_t) m_ptr->DS_VAL; /* store data */
- break;
- case DS_TYPE_STR:
- /* store string data: check size, then do copy */
- if(m_ptr->DS_VAL_LEN < 1 || m_ptr->DS_VAL_LEN > DS_MAX_VALLEN) {
- printf("DS: publish: bogus len from %d: %d\n",
- m_ptr->m_source, m_ptr->DS_VAL_LEN);
- return EINVAL;
- }
-
- if((r=sys_safecopyfrom(m_ptr->m_source, m_ptr->DS_VAL, 0,
- (vir_bytes) dsp->ds_val.ds_val_str,
- m_ptr->DS_VAL_LEN, D)) != OK) {
- printf("DS: publish: str copy failed from %d: %d\n",
- m_ptr->m_source, r);
- return r;
- }
- break;
- default:
- panic(__FILE__, "Impossible type.", type);
- break;
- }
+ /* Set attributes. */
+ strcpy(dsp->key, key_name);
+ strcpy(dsp->owner, ds_getprocname(m_ptr->m_source));
+ dsp->flags = DSF_IN_USE | (flags & DSF_MASK_INTERNAL);
- /* If anyone has a matching subscription, update them. */
- check_subscribers(dsp);
+ /* Update subscribers having a matching subscription. */
+ update_subscribers(dsp, 1);
return(OK);
}
-
/*===========================================================================*
* do_retrieve *
*===========================================================================*/
-PUBLIC int do_retrieve(m_ptr)
-message *m_ptr; /* request message */
+PUBLIC int do_retrieve(message *m_ptr)
{
struct data_store *dsp;
char key_name[DS_MAX_KEYLEN];
- int r, type;
- size_t len;
-
- if (m_ptr->DS_KEY_LEN > DS_MAX_KEYLEN || m_ptr->DS_KEY_LEN < 1) {
- printf("DS: bogus key length (%d) from %d\n", m_ptr->DS_KEY_LEN,
- m_ptr->m_source);
- return EINVAL;
- }
-
- /* Copy name from caller. */
- if ((r=sys_safecopyfrom(m_ptr->m_source,
- (cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0,
- (vir_bytes) key_name, m_ptr->DS_KEY_LEN, D)) != OK) {
- printf("DS: retrieve: copy failed from %d: %d\n", m_ptr->m_source, r);
+ int flags = m_ptr->DS_FLAGS;
+ int type = flags & DSF_MASK_TYPE;
+ size_t length;
+ void *data;
+ int index, r;
+
+ /* Get key name. */
+ if((r = get_key_name(m_ptr, key_name)) != OK)
return r;
- }
- /* Make sure name is 0-terminated. */
- key_name[DS_MAX_KEYLEN-1] = '\0';
+ /* Lookup the entry. */
+ if((dsp = lookup_entry(key_name, type)) == NULL)
+ return ESRCH;
+ if(!check_auth(dsp, m_ptr->m_source, DSF_PRIV_RETRIEVE))
+ return EPERM;
+ /* Copy the requested data. */
+ switch(type) {
+ case DSF_TYPE_U32:
+ case DSF_TYPE_LABEL:
+ m_ptr->DS_VAL = dsp->u.u32;
+ break;
+ case DSF_TYPE_STR:
+ strncpy((char *)(&m_ptr->DS_STRING), dsp->u.string, DS_MAX_STRLEN);
+ break;
+ case DSF_TYPE_MEM:
+ length = MIN(m_ptr->DS_VAL_LEN, dsp->u.mem.length);
+ r = sys_safecopyto(m_ptr->m_source, m_ptr->DS_VAL, 0,
+ (vir_bytes) dsp->u.mem.data, length, D);
+ if(r != OK) {
+ printf("DS: retrieve: copy failed to %d: %d\n",
+ m_ptr->m_source, r);
+ return r;
+ }
+ m_ptr->DS_VAL_LEN = length;
+ break;
+ case DSF_TYPE_MAP:
+ /* The caller requested to map a mapped memory range.
+ * Create a MAP grant for the caller, the caller will do the
+ * safemap itself later.
+ */
+ if(flags & DSMF_MAP_MAPPED) {
+ cp_grant_id_t gid;
+ gid = cpf_grant_direct(m_ptr->m_source,
+ (vir_bytes)dsp->u.map.data,
+ dsp->u.map.length,
+ CPF_READ|CPF_WRITE|CPF_MAP);
+ if(!GRANT_VALID(gid))
+ return -1;
+ m_ptr->DS_VAL = gid;
+ m_ptr->DS_VAL_LEN = length;
+ }
- /* Retrieve data. Look up the key in the data store. Return an error if it
- * is not found. If this data is private, only the owner may retrieve it.
- */
- type = m_ptr->DS_FLAGS & DS_TYPE_MASK;
- if (find_key(key_name, &dsp, type)) { /* look up key */
- /* Data is public or the caller is authorized to retrieve it. */
- switch(type) {
- case DS_TYPE_U32:
- m_ptr->DS_VAL = dsp->ds_val.ds_val_u32; /* return value */
- break;
- case DS_TYPE_STR:
- len = strlen(dsp->ds_val.ds_val_str) + 1;
- if(len > m_ptr->DS_VAL_LEN)
- len = m_ptr->DS_VAL_LEN;
- if ((r=sys_safecopyto(m_ptr->m_source, m_ptr->DS_VAL,
- 0, (vir_bytes) dsp->ds_val.ds_val_str,len, D)) != OK) {
+ /* The caller requested a copy of a mapped mem range or a snapshot. */
+ else if(flags & (DSMF_COPY_MAPPED|DSMF_COPY_SNAPSHOT)) {
+ if(flags & DSMF_COPY_MAPPED) {
+ data = dsp->u.map.data;
+ } else {
+ index = m_ptr->DS_NR_SNAPSHOT;
+ if(check_snapshot_index(dsp, index))
+ return EINVAL;
+ data = dsp->u.map.snapshots[index % NR_DS_SNAPSHOT];
+ }
+
+ length = MIN(m_ptr->DS_VAL_LEN, dsp->u.map.length);
+ r = sys_safecopyto(m_ptr->m_source, m_ptr->DS_VAL, 0,
+ (vir_bytes) data, length, D);
+ if(r != OK) {
printf("DS: retrieve: copy failed to %d: %d\n",
m_ptr->m_source, r);
return r;
}
- break;
- default:
- panic(__FILE__, "retrieve: impossible type.", type);
- /* not reached. */
- break;
-
- }
- return(OK); /* report success */
+ m_ptr->DS_VAL_LEN = length;
+ }
+ else {
+ return EINVAL;
+ }
+ break;
+ default:
+ return EINVAL;
}
- return(ESRCH); /* key not found */
+
+ return OK;
}
/*===========================================================================*
- * do_check *
+ * do_retrieve_label *
*===========================================================================*/
-PUBLIC int do_check(m_ptr)
-message *m_ptr; /* request message */
+PUBLIC int do_retrieve_label(message *m_ptr)
{
-/* This routine goes through all subscriptions for a client,
- * and checks all data items if it has been flagged (i.e.,
- * created or updated) matching that subscription. Return
- * a message and copy the key and value for every one.
- */
- int r, s, d, type = m_ptr->DS_FLAGS & DS_TYPE_MASK;
- if(!type) return EINVAL;
- for(s = 0; s < NR_DS_SUBS; s++) {
- int len;
- if(!(ds_subs[s].sub_flags & DS_IN_USE))
- continue;
- if(m_ptr->m_source != ds_subs[s].sub_owner)
- continue;
- for(d = 0; d < NR_DS_KEYS; d++) {
-
- /* No match if this is no value, it's
- * not flagged, or the type is wrong.
- */
-
- if(!(ds_store[d].ds_flags & DS_IN_USE))
- continue;
- if(!GET_BIT(ds_store[d].ds_old_subs, s))
- continue;
- if(type != (ds_store[d].ds_flags & DS_TYPE_MASK))
- continue;
-
- /* We have a match. Unflag it for this
- * subscription.
- */
- UNSET_BIT(ds_store[d].ds_old_subs, s);
- len = strlen(ds_store[d].ds_key)+1;
- if(len > m_ptr->DS_KEY_LEN)
- len = m_ptr->DS_KEY_LEN;
-
- /* Copy the key into client. */
- if ((r=sys_safecopyto(m_ptr->m_source,
- (cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0,
- (vir_bytes) ds_store[d].ds_key,
- len, D)) != OK)
- return r;
-
- /* Now copy the value. */
- switch(type) {
- case DS_TYPE_STR:
- len = strlen(ds_store[d].
- ds_val.ds_val_str)+1;
- if(len > m_ptr->DS_VAL_LEN)
- len = m_ptr->DS_VAL_LEN;
- if ((r=sys_safecopyto(m_ptr->m_source,
- m_ptr->DS_VAL, 0,
- (vir_bytes) ds_store[d].
- ds_val.ds_val_str,
- len, D)) != OK)
- return r;
- break;
- case DS_TYPE_U32:
- m_ptr->DS_VAL =
- ds_store[d].ds_val.ds_val_u32;
- break;
- default:
- panic(__FILE__,
- "Check impossible type.",
- type);
- }
-
- return OK;
- }
- }
+ struct data_store *dsp;
+ int r;
+
+ /* Lookup the label entry. */
+ if((dsp = lookup_label_entry(m_ptr->DS_VAL)) == NULL)
+ return ESRCH;
+
+ /* Copy the key name. */
+ r = sys_safecopyto(m_ptr->m_source,
+ (cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0,
+ (vir_bytes) dsp->key, strlen(dsp->key) + 1, D);
+ if(r != OK) {
+ printf("DS: copy failed from %d: %d\n", m_ptr->m_source, r);
+ return r;
+ }
- return(ESRCH); /* key not found */
+ return OK;
}
-PUBLIC int do_subscribe(m_ptr)
-message *m_ptr; /* request message */
+/*===========================================================================*
+ * do_subscribe *
+ *===========================================================================*/
+PUBLIC int do_subscribe(message *m_ptr)
{
char regex[DS_MAX_KEYLEN+3];
- int s, type, e, d, n = 0;
+ struct subscription *subp;
char errbuf[80];
+ char *owner;
+ int type_set;
+ int r, e, b;
+
+ /* Find the owner. */
+ owner = ds_getprocname(m_ptr->m_source);
+ if(owner == NULL)
+ return ESRCH;
+
+ /* See if the owner already has an existing subscription. */
+ if((subp = lookup_sub(owner)) == NULL) {
+ /* The subscription doesn't exist, allocate a new one. */
+ if((subp = alloc_sub_slot()) == NULL)
+ return EAGAIN;
+ } else if(!(m_ptr->DS_FLAGS & DSF_OVERWRITE)) {
+ /* The subscription exists but we can't overwrite, return error. */
+ return EEXIST;
+ }
- /* Subscribe to a key of interest.
- * All updates to the key will cause a notification message
- * to be sent to the subscribed. On success, directly return a copy of the
- * data for the given key.
- */
- if(m_ptr->DS_KEY_LEN < 2 || m_ptr->DS_KEY_LEN > DS_MAX_KEYLEN)
- return EINVAL;
-
- /* Copy name from caller. Anchor the subscription with "^regexp$" so
- * substrings don't match. The caller probably will not expect this,
+ /* Copy key name from the caller. Anchor the subscription with "^regexp$" so
+ * substrings don't match. The caller will probably not expect this,
* and the usual case is for a complete match.
*/
regex[0] = '^';
- if ((s=sys_safecopyfrom(m_ptr->m_source,
- (cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0,
- (vir_bytes) regex + 1, m_ptr->DS_KEY_LEN, D)) != OK) {
- printf("DS: retrieve: copy failed from %d: %d\n", m_ptr->m_source, s);
- return s;
- }
-
+ if((r = get_key_name(m_ptr, regex)) != OK)
+ return r;
regex[DS_MAX_KEYLEN-1] = '\0';
strcat(regex, "$");
- /* Find subscription slot. */
- for(s = 0; s < NR_DS_SUBS; s++)
- if(!(ds_subs[s].sub_flags & DS_IN_USE))
+ /* Compile regular expression. */
+ if((e=regcomp(&subp->regex, regex, REG_EXTENDED)) != 0) {
+ regerror(e, &subp->regex, errbuf, sizeof(errbuf));
+ printf("DS: subscribe: regerror: %s\n", errbuf);
+ return EINVAL;
+ }
+
+ /* If type_set = 0, then subscribe all types. */
+ type_set = m_ptr->DS_FLAGS & DSF_MASK_TYPE;
+ if(type_set == 0)
+ type_set = DSF_MASK_TYPE;
+
+ subp->flags = DSF_IN_USE | type_set;
+ strcpy(subp->owner, owner);
+ for(b = 0; b < BITMAP_CHUNKS(NR_DS_SUBS); b++)
+ subp->old_subs[b] = 0;
+
+ /* See if caller requested an instant initial list. */
+ if(m_ptr->DS_FLAGS & DSF_INITIAL) {
+ int i, match_found = FALSE;
+ for(i = 0; i < NR_DS_KEYS; i++) {
+ if(!(ds_store[i].flags & DSF_IN_USE))
+ continue;
+ if(!(ds_store[i].flags & type_set))
+ continue;
+ if(!check_sub_match(subp, &ds_store[i], m_ptr->m_source))
+ continue;
+
+ SET_BIT(subp->old_subs, i);
+ match_found = TRUE;
+ }
+
+ /* Notify in case of match. */
+ if(match_found)
+ notify(m_ptr->m_source);
+ }
+
+ return OK;
+}
+
+/*===========================================================================*
+ * do_check *
+ *===========================================================================*/
+PUBLIC int do_check(message *m_ptr)
+{
+ struct subscription *subp;
+ char *owner;
+ int r, i;
+
+ /* Find the owner. */
+ owner = ds_getprocname(m_ptr->m_source);
+ if(owner == NULL)
+ return ESRCH;
+
+ /* Lookup the owner's subscription. */
+ if((subp = lookup_sub(owner)) == NULL)
+ return ESRCH;
+
+ /* Look for an updated entry the subscriber is interested in. */
+ for(i = 0; i < NR_DS_KEYS; i++) {
+ if(GET_BIT(subp->old_subs, i))
break;
+ }
+ if(i == NR_DS_KEYS)
+ return ENOENT;
- if(s >= NR_DS_SUBS) {
- printf("DS: no space for subscription by %d.\n", m_ptr->m_source);
- return ENOSPC;
+ /* Copy the key name. */
+ r = sys_safecopyto(m_ptr->m_source,
+ (cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0,
+ (vir_bytes) ds_store[i].key, strlen(ds_store[i].key), D);
+ if(r != OK) {
+ printf("DS: check: copy failed from %d: %d\n", m_ptr->m_source, r);
+ return r;
}
- /* Compile regular expression. */
- if((e=regcomp(&ds_subs[s].sub_regex, regex, REG_EXTENDED)) != 0) {
- regerror(e, &ds_subs[s].sub_regex, errbuf, sizeof(errbuf));
- printf("DS: subscribe: regerror: %s\n", errbuf);
+ /* Copy the type. */
+ m_ptr->DS_FLAGS = ds_store[i].flags & DSF_MASK_TYPE;
+
+ /* Mark the entry as no longer updated for the subscriber. */
+ UNSET_BIT(subp->old_subs, i);
+
+ return OK;
+}
+
+/*===========================================================================*
+ * do_delete *
+ *===========================================================================*/
+PUBLIC int do_delete(message *m_ptr)
+{
+ struct data_store *dsp;
+ char key_name[DS_MAX_KEYLEN];
+ int type = m_ptr->DS_FLAGS & DSF_MASK_TYPE;
+ int top, i, r;
+
+ /* Get key name. */
+ if((r = get_key_name(m_ptr, key_name)) != OK)
+ return r;
+
+ /* Lookup the entry. */
+ if((dsp = lookup_entry(key_name, type)) == NULL)
+ return ESRCH;
+
+ /* Only the owner can delete. */
+ if(strcmp(dsp->owner, ds_getprocname(m_ptr->m_source)))
+ return EPERM;
+
+ switch(type) {
+ case DSF_TYPE_U32:
+ case DSF_TYPE_STR:
+ case DSF_TYPE_LABEL:
+ break;
+ case DSF_TYPE_MEM:
+ free(dsp->u.mem.data);
+ break;
+ case DSF_TYPE_MAP:
+ /* Unmap the mapped data. */
+ r = sys_safeunmap(D, (vir_bytes)dsp->u.map.data);
+ if(r != OK)
+ return r;
+
+ /* Revoke all the mapped grants. */
+ r = sys_saferevmap_addr((vir_bytes)dsp->u.map.data);
+ if(r != OK)
+ return r;
+
+ /* Free snapshots. */
+ top = MIN(NR_DS_SNAPSHOT - 1, dsp->u.map.sindex);
+ for(i = 0; i <= top; i++) {
+ free(dsp->u.map.snapshots[i]);
+ }
+
+ free(dsp->u.map.realpointer);
+ break;
+ default:
return EINVAL;
}
- type = (m_ptr->DS_FLAGS & DS_TYPE_MASK);
- ds_subs[s].sub_flags = DS_IN_USE | type;
- ds_subs[s].sub_owner = m_ptr->m_source;
-
- /* Caller requested an instant initial list? */
- if(m_ptr->DS_FLAGS & DS_INITIAL) {
- for(d = 0; d < NR_DS_KEYS; d++) {
- if(!(ds_store[d].ds_flags & DS_IN_USE))
- continue;
- if(regexec(&ds_subs[s].sub_regex, ds_store[d].ds_key,
- 0, NULL, 0) == 0) {
- SET_BIT(ds_store[d].ds_old_subs, s);
- n = 1;
- }
- }
-
- /* Any matches? */
- if(n) notify(ds_subs[s].sub_owner);
- }
-
- return OK;
+
+ /* Update subscribers having a matching subscription. */
+ update_subscribers(dsp, 0);
+
+ /* Clear the entry. */
+ dsp->flags = 0;
+
+ return OK;
}
+/*===========================================================================*
+ * do_snapshot *
+ *===========================================================================*/
+PUBLIC int do_snapshot(message *m_ptr)
+{
+ struct data_store *dsp;
+ struct dsi_map *p;
+ char key_name[DS_MAX_KEYLEN];
+ int i, r;
+
+ /* Get key name. */
+ if((r = get_key_name(m_ptr, key_name)) != OK)
+ return r;
+
+ /* Lookup the entry. */
+ if((dsp = lookup_entry(key_name, DSF_TYPE_MAP)) == NULL)
+ return ESRCH;
+
+ if(!check_auth(dsp, m_ptr->m_source, DSF_PRIV_SNAPSHOT))
+ return EPERM;
+
+ /* Find a snapshot slot. */
+ p = &dsp->u.map;
+ p->sindex++;
+ i = p->sindex % DS_MAX_KEYLEN;
+ if(p->sindex < DS_MAX_KEYLEN) {
+ if((p->snapshots[i] = malloc(p->length)) == NULL) {
+ p->sindex--;
+ return ENOMEM;
+ }
+ }
+
+ /* Store the snapshot. */
+ memcpy(p->snapshots[i], p->data, p->length);
+
+ /* Copy the snapshot index. */
+ m_ptr->DS_NR_SNAPSHOT = p->sindex;
+
+ return OK;
+}
/*===========================================================================*
* do_getsysinfo *
*===========================================================================*/
-PUBLIC int do_getsysinfo(m_ptr)
-message *m_ptr;
+PUBLIC int do_getsysinfo(message *m_ptr)
{
- vir_bytes src_addr, dst_addr;
- int dst_proc;
- size_t len;
+ vir_bytes src_addr;
+ size_t length;
int s;
switch(m_ptr->m1_i1) {
case SI_DATA_STORE:
- src_addr = (vir_bytes) ds_store;
- len = sizeof(struct data_store) * NR_DS_KEYS;
- break;
+ src_addr = (vir_bytes)ds_store;
+ length = sizeof(struct data_store) * NR_DS_KEYS;
+ break;
+ case SI_SUBSCRIPTION:
+ src_addr = (vir_bytes)ds_subs;
+ length = sizeof(struct subscription) * NR_DS_SUBS;
+ break;
default:
- return(EINVAL);
+ return EINVAL;
}
- dst_proc = m_ptr->m_source;
- dst_addr = (vir_bytes) m_ptr->m1_p1;
- if (OK != (s=sys_datacopy(SELF, src_addr, dst_proc, dst_addr, len))) {
+ if (OK != (s=sys_datacopy(SELF, src_addr,
+ m_ptr->m_source, (vir_bytes)m_ptr->m1_p1, length))) {
printf("DS: copy failed: %d\n", s);
- return(s);
+ return s;
}
- return(OK);
-}
-/*===========================================================================*
- * check_subscribers *
- *===========================================================================*/
-PRIVATE void
-check_subscribers(struct data_store *dsp)
-{
-/* Send subscribers whose subscriptions match this (new
- * or updated) data item a notify(), and flag the subscriptions
- * as updated.
- */
- int i;
- for(i = 0; i < NR_DS_SUBS; i++) {
- if(ds_subs[i].sub_flags & DS_IN_USE) {
- if(regexec(&ds_subs[i].sub_regex, dsp->ds_key,
- 0, NULL, 0) == 0) {
- SET_BIT(dsp->ds_old_subs, i);
- notify(ds_subs[i].sub_owner);
- } else {
- UNSET_BIT(dsp->ds_old_subs, i);
- }
- }
- }
+ return OK;
}
-/* Type definitions for the Data Store Server. */
+#ifndef _DS_STORE_H_
+#define _DS_STORE_H_
+/* Type definitions for the Data Store Server. */
#include <sys/types.h>
#include <minix/sys_config.h>
#include <minix/ds.h>
#include <minix/bitmap.h>
#include <regex.h>
-/* Constants for the Data Store Server. */
-#define NR_DS_KEYS 64 /* reserve space for so many items */
-#define NR_DS_SUBS (4*_NR_SYS_PROCS) /* .. and so many subscriptions */
-
-/* Types. */
+#define NR_DS_KEYS 64 /* number of entries */
+#define NR_DS_SUBS (4*_NR_SYS_PROCS) /* number of subscriptions */
+#define NR_DS_SNAPSHOT 5 /* number of snapshots */
+/* Base 'class' for the following 3 structs. */
struct data_store {
- int ds_flags; /* flags for this store, includes type info */
- char ds_key[DS_MAX_KEYLEN]; /* key to lookup information */
- union {
- u32_t ds_val_u32; /* u32 data (DS_TYPE_U32) */
- char ds_val_str[DS_MAX_VALLEN]; /* string data (DS_TYPE_STR) */
- } ds_val;
-
- /* out of date subscribers. */
- bitchunk_t ds_old_subs[BITMAP_CHUNKS(NR_DS_SUBS)];
+ int flags;
+ char key[DS_MAX_KEYLEN]; /* key to lookup information */
+ char owner[DS_MAX_KEYLEN];
+
+ union {
+ unsigned u32;
+ char string[DS_MAX_STRLEN];
+ struct {
+ void *data;
+ size_t length;
+ size_t reallen;
+ } mem;
+ struct dsi_map {
+ void *data;
+ size_t length;
+ void *realpointer;
+ void *snapshots[NR_DS_SNAPSHOT];
+ int sindex;
+ } map;
+ } u;
};
struct subscription {
- int sub_flags; /* flags for this subscription */
- regex_t sub_regex; /* regular expression agains keys */
- endpoint_t sub_owner; /* who is subscribed */
+ int flags;
+ char owner[DS_MAX_KEYLEN];
+ regex_t regex;
+ bitchunk_t old_subs[BITMAP_CHUNKS(NR_DS_KEYS)];
};
-
+#endif /* _DS_STORE_H_ */
init_rand256(randbits);
/* Our new identity as a server. */
- r= ds_retrieve_u32("inet", &tasknr);
+ r= ds_retrieve_label_num("inet", &tasknr);
if (r != OK)
- ip_panic(("inet: ds_retrieve_u32 failed for 'inet': %d", r));
+ ip_panic(("inet: ds_retrieve_label_num failed for 'inet': %d", r));
this_proc= tasknr;
/* Register the device group. */
}
eth_port->etp_osdep.etp_rd_vec_grant= gid;
- r= ds_retrieve_u32(ecp->ec_task, &tasknr);
+ r= ds_retrieve_label_num(ecp->ec_task, &tasknr);
if (r != OK && r != ESRCH)
{
- printf("inet: ds_retrieve_u32 failed for '%s': %d\n",
+ printf("inet: ds_retrieve_label_num failed for '%s': %d\n",
ecp->ec_task, r);
}
if (r != OK)
-/* This file contains procedures to dump DS data structures.
- *
- * The entry points into this file are
- * data_store_dmp: display DS data store contents
- *
- * Created:
- * Oct 18, 2005: by Jorrit N. Herder
- */
-
#include "inc.h"
#include "../ds/store.h"
-PUBLIC struct data_store store[NR_DS_KEYS];
-
-FORWARD _PROTOTYPE( char *s_flags_str, (int flags) );
+PRIVATE struct data_store ds_store[NR_DS_KEYS];
-/*===========================================================================*
- * data_store_dmp *
- *===========================================================================*/
PUBLIC void data_store_dmp()
{
- struct data_store *dsp;
- int i,j, n=0, s;
- static int prev_i=0;
-
+ struct data_store *p;
+ static int prev_i = 0;
+ int r, i, n = 0;
- printf("Data Store (DS) contents dump\n");
-
- if((s=getsysinfo(DS_PROC_NR, SI_DATA_STORE, store)) != OK) {
- printf("Couldn't talk to DS: %d.\n", s);
+ if((r=getsysinfo(DS_PROC_NR, SI_DATA_STORE, ds_store)) != OK) {
+ printf("Couldn't talk to DS: %d.\n", r);
return;
}
- printf("slot key type value\n");
-
- for (i=prev_i; i<NR_DS_KEYS; i++) {
- dsp = &store[i];
- if (! dsp->ds_flags & DS_IN_USE) continue;
- if (++n > 22) break;
- printf("%3d %-20s ",
- i, dsp->ds_key);
- if(dsp->ds_flags & DS_TYPE_U32) {
- printf("u32 %lu\n", dsp->ds_val.ds_val_u32);
- } else if(dsp->ds_flags & DS_TYPE_STR) {
- printf("str \"%s\"\n", dsp->ds_val.ds_val_str);
- } else {
- printf("Bogus type\n");
+ printf("Data store contents:\n");
+ printf("-slot- ------key------ -----owner----- ---type--- ----value---\n");
+ for(i = prev_i; i < NR_DS_KEYS; i++) {
+ p = &ds_store[i];
+ if(!(p->flags & DSF_IN_USE))
+ continue;
+
+ printf("%6d %-15s %-15s ", i, p->key, p->owner);
+ switch(p->flags & DSF_MASK_TYPE) {
+ case DSF_TYPE_U32:
+ printf("%-10s %12u\n", "U32", p->u.u32);
+ break;
+ case DSF_TYPE_STR:
+ printf("%-10s %12s\n", "STR", p->u.string);
+ break;
+ case DSF_TYPE_MEM:
+ printf("%-10s %12u\n", "MEM", p->u.mem.length);
+ break;
+ case DSF_TYPE_MAP:
+ printf("%-10s %9u/%3u\n", "MAP", p->u.map.length,
+ p->u.map.sindex);
+ break;
+ case DSF_TYPE_LABEL:
+ printf("%-10s %12u\n", "LABEL", p->u.u32);
+ break;
+ default:
+ return;
}
+
+ if(n++ == 21)
+ break;
}
+
if (i >= NR_DS_KEYS) i = 0;
else printf("--more--\r");
prev_i = i;
}
-
-PRIVATE char *s_flags_str(int flags)
-{
- static char str[5];
- str[0] = (flags & DS_IN_USE) ? 'U' : '-';
- str[1] = (flags & DS_PUBLIC) ? 'P' : '-';
- str[2] = '-';
- str[3] = '\0';
-
- return(str);
-}
-
return(EINVAL);
}
- r = ds_retrieve_u32(fs_dev_label, &tasknr);
- if (r != OK) {
- printf("%s:%d fs_readsuper: ds_retrieve_u32 failed for '%s': %d\n",
- __FILE__, __LINE__, fs_dev_label, r);
- return(EINVAL);
+ r= ds_retrieve_label_num(fs_dev_label, &tasknr);
+ if (r != OK)
+ {
+ printf("mfs:fs_readsuper: ds_retrieve_label_num failed for '%s': %d\n",
+ fs_dev_label, r);
+ return EINVAL;
}
driver_e = tasknr;
mem_sp = &proc.p_memmap[S]; /* pointer to stack segment map */
/* Compute how many clicks the data segment is to become. */
- data_clicks = (vir_clicks) ( ((long) new_brksize + CLICK_SIZE - 1) >>
- CLICK_SHIFT) - mem_dp->mem_vir;
+ data_clicks = (vir_clicks) (CLICK_CEIL(new_brksize) >> CLICK_SHIFT)
+ - mem_dp->mem_vir;
/* See if stack size has gone negative (i.e., sp too close to 0xFFFF...) */
base_of_stack = (long) mem_sp->mem_vir + (long) mem_sp->mem_len;
/* Add a safety margin for future stack growth. Impossible to do right. */
#define SAFETY_BYTES (384 * sizeof(char *))
-#define SAFETY_CLICKS ((SAFETY_BYTES + CLICK_SIZE - 1) / CLICK_SIZE)
+#define SAFETY_CLICKS ((vir_clicks) (CLICK_CEIL(SAFETY_BYTES) >> CLICK_SHIFT))
gap_base = mem_dp->mem_vir + data_clicks + SAFETY_CLICKS;
if (sp_lower < gap_base)
{
fprintf(stderr, "Warning, %s\n", problem);
fprintf(stderr, "Usage:\n");
fprintf(stderr,
- " %s [-c] (up|run) <binary> [%s <args>] [%s <special>] [%s <ticks>]\n",
+ " %s [-c -r] (up|run) <binary> [%s <args>] [%s <special>] [%s <ticks>]\n",
app_name, ARG_ARGS, ARG_DEV, ARG_PERIOD);
fprintf(stderr, " %s down label\n", app_name);
fprintf(stderr, " %s refresh label\n", app_name);
{ "GETINFO", SYS_GETINFO },
{ "SAFECOPYFROM", SYS_SAFECOPYFROM },
{ "SAFECOPYTO", SYS_SAFECOPYTO },
+ { "SAFEMAP", SYS_SAFEMAP },
+ { "SAFEREVMAP", SYS_SAFEREVMAP },
+ { "SAFEUNMAP", SYS_SAFEUNMAP },
{ "VSAFECOPY", SYS_VSAFECOPY },
{ "SETGRANT", SYS_SETGRANT },
{ "READBIOS", SYS_READBIOS },
*/
#define FS_KC SYS_KILL, SYS_VIRCOPY, SYS_SAFECOPYFROM, SYS_SAFECOPYTO, \
SYS_UMAP, SYS_GETINFO, SYS_EXIT, SYS_TIMES, SYS_SETALARM, \
- SYS_PRIVCTL, SYS_TRACE , SYS_SETGRANT, SYS_PROFBUF, SYS_SYSCTL
+ SYS_PRIVCTL, SYS_TRACE , SYS_SETGRANT, SYS_PROFBUF, SYS_SYSCTL, \
+ SYS_SAFEMAP, SYS_SAFEREVMAP, SYS_SAFEUNMAP
#define DRV_KC FS_KC, SYS_SEGCTL, SYS_IRQCTL, SYS_INT86, SYS_DEVIO, \
SYS_SDEVIO, SYS_VDEVIO, SYS_SETGRANT, SYS_PROFBUF, SYS_SYSCTL
rpub = rp->r_pub;
/* Register its label with DS. */
- s= ds_publish_u32(rpub->label, rpub->endpoint);
+ s= ds_publish_label(rpub->label, rpub->endpoint, DSF_OVERWRITE);
if (s != OK) {
return s;
}
label[label_len]= '\0';
- r= ds_retrieve_u32(label, &tasknr);
+ r= ds_retrieve_label_num(label, &tasknr);
if (r != OK)
{
printf("vfs:do_mapdriver: ds doesn't know '%s'\n", label);
mount_label[sizeof(mount_label)-1] = 0;
- r = ds_retrieve_u32(mount_label, &fs_e);
+ r = ds_retrieve_label_num(mount_label, &fs_e);
if (r != OK) return(r);
if (isokendpt(fs_e, &proc_nr) != OK) return(EINVAL);
OBJ = main.o alloc.o utility.o exec.o exit.o fork.o break.o \
signal.o vfs.o mmap.o slaballoc.o region.o pagefaults.o addravl.o \
- physravl.o rs.o queryexit.o
+ physravl.o rs.o queryexit.o map_mem.o
ARCHOBJ = $(ARCH)/vm.o $(ARCH)/pagetable.o $(ARCH)/arch_pagefaults.o $(ARCH)/util.o
CPPFLAGS=-I../../kernel/arch/$(ARCH)/include -I$(ARCH)
/* Add a safety margin for future stack growth. Impossible to do right. */
#define SAFETY_BYTES (384 * sizeof(char *))
-#define SAFETY_CLICKS ((SAFETY_BYTES + CLICK_SIZE - 1) / CLICK_SIZE)
+#define SAFETY_CLICKS ((vir_clicks) (CLICK_CEIL(SAFETY_BYTES) >> CLICK_SHIFT))
gap_base = mem_dp->mem_vir + data_clicks + SAFETY_CLICKS;
if (sp_lower < gap_base)
{
vir_clicks new_clicks;
int r;
- new_clicks = (vir_clicks) ( ((long) v + CLICK_SIZE - 1) >> CLICK_SHIFT);
+ new_clicks = (vir_clicks) (CLICK_CEIL(v) >> CLICK_SHIFT);
if (new_clicks < vmp->vm_arch.vm_seg[D].mem_vir) {
printf("VM: real_brk failed because new_clicks too high: %d\n",
new_clicks);
}
/* Check to see if segment sizes are feasible. */
- tc = ((unsigned long) args.text_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
- dc = (args.data_bytes+args.bss_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
- totc = (args.tot_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
- sc = (args.args_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
+ tc = (vir_clicks) (CLICK_CEIL(args.text_bytes) >> CLICK_SHIFT);
+ dc = (vir_clicks) (CLICK_CEIL(args.data_bytes+args.bss_bytes) >> CLICK_SHIFT);
+ totc = (vir_clicks) (CLICK_CEIL(args.tot_bytes) >> CLICK_SHIFT);
+ sc = (vir_clicks) (CLICK_CEIL(args.args_bytes) >> CLICK_SHIFT);
if (dc >= totc) {
printf("VM: newmem: no stack?\n");
return(ENOEXEC); /* stack must be at least 1 click */
* and stack occupies an integral number of clicks, starting at click
* boundary. The data and bss parts are run together with no space.
*/
- text_clicks = ((unsigned long) text_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
- data_clicks = (data_bytes + bss_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
- stack_clicks = (stk_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
- tot_clicks = (tot_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
+ text_clicks = (vir_clicks) (CLICK_CEIL(text_bytes) >> CLICK_SHIFT);
+ data_clicks = (vir_clicks) (CLICK_CEIL(data_bytes + bss_bytes) >> CLICK_SHIFT);
+ stack_clicks = (vir_clicks) (CLICK_CEIL(stk_bytes) >> CLICK_SHIFT);
+ tot_clicks = (vir_clicks) (CLICK_CEIL(tot_bytes) >> CLICK_SHIFT);
gap_clicks = tot_clicks - data_clicks - stack_clicks;
if ( (int) gap_clicks < 0) {
printf("VM: new_mem: no gap?\n");
#define _SYSTEM 1
#define _POSIX_SOURCE 1
-#define VERBOSE 0
-
#include <minix/callnr.h>
#include <minix/com.h>
#include <minix/config.h>
#define _SYSTEM 1
-#define VERBOSE 0
-
#include <minix/callnr.h>
#include <minix/com.h>
#include <minix/config.h>
--- /dev/null
+
+#define _SYSTEM 1
+
+#include <minix/com.h>
+#include <minix/callnr.h>
+#include <minix/type.h>
+#include <minix/config.h>
+#include <minix/const.h>
+#include <minix/sysutil.h>
+#include <minix/syslib.h>
+
+#include <sys/mman.h>
+
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdint.h>
+#include <memory.h>
+
+#include "vm.h"
+#include "proto.h"
+#include "util.h"
+#include "glo.h"
+#include "region.h"
+#include "sanitycheck.h"
+
+/*===========================================================================*
+ * split_phys *
+ *===========================================================================*/
+PRIVATE int split_phys(struct phys_region *pr, vir_bytes point)
+{
+ struct phys_region *newpr, *q, *prev;
+ struct phys_block *newpb;
+ struct phys_block *pb = pr->ph;
+/* Split the phys region into 2 parts by @point. */
+
+ if(pr->offset >= point || pr->offset + pb->length <= point)
+ return OK;
+ if(!SLABALLOC(newpb))
+ return ENOMEM;
+
+ /* Split phys block. */
+ *newpb = *pb;
+ pb->length = point - pr->offset;
+ newpb->length -= pb->length;
+ newpb->phys += pb->length;
+
+ /* Split phys regions in a list. */
+ for(q = pb->firstregion; q; q = q->next_ph_list) {
+ if(!SLABALLOC(newpr))
+ return ENOMEM;
+
+ *newpr = *q;
+ newpr->ph = newpb;
+ newpr->offset += pb->length;
+
+ /* Link to the vir region's phys region list. */
+ physr_insert(newpr->parent->phys, newpr);
+
+ /* Link to the next_ph_list. */
+ if(q == pb->firstregion) {
+ newpb->firstregion = newpr;
+ prev = newpr;
+ } else {
+ prev->next_ph_list = newpr;
+ prev = newpr;
+ }
+ }
+ prev->next_ph_list = NULL;
+
+ return OK;
+}
+
+/*===========================================================================*
+ * rm_phys_regions *
+ *===========================================================================*/
+PRIVATE void rm_phys_regions(struct vir_region *region,
+ vir_bytes begin, vir_bytes length)
+{
+/* Remove all phys regions between @begin and @begin+length.
+ *
+ * Don't update the page table, because we will update it at map_memory()
+ * later.
+ */
+ struct phys_region *pr;
+ physr_iter iter;
+
+ physr_start_iter(region->phys, &iter, begin, AVL_GREATER_EQUAL);
+ while((pr = physr_get_iter(&iter)) && pr->offset < begin + length) {
+ pb_unreferenced(region, pr);
+ physr_remove(region->phys, pr->offset);
+ physr_start_iter(region->phys, &iter, begin,
+ AVL_GREATER_EQUAL);
+ SLABFREE(pr);
+ }
+}
+
+/*===========================================================================*
+ * clean_phys_regions *
+ *===========================================================================*/
+PRIVATE void clean_phys_regions(struct vir_region *region,
+ vir_bytes offset, vir_bytes length)
+{
+/* Consider @offset as the start address and @offset+length as the end address.
+ * If there are phys regions crossing the start address or the end address,
+ * split them into 2 parts.
+ *
+ * We assume that the phys regions are listed in order and don't overlap.
+ */
+ struct phys_region *pr;
+ physr_iter iter;
+
+ physr_start_iter_least(region->phys, &iter);
+ while((pr = physr_get_iter(&iter))) {
+ /* If this phys region crosses the start address, split it. */
+ if(pr->offset < offset
+ && pr->offset + pr->ph->length > offset) {
+ split_phys(pr, offset);
+ physr_start_iter_least(region->phys, &iter);
+ }
+ /* If this phys region crosses the end address, split it. */
+ else if(pr->offset < offset + length
+ && pr->offset + pr->ph->length > offset + length) {
+ split_phys(pr, offset + length);
+ physr_start_iter_least(region->phys, &iter);
+ }
+ else {
+ physr_incr_iter(&iter);
+ }
+ }
+}
+
+/*===========================================================================*
+ * do_map_memory *
+ *===========================================================================*/
+PRIVATE int do_map_memory(struct vmproc *vms, struct vmproc *vmd,
+ struct vir_region *vrs, struct vir_region *vrd,
+ vir_bytes offset_s, vir_bytes offset_d,
+ vir_bytes length, int flag)
+{
+ struct phys_region *prs;
+ struct phys_region *newphysr;
+ struct phys_block *pb;
+ physr_iter iter;
+ u32_t pt_flag = PTF_PRESENT | PTF_USER;
+ vir_bytes end;
+
+ /* Search for the first phys region in the source process. */
+ physr_start_iter(vrs->phys, &iter, offset_s, AVL_EQUAL);
+ prs = physr_get_iter(&iter);
+ if(!prs)
+ vm_panic("map_memory: no aligned phys region.", 0);
+
+ /* flag: 0 -> read-only
+ * 1 -> writable
+ * -1 -> share as COW, so read-only
+ */
+ if(flag > 0)
+ pt_flag |= PTF_WRITE;
+
+ /* Map phys blocks in the source process to the destination process. */
+ end = offset_d + length;
+ while((prs = physr_get_iter(&iter)) && offset_d < end) {
+ /* If a SMAP share was requested but the phys block has already
+ * been shared as COW, copy the block for the source phys region
+ * first.
+ */
+ pb = prs->ph;
+ if(flag >= 0 && pb->refcount > 1
+ && pb->share_flag == PBSH_COW) {
+ map_copy_ph_block(vms, vrs, prs);
+ pb = prs->ph;
+ }
+
+ /* Allocate a new phys region. */
+ if(!SLABALLOC(newphysr))
+ return ENOMEM;
+
+ /* Set and link the new phys region to the block. */
+ newphysr->ph = pb;
+ newphysr->offset = offset_d;
+ newphysr->parent = vrd;
+ newphysr->next_ph_list = pb->firstregion;
+ pb->firstregion = newphysr;
+ physr_insert(newphysr->parent->phys, newphysr);
+ pb->refcount++;
+
+ /* If a COW share was requested but the phys block has already
+ * been shared as SMAP, give up on COW and copy the block for
+ * the destination phys region now.
+ */
+ if(flag < 0 && pb->refcount > 1
+ && pb->share_flag == PBSH_SMAP) {
+ map_copy_ph_block(vmd, vrd, newphysr);
+ }
+ else {
+ /* See if this is a COW share or SMAP share. */
+ if(flag < 0) { /* COW share */
+ pb->share_flag = PBSH_COW;
+ /* Update the page table for the src process. */
+ pt_writemap(&vms->vm_pt, offset_s + vrs->vaddr,
+ pb->phys, pb->length,
+ pt_flag, WMF_OVERWRITE);
+ }
+ else { /* SMAP share */
+ pb->share_flag = PBSH_SMAP;
+ }
+ /* Update the page table for the destination process. */
+ pt_writemap(&vmd->vm_pt, offset_d + vrd->vaddr,
+ pb->phys, pb->length, pt_flag, WMF_OVERWRITE);
+ }
+
+ physr_incr_iter(&iter);
+ offset_d += pb->length;
+ offset_s += pb->length;
+ }
+}
+
+/*===========================================================================*
+ * map_memory *
+ *===========================================================================*/
+PUBLIC int map_memory(endpoint_t sour, endpoint_t dest,
+ vir_bytes virt_s, vir_bytes virt_d, vir_bytes length, int flag)
+{
+/* This is the entry point. This function will be called by handle_memory() when
+ * VM recieves a map-memory request.
+ */
+ struct vmproc *vms, *vmd;
+ struct vir_region *vrs, *vrd;
+ struct phys_region *prs, *prd;
+ physr_iter iters, iterd;
+ vir_bytes offset_s, offset_d;
+ int p;
+
+ if(vm_isokendpt(sour, &p) != OK)
+ vm_panic("handle_memory: endpoint wrong", sour);
+ vms = &vmproc[p];
+ if(vm_isokendpt(dest, &p) != OK)
+ vm_panic("handle_memory: endpoint wrong", dest);
+ vmd = &vmproc[p];
+
+ vrs = map_lookup(vms, virt_s);
+ vm_assert(vrs);
+ vrd = map_lookup(vmd, virt_d);
+ vm_assert(vrd);
+
+ /* Linear address -> offset from start of vir region. */
+ offset_s = virt_s - vrs->vaddr;
+ offset_d = virt_d - vrd->vaddr;
+
+ /* Make sure that the range in the source process has been mapped
+ * to physical memory.
+ */
+ map_handle_memory(vms, vrs, offset_s, length, 0);
+
+ /* Prepare work. */
+ #define map_printregion(x, y) (x = x)
+ #define printf(x, y, z) (z = z)
+ printf("before clean with offset, length: %d, %d\n", offset_s, length);
+ map_printregion(vms, vrs);
+ clean_phys_regions(vrs, offset_s, length);
+ printf("after clean with offset, length: %d, %d\n", offset_s, length);
+ map_printregion(vms, vrs);
+
+ printf("before clean with offset, length: %d, %d\n", offset_d, length);
+ map_printregion(vmd, vrd);
+ clean_phys_regions(vrd, offset_d, length);
+ printf("after clean with offset, length: %d, %d\n", offset_d, length);
+ map_printregion(vmd, vrd);
+
+ rm_phys_regions(vrd, offset_d, length);
+ printf("after rm with offset, length: %d, %d\n", offset_d, length);
+ map_printregion(vmd, vrd);
+
+ /* Map memory. */
+ do_map_memory(vms, vmd, vrs, vrd, offset_s, offset_d, length, flag);
+ printf("after map (dst) with offset, length: %d, %d\n", offset_d, length);
+ map_printregion(vmd, vrd);
+ #undef map_printregion
+ #undef printf
+
+ return OK;
+}
+
+/*===========================================================================*
+ * unmap_memory *
+ *===========================================================================*/
+PUBLIC int unmap_memory(endpoint_t sour, endpoint_t dest,
+ vir_bytes virt_s, vir_bytes virt_d, vir_bytes length, int flag)
+{
+ struct vmproc *vmd;
+ struct vir_region *vrd;
+ struct phys_region *pr;
+ struct phys_block *pb;
+ physr_iter iter;
+ vir_bytes off, end;
+ int p;
+
+ /* Use information on the destination process to unmap. */
+ if(vm_isokendpt(dest, &p) != OK)
+ vm_panic("handle_memory: endpoint wrong", dest);
+ vmd = &vmproc[p];
+
+ vrd = map_lookup(vmd, virt_d);
+ vm_assert(vrd);
+
+ /* Search for the first phys region in the destination process. */
+ off = virt_d - vrd->vaddr;
+ physr_start_iter(vrd->phys, &iter, off, AVL_EQUAL);
+ pr = physr_get_iter(&iter);
+ if(!pr)
+ vm_panic("map_memory: no aligned phys region.", 0);
+
+ /* Copy the phys block now rather than doing COW. */
+ end = off + length;
+ while((pr = physr_get_iter(&iter)) && off < end) {
+ pb = pr->ph;
+ vm_assert(pb->refcount > 1);
+ vm_assert(pb->share_flag == PBSH_SMAP);
+
+ map_copy_ph_block(vmd, vrd, pr);
+
+ physr_incr_iter(&iter);
+ off += pb->length;
+ }
+
+ return OK;
+}
+
#define _SYSTEM 1
-#define VERBOSE 0
-
#include <minix/callnr.h>
#include <minix/com.h>
#include <minix/config.h>
}
/*===========================================================================*
- * do_memory *
+ * do_memory *
*===========================================================================*/
PUBLIC void do_memory(void)
{
- int r, s;
- endpoint_t who, requestor;
- vir_bytes mem;
+ endpoint_t who, who_s, requestor;
+ vir_bytes mem, mem_s;
vir_bytes len;
int wrflag;
- while((r=sys_vmctl_get_memreq(&who, &mem, &len, &wrflag, &requestor))
- == OK) {
+ while(1) {
int p, r = OK;
struct vmproc *vmp;
- if(vm_isokendpt(who, &p) != OK)
- vm_panic("do_memory: endpoint wrong", who);
- vmp = &vmproc[p];
-
- r = handle_memory(vmp, mem, len, wrflag);
+ r = sys_vmctl_get_memreq(&who, &mem, &len, &wrflag, &who_s,
+ &mem_s, &requestor);
+
+ switch(r) {
+ case VMPTYPE_CHECK:
+ if(vm_isokendpt(who, &p) != OK)
+ vm_panic("do_memory: bad endpoint", who);
+ vmp = &vmproc[p];
+
+ r = handle_memory(vmp, mem, len, wrflag);
+ break;
+ case VMPTYPE_COWMAP:
+ r = map_memory(who_s, who, mem_s, mem, len, -1);
+ break;
+ case VMPTYPE_SMAP:
+ r = map_memory(who_s, who, mem_s, mem, len, wrflag);
+ break;
+ case VMPTYPE_SUNMAP:
+ r = unmap_memory(who_s, who, mem_s, mem, len, wrflag);
+ break;
+ default:
+ return;
+ }
if(sys_vmctl(requestor, VMCTL_MEMREQ_REPLY, r) != OK)
vm_panic("do_memory: sys_vmctl failed", r);
struct stat;
struct mem_map;
struct memory;
+struct vir_region;
+struct phys_region;
#include <minix/ipc.h>
#include <minix/endpoint.h>
_PROTOTYPE( int vfs_close, (struct vmproc *for_who, callback_t callback,
int fd));
+/* map_mem.c */
+_PROTOTYPE( int map_memory, (endpoint_t sour, endpoint_t dest,
+ vir_bytes virt_s, vir_bytes virt_d, vir_bytes length, int flag));
+_PROTOTYPE( int unmap_memory, (endpoint_t sour, endpoint_t dest,
+ vir_bytes virt_s, vir_bytes virt_d, vir_bytes length, int flag));
+
/* mmap.c */
_PROTOTYPE(int do_mmap, (message *msg) );
_PROTOTYPE(int do_munmap, (message *msg) );
_PROTOTYPE(int map_get_phys, (struct vmproc *vmp, vir_bytes addr, phys_bytes *r));
_PROTOTYPE(int map_get_ref, (struct vmproc *vmp, vir_bytes addr, u8_t *cnt));
+_PROTOTYPE(int map_copy_ph_block, (struct vmproc *vmp,
+ struct vir_region *region, struct phys_region *ph));
+_PROTOTYPE(void pb_unreferenced, (struct vir_region *region,
+ struct phys_region *pr));
#if SANITYCHECKS
_PROTOTYPE(void map_sanitycheck,(char *file, int line));
#endif
#define _SYSTEM 1
-#define VERBOSE 0
-
#include <minix/callnr.h>
#include <minix/com.h>
#include <minix/config.h>
FORWARD _PROTOTYPE(int map_ph_writept, (struct vmproc *vmp, struct vir_region *vr,
struct phys_region *pr));
-FORWARD _PROTOTYPE(int map_copy_ph_block, (struct vmproc *vmp, struct vir_region *region, struct phys_region *ph));
-
FORWARD _PROTOTYPE(struct vir_region *map_copy_region, (struct vmproc *vmp, struct vir_region *vr));
PRIVATE char *map_name(struct vir_region *vr)
/*===========================================================================*
* pb_unreferenced *
*===========================================================================*/
-void pb_unreferenced(struct vir_region *region, struct phys_region *pr)
+PUBLIC void pb_unreferenced(struct vir_region *region, struct phys_region *pr)
{
struct phys_block *pb;
int remap = 0;
vm_panic("strange phys flags", NO_NUM);
}
SLABFREE(pb);
- } else if(WRITABLE(region, pb)) {
- /* If a writable piece of physical memory is now only
- * referenced once, map it writable right away instead of
- * waiting for a page fault.
- */
- vm_assert(pb);
- vm_assert(pb->firstregion);
- vm_assert(!pb->firstregion->next_ph_list);
- vm_assert(pb->firstregion->ph == pb);
- vm_assert(pb->firstregion->ph == pb);
- if(map_ph_writept(pb->firstregion->parent->parent,
- pb->firstregion->parent, pb->firstregion) != OK) {
- vm_panic("pb_unreferenced: writept", NO_NUM);
- }
}
}
/*===========================================================================*
* map_copy_ph_block *
*===========================================================================*/
-PRIVATE int map_copy_ph_block(vmp, region, ph)
+PUBLIC int map_copy_ph_block(vmp, region, ph)
struct vmproc *vmp;
struct vir_region *region;
struct phys_region *ph;
if(r != OK)
printf("map_ph_writept failed\n");
} else {
- r = map_copy_ph_block(vmp, region, ph);
- if(r != OK)
- printf("map_copy_ph_block failed\n");
+ if(ph->ph->refcount > 0
+ && ph->ph->share_flag != PBSH_COW) {
+ printf("VM: write RO mapped pages.\n");
+ return EFAULT;
+ } else {
+ r = map_copy_ph_block(vmp, region, ph);
+ }
}
} else {
/* Pagefault in non-existing block. Map in new block. */
SANITYCHECK(SCL_FUNCTIONS);
if(changes < 1) {
+#if VERBOSE
printf("region start at 0x%lx offset 0x%lx len 0x%lx write %d\n",
region->vaddr, offset, length, write);
- vm_panic("no changes in map_handle_memory", NO_NUM);
+ printf("no changes in map_handle_memory\n");
+#endif
+ return EFAULT;
}
#if SANITYCHECKS
physr_iter iter;
physr_start_iter_least(vr->phys, &iter);
while((ph = physr_get_iter(&iter))) {
+ physr_incr_iter(&iter);
+
+ /* If this phys block is shared as SMAP, then do
+ * not update the page table. */
+ if(ph->ph->refcount > 1
+ && ph->ph->share_flag == PBSH_SMAP) {
+ continue;
+ }
+
if((r=map_ph_writept(vmp, vr, ph)) != OK) {
printf("VM: map_writept: failed\n");
return r;
}
- physr_incr_iter(&iter);
}
}
USE(pb, pb->refcount++;);
vm_assert(pb->refcount > 1);
+ /* If the phys block has been shared as SMAP,
+ * do the regular copy. */
+ if(pb->refcount > 2 && pb->share_flag == PBSH_SMAP) {
+ map_copy_ph_block(dst, newvr, new_ph);
+ } else {
+ pb->share_flag = PBSH_COW;
+ }
+
/* Get next new physregion */
physr_incr_iter(&iter_orig);
physr_incr_iter(&iter_new);
vir_bytes length; /* no. of contiguous bytes */
phys_bytes phys; /* physical memory */
u8_t refcount; /* Refcount of these pages */
+#define PBSH_COW 1
+#define PBSH_SMAP 2
+ u8_t share_flag; /* PBSH_COW or PBSH_SMAP */
/* first in list of phys_regions that reference this block */
struct phys_region *firstregion;
#define _SYSTEM 1
-#define VERBOSE 0
-
#include <minix/callnr.h>
#include <minix/com.h>
#include <minix/config.h>
base = mem_chunks[i].base;
size = mem_chunks[i].size;
limit = base + size;
- base = (base + CLICK_SIZE-1) & ~(long)(CLICK_SIZE-1);
- limit &= ~(long)(CLICK_SIZE-1);
+ base = (phys_bytes) (CLICK_CEIL(base));
+ limit = (phys_bytes) (CLICK_FLOOR(limit));
if (limit <= base) {
memp->base = memp->size = 0;
} else {
#define _SYSTEM 1
-#define VERBOSE 0
-
#include <minix/callnr.h>
#include <minix/com.h>
#include <minix/config.h>
--- /dev/null
+all: dstest subs
+ chmod +x down run
+
+dstest: dstest.c inc.h
+ cc -o $@ $< -lsys
+
+subs: subs.c inc.h
+ cc -o $@ $< -lsys
+
+run: all
+ sh run
+
+kill:
+ sh down
+
+clean:
+ rm -f dstest subs
+
--- /dev/null
+Test Program for DataServer
+
+How to run
+==========
+
+ 1. Type `make run` to prepare and run test.
+ 2. When done testing, type `make clean` to clean up.
+
+How the test works
+==================
+
+`dstest` tests the new DS API (excluding ds_subscribe() and ds_check()).
+test_u32, test_str, test_mem, test_label, and test_map test U32, STR, MEM, LABEL
+and MAP type respectively.
+
+Invalid invokation is tested as well. Erroneous conditions are tested only once.
+For example, publishing an entry with same label name, but without
+DSF_OVERWRITE set, is tested in test_u32 and nowhere else again.
+Type-specific features are always tested.
+
+`subs` tests ds_subscribe() and ds_check(). The server subscribes
+to a U32 type. When `dstest` runs, `subs` catches all the updates.
+
--- /dev/null
+#!/bin/sh
+
+service down dstest
+service down subs
--- /dev/null
+#include "inc.h"
+
+char *key_u32 = "test_u32";
+char *key_str = "test_str";
+char *key_mem = "test_mem";
+char *key_map = "test_map";
+char *key_label = "test_label";
+
+/*===========================================================================*
+ * test_u32 *
+ *===========================================================================*/
+void test_u32(void)
+{
+ int r;
+ unsigned long value;
+
+ /* Publish and retrieve. */
+ r = ds_publish_u32(key_u32, 1234, 0);
+ assert(r == OK);
+ r = ds_retrieve_u32(key_u32, &value);
+ assert(r == OK && value == 1234);
+
+ /* If dstest deletes 'test_u32' immediately after publishing it,
+ * subs will catch the event, but it can't check it immediately.
+ * So dstest will sleep 2 seconds to wait for subs to complete. */
+ sleep(2);
+
+ /* Publish again without DSF_OVERWRITE. */
+ r = ds_publish_u32(key_u32, 4321, 0);
+ assert(r == EEXIST);
+
+ /* Publish again with DSF_OVERWRITE to overwrite it. */
+ r = ds_publish_u32(key_u32, 4321, DSF_OVERWRITE);
+ assert(r == OK);
+ r = ds_retrieve_u32(key_u32, &value);
+ assert(r == OK && value == 4321);
+
+ /* Delete. */
+ r = ds_delete_u32(key_u32);
+ assert(r == OK);
+ r = ds_retrieve_u32(key_u32, &value);
+ assert(r == ESRCH);
+
+ printf("DSTEST: U32 test successful!\n");
+}
+
+/*===========================================================================*
+ * test_str *
+ *===========================================================================*/
+void test_str(void)
+{
+ int r;
+ char *string = "little";
+ char *longstring = "verylooooooongstring";
+ char buf[17];
+
+ r = ds_publish_str(key_str, string, 0);
+ assert(r == OK);
+
+ r = ds_retrieve_str(key_str, buf, 0);
+ assert(r == OK && strcmp(string, buf) == 0);
+
+ r = ds_delete_str(key_str);
+ assert(r == OK);
+
+ /* Publish a long string. */
+ r = ds_publish_str(key_str, longstring, 0);
+ assert(r == EINVAL);
+
+ printf("DSTEST: STRING test successful!\n");
+}
+
+/*===========================================================================*
+ * test_mem *
+ *===========================================================================*/
+void test_mem(void)
+{
+ char *string1 = "ok, this is a string";
+ char *string2 = "ok, this is a very looooong string";
+ size_t len1 = strlen(string1) + 1;
+ size_t len2 = strlen(string2) + 1;
+ char buf[100];
+ size_t get_len;
+ int r;
+
+ /* Publish and retrieve. */
+ r = ds_publish_mem(key_mem, string1, len1, 0);
+ assert(r == OK);
+ get_len = 100;
+ r = ds_retrieve_mem(key_mem, buf, &get_len);
+ assert(r == OK && strcmp(string1, buf) == 0);
+ assert(get_len == len1);
+
+ /* Let get_len=8, which is less than strlen(string1). */
+ get_len = 8;
+ r = ds_retrieve_mem(key_mem, buf, &get_len);
+ assert(r == OK && get_len == 8);
+
+ /* Publish again to overwrite with a bigger memory range. */
+ r = ds_publish_mem(key_mem, string2, len2, DSF_OVERWRITE);
+ assert(r == OK);
+
+ get_len = 100;
+ r = ds_retrieve_mem(key_mem, buf, &get_len);
+ assert(r == OK && strcmp(string2, buf) == 0);
+ assert(get_len == len2);
+
+ r = ds_delete_mem(key_mem);
+ assert(r == OK);
+
+ printf("DSTEST: MEM test successful!\n");
+}
+
+/*===========================================================================*
+ * test_label *
+ *===========================================================================*/
+void test_label(void)
+{
+ int r;
+ char get_label[DS_MAX_KEYLEN];
+ unsigned long num;
+
+ /* Publish and retrieve. */
+ r = ds_publish_label(key_label, 1234, 0);
+ assert(r == OK);
+ r = ds_retrieve_label_num(key_label, &num);
+ assert(r == OK && num == 1234);
+
+ /* Here are the differences w.r.t. U32. */
+ r = ds_publish_label("hello", 1234, 0);
+ assert(r == EEXIST);
+ r = ds_retrieve_label_name(get_label, 1234);
+ assert(r == OK && strcmp(key_label, get_label) == 0);
+
+ r = ds_delete_label(key_label);
+ assert(r == OK);
+
+ printf("DSTEST: LABEL test successful!\n");
+}
+
+/*===========================================================================*
+ * test_map *
+ *===========================================================================*/
+void test_map(void)
+{
+ char buf_buf[CLICK_SIZE * 2];
+ char buf_buf2[CLICK_SIZE * 2];
+ char *buf, *buf2;
+ char get_buf[CLICK_SIZE];
+ int *p;
+ volatile int *p2;
+ int *get_p;
+ size_t get_len;
+ int is;
+ int r;
+
+ buf = (char*) CLICK_CEIL(buf_buf);
+ buf2 = (char*) CLICK_CEIL(buf_buf2);
+
+ p = (int *)buf;
+ p2 = (int *)buf2;
+ get_p = (int *)get_buf;
+
+ *p = 1;
+ r = ds_publish_map(key_map, buf, CLICK_SIZE, 0);
+ assert(r == OK);
+
+ r = ds_snapshot_map(key_map, &is);
+ assert(r == OK);
+
+ /* Copy the mapped memory range.
+ * Set *p=2, then the mapped memory range should change too
+ * and *get_p should be 2.
+ */
+ *p = 2;
+ get_len = CLICK_SIZE;
+ r = ds_retrieve_map(key_map, get_buf, &get_len, 0, DSMF_COPY_MAPPED);
+ assert(r == OK && get_len == CLICK_SIZE && *get_p == 2);
+
+ /* Copy snapshot, where *get_p should still be 1. */
+ get_len = CLICK_SIZE;
+ r = ds_retrieve_map(key_map, get_buf, &get_len, is, DSMF_COPY_SNAPSHOT);
+ assert(r == OK && get_len == CLICK_SIZE && *get_p == 1);
+
+ /* Map the mapped memory range to @buf2, then set *p=3, which
+ * in turn should let *p2=3.
+ */
+ get_len = CLICK_SIZE;
+ r = ds_retrieve_map(key_map, buf2, &get_len, 0, DSMF_MAP_MAPPED);
+ assert(r == OK && get_len == CLICK_SIZE);
+ *p = 3;
+ assert(*p2 == 3);
+
+ r = ds_delete_map(key_map);
+ assert(r == OK);
+
+ printf("DSTEST: MAP test successful!\n");
+}
+
+/* SEF functions and variables. */
+FORWARD _PROTOTYPE( void sef_local_startup, (void) );
+
+/*===========================================================================*
+ * main *
+ *===========================================================================*/
+int main(void)
+{
+ /* SEF local startup. */
+ sef_local_startup();
+
+ /* Run all the tests. */
+ test_u32();
+ test_str();
+ test_mem();
+ test_map();
+ test_label();
+
+ return 0;
+}
+
+
+/*===========================================================================*
+ * sef_local_startup *
+ *===========================================================================*/
+PRIVATE void sef_local_startup()
+{
+ /* Let SEF perform startup. */
+ sef_startup();
+}
+
--- /dev/null
+#define _MINIX
+#define _SYSTEM
+#include <stdio.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <minix/config.h>
+#include <minix/com.h>
+#include <minix/type.h>
+#include <minix/const.h>
+#include <minix/endpoint.h>
+#include <minix/ds.h>
+#include <minix/syslib.h>
--- /dev/null
+#!/bin/sh
+
+PWD=`pwd`
+
+service up ${PWD}/subs -config ${PWD}/system.conf -script ${PWD}/down
+service up ${PWD}/dstest -config ${PWD}/system.conf -script ${PWD}/down
--- /dev/null
+#include "inc.h"
+
+char *key_u32 = "test_u32";
+
+/* SEF functions and variables. */
+FORWARD _PROTOTYPE( void sef_local_startup, (void) );
+
+/*===========================================================================*
+ * main *
+ *===========================================================================*/
+int main(void)
+{
+ int r;
+ message mess;
+ char key[DS_MAX_KEYLEN];
+ int type;
+ unsigned long num;
+ char string[17];
+ char buf[1000];
+ size_t length = 1000;
+
+ /* SEF local startup. */
+ sef_local_startup();
+
+ /* Subscribe. */
+ r = ds_subscribe(key_u32, DSF_INITIAL);
+ if(r != OK && r != EEXIST) {
+ printf("SUBSCRIBER: error in ds_subscribe: %d\n", r);
+ return -1;
+ }
+
+ while(1) {
+ /* Wait for a message. */
+ r = sef_receive(ANY, &mess);
+ if(r != OK) {
+ printf("SUBSCRIBER: sef_receive failed.\n");
+ return 1;
+ }
+ /* Only handle notifications from DS. */
+ if(mess.m_source != DS_PROC_NR)
+ continue;
+
+ /* Check which one was changed. */
+ r = ds_check(key, &type);
+ if(r == ENOENT) {
+ printf("SUBSCRIBER: the key %s was deleted.\n",
+ key);
+ continue;
+ }
+ if(r != OK) {
+ printf("SUBSCRIBER: error in ds_check.\n");
+ continue;
+ }
+
+ /* Retrieve the entry. */
+ printf("SUBSCRIBER: key: %s, ", key);
+ switch(type) {
+ case DSF_TYPE_U32:
+ r = ds_retrieve_u32(key, &num);
+ if(r != OK)
+ printf("error in ds_retrieve_u32.\n");
+ printf("U32: %d\n", num);
+ break;
+ case DSF_TYPE_STR:
+ r = ds_retrieve_str(key, string, 0);
+ if(r != OK)
+ printf("error in ds_retrieve_str.\n");
+ printf("STR: %s\n", string);
+ break;
+ case DSF_TYPE_MEM:
+ r = ds_retrieve_mem(key, buf, &length);
+ if(r != OK)
+ printf("error in ds_retrieve_mem.\n");
+ break;
+ case DSF_TYPE_MAP:
+ break;
+ default:
+ printf("error in type! %d\n", type);
+ }
+ }
+
+ return 0;
+}
+
+/*===========================================================================*
+ * sef_local_startup *
+ *===========================================================================*/
+PRIVATE void sef_local_startup()
+{
+ /* Let SEF perform startup. */
+ sef_startup();
+}
+
--- /dev/null
+
+service dstest
+{
+ system
+ UMAP
+ PRIVCTL
+ SAFEMAP
+ SETGRANT
+ GETINFO
+ SYSCTL
+ ;
+ uid 0;
+};
+
+service subs
+{
+ system
+ UMAP
+ PRIVCTL
+ SETGRANT
+ GETINFO
+ SYSCTL
+ ;
+ uid 0;
+};
--- /dev/null
+all: requestor grantor 1fifo 2fifo
+ chmod +x down run
+
+requestor: requestor.c inc.h
+ cc -o $@ $< -lsys
+
+grantor: grantor.c inc.h
+ cc -o $@ $< -lsys
+
+1fifo 2fifo:
+ mkfifo $@
+
+run: all
+ sh run
+
+kill:
+ sh down
+
+clean:
+ rm -f grantor requestor 1fifo 2fifo
+
--- /dev/null
+Test Program for Safecopy with or without COW
+
+How to run
+==========
+
+Test safecopy with COW:
+ 1. Set USE_COW_SAFECOPY to 1 in /usr/src/kernel/system/do_safecopy.c
+ 2. Type `make run` to prepare and run test.
+ 3. When done testing, type `make clean` to clean up.
+
+Test safecopy without COW:
+ 1. Set USE_COW_SAFECOPY to 0 in /usr/src/kernel/system/do_safecopy.c
+ 2. Type `make run` to prepare and run test.
+ 3. When done testing, type `make clean` to clean up.
+
+If you want to modify the test buffer size:
+ 1. Modify TEST_PAGE_NUM in inc.h
+ 2. Modify TEST_PAGE_SHIFT in inc.h
+
--- /dev/null
+#!/bin/sh
+
+service down grantor
+service down requestor
+
--- /dev/null
+#include "inc.h"
+
+char buf_buf[BUF_SIZE + CLICK_SIZE];
+
+/* SEF functions and variables. */
+FORWARD _PROTOTYPE( void sef_local_startup, (void) );
+
+/*===========================================================================*
+ * main *
+ *===========================================================================*/
+int main(int argc, char **argv)
+{
+ endpoint_t ep_self, ep_requestor;
+ int fid_send, fid_get;
+ cp_grant_id_t gid;
+ char *buf;
+ int i;
+
+ /* SEF local startup. */
+ env_setargs(argc, argv);
+ sef_local_startup();
+
+ /* Prepare work. */
+ buf = (char*) CLICK_CEIL(buf_buf);
+ fid_send = open(FIFO_GRANTOR, O_WRONLY);
+ fid_get = open(FIFO_REQUESTOR, O_RDONLY);
+ if(fid_get < 0 || fid_send < 0) {
+ printf("GRANTOR: can't open fifo files.\n");
+ return 1;
+ }
+ buf[0] = BUF_START;
+
+ /* Get the requestor's endpoint. */
+ read(fid_get, &ep_requestor, sizeof(ep_requestor));
+ dprint("GRANTOR: getting requestor's endpoint: %d\n", ep_requestor);
+
+ /* Grant. */
+ gid = cpf_grant_direct(ep_requestor, (long)buf, BUF_SIZE,
+ CPF_READ | CPF_WRITE);
+ ep_self = getprocnr();
+ dprint("GRANTOR: sending my endpoint %d and gid %d\n", ep_self, gid);
+ write(fid_send, &ep_self, sizeof(ep_self));
+ write(fid_send, &gid, sizeof(gid));
+
+ /* Wait till requestor is done. */
+ FIFO_WAIT(fid_get);
+
+ return 0;
+}
+
+/*===========================================================================*
+ * sef_local_startup *
+ *===========================================================================*/
+PRIVATE void sef_local_startup()
+{
+ /* Let SEF perform startup. */
+ sef_startup();
+}
+
--- /dev/null
+#define _SYSTEM
+#define _MINIX
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <minix/config.h>
+#include <minix/com.h>
+#include <minix/type.h>
+#include <minix/const.h>
+#include <minix/endpoint.h>
+#include <minix/safecopies.h>
+#include <minix/syslib.h>
+#include <minix/sysutil.h>
+#include <errno.h>
+
+/* TEST_PAGE_SHIFT =
+ * log2(CLICK_SIZE * TEST_PAGE_NUM) = CLICK_SHIFT + log2(TEST_PAGE_NUM)
+ */
+#define TEST_PAGE_NUM 8
+#define TEST_PAGE_SHIFT 15
+
+#define BUF_SIZE (TEST_PAGE_NUM * CLICK_SIZE)
+#define BUF_START 100
+
+#define FIFO_REQUESTOR "/usr/src/test/safecopy/1fifo"
+#define FIFO_GRANTOR "/usr/src/test/safecopy/2fifo"
+
+#define FIFO_WAIT(fid) { \
+ int a; \
+ if(read(fid, &a, sizeof(a)) != sizeof(a)) \
+ panic(__FILE__, "FIFO_WAIT failed", NO_NUM); \
+}
+#define FIFO_NOTIFY(fid) { \
+ int a = 1; \
+ if(write(fid, &a, sizeof(a)) != sizeof(a)) \
+ panic(__FILE__, "FIFO_NOTIFY failed", NO_NUM); \
+}
+
+#define DEBUG 0
+#if DEBUG
+# define dprint printf
+#else
+# define dprint (void)
+#endif
+
--- /dev/null
+#include "inc.h"
+
+char buf_buf[BUF_SIZE + CLICK_SIZE];
+
+endpoint_t ep_granter;
+int gid;
+char *buf;
+
+/*===========================================================================*
+ * test *
+ *===========================================================================*/
+int test(size_t size)
+{
+ u32_t low1, high1;
+ u32_t low2, high2;
+ int r;
+
+ /* Timing. */
+ read_tsc(&high1, &low1);
+ r = sys_safecopyfrom(ep_granter, gid, 0, (long)buf, size, D);
+ read_tsc(&high2, &low2);
+ if(r != OK) {
+ printf("REQUESTOR: error in safecopy: %d\n", r);
+ return r;
+ }
+ printf("REQUESTOR: SAFECOPY 0x%-8x - %d\n", size, low2 - low1);
+
+ /* Test. */
+ if(buf[0] != BUF_START) {
+ printf("REQUESTOR: error in safecopy!\n");
+ printf(" size, value: %d, %d\n", size, buf[0]);
+ return r;
+ }
+
+ return OK;
+}
+
+/* SEF functions and variables. */
+FORWARD _PROTOTYPE( void sef_local_startup, (void) );
+
+/*===========================================================================*
+ * main *
+ *===========================================================================*/
+int main(int argc, char **argv)
+{
+ endpoint_t ep_self;
+ int fid_send, fid_get;
+ int i;
+
+ /* SEF local startup. */
+ env_setargs(argc, argv);
+ sef_local_startup();
+
+ /* Prepare work. */
+ buf = (char*) CLICK_CEIL(buf_buf);
+ fid_get = open(FIFO_GRANTOR, O_RDONLY);
+ fid_send = open(FIFO_REQUESTOR, O_WRONLY);
+ if(fid_get < 0 || fid_send < 0) {
+ printf("REQUESTOR: can't open fifo files.\n");
+ return 1;
+ }
+
+ /* Sending the endpoint to the granter, in order to let him
+ * create the grant.
+ */
+ ep_self = getprocnr();
+ write(fid_send, &ep_self, sizeof(ep_self));
+ dprint("REQUESTOR: sending my endpoint: %d\n", ep_self);
+
+ /* Getting the granter's endpoint and gid. */
+ read(fid_get, &ep_granter, sizeof(ep_granter));
+ read(fid_get, &gid, sizeof(gid));
+ dprint("REQUESTOR: getting granter's endpoint %d and gid %d\n",
+ ep_granter, gid);
+
+ /* Test SAFECOPY. */
+ for(i = 0; i <= TEST_PAGE_SHIFT; i++) {
+ if(test(1 << i) != OK)
+ break;
+ }
+
+ /* Notify grantor we are done. */
+ FIFO_NOTIFY(fid_send);
+
+ return 0;
+}
+
+/*===========================================================================*
+ * sef_local_startup *
+ *===========================================================================*/
+PRIVATE void sef_local_startup()
+{
+ /* Let SEF perform startup. */
+ sef_startup();
+}
+
--- /dev/null
+#!/bin/sh
+
+PWD=`pwd`
+
+service up ${PWD}/grantor -config ${PWD}/system.conf -script ${PWD}/down
+service up ${PWD}/requestor -config ${PWD}/system.conf -script ${PWD}/down
+
--- /dev/null
+
+service requestor
+{
+ system
+ SAFECOPYFROM
+ SAFECOPYTO
+ SAFEMAP
+ SAFEREVMAP
+ SAFEUNMAP
+ UMAP
+ PRIVCTL
+ SETGRANT
+ GETINFO
+ SYSCTL
+ ;
+ uid 0;
+};
+
+service grantor
+{
+ system
+ SAFECOPYFROM
+ SAFECOPYTO
+ SAFEMAP
+ SAFEREVMAP
+ SAFEUNMAP
+ UMAP
+ PRIVCTL
+ SETGRANT
+ GETINFO
+ SYSCTL
+ ;
+ uid 0;
+};
--- /dev/null
+all: requestor grantor 1fifo 2fifo
+ chmod +x down run
+
+requestor: requestor.c inc.h
+ cc -o $@ $< -lsys
+
+grantor: grantor.c inc.h
+ cc -o $@ $< -lsys
+
+1fifo 2fifo:
+ mkfifo $@
+
+run: all
+ sh run
+
+kill:
+ sh down
+
+clean:
+ rm -f grantor requestor 1fifo 2fifo
+
--- /dev/null
+Test Program for Safemap
+
+How to run
+==========
+
+ 1. Type `make run` to prepare and run test.
+ 2. When done testing, type `make clean` to clean up.
+
--- /dev/null
+#!/bin/sh
+
+service down grantor
+service down requestor
--- /dev/null
+#include "inc.h"
+
+char buf_buf[BUF_SIZE + CLICK_SIZE];
+
+int fid_send, fid_get;
+
+/* SEF functions and variables. */
+FORWARD _PROTOTYPE( void sef_local_startup, (void) );
+
+/*===========================================================================*
+ * main *
+ *===========================================================================*/
+int main(int argc, char **argv)
+{
+ endpoint_t ep_self, ep_requestor, ep_child;
+ cp_grant_id_t gid;
+ int i, r, pid;
+ char *buf;
+ int status;
+
+ /* SEF local startup. */
+ env_setargs(argc, argv);
+ sef_local_startup();
+
+ /* Prepare work. */
+ buf = (char*) CLICK_CEIL(buf_buf);
+ fid_send = open(FIFO_GRANTOR, O_WRONLY);
+ fid_get = open(FIFO_REQUESTOR, O_RDONLY);
+ if(fid_get < 0 || fid_send < 0) {
+ printf("GRANTOR: can't open fifo files.\n");
+ return 1;
+ }
+
+ /* Get the requestor's endpoint. */
+ read(fid_get, &ep_requestor, sizeof(ep_requestor));
+ dprint("GRANTOR: getting requestor's endpoint: %d\n", ep_requestor);
+
+ /* Grant. */
+ gid = cpf_grant_direct(ep_requestor, (long)buf, BUF_SIZE,
+ CPF_READ | CPF_WRITE | CPF_MAP);
+ ep_self = getprocnr();
+ dprint("GRANTOR: sending my endpoint %d and gid %d\n", ep_self, gid);
+ write(fid_send, &ep_self, sizeof(ep_self));
+ write(fid_send, &gid, sizeof(gid));
+
+ /* Test MAP. */
+ buf[0] = BUF_START_GRANTOR;
+ FIFO_NOTIFY(fid_send);
+ FIFO_WAIT(fid_get);
+ CHECK_TEST("GRANTOR", buf[0], BUF_START_REQUESTOR, "MAP");
+
+ /* Test UNMAP. */
+ buf[0] = BUF_START_GRANTOR;
+ FIFO_NOTIFY(fid_send);
+ FIFO_WAIT(fid_get);
+ CHECK_TEST("GRANTOR", buf[0], BUF_START_GRANTOR, "UNMAP");
+
+ /* Test REVOKE. */
+ r = sys_saferevmap_gid(gid);
+ if(r != OK) {
+ printf("GRANTOR: error in sys_saferevmap_gid: %d\n", r);
+ return 1;
+ }
+ buf[0] = BUF_START_GRANTOR+1;
+ FIFO_NOTIFY(fid_send);
+ FIFO_WAIT(fid_get);
+ CHECK_TEST("GRANTOR", buf[0], BUF_START_GRANTOR+1, "REVOKE");
+
+ /* Test SMAP_COW. */
+ FIFO_NOTIFY(fid_send);
+ FIFO_WAIT(fid_get);
+ buf[0] = BUF_START_GRANTOR;
+ FIFO_NOTIFY(fid_send);
+ FIFO_WAIT(fid_get);
+ CHECK_TEST("GRANTOR", buf[0], BUF_START_GRANTOR, "SMAP_COW");
+
+ /* Test COW_SMAP. */
+ r = sys_saferevmap_gid(gid);
+ if(r != OK) {
+ printf("GRANTOR: error in sys_saferevmap_gid: %d\n", r);
+ return 1;
+ }
+ buf[0] = BUF_START_GRANTOR+1;
+ pid = fork();
+ if(pid < 0) {
+ printf("GRANTOR: error in fork.\n");
+ return 1;
+ }
+ if(pid == 0) {
+ buf[0] = BUF_START_GRANTOR+2;
+ exit(0);
+ }
+ FIFO_NOTIFY(fid_send);
+ FIFO_WAIT(fid_get);
+ ep_child = getnprocnr(pid);
+ if ((r = sys_privctl(ep_child, SYS_PRIV_SET_USER, NULL)) != OK) {
+ printf("GRANTOR: unable to set privileges: %d\n", r);
+ return 1;
+ }
+ if ((r = sys_privctl(ep_child, SYS_PRIV_ALLOW, NULL)) != OK) {
+ printf("GRANTOR: child process can't run: %d\n", r);
+ return 1;
+ }
+ wait(&status);
+ FIFO_NOTIFY(fid_send);
+ CHECK_TEST("GRANTOR", buf[0], BUF_START_GRANTOR+1, "COW_SMAP");
+
+ /* Test COW_SMAP2 (with COW safecopy). */
+ r = sys_saferevmap_gid(gid);
+ if(r != OK) {
+ printf("GRANTOR: error in sys_saferevmap_gid: %d\n", r);
+ return 1;
+ }
+ FIFO_NOTIFY(fid_send);
+ FIFO_WAIT(fid_get);
+ CHECK_TEST("GRANTOR", buf[0], BUF_START_REQUESTOR, "COW_SMAP2");
+
+ return 0;
+}
+
+/*===========================================================================*
+ * sef_local_startup *
+ *===========================================================================*/
+PRIVATE void sef_local_startup()
+{
+ /* Let SEF perform startup. */
+ sef_startup();
+}
+
--- /dev/null
+#define _SYSTEM
+#define _MINIX
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <minix/config.h>
+#include <minix/com.h>
+#include <minix/type.h>
+#include <minix/const.h>
+#include <minix/endpoint.h>
+#include <minix/safecopies.h>
+#include <minix/syslib.h>
+#include <minix/sysutil.h>
+#include <errno.h>
+
+#define TEST_PAGE_NUM 4
+#define BUF_SIZE (TEST_PAGE_NUM * CLICK_SIZE)
+#define BUF_START_REQUESTOR 10
+#define BUF_START_GRANTOR 20
+
+#define FIFO_REQUESTOR "/usr/src/test/safemap/1fifo"
+#define FIFO_GRANTOR "/usr/src/test/safemap/2fifo"
+
+#define FIFO_WAIT(fid) { \
+ int a; \
+ if(read(fid, &a, sizeof(a)) != sizeof(a)) \
+ panic(__FILE__, "FIFO_WAIT failed", NO_NUM); \
+}
+#define FIFO_NOTIFY(fid) { \
+ int a = 1; \
+ if(write(fid, &a, sizeof(a)) != sizeof(a)) \
+ panic(__FILE__, "FIFO_NOTIFY failed", NO_NUM); \
+}
+
+#define CHECK_TEST(who, result, expected, test_name) { \
+ printf("%-9s: test %s %s\n", who, test_name, \
+ (expected == result ? "succeeded" : "failed")); \
+ if(expected != result) { \
+ exit(1); \
+ } \
+}
+
+#define DEBUG 0
+#if DEBUG
+# define dprint printf
+#else
+# define dprint (void)
+#endif
+
--- /dev/null
+#include "inc.h"
+
+char buf_buf[BUF_SIZE + CLICK_SIZE];
+
+endpoint_t ep_granter;
+cp_grant_id_t gid;
+char *buf;
+int fid_send, fid_get;
+
+/* SEF functions and variables. */
+FORWARD _PROTOTYPE( void sef_local_startup, (void) );
+
+/*===========================================================================*
+ * main *
+ *===========================================================================*/
+int main(int argc, char **argv)
+{
+ endpoint_t ep_self, ep_child;
+ size_t size = BUF_SIZE;
+ int i, r, pid;
+ int status;
+
+ /* SEF local startup. */
+ env_setargs(argc, argv);
+ sef_local_startup();
+
+ /* Prepare work. */
+ buf = (char*) CLICK_CEIL(buf_buf);
+ fid_get = open(FIFO_GRANTOR, O_RDONLY);
+ fid_send = open(FIFO_REQUESTOR, O_WRONLY);
+ if(fid_get < 0 || fid_send < 0) {
+ printf("REQUESTOR: can't open fifo files.\n");
+ return 1;
+ }
+
+ /* Send the endpoint to the granter, in order to let him to
+ * create the grant.
+ */
+ ep_self = getprocnr();
+ write(fid_send, &ep_self, sizeof(ep_self));
+ dprint("REQUESTOR: sending my endpoint: %d\n", ep_self);
+
+ /* Get the granter's endpoint and gid. */
+ read(fid_get, &ep_granter, sizeof(ep_granter));
+ read(fid_get, &gid, sizeof(gid));
+ dprint("REQUESTOR: getting granter's endpoint %d and gid %d\n",
+ ep_granter, gid);
+
+ /* Test MAP. */
+ FIFO_WAIT(fid_get);
+ r = sys_safemap(ep_granter, gid, 0, (long)buf, size, D, 1);
+ if(r != OK) {
+ printf("REQUESTOR: error in sys_safemap: %d\n", r);
+ return 1;
+ }
+ CHECK_TEST("REQUESTOR", buf[0], BUF_START_GRANTOR, "MAP");
+ buf[0] = BUF_START_REQUESTOR;
+ r = sys_safeunmap(D, (long)buf);
+ if(r != OK) {
+ printf("REQUESTOR: error in sys_safeunmap: %d\n", r);
+ return 1;
+ }
+ FIFO_NOTIFY(fid_send);
+
+ /* Test UNMAP. */
+ FIFO_WAIT(fid_get);
+ CHECK_TEST("REQUESTOR", buf[0], BUF_START_REQUESTOR, "UNMAP");
+ r = sys_safemap(ep_granter, gid, 0, (long)buf, size, D, 1);
+ if(r != 0) {
+ printf("REQUESTOR: error in sys_safemap: %d\n", r);
+ return 1;
+ }
+ FIFO_NOTIFY(fid_send);
+
+ /* Test REVOKE. */
+ FIFO_WAIT(fid_get);
+ CHECK_TEST("REQUESTOR", buf[0], BUF_START_GRANTOR, "REVOKE");
+ buf[0] = BUF_START_REQUESTOR;
+ FIFO_NOTIFY(fid_send);
+
+ /* Test SMAP_COW. */
+ FIFO_WAIT(fid_get);
+ r = sys_safemap(ep_granter, gid, 0, (long)buf, size, D, 1);
+ if(r != OK) {
+ printf("REQUESTOR: error in sys_safemap: %d\n", r);
+ return 1;
+ }
+ buf[0] = BUF_START_REQUESTOR;
+ pid = fork();
+ if(pid < 0) {
+ printf("REQUESTOR: error in fork\n");
+ return 1;
+ }
+ if(pid == 0) {
+ exit(buf[0] != BUF_START_REQUESTOR);
+ }
+ FIFO_NOTIFY(fid_send);
+ FIFO_WAIT(fid_get);
+ ep_child = getnprocnr(pid);
+ if ((r = sys_privctl(ep_child, SYS_PRIV_SET_USER, NULL)) != OK) {
+ printf("REQUESTOR: unable to set privileges: %d\n", r);
+ return 1;
+ }
+ if ((r = sys_privctl(ep_child, SYS_PRIV_ALLOW, NULL)) != OK) {
+ printf("REQUESTOR: child process can't run: %d\n", r);
+ return 1;
+ }
+ wait(&status);
+ FIFO_NOTIFY(fid_send);
+ CHECK_TEST("REQUESTOR", buf[0], BUF_START_GRANTOR, "SMAP_COW");
+ CHECK_TEST("REQUESTOR", 1, WIFEXITED(status)
+ && (WEXITSTATUS(status) == 0), "SMAP_COW child");
+
+ /* Test COW_SMAP. */
+ FIFO_WAIT(fid_get);
+ buf[0] = BUF_START_REQUESTOR;
+ r = sys_safemap(ep_granter, gid, 0, (long)buf, size, D, 1);
+ if(r != OK) {
+ printf("REQUESTOR: error in sys_safemap: %d\n", r);
+ return 1;
+ }
+ FIFO_NOTIFY(fid_send);
+ FIFO_WAIT(fid_get);
+ CHECK_TEST("REQUESTOR", buf[0], BUF_START_GRANTOR+1, "COW_SMAP");
+
+ /* Test COW_SMAP2 (with COW safecopy). */
+ FIFO_WAIT(fid_get);
+ buf[0] = BUF_START_REQUESTOR;
+ r = sys_safecopyto(ep_granter, gid, 0, (long)buf, size, D);
+ if(r != OK) {
+ printf("REQUESTOR: error in sys_safecopyto: %d\n", r);
+ return 1;
+ }
+ r = sys_safemap(ep_granter, gid, 0, (long)buf, size, D, 1);
+ if(r != OK) {
+ printf("REQUESTOR: error in sys_safemap: %d\n", r);
+ return 1;
+ }
+ FIFO_NOTIFY(fid_send);
+ CHECK_TEST("REQUESTOR", buf[0], BUF_START_REQUESTOR, "COW_SMAP2");
+
+ return 0;
+}
+
+/*===========================================================================*
+ * sef_local_startup *
+ *===========================================================================*/
+PRIVATE void sef_local_startup()
+{
+ /* Let SEF perform startup. */
+ sef_startup();
+}
+
--- /dev/null
+#!/bin/sh
+
+PWD=`pwd`
+
+service up ${PWD}/grantor -config ${PWD}/system.conf -script ${PWD}/down
+service up ${PWD}/requestor -config ${PWD}/system.conf -script ${PWD}/down
--- /dev/null
+
+service requestor
+{
+ system
+ SAFECOPYFROM
+ SAFECOPYTO
+ SAFEMAP
+ SAFEREVMAP
+ SAFEUNMAP
+ UMAP
+ PRIVCTL
+ SETGRANT
+ GETINFO
+ SYSCTL
+ ;
+ uid 0;
+};
+
+service grantor
+{
+ system
+ SAFECOPYFROM
+ SAFECOPYTO
+ SAFEMAP
+ SAFEREVMAP
+ SAFEUNMAP
+ UMAP
+ PRIVCTL
+ SETGRANT
+ GETINFO
+ SYSCTL
+ ;
+ uid 0;
+};
--- /dev/null
+all: requestor grantor 1fifo 2fifo
+ chmod +x down run
+
+requestor: requestor.c inc.h
+ cc -o $@ $< -lsys
+
+grantor: grantor.c inc.h
+ cc -o $@ $< -lsys
+
+1fifo 2fifo:
+ mkfifo $@
+
+run: all
+ sh run
+
+kill:
+ sh down
+
+clean:
+ rm -f grantor requestor 1fifo 2fifo
+
--- /dev/null
+Performance Test Program for Safecopy and Safemap
+
+How to run
+==========
+
+ 1. Set USE_COW_SAFECOPY to 1 or 0 in kernel/system/do_safecopy.c
+ to run safecopy tests with or without COW optimization.
+ 2. Type `make run` to prepare and run tests. Configuration parameters
+ for performance tests are in ./run.
+ 3. When done testing, type `make clean` to clean up.
+
--- /dev/null
+#!/bin/sh
+
+service down grantor
+service down requestor
+
--- /dev/null
+#include "inc.h"
+
+char buf_buf[BUF_SIZE + CLICK_SIZE];
+
+int fid_send, fid_get;
+
+/* SEF functions and variables. */
+FORWARD _PROTOTYPE( void sef_local_startup, (void) );
+
+/*===========================================================================*
+ * main *
+ *===========================================================================*/
+int main(int argc, char **argv)
+{
+ endpoint_t ep_self, ep_requestor, ep_child;
+ cp_grant_id_t gid;
+ int i, r, pid;
+ char *buf;
+ int status;
+
+ /* SEF local startup. */
+ env_setargs(argc, argv);
+ sef_local_startup();
+
+ /* Prepare work. */
+ buf = (char*) CLICK_CEIL(buf_buf);
+ fid_send = open(FIFO_GRANTOR, O_WRONLY);
+ fid_get = open(FIFO_REQUESTOR, O_RDONLY);
+ if(fid_get < 0 || fid_send < 0) {
+ printf("GRANTOR: can't open fifo files.\n");
+ return 1;
+ }
+
+ /* Get the requestor's endpoint. */
+ read(fid_get, &ep_requestor, sizeof(ep_requestor));
+ dprint("GRANTOR: getting requestor's endpoint: %d\n", ep_requestor);
+
+ /* Grant. */
+ gid = cpf_grant_direct(ep_requestor, (long)buf, BUF_SIZE,
+ CPF_READ | CPF_WRITE | CPF_MAP);
+ ep_self = getprocnr();
+ dprint("GRANTOR: sending my endpoint %d and gid %d\n", ep_self, gid);
+ write(fid_send, &ep_self, sizeof(ep_self));
+ write(fid_send, &gid, sizeof(gid));
+
+ /* Test safemap. */
+ buf[0] = 0;
+ FIFO_NOTIFY(fid_send);
+ FIFO_WAIT(fid_get);
+
+ return 0;
+}
+
+/*===========================================================================*
+ * sef_local_startup *
+ *===========================================================================*/
+PRIVATE void sef_local_startup()
+{
+ /* Let SEF perform startup. */
+ sef_startup();
+}
+
--- /dev/null
+#define _SYSTEM
+#define _MINIX
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <minix/config.h>
+#include <minix/com.h>
+#include <minix/type.h>
+#include <minix/const.h>
+#include <minix/endpoint.h>
+#include <minix/safecopies.h>
+#include <minix/syslib.h>
+#include <minix/sysutil.h>
+#include <errno.h>
+
+#define TEST_PAGE_NUM 50
+#define BUF_SIZE (TEST_PAGE_NUM * CLICK_SIZE)
+
+#define NR_TEST_ITERATIONS 100
+
+#define FIFO_REQUESTOR "/usr/src/test/safeperf/1fifo"
+#define FIFO_GRANTOR "/usr/src/test/safeperf/2fifo"
+
+#define FIFO_WAIT(fid) { \
+ int a; \
+ if(read(fid, &a, sizeof(a)) != sizeof(a)) \
+ panic(__FILE__, "FIFO_WAIT failed", NO_NUM); \
+}
+#define FIFO_NOTIFY(fid) { \
+ int a = 1; \
+ if(write(fid, &a, sizeof(a)) != sizeof(a)) \
+ panic(__FILE__, "FIFO_NOTIFY failed", NO_NUM); \
+}
+
+#define REPORT_TEST(who, test_name, diff) { \
+ printf("%-9s: test %s took an average of %d.%dus per page\n", \
+ who, test_name, (int)diff, ((int)(diff*1000))%1000); \
+}
+
+#define DEBUG 0
+#if DEBUG
+# define dprint printf
+#else
+# define dprint (void)
+#endif
+
--- /dev/null
+#include "inc.h"
+
+char buf_buf[BUF_SIZE + CLICK_SIZE];
+
+endpoint_t ep_granter;
+cp_grant_id_t gid;
+char *buf;
+int fid_send, fid_get;
+
+/* SEF functions and variables. */
+FORWARD _PROTOTYPE( void sef_local_startup, (void) );
+
+/*===========================================================================*
+ * read_write_buff *
+ *===========================================================================*/
+void read_write_buff(char* buff, int size, int is_write)
+{
+ int i;
+ char c;
+
+ if(size % CLICK_SIZE != 0) {
+ panic("REQUESTOR", "buff_size not page aligned", NO_NUM);
+ }
+ if(is_write) {
+ for(i=0;i<size;i+=CLICK_SIZE) buff[i] = 1;
+ }
+ else {
+ for(i=0;i<size;i+=CLICK_SIZE) c = buff[i];
+ }
+}
+
+/*===========================================================================*
+ * exit_usage *
+ *===========================================================================*/
+void exit_usage(void)
+{
+ printf("Usage: requestor pages=<nr_pages> map=<0|1> write=<0|1>\n");
+ exit(1);
+}
+
+/*===========================================================================*
+ * main *
+ *===========================================================================*/
+int main(int argc, char **argv)
+{
+ endpoint_t ep_self, ep_child;
+ size_t size = BUF_SIZE;
+ int i, r, pid;
+ int status;
+ u64_t start, end, diff;
+ double micros;
+ char nr_pages_str[10], is_map_str[2], is_write_str[2];
+ int nr_pages, is_map, is_write;
+
+ /* SEF local startup. */
+ env_setargs(argc, argv);
+ sef_local_startup();
+
+ /* Parse the command line. */
+ r = env_get_param("pages", nr_pages_str, sizeof(nr_pages_str));
+ errno = 0;
+ nr_pages = atoi(nr_pages_str);
+ if (r != OK || errno || nr_pages <=0) {
+ exit_usage();
+ }
+ if(nr_pages > TEST_PAGE_NUM) {
+ printf("REQUESTOR: too many pages. Max allowed: %d\n",
+ TEST_PAGE_NUM);
+ exit_usage();
+ }
+ r = env_get_param("map", is_map_str, sizeof(is_map_str));
+ errno = 0;
+ is_map = atoi(is_map_str);
+ if (r != OK || errno || (is_map!=0 && is_map!=1)) {
+ exit_usage();
+ }
+ r = env_get_param("write", is_write_str, sizeof(is_write_str));
+ errno = 0;
+ is_write = atoi(is_write_str);
+ if (r != OK || errno || (is_write!=0 && is_write!=1)) {
+ exit_usage();
+ }
+ printf("REQUESTOR: Running tests with pages=%d map=%d write=%d...\n",
+ nr_pages, is_map, is_write);
+
+ /* Prepare work. */
+ buf = (char*) CLICK_CEIL(buf_buf);
+ fid_get = open(FIFO_GRANTOR, O_RDONLY);
+ fid_send = open(FIFO_REQUESTOR, O_WRONLY);
+ if(fid_get < 0 || fid_send < 0) {
+ printf("REQUESTOR: can't open fifo files.\n");
+ return 1;
+ }
+
+ /* Send the endpoint to the granter, in order to let him to
+ * create the grant.
+ */
+ ep_self = getprocnr();
+ write(fid_send, &ep_self, sizeof(ep_self));
+ dprint("REQUESTOR: sending my endpoint: %d\n", ep_self);
+
+ /* Get the granter's endpoint and gid. */
+ read(fid_get, &ep_granter, sizeof(ep_granter));
+ read(fid_get, &gid, sizeof(gid));
+ dprint("REQUESTOR: getting granter's endpoint %d and gid %d\n",
+ ep_granter, gid);
+
+ FIFO_WAIT(fid_get);
+ diff = make64(0, 0);
+
+ if(is_map) {
+ /* Test safemap. */
+ for(i=0;i<NR_TEST_ITERATIONS;i++) {
+ read_tsc_64(&start);
+ r = sys_safemap(ep_granter, gid, 0, (long)buf,
+ nr_pages*CLICK_SIZE, D, 1);
+ if(r != OK) {
+ printf("REQUESTOR: safemap error: %d\n", r);
+ return 1;
+ }
+ read_write_buff(buf, nr_pages*CLICK_SIZE, is_write);
+ read_tsc_64(&end);
+ diff = add64(diff, (sub64(end, start)));
+ r = sys_safeunmap(D, (long)buf);
+ if(r != OK) {
+ printf("REQUESTOR: safeunmap error: %d\n", r);
+ return 1;
+ }
+ }
+ micros = ((double)tsc_64_to_micros(diff))
+ / (NR_TEST_ITERATIONS*nr_pages);
+ REPORT_TEST("REQUESTOR", "SAFEMAP", micros);
+ }
+ else {
+ /* Test safecopy. */
+ for(i=0;i<NR_TEST_ITERATIONS;i++) {
+ read_tsc_64(&start);
+ r = sys_safecopyfrom(ep_granter, gid, 0, (long)buf,
+ nr_pages*CLICK_SIZE, D);
+ if(r != OK) {
+ printf("REQUESTOR: safecopy error: %d\n", r);
+ return 1;
+ }
+ read_write_buff(buf, nr_pages*CLICK_SIZE, is_write);
+ read_tsc_64(&end);
+ diff = add64(diff, (sub64(end, start)));
+ }
+ micros = ((double)tsc_64_to_micros(diff))
+ / (NR_TEST_ITERATIONS*nr_pages);
+ REPORT_TEST("REQUESTOR", "SAFECOPY", micros);
+ }
+
+ FIFO_NOTIFY(fid_send);
+
+ return 0;
+}
+
+/*===========================================================================*
+ * sef_local_startup *
+ *===========================================================================*/
+PRIVATE void sef_local_startup()
+{
+ /* Let SEF perform startup. */
+ sef_startup();
+}
+
--- /dev/null
+#!/bin/sh
+
+PAGES="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50"
+MAP=0
+WRITE=1
+
+PWD=`pwd`
+
+for P in `echo $PAGES`
+do
+ service up ${PWD}/grantor -config ${PWD}/system.conf -script ${PWD}/down
+ service up ${PWD}/requestor -config ${PWD}/system.conf -script ${PWD}/down \
+ -args pages=${P}\ map=${MAP}\ write=${WRITE}
+ sleep 2
+done
+
--- /dev/null
+
+service requestor
+{
+ system
+ SAFECOPYFROM
+ SAFECOPYTO
+ SAFEMAP
+ SAFEREVMAP
+ SAFEUNMAP
+ UMAP
+ PRIVCTL
+ SETGRANT
+ GETINFO
+ SYSCTL
+ ;
+ uid 0;
+};
+
+service grantor
+{
+ system
+ SAFECOPYFROM
+ SAFECOPYTO
+ SAFEMAP
+ SAFEREVMAP
+ SAFEUNMAP
+ UMAP
+ PRIVCTL
+ SETGRANT
+ GETINFO
+ SYSCTL
+ ;
+ uid 0;
+};