From: Jorrit Herder Date: Fri, 29 Jul 2005 15:26:23 +0000 (+0000) Subject: - Kernel call handlers cleaned up. More strict checking of input parameters. X-Git-Tag: v3.1.0~491 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/man.dnssec-dsfromkey.html?a=commitdiff_plain;h=0946d128cd973684ba7aad4763c74350c2cdfcfc;p=minix.git - Kernel call handlers cleaned up. More strict checking of input parameters. - Moved generic_handler() from system.c to system/do_irqctl.c. - Set privileges of system processes somewhat stricter. --- diff --git a/kernel/glo.h b/kernel/glo.h index 9cde441f0..a80b84dc6 100755 --- a/kernel/glo.h +++ b/kernel/glo.h @@ -47,7 +47,7 @@ EXTERN reg_t mon_ss, mon_sp; /* boot monitor stack */ EXTERN int mon_return; /* true if we can return to monitor */ /* Variables that are initialized elsewhere are just extern here. */ -extern struct system_image image[]; /* system image processes */ +extern struct boot_image image[]; /* system image processes */ extern char *t_stack[]; /* task stack space */ extern struct segdesc_s gdt[]; /* global descriptor table */ diff --git a/kernel/ipc.h b/kernel/ipc.h index cd414619e..ffff3cf2c 100644 --- a/kernel/ipc.h +++ b/kernel/ipc.h @@ -30,6 +30,7 @@ */ #define EMPTY_MASK (0) #define FILLED_MASK (~0) +#define TASK_CALL_MASK (1 << RECEIVE) #define USER_CALL_MASK ((1 << SENDREC) | (1 << ECHO)) /* Send masks determine to whom processes can send messages or notifications. diff --git a/kernel/main.c b/kernel/main.c index bdc63580e..51d943065 100755 --- a/kernel/main.c +++ b/kernel/main.c @@ -25,8 +25,6 @@ FORWARD _PROTOTYPE( void announce, (void)); FORWARD _PROTOTYPE( void shutdown, (timer_t *tp)); -#define SHUTDOWN_TICKS 5 /* time allowed to do cleanup */ - /*===========================================================================* * main * @@ -34,7 +32,7 @@ FORWARD _PROTOTYPE( void shutdown, (timer_t *tp)); PUBLIC void main() { /* Start the ball rolling. */ - struct system_image *ip; /* boot image pointer */ + struct boot_image *ip; /* boot image pointer */ register struct proc *rp; /* process pointer */ register struct priv *sp; /* privilege structure pointer */ register int i, s; @@ -188,8 +186,8 @@ PUBLIC void prepare_shutdown(how) int how; { /* This function prepares to shutdown MINIX. */ - register struct proc *rp; static timer_t shutdown_timer; + register struct proc *rp; message m; /* Show debugging dumps on panics. Make sure that the TTY task is still @@ -221,7 +219,7 @@ int how; */ kprintf("MINIX will now be shut down ...\n"); tmr_arg(&shutdown_timer)->ta_int = how; - set_timer(&shutdown_timer, get_uptime() + SHUTDOWN_TICKS, shutdown); + set_timer(&shutdown_timer, get_uptime() + HZ, shutdown); } diff --git a/kernel/proto.h b/kernel/proto.h index c70db811c..2cb05fa6f 100755 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -51,7 +51,6 @@ _PROTOTYPE( phys_bytes umap_remote, (struct proc *rp, int seg, vir_bytes vir_addr, vir_bytes bytes) ); _PROTOTYPE( phys_bytes umap_bios, (struct proc *rp, vir_bytes vir_addr, vir_bytes bytes) ); -_PROTOTYPE( int generic_handler, (irq_hook_t *hook) ); #if (CHIP == INTEL) diff --git a/kernel/system.c b/kernel/system.c index b4f19d016..714bf3732 100755 --- a/kernel/system.c +++ b/kernel/system.c @@ -20,15 +20,11 @@ * numap_local: umap_local D segment from proc nr instead of pointer * virtual_copy: copy bytes from one virtual address to another * get_randomness: accumulate randomness in a buffer - * generic_handler: interrupt handler for user-level device drivers * * Changes: - * Apr 25, 2005 made mapping of call vector explicit (Jorrit N. Herder) - * Oct 17, 2004 generic handler and IRQ policies (Jorrit N. Herder) * Oct 10, 2004 dispatch system calls from call vector (Jorrit N. Herder) * Sep 30, 2004 source code documentation updated (Jorrit N. Herder) - * Sep 10, 2004 system call functions in library (Jorrit N. Herder) - * 2004 to 2005 various new syscalls (see syslib.h) (Jorrit N. Herder) + * 2004 to 2005 various new syscalls (see system.h) (Jorrit N. Herder) */ #include "kernel.h" @@ -184,6 +180,7 @@ int proc_type; /* system or user process flag */ if (sp->s_proc_nr != NONE) 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 */ } else { rc->p_priv = &priv[USER_PRIV_ID]; /* use shared slot */ rc->p_priv->s_proc_nr = INIT_PROC_NR; /* set association */ @@ -228,34 +225,6 @@ int source; } -/*===========================================================================* - * generic_handler * - *===========================================================================*/ -PUBLIC int generic_handler(hook) -irq_hook_t *hook; -{ -/* This function handles hardware interrupt in a simple and generic way. All - * interrupts are transformed into messages to a driver. The IRQ line will be - * reenabled if the policy says so. - */ - - /* As a side-effect, the interrupt handler gathers random information by - * timestamping the interrupt events. This is used for /dev/random. - */ - get_randomness(hook->irq); - - /* Add a bit for this interrupt to the process' pending interrupts. When - * sending the notification message, this bit map will be magically set - * as an argument. - */ - priv(proc_addr(hook->proc_nr))->s_int_pending |= (1 << hook->notify_id); - - /* Build notification message and return. */ - lock_notify(HARDWARE, hook->proc_nr); - return(hook->policy & IRQ_REENABLE); -} - - /*===========================================================================* * send_sig * *===========================================================================*/ diff --git a/kernel/system/Makefile b/kernel/system/Makefile index 96e2c53d5..f852ae666 100644 --- a/kernel/system/Makefile +++ b/kernel/system/Makefile @@ -25,7 +25,7 @@ OBJECTS = \ $(SYSTEM)(do_trace.o) \ $(SYSTEM)(do_nice.o) \ $(SYSTEM)(do_times.o) \ - $(SYSTEM)(do_alarm.o) \ + $(SYSTEM)(do_setalarm.o) \ $(SYSTEM)(do_irqctl.o) \ $(SYSTEM)(do_devio.o) \ $(SYSTEM)(do_vdevio.o) \ @@ -82,8 +82,8 @@ $(SYSTEM)(do_nice.o): do_nice.c $(SYSTEM)(do_times.o): do_times.c $(CC) do_times.c -$(SYSTEM)(do_alarm.o): do_alarm.c - $(CC) do_alarm.c +$(SYSTEM)(do_setalarm.o): do_setalarm.c + $(CC) do_setalarm.c $(SYSTEM)(do_irqctl.o): do_irqctl.c $(CC) do_irqctl.c diff --git a/kernel/system/do_abort.c b/kernel/system/do_abort.c index 8b2c247b4..3f9670fb3 100644 --- a/kernel/system/do_abort.c +++ b/kernel/system/do_abort.c @@ -20,23 +20,25 @@ PUBLIC int do_abort(m_ptr) message *m_ptr; /* pointer to request message */ { /* Handle sys_abort. MINIX is unable to continue. This can originate in the - * PM (normal abort or panic) or FS (panic), or TTY (user issued CTRL-ALT-DEL - * or ESC after debugging dumps). + * PM (normal abort or panic) or FS (panic), or TTY (after CTRL-ALT-DEL). */ int how = m_ptr->ABRT_HOW; + int proc_nr; + int length; + phys_bytes src_phys; /* See if the monitor is to run the specified instructions. */ if (how == RBT_MONITOR) { - int proc_nr = m_ptr->ABRT_MON_PROC; - int length = m_ptr->ABRT_MON_LEN + 1; - vir_bytes src_vir = (vir_bytes) m_ptr->ABRT_MON_ADDR; - phys_bytes src_phys = numap_local(proc_nr, src_vir, length); - - /* Validate length and address of shutdown code before copying. */ - if (length > kinfo.params_size || src_phys == 0) - phys_copy(vir2phys("delay;boot"), kinfo.params_base, 11); - else - phys_copy(src_phys, kinfo.params_base, (phys_bytes) length); + + proc_nr = m_ptr->ABRT_MON_PROC; + if (! isokprocn(proc_nr)) return(EINVAL); + length = m_ptr->ABRT_MON_LEN + 1; + if (length > kinfo.params_size) return(E2BIG); + src_phys = numap_local(proc_nr,(vir_bytes)m_ptr->ABRT_MON_ADDR,length); + if (! src_phys) return(EFAULT); + + /* Parameters seem ok, copy them and prepare shutting down. */ + phys_copy(src_phys, kinfo.params_base, (phys_bytes) length); } /* Now prepare to shutdown MINIX. */ diff --git a/kernel/system/do_endksig.c b/kernel/system/do_endksig.c index 6f046364d..5311bf570 100644 --- a/kernel/system/do_endksig.c +++ b/kernel/system/do_endksig.c @@ -23,8 +23,11 @@ message *m_ptr; /* pointer to request message */ */ register struct proc *rp; + /* Get process pointer and verify that it had signals pending. If the + * process is already dead its flags will be reset. + */ rp = proc_addr(m_ptr->SIG_PROC); - if (isemptyp(rp)) return(EINVAL); /* process already dead? */ + if (! (rp->p_rts_flags & SIG_PENDING)) return(EINVAL); /* PM has finished one kernel signal. Perhaps process is ready now? */ if (! (rp->p_rts_flags & SIGNALED)) /* new signal arrived */ diff --git a/kernel/system/do_fork.c b/kernel/system/do_fork.c index 8ae1df01c..a342d2e6b 100644 --- a/kernel/system/do_fork.c +++ b/kernel/system/do_fork.c @@ -4,7 +4,6 @@ * The parameters for this system call are: * m1_i1: PR_PROC_NR (child's process table slot) * m1_i2: PR_PPROC_NR (parent, process that forked) - * m1_i3: PR_PID (child pid received from PM) */ #include "../system.h" @@ -33,6 +32,18 @@ register message *m_ptr; /* pointer to request message */ rpc = proc_addr(m_ptr->PR_PROC_NR); if (isemptyp(rpp) || ! isemptyp(rpc)) return(EINVAL); + /* If this is a system process, make sure the child process gets its own + * privilege structure for accounting. This is the only part that can fail, + * so do this before allocating the process table slot. + */ + if (priv(rpc)->s_flags & SYS_PROC) { + if (OK != (i=get_priv(rpc, SYS_PROC))) return(i); /* get structure */ + for (i=0; i< BITMAP_CHUNKS(NR_SYS_PROCS); i++) /* remove pending: */ + priv(rpc)->s_notify_pending.chunk[i] = 0; /* - notifications */ + priv(rpc)->s_int_pending = 0; /* - interrupts */ + sigemptyset(&priv(rpc)->s_sig_pending); /* - signals */ + } + /* Copy parent 'proc' struct to child. And reinitialize some fields. */ #if (CHIP == INTEL) old_ldt_sel = rpc->p_ldt_sel; /* backup local descriptors */ @@ -52,16 +63,6 @@ register message *m_ptr; /* pointer to request message */ rpc->p_user_time = 0; /* set all the accounting times to 0 */ rpc->p_sys_time = 0; - /* If this is a system process, make sure the child process gets its own - * privilege structure for accounting. - */ - if (priv(rpc)->s_flags & SYS_PROC) { - if (OK != (i=get_priv(rpc, SYS_PROC))) return(i); /* get structure */ - for (i=0; i< BITMAP_CHUNKS(NR_SYS_PROCS); i++) /* remove pending: */ - priv(rpc)->s_notify_pending.chunk[i] = 0; /* - notifications */ - priv(rpc)->s_int_pending = 0; /* - interrupts */ - sigemptyset(&priv(rpc)->s_sig_pending); /* - signals */ - } return(OK); } diff --git a/kernel/system/do_getinfo.c b/kernel/system/do_getinfo.c index a7cbb2644..8b09f572d 100644 --- a/kernel/system/do_getinfo.c +++ b/kernel/system/do_getinfo.c @@ -3,7 +3,6 @@ * * The parameters for this system call are: * m1_i3: I_REQUEST (what info to get) - * m1_i4: I_PROC_NR (process to store value at) * m1_p1: I_VAL_PTR (where to put it) * m1_i1: I_VAL_LEN (maximum length expected, optional) * m1_p2: I_VAL_PTR2 (second, optional pointer) @@ -47,7 +46,7 @@ register message *m_ptr; /* pointer to request message */ break; } case GET_IMAGE: { - length = sizeof(struct system_image) * NR_BOOT_PROCS; + length = sizeof(struct boot_image) * NR_BOOT_PROCS; src_phys = vir2phys(image); break; } diff --git a/kernel/system/do_irqctl.c b/kernel/system/do_irqctl.c index 7d7d89f17..3833606ef 100644 --- a/kernel/system/do_irqctl.c +++ b/kernel/system/do_irqctl.c @@ -5,7 +5,8 @@ * m5_c1: IRQ_REQUEST (control operation to perform) * m5_c2: IRQ_VECTOR (irq line that must be controlled) * m5_i1: IRQ_POLICY (irq policy allows reenabling interrupts) - * m5_l3: IRQ_HOOK_ID (index of irq hook assigned at kernel) + * m5_l3: IRQ_HOOK_ID (provides index to be returned on interrupt) + * ,, ,, (returns index of irq hook assigned at kernel) * * Author: * Jorrit N. Herder @@ -13,8 +14,11 @@ #include "../system.h" + #if USE_IRQCTL +FORWARD _PROTOTYPE(int generic_handler, (irq_hook_t *hook)); + /*===========================================================================* * do_irqctl * *===========================================================================*/ @@ -99,5 +103,33 @@ register message *m_ptr; /* pointer to request message */ return(r); } + +/*===========================================================================* + * generic_handler * + *===========================================================================*/ +PRIVATE int generic_handler(hook) +irq_hook_t *hook; +{ +/* This function handles hardware interrupt in a simple and generic way. All + * interrupts are transformed into messages to a driver. The IRQ line will be + * reenabled if the policy says so. + */ + + /* As a side-effect, the interrupt handler gathers random information by + * timestamping the interrupt events. This is used for /dev/random. + */ + get_randomness(hook->irq); + + /* Add a bit for this interrupt to the process' pending interrupts. When + * sending the notification message, this bit map will be magically set + * as an argument. + */ + priv(proc_addr(hook->proc_nr))->s_int_pending |= (1 << hook->notify_id); + + /* Build notification message and return. */ + lock_notify(HARDWARE, hook->proc_nr); + return(hook->policy & IRQ_REENABLE); +} + #endif /* USE_IRQCTL */ diff --git a/kernel/system/do_kill.c b/kernel/system/do_kill.c index 9f8a248f4..442a0e4e8 100644 --- a/kernel/system/do_kill.c +++ b/kernel/system/do_kill.c @@ -30,6 +30,7 @@ message *m_ptr; /* pointer to request message */ int sig_nr = m_ptr->SIG_NUMBER; if (! isokprocn(proc_nr) || sig_nr > _NSIG) return(EINVAL); + if (iskerneln(proc_nr)) return(EPERM); if (m_ptr->m_source == PM_PROC_NR) { /* Directly send signal notification to a system process. */ diff --git a/kernel/system/do_memset.c b/kernel/system/do_memset.c index 360fdc410..0235c2e11 100644 --- a/kernel/system/do_memset.c +++ b/kernel/system/do_memset.c @@ -2,9 +2,9 @@ * m_type: SYS_MEMSET * * The parameters for this system call are: - * m1_p1: MEM_PTR (virtual address) - * m1_i1: MEM_COUNT (returns physical address) - * m1_i2: MEM_PATTERN (size of datastructure) + * m2_p1: MEM_PTR (virtual address) + * m2_l1: MEM_COUNT (returns physical address) + * m2_l2: MEM_PATTERN (size of datastructure) */ #include "../system.h" diff --git a/kernel/system/do_newmap.c b/kernel/system/do_newmap.c index 74048d9d6..c9d70ce7b 100644 --- a/kernel/system/do_newmap.c +++ b/kernel/system/do_newmap.c @@ -26,6 +26,7 @@ message *m_ptr; /* pointer to request message */ caller = m_ptr->m_source; map_ptr = (struct mem_map *) m_ptr->PR_MEM_PTR; if (! isokprocn(m_ptr->PR_PROC_NR)) return(EINVAL); + if (iskerneln(m_ptr->PR_PROC_NR)) return(EPERM); rp = proc_addr(m_ptr->PR_PROC_NR); /* Copy the map from PM. */ diff --git a/kernel/system/do_nice.c b/kernel/system/do_nice.c index eaa539e02..879ae32ff 100644 --- a/kernel/system/do_nice.c +++ b/kernel/system/do_nice.c @@ -23,6 +23,7 @@ PUBLIC int do_nice(message *m_ptr) /* Extract the message parameters and do sanity checking. */ proc_nr = m_ptr->PR_PROC_NR; if (! isokprocn(proc_nr)) return(EINVAL); + if (iskerneln(proc_nr)) return(EPERM); pri = m_ptr->PR_PRIORITY; if (pri < PRIO_MIN || pri > PRIO_MAX) return(EINVAL); diff --git a/kernel/system/do_privctl.c b/kernel/system/do_privctl.c index ed4835faa..0882569c8 100644 --- a/kernel/system/do_privctl.c +++ b/kernel/system/do_privctl.c @@ -33,7 +33,7 @@ message *m_ptr; /* pointer to request message */ /* Make sure this process has its own privileges structure. */ if (! (priv(rp)->s_flags & SYS_PROC)) - get_priv(rp, SYS_PROC); + if ((i=get_priv(rp, SYS_PROC)) != OK) return(i); /* Now update the process' privileges as requested. */ rp->p_priv->s_call_mask = FILLED_MASK; diff --git a/kernel/system/do_sdevio.c b/kernel/system/do_sdevio.c index 58ea4fd57..7ca526ddb 100644 --- a/kernel/system/do_sdevio.c +++ b/kernel/system/do_sdevio.c @@ -26,10 +26,13 @@ register message *m_ptr; /* pointer to request message */ long port = m_ptr->DIO_PORT; phys_bytes phys_buf; - /* Check if process number is OK. */ + /* Check if process number is OK. A process number is allowed here, because + * driver may directly provide a pointer to a buffer at the user-process + * that initiated the device I/O. Kernel processes, of course, are denied. + */ if (proc_nr == SELF) proc_nr = m_ptr->m_source; - if (! isokprocn(proc_nr)) - return(EINVAL); + if (! isokprocn(proc_nr)) return(EINVAL); + if (iskerneln(proc_nr)) return(EPERM); /* Get and check physical address. */ if ((phys_buf = numap_local(proc_nr, (vir_bytes) m_ptr->DIO_VEC_ADDR, count)) == 0) diff --git a/kernel/system/do_alarm.c b/kernel/system/do_setalarm.c similarity index 93% rename from kernel/system/do_alarm.c rename to kernel/system/do_setalarm.c index a57c00f1e..ac5ec61c1 100644 --- a/kernel/system/do_alarm.c +++ b/kernel/system/do_setalarm.c @@ -23,6 +23,7 @@ PUBLIC int do_setalarm(m_ptr) message *m_ptr; /* pointer to request message */ { /* A process requests a synchronous alarm, or wants to cancel its alarm. */ + register struct proc *rp; /* pointer to requesting process */ int proc_nr; /* which process wants the alarm */ long exp_time; /* expiration time for this alarm */ int use_abs_time; /* use absolute or relative time */ @@ -30,12 +31,14 @@ message *m_ptr; /* pointer to request message */ clock_t uptime; /* placeholder for current uptime */ /* Extract shared parameters from the request message. */ - proc_nr = m_ptr->m_source; /* process to interrupt later */ exp_time = m_ptr->ALRM_EXP_TIME; /* alarm's expiration time */ use_abs_time = m_ptr->ALRM_ABS_TIME; /* flag for absolute time */ + proc_nr = m_ptr->m_source; /* process to interrupt later */ + rp = proc_addr(proc_nr); + if (! (priv(rp)->s_flags & SYS_PROC)) return(EPERM); /* Get the timer structure and set the parameters for this alarm. */ - tp = &(proc_addr(proc_nr)->p_priv->s_alarm_timer); + tp = &(priv(rp)->s_alarm_timer); tmr_arg(tp)->ta_int = proc_nr; tp->tmr_func = cause_alarm; diff --git a/kernel/system/do_sigreturn.c b/kernel/system/do_sigreturn.c index 576240cce..b77fb2713 100644 --- a/kernel/system/do_sigreturn.c +++ b/kernel/system/do_sigreturn.c @@ -27,6 +27,8 @@ message *m_ptr; /* pointer to request message */ register struct proc *rp; phys_bytes src_phys; + if (! isokprocn(m_ptr->SIG_PROC)) return(EINVAL); + if (iskerneln(m_ptr->SIG_PROC)) return(EPERM); rp = proc_addr(m_ptr->SIG_PROC); /* Copy in the sigcontext structure. */ diff --git a/kernel/system/do_sigsend.c b/kernel/system/do_sigsend.c index 33bd85bad..f37048388 100644 --- a/kernel/system/do_sigsend.c +++ b/kernel/system/do_sigsend.c @@ -29,6 +29,8 @@ message *m_ptr; /* pointer to request message */ struct sigcontext sc, *scp; struct sigframe fr, *frp; + if (! isokprocn(m_ptr->SIG_PROC)) return(EINVAL); + if (iskerneln(m_ptr->SIG_PROC)) return(EPERM); rp = proc_addr(m_ptr->SIG_PROC); /* Get the sigmsg structure into our address space. */ diff --git a/kernel/system/do_trace.c b/kernel/system/do_trace.c index 4f559f3b5..278ce9bd5 100644 --- a/kernel/system/do_trace.c +++ b/kernel/system/do_trace.c @@ -47,6 +47,9 @@ register message *m_ptr; int tr_proc_nr = m_ptr->CTL_PROC_NR; int i; + if (! isokprocn(tr_proc_nr)) return(EINVAL); + if (iskerneln(tr_proc_nr)) return(EPERM); + rp = proc_addr(tr_proc_nr); if (isemptyp(rp)) return(EIO); switch (tr_request) { diff --git a/kernel/system/do_vcopy.c b/kernel/system/do_vcopy.c index 26323afd6..47260cfc5 100644 --- a/kernel/system/do_vcopy.c +++ b/kernel/system/do_vcopy.c @@ -2,13 +2,9 @@ * m_type: SYS_VIRVCOPY, SYS_PHYSVCOPY * * The parameters for this system call are: - * m5_c1: CP_SRC_SPACE - * m5_l1: CP_SRC_ADDR - * m5_i1: CP_SRC_PROC_NR - * m5_c2: CP_DST_SPACE - * m5_l2: CP_DST_ADDR - * m5_i2: CP_DST_PROC_NR - * m5_l3: CP_NR_BYTES + * m1_i3: VCP_VEC_SIZE size of copy request vector + * m1_p1: VCP_VEC_ADDR address of vector at caller + * m1_i2: VCP_NR_OK number of successfull copies */ #include "../system.h" @@ -52,16 +48,17 @@ register message *m_ptr; /* pointer to request message */ phys_copy(caller_phys, kernel_phys, (phys_bytes) bytes); /* Assume vector with requests is correct. Try to copy everything. */ + m_ptr->VCP_NR_OK = 0; for (i=0; isrc.segment | req->dst.segment) & PHYS_SEG) && - m_ptr->m_type != SYS_PHYSVCOPY) - return(EPERM); + m_ptr->m_type != SYS_PHYSVCOPY) return(EPERM); if ((s=virtual_copy(&req->src, &req->dst, req->count)) != OK) return(s); + m_ptr->VCP_NR_OK ++; } return(OK); } diff --git a/kernel/system/do_vdevio.c b/kernel/system/do_vdevio.c index 9c455fcb6..dfc4a6405 100644 --- a/kernel/system/do_vdevio.c +++ b/kernel/system/do_vdevio.c @@ -14,16 +14,11 @@ #if USE_VDEVIO /* Buffer for SYS_VDEVIO to copy (port,value)-pairs from/ to user. */ -PRIVATE char vdevio_pv_buf[VDEVIO_BUF_SIZE]; +PRIVATE char vdevio_buf[VDEVIO_BUF_SIZE]; +PRIVATE pvb_pair_t *pvb = (pvb_pair_t *) vdevio_buf; +PRIVATE pvw_pair_t *pvw = (pvw_pair_t *) vdevio_buf; +PRIVATE pvl_pair_t *pvl = (pvl_pair_t *) vdevio_buf; -/* SYS_VDEVIO sends a pointer to a (port,value)-pairs vector at the caller. - * Define the maximum number of (port,value)-pairs that can be handled in a - * in a single SYS_VDEVIO system call based on the struct definitions. - */ -#define MAX_PVB_PAIRS ((VDEVIO_BUF_SIZE * sizeof(char)) / sizeof(pvb_pair_t)) -#define MAX_PVW_PAIRS ((VDEVIO_BUF_SIZE * sizeof(char)) / sizeof(pvw_pair_t)) -#define MAX_PVL_PAIRS ((VDEVIO_BUF_SIZE * sizeof(char)) / sizeof(pvl_pair_t)) - /*===========================================================================* * do_vdevio * @@ -37,88 +32,57 @@ register message *m_ptr; /* pointer to request message */ * that I/O batch from being interrrupted. * This is the counterpart of do_devio, which performs a single device I/O. */ - pvb_pair_t *pvb_pairs; /* needed for byte values */ - pvw_pair_t *pvw_pairs; /* needed for word values */ - pvl_pair_t *pvl_pairs; /* needed for long values */ - int i; - int caller_proc; /* process number of caller */ - size_t bytes; /* # bytes to be copied */ - vir_bytes caller_vir; /* virtual address at caller */ - phys_bytes caller_phys; /* physical address at caller */ - phys_bytes kernel_phys; /* physical address in kernel */ - - - /* Check if nr of ports is ok and get size of (port,value) data. */ - if (m_ptr->DIO_VEC_SIZE <= 0) return(EINVAL); - switch(m_ptr->DIO_TYPE) { - case DIO_BYTE: - if (m_ptr->DIO_VEC_SIZE > MAX_PVB_PAIRS) return(EINVAL); - bytes = (size_t) (m_ptr->DIO_VEC_SIZE * sizeof(pvb_pair_t)); - break; - case DIO_WORD: - if (m_ptr->DIO_VEC_SIZE > MAX_PVW_PAIRS) return(EINVAL); - bytes = (size_t) (m_ptr->DIO_VEC_SIZE * sizeof(pvw_pair_t)); - break; - case DIO_LONG: - if (m_ptr->DIO_VEC_SIZE > MAX_PVL_PAIRS) return(EINVAL); - bytes = (size_t) (m_ptr->DIO_VEC_SIZE * sizeof(pvl_pair_t)); - break; - default: /* this once and for all checks for a correct type */ - return(EINVAL); - } + int vec_size; /* size of vector */ + int io_in; /* true if input */ + size_t bytes; /* # bytes to be copied */ + int caller_proc; /* process number of caller */ + vir_bytes caller_vir; /* virtual address at caller */ + phys_bytes caller_phys; /* physical address at caller */ + int i; + + /* Get the request, size of the request vector, and check the values. */ + if (m_ptr->DIO_REQUEST == DIO_INPUT) io_in = TRUE; + else if (m_ptr->DIO_REQUEST == DIO_OUTPUT) io_in = FALSE; + else return(EINVAL); + if ((vec_size = m_ptr->DIO_VEC_SIZE) <= 0) return(EINVAL); + switch (m_ptr->DIO_TYPE) { + case DIO_BYTE: bytes = vec_size * sizeof(pvb_pair_t); break; + case DIO_WORD: bytes = vec_size * sizeof(pvw_pair_t); break; + case DIO_LONG: bytes = vec_size * sizeof(pvl_pair_t); break; + default: return(EINVAL); /* check type once and for all */ + } + if (bytes > sizeof(vdevio_buf)) return(E2BIG); - /* Calculate physical addresses and copy (port,value)-pairs from user. */ - caller_proc = m_ptr->m_source; - caller_vir = (vir_bytes) m_ptr->DIO_VEC_ADDR; - caller_phys = umap_local(proc_addr(caller_proc), D, caller_vir, bytes); - if (0 == caller_phys) return EFAULT; - kernel_phys = vir2phys(vdevio_pv_buf); - phys_copy(caller_phys, kernel_phys, (phys_bytes) bytes); + /* Calculate physical addresses and copy (port,value)-pairs from user. */ + caller_proc = m_ptr->m_source; + caller_vir = (vir_bytes) m_ptr->DIO_VEC_ADDR; + caller_phys = umap_local(proc_addr(caller_proc), D, caller_vir, bytes); + if (0 == caller_phys) return(EFAULT); + phys_copy(caller_phys, vir2phys(vdevio_buf), (phys_bytes) bytes); - /* Perform actual device I/O for byte, word, and long values. Note that - * the entire switch is wrapped in lock() and unlock() to prevent the I/O - * batch from being interrupted. It may be cleaner to do this just around - * the for loops, but this results in rather lenghty code. - */ - lock(13, "do_vdevio"); - switch (m_ptr->DIO_TYPE) { - case DIO_BYTE: /* byte values */ - pvb_pairs = (pvb_pair_t *) vdevio_pv_buf; - if (DIO_INPUT == m_ptr->DIO_REQUEST) { - for (i=0; i < m_ptr->DIO_VEC_SIZE; i++) - pvb_pairs[i].value = inb(pvb_pairs[i].port); - } else { - for (i=0; i < m_ptr->DIO_VEC_SIZE; i++) - outb(pvb_pairs[i].port, pvb_pairs[i].value); - } - break; - case DIO_WORD: /* word values */ - pvw_pairs = (pvw_pair_t *) vdevio_pv_buf; - if (DIO_INPUT == m_ptr->DIO_REQUEST) { - for (i=0; i < m_ptr->DIO_VEC_SIZE; i++) - pvw_pairs[i].value = inw(pvw_pairs[i].port); - } else { - for (i=0; i < m_ptr->DIO_VEC_SIZE; i++) - outw(pvw_pairs[i].port, pvw_pairs[i].value); - } - break; - case DIO_LONG: /* fall through: long values */ - default: /* only DIO_LONG can arrive here, see above switch */ - pvl_pairs = (pvl_pair_t *) vdevio_pv_buf; - if (DIO_INPUT == m_ptr->DIO_REQUEST) { - for (i=0; i < m_ptr->DIO_VEC_SIZE; i++) - pvl_pairs[i].value = inl(pvl_pairs[i].port); - } else { - for (i=0; i < m_ptr->DIO_VEC_SIZE; i++) - outl(pvb_pairs[i].port, pvl_pairs[i].value); - } - } - unlock(13); + /* Perform actual device I/O for byte, word, and long values. Note that + * the entire switch is wrapped in lock() and unlock() to prevent the I/O + * batch from being interrupted. + */ + lock(13, "do_vdevio"); + switch (m_ptr->DIO_TYPE) { + case DIO_BYTE: /* byte values */ + if (io_in) for (i=0; iREQUEST) - phys_copy(kernel_phys, caller_phys, (phys_bytes) bytes); - return(OK); + /* Almost done, copy back results for input requests. */ + if (io_in) phys_copy(vir2phys(vdevio_buf), caller_phys, (phys_bytes) bytes); + return(OK); } #endif /* USE_VDEVIO */ diff --git a/kernel/table.c b/kernel/table.c index c11ed4982..7aad53114 100755 --- a/kernel/table.c +++ b/kernel/table.c @@ -19,7 +19,7 @@ * or PRIVATE. The reason for this is that extern variables cannot have a * default initialization. If such variables are shared, they must also be * declared in one of the *.h files without the initialization. Examples - * include 'system_image' (this file) and 'idt' and 'gdt' (protect.c). + * include 'boot_image' (this file) and 'idt' and 'gdt' (protect.c). * * Changes: * Nov 10, 2004 removed controller->driver mappings (Jorrit N. Herder) @@ -68,10 +68,10 @@ PUBLIC char *t_stack[TOT_STACK_SPACE / sizeof(char *)]; #define USER_T 8 /* ticks */ #define SYS_T 16 /* ticks */ -PUBLIC struct system_image image[] = { +PUBLIC struct boot_image image[] = { { IDLE, idle_task, IDLE_F, IDLE_T, IDLE_Q, IDLE_S, EMPTY_MASK, EMPTY_MASK, "IDLE" }, - { CLOCK, clock_task, TASK_F, SYS_T, TASK_Q, CLOCK_S, FILLED_MASK, SYSTEM_SEND_MASK, "CLOCK" }, - { SYSTEM, sys_task, TASK_F, SYS_T, TASK_Q, SYSTEM_S, FILLED_MASK, SYSTEM_SEND_MASK, "SYSTEM" }, + { CLOCK, clock_task, TASK_F, SYS_T, TASK_Q, CLOCK_S, TASK_CALL_MASK, SYSTEM_SEND_MASK, "CLOCK" }, + { SYSTEM, sys_task, TASK_F, SYS_T, TASK_Q, SYSTEM_S, TASK_CALL_MASK, SYSTEM_SEND_MASK, "SYSTEM" }, { HARDWARE, 0, TASK_F, SYS_T, TASK_Q, HARDWARE_S, EMPTY_MASK, SYSTEM_SEND_MASK, "KERNEL" }, { PM_PROC_NR, 0, SYS_F, SYS_T, 3, 0, FILLED_MASK, SERVER_SEND_MASK, "PM" }, { FS_PROC_NR, 0, SYS_F, SYS_T, 4, 0, FILLED_MASK, SERVER_SEND_MASK, "FS" }, @@ -111,5 +111,5 @@ PUBLIC struct system_image image[] = { * a compile time error. Note that no space is allocated because 'dummy' is * declared extern. */ -extern int dummy[(NR_BOOT_PROCS==sizeof(image)/sizeof(struct system_image))?1:-1]; +extern int dummy[(NR_BOOT_PROCS==sizeof(image)/sizeof(struct boot_image))?1:-1]; diff --git a/kernel/type.h b/kernel/type.h index 4d9a8890a..5db894229 100755 --- a/kernel/type.h +++ b/kernel/type.h @@ -10,7 +10,7 @@ typedef struct { /* bitmap for system indexes */ bitchunk_t chunk[BITMAP_CHUNKS(NR_SYS_PROCS)]; } sys_map_t; -struct system_image { +struct boot_image { proc_nr_t proc_nr; /* process number to use */ task_t *initial_pc; /* start function for tasks */ int flags; /* process flags */