From: Cristiano Giuffrida Date: Fri, 11 Dec 2009 00:08:19 +0000 (+0000) Subject: Rewrite of boot process X-Git-Tag: v3.1.6~156 X-Git-Url: http://zhaoyanbai.com/repos/?a=commitdiff_plain;h=f4574783dc7a5321e7ffc1c60a61eefe1c27bc32;p=minix.git Rewrite of boot process KERNEL CHANGES: - The kernel only knows about privileges of kernel tasks and the root system process (now RS). - Kernel tasks and the root system process are the only processes that are made schedulable by the kernel at startup. All the other processes in the boot image don't get their privileges set at startup and are inhibited from running by the RTS_NO_PRIV flag. - Removed the assumption on the ordering of processes in the boot image table. System processes can now appear in any order in the boot image table. - Privilege ids can now be assigned both statically or dynamically. The kernel assigns static privilege ids to kernel tasks and the root system process. Each id is directly derived from the process number. - User processes now all share the static privilege id of the root user process (now INIT). - sys_privctl split: we have more calls now to let RS set privileges for system processes. SYS_PRIV_ALLOW / SYS_PRIV_DISALLOW are only used to flip the RTS_NO_PRIV flag and allow / disallow a process from running. SYS_PRIV_SET_SYS / SYS_PRIV_SET_USER are used to set privileges for a system / user process. - boot image table flags split: PROC_FULLVM is the only flag that has been moved out of the privilege flags and is still maintained in the boot image table. All the other privilege flags are out of the kernel now. RS CHANGES: - RS is the only user-space process who gets to run right after in-kernel startup. - RS uses the boot image table from the kernel and three additional boot image info table (priv table, sys table, dev table) to complete the initialization of the system. - RS checks that the entries in the priv table match the entries in the boot image table to make sure that every process in the boot image gets schedulable. - RS only uses static privilege ids to set privileges for system services in the boot image. - RS includes basic memory management support to allocate the boot image buffer dynamically during initialization. The buffer shall contain the executable image of all the system services we would like to restart after a crash. - First step towards decoupling between resource provisioning and resource requirements in RS: RS must know what resources it needs to restart a process and what resources it has currently available. This is useful to tradeoff reliability and resource consumption. When required resources are missing, the process cannot be restarted. In that case, in the future, a system flag will tell RS what to do. For example, if CORE_PROC is set, RS should trigger a system-wide panic because the system can no longer function correctly without a core system process. PM CHANGES: - The process tree built at initialization time is changed to have INIT as root with pid 0, RS child of INIT and all the system services children of RS. This is required to make RS in control of all the system services. - PM no longer registers labels for system services in the boot image. This is now part of RS's initialization process. --- 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_ADD_IRQ 4 /* Add IRQ */ -#define SYS_PRIV_USER 5 /* Make a process an oridinary user - * process. +#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_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 */ - - 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); - - for (j = 0; j < NR_SYS_PROCS && j < BITCHUNK_BITS; j++) - if (ip->ipc_to & (1 << j)) - set_sendto_bit(rp, j); /* restrict targets */ - - if (iskerneln(proc_nr(rp))) { /* part of the kernel? */ + 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)); + + /* 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 */ + } + + /* 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); + } + + /* 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 */ - - 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 */ + register struct priv *sp; /* privilege structure */ - /* 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); +#endif + } + } + + /* 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 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 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 + } } - /* Check requests for IRQs */ - priv(rp)->s_flags |= CHECK_IO_PORT; + /* 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); - } + /* 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); } - /* Done. Privileges have been set. Allow process to run again. */ - RTS_LOCK_UNSET(rp, RTS_NO_PRIV); 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); +} +