From c5b309ff074389fc19d091b0ab510e46e3734535 Mon Sep 17 00:00:00 2001 From: Cristiano Giuffrida Date: Thu, 14 Jan 2010 15:24:16 +0000 Subject: [PATCH] Merge of Wu's GSOC 09 branch (src.20090525.r4372.wu) Main changes: - COW optimization for safecopy. - safemap, a grant-based interface for sharing memory regions between processes. - Integration with safemap and complete rework of DS, supporting new data types natively (labels, memory ranges, memory mapped ranges). - For further information: http://wiki.minix3.org/en/SummerOfCode2009/MemoryGrants Additional changes not included in the original Wu's branch: - Fixed unhandled case in VM when using COW optimization for safecopy in case of a block that has already been shared as SMAP. - Better interface and naming scheme for sys_saferevmap and ds_retrieve_map calls. - Better input checking in syslib: check for page alignment when creating memory mapping grants. - DS notifies subscribers when an entry is deleted. - Documented the behavior of indirect grants in case of memory mapping. - Test suite in /usr/src/test/safeperf|safecopy|safemap|ds/* reworked and extended. - Minor fixes and general cleanup. - TO-DO: Grant ids should be generated and managed the way endpoints are to make sure grant slots are never misreused. --- drivers/audio/framework/audio_fw.c | 4 +- drivers/e1000/e1000.c | 4 +- drivers/fxp/fxp.c | 12 +- drivers/orinoco/orinoco.c | 4 +- drivers/rtl8139/rtl8139.c | 8 +- drivers/ti1225/ti1225.c | 4 +- include/minix/com.h | 48 +- include/minix/const.h | 4 + include/minix/ds.h | 74 +- include/minix/safecopies.h | 8 + include/minix/syslib.h | 11 +- include/minix/sysutil.h | 4 +- include/unistd.h | 13 +- kernel/arch/i386/memory.c | 9 +- kernel/arch/i386/protect.c | 7 +- kernel/main.c | 11 +- kernel/proc.h | 22 +- kernel/proto.h | 6 + kernel/system.c | 11 +- kernel/system.h | 4 + kernel/system/Makefile | 4 + kernel/system/do_fork.c | 6 - kernel/system/do_privctl.c | 2 + kernel/system/do_safecopy.c | 47 +- kernel/system/do_safemap.c | 285 +++++++ kernel/system/do_vmctl.c | 59 +- lib/Makefile | 92 +-- lib/syslib/Makefile.in | 1 + lib/syslib/ds.c | 383 +++++---- lib/syslib/pci_del_acl.c | 2 +- lib/syslib/pci_init1.c | 4 +- lib/syslib/pci_set_acl.c | 4 +- lib/syslib/safecopies.c | 28 +- lib/syslib/sys_safemap.c | 72 ++ lib/syslib/sys_vmctl.c | 15 +- lib/sysutil/Makefile.in | 2 +- lib/sysutil/{micro_delay.c => tsc_util.c} | 30 +- servers/ds/inc.h | 3 +- servers/ds/main.c | 9 + servers/ds/proto.h | 3 + servers/ds/store.c | 960 ++++++++++++++-------- servers/ds/store.h | 51 +- servers/inet/inet.c | 4 +- servers/inet/mnx_eth.c | 4 +- servers/is/dmp_ds.c | 86 +- servers/mfs/mount.c | 11 +- servers/rs/memory.c | 6 +- servers/rs/service.c | 5 +- servers/rs/table.c | 3 +- servers/rs/utility.c | 2 +- servers/vfs/dmap.c | 2 +- servers/vfs/mount.c | 2 +- servers/vm/Makefile | 2 +- servers/vm/break.c | 4 +- servers/vm/exec.c | 16 +- servers/vm/i386/pagetable.c | 2 - servers/vm/main.c | 2 - servers/vm/map_mem.c | 330 ++++++++ servers/vm/mmap.c | 2 - servers/vm/pagefaults.c | 38 +- servers/vm/proto.h | 12 + servers/vm/queryexit.c | 2 - servers/vm/region.c | 53 +- servers/vm/region.h | 3 + servers/vm/rs.c | 2 - servers/vm/utility.c | 4 +- servers/vm/vfs.c | 2 - test/ds/Makefile | 18 + test/ds/README | 23 + test/ds/down | 4 + test/ds/dstest.c | 230 ++++++ test/ds/inc.h | 15 + test/ds/run | 6 + test/ds/subs.c | 93 +++ test/ds/system.conf | 25 + test/safecopy/Makefile | 21 + test/safecopy/README | 19 + test/safecopy/down | 5 + test/safecopy/grantor.c | 59 ++ test/safecopy/inc.h | 50 ++ test/safecopy/requestor.c | 96 +++ test/safecopy/run | 7 + test/safecopy/system.conf | 34 + test/safemap/Makefile | 21 + test/safemap/README | 8 + test/safemap/down | 4 + test/safemap/grantor.c | 129 +++ test/safemap/inc.h | 54 ++ test/safemap/requestor.c | 153 ++++ test/safemap/run | 6 + test/safemap/system.conf | 34 + test/safeperf/Makefile | 21 + test/safeperf/README | 11 + test/safeperf/down | 5 + test/safeperf/grantor.c | 62 ++ test/safeperf/inc.h | 51 ++ test/safeperf/requestor.c | 166 ++++ test/safeperf/run | 16 + test/safeperf/system.conf | 34 + 99 files changed, 3576 insertions(+), 833 deletions(-) create mode 100644 kernel/system/do_safemap.c create mode 100644 lib/syslib/sys_safemap.c rename lib/sysutil/{micro_delay.c => tsc_util.c} (80%) create mode 100644 servers/vm/map_mem.c create mode 100644 test/ds/Makefile create mode 100644 test/ds/README create mode 100644 test/ds/down create mode 100644 test/ds/dstest.c create mode 100644 test/ds/inc.h create mode 100644 test/ds/run create mode 100644 test/ds/subs.c create mode 100644 test/ds/system.conf create mode 100644 test/safecopy/Makefile create mode 100644 test/safecopy/README create mode 100644 test/safecopy/down create mode 100644 test/safecopy/grantor.c create mode 100644 test/safecopy/inc.h create mode 100644 test/safecopy/requestor.c create mode 100644 test/safecopy/run create mode 100644 test/safecopy/system.conf create mode 100644 test/safemap/Makefile create mode 100644 test/safemap/README create mode 100644 test/safemap/down create mode 100644 test/safemap/grantor.c create mode 100644 test/safemap/inc.h create mode 100644 test/safemap/requestor.c create mode 100644 test/safemap/run create mode 100644 test/safemap/system.conf create mode 100644 test/safeperf/Makefile create mode 100644 test/safeperf/README create mode 100644 test/safeperf/down create mode 100644 test/safeperf/grantor.c create mode 100644 test/safeperf/inc.h create mode 100644 test/safeperf/requestor.c create mode 100644 test/safeperf/run create mode 100644 test/safeperf/system.conf diff --git a/drivers/audio/framework/audio_fw.c b/drivers/audio/framework/audio_fw.c index e01526c99..50bacc235 100644 --- a/drivers/audio/framework/audio_fw.c +++ b/drivers/audio/framework/audio_fw.c @@ -1027,11 +1027,11 @@ int pci_func; 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; diff --git a/drivers/e1000/e1000.c b/drivers/e1000/e1000.c index 28ed13d30..0734461af 100644 --- a/drivers/e1000/e1000.c +++ b/drivers/e1000/e1000.c @@ -157,9 +157,9 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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) diff --git a/drivers/fxp/fxp.c b/drivers/fxp/fxp.c index 1d3dbba6e..3be1788bb 100644 --- a/drivers/fxp/fxp.c +++ b/drivers/fxp/fxp.c @@ -414,15 +414,15 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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); } @@ -3013,12 +3013,12 @@ int pci_func; 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; diff --git a/drivers/orinoco/orinoco.c b/drivers/orinoco/orinoco.c index 515246ad2..c09a84467 100644 --- a/drivers/orinoco/orinoco.c +++ b/drivers/orinoco/orinoco.c @@ -367,11 +367,11 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) /* 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); } diff --git a/drivers/rtl8139/rtl8139.c b/drivers/rtl8139/rtl8139.c index e709ea43f..888acf6b5 100644 --- a/drivers/rtl8139/rtl8139.c +++ b/drivers/rtl8139/rtl8139.c @@ -336,11 +336,11 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) * 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); } @@ -3017,12 +3017,12 @@ int pci_func; 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; diff --git a/drivers/ti1225/ti1225.c b/drivers/ti1225/ti1225.c index 83e5a8fe8..9ada092e6 100644 --- a/drivers/ti1225/ti1225.c +++ b/drivers/ti1225/ti1225.c @@ -117,8 +117,8 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) (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) diff --git a/include/minix/com.h b/include/minix/com.h index 318ee380d..0386e6c24 100644 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -350,8 +350,11 @@ # 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. */ @@ -536,6 +539,15 @@ #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 */ @@ -556,11 +568,13 @@ #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 */ @@ -654,19 +668,23 @@ #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 * diff --git a/include/minix/const.h b/include/minix/const.h index 38252b333..1a495a74b 100644 --- a/include/minix/const.h +++ b/include/minix/const.h @@ -79,6 +79,10 @@ #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. diff --git a/include/minix/ds.h b/include/minix/ds.h index ce6453b95..fd9f42296 100644 --- a/include/minix/ds.h +++ b/include/minix/ds.h @@ -5,34 +5,68 @@ #include -/* 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 */ diff --git a/include/minix/safecopies.h b/include/minix/safecopies.h index 697d77889..50b8623d7 100644 --- a/include/minix/safecopies.h +++ b/include/minix/safecopies.h @@ -49,6 +49,13 @@ struct vscp_vec { 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) @@ -56,6 +63,7 @@ struct vscp_vec { /* 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. */ diff --git a/include/minix/syslib.h b/include/minix/syslib.h index 6ff557a3f..c0c1df9ff 100644 --- a/include/minix/syslib.h +++ b/include/minix/syslib.h @@ -62,7 +62,8 @@ _PROTOTYPE( int sys_vmctl, (endpoint_t who, int param, u32_t value)); _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)); @@ -149,6 +150,14 @@ _PROTOTYPE(int sys_vsafecopy, (struct vscp_vec *copyvec, int elements)); _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, diff --git a/include/minix/sysutil.h b/include/minix/sysutil.h index 487c6b864..cc09c2dd4 100644 --- a/include/minix/sysutil.h +++ b/include/minix/sysutil.h @@ -49,13 +49,15 @@ _PROTOTYPE( void panic, (char *who, char *mess, int num)); _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)); diff --git a/include/unistd.h b/include/unistd.h index 5c25f64fc..e7c8bd682 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -44,12 +44,13 @@ #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 according to POSIX Sec. 2.7.1. */ #define NULL ((void *)0) diff --git a/kernel/arch/i386/memory.c b/kernel/arch/i386/memory.c index 4f2b44ec7..4b5793b6b 100644 --- a/kernel/arch/i386/memory.c +++ b/kernel/arch/i386/memory.c @@ -613,10 +613,11 @@ PUBLIC int vm_suspend(struct proc *caller, struct proc *target, 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. */ diff --git a/kernel/arch/i386/protect.c b/kernel/arch/i386/protect.c index 203865e34..afb142cde 100644 --- a/kernel/arch/i386/protect.c +++ b/kernel/arch/i386/protect.c @@ -137,12 +137,7 @@ PUBLIC void prot_init(void) /* 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]; diff --git a/kernel/main.c b/kernel/main.c index 988fb1f71..589645578 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -154,13 +154,14 @@ PUBLIC void main() /* 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; diff --git a/kernel/proc.h b/kernel/proc.h index 092edbe06..788f7b2c4 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -61,7 +61,7 @@ struct proc { * 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 { @@ -70,6 +70,8 @@ struct proc { #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 */ @@ -77,10 +79,20 @@ struct proc { } 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; diff --git a/kernel/proto.h b/kernel/proto.h index 3c8fb3c7f..2ca58ec92 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -89,6 +89,12 @@ _PROTOTYPE( void check_runqueues_f, (char *file, int line) ); _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 *)); diff --git a/kernel/system.c b/kernel/system.c index 589f5c9c7..cb0ab8d5d 100644 --- a/kernel/system.c +++ b/kernel/system.c @@ -208,6 +208,11 @@ PRIVATE void initialize(void) 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 */ @@ -262,10 +267,6 @@ int priv_id; /* privilege id */ } 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); } @@ -482,9 +483,11 @@ register struct proc *rc; /* slot of process to clean up */ 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; } diff --git a/kernel/system.h b/kernel/system.h index 5fcd116f3..ac13bb908 100644 --- a/kernel/system.h +++ b/kernel/system.h @@ -181,6 +181,10 @@ _PROTOTYPE( int do_setgrant, (message *m_ptr) ); _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 diff --git a/kernel/system/Makefile b/kernel/system/Makefile index ec46ebe8e..67bddfb89 100644 --- a/kernel/system/Makefile +++ b/kernel/system/Makefile @@ -44,6 +44,7 @@ OBJECTS = \ $(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) \ @@ -155,6 +156,9 @@ $(SYSTEM)(do_privctl.o): do_privctl.c $(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 diff --git a/kernel/system/do_fork.c b/kernel/system/do_fork.c index 6d9c39cb0..ef67d6d24 100644 --- a/kernel/system/do_fork.c +++ b/kernel/system/do_fork.c @@ -49,12 +49,6 @@ register message *m_ptr; /* pointer to request message */ 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. */ diff --git a/kernel/system/do_privctl.c b/kernel/system/do_privctl.c index 7081d3190..4cf90084c 100644 --- a/kernel/system/do_privctl.c +++ b/kernel/system/do_privctl.c @@ -101,6 +101,8 @@ message *m_ptr; /* pointer to request message */ 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 */ diff --git a/kernel/system/do_safecopy.c b/kernel/system/do_safecopy.c index aa171551f..9306cd650 100644 --- a/kernel/system/do_safecopy.c +++ b/kernel/system/do_safecopy.c @@ -24,6 +24,8 @@ #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) \ @@ -229,9 +231,10 @@ int access; /* CPF_READ for a copy from granter to grantee, CPF_WRITE { 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; @@ -279,8 +282,48 @@ int access; /* CPF_READ for a copy from granter to grantee, CPF_WRITE } /* 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 } /*===========================================================================* diff --git a/kernel/system/do_safemap.c b/kernel/system/do_safemap.c new file mode 100644 index 000000000..95b448ca5 --- /dev/null +++ b/kernel/system/do_safemap.c @@ -0,0 +1,285 @@ +/* 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 +#include + +#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; +} + diff --git a/kernel/system/do_vmctl.c b/kernel/system/do_vmctl.c index 9ab157895..afc2729a8 100644 --- a/kernel/system/do_vmctl.c +++ b/kernel/system/do_vmctl.c @@ -65,21 +65,51 @@ register message *m_ptr; /* pointer to request message */ #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); @@ -94,21 +124,28 @@ register message *m_ptr; /* pointer to request message */ 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); diff --git a/lib/Makefile b/lib/Makefile index cc8b0a072..9d36f2b77 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -6,10 +6,10 @@ all-gnu: 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 @@ -17,47 +17,47 @@ Makefile: Makefile.in Makedepend-ack Makedepend-gnu @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 @@ -150,56 +150,56 @@ makefiles: ack/Makefile 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 diff --git a/lib/syslib/Makefile.in b/lib/syslib/Makefile.in index da20eba46..9549cc31b 100644 --- a/lib/syslib/Makefile.in +++ b/lib/syslib/Makefile.in @@ -52,6 +52,7 @@ libsys_FILES=" \ sys_readbios.c \ sys_runctl.c \ sys_safecopy.c \ + sys_safemap.c \ sys_sysctl.c \ sys_vsafecopy.c \ sys_profbuf.c \ diff --git a/lib/syslib/ds.c b/lib/syslib/ds.c index d647c41d5..ec82595ca 100644 --- a/lib/syslib/ds.c +++ b/lib/syslib/ds.c @@ -4,260 +4,257 @@ #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; } - diff --git a/lib/syslib/pci_del_acl.c b/lib/syslib/pci_del_acl.c index b50d355f0..9fc5db494 100644 --- a/lib/syslib/pci_del_acl.c +++ b/lib/syslib/pci_del_acl.c @@ -21,7 +21,7 @@ endpoint_t proc_ep; if (pci_procnr == ANY) { - r= ds_retrieve_u32("pci", &u32); + r= ds_retrieve_label_num("pci", &u32); if (r != 0) { panic("syslib/" __FILE__, diff --git a/lib/syslib/pci_init1.c b/lib/syslib/pci_init1.c index 11b2fb913..758d88b0d 100644 --- a/lib/syslib/pci_init1.c +++ b/lib/syslib/pci_init1.c @@ -22,9 +22,9 @@ char *name; 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; diff --git a/lib/syslib/pci_set_acl.c b/lib/syslib/pci_set_acl.c index 8e8885322..12cafbca0 100644 --- a/lib/syslib/pci_set_acl.c +++ b/lib/syslib/pci_set_acl.c @@ -22,11 +22,11 @@ struct rs_pci *rs_pci; 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; diff --git a/lib/syslib/safecopies.c b/lib/syslib/safecopies.c index 3159f6f09..91dae250e 100644 --- a/lib/syslib/safecopies.c +++ b/lib/syslib/safecopies.c @@ -16,7 +16,7 @@ #include #define ACCESS_CHECK(a) { \ - if((a) & ~(CPF_READ|CPF_WRITE)) { \ + if((a) & ~(CPF_READ|CPF_WRITE|CPF_MAP)) { \ errno = EINVAL; \ return -1; \ } \ @@ -37,6 +37,13 @@ } \ } +#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; @@ -206,8 +213,16 @@ PUBLIC int 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. */ @@ -262,6 +277,12 @@ int access; 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; @@ -298,6 +319,11 @@ int access; 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; diff --git a/lib/syslib/sys_safemap.c b/lib/syslib/sys_safemap.c new file mode 100644 index 000000000..8621dfe2e --- /dev/null +++ b/lib/syslib/sys_safemap.c @@ -0,0 +1,72 @@ + +#include "syslib.h" + +#include + +/*===========================================================================* + * 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)); +} + diff --git a/lib/syslib/sys_vmctl.c b/lib/syslib/sys_vmctl.c index 5e93bace5..a6aa159fe 100644 --- a/lib/syslib/sys_vmctl.c +++ b/lib/syslib/sys_vmctl.c @@ -43,7 +43,8 @@ PUBLIC int sys_vmctl_get_cr3_i386(endpoint_t who, u32_t *cr3) } 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; @@ -51,11 +52,13 @@ PUBLIC int sys_vmctl_get_memreq(endpoint_t *who, vir_bytes *mem, 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; diff --git a/lib/sysutil/Makefile.in b/lib/sysutil/Makefile.in index c5baf71f6..2680b4ee1 100644 --- a/lib/sysutil/Makefile.in +++ b/lib/sysutil/Makefile.in @@ -18,7 +18,7 @@ libsys_FILES=" \ env_panic.c \ env_prefix.c \ fkey_ctl.c \ - micro_delay.c \ + tsc_util.c \ report.c \ taskcall.c \ read_tsc.s \ diff --git a/lib/sysutil/micro_delay.c b/lib/sysutil/tsc_util.c similarity index 80% rename from lib/sysutil/micro_delay.c rename to lib/sysutil/tsc_util.c index b549510f9..b21bfdf06 100644 --- a/lib/sysutil/micro_delay.c +++ b/lib/sysutil/tsc_util.c @@ -17,15 +17,15 @@ #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; @@ -50,11 +50,11 @@ micro_delay_calibrate(void) 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))); @@ -94,3 +94,23 @@ micro_delay(u32_t micros) 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; +} + diff --git a/servers/ds/inc.h b/servers/ds/inc.h index 9aef23a35..c2fae7621 100644 --- a/servers/ds/inc.h +++ b/servers/ds/inc.h @@ -7,12 +7,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -27,5 +29,4 @@ #include "proto.h" #include "glo.h" -#include "store.h" diff --git a/servers/ds/main.c b/servers/ds/main.c index 655e1f7c2..9ba8c57f9 100644 --- a/servers/ds/main.c +++ b/servers/ds/main.c @@ -71,12 +71,21 @@ PUBLIC int main(int argc, char **argv) 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; diff --git a/servers/ds/proto.h b/servers/ds/proto.h index 6844e976f..f15edaafe 100644 --- a/servers/ds/proto.h +++ b/servers/ds/proto.h @@ -6,8 +6,11 @@ _PROTOTYPE(int main, (int argc, char **argv)); /* 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)); diff --git a/servers/ds/store.c b/servers/ds/store.c index a150e97ab..0aa253799 100644 --- a/servers/ds/store.c +++ b/servers/ds/store.c @@ -1,17 +1,225 @@ -/* 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 * @@ -24,14 +232,11 @@ PUBLIC int sef_cb_init_fresh(int type, sef_init_info_t *info) /* 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, @@ -58,397 +263,498 @@ struct rprocpub *rpub; /* 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; iDS_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; } diff --git a/servers/ds/store.h b/servers/ds/store.h index d70d9e59f..6653318ff 100644 --- a/servers/ds/store.h +++ b/servers/ds/store.h @@ -1,33 +1,46 @@ -/* Type definitions for the Data Store Server. */ +#ifndef _DS_STORE_H_ +#define _DS_STORE_H_ +/* Type definitions for the Data Store Server. */ #include #include #include #include #include -/* 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_ */ diff --git a/servers/inet/inet.c b/servers/inet/inet.c index 93c0fa40a..0e43e7f51 100644 --- a/servers/inet/inet.c +++ b/servers/inet/inet.c @@ -257,9 +257,9 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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. */ diff --git a/servers/inet/mnx_eth.c b/servers/inet/mnx_eth.c index 241f659a9..9da1f0ddc 100644 --- a/servers/inet/mnx_eth.c +++ b/servers/inet/mnx_eth.c @@ -99,10 +99,10 @@ PUBLIC void osdep_eth_init() } 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) diff --git a/servers/is/dmp_ds.c b/servers/is/dmp_ds.c index 27b337eb3..5e9086cd1 100644 --- a/servers/is/dmp_ds.c +++ b/servers/is/dmp_ds.c @@ -1,66 +1,54 @@ -/* 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; ids_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); -} - diff --git a/servers/mfs/mount.c b/servers/mfs/mount.c index 4a9a58dc8..64e129003 100644 --- a/servers/mfs/mount.c +++ b/servers/mfs/mount.c @@ -49,11 +49,12 @@ PUBLIC int fs_readsuper() 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; diff --git a/servers/rs/memory.c b/servers/rs/memory.c index b80561058..539480278 100644 --- a/servers/rs/memory.c +++ b/servers/rs/memory.c @@ -45,8 +45,8 @@ PRIVATE int check_mem_available(char *new_brksize) 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; @@ -62,7 +62,7 @@ PRIVATE int check_mem_available(char *new_brksize) /* 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) { diff --git a/servers/rs/service.c b/servers/rs/service.c index cb7074998..d6d26dc98 100644 --- a/servers/rs/service.c +++ b/servers/rs/service.c @@ -112,7 +112,7 @@ PRIVATE void print_usage(char *app_name, char *problem) fprintf(stderr, "Warning, %s\n", problem); fprintf(stderr, "Usage:\n"); fprintf(stderr, - " %s [-c] (up|run) [%s ] [%s ] [%s ]\n", + " %s [-c -r] (up|run) [%s ] [%s ] [%s ]\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); @@ -729,6 +729,9 @@ struct { "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 }, diff --git a/servers/rs/table.c b/servers/rs/table.c index de4c40e70..6217ba617 100644 --- a/servers/rs/table.c +++ b/servers/rs/table.c @@ -15,7 +15,8 @@ */ #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 diff --git a/servers/rs/utility.c b/servers/rs/utility.c index e58f3fdad..0845206d6 100644 --- a/servers/rs/utility.c +++ b/servers/rs/utility.c @@ -45,7 +45,7 @@ struct rproc *rp; /* pointer to process slot */ 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; } diff --git a/servers/vfs/dmap.c b/servers/vfs/dmap.c index 14a6be497..645f8197e 100644 --- a/servers/vfs/dmap.c +++ b/servers/vfs/dmap.c @@ -96,7 +96,7 @@ PUBLIC int do_mapdriver() 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); diff --git a/servers/vfs/mount.c b/servers/vfs/mount.c index bb9e19ef2..da8627899 100644 --- a/servers/vfs/mount.c +++ b/servers/vfs/mount.c @@ -96,7 +96,7 @@ PUBLIC int do_mount() 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); diff --git a/servers/vm/Makefile b/servers/vm/Makefile index 42091291b..b3dc8d5b3 100644 --- a/servers/vm/Makefile +++ b/servers/vm/Makefile @@ -5,7 +5,7 @@ include /etc/make.conf 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) diff --git a/servers/vm/break.c b/servers/vm/break.c index 75a91e5eb..b6022f848 100644 --- a/servers/vm/break.c +++ b/servers/vm/break.c @@ -96,7 +96,7 @@ vir_bytes sp; /* new value of sp */ /* 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) { @@ -165,7 +165,7 @@ vir_bytes v; 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); diff --git a/servers/vm/exec.c b/servers/vm/exec.c index 65106af72..264550cb9 100644 --- a/servers/vm/exec.c +++ b/servers/vm/exec.c @@ -110,10 +110,10 @@ SANITYCHECK(SCL_DETAIL); } /* 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 */ @@ -204,10 +204,10 @@ vir_bytes *stack_top; /* top of process stack */ * 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"); diff --git a/servers/vm/i386/pagetable.c b/servers/vm/i386/pagetable.c index f2019f4bf..f7fe85333 100644 --- a/servers/vm/i386/pagetable.c +++ b/servers/vm/i386/pagetable.c @@ -2,8 +2,6 @@ #define _SYSTEM 1 #define _POSIX_SOURCE 1 -#define VERBOSE 0 - #include #include #include diff --git a/servers/vm/main.c b/servers/vm/main.c index 7524eb344..fcf097666 100644 --- a/servers/vm/main.c +++ b/servers/vm/main.c @@ -1,8 +1,6 @@ #define _SYSTEM 1 -#define VERBOSE 0 - #include #include #include diff --git a/servers/vm/map_mem.c b/servers/vm/map_mem.c new file mode 100644 index 000000000..508dbcb36 --- /dev/null +++ b/servers/vm/map_mem.c @@ -0,0 +1,330 @@ + +#define _SYSTEM 1 + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#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; +} + diff --git a/servers/vm/mmap.c b/servers/vm/mmap.c index 686db4779..5447f15fa 100644 --- a/servers/vm/mmap.c +++ b/servers/vm/mmap.c @@ -1,8 +1,6 @@ #define _SYSTEM 1 -#define VERBOSE 0 - #include #include #include diff --git a/servers/vm/pagefaults.c b/servers/vm/pagefaults.c index 6c5fc4755..34c6570d0 100644 --- a/servers/vm/pagefaults.c +++ b/servers/vm/pagefaults.c @@ -127,26 +127,42 @@ PUBLIC void do_pagefaults(void) } /*===========================================================================* - * 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); diff --git a/servers/vm/proto.h b/servers/vm/proto.h index 3ae0b205d..daf6ac983 100644 --- a/servers/vm/proto.h +++ b/servers/vm/proto.h @@ -4,6 +4,8 @@ struct vmproc; struct stat; struct mem_map; struct memory; +struct vir_region; +struct phys_region; #include #include @@ -76,6 +78,12 @@ _PROTOTYPE( int vfs_open, (struct vmproc *for_who, callback_t callback, _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) ); @@ -156,6 +164,10 @@ _PROTOTYPE(int map_remap, (struct vmproc *dvmp, vir_bytes da, size_t size, _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 diff --git a/servers/vm/queryexit.c b/servers/vm/queryexit.c index 339d53789..7d981a4ab 100644 --- a/servers/vm/queryexit.c +++ b/servers/vm/queryexit.c @@ -1,8 +1,6 @@ #define _SYSTEM 1 -#define VERBOSE 0 - #include #include #include diff --git a/servers/vm/region.c b/servers/vm/region.c index 559f3eecb..33768ada7 100644 --- a/servers/vm/region.c +++ b/servers/vm/region.c @@ -40,8 +40,6 @@ FORWARD _PROTOTYPE(struct phys_region *map_new_physblock, (struct vmproc *vmp, 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) @@ -422,7 +420,7 @@ USE(newregion, /*===========================================================================* * 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; @@ -460,20 +458,6 @@ void pb_unreferenced(struct vir_region *region, struct phys_region *pr) 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); - } } } @@ -709,7 +693,7 @@ phys_bytes what_mem; /*===========================================================================* * 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; @@ -816,9 +800,13 @@ int write; 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. */ @@ -959,9 +947,12 @@ int write; 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 @@ -1065,11 +1056,19 @@ PUBLIC int map_writept(struct vmproc *vmp) 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); } } @@ -1125,6 +1124,14 @@ struct vmproc *src; 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); diff --git a/servers/vm/region.h b/servers/vm/region.h index 69419ec58..948ce715a 100644 --- a/servers/vm/region.h +++ b/servers/vm/region.h @@ -23,6 +23,9 @@ struct phys_block { 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; diff --git a/servers/vm/rs.c b/servers/vm/rs.c index 1eb194f61..6611a1e2b 100644 --- a/servers/vm/rs.c +++ b/servers/vm/rs.c @@ -1,8 +1,6 @@ #define _SYSTEM 1 -#define VERBOSE 0 - #include #include #include diff --git a/servers/vm/utility.c b/servers/vm/utility.c index 09b4dbbc0..a9d4182b6 100644 --- a/servers/vm/utility.c +++ b/servers/vm/utility.c @@ -76,8 +76,8 @@ struct memory *mem_chunks; /* store mem chunks here */ 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 { diff --git a/servers/vm/vfs.c b/servers/vm/vfs.c index 9f8d34899..df2ec4e79 100644 --- a/servers/vm/vfs.c +++ b/servers/vm/vfs.c @@ -1,8 +1,6 @@ #define _SYSTEM 1 -#define VERBOSE 0 - #include #include #include diff --git a/test/ds/Makefile b/test/ds/Makefile new file mode 100644 index 000000000..63bf396ac --- /dev/null +++ b/test/ds/Makefile @@ -0,0 +1,18 @@ +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 + diff --git a/test/ds/README b/test/ds/README new file mode 100644 index 000000000..e8702edad --- /dev/null +++ b/test/ds/README @@ -0,0 +1,23 @@ +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. + diff --git a/test/ds/down b/test/ds/down new file mode 100644 index 000000000..ad9cd5bd7 --- /dev/null +++ b/test/ds/down @@ -0,0 +1,4 @@ +#!/bin/sh + +service down dstest +service down subs diff --git a/test/ds/dstest.c b/test/ds/dstest.c new file mode 100644 index 000000000..d6d13fef6 --- /dev/null +++ b/test/ds/dstest.c @@ -0,0 +1,230 @@ +#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(); +} + diff --git a/test/ds/inc.h b/test/ds/inc.h new file mode 100644 index 000000000..2f7907d55 --- /dev/null +++ b/test/ds/inc.h @@ -0,0 +1,15 @@ +#define _MINIX +#define _SYSTEM +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include diff --git a/test/ds/run b/test/ds/run new file mode 100644 index 000000000..46ab1133f --- /dev/null +++ b/test/ds/run @@ -0,0 +1,6 @@ +#!/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 diff --git a/test/ds/subs.c b/test/ds/subs.c new file mode 100644 index 000000000..ad7377646 --- /dev/null +++ b/test/ds/subs.c @@ -0,0 +1,93 @@ +#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(); +} + diff --git a/test/ds/system.conf b/test/ds/system.conf new file mode 100644 index 000000000..17fba33b2 --- /dev/null +++ b/test/ds/system.conf @@ -0,0 +1,25 @@ + +service dstest +{ + system + UMAP + PRIVCTL + SAFEMAP + SETGRANT + GETINFO + SYSCTL + ; + uid 0; +}; + +service subs +{ + system + UMAP + PRIVCTL + SETGRANT + GETINFO + SYSCTL + ; + uid 0; +}; diff --git a/test/safecopy/Makefile b/test/safecopy/Makefile new file mode 100644 index 000000000..67d7da7db --- /dev/null +++ b/test/safecopy/Makefile @@ -0,0 +1,21 @@ +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 + diff --git a/test/safecopy/README b/test/safecopy/README new file mode 100644 index 000000000..bc5da6703 --- /dev/null +++ b/test/safecopy/README @@ -0,0 +1,19 @@ +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 + diff --git a/test/safecopy/down b/test/safecopy/down new file mode 100644 index 000000000..6ca8abe02 --- /dev/null +++ b/test/safecopy/down @@ -0,0 +1,5 @@ +#!/bin/sh + +service down grantor +service down requestor + diff --git a/test/safecopy/grantor.c b/test/safecopy/grantor.c new file mode 100644 index 000000000..51c700b59 --- /dev/null +++ b/test/safecopy/grantor.c @@ -0,0 +1,59 @@ +#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(); +} + diff --git a/test/safecopy/inc.h b/test/safecopy/inc.h new file mode 100644 index 000000000..b737c4480 --- /dev/null +++ b/test/safecopy/inc.h @@ -0,0 +1,50 @@ +#define _SYSTEM +#define _MINIX +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 + diff --git a/test/safecopy/requestor.c b/test/safecopy/requestor.c new file mode 100644 index 000000000..f57bbf4ff --- /dev/null +++ b/test/safecopy/requestor.c @@ -0,0 +1,96 @@ +#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(); +} + diff --git a/test/safecopy/run b/test/safecopy/run new file mode 100644 index 000000000..1067ef75c --- /dev/null +++ b/test/safecopy/run @@ -0,0 +1,7 @@ +#!/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 + diff --git a/test/safecopy/system.conf b/test/safecopy/system.conf new file mode 100644 index 000000000..57f778f32 --- /dev/null +++ b/test/safecopy/system.conf @@ -0,0 +1,34 @@ + +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; +}; diff --git a/test/safemap/Makefile b/test/safemap/Makefile new file mode 100644 index 000000000..67d7da7db --- /dev/null +++ b/test/safemap/Makefile @@ -0,0 +1,21 @@ +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 + diff --git a/test/safemap/README b/test/safemap/README new file mode 100644 index 000000000..a1076a978 --- /dev/null +++ b/test/safemap/README @@ -0,0 +1,8 @@ +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. + diff --git a/test/safemap/down b/test/safemap/down new file mode 100644 index 000000000..153041abb --- /dev/null +++ b/test/safemap/down @@ -0,0 +1,4 @@ +#!/bin/sh + +service down grantor +service down requestor diff --git a/test/safemap/grantor.c b/test/safemap/grantor.c new file mode 100644 index 000000000..60052e13d --- /dev/null +++ b/test/safemap/grantor.c @@ -0,0 +1,129 @@ +#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(); +} + diff --git a/test/safemap/inc.h b/test/safemap/inc.h new file mode 100644 index 000000000..32ef9c61e --- /dev/null +++ b/test/safemap/inc.h @@ -0,0 +1,54 @@ +#define _SYSTEM +#define _MINIX +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + diff --git a/test/safemap/requestor.c b/test/safemap/requestor.c new file mode 100644 index 000000000..89773c1fc --- /dev/null +++ b/test/safemap/requestor.c @@ -0,0 +1,153 @@ +#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(); +} + diff --git a/test/safemap/run b/test/safemap/run new file mode 100644 index 000000000..b5600e074 --- /dev/null +++ b/test/safemap/run @@ -0,0 +1,6 @@ +#!/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 diff --git a/test/safemap/system.conf b/test/safemap/system.conf new file mode 100644 index 000000000..57f778f32 --- /dev/null +++ b/test/safemap/system.conf @@ -0,0 +1,34 @@ + +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; +}; diff --git a/test/safeperf/Makefile b/test/safeperf/Makefile new file mode 100644 index 000000000..67d7da7db --- /dev/null +++ b/test/safeperf/Makefile @@ -0,0 +1,21 @@ +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 + diff --git a/test/safeperf/README b/test/safeperf/README new file mode 100644 index 000000000..a2d345aea --- /dev/null +++ b/test/safeperf/README @@ -0,0 +1,11 @@ +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. + diff --git a/test/safeperf/down b/test/safeperf/down new file mode 100644 index 000000000..6ca8abe02 --- /dev/null +++ b/test/safeperf/down @@ -0,0 +1,5 @@ +#!/bin/sh + +service down grantor +service down requestor + diff --git a/test/safeperf/grantor.c b/test/safeperf/grantor.c new file mode 100644 index 000000000..2a2e908a4 --- /dev/null +++ b/test/safeperf/grantor.c @@ -0,0 +1,62 @@ +#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(); +} + diff --git a/test/safeperf/inc.h b/test/safeperf/inc.h new file mode 100644 index 000000000..893f29ec9 --- /dev/null +++ b/test/safeperf/inc.h @@ -0,0 +1,51 @@ +#define _SYSTEM +#define _MINIX +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + diff --git a/test/safeperf/requestor.c b/test/safeperf/requestor.c new file mode 100644 index 000000000..f348aae66 --- /dev/null +++ b/test/safeperf/requestor.c @@ -0,0 +1,166 @@ +#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 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