diff --git a/commands/ps/ps.c b/commands/ps/ps.c index 03d637a77..08efe8a50 100644 --- a/commands/ps/ps.c +++ b/commands/ps/ps.c @@ -84,6 +84,7 @@ #include "../../kernel/proc.h" #include "../../servers/pm/mproc.h" +#include "../../servers/pm/const.h" #include "../../servers/vfs/fproc.h" #include "../../servers/vfs/const.h" #include "../../servers/mfs/const.h" @@ -518,12 +519,18 @@ int endpoints; if(endpoints) bufp->ps_pid = ps_proc[p_ki].p_endpoint; else bufp->ps_pid = ps_mproc[p_nr].mp_pid; bufp->ps_ppid = ps_mproc[ps_mproc[p_nr].mp_parent].mp_pid; + /* Assume no parent when the parent and the child share the same pid. + * This is what PM currently assumes. + */ + if(bufp->ps_ppid == bufp->ps_pid) { + bufp->ps_ppid = NO_PID; + } bufp->ps_pgrp = ps_mproc[p_nr].mp_procgrp; bufp->ps_mflags = ps_mproc[p_nr].mp_flags; } else { if(endpoints) bufp->ps_pid = ps_proc[p_ki].p_endpoint; - else bufp->ps_pid = 0; - bufp->ps_ppid = 0; + else bufp->ps_pid = NO_PID; + bufp->ps_ppid = NO_PID; bufp->ps_ruid = bufp->ps_euid = 0; bufp->ps_pgrp = 0; bufp->ps_mflags = 0; diff --git a/include/minix/com.h b/include/minix/com.h index 0b95b687a..82f573fe4 100644 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -73,6 +73,10 @@ #define VM_PROC_NR 8 /* memory server */ #define INIT_PROC_NR 9 /* init -- goes multiuser */ +/* Root system process and root user process. */ +#define ROOT_SYS_PROC_NR RS_PROC_NR +#define ROOT_USR_PROC_NR INIT_PROC_NR + /* Number of processes contained in the system image. */ #define NR_BOOT_PROCS (NR_TASKS + INIT_PROC_NR + 1) @@ -354,15 +358,15 @@ #define SYS_ALL_CALLS (NR_SYS_CALLS) /* Subfunctions for SYS_PRIVCTL */ -#define SYS_PRIV_INIT 1 /* Initialize a privilege structure */ -#define SYS_PRIV_ADD_IO 2 /* Add I/O range (struct io_range) */ -#define SYS_PRIV_ADD_MEM 3 /* Add memory range (struct mem_range) +#define SYS_PRIV_ALLOW 1 /* Allow process to run */ +#define SYS_PRIV_DISALLOW 2 /* Disallow process to run */ +#define SYS_PRIV_SET_SYS 3 /* Set a system privilege structure */ +#define SYS_PRIV_SET_USER 4 /* Set a user privilege structure */ +#define SYS_PRIV_ADD_IO 5 /* Add I/O range (struct io_range) */ +#define SYS_PRIV_ADD_MEM 6 /* Add memory range (struct mem_range) */ -#define SYS_PRIV_ADD_IRQ 4 /* Add IRQ */ -#define SYS_PRIV_USER 5 /* Make a process an oridinary user - * process. - */ -#define SYS_PRIV_QUERY_MEM 6 /* Verify memory privilege. */ +#define SYS_PRIV_ADD_IRQ 7 /* Add IRQ */ +#define SYS_PRIV_QUERY_MEM 8 /* Verify memory privilege. */ /* Subfunctions for SYS_SETGRANT */ #define SYS_PARAM_SET_GRANT 1 /* Set address and size of grant table */ @@ -478,11 +482,12 @@ # define GET_BIOSBUFFER 14 /* get a buffer for BIOS calls */ # define GET_LOADINFO 15 /* get load average information */ # define GET_IRQACTIDS 16 /* get the IRQ masks */ -# define GET_PRIVID 17 /* get ID of privilege structure */ +# define GET_PRIV 17 /* get privilege structure */ # define GET_HZ 18 /* get HZ value */ # define GET_WHOAMI 19 /* get own name and endpoint */ # define GET_RANDOMNESS_BIN 20 /* get one randomness bin */ # define GET_IDLETSC 21 /* get cumulative idle time stamp counter */ +# define GET_AOUTHEADER 22 /* get a.out headers from the boot image */ #define I_ENDPT m7_i4 /* calling process */ #define I_VAL_PTR m7_p1 /* virtual address at caller */ #define I_VAL_LEN m7_i1 /* max length of value */ diff --git a/include/minix/const.h b/include/minix/const.h index e4ec34f18..010ad7df7 100644 --- a/include/minix/const.h +++ b/include/minix/const.h @@ -132,12 +132,14 @@ #define SERVARNAME "cttyline" /* Bits for the system property flags in boot image processes. */ +#define PROC_FULLVM 0x100 /* VM sets and manages full pagetable */ + +/* Bits for s_flags in the privilege structure. */ #define PREEMPTIBLE 0x02 /* kernel tasks are not preemptible */ #define BILLABLE 0x04 /* some processes are not billable */ +#define DYN_PRIV_ID 0x08 /* privilege id assigned dynamically */ #define SYS_PROC 0x10 /* system processes have own priv structure */ #define CHECK_IO_PORT 0x20 /* check if I/O request is allowed */ #define CHECK_IRQ 0x40 /* check if IRQ can be used */ #define CHECK_MEM 0x80 /* check if (VM) mem map request is allowed */ -#define PROC_FULLVM 0x100 /* VM sets and manages full pagetable */ - diff --git a/include/minix/syslib.h b/include/minix/syslib.h index 02c03bed5..60f8587da 100644 --- a/include/minix/syslib.h +++ b/include/minix/syslib.h @@ -101,7 +101,7 @@ _PROTOTYPE(void *alloc_contig, (size_t len, int flags, phys_bytes *phys)); * retrieve/set a process-virtual timer. */ _PROTOTYPE( int sys_times, (endpoint_t proc_ep, clock_t *user_time, - clock_t *sys_time, clock_t *uptime)); + clock_t *sys_time, clock_t *uptime, time_t *boottime)); _PROTOTYPE(int sys_setalarm, (clock_t exp_time, int abs_time)); _PROTOTYPE( int sys_vtimer, (endpoint_t proc_nr, int which, clock_t *newval, clock_t *oldval)); @@ -178,8 +178,9 @@ _PROTOTYPE(int sys_segctl, (int *index, u16_t *seg, vir_bytes *off, #define sys_getmonparams(v,vl) sys_getinfo(GET_MONPARAMS, v,vl, 0,0) #define sys_getschedinfo(v1,v2) sys_getinfo(GET_SCHEDINFO, v1,0, v2,0) #define sys_getlocktimings(dst) sys_getinfo(GET_LOCKTIMING, dst, 0,0,0) -#define sys_getprivid(nr) sys_getinfo(GET_PRIVID, 0, 0,0, nr) +#define sys_getpriv(dst, nr) sys_getinfo(GET_PRIV, dst, 0,0, nr) #define sys_getidletsc(dst) sys_getinfo(GET_IDLETSC, dst, 0,0,0) +#define sys_getaoutheader(dst,nr) sys_getinfo(GET_AOUTHEADER, dst, 0,0,nr) _PROTOTYPE(int sys_getinfo, (int request, void *val_ptr, int val_len, void *val_ptr2, int val_len2) ); _PROTOTYPE(int sys_whoami, (endpoint_t *ep, char *name, int namelen)); diff --git a/kernel/const.h b/kernel/const.h index 9f41136f1..771291241 100644 --- a/kernel/const.h +++ b/kernel/const.h @@ -8,9 +8,6 @@ #include "config.h" #include "debug.h" -/* Map a process number to a privilege structure id. */ -#define s_nr_to_id(n) (NR_TASKS + (n) + 1) - /* Translate a pointer to a field in a structure to a pointer to the structure * itself. So it translates '&struct_ptr->field' back to 'struct_ptr'. */ diff --git a/kernel/main.c b/kernel/main.c index 30c040585..94df07380 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -73,7 +73,8 @@ PUBLIC void main() ktsb = (reg_t) t_stack; for (i=0; i < NR_BOOT_PROCS; ++i) { - int ci; + int schedulable_proc, proc_nr; + int ipc_to_m, kcalls; bitchunk_t fv; ip = &image[i]; /* process' attributes */ @@ -84,35 +85,57 @@ PUBLIC void main() rp->p_quantum_size = ip->quantum; /* quantum size in ticks */ rp->p_ticks_left = ip->quantum; /* current credit */ strncpy(rp->p_name, ip->proc_name, P_NAME_LEN); /* set process name */ - (void) get_priv(rp, (ip->flags & SYS_PROC)); /* assign structure */ - priv(rp)->s_flags = ip->flags; /* process flags */ - priv(rp)->s_trap_mask = ip->trap_mask; /* allowed traps */ - /* Warn about violations of the boot image table order consistency. */ - if (priv_id(rp) != s_nr_to_id(ip->proc_nr) && (ip->flags & SYS_PROC)) - kprintf("Warning: boot image table has wrong process order\n"); - - /* Initialize call mask bitmap from unordered set. - * A single SYS_ALL_CALLS is a special case - it - * means all calls are allowed. + /* See if this process is immediately schedulable. + * In that case, set its privileges now and allow it to run. + * Only kernel tasks and the root system process get to run immediately. + * All the other system processes are inhibited from running by the + * RTS_NO_PRIV flag. They can only be scheduled once the root system + * process has set their privileges. */ - if(ip->nr_k_calls == 1 && ip->k_calls[0] == SYS_ALL_CALLS) - fv = ~0; /* fill call mask */ - else - fv = 0; /* clear call mask */ + proc_nr = proc_nr(rp); + schedulable_proc = (iskerneln(proc_nr) || isrootsysn(proc_nr)); + if(schedulable_proc) { + /* Assign privilege structure. Force a static privilege id. */ + (void) get_priv(rp, static_priv_id(proc_nr)); - for(ci = 0; ci < CALL_MASK_SIZE; ci++) /* fill or clear call mask */ - priv(rp)->s_k_call_mask[ci] = fv; - if(!fv) /* not all full? enter calls bit by bit */ - for(ci = 0; ci < ip->nr_k_calls; ci++) - SET_BIT(priv(rp)->s_k_call_mask, - ip->k_calls[ci]-KERNEL_CALL); + /* Priviliges for kernel tasks. */ + if(iskerneln(proc_nr)) { + /* Privilege flags. */ + priv(rp)->s_flags = (proc_nr == IDLE ? IDL_F : TSK_F); + /* Allowed traps. */ + priv(rp)->s_trap_mask = (proc_nr == CLOCK + || proc_nr == SYSTEM ? CSK_T : TSK_T); + ipc_to_m = TSK_M; /* allowed targets */ + kcalls = TSK_KC; /* allowed kernel calls */ + } + /* Priviliges for the root system process. */ + else if(isrootsysn(proc_nr)) { + priv(rp)->s_flags= RSYS_F; /* privilege flags */ + priv(rp)->s_trap_mask= RSYS_T; /* allowed traps */ + ipc_to_m = RSYS_M; /* allowed targets */ + kcalls = RSYS_KC; /* allowed kernel calls */ + } - for (j = 0; j < NR_SYS_PROCS && j < BITCHUNK_BITS; j++) - if (ip->ipc_to & (1 << j)) - set_sendto_bit(rp, j); /* restrict targets */ + /* Fill in target mask. */ + for (j=0; j < NR_SYS_PROCS; j++) { + if (ipc_to_m & (1 << j)) + set_sendto_bit(rp, j); + else + unset_sendto_bit(rp, j); + } - if (iskerneln(proc_nr(rp))) { /* part of the kernel? */ + /* Fill in kernel call mask. */ + for(j = 0; j < CALL_MASK_SIZE; j++) { + priv(rp)->s_k_call_mask[j] = (kcalls == NO_C ? 0 : (~0)); + } + } + else { + /* Don't let the process run for now. */ + RTS_SET(rp, RTS_NO_PRIV); + } + + if (iskerneln(proc_nr)) { /* part of the kernel? */ if (ip->stksize > 0) { /* HARDWARE stack size is 0 */ rp->p_priv->s_stack_guard = (reg_t *) ktsb; *rp->p_priv->s_stack_guard = STACK_GUARD; @@ -121,7 +144,7 @@ PUBLIC void main() rp->p_reg.sp = ktsb; /* this task's initial stack ptr */ hdrindex = 0; /* all use the first a.out header */ } else { - hdrindex = 1 + i-NR_TASKS; /* servers, drivers, INIT */ + hdrindex = 1 + i-NR_TASKS; /* system/user processes */ } /* Architecture-specific way to find out aout header of this @@ -153,12 +176,12 @@ PUBLIC void main() * access I/O; this is not allowed to less-privileged processes */ rp->p_reg.pc = (reg_t) ip->initial_pc; - rp->p_reg.psw = (iskernelp(rp)) ? INIT_TASK_PSW : INIT_PSW; + rp->p_reg.psw = (iskerneln(proc_nr)) ? INIT_TASK_PSW : INIT_PSW; /* Initialize the server stack pointer. Take it down one word * to give crtso.s something to use as "argc". */ - if (isusern(proc_nr(rp))) { /* user-space process? */ + if (isusern(proc_nr)) { /* user-space process? */ rp->p_reg.sp = (rp->p_memmap[S].mem_vir + rp->p_memmap[S].mem_len) << CLICK_SHIFT; rp->p_reg.sp -= sizeof(reg_t); @@ -171,9 +194,9 @@ PUBLIC void main() * PT up and manage it. VM will signal the kernel when it has * done this; until then, don't let it run. */ - if(priv(rp)->s_flags & PROC_FULLVM) + if(ip->flags & PROC_FULLVM) RTS_SET(rp, RTS_VMINHIBIT); - + /* Set ready. The HARDWARE task is never ready. */ if (rp->p_nr == HARDWARE) RTS_SET(rp, RTS_PROC_STOP); /* IDLE task is never put on a run queue as it is never ready to run */ diff --git a/kernel/priv.h b/kernel/priv.h index 6775be7fb..39a397aaa 100644 --- a/kernel/priv.h +++ b/kernel/priv.h @@ -9,7 +9,8 @@ * between common and privileged process fields and is very space efficient. * * Changes: - * Jul 01, 2005 Created. (Jorrit N. Herder) + * Nov 22, 2009 rewrite of privilege management (Cristiano Giuffrida) + * Jul 01, 2005 Created. (Jorrit N. Herder) */ #include #include "const.h" @@ -65,9 +66,18 @@ struct priv { /* Guard word for task stacks. */ #define STACK_GUARD ((reg_t) (sizeof(reg_t) == 2 ? 0xBEEF : 0xDEADBEEF)) +/* Static privilege id definitions. */ +#define NR_STATIC_PRIV_IDS NR_BOOT_PROCS +#define is_static_priv_id(id) (id >= 0 && id < NR_STATIC_PRIV_IDS) +#define static_priv_id(n) (NR_TASKS + (n)) + /* Magic system structure table addresses. */ -#define BEG_PRIV_ADDR (&priv[0]) -#define END_PRIV_ADDR (&priv[NR_SYS_PROCS]) +#define BEG_PRIV_ADDR (&priv[0]) +#define END_PRIV_ADDR (&priv[NR_SYS_PROCS]) +#define BEG_STATIC_PRIV_ADDR BEG_PRIV_ADDR +#define END_STATIC_PRIV_ADDR (BEG_STATIC_PRIV_ADDR + NR_STATIC_PRIV_IDS) +#define BEG_DYN_PRIV_ADDR END_STATIC_PRIV_ADDR +#define END_DYN_PRIV_ADDR END_PRIV_ADDR #define priv_addr(i) (ppriv_addr)[(i)] #define priv_id(rp) ((rp)->p_priv->s_id) @@ -78,6 +88,10 @@ struct priv { #define may_send_to(rp, nr) (get_sys_bit(priv(rp)->s_ipc_to, nr_to_id(nr))) +/* Privilege management shorthands. */ +#define spi_to(n) (1 << (static_priv_id(n))) +#define unset_usr_to(m) ((m) & ~(1 << USER_PRIV_ID)) + /* The system structures table and pointers to individual table slots. The * pointers allow faster access because now a process entry can be found by * indexing the psys_addr array, while accessing an element i requires a @@ -86,10 +100,14 @@ struct priv { EXTERN struct priv priv[NR_SYS_PROCS]; /* system properties table */ EXTERN struct priv *ppriv_addr[NR_SYS_PROCS]; /* direct slot pointers */ -/* Unprivileged user processes all share the same privilege structure. +/* Unprivileged user processes all share the privilege structure of the + * root user process. * This id must be fixed because it is used to check send mask entries. */ -#define USER_PRIV_ID 0 +#define USER_PRIV_ID static_priv_id(ROOT_USR_PROC_NR) +/* Specifies a null privilege id. + */ +#define NULL_PRIV_ID -1 /* Make sure the system can boot. The following sanity check verifies that * the system privileges table is large enough for the number of processes @@ -99,4 +117,37 @@ EXTERN struct priv *ppriv_addr[NR_SYS_PROCS]; /* direct slot pointers */ #error NR_SYS_PROCS must be larger than NR_BOOT_PROCS #endif +/* + * Privileges masks used by the kernel. + */ +#define IDL_F (SYS_PROC | BILLABLE) /* idle task is not preemptible as we + * don't want it to interfere with the + * timer tick interrupt handler code. + * Unlike other processes idle task is + * handled in a special way and is + * preempted always if timer tick occurs + * and there is another runnable process + */ +#define TSK_F (SYS_PROC) /* other kernel tasks */ +#define RSYS_F (SYS_PROC | PREEMPTIBLE) /* root system proc */ +#define DEF_SYS_F (RSYS_F | DYN_PRIV_ID) /* default sys proc */ + +/* allowed traps */ +#define CSK_T (1 << RECEIVE) /* clock and system */ +#define TSK_T 0 /* other kernel tasks */ +#define RSYS_T (~0) /* root system proc */ +#define DEF_SYS_T RSYS_T /* default sys proc */ + +/* allowed targets */ +#define TSK_M 0 /* all kernel tasks */ +#define RSYS_M (~0) /* root system proc */ +#define DEF_SYS_M unset_usr_to(RSYS_M) /* default sys proc */ + +/* allowed kernel calls */ +#define NO_C 0 /* no calls allowed */ +#define ALL_C 1 /* all calls allowed */ +#define TSK_KC NO_C /* all kernel tasks */ +#define RSYS_KC ALL_C /* root system proc */ +#define DEF_SYS_KC RSYS_KC /* default sys proc */ + #endif /* PRIV_H */ diff --git a/kernel/proc.c b/kernel/proc.c index c39470937..f693525d6 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -824,7 +824,7 @@ endpoint_t dst_e; /* which process to notify */ } /* Destination is not ready to receive the notification. Add it to the - * bit map with pending notifications. Note the indirectness: the system id + * bit map with pending notifications. Note the indirectness: the privilege id * instead of the process number is used in the pending bit map. */ src_id = priv(caller_ptr)->s_id; diff --git a/kernel/proc.h b/kernel/proc.h index 4606b5717..092edbe06 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -250,6 +250,8 @@ struct proc { #define iskerneln(n) ((n) < 0) #define isuserp(p) isusern((p) >= BEG_USER_ADDR) #define isusern(n) ((n) >= 0) +#define isrootsysp(p) isrootsysn((p)->p_nr) +#define isrootsysn(n) ((n) == ROOT_SYS_PROC_NR) #ifndef __ASSEMBLY__ diff --git a/kernel/system.c b/kernel/system.c index b949ac2db..e4d72d17d 100644 --- a/kernel/system.c +++ b/kernel/system.c @@ -22,6 +22,7 @@ * clear_endpoint: remove a process' ability to send and receive messages * * Changes: +* Nov 22, 2009 get_priv supports static priv ids (Cristiano Giuffrida) * Aug 04, 2005 check if system call is allowed (Jorrit N. Herder) * Jul 20, 2005 send signal to services with message (Jorrit N. Herder) * Jan 15, 2005 new, generalized virtual copy function (Jorrit N. Herder) @@ -238,32 +239,36 @@ PRIVATE void initialize(void) /*===========================================================================* * get_priv * *===========================================================================*/ -PUBLIC int get_priv(rc, proc_type) +PUBLIC int get_priv(rc, priv_id) register struct proc *rc; /* new (child) process pointer */ -int proc_type; /* system or user process flag */ +int priv_id; /* privilege id */ { -/* Get a privilege structure. All user processes share the same privilege - * structure. System processes get their own privilege structure. +/* Allocate a new privilege structure for a system process. Privilege ids + * can be assigned either statically or dynamically. */ - register struct priv *sp; /* privilege structure */ + register struct priv *sp; /* privilege structure */ - if (proc_type == SYS_PROC) { /* find a new slot */ - for (sp = BEG_PRIV_ADDR; sp < END_PRIV_ADDR; ++sp) - if (sp->s_proc_nr == NONE && sp->s_id != USER_PRIV_ID) break; - if (sp >= END_PRIV_ADDR) return(ENOSPC); - rc->p_priv = sp; /* assign new slot */ - rc->p_priv->s_proc_nr = proc_nr(rc); /* set association */ - rc->p_priv->s_flags = SYS_PROC; /* mark as privileged */ - - /* Clear some fields */ - sp->s_asyntab= -1; - sp->s_asynsize= 0; - } else { - rc->p_priv = &priv[USER_PRIV_ID]; /* use shared slot */ - rc->p_priv->s_proc_nr = INIT_PROC_NR; /* set association */ - - /* s_flags of this shared structure are to be once at system startup. */ + if(priv_id == NULL_PRIV_ID) { /* allocate slot dynamically */ + for (sp = BEG_DYN_PRIV_ADDR; sp < END_DYN_PRIV_ADDR; ++sp) + if (sp->s_proc_nr == NONE) break; + if (sp >= END_DYN_PRIV_ADDR) return(ENOSPC); } + else { /* allocate slot from id */ + if(!is_static_priv_id(priv_id)) { + return EINVAL; /* invalid static priv id */ + } + if(priv[priv_id].s_proc_nr != NONE) { + return EBUSY; /* slot already in use */ + } + sp = &priv[priv_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); } @@ -275,22 +280,24 @@ PUBLIC void set_sendto_bit(struct proc *rp, int id) /* Allow a process to send messages to the process(es) associated with the * system privilege structure with the given ID. */ - struct proc *rrp; /* receiver process */ - /* Disallow the process from sending to a system privilege structure with no + /* Disallow the process from sending to a process privilege structure with no * associated process, and disallow the process from sending to itself. */ - if (id_to_nr(id) == NONE || priv_id(rp) == id) + if (id_to_nr(id) == NONE || priv_id(rp) == id) { + unset_sys_bit(priv(rp)->s_ipc_to, id); return; + } set_sys_bit(priv(rp)->s_ipc_to, id); - /* The process that this process can now send to, must be able to reply. - * Therefore, its send mask should be updated as well. + /* The process that this process can now send to, must be able to reply (or + * vice versa). Therefore, its send mask should be updated as well. Ignore + * receivers that don't support traps other than RECEIVE, they can't reply + * or send messages anyway. */ - rrp = proc_addr(id_to_nr(id)); - if (!iskernelp(rrp)) - set_sys_bit(priv(rrp)->s_ipc_to, priv_id(rp)); + if (priv_addr(id)->s_trap_mask & ~((1 << RECEIVE))) + set_sys_bit(priv_addr(id)->s_ipc_to, priv_id(rp)); } /*===========================================================================* diff --git a/kernel/system/do_getinfo.c b/kernel/system/do_getinfo.c index 22cbcbe5c..f7568c71e 100644 --- a/kernel/system/do_getinfo.c +++ b/kernel/system/do_getinfo.c @@ -10,6 +10,7 @@ */ #include +#include #include "../system.h" #include "../vm.h" @@ -31,6 +32,7 @@ register message *m_ptr; /* pointer to request message */ int proc_nr, nr_e, nr, r; struct proc *caller; int wipe_rnd_bin = -1; + struct exec e_hdr; caller = proc_addr(who_p); @@ -84,6 +86,14 @@ register message *m_ptr; /* pointer to request message */ src_vir = (vir_bytes) proc_addr(nr); break; } + case GET_PRIV: { + nr_e = (m_ptr->I_VAL_LEN2_E == SELF) ? + who_e : m_ptr->I_VAL_LEN2_E; + if(!isokendpt(nr_e, &nr)) return EINVAL; /* validate request */ + length = sizeof(struct priv); + src_vir = (vir_bytes) priv_addr(nr_to_id(nr)); + break; + } case GET_WHOAMI: { int len; /* GET_WHOAMI uses m3 and only uses the message contents for info. */ @@ -146,11 +156,6 @@ register message *m_ptr; /* pointer to request message */ src_vir = (vir_bytes) irq_actids; break; } - case GET_PRIVID: { - if (!isokendpt(m_ptr->I_VAL_LEN2_E, &proc_nr)) - return EINVAL; - return proc_addr(proc_nr)->p_priv->s_id; - } case GET_IDLETSC: { #ifdef CONFIG_IDLE_TSC length = sizeof(idle_tsc); @@ -161,6 +166,22 @@ register message *m_ptr; /* pointer to request message */ return(EINVAL); #endif } + case GET_AOUTHEADER: { + int hdrindex, index = m_ptr->I_VAL_LEN2_E; + if(index < 0 || index >= NR_BOOT_PROCS) { + return EINVAL; + } + if (iskerneln(_ENDPOINT_P(image[index].endpoint))) { + hdrindex = 0; + } else { + hdrindex = 1 + index-NR_TASKS; + } + arch_get_aout_headers(hdrindex, &e_hdr); + length = sizeof(e_hdr); + src_vir = (vir_bytes) &e_hdr; + break; + } + default: kprintf("do_getinfo: invalid request %d\n", m_ptr->I_REQUEST); return(EINVAL); diff --git a/kernel/system/do_privctl.c b/kernel/system/do_privctl.c index befcb043d..d32ade0dc 100644 --- a/kernel/system/do_privctl.c +++ b/kernel/system/do_privctl.c @@ -14,8 +14,6 @@ #if USE_PRIVCTL -#define FILLED_MASK (~0) - /*===========================================================================* * do_privctl * *===========================================================================*/ @@ -29,6 +27,7 @@ message *m_ptr; /* pointer to request message */ register struct proc *rp; int proc_nr; int priv_id; + int ipc_to_m, kcalls; int i, r; struct io_range io_range; struct mem_range mem_range; @@ -48,16 +47,49 @@ message *m_ptr; /* pointer to request message */ switch(m_ptr->CTL_REQUEST) { - case SYS_PRIV_INIT: + case SYS_PRIV_ALLOW: + /* Allow process to run. Make sure its privilege structure has already + * been set. + */ + if (!RTS_ISSET(rp, RTS_NO_PRIV) || priv(rp)->s_proc_nr == NONE) { + return(EPERM); + } + RTS_LOCK_UNSET(rp, RTS_NO_PRIV); + return(OK); + + case SYS_PRIV_DISALLOW: + /* Disallow process from running. */ + if (RTS_ISSET(rp, RTS_NO_PRIV)) return(EPERM); + RTS_LOCK_SET(rp, RTS_NO_PRIV); + return(OK); + + case SYS_PRIV_SET_SYS: + /* Set a privilege structure of a blocked system process. */ if (! RTS_ISSET(rp, RTS_NO_PRIV)) return(EPERM); + /* Check whether a static or dynamic privilege id must be allocated. */ + priv_id = NULL_PRIV_ID; + if (m_ptr->CTL_ARG_PTR) + { + /* Copy privilege structure from caller */ + if((r=data_copy(who_e, (vir_bytes) m_ptr->CTL_ARG_PTR, + SYSTEM, (vir_bytes) &priv, sizeof(priv))) != OK) + return r; + + /* See if the caller wants to assign a static privilege id. */ + if(!(priv.s_flags & DYN_PRIV_ID)) { + priv_id = priv.s_id; + } + } + /* Make sure this process has its own privileges structure. This may * fail, since there are only a limited number of system processes. - * Then copy the privileges from the caller and restore some defaults. + * Then copy privileges from the caller and restore some defaults. */ - if ((i=get_priv(rp, SYS_PROC)) != OK) + if ((i=get_priv(rp, priv_id)) != OK) { - kprintf("do_privctl: out of priv structures\n"); + kprintf("do_privctl: unable to allocate priv_id %d: %d\n", + priv_id, i); return(i); } priv_id = priv(rp)->s_id; /* backup privilege id */ @@ -70,88 +102,109 @@ message *m_ptr; /* pointer to request message */ priv(rp)->s_int_pending = 0; /* - interrupts */ sigemptyset(&priv(rp)->s_sig_pending); /* - signals */ - /* Now update the process' privileges as requested. */ - rp->p_priv->s_trap_mask = FILLED_MASK; - - /* Set a default send mask. */ - for (i=0; i < NR_SYS_PROCS; i++) { - if (i != USER_PRIV_ID) - set_sendto_bit(rp, i); - else - unset_sendto_bit(rp, i); + /* Set defaults for privilege bitmaps. */ + priv(rp)->s_flags= DEF_SYS_F; /* privilege flags */ + priv(rp)->s_trap_mask= DEF_SYS_T; /* allowed traps */ + ipc_to_m = DEF_SYS_M; /* allowed targets */ + kcalls = DEF_SYS_KC; /* allowed kernel calls */ + for(i = 0; i < CALL_MASK_SIZE; i++) { + priv(rp)->s_k_call_mask[i] = (kcalls == NO_C ? 0 : (~0)); } - /* No I/O resources, no memory resources, no IRQs, no grant table */ + /* Set defaults for resources: no I/O resources, no memory resources, + * no IRQs, no grant table + */ priv(rp)->s_nr_io_range= 0; priv(rp)->s_nr_mem_range= 0; priv(rp)->s_nr_irq= 0; priv(rp)->s_grant_table= 0; priv(rp)->s_grant_entries= 0; + /* Override defaults if the caller has supplied a privilege structure. */ if (m_ptr->CTL_ARG_PTR) { - /* Copy privilege structure from caller */ - if((r=data_copy(who_e, (vir_bytes) m_ptr->CTL_ARG_PTR, - SYSTEM, (vir_bytes) &priv, sizeof(priv))) != OK) - return r; - - /* Copy the call mask */ - for (i= 0; is_k_call_mask[i]= priv.s_k_call_mask[i]; + /* Copy s_flags. */ + priv(rp)->s_flags = priv.s_flags; /* Copy IRQs */ - if (priv.s_nr_irq < 0 || priv.s_nr_irq > NR_IRQ) - return EINVAL; - priv(rp)->s_nr_irq= priv.s_nr_irq; - for (i= 0; is_irq_tab[i]= priv.s_irq_tab[i]; + if(priv.s_flags & CHECK_IRQ) { + if (priv.s_nr_irq < 0 || priv.s_nr_irq > NR_IRQ) + return EINVAL; + priv(rp)->s_nr_irq= priv.s_nr_irq; + for (i= 0; is_irq_tab[i]= priv.s_irq_tab[i]; #if 0 - kprintf("do_privctl: adding IRQ %d for %d\n", - priv(rp)->s_irq_tab[i], rp->p_endpoint); + kprintf("do_privctl: adding IRQ %d for %d\n", + priv(rp)->s_irq_tab[i], rp->p_endpoint); #endif + } } - priv(rp)->s_flags |= CHECK_IRQ; /* Check requests for IRQs */ - /* Copy I/O ranges */ - if (priv.s_nr_io_range < 0 || priv.s_nr_io_range > NR_IO_RANGE) - return EINVAL; - priv(rp)->s_nr_io_range= priv.s_nr_io_range; - for (i= 0; is_io_tab[i]= priv.s_io_tab[i]; + if(priv.s_flags & CHECK_IO_PORT) { + if (priv.s_nr_io_range < 0 || priv.s_nr_io_range > NR_IO_RANGE) + return EINVAL; + priv(rp)->s_nr_io_range= priv.s_nr_io_range; + for (i= 0; is_io_tab[i]= priv.s_io_tab[i]; #if 0 - kprintf("do_privctl: adding I/O range [%x..%x] for %d\n", - priv(rp)->s_io_tab[i].ior_base, - priv(rp)->s_io_tab[i].ior_limit, - rp->p_endpoint); + kprintf("do_privctl: adding I/O range [%x..%x] for %d\n", + priv(rp)->s_io_tab[i].ior_base, + priv(rp)->s_io_tab[i].ior_limit, + rp->p_endpoint); #endif + } } - /* Check requests for IRQs */ - priv(rp)->s_flags |= CHECK_IO_PORT; + /* Copy memory ranges */ + if(priv.s_flags & CHECK_MEM) { + if (priv.s_nr_mem_range < 0 || priv.s_nr_mem_range > NR_MEM_RANGE) + return EINVAL; + priv(rp)->s_nr_mem_range= priv.s_nr_mem_range; + for (i= 0; is_mem_tab[i]= priv.s_mem_tab[i]; +#if 0 + kprintf("do_privctl: adding mem range [%x..%x] for %d\n", + priv(rp)->s_mem_tab[i].mr_base, + priv(rp)->s_mem_tab[i].mr_limit, + rp->p_endpoint); +#endif + } + } + /* Copy trap mask. */ + priv(rp)->s_trap_mask = priv.s_trap_mask; + + /* Copy target mask. */ + memcpy(&ipc_to_m, &priv.s_ipc_to, sizeof(ipc_to_m)); + + /* Copy kernel call mask. */ memcpy(priv(rp)->s_k_call_mask, priv.s_k_call_mask, sizeof(priv(rp)->s_k_call_mask)); - - /* Set a custom send mask. */ - for (i=0; i < NR_SYS_PROCS; i++) { - if (get_sys_bit(priv.s_ipc_to, i)) - set_sendto_bit(rp, i); - else - unset_sendto_bit(rp, i); - } } - /* Done. Privileges have been set. Allow process to run again. */ - RTS_LOCK_UNSET(rp, RTS_NO_PRIV); + /* Fill in target mask. */ + for (i=0; i < NR_SYS_PROCS; i++) { + if (ipc_to_m & (1 << i)) + set_sendto_bit(rp, i); + else + unset_sendto_bit(rp, i); + } + return(OK); - case SYS_PRIV_USER: - /* Make this process an ordinary user process. */ + + case SYS_PRIV_SET_USER: + /* Set a privilege structure of a blocked user process. */ if (!RTS_ISSET(rp, RTS_NO_PRIV)) return(EPERM); - if ((i=get_priv(rp, 0)) != OK) return(i); - RTS_LOCK_UNSET(rp, RTS_NO_PRIV); + + /* Link the process to the privilege structure of the root user + * process all the user processes share. + */ + priv(rp) = priv_addr(USER_PRIV_ID); + return(OK); case SYS_PRIV_ADD_IO: diff --git a/kernel/table.c b/kernel/table.c index 7d068f521..d4d830e41 100644 --- a/kernel/table.c +++ b/kernel/table.c @@ -22,6 +22,7 @@ * include 'boot_image' (this file) and 'idt' and 'gdt' (protect.c). * * Changes: + * Nov 22, 2009 rewrite of privilege management (Cristiano Giuffrida) * Aug 02, 2005 set privileges and minimal boot image (Jorrit N. Herder) * Oct 17, 2004 updated above and tasktab comments (Jorrit N. Herder) * May 01, 2004 changed struct for system image (Jorrit N. Herder) @@ -43,97 +44,37 @@ /* Stack space for all the task stacks. Declared as (char *) to align it. */ #define TOT_STACK_SPACE (IDL_S + HRD_S + (2 * TSK_S)) PUBLIC char *t_stack[TOT_STACK_SPACE / sizeof(char *)]; - -/* Define flags for the various process types. */ -#define IDL_F (SYS_PROC | BILLABLE) /* idle task is not preemptible as we - * don't want it to interfere with the - * timer tick interrupt handler code. - * Unlike other processes idle task is - * handled in a special way and is - * preempted always if timer tick occurs - * and there is another runnable process - */ -#define TSK_F (SYS_PROC) /* kernel tasks */ -#define SRV_F (SYS_PROC | PREEMPTIBLE) /* system services */ -#define VM_F (SYS_PROC) /* vm */ -#define USR_F (BILLABLE | PREEMPTIBLE | PROC_FULLVM) /* user processes */ -#define SVM_F (SRV_F | PROC_FULLVM) /* servers with VM */ -/* Define system call traps for the various process types. These call masks - * determine what system call traps a process is allowed to make. - */ -#define TSK_T (1 << RECEIVE) /* clock and system */ -#define SRV_T (~0) /* system services */ -#define USR_T ((1 << SENDREC)) /* user processes */ - -/* Send masks determine to whom processes can send messages or notifications. - * The values here are used for the processes in the boot image. We rely on - * the boot image table itself to match the order of the process numbers, so - * that the send mask that is defined here can be interpreted properly. - * Privilege structure 0 is shared by user processes. - */ -#define s(n) (1 << (s_nr_to_id(n))) -#define SRV_M (~0) -#define SYS_M (~0) -#define USR_M (s(PM_PROC_NR) | s(FS_PROC_NR) | s(RS_PROC_NR) | s(VM_PROC_NR)) -#define DRV_M (USR_M | s(SYSTEM) | s(DS_PROC_NR) | s(LOG_PROC_NR) | s(TTY_PROC_NR)) - -/* Define kernel calls that processes are allowed to make. This is not looking - * very nice, but we need to define the access rights on a per call basis. - * Note that the reincarnation server has all bits on, because it should - * be allowed to distribute rights to services that it starts. - * - * Calls are unordered lists, converted by the kernel to bitmasks - * once at runtime. - */ -#define FS_C SYS_KILL, SYS_VIRCOPY, SYS_SAFECOPYFROM, SYS_SAFECOPYTO, \ - SYS_VIRVCOPY, SYS_UMAP, SYS_GETINFO, SYS_EXIT, SYS_TIMES, SYS_SETALARM, \ - SYS_PRIVCTL, SYS_TRACE , SYS_SETGRANT, SYS_PROFBUF, SYS_SYSCTL -#define DRV_C FS_C, SYS_SEGCTL, SYS_IRQCTL, SYS_INT86, SYS_DEVIO, \ - SYS_SDEVIO, SYS_VDEVIO, SYS_SETGRANT, SYS_PROFBUF, SYS_SYSCTL - -PRIVATE int - fs_c[] = { FS_C }, - pm_c[] = { SYS_ALL_CALLS }, - rs_c[] = { SYS_ALL_CALLS }, - ds_c[] = { SYS_ALL_CALLS }, - vm_c[] = { SYS_ALL_CALLS }, - drv_c[] = { DRV_C }, - usr_c[] = { SYS_SYSCTL }, - tty_c[] = { DRV_C, SYS_PHYSCOPY, SYS_ABORT, SYS_IOPENABLE, - SYS_READBIOS }, - mem_c[] = { DRV_C, SYS_PHYSCOPY, SYS_PHYSVCOPY, SYS_IOPENABLE }; +/* Define boot process flags. */ +#define BVM_F (PROC_FULLVM) /* boot processes with VM */ /* The system image table lists all programs that are part of the boot image. * The order of the entries here MUST agree with the order of the programs - * in the boot image and all kernel tasks must come first. Furthermore, the - * order of the entries MUST agree with their process numbers. See above. + * in the boot image and all kernel tasks must come first. * * Each entry provides the process number, flags, quantum size, scheduling - * queue, allowed traps, ipc mask, and a name for the process table. The - * initial program counter and stack size is also provided for kernel tasks. + * queue, and a name for the process table. The initial program counter and + * stack size is also provided for kernel tasks. * * Note: the quantum size must be positive in all cases! */ -#define c(calls) calls, (sizeof(calls) / sizeof((calls)[0])) -#define no_c { 0 }, 0 PUBLIC struct boot_image image[] = { -/* process nr, pc,flags, qs, queue, stack, traps, ipcto, call, name */ -{IDLE, NULL,IDL_F, 0, 0, IDL_S, 0, 0, no_c,"idle" }, -{CLOCK,clock_task,TSK_F, 8, TASK_Q, TSK_S, TSK_T, 0, no_c,"clock" }, -{SYSTEM, sys_task,TSK_F, 8, TASK_Q, TSK_S, TSK_T, 0, no_c,"system"}, -{HARDWARE, 0,TSK_F, 8, TASK_Q, HRD_S, 0, 0, no_c,"kernel"}, -{PM_PROC_NR, 0,SRV_F, 32, 4, 0, SRV_T, SRV_M, c(pm_c),"pm" }, -{FS_PROC_NR, 0,SRV_F, 32, 5, 0, SRV_T, SRV_M, c(fs_c),"vfs" }, -{RS_PROC_NR, 0,SVM_F, 4, 4, 0, SRV_T, SYS_M, c(rs_c),"rs" }, -{MEM_PROC_NR, 0,SVM_F, 4, 3, 0, SRV_T, SYS_M,c(mem_c),"memory"}, -{LOG_PROC_NR, 0,SRV_F, 4, 2, 0, SRV_T, SYS_M,c(drv_c),"log" }, -{TTY_PROC_NR, 0,SVM_F, 4, 1, 0, SRV_T, SYS_M,c(tty_c),"tty" }, -{DS_PROC_NR, 0,SVM_F, 4, 4, 0, SRV_T, SYS_M, c(ds_c),"ds" }, -{MFS_PROC_NR, 0,SVM_F, 32, 5, 0, SRV_T, SRV_M, c(fs_c),"mfs" }, -{VM_PROC_NR, 0,VM_F, 32, 2, 0, SRV_T, SRV_M, c(vm_c),"vm" }, -{INIT_PROC_NR, 0,USR_F, 8, USER_Q, 0, USR_T, USR_M, c(usr_c),"init" }, +/* process nr, pc, flags, qs, queue, stack, name */ +{IDLE, NULL, 0, 0, 0, IDL_S, "idle" }, +{CLOCK,clock_task, 0, 8, TASK_Q, TSK_S, "clock" }, +{SYSTEM, sys_task, 0, 8, TASK_Q, TSK_S, "system"}, +{HARDWARE, 0, 0, 8, TASK_Q, HRD_S, "kernel"}, +{PM_PROC_NR, 0, 0, 32, 4, 0, "pm" }, +{FS_PROC_NR, 0, 0, 32, 5, 0, "vfs" }, +{RS_PROC_NR, 0, 0, 4, 4, 0, "rs" }, +{MEM_PROC_NR, 0, BVM_F, 4, 3, 0, "memory"}, +{LOG_PROC_NR, 0, BVM_F, 4, 2, 0, "log" }, +{TTY_PROC_NR, 0, BVM_F, 4, 1, 0, "tty" }, +{DS_PROC_NR, 0, BVM_F, 4, 4, 0, "ds" }, +{MFS_PROC_NR, 0, BVM_F, 32, 5, 0, "mfs" }, +{VM_PROC_NR, 0, 0, 32, 2, 0, "vm" }, +{INIT_PROC_NR, 0, BVM_F, 8, USER_Q, 0, "init" }, }; /* Verify the size of the system image table at compile time. Also verify that diff --git a/kernel/type.h b/kernel/type.h index f09939737..d9e80519b 100644 --- a/kernel/type.h +++ b/kernel/type.h @@ -20,10 +20,6 @@ struct boot_image { unsigned char quantum; /* quantum (tick count) */ int priority; /* scheduling priority */ int stksize; /* stack size for tasks */ - short trap_mask; /* allowed system call traps */ - bitchunk_t ipc_to; /* send mask protection */ - int *k_calls; /* kern. call protection */ - int nr_k_calls; char proc_name[P_NAME_LEN]; /* name in process table */ endpoint_t endpoint; /* endpoint number when started */ }; diff --git a/lib/syslib/sys_times.c b/lib/syslib/sys_times.c index 5615c0170..68982489f 100644 --- a/lib/syslib/sys_times.c +++ b/lib/syslib/sys_times.c @@ -1,12 +1,13 @@ #include "syslib.h" -PUBLIC int sys_times(proc_ep, user_time, sys_time, uptime) +PUBLIC int sys_times(proc_ep, user_time, sys_time, uptime, boottime) endpoint_t proc_ep; /* proc_ep whose times are needed */ clock_t *user_time; /* time spend in the process itself */ clock_t *sys_time; /* time spend in system on behalf of the * process */ clock_t *uptime; /* time the system is running */ +time_t *boottime; /* boot time */ { /* Fetch the accounting info for a proc_ep. */ message m; @@ -17,5 +18,6 @@ clock_t *uptime; /* time the system is running */ if (user_time) *user_time = m.T_USER_TIME; if (sys_time) *sys_time = m.T_SYSTEM_TIME; if (uptime) *uptime = m.T_BOOT_TICKS; + if (boottime) *boottime = m.T_BOOTTIME; return(r); } diff --git a/servers/init/init.c b/servers/init/init.c index 5fd15fd3e..05c8236c3 100644 --- a/servers/init/init.c +++ b/servers/init/init.c @@ -69,6 +69,7 @@ int main(void) int fd; /* generally useful */ int linenr; /* loop variable */ int check; /* check if a new process must be spawned */ + int sn; /* signal number */ struct slotent *slotp; /* slots[] pointer */ struct ttyent *ttyp; /* ttytab entry */ struct sigaction sa; @@ -85,6 +86,12 @@ int main(void) sigemptyset(&sa.sa_mask); sa.sa_flags = 0; + /* Default: Ignore every signal (except those that follow). */ + sa.sa_handler = SIG_IGN; + for (sn = 1; sn < _NSIG; sn++) { + sigaction(sn, &sa, NULL); + } + /* Hangup: Reexamine /etc/ttytab for newly enabled terminal lines. */ sa.sa_handler = onhup; sigaction(SIGHUP, &sa, NULL); diff --git a/servers/is/dmp_kernel.c b/servers/is/dmp_kernel.c index 9f335d0f5..8c0ea2b53 100644 --- a/servers/is/dmp_kernel.c +++ b/servers/is/dmp_kernel.c @@ -45,6 +45,7 @@ FORWARD _PROTOTYPE( char *proc_name, (int proc_nr) ); FORWARD _PROTOTYPE( char *s_traps_str, (int flags) ); FORWARD _PROTOTYPE( char *s_flags_str, (int flags) ); FORWARD _PROTOTYPE( char *p_rts_flags_str, (int flags) ); +FORWARD _PROTOTYPE( char *boot_flags_str, (int flags) ); /* Some global data that is shared among several dumping procedures. * Note that the process table copy has the same name as in the kernel @@ -195,6 +196,18 @@ PUBLIC void irqtab_dmp() printf("\n"); } +/*===========================================================================* + * boot_flags_str * + *===========================================================================*/ +PRIVATE char *boot_flags_str(int flags) +{ + static char str[10]; + str[0] = (flags & PROC_FULLVM) ? 'V' : '-'; + str[1] = '\0'; + + return str; +} + /*===========================================================================* * image_dmp * *===========================================================================*/ @@ -202,25 +215,18 @@ PUBLIC void image_dmp() { int m, i,j,r; struct boot_image *ip; - static char ipc_to[BITCHUNK_BITS*2]; if ((r = sys_getimage(image)) != OK) { report("IS","warning: couldn't get copy of image table", r); return; } printf("Image table dump showing all processes included in system image.\n"); - printf("---name-- -nr- -flags- -traps- -sq- ----pc- -stack- -ipc_to[0]--------\n"); + printf("---name- -nr- ----pc- flags -qs- -queue- -stack-\n"); for (m=0; mipc_to & (1<proc_name, ip->proc_nr, - s_flags_str(ip->flags), s_traps_str(ip->trap_mask), - ip->priority, (long)ip->initial_pc, ip->stksize, ipc_to); + printf("%8s %4d %7lu %5s %4d %7d %7lu\n", + ip->proc_name, ip->proc_nr, (long)ip->initial_pc, + boot_flags_str(ip->flags), ip->quantum, ip->priority, ip->stksize); } printf("\n"); } @@ -267,19 +273,27 @@ PUBLIC void kenv_dmp() printf("\n"); } +/*===========================================================================* + * s_flags_str * + *===========================================================================*/ PRIVATE char *s_flags_str(int flags) { static char str[10]; - str[0] = (flags & PREEMPTIBLE) ? 'P' : '-'; - str[1] = '-'; - str[2] = (flags & BILLABLE) ? 'B' : '-'; - str[3] = (flags & SYS_PROC) ? 'S' : '-'; - str[4] = '-'; - str[5] = '\0'; + str[0] = (flags & PREEMPTIBLE) ? 'P' : '-'; + str[1] = (flags & BILLABLE) ? 'B' : '-'; + str[2] = (flags & DYN_PRIV_ID) ? 'D' : '-'; + str[3] = (flags & SYS_PROC) ? 'S' : '-'; + str[4] = (flags & CHECK_IO_PORT) ? 'I' : '-'; + str[5] = (flags & CHECK_IRQ) ? 'Q' : '-'; + str[6] = (flags & CHECK_MEM) ? 'M' : '-'; + str[7] = '\0'; return str; } +/*===========================================================================* + * s_traps_str * + *===========================================================================*/ PRIVATE char *s_traps_str(int flags) { static char str[10]; @@ -313,7 +327,7 @@ PUBLIC void privileges_dmp() return; } - printf("\n--nr-id-name---- -flags- -traps- grants -ipc_to-- -system calls--\n"); + printf("-nr- -id- -name-- -flags- traps grants -ipc_to-- -kernel calls-\n"); PROCLOOP(rp, oldrp) r = -1; @@ -322,7 +336,7 @@ PUBLIC void privileges_dmp() if (r == -1 && !isemptyp(rp)) { sp = &priv[USER_PRIV_ID]; } - printf("(%02u) %-7.7s %s %s %7d", + printf("(%02u) %-7.7s %s %s %7d", sp->s_id, rp->p_name, s_flags_str(sp->s_flags), s_traps_str(sp->s_trap_mask), sp->s_grant_entries); @@ -339,6 +353,9 @@ PUBLIC void privileges_dmp() } } +/*===========================================================================* + * p_rts_flags_str * + *===========================================================================*/ PRIVATE char *p_rts_flags_str(int flags) { static char str[10]; diff --git a/servers/is/dmp_rs.c b/servers/is/dmp_rs.c index c3f738954..da7b7cfba 100644 --- a/servers/is/dmp_rs.c +++ b/servers/is/dmp_rs.c @@ -11,7 +11,8 @@ #include #include #include "../../kernel/priv.h" -#include "../rs/manager.h" +#include "../rs/const.h" +#include "../rs/type.h" PUBLIC struct rproc rproc[NR_SYS_PROCS]; @@ -29,19 +30,15 @@ PUBLIC void rproc_dmp() getsysinfo(RS_PROC_NR, SI_PROC_TAB, rproc); printf("Reincarnation Server (RS) system process table dump\n"); - printf("-endpoint-flag--dev- -T---checked----alive-starts-backoff-label command-\n"); + printf("----label---- endpoint- -pid- flags -dev- -T- alive_tm starts command\n"); for (i=prev_i; ir_flags & RS_IN_USE) continue; if (++n > 22) break; - printf("%9d %s %3d/%2d %3u %8u %8u %4dx %3d %s %s", - rp->r_proc_nr_e, - s_flags_str(rp->r_flags), - rp->r_dev_nr, rp->r_dev_style, - rp->r_period, - rp->r_check_tm, rp->r_alive_tm, - rp->r_restarts, rp->r_backoff, - rp->r_label, + printf("%13s %9d %5d %5s %3d/%1d %3u %8u %5dx %s", + rp->r_label, rp->r_proc_nr_e, rp->r_pid, + s_flags_str(rp->r_flags), rp->r_dev_nr, rp->r_dev_style, + rp->r_period, rp->r_alive_tm, rp->r_restarts, rp->r_cmd ); printf("\n"); @@ -54,11 +51,13 @@ PUBLIC void rproc_dmp() PRIVATE char *s_flags_str(int flags) { - static char str[5]; - str[0] = (flags & RS_IN_USE) ? 'U' : '-'; - str[1] = (flags & RS_EXITING) ? 'E' : '-'; - str[2] = '-'; - str[3] = '\0'; + static char str[10]; + str[0] = (flags & RS_IN_USE) ? 'U' : '-'; + str[1] = (flags & RS_EXITING) ? 'E' : '-'; + str[2] = (flags & RS_REFRESHING) ? 'R' : '-'; + str[3] = (flags & RS_NOPINGREPLY) ? 'N' : '-'; + str[4] = '-'; + str[5] = '\0'; return(str); } diff --git a/servers/pm/const.h b/servers/pm/const.h index 2fa9bdad1..9ed579048 100644 --- a/servers/pm/const.h +++ b/servers/pm/const.h @@ -5,7 +5,7 @@ * a 'short' instead of pid_t.) */ -#define PM_PID 0 /* PM's process id number */ +#define NO_PID 0 /* pid value indicating no process */ #define INIT_PID 1 /* INIT's process id number */ #define NO_TRACER 0 /* process is not being traced */ diff --git a/servers/pm/forkexit.c b/servers/pm/forkexit.c index bc57d80ef..72b3d91a1 100644 --- a/servers/pm/forkexit.c +++ b/servers/pm/forkexit.c @@ -260,7 +260,7 @@ int dump_core; /* flag indicating whether to dump core */ if (rmp->mp_flags & ALARM_ON) set_alarm(rmp, (clock_t) 0); /* Do accounting: fetch usage times and accumulate at parent. */ - if((r=sys_times(proc_nr_e, &user_time, &sys_time, NULL)) != OK) + if((r=sys_times(proc_nr_e, &user_time, &sys_time, NULL, NULL)) != OK) panic(__FILE__,"exit_proc: sys_times failed", r); p_mp = &mproc[rmp->mp_parent]; /* process' parent */ diff --git a/servers/pm/main.c b/servers/pm/main.c index 6c317082d..4d18b0ca7 100644 --- a/servers/pm/main.c +++ b/servers/pm/main.c @@ -226,8 +226,6 @@ extern int unmap_ok; *===========================================================================*/ PRIVATE void pm_init() { - int failed = 0; - int f = 0; /* Initialize the process manager. * Memory use info is collected from the boot monitor, the kernel, and * all processes compiled into the system image. Initially this information @@ -288,19 +286,28 @@ PRIVATE void pm_init() /* Set process details found in the image table. */ rmp = &mproc[ip->proc_nr]; strncpy(rmp->mp_name, ip->proc_name, PROC_NAME_LEN); -#if 0 - rmp->mp_parent = RS_PROC_NR; -#endif rmp->mp_nice = get_nice_value(ip->priority); sigemptyset(&rmp->mp_sig2mess); sigemptyset(&rmp->mp_ignore); sigemptyset(&rmp->mp_sigmask); sigemptyset(&rmp->mp_catch); if (ip->proc_nr == INIT_PROC_NR) { /* user process */ + /* INIT is root, we make it father of itself. This is + * not really OK, INIT should have no father, i.e. + * a father with pid NO_PID. But PM currently assumes + * that mp_parent always points to a valid slot number. + */ + rmp->mp_parent = INIT_PROC_NR; rmp->mp_procgrp = rmp->mp_pid = INIT_PID; rmp->mp_flags |= IN_USE; } else { /* system process */ + if(ip->proc_nr == RS_PROC_NR) { + rmp->mp_parent = INIT_PROC_NR; + } + else { + rmp->mp_parent = RS_PROC_NR; + } rmp->mp_pid = get_free_pid(); rmp->mp_flags |= IN_USE | PRIV_PROC; for (sig_ptr = mess_sigs; @@ -318,23 +325,10 @@ PRIVATE void pm_init() mess.PR_ENDPT = rmp->mp_endpoint; if (OK != (s=send(FS_PROC_NR, &mess))) panic(__FILE__,"can't sync up with FS", s); - - /* Register proces with ds */ - s= ds_publish_u32(rmp->mp_name, rmp->mp_endpoint); - if (s != OK) - failed++; } } - if(failed > 0) - printf("PM: failed to register %d/%d boot processes\n", - failed, NR_BOOT_PROCS); - - /* Override some details. INIT, PM, FS and RS are somewhat special. */ - mproc[PM_PROC_NR].mp_pid = PM_PID; /* PM has magic pid */ -#if 0 - mproc[RS_PROC_NR].mp_parent = INIT_PROC_NR; /* INIT is root */ -#endif + /* Override some details for PM. */ sigfillset(&mproc[PM_PROC_NR].mp_ignore); /* guard against signals */ /* Tell FS that no more system processes follow and synchronize. */ @@ -347,8 +341,6 @@ PRIVATE void pm_init() strcpy(uts_val.machine + 1, itoa(getprocessor())); #endif - if(f > 0) printf("PM: failed to register %d processes with DS.\n", f); - system_hz = sys_hz(); /* Map out our own text and data. This is normally done in crtso.o diff --git a/servers/pm/time.c b/servers/pm/time.c index 9c5497aae..ffbceb5ac 100644 --- a/servers/pm/time.c +++ b/servers/pm/time.c @@ -69,7 +69,7 @@ PUBLIC int do_times() clock_t user_time, sys_time, uptime; int s; - if (OK != (s=sys_times(who_e, &user_time, &sys_time, &uptime))) + if (OK != (s=sys_times(who_e, &user_time, &sys_time, &uptime, NULL))) panic(__FILE__,"do_times couldn't get times", s); rmp->mp_reply.reply_t1 = user_time; /* user time */ rmp->mp_reply.reply_t2 = sys_time; /* system time */ diff --git a/servers/rs/Makefile b/servers/rs/Makefile index 8963584c2..72cd9261b 100644 --- a/servers/rs/Makefile +++ b/servers/rs/Makefile @@ -19,7 +19,7 @@ LDFLAGS = -i LIBS = -lsys UTIL_OBJ = service.o -OBJ = exec.o main.o manager.o +OBJ = exec.o main.o manager.o table.o utility.o memory.o # build local binary all build: $(SERVER) $(UTIL) @@ -27,7 +27,7 @@ $(UTIL): $(UTIL_OBJ) $(CC) -o $@ $(LDFLAGS) $(UTIL_OBJ) $(UTIL_LIBS) $(SERVER): $(OBJ) $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS) - install -S 32k $@ + install -S 350k $@ # install with other servers install: /bin/$(UTIL) /usr/sbin/$(SERVER) diff --git a/servers/rs/const.h b/servers/rs/const.h new file mode 100644 index 000000000..25f135a0b --- /dev/null +++ b/servers/rs/const.h @@ -0,0 +1,83 @@ +/* Global constants used in RS. + */ +#ifndef RS_CONST_H +#define RS_CONST_H + +/* Space reserved for program and arguments. */ +#define MAX_COMMAND_LEN 512 /* maximum argument string length */ +#define MAX_LABEL_LEN 16 /* Unique name of (this instance of) + * the driver + */ +#define MAX_SCRIPT_LEN 256 /* maximum restart script name length */ +#define MAX_NR_ARGS 4 /* maximum number of arguments */ +#define MAX_RESCUE_DIR_LEN 64 /* maximum rescue dir length */ + +#define MAX_IPC_LIST 256 /* Max size of list for IPC target + * process names + */ +#define MAX_VM_LIST 256 + +/* Flag values. */ +#define RS_IN_USE 0x001 /* set when process slot is in use */ +#define RS_EXITING 0x004 /* set when exit is expected */ +#define RS_REFRESHING 0x008 /* set when refresh must be done */ +#define RS_NOPINGREPLY 0x010 /* driver failed to reply to a ping request */ +#define RS_KILLED 0x020 /* driver is killed */ +#define RS_CRASHED 0x040 /* driver crashed */ +#define RS_LATEREPLY 0x080 /* no reply sent to RS_DOWN caller yet */ +#define RS_SIGNALED 0x100 /* driver crashed */ + +/* Sys flag values. */ +#define SF_CORE_PROC 0x001 /* set for core system processes + * XXX FIXME: This should trigger a system + * panic when a CORE_PROC service cannot + * be restarted. We need better error-handling + * in RS to change this. + */ +#define SF_NEED_COPY 0x004 /* set when process needs copy to restart */ +#define SF_USE_COPY 0x008 /* set when process has a copy in memory */ + +/* Constants determining RS period and binary exponential backoff. */ +#define RS_DELTA_T 60 /* check every T ticks */ +#define BACKOFF_BITS (sizeof(long)*8) /* bits in backoff field */ +#define MAX_BACKOFF 30 /* max backoff in RS_DELTA_T */ + +/* Magic process table addresses. */ +#define BEG_RPROC_ADDR (&rproc[0]) +#define END_RPROC_ADDR (&rproc[NR_SYS_PROCS]) +#define NIL_RPROC ((struct mproc *) 0) + + +/* Definitions for boot info tables. */ +#define NULL_BOOT_NR NR_BOOT_PROCS /* marks a null boot entry */ +#define DEFAULT_BOOT_NR NR_BOOT_PROCS /* marks the default boot entry */ +#define SYS_ALL_C (NR_SYS_CALLS+0) /* specifies all calls */ +#define SYS_NULL_C (NR_SYS_CALLS+1) /* marks a null call entry */ + +/* Define privilege flags for the various process types. */ +#define SRV_F (SYS_PROC | PREEMPTIBLE) /* system services */ +#define DSRV_F (SRV_F | DYN_PRIV_ID | CHECK_IO_PORT | CHECK_IRQ) + /* dynamic system services */ +#define VM_F (SYS_PROC) /* vm */ +#define RUSR_F (BILLABLE | PREEMPTIBLE) /* root user proc */ + +/* Define system call traps for the various process types. These call masks + * determine what system call traps a process is allowed to make. + */ +#define SRV_T (~0) /* system services */ +#define DSRV_T SRV_T /* dynamic system services */ +#define RUSR_T (1 << SENDREC) /* root user proc */ + +/* Send masks determine to whom processes can send messages or notifications. */ +#define SRV_M (~0) /* system services */ +#define RUSR_M \ + ( spi_to(PM_PROC_NR) | spi_to(FS_PROC_NR) | spi_to(RS_PROC_NR) \ + | spi_to(VM_PROC_NR) ) /* root user proc */ + +/* Define sys flags for the various process types. */ +#define SRV_SF (SF_CORE_PROC | SF_NEED_COPY) /* system services */ +#define SRVC_SF (SRV_SF | SF_USE_COPY) /* system services with a copy */ +#define DSRV_SF (0) /* dynamic system services */ + +#endif /* RS_CONST_H */ + diff --git a/servers/rs/glo.h b/servers/rs/glo.h new file mode 100644 index 000000000..e1681b342 --- /dev/null +++ b/servers/rs/glo.h @@ -0,0 +1,44 @@ +/* Global variables used in RS. + */ +#ifndef RS_GLO_H +#define RS_GLO_H + +#ifdef _TABLE +#undef EXTERN +#define EXTERN +#endif + +/* The boot image priv table. This table has entries for all system + * services in the boot image. + */ +extern struct boot_image_priv boot_image_priv_table[]; + +/* The boot image sys table. This table has entries for system services in + * the boot image that override default sys properties. + */ +extern struct boot_image_sys boot_image_sys_table[]; + +/* The boot image dev table. This table has entries for system services in + * the boot image that support dev properties. + */ +extern struct boot_image_dev boot_image_dev_table[]; + +/* The system process table. This table only has entries for system + * services (servers and drivers), and thus is not directly indexed by + * slot number. + */ +EXTERN struct rproc rproc[NR_SYS_PROCS]; +EXTERN struct rproc *rproc_ptr[NR_PROCS]; /* mapping for fast access */ + +/* Pipe for detection of exec failures. The pipe is close-on-exec, and + * no data will be written to the pipe if the exec succeeds. After an + * exec failure, the slot number is written to the pipe. After each exit, + * a non-blocking read retrieves the slot number from the pipe. + */ +EXTERN int exec_pipe[2]; + +/* Enable/disable verbose output. */ +EXTERN long rs_verbose; + +#endif /* RS_GLO_H */ + diff --git a/servers/rs/inc.h b/servers/rs/inc.h index b4c6ee566..892aa76fb 100644 --- a/servers/rs/inc.h +++ b/servers/rs/inc.h @@ -7,8 +7,6 @@ #define _SYSTEM 1 /* get OK and negative error codes */ #define _MINIX 1 /* tell headers to include MINIX stuff */ -#define VERBOSE 0 /* display diagnostics */ - #include #include #include @@ -26,10 +24,13 @@ #include #include #include +#include +#include #include #include /* For priv.h */ #include "../../kernel/priv.h" +#include "../../kernel/ipc.h" #include #include @@ -38,5 +39,7 @@ #include #include "proto.h" -#include "manager.h" +#include "const.h" +#include "type.h" +#include "glo.h" diff --git a/servers/rs/main.c b/servers/rs/main.c index 72174bc3c..b67cf5c06 100644 --- a/servers/rs/main.c +++ b/servers/rs/main.c @@ -4,25 +4,45 @@ * services to see whether they are still alive. The system services are * expected to periodically send a heartbeat message. * - * Created: - * Jul 22, 2005 by Jorrit N. Herder + * Changes: + * Nov 22, 2009: rewrite of boot process (Cristiano Giuffrida) + * Jul 22, 2005: Created (Jorrit N. Herder) */ #include "inc.h" #include -#include +#include +#include #include "../../kernel/const.h" #include "../../kernel/type.h" +#include "../../kernel/proc.h" +#include "../pm/mproc.h" +#include "../pm/const.h" /* Declare some local functions. */ +FORWARD _PROTOTYPE(void exec_image_copy, ( int boot_proc_idx, + struct boot_image *ip, struct rproc *rp) ); +FORWARD _PROTOTYPE(void boot_image_info_lookup, ( endpoint_t endpoint, + struct boot_image *image, + struct boot_image **ip, struct boot_image_priv **pp, + struct boot_image_sys **sp, struct boot_image_dev **dp) ); +FORWARD _PROTOTYPE(void fill_call_mask, ( int *calls, int tot_nr_calls, + bitchunk_t *call_mask, int call_base) ); FORWARD _PROTOTYPE(void init_server, (void) ); FORWARD _PROTOTYPE(void sig_handler, (void) ); FORWARD _PROTOTYPE(void get_work, (message *m) ); FORWARD _PROTOTYPE(void reply, (int whom, message *m_out) ); -/* Data buffers to retrieve info during initialization. */ -PRIVATE struct boot_image image[NR_BOOT_PROCS]; +/* The buffer where the boot image is copied during initialization. */ +PRIVATE int boot_image_buffer_size; +PRIVATE char *boot_image_buffer; -long rs_verbose = 0; +/* Macro to identify a system service in the boot image. This rules out + * kernel tasks and the root system process (RS). + */ +#define isbootsrvprocn(n) (!iskerneln((n)) && !isrootsysn((n))) + +/* Flag set when memory unmapping can be done. */ +EXTERN int unmap_ok; /*===========================================================================* * main * @@ -120,6 +140,168 @@ PUBLIC int main(void) } } +/*===========================================================================* + * exec_image_copy * + *===========================================================================*/ +PRIVATE void exec_image_copy(boot_proc_idx, ip, rp) +int boot_proc_idx; +struct boot_image *ip; +struct rproc *rp; +{ +/* Copy the executable image of the given boot process. */ + int s; + struct exec header; + static char *boot_image_ptr = NULL; + + if(boot_image_ptr == NULL) { + boot_image_ptr = boot_image_buffer; + } + s = NO_NUM; + + /* Get a.out header. */ + if(boot_image_buffer+boot_image_buffer_size - boot_image_ptr < sizeof(header) + || (s = sys_getaoutheader(&header, boot_proc_idx)) != OK) { + panic("RS", "unable to get copy of a.out header", s); + } + memcpy(boot_image_ptr, &header, header.a_hdrlen); + boot_image_ptr += header.a_hdrlen; + + /* Get text segment. */ + if(boot_image_buffer+boot_image_buffer_size - boot_image_ptr < header.a_text + || (s = rs_startup_segcopy(ip->endpoint, T, D, (vir_bytes) boot_image_ptr, + header.a_text)) != OK) { + panic("RS", "unable to get copy of text segment", s); + } + boot_image_ptr += header.a_text; + + /* Get data segment. */ + if(boot_image_buffer+boot_image_buffer_size - boot_image_ptr < header.a_data + || (s = rs_startup_segcopy(ip->endpoint, D, D, (vir_bytes) boot_image_ptr, + header.a_data)) != OK) { + panic("RS", "unable to get copy of data segment", s); + } + boot_image_ptr += header.a_data; + + /* Set the executable image for the given boot process. */ + rp->r_exec_len = header.a_hdrlen + header.a_text + header.a_data; + rp->r_exec = boot_image_ptr - rp->r_exec_len; +} + +/*===========================================================================* + * boot_image_info_lookup * + *===========================================================================*/ +PRIVATE void boot_image_info_lookup(endpoint, image, ip, pp, sp, dp) +endpoint_t endpoint; +struct boot_image *image; +struct boot_image **ip; +struct boot_image_priv **pp; +struct boot_image_sys **sp; +struct boot_image_dev **dp; +{ +/* Lookup entries in boot image tables. */ + int i; + + /* When requested, locate the corresponding entry in the boot image table + * or panic if not found. + */ + if(ip) { + for (i=0; i < NR_BOOT_PROCS; i++) { + if(image[i].endpoint == endpoint) { + *ip = &image[i]; + break; + } + } + if(i == NR_BOOT_PROCS) { + panic("RS", "boot image table lookup failed", NO_NUM); + } + } + + /* When requested, locate the corresponding entry in the boot image priv table + * or panic if not found. + */ + if(pp) { + for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) { + if(boot_image_priv_table[i].endpoint == endpoint) { + *pp = &boot_image_priv_table[i]; + break; + } + } + if(i == NULL_BOOT_NR) { + panic("RS", "boot image priv table lookup failed", NO_NUM); + } + } + + /* When requested, locate the corresponding entry in the boot image sys table + * or resort to the default entry if not found. + */ + if(sp) { + for (i=0; boot_image_sys_table[i].endpoint != DEFAULT_BOOT_NR; i++) { + if(boot_image_sys_table[i].endpoint == endpoint) { + *sp = &boot_image_sys_table[i]; + break; + } + } + if(boot_image_sys_table[i].endpoint == DEFAULT_BOOT_NR) { + *sp = &boot_image_sys_table[i]; /* accept the default entry */ + } + } + + /* When requested, locate the corresponding entry in the boot image dev table + * or resort to the default entry if not found. + */ + if(dp) { + for (i=0; boot_image_dev_table[i].endpoint != DEFAULT_BOOT_NR; i++) { + if(boot_image_dev_table[i].endpoint == endpoint) { + *dp = &boot_image_dev_table[i]; + break; + } + } + if(boot_image_dev_table[i].endpoint == DEFAULT_BOOT_NR) { + *dp = &boot_image_dev_table[i]; /* accept the default entry */ + } + } +} + +/*===========================================================================* + * fill_call_mask * + *===========================================================================*/ +PRIVATE void fill_call_mask(calls, tot_nr_calls, call_mask, call_base) +int *calls; /* the unordered set of calls */ +int tot_nr_calls; /* the total number of calls */ +bitchunk_t *call_mask; /* the call mask to fill in */ +int call_base; /* the base offset for the calls */ +{ +/* Fill a call mask from an unordered set of calls. */ + int i; + bitchunk_t fv; + int call_mask_size, nr_calls; + + call_mask_size = BITMAP_CHUNKS(tot_nr_calls); + + /* Count the number of calls to fill in. */ + nr_calls = 0; + for(i=0; calls[i] != SYS_NULL_C; i++) { + nr_calls++; + } + + /* See if all calls are allowed and call mask must be completely filled. */ + fv = 0; + if(nr_calls == 1 && calls[0] == SYS_ALL_C) { + fv = (~0); + } + + /* Fill or clear call mask. */ + for(i=0; i < call_mask_size; i++) { + call_mask[i] = fv; + } + + /* Not all calls allowed? Enter calls bit by bit. */ + if(!fv) { + for(i=0; i < nr_calls; i++) { + SET_BIT(call_mask, calls[i] - call_base); + } + } +} /*===========================================================================* * init_server * @@ -129,7 +311,252 @@ PRIVATE void init_server(void) /* Initialize the reincarnation server. */ struct sigaction sa; struct boot_image *ip; - int s,t; + int s,i,j; + int nr_image_srvs, nr_image_priv_srvs; + struct rproc *rp; + struct boot_image image[NR_BOOT_PROCS]; + struct mproc mproc[NR_PROCS]; + struct exec header; + struct boot_image_priv *boot_image_priv; + struct boot_image_sys *boot_image_sys; + struct boot_image_dev *boot_image_dev; + + /* See if we run in verbose mode. */ + env_parse("rs_verbose", "d", 0, &rs_verbose, 0, 1); + + /* Get a copy of the boot image table. */ + if ((s = sys_getimage(image)) != OK) { + panic("RS", "unable to get copy of boot image table", s); + } + + /* Determine the number of system services in the boot image table and + * compute the size required for the boot image buffer. + */ + nr_image_srvs = 0; + boot_image_buffer_size = 0; + for(i=0;iendpoint))) { + continue; + } + nr_image_srvs++; + + /* Lookup the corresponding entry in the boot image sys table. */ + boot_image_info_lookup(ip->endpoint, image, + NULL, NULL, &boot_image_sys, NULL); + + /* If we must keep a copy of this system service, read the header + * and increase the size of the boot image buffer. + */ + if(boot_image_sys->flags & SF_USE_COPY) { + if((s = sys_getaoutheader(&header, i)) != OK) { + panic("RS", "unable to get copy of a.out header", s); + } + boot_image_buffer_size += header.a_hdrlen + + header.a_text + header.a_data; + } + } + + /* Determine the number of entries in the boot image priv table and make sure + * it matches the number of system services in the boot image table. + */ + nr_image_priv_srvs = 0; + for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) { + boot_image_priv = &boot_image_priv_table[i]; + + /* System services only. */ + if(!isbootsrvprocn(_ENDPOINT_P(boot_image_priv->endpoint))) { + continue; + } + nr_image_priv_srvs++; + } + if(nr_image_srvs != nr_image_priv_srvs) { + panic("RS", "boot image table and boot image priv table mismatch", + NO_NUM); + } + + /* Allocate boot image buffer. */ + if(boot_image_buffer_size > 0) { + boot_image_buffer = rs_startup_sbrk(boot_image_buffer_size); + if(boot_image_buffer == (char *) -1) { + panic("RS", "unable to allocate boot image buffer", NO_NUM); + } + } + + /* Initialize the system process table in 3 steps, each of them following + * the appearance of system services in the boot image priv table. + * - Step 1: get a copy of the executable image of every system service that + * requires it while it is not yet running. + * In addition, set priviliges, sys properties, and dev properties (if any) + * for every system service. + */ + for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) { + boot_image_priv = &boot_image_priv_table[i]; + + /* System services only. */ + if(!isbootsrvprocn(_ENDPOINT_P(boot_image_priv->endpoint))) { + continue; + } + + /* Lookup the corresponding entries in other tables. */ + boot_image_info_lookup(boot_image_priv->endpoint, image, + &ip, NULL, &boot_image_sys, &boot_image_dev); + rp = &rproc[boot_image_priv - boot_image_priv_table]; + + /* + * Get a copy of the executable image if required. + */ + rp->r_exec_len = 0; + rp->r_exec = NULL; + if(boot_image_sys->flags & SF_USE_COPY) { + exec_image_copy(ip - image, ip, rp); + } + + /* + * Set privileges. + * XXX FIXME: We should also let RS set vm calls allowed for each sys + * service by using vm_set_priv(). We need a more uniform privilege + * management scheme in VM for this change. + */ + /* Force a static privilege id for system services in the boot image. */ + rp->r_priv.s_id = static_priv_id(_ENDPOINT_P(boot_image_priv->endpoint)); + + /* Initialize privilege bitmaps. */ + rp->r_priv.s_flags = boot_image_priv->flags; /* privilege flags */ + rp->r_priv.s_trap_mask = boot_image_priv->trap_mask; /* allowed traps */ + memcpy(&rp->r_priv.s_ipc_to, &boot_image_priv->ipc_to, + sizeof(rp->r_priv.s_ipc_to)); /* allowed targets */ + + /* Initialize call mask bitmap from unordered set. */ + fill_call_mask(boot_image_priv->k_calls, NR_SYS_CALLS, + rp->r_priv.s_k_call_mask, KERNEL_CALL); + + /* Set the privilege structure. */ + if ((s = sys_privctl(ip->endpoint, SYS_PRIV_SET_SYS, &(rp->r_priv))) + != OK) { + panic("RS", "unable to set privilege structure", s); + } + + /* Synch the privilege structure with the kernel. */ + if ((s = sys_getpriv(&(rp->r_priv), ip->endpoint)) != OK) { + panic("RS", "unable to synch privilege structure", s); + } + + /* + * Set sys properties. + */ + rp->r_sys_flags = boot_image_sys->flags; /* sys flags */ + + /* + * Set dev properties. + */ + rp->r_dev_nr = boot_image_dev->dev_nr; /* major device number */ + rp->r_dev_style = boot_image_dev->dev_style; /* device style */ + rp->r_period = boot_image_dev->period; /* heartbeat period */ + } + + /* - Step 2: allow every system service in the boot image to run. + */ + for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) { + boot_image_priv = &boot_image_priv_table[i]; + + /* System services only. */ + if(!isbootsrvprocn(_ENDPOINT_P(boot_image_priv->endpoint))) { + continue; + } + + /* Lookup the corresponding entry in the boot image table. */ + boot_image_info_lookup(boot_image_priv->endpoint, image, + &ip, NULL, NULL, NULL); + + /* Allow the process to run. */ + if ((s = sys_privctl(ip->endpoint, SYS_PRIV_ALLOW, NULL)) != OK) { + panic("RS", "unable to initialize privileges", s); + } + } + + /* - Step 3: all the system services in the boot image are now running. Use + * the boot image table from the kernel and PM process table to complete + * the initialization of the system process table. + */ + if ((s = getsysinfo(PM_PROC_NR, SI_PROC_TAB, mproc)) != OK) { + panic("RS", "unable to get copy of PM process table", s); + } + for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) { + boot_image_priv = &boot_image_priv_table[i]; + + /* System services only. */ + if(!isbootsrvprocn(_ENDPOINT_P(boot_image_priv->endpoint))) { + continue; + } + + /* Lookup the corresponding entry in the boot image table. */ + boot_image_info_lookup(boot_image_priv->endpoint, image, + &ip, NULL, NULL, NULL); + rp = &rproc[boot_image_priv - boot_image_priv_table]; + + /* Get label. */ + strcpy(rp->r_label, ip->proc_name); + + /* Get command settings. */ + rp->r_cmd[0]= '\0'; + rp->r_argv[0] = rp->r_cmd; + rp->r_argv[1] = NULL; + rp->r_argc = 1; + rp->r_script[0]= '\0'; + + /* Get settings from the boot image table. */ + rp->r_nice = ip->priority; + rp->r_proc_nr_e = ip->endpoint; + + /* Get pid from PM process table. */ + rp->r_pid = NO_PID; + for (j = 0; j < NR_PROCS; j++) { + if (mproc[j].mp_endpoint == rp->r_proc_nr_e) { + rp->r_pid = mproc[j].mp_pid; + break; + } + } + if(j == NR_PROCS) { + panic("RS", "unable to get pid", NO_NUM); + } + + /* Set some defaults. */ + rp->r_uid = 0; /* root */ + rp->r_check_tm = 0; /* not checked yet */ + getuptime(&rp->r_alive_tm); /* currently alive */ + rp->r_stop_tm = 0; /* not exiting yet */ + rp->r_restarts = 0; /* no restarts so far */ + rp->r_set_resources = 0; /* no resources */ + + /* Mark as in use. */ + rp->r_flags = RS_IN_USE; + rproc_ptr[_ENDPOINT_P(rp->r_proc_nr_e)]= rp; + + /* Publish the new system service. */ + s = publish_service(rp); + if (s != OK) { + panic("RS", "unable to publish boot system service", s); + } + } + + /* + * Now complete RS initialization process in collaboration with other + * system services. + */ + /* Let the rest of the system know about our dynamically allocated buffer. */ + if(boot_image_buffer_size > 0) { + boot_image_buffer = rs_startup_sbrk_synch(boot_image_buffer_size); + if(boot_image_buffer == (char *) -1) { + panic("RS", "unable to synch boot image buffer", NO_NUM); + } + } + + /* Set alarm to periodically check service status. */ + if (OK != (s=sys_setalarm(RS_DELTA_T, 0))) + panic("RS", "couldn't set alarm", s); /* Install signal handlers. Ask PM to transform signal into message. */ sa.sa_handler = SIG_MESS; @@ -138,19 +565,6 @@ PRIVATE void init_server(void) if (sigaction(SIGCHLD,&sa,NULL)<0) panic("RS","sigaction failed", errno); if (sigaction(SIGTERM,&sa,NULL)<0) panic("RS","sigaction failed", errno); - /* Initialize the system process table. Use the boot image from the kernel - * and the device map from the FS to gather all needed information. - */ - if ((s = sys_getimage(image)) != OK) - panic("RS","warning: couldn't get copy of image table", s); - - /* Set alarm to periodically check driver status. */ - if (OK != (s=sys_setalarm(RS_DELTA_T, 0))) - panic("RS", "couldn't set alarm", s); - - /* See if we run in verbose mode. */ - env_parse("rs_verbose", "d", 0, &rs_verbose, 0, 1); - /* Initialize the exec pipe. */ if (pipe(exec_pipe) == -1) panic("RS", "pipe failed", errno); @@ -169,6 +583,17 @@ PRIVATE void init_server(void) { panic("RS", "fcntl set O_NONBLOCK on pipe input failed", errno); } + + /* Map out our own text and data. This is normally done in crtso.o + * but RS is an exception - we don't get to talk to VM so early on. + * That's why we override munmap() and munmap_text() in utility.c. + * + * _minix_unmapzero() is the same code in crtso.o that normally does + * it on startup. It's best that it's there as crtso.o knows exactly + * what the ranges are of the filler data. + */ + unmap_ok = 1; + _minix_unmapzero(); } /*===========================================================================* @@ -198,7 +623,6 @@ message *m_in; /* pointer to message */ panic("RS","receive failed", s); } - /*===========================================================================* * reply * *===========================================================================*/ @@ -213,6 +637,3 @@ message *m_out; /* reply message */ printf("RS: unable to send reply to %d: %d\n", who, s); } - - - diff --git a/servers/rs/manager.c b/servers/rs/manager.c index 1528b2e0a..33897e5cb 100644 --- a/servers/rs/manager.c +++ b/servers/rs/manager.c @@ -12,18 +12,10 @@ #include #include #include -#include -#include -#include #include #include -#include /* For priv.h */ -#include "../../kernel/priv.h" - -/* Allocate variables. */ -struct rproc rproc[NR_SYS_PROCS]; /* system process table */ -struct rproc *rproc_ptr[NR_PROCS]; /* mapping for fast access */ +#include /* Prototypes for internal functions that do the hard work. */ FORWARD _PROTOTYPE( int caller_is_root, (endpoint_t endpoint) ); @@ -46,12 +38,12 @@ FORWARD _PROTOTYPE( void add_forward_ipc, (struct rproc *rp, FORWARD _PROTOTYPE( void add_backward_ipc, (struct rproc *rp, struct priv *privp) ); FORWARD _PROTOTYPE( void init_privs, (struct rproc *rp, struct priv *privp) ); +FORWARD _PROTOTYPE( int set_privs, (endpoint_t endpoint, struct priv *privp, + int req) ); FORWARD _PROTOTYPE( void init_pci, (struct rproc *rp, int endpoint) ); PRIVATE int shutting_down = FALSE; -extern int rs_verbose; - /*===========================================================================* * caller_is_root * *===========================================================================*/ @@ -219,6 +211,7 @@ int flags; /* extra flags, if any */ rp->r_uid= 0; rp->r_nice= 0; + rp->r_sys_flags = DSRV_SF; rp->r_exec= NULL; if (do_copy) @@ -226,6 +219,8 @@ int flags; /* extra flags, if any */ s= read_exec(rp); if (s != OK) return s; + + rp->r_sys_flags |= SF_USE_COPY; } /* Initialize some fields. */ @@ -404,6 +399,7 @@ message *m_ptr; /* request message pointer */ else rp->r_ipc_list[0]= '\0'; + rp->r_sys_flags = DSRV_SF; rp->r_exec= NULL; if (rs_start.rss_flags & RF_COPY) { int exst_cpy; @@ -417,7 +413,7 @@ message *m_ptr; /* request message pointer */ for(i = 0; i < NR_SYS_PROCS; i++) { rp2 = &rproc[i]; if(strcmp(rp->r_cmd, rp2->r_cmd) == 0 && - rp2->r_exec != NULL) { + (rp2->r_sys_flags & SF_USE_COPY)) { /* We have found the same binary that's * already been copied */ exst_cpy = 1; @@ -433,8 +429,17 @@ message *m_ptr; /* request message pointer */ if (s != OK) return s; + + rp->r_sys_flags |= SF_USE_COPY; } + /* All dynamically created services get the same privilege flags, and + * allowed traps. Other privilege settings can be specified at runtime. + * The privilege id is dynamically allocated by the kernel. + */ + rp->r_priv.s_flags = DSRV_F; /* privilege flags */ + rp->r_priv.s_trap_mask = DSRV_T; /* allowed traps */ + /* Copy granted resources */ if (rs_start.rss_nr_irq > NR_IRQ) { @@ -460,12 +465,10 @@ message *m_ptr; /* request message pointer */ rp->r_priv.s_io_tab[i].ior_base= rs_start.rss_io[i].base; rp->r_priv.s_io_tab[i].ior_limit= rs_start.rss_io[i].base+rs_start.rss_io[i].len-1; -#if 0 if(rs_verbose) printf("RS: do_start: I/O [%x..%x]\n", rp->r_priv.s_io_tab[i].ior_base, rp->r_priv.s_io_tab[i].ior_limit); -#endif } if (rs_start.rss_nr_pci_id > RSS_NR_PCI_ID) @@ -516,7 +519,7 @@ message *m_ptr; /* request message pointer */ rp->r_dev_nr = rs_start.rss_major; rp->r_dev_style = STYLE_DEV; rp->r_restarts = -1; /* will be incremented */ - rp->r_set_resources= 1; /* new style, enforece + rp->r_set_resources= 1; /* new style, enforce * I/O resources */ if (sizeof(rp->r_vm) == sizeof(rs_start.rss_vm) && @@ -632,9 +635,10 @@ PUBLIC int do_restart(message *m_ptr) return(r); } } -#if VERBOSE - printf("RS: do_restart: '%s' not found\n", label); -#endif + if(rs_verbose) { + printf("RS: do_restart: '%s' not found\n", label); + } + return(ESRCH); } @@ -666,16 +670,17 @@ PUBLIC int do_refresh(message *m_ptr) for (rp=BEG_RPROC_ADDR; rpr_flags & RS_IN_USE && strcmp(rp->r_label, label) == 0) { -#if VERBOSE - printf("RS: refreshing %s (%d)\n", rp->r_label, rp->r_pid); -#endif + if(rs_verbose) { + printf("RS: refreshing %s (%d)\n", rp->r_label, rp->r_pid); + } stop_service(rp,RS_REFRESHING); return(OK); } } -#if VERBOSE - printf("RS: do_refresh: '%s' not found\n", label); -#endif + if(rs_verbose) { + printf("RS: do_refresh: '%s' not found\n", label); + } + return(ESRCH); } @@ -818,7 +823,7 @@ rp->r_restarts= 0; rp->r_cmd, rp->r_backoff); rp->r_backoff = 1 << MIN(rp->r_restarts,(BACKOFF_BITS-2)); rp->r_backoff = MIN(rp->r_backoff,MAX_BACKOFF); - if (rp->r_exec != NULL && rp->r_backoff > 1) + if ((rp->r_sys_flags & SF_USE_COPY) && rp->r_backoff > 1) rp->r_backoff= 1; } else { @@ -897,8 +902,10 @@ message *m_ptr; * check and, if so request the system service's status. */ else if (now - rp->r_check_tm > rp->r_period) { +#if 0 if(rs_verbose) - printf("RS: status request sent to %d\n", rp->r_proc_nr_e); + printf("RS: status request sent to %d\n", rp->r_proc_nr_e); +#endif notify(rp->r_proc_nr_e); /* request status */ rp->r_check_tm = now; /* mark time */ } @@ -933,8 +940,15 @@ endpoint_t *endpoint; message m; char * null_env = NULL; - use_copy= (rp->r_exec != NULL); - + use_copy= (rp->r_sys_flags & SF_USE_COPY); + + /* See if we are not using a copy but we do need one to start the service. */ + if(!use_copy && (rp->r_sys_flags & SF_NEED_COPY)) { + printf("RS: unable to start service %s without an in-memory copy\n", + rp->r_label); + return(EPERM); + } + /* Now fork and branch for parent and child process (and check for error). */ if (use_copy) { if(rs_verbose) printf("RS: fork_nb..\n"); @@ -1046,21 +1060,13 @@ endpoint_t *endpoint; * That will also cause the child process to start running. * This call should succeed: we tested number in use above. */ - if ((s = sys_privctl(child_proc_nr_e, SYS_PRIV_INIT, privp)) < 0) { - report("RS","sys_privctl call failed", s); /* to let child run */ + if ((s = set_privs(child_proc_nr_e, privp, SYS_PRIV_SET_SYS)) != OK) { + report("RS","set_privs failed", s); kill(child_pid, SIGKILL); /* kill driver */ rp->r_flags |= RS_EXITING; /* expect exit */ return(s); /* return error */ } - /* The child is now running. Publish its endpoint in DS. */ - s= ds_publish_u32(rp->r_label, child_proc_nr_e); - if (s != OK) - printf("RS: start_service: ds_publish_u32 failed: %d\n", s); - else if(rs_verbose) - printf("RS: start_service: ds_publish_u32 done: %s -> %d\n", - rp->r_label, child_proc_nr_e); - /* The purpose of non-blocking forks is to avoid involving VFS in the forking * process, because VFS may be blocked on a sendrec() to a MFS that is * waiting for a endpoint update for a dead driver. We have just published @@ -1074,6 +1080,11 @@ endpoint_t *endpoint; if (use_copy) setuid(0); + /* Publish the new system service. */ + s = publish_service(rp); + if (s != OK) { + printf("RS: warning: publish_service failed: %d\n", s); + } if (rp->r_dev_nr > 0) { /* set driver map */ if ((s=mapdriver5(rp->r_label, strlen(rp->r_label), rp->r_dev_nr, rp->r_dev_style, !!use_copy /* force */)) < 0) { @@ -1270,14 +1281,13 @@ struct rproc *rp; rp->r_script, strerror(errno)); exit(1); default: - /* Set the privilege structure for the child process to let it + /* Set the privilege structure for the child process and let it * run. */ proc_nr_e = getnprocnr(pid); - r= sys_privctl(proc_nr_e, SYS_PRIV_USER, NULL); - if (r < 0) - printf("RS: run_script: sys_privctl call failed: %d\n", r); - + if ((r= set_privs(proc_nr_e, NULL, SYS_PRIV_SET_USER)) != OK) { + printf("RS: run_script: set_privs call failed: %d\n",r); + } /* Do not wait for the child */ break; } @@ -1339,7 +1349,9 @@ struct priv *privp; char label[MAX_LABEL_LEN+1], *p; struct rproc *tmp_rp; endpoint_t proc_nr_e; + int r; int slot_nr, priv_id; + struct priv priv; p = rp->r_ipc_list; @@ -1385,14 +1397,14 @@ struct priv *privp; proc_nr_e= tmp_rp->r_proc_nr_e; } - priv_id= sys_getprivid(proc_nr_e); - if (priv_id < 0) + if ((r = sys_getpriv(&priv, proc_nr_e)) < 0) { printf( "add_forward_ipc: unable to get priv_id for '%s': %d\n", - label, priv_id); + label, r); continue; } + priv_id= priv.s_id; set_sys_bit(privp->s_ipc_to, priv_id); } } @@ -1440,14 +1452,7 @@ struct priv *privp; continue; } - priv_id= sys_getprivid(rrp->r_proc_nr_e); - if (priv_id < 0) - { - printf( - "add_backward_ipc: unable to get priv_id for '%s': %d\n", - label, priv_id); - continue; - } + priv_id= rrp->r_priv.s_id; set_sys_bit(privp->s_ipc_to, priv_id); } @@ -1513,6 +1518,35 @@ struct priv *privp; } } +/*===========================================================================* + * set_privs * + *===========================================================================*/ +PRIVATE int set_privs(endpoint, privp, req) +endpoint_t endpoint; +struct priv *privp; +int req; +{ + int r; + + /* Set the privilege structure. */ + if ((r = sys_privctl(endpoint, req, privp)) != OK) { + return r; + } + + /* Synch the privilege structure with the kernel for system services. */ + if(req == SYS_PRIV_SET_SYS) { + if ((r = sys_getpriv(privp, endpoint)) != OK) { + return r; + } + } + + /* Allow the process to run. */ + if ((r = sys_privctl(endpoint, SYS_PRIV_ALLOW, NULL)) != OK) { + return r; + } + + return(OK); +} /*===========================================================================* * init_pci * diff --git a/servers/rs/memory.c b/servers/rs/memory.c new file mode 100644 index 000000000..b80561058 --- /dev/null +++ b/servers/rs/memory.c @@ -0,0 +1,213 @@ +/* This file contains memory management routines for RS. + * + * Changes: + * Nov 22, 2009: Created (Cristiano Giuffrida) + */ + +#include "inc.h" +#include "../../kernel/const.h" +#include "../../kernel/type.h" +#include "../../kernel/proc.h" + +EXTERN char *_brksize; + +PRIVATE char * _rs_startbrksize = NULL; +PRIVATE char * _rs_endbrksize = NULL; + +#define munmap _munmap +#define munmap_text _munmap_text +#include +#undef munmap +#undef munmap_text + +PUBLIC int unmap_ok = 0; + +/*===========================================================================* + * check_mem_available * + *===========================================================================*/ +PRIVATE int check_mem_available(char *new_brksize) +{ +/* Check if enough memory is available to grow break size. */ + register struct mem_map *mem_sp, *mem_dp; + vir_clicks sp_click, gap_base, sp_lower; + int s; + long base_of_stack, sp_delta; /* longs avoid certain problems */ + vir_bytes sp; + struct proc proc; + vir_clicks data_clicks; + + /* Get stack pointer and pointers to data/stack segment maps. */ + if ((s=sys_getproc(&proc, SELF)) != OK) { + return(s); + } + sp = proc.p_reg.sp; /* stack pointer */ + mem_dp = &proc.p_memmap[D]; /* pointer to data segment map */ + 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; + + /* 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; + sp_click = sp >> CLICK_SHIFT; /* click containing sp */ + if (sp_click >= base_of_stack) + { + return(ENOMEM); /* sp too high */ + } + + /* Compute size of gap between stack and data segments. */ + sp_delta = (long) mem_sp->mem_vir - (long) sp_click; + sp_lower = (sp_delta > 0 ? sp_click : mem_sp->mem_vir); + + /* 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) + gap_base = mem_dp->mem_vir + data_clicks + SAFETY_CLICKS; + if (sp_lower < gap_base) + { + return(ENOMEM); /* data and stack collided */ + } + + return(OK); +} + +/*===========================================================================* + * rs_startup_sbrk * + *===========================================================================*/ +PUBLIC void* rs_startup_sbrk(size) +size_t size; /* the size to grow */ +{ +/* RS's own sbrk() used at startup. */ + void* addr; + char* new_brksize; + + /* Check input for non-positive size or size overflows. */ + new_brksize = _brksize + size; + if (size <= 0 || new_brksize < _brksize) { + return( (char *) -1); + } + + /* Check if enough memory is available. */ + if(check_mem_available(new_brksize) != OK) { + return( (char *) -1); + } + + /* Save initial break size. */ + if(_rs_startbrksize == NULL) { + _rs_startbrksize = _brksize; + } + + /* Set address and adjust break size. */ + addr = _brksize; + _brksize = new_brksize; + _rs_endbrksize = _brksize; + + return addr; +} + +/*===========================================================================* + * rs_startup_sbrk_synch * + *===========================================================================*/ +PUBLIC void* rs_startup_sbrk_synch(size) +size_t size; /* the size to grow */ +{ +/* Synchronize RS's own sbrk() with the rest of the system right after + * startup. We use the original sbrk() here. + */ + void* addr; + + /* Restore original break size. */ + _brksize = _rs_startbrksize; + + /* Call original sbrk() and see if we observe the same effect. */ + addr = (void*)sbrk(size); + if(_rs_startbrksize != addr) { + printf("Unable to synch rs_startup_sbrk() and sbrk(): addr 0x%x!=0x%x\n", + (int) _rs_startbrksize, (int) addr); + return( (char *) -1); + } + if(_rs_endbrksize != _brksize) { + printf("Unable to synch rs_startup_sbrk() and sbrk(): size 0x%x!=0x%x\n", + (int) _rs_endbrksize, (int) _brksize); + return( (char *) -1); + } + + return addr; +} + +/*===========================================================================* + * rs_startup_segcopy * + *===========================================================================*/ +PUBLIC int rs_startup_segcopy(src_proc, src_seg, dst_seg, dst_vir, bytes) +endpoint_t src_proc; /* source process */ +int src_seg; /* source memory segment */ +int dst_seg; /* destination memory segment */ +vir_bytes dst_vir; /* destination virtual address */ +phys_bytes bytes; /* how many bytes */ +{ +/* Copy a process's T, D, S segment to RS's address space. Used at startup. */ + struct proc src_p, dst_p; + phys_bytes src_phys, dst_phys; + int s; + + /* Check input. */ + if((src_seg != T && src_seg != D && src_seg != S) || bytes <= 0) { + return EINVAL; + } + + /* We don't override normal behavior when not copying to our data segment. */ + if(dst_seg != D) { + s = sys_vircopy(src_proc, src_seg, 0, SELF, dst_seg, dst_vir, bytes); + return(s); + } + + /* Get kernel process slot for both source and destination. */ + if ((s=sys_getproc(&src_p, src_proc)) != OK) { + return(s); + } + if ((s=sys_getproc(&dst_p, SELF)) != OK) { + return(s); + } + + /* Map source address to physical address. */ + src_phys = (phys_bytes) src_p.p_memmap[src_seg].mem_phys << CLICK_SHIFT; + + /* Check if destination address is out of bounds or overflows. */ + if(dst_vir+bytes > (vir_bytes)_rs_endbrksize + || dst_vir < (vir_bytes)_rs_startbrksize || dst_vir+bytes < dst_vir) { + return EFAULT; + } + + /* Map destination address to physical address. */ + dst_phys = (phys_bytes) dst_p.p_memmap[D].mem_phys << CLICK_SHIFT; + dst_phys += dst_vir - (dst_p.p_memmap[D].mem_vir << CLICK_SHIFT); + + /* Make a physical copy for the requested data. */ + s = sys_abscopy(src_phys, dst_phys, bytes); + + return(s); +} + +/*===========================================================================* + * munmap * + *===========================================================================*/ +PUBLIC int munmap(void *addrstart, vir_bytes len) +{ + if(!unmap_ok) + return ENOSYS; + + return _munmap(addrstart, len); +} + +/*===========================================================================* + * munmap_text * + *===========================================================================*/ +PUBLIC int munmap_text(void *addrstart, vir_bytes len) +{ + if(!unmap_ok) + return ENOSYS; + + return _munmap_text(addrstart, len); +} + diff --git a/servers/rs/proto.h b/servers/rs/proto.h index 7ec33f0ca..e8d9a099f 100644 --- a/servers/rs/proto.h +++ b/servers/rs/proto.h @@ -1,5 +1,8 @@ /* Function prototypes. */ +/* Structs used in prototypes must be declared as such first. */ +struct rproc; + /* exec.c */ _PROTOTYPE( int dev_execve, (int proc_e, char *exec, size_t exec_len, char *argv[], char **env)); @@ -19,4 +22,12 @@ _PROTOTYPE( void do_period, (message *m)); _PROTOTYPE( void do_exit, (message *m)); _PROTOTYPE( int do_getsysinfo, (message *m)); +/* utility.c */ +_PROTOTYPE( int publish_service, (struct rproc *rp)); + +/* memory.c */ +_PROTOTYPE( void* rs_startup_sbrk, (size_t size)); +_PROTOTYPE( void* rs_startup_sbrk_synch, (size_t size)); +_PROTOTYPE( int rs_startup_segcopy, (endpoint_t src_proc, int src_s, + int dst_s, vir_bytes dst_vir, phys_bytes bytes)); diff --git a/servers/rs/table.c b/servers/rs/table.c new file mode 100644 index 000000000..4264c8719 --- /dev/null +++ b/servers/rs/table.c @@ -0,0 +1,67 @@ +/* This file contains the definition of the boot image info tables. + * + * Changes: + * Nov 22, 2009: Created (Cristiano Giuffrida) + */ + +#define _TABLE + +#include "inc.h" + +/* Define kernel calls that processes are allowed to make. This is not looking + * very nice, but we need to define the access rights on a per call basis. + * + * Calls are unordered lists, converted by RS to bitmasks + * once at runtime. + */ +#define FS_KC SYS_KILL, SYS_VIRCOPY, SYS_SAFECOPYFROM, SYS_SAFECOPYTO, \ + SYS_VIRVCOPY, SYS_UMAP, SYS_GETINFO, SYS_EXIT, SYS_TIMES, SYS_SETALARM, \ + SYS_PRIVCTL, SYS_TRACE , SYS_SETGRANT, SYS_PROFBUF, SYS_SYSCTL +#define DRV_KC FS_KC, SYS_SEGCTL, SYS_IRQCTL, SYS_INT86, SYS_DEVIO, \ + SYS_SDEVIO, SYS_VDEVIO, SYS_SETGRANT, SYS_PROFBUF, SYS_SYSCTL + +PRIVATE int + fs_kc[] = { FS_KC, SYS_NULL_C }, + pm_kc[] = { SYS_ALL_C, SYS_NULL_C }, + ds_kc[] = { SYS_ALL_C, SYS_NULL_C }, + vm_kc[] = { SYS_ALL_C, SYS_NULL_C }, + drv_kc[] = { DRV_KC, SYS_NULL_C }, + tty_kc[] = { DRV_KC, SYS_PHYSCOPY, SYS_ABORT, SYS_IOPENABLE, + SYS_READBIOS, SYS_NULL_C }, + mem_kc[] = { DRV_KC, SYS_PHYSCOPY, SYS_PHYSVCOPY, SYS_IOPENABLE, SYS_NULL_C }, + rusr_kc[] = { SYS_NULL_C }, + + no_kc[] = { SYS_NULL_C }; /* no kernel call */ + +/* Definition of the boot image priv table. */ +PUBLIC struct boot_image_priv boot_image_priv_table[] = { + /*endpoint, priv flags, traps, ipcto, kcalls */ + { VM_PROC_NR, VM_F, SRV_T, SRV_M, vm_kc }, + { PM_PROC_NR, SRV_F, SRV_T, SRV_M, pm_kc }, + { FS_PROC_NR, SRV_F, SRV_T, SRV_M, fs_kc }, + { DS_PROC_NR, SRV_F, SRV_T, SRV_M, ds_kc }, + { TTY_PROC_NR, SRV_F, SRV_T, SRV_M, tty_kc }, + { MEM_PROC_NR, SRV_F, SRV_T, SRV_M, mem_kc }, + { LOG_PROC_NR, SRV_F, SRV_T, SRV_M, drv_kc }, + { MFS_PROC_NR, SRV_F, SRV_T, SRV_M, fs_kc }, + { INIT_PROC_NR, RUSR_F, RUSR_T, RUSR_M, rusr_kc }, + { NULL_BOOT_NR, 0, 0, 0, no_kc } /* null entry */ +}; + +/* Definition of the boot image sys table. */ +PUBLIC struct boot_image_sys boot_image_sys_table[] = { + /*endpoint, sys flags */ + { LOG_PROC_NR, SRVC_SF }, + { MFS_PROC_NR, SRVC_SF }, + { DEFAULT_BOOT_NR, SRV_SF } /* default entry */ +}; + +/* Definition of the boot image dev table. */ +PUBLIC struct boot_image_dev boot_image_dev_table[] = { + /*endpoint, dev_nr, dev_style, period */ + { TTY_PROC_NR, TTY_MAJOR, STYLE_TTY, 0 }, + { MEM_PROC_NR, MEMORY_MAJOR, STYLE_DEV, 0 }, + { LOG_PROC_NR, LOG_MAJOR, STYLE_DEV, 0 }, + { DEFAULT_BOOT_NR, 0, STYLE_NDEV, 0 } /* default entry */ +}; + diff --git a/servers/rs/type.h b/servers/rs/type.h new file mode 100644 index 000000000..aa2e2ce2c --- /dev/null +++ b/servers/rs/type.h @@ -0,0 +1,78 @@ +/* Type definitions used in RS. + */ +#ifndef RS_TYPE_H +#define RS_TYPE_H + +/* Definition of an entry of the boot image priv table. */ +struct boot_image_priv { + endpoint_t endpoint; /* process endpoint number */ + + int flags; /* privilege flags */ + short trap_mask; /* allowed system call traps */ + int ipc_to; /* send mask protection */ + int *k_calls; /* kernel call protection */ +}; + +/* Definition of an entry of the boot image sys table. */ +struct boot_image_sys { + endpoint_t endpoint; /* process endpoint number */ + + int flags; /* system flags */ +}; + +/* Definition of an entry of the boot image dev table. */ +struct boot_image_dev { + endpoint_t endpoint; /* process endpoint number */ + + dev_t dev_nr; /* major device number */ + int dev_style; /* device style */ + long period; /* heartbeat period (or zero) */ +}; + +/* Definition of an entry of the system process table. */ +struct rproc { + endpoint_t r_proc_nr_e; /* process endpoint number */ + pid_t r_pid; /* process id, -1 if the process is not there */ + dev_t r_dev_nr; /* major device number */ + int r_dev_style; /* device style */ + + int r_restarts; /* number of restarts (initially zero) */ + long r_backoff; /* number of periods to wait before revive */ + unsigned r_flags; /* status and policy flags */ + unsigned r_sys_flags; /* sys flags */ + + long r_period; /* heartbeat period (or zero) */ + clock_t r_check_tm; /* timestamp of last check */ + clock_t r_alive_tm; /* timestamp of last heartbeat */ + clock_t r_stop_tm; /* timestamp of SIGTERM signal */ + endpoint_t r_caller; /* RS_LATEREPLY caller */ + + char *r_exec; /* Executable image */ + size_t r_exec_len; /* Length of image */ + + char r_label[MAX_LABEL_LEN]; /* unique name of this driver */ + char r_cmd[MAX_COMMAND_LEN]; /* raw command plus arguments */ + char r_script[MAX_SCRIPT_LEN]; /* name of the restart script executable */ + char *r_argv[MAX_NR_ARGS+2]; /* parsed arguments vector */ + int r_argc; /* number of arguments */ + + /* Resources */ + int r_set_resources; + struct priv r_priv; /* Privilege structure to be passed to the + * kernel. + */ + uid_t r_uid; + int r_nice; + int r_nr_pci_id; /* Number of PCI devices IDs */ + struct { u16_t vid; u16_t did; } r_pci_id[RSS_NR_PCI_ID]; + int r_nr_pci_class; /* Number of PCI class IDs */ + struct { u32_t class; u32_t mask; } r_pci_class[RSS_NR_PCI_CLASS]; + + u32_t r_call_mask[RSS_NR_SYSTEM]; + char r_ipc_list[MAX_IPC_LIST]; + bitchunk_t r_vm[RSS_VM_CALL_SIZE]; + int r_nr_control; + char r_control[RSS_NR_CONTROL][MAX_LABEL_LEN]; +}; + +#endif /* RS_TYPE_H */ diff --git a/servers/rs/utility.c b/servers/rs/utility.c new file mode 100644 index 000000000..5caf96c58 --- /dev/null +++ b/servers/rs/utility.c @@ -0,0 +1,32 @@ +/* This file contains some utility routines for RS. + * + * Changes: + * Nov 22, 2009: Created (Cristiano Giuffrida) + */ + +#include "inc.h" + +#include + +/*===========================================================================* + * publish_service * + *===========================================================================*/ +PUBLIC int publish_service(rp) +struct rproc *rp; /* pointer to process slot */ +{ +/* A new system service has been started. Publish the necessary information. */ + int s; + + /* Register its label with DS. */ + s= ds_publish_u32(rp->r_label, rp->r_proc_nr_e); + if (s != OK) { + return s; + } + if (rs_verbose) { + printf("RS: publish_service: DS label registration done: %s -> %d\n", + rp->r_label, rp->r_proc_nr_e); + } + + return(OK); +} +