. 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
This commit is contained in:
parent
cfb984e9bd
commit
9df1183b94
14 changed files with 355 additions and 26 deletions
|
@ -14,7 +14,7 @@ extern _CONST char ***_penviron;
|
|||
|
||||
int
|
||||
putenv(name)
|
||||
_CONST char *name;
|
||||
char *name;
|
||||
{
|
||||
register _CONST char **v = *_penviron;
|
||||
register char *r;
|
||||
|
|
|
@ -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 \
|
||||
|
|
264
lib/syslib/safecopies.c
Normal file
264
lib/syslib/safecopies.c
Normal file
|
@ -0,0 +1,264 @@
|
|||
|
||||
/* Library functions to maintain internal data copying tables.
|
||||
*
|
||||
* April 21 2006: Initial version (Ben Gras)
|
||||
*
|
||||
*/
|
||||
|
||||
#include <lib.h>
|
||||
#include <errno.h>
|
||||
#include <minix/sysutil.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <minix/syslib.h>
|
||||
#include <minix/safecopies.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
48
lib/syslib/sys_safecopy.c
Normal file
48
lib/syslib/sys_safecopy.c
Normal file
|
@ -0,0 +1,48 @@
|
|||
|
||||
#include "syslib.h"
|
||||
|
||||
#include <minix/safecopies.h>
|
||||
|
||||
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));
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue