From 9df1183b94f91240985c2f5a6dae163de0ba5884 Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Tue, 20 Jun 2006 08:45:04 +0000 Subject: [PATCH] . removed const from putenv() for g++ . added safecopies.c: these are library functions to maintain grant tables in own address space . sys_safecopy.c: interfaces to kernel calls to perform safe copy functions in from or to foreign process . changes in i/o fields (type merged with request) reflected in library functions (sys_out.c, sys_vinb.c, sys_vinl.c, sys_vinw.c, sys_voutb.c, sys_voutl.c, sys_voutw.c) . type merged with request in sys_sdevio, also now accepts offset which is used when a grant is specified (the _DIO_SAFE subtype) . system printf() function changed to send DIAGNOSTICS_S messages, which specify a grant id instead of a direct address for the buffer to be printed; tty and log can then safecopy the buffer --- lib/other/putenv.c | 2 +- lib/syslib/Makefile.in | 2 + lib/syslib/safecopies.c | 264 ++++++++++++++++++++++++++++++++++++++ lib/syslib/sys_in.c | 3 +- lib/syslib/sys_out.c | 3 +- lib/syslib/sys_safecopy.c | 48 +++++++ lib/syslib/sys_sdevio.c | 10 +- lib/syslib/sys_vinb.c | 3 +- lib/syslib/sys_vinl.c | 3 +- lib/syslib/sys_vinw.c | 3 +- lib/syslib/sys_voutb.c | 3 +- lib/syslib/sys_voutl.c | 3 +- lib/syslib/sys_voutw.c | 3 +- lib/sysutil/kputc.c | 31 ++++- 14 files changed, 355 insertions(+), 26 deletions(-) create mode 100644 lib/syslib/safecopies.c create mode 100644 lib/syslib/sys_safecopy.c diff --git a/lib/other/putenv.c b/lib/other/putenv.c index d49ab9d0a..455ad5c5b 100755 --- a/lib/other/putenv.c +++ b/lib/other/putenv.c @@ -14,7 +14,7 @@ extern _CONST char ***_penviron; int putenv(name) -_CONST char *name; +char *name; { register _CONST char **v = *_penviron; register char *r; diff --git a/lib/syslib/Makefile.in b/lib/syslib/Makefile.in index 11215b999..2a4b8b025 100644 --- a/lib/syslib/Makefile.in +++ b/lib/syslib/Makefile.in @@ -23,6 +23,7 @@ libsys_FILES=" \ pci_rescan_bus.c \ pci_reserve.c \ pci_slot_name.c \ + safecopies.c \ sys_abort.c \ sys_endsig.c \ sys_eniop.c \ @@ -40,6 +41,7 @@ libsys_FILES=" \ sys_nice.c \ sys_out.c \ sys_physcopy.c \ + sys_safecopy.c \ sys_sdevio.c \ sys_segctl.c \ sys_setalarm.c \ diff --git a/lib/syslib/safecopies.c b/lib/syslib/safecopies.c new file mode 100644 index 000000000..01dff96e0 --- /dev/null +++ b/lib/syslib/safecopies.c @@ -0,0 +1,264 @@ + +/* Library functions to maintain internal data copying tables. + * + * April 21 2006: Initial version (Ben Gras) + * + */ + +#include +#include +#include +#include +#include +#include +#include + +PRIVATE cp_grant_t *grants = NULL; +PRIVATE int ngrants = 0, dynamic = 1; + +PUBLIC int +cpf_preallocate(cp_grant_t *new_grants, int new_ngrants) +{ +/* Use a statically allocated block of grants as our grant table. + * This means we can't grow it dynamically any more. + * + * This function is used in processes that can't safely call realloc(). + */ + int s; + + /* If any table is already in place, we can't change it. */ + if(ngrants > 0) { + errno = EBUSY; + return -1; + } + + /* Update kernel about the table. */ + if((s=sys_privctl(SELF, SYS_PRIV_SET_GRANTS, + new_ngrants, new_grants))) { + return -1; + } + + /* Update internal data. dynamic = 0 means no realloc()ing will be done + * and we can't grow beyond this size. + */ + grants = new_grants; + ngrants = new_ngrants; + dynamic = 0; + + return 0; +} + +PRIVATE void +cpf_grow(void) +{ +/* Grow the grants table if possible. If a preallocated block has been + * submitted ('dynamic' is clear), we can't grow it. Otherwise, realloc(). + * Caller is expected to check 'ngrants' to see if the call was successful. + */ + cp_grant_t *new_grants; + cp_grant_id_t g; + int new_size; + + /* Can't grow if static block already assigned. */ + if(!dynamic) + return; + + new_size = (1+ngrants)*2; + assert(new_size > ngrants); + + /* Grow block to new size. */ + if(!(new_grants=realloc(grants, new_size * sizeof(grants[0])))) + return; + + /* Make sure new slots are marked unused (CPF_USED is clear). */ + for(g = ngrants; g < new_size; g++) + grants[g].cp_flags = 0; + + /* Inform kernel about new size (and possibly new location). */ + if(sys_privctl(SELF, SYS_PRIV_SET_GRANTS, new_size, new_grants)) + return; /* Failed - don't grow then. */ + + /* Update internal data. */ + grants = new_grants; + ngrants = new_size; +} + +PRIVATE cp_grant_id_t +cpf_new_grantslot(void) +{ +/* Find a new, free grant slot in the grant table, grow it if + * necessary. If no free slot is found and the grow failed, + * return -1. Otherwise, return grant slot number. + */ + static cp_grant_id_t i = 0; + cp_grant_id_t g; + int n = 0; + + /* Any slots at all? */ + if(ngrants < 1) { + errno = ENOSPC; + return -1; + } + + /* Find free slot. */ + for(g = i % ngrants; + n < ngrants && (grants[g].cp_flags & CPF_USED); n++) + g = (g+1) % ngrants; + + /* Where to start searching next time. */ + i = g+1; + + assert(g <= ngrants); + assert(n <= ngrants); + + /* No free slot found? */ + if(n == ngrants) { + cpf_grow(); + assert(n <= ngrants); /* ngrants can't shrink. */ + if(n == ngrants) { + /* ngrants hasn't increased. */ + errno = ENOSPC; + return -1; + } + /* The new grant is the first available new grant slot. */ + g = n; + } + + /* Basic sanity checks - if we get this far, g must be a valid, + * free slot. + */ + assert(GRANT_VALID(g)); + assert(g >= 0); + assert(g < ngrants); + assert(!(grants[g].cp_flags & CPF_USED)); + + return g; +} + +PUBLIC cp_grant_id_t +cpf_grant_direct(endpoint_t who_to, vir_bytes addr, size_t bytes, int access) +{ + cp_grant_id_t g; + + /* Get new slot to put new grant in. */ + if((g = cpf_new_grantslot()) < 0) + return -1; + + /* Don't let caller specify any other flags than access. */ + if(access & ~(CPF_READ|CPF_WRITE)) { + errno = EINVAL; + return -1; + } + + assert(GRANT_VALID(g)); + assert(g >= 0); + assert(g < ngrants); + assert(!(grants[g].cp_flags & CPF_USED)); + + grants[g].cp_flags = CPF_USED | CPF_DIRECT | access; + grants[g].cp_u.cp_direct.cp_who_to = who_to; + grants[g].cp_u.cp_direct.cp_start = addr; + grants[g].cp_u.cp_direct.cp_len = bytes; + + return g; +} + +PUBLIC cp_grant_id_t +cpf_grant_indirect(endpoint_t who_to, endpoint_t who_from, cp_grant_id_t gr) +{ +/* Grant process A access into process B. B has granted us access as grant + * id 'gr'. + */ + cp_grant_id_t g; + + /* Obtain new slot. */ + if((g = cpf_new_grantslot()) < 0) + return -1; + + /* Basic sanity checks. */ + assert(GRANT_VALID(g)); + assert(g >= 0); + assert(g < ngrants); + assert(!(grants[g].cp_flags & CPF_USED)); + + /* Fill in new slot data. */ + grants[g].cp_flags = CPF_USED | CPF_INDIRECT; + grants[g].cp_u.cp_indirect.cp_who_to = who_to; + grants[g].cp_u.cp_indirect.cp_who_from = who_from; + grants[g].cp_u.cp_indirect.cp_grant = gr; + + return g; +} + +PUBLIC cp_grant_id_t +cpf_grant_magic(endpoint_t who_to, endpoint_t who_from, + vir_bytes addr, size_t bytes, int access) +{ +/* Grant process A access into process B. Not everyone can do this. */ + cp_grant_id_t g; + + /* Obtain new slot. */ + if((g = cpf_new_grantslot()) < 0) + return -1; + + /* Basic sanity checks. */ + assert(GRANT_VALID(g)); + assert(g >= 0); + assert(g < ngrants); + assert(!(grants[g].cp_flags & CPF_USED)); + + /* Don't let caller specify any other flags than access. */ + if(access & ~(CPF_READ|CPF_WRITE)) { + errno = EINVAL; + return -1; + } + + /* Fill in new slot data. */ + grants[g].cp_flags = CPF_USED | CPF_MAGIC | access; + grants[g].cp_u.cp_magic.cp_who_to = who_to; + grants[g].cp_u.cp_magic.cp_who_from = who_from; + grants[g].cp_u.cp_magic.cp_start = addr; + grants[g].cp_u.cp_magic.cp_len = bytes; + + return g; +} + +PUBLIC int +cpf_revoke(cp_grant_id_t g) +{ +/* Revoke previously granted access, identified by grant id. */ + /* First check slot validity, and if it's in use currently. */ + if(g < 0 || g >= ngrants || !(grants[g].cp_flags & CPF_USED)) { + errno = EINVAL; + return -1; + } + + /* Make grant invalid by setting flags to 0, clearing CPF_USED. + * This invalidates the grant. + */ + grants[g].cp_flags = 0; + + return 0; +} + +PUBLIC int +cpf_lookup(cp_grant_id_t g, endpoint_t *granter, endpoint_t *grantee) +{ + /* First check slot validity, and if it's in use currently. */ + if(!GRANT_VALID(g) || + g < 0 || g >= ngrants || !(grants[g].cp_flags & CPF_USED)) { + errno = EINVAL; + return -1; + } + + if(grants[g].cp_flags & CPF_DIRECT) { + if(granter) *granter = SELF; + if(grantee) *grantee = grants[g].cp_u.cp_direct.cp_who_to; + } else if(grants[g].cp_flags & CPF_MAGIC) { + if(granter) *granter = grants[g].cp_u.cp_magic.cp_who_from; + if(grantee) *grantee = grants[g].cp_u.cp_magic.cp_who_to; + } else return -1; + + return 0; +} + diff --git a/lib/syslib/sys_in.c b/lib/syslib/sys_in.c index cfa203ad7..2a6fa0cc8 100644 --- a/lib/syslib/sys_in.c +++ b/lib/syslib/sys_in.c @@ -11,8 +11,7 @@ int type; /* byte, word, long */ message m_io; int result; - m_io.DIO_TYPE = type; - m_io.DIO_REQUEST = DIO_INPUT; + m_io.DIO_REQUEST = _DIO_INPUT | type; m_io.DIO_PORT = port; result = _taskcall(SYSTASK, SYS_DEVIO, &m_io); diff --git a/lib/syslib/sys_out.c b/lib/syslib/sys_out.c index 0d62d5ffc..f1f2a03d7 100644 --- a/lib/syslib/sys_out.c +++ b/lib/syslib/sys_out.c @@ -10,8 +10,7 @@ int type; /* byte, word, long */ { message m_io; - m_io.DIO_TYPE = type; - m_io.DIO_REQUEST = DIO_OUTPUT; + m_io.DIO_REQUEST = _DIO_OUTPUT | type; m_io.DIO_PORT = port; m_io.DIO_VALUE = value; diff --git a/lib/syslib/sys_safecopy.c b/lib/syslib/sys_safecopy.c new file mode 100644 index 000000000..2060c3f20 --- /dev/null +++ b/lib/syslib/sys_safecopy.c @@ -0,0 +1,48 @@ + +#include "syslib.h" + +#include + +PUBLIC int sys_safecopyfrom(endpoint_t src_e, + cp_grant_id_t gr_id, vir_bytes offset, + vir_bytes address, size_t bytes, + int my_seg) +{ +/* Transfer a block of data for which the other process has previously + * given permission. + */ + + message copy_mess; + + copy_mess.SCP_FROM_TO = src_e; + copy_mess.SCP_INFO = SCP_MAKEINFO(my_seg); + copy_mess.SCP_GID = gr_id; + copy_mess.SCP_OFFSET = (long) offset; + copy_mess.SCP_ADDRESS = (char *) address; + copy_mess.SCP_BYTES = (long) bytes; + + return(_taskcall(SYSTASK, SYS_SAFECOPYFROM, ©_mess)); + +} + +PUBLIC int sys_safecopyto(endpoint_t dst_e, + cp_grant_id_t gr_id, vir_bytes offset, + vir_bytes address, size_t bytes, + int my_seg) +{ +/* Transfer a block of data for which the other process has previously + * given permission. + */ + + message copy_mess; + + copy_mess.SCP_FROM_TO = dst_e; + copy_mess.SCP_INFO = SCP_MAKEINFO(my_seg); + copy_mess.SCP_GID = gr_id; + copy_mess.SCP_OFFSET = (long) offset; + copy_mess.SCP_ADDRESS = (char *) address; + copy_mess.SCP_BYTES = (long) bytes; + + return(_taskcall(SYSTASK, SYS_SAFECOPYTO, ©_mess)); + +} diff --git a/lib/syslib/sys_sdevio.c b/lib/syslib/sys_sdevio.c index 481d74ae6..e6bfcb2f8 100644 --- a/lib/syslib/sys_sdevio.c +++ b/lib/syslib/sys_sdevio.c @@ -3,23 +3,23 @@ /*===========================================================================* * sys_sdevio * *===========================================================================*/ -PUBLIC int sys_sdevio(req, port, type, proc_nr, buffer, count) -int req; /* request: DIO_INPUT/ DIO_OUTPUT */ +PUBLIC int sys_sdevio(req, port, proc_nr, buffer, count, offset) +int req; /* request: DIO_{IN,OUT}PUT_* */ long port; /* port address to read from */ -int type; /* byte, word, long */ -int proc_nr; /* process where buffer is */ +endpoint_t proc_nr; /* process where buffer is */ void *buffer; /* pointer to buffer */ int count; /* number of elements */ +vir_bytes offset; /* offset from grant */ { message m_io; int result; m_io.DIO_REQUEST = req; - m_io.DIO_TYPE = type; m_io.DIO_PORT = port; m_io.DIO_VEC_ENDPT = proc_nr; m_io.DIO_VEC_ADDR = buffer; m_io.DIO_VEC_SIZE = count; + m_io.DIO_OFFSET = offset; return(_taskcall(SYSTASK, SYS_SDEVIO, &m_io)); } diff --git a/lib/syslib/sys_vinb.c b/lib/syslib/sys_vinb.c index c74d79970..af1cc2be7 100644 --- a/lib/syslib/sys_vinb.c +++ b/lib/syslib/sys_vinb.c @@ -9,8 +9,7 @@ int nr_ports; /* nr of pairs to be processed */ { message m_io; - m_io.DIO_TYPE = DIO_BYTE; - m_io.DIO_REQUEST = DIO_INPUT; + m_io.DIO_REQUEST = _DIO_INPUT | _DIO_BYTE; m_io.DIO_VEC_ADDR = (char *) pvb_pairs; m_io.DIO_VEC_SIZE = nr_ports; return _taskcall(SYSTASK, SYS_VDEVIO, &m_io); diff --git a/lib/syslib/sys_vinl.c b/lib/syslib/sys_vinl.c index 8ff83c34c..1649a76e3 100644 --- a/lib/syslib/sys_vinl.c +++ b/lib/syslib/sys_vinl.c @@ -9,8 +9,7 @@ int nr_ports; /* nr of pairs to be processed */ { message m_io; - m_io.DIO_TYPE = DIO_LONG; - m_io.DIO_REQUEST = DIO_INPUT; + m_io.DIO_REQUEST = _DIO_INPUT | _DIO_LONG; m_io.DIO_VEC_ADDR = (char *) pvl_pairs; m_io.DIO_VEC_SIZE = nr_ports; return _taskcall(SYSTASK, SYS_VDEVIO, &m_io); diff --git a/lib/syslib/sys_vinw.c b/lib/syslib/sys_vinw.c index e01c46610..c2ba3eeb7 100644 --- a/lib/syslib/sys_vinw.c +++ b/lib/syslib/sys_vinw.c @@ -10,8 +10,7 @@ int nr_ports; /* nr of pairs to be processed */ { message m_io; - m_io.DIO_TYPE = DIO_WORD; - m_io.DIO_REQUEST = DIO_INPUT; + m_io.DIO_REQUEST = _DIO_WORD | _DIO_INPUT; m_io.DIO_VEC_ADDR = (char *) pvw_pairs; m_io.DIO_VEC_SIZE = nr_ports; return _taskcall(SYSTASK, SYS_VDEVIO, &m_io); diff --git a/lib/syslib/sys_voutb.c b/lib/syslib/sys_voutb.c index 35d379bd9..42467274e 100644 --- a/lib/syslib/sys_voutb.c +++ b/lib/syslib/sys_voutb.c @@ -8,8 +8,7 @@ pvb_pair_t *pvb_pairs; /* (port,byte-value)-pairs */ int nr_ports; /* nr of pairs to be processed */ { message m_io; - m_io.DIO_TYPE = DIO_BYTE; - m_io.DIO_REQUEST = DIO_OUTPUT; + m_io.DIO_REQUEST = _DIO_OUTPUT | _DIO_BYTE; m_io.DIO_VEC_ADDR = (char *) pvb_pairs; m_io.DIO_VEC_SIZE = nr_ports; return _taskcall(SYSTASK, SYS_VDEVIO, &m_io); diff --git a/lib/syslib/sys_voutl.c b/lib/syslib/sys_voutl.c index 184223dae..1cec294d9 100644 --- a/lib/syslib/sys_voutl.c +++ b/lib/syslib/sys_voutl.c @@ -9,8 +9,7 @@ int nr_ports; /* nr of pairs to be processed */ { message m_io; - m_io.DIO_TYPE = DIO_LONG; - m_io.DIO_REQUEST = DIO_OUTPUT; + m_io.DIO_REQUEST = _DIO_OUTPUT | _DIO_LONG; m_io.DIO_VEC_ADDR = (char *) pvl_pairs; m_io.DIO_VEC_SIZE = nr_ports; return _taskcall(SYSTASK, SYS_VDEVIO, &m_io); diff --git a/lib/syslib/sys_voutw.c b/lib/syslib/sys_voutw.c index a8d20f70e..107e2ecde 100644 --- a/lib/syslib/sys_voutw.c +++ b/lib/syslib/sys_voutw.c @@ -10,8 +10,7 @@ int nr_ports; /* nr of pairs to be processed */ { message m_io; - m_io.DIO_TYPE = DIO_WORD; - m_io.DIO_REQUEST = DIO_OUTPUT; + m_io.DIO_REQUEST = _DIO_OUTPUT | _DIO_WORD; m_io.DIO_VEC_ADDR = (char *) pvw_pairs; m_io.DIO_VEC_SIZE = nr_ports; return _taskcall(SYSTASK, SYS_VDEVIO, &m_io); diff --git a/lib/sysutil/kputc.c b/lib/sysutil/kputc.c index 18aa3d03a..ba1f23fe9 100644 --- a/lib/sysutil/kputc.c +++ b/lib/sysutil/kputc.c @@ -9,6 +9,8 @@ #include "sysutil.h" +static char print_buf[80]; /* output is buffered here */ + /*===========================================================================* * kputc * *===========================================================================*/ @@ -17,21 +19,42 @@ int c; { /* Accumulate another character. If 0 or buffer full, print it. */ static int buf_count; /* # characters in the buffer */ - static char print_buf[80]; /* output is buffered here */ message m; if ((c == 0 && buf_count > 0) || buf_count == sizeof(print_buf)) { +#define PRINTPROCS (sizeof(procs)/sizeof(procs[0])) int procs[] = OUTPUT_PROCS_ARRAY; + static int firstprint = 1; + static cp_grant_t printgrant_buffer[PRINTPROCS]; + static cp_grant_id_t printgrants[PRINTPROCS]; int p; + if(firstprint) { + /* First time? Initialize grant table; + * Grant printing processes read copy access to our + * print buffer. (So buffer can't be on stack!) + */ + cpf_preallocate(printgrant_buffer, PRINTPROCS); + for(p = 0; procs[p] != NONE; p++) { + printgrants[p] = cpf_grant_direct(procs[p], print_buf, + sizeof(print_buf), CPF_READ); + } + firstprint = 0; + } + for(p = 0; procs[p] != NONE; p++) { /* Send the buffer to this output driver. */ m.DIAG_BUF_COUNT = buf_count; - m.DIAG_PRINT_BUF = print_buf; - m.DIAG_ENDPT = SELF; - m.m_type = DIAGNOSTICS; + if(GRANT_VALID(printgrants[p])) { + m.m_type = DIAGNOSTICS_S; + m.DIAG_PRINT_BUF_G = printgrants[p]; + } else { + m.m_type = DIAGNOSTICS; + m.DIAG_PRINT_BUF_G = print_buf; + } (void) _sendrec(procs[p], &m); } + buf_count = 0; /* If the output fails, e.g., due to an ELOCKED, do not retry output