diff --git a/kernel/arch/i386/arch_system.c b/kernel/arch/i386/arch_system.c index 91bc629a7..486785d4f 100644 --- a/kernel/arch/i386/arch_system.c +++ b/kernel/arch/i386/arch_system.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "archconst.h" #include "proto.h" @@ -455,20 +456,11 @@ PUBLIC int arch_set_params(char *params, int size) PUBLIC void arch_do_syscall(struct proc *proc) { -/* Perform a previously postponed system call. - */ - int call_nr, src_dst_e; - message *m_ptr; - long bit_map; - - /* Get the system call parameters from their respective registers. */ - call_nr = proc->p_reg.cx; - src_dst_e = proc->p_reg.retreg; - m_ptr = (message *) proc->p_reg.bx; - bit_map = proc->p_reg.dx; - + /* do_ipc assumes that it's running because of the current process */ + assert(proc == proc_ptr); /* Make the system call, for real this time. */ - proc->p_reg.retreg = do_ipc(call_nr, src_dst_e, m_ptr, bit_map); + proc->p_reg.retreg = + do_ipc(proc->p_reg.cx, proc->p_reg.retreg, proc->p_reg.bx); } PUBLIC struct proc * arch_finish_schedcheck(void) diff --git a/kernel/arch/i386/mpx.S b/kernel/arch/i386/mpx.S index 4a98d84bf..f441d79af 100644 --- a/kernel/arch/i386/mpx.S +++ b/kernel/arch/i386/mpx.S @@ -396,7 +396,6 @@ ipc_entry: * SAVE_PROCESS_CTX() does not clobber these registers, they are still * set as the userspace have set them */ - push %edx push %ebx push %eax push %ecx @@ -412,7 +411,7 @@ ipc_entry: call do_ipc /* restore the current process pointer and save the return value */ - add $4 * 4, %esp + add $3 * 4, %esp pop %esi mov %eax, AXREG(%esi) diff --git a/kernel/proc.c b/kernel/proc.c index 69b90213a..3a143aa9b 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -240,74 +240,25 @@ check_misc_flags: return proc_ptr; } -/*===========================================================================* - * sys_call * - *===========================================================================*/ -PUBLIC int do_ipc(call_nr, src_dst_e, m_ptr, bit_map) -int call_nr; /* system call number and flags */ -endpoint_t src_dst_e; /* src to receive from or dst to send to */ -message *m_ptr; /* pointer to message in the caller's space */ -long bit_map; /* notification event set or flags */ -{ -/* System calls are done by trapping to the kernel with an INT instruction. - * The trap is caught and sys_call() is called to send or receive a message - * (or both). The caller is always given by 'proc_ptr'. +/* + * handler for all synchronous IPC callsi */ - struct proc *const caller_ptr = proc_ptr; /* get pointer to caller */ +PUBLIC int do_sync_ipc(struct proc * caller_ptr, /* who made the call */ + int call_nr, /* system call number and flags */ + endpoint_t src_dst_e, /* src or dst of the call */ + message *m_ptr) /* users pointer to a message */ +{ int result; /* the system call's result */ int src_dst_p; /* Process slot number */ - size_t msg_size; - assert(!RTS_ISSET(caller_ptr, RTS_SLOT_FREE)); - - /* If this process is subject to system call tracing, handle that first. */ - if (caller_ptr->p_misc_flags & (MF_SC_TRACE | MF_SC_DEFER)) { - /* Are we tracing this process, and is it the first sys_call entry? */ - if ((caller_ptr->p_misc_flags & (MF_SC_TRACE | MF_SC_DEFER)) == - MF_SC_TRACE) { - /* We must notify the tracer before processing the actual - * system call. If we don't, the tracer could not obtain the - * input message. Postpone the entire system call. - */ - caller_ptr->p_misc_flags &= ~MF_SC_TRACE; - caller_ptr->p_misc_flags |= MF_SC_DEFER; - - /* Signal the "enter system call" event. Block the process. */ - cause_sig(proc_nr(caller_ptr), SIGTRAP); - - /* Preserve the return register's value. */ - return caller_ptr->p_reg.retreg; - } - - /* If the MF_SC_DEFER flag is set, the syscall is now being resumed. */ - caller_ptr->p_misc_flags &= ~MF_SC_DEFER; - - assert (!(caller_ptr->p_misc_flags & MF_SC_ACTIVE)); - - /* Set a flag to allow reliable tracing of leaving the system call. */ - caller_ptr->p_misc_flags |= MF_SC_ACTIVE; - } - - if(caller_ptr->p_misc_flags & MF_DELIVERMSG) { - panic("sys_call: MF_DELIVERMSG on for %s / %d\n", - caller_ptr->p_name, caller_ptr->p_endpoint); - } - - /* Clear IPC status code. */ - IPC_STATUS_CLEAR(caller_ptr); - - /* Check destination. SENDA is special because its argument is a table and - * not a single destination. RECEIVE is the only call that accepts ANY (in - * addition to a real endpoint). The other calls (SEND, SENDREC, - * and NOTIFY) require an endpoint to corresponds to a process. In addition, - * it is necessary to check whether a process is allowed to send to a given - * destination. + /* Check destination. RECEIVE is the only call that accepts ANY (in addition + * to a real endpoint). The other calls (SEND, SENDREC, and NOTIFY) require an + * endpoint to corresponds to a process. In addition, it is necessary to check + * whether a process is allowed to send to a given destination. */ - if (call_nr == SENDA) - { - /* No destination argument */ - } - else if (src_dst_e == ANY) + assert(call_nr != SENDA); + + if (src_dst_e == ANY) { if (call_nr != RECEIVE) { @@ -317,7 +268,7 @@ long bit_map; /* notification event set or flags */ #endif return EINVAL; } - src_dst_p = src_dst_e; + src_dst_p = (int) src_dst_e; } else { @@ -369,10 +320,7 @@ long bit_map; /* notification event set or flags */ return(ETRAPDENIED); /* trap denied by mask or kernel */ } - /* SENDA has no src_dst value here, so this check is in mini_senda() as well. - */ - if (call_nr != SENDREC && call_nr != RECEIVE && call_nr != SENDA && - iskerneln(src_dst_p)) { + if (call_nr != SENDREC && call_nr != RECEIVE && iskerneln(src_dst_p)) { #if DEBUG_ENABLE_IPC_WARNINGS printf("sys_call: trap %d not allowed, caller %d, src_dst %d\n", call_nr, proc_nr(caller_ptr), src_dst_e); @@ -380,31 +328,6 @@ long bit_map; /* notification event set or flags */ return(ETRAPDENIED); /* trap denied by mask or kernel */ } - /* Get and check the size of the argument in bytes. - * Normally this is just the size of a regular message, but in the - * case of SENDA the argument is a table. - */ - if(call_nr == SENDA) { - msg_size = (size_t) src_dst_e; - - /* Limit size to something reasonable. An arbitrary choice is 16 - * times the number of process table entries. - */ - if (msg_size > 16*(NR_TASKS + NR_PROCS)) - return EDOM; - msg_size *= sizeof(asynmsg_t); /* convert to bytes */ - } else { - msg_size = sizeof(*m_ptr); - } - - /* Now check if the call is known and try to perform the request. The only - * system calls that exist in MINIX are sending and receiving messages. - * - SENDREC: combines SEND and RECEIVE in a single system call - * - SEND: sender blocks until its message has been delivered - * - RECEIVE: receiver blocks until an acceptable message has arrived - * - NOTIFY: asynchronous call; deliver notification or mark pending - * - SENDA: list of asynchronous send requests - */ switch(call_nr) { case SENDREC: /* A flag is set so that notifications cannot interrupt SENDREC. */ @@ -426,9 +349,6 @@ long bit_map; /* notification event set or flags */ case SENDNB: result = mini_send(caller_ptr, src_dst_e, m_ptr, NON_BLOCKING); break; - case SENDA: - result = mini_senda(caller_ptr, (asynmsg_t *)m_ptr, (size_t)src_dst_e); - break; default: result = EBADCALL; /* illegal system call */ } @@ -437,6 +357,85 @@ long bit_map; /* notification event set or flags */ return(result); } +PUBLIC int do_ipc(reg_t r1, reg_t r2, reg_t r3) +{ + struct proc * caller_ptr = proc_ptr; /* always the current process */ + int call_nr = (int) r1; + + assert(!RTS_ISSET(caller_ptr, RTS_SLOT_FREE)); + + /* If this process is subject to system call tracing, handle that first. */ + if (caller_ptr->p_misc_flags & (MF_SC_TRACE | MF_SC_DEFER)) { + /* Are we tracing this process, and is it the first sys_call entry? */ + if ((caller_ptr->p_misc_flags & (MF_SC_TRACE | MF_SC_DEFER)) == + MF_SC_TRACE) { + /* We must notify the tracer before processing the actual + * system call. If we don't, the tracer could not obtain the + * input message. Postpone the entire system call. + */ + caller_ptr->p_misc_flags &= ~MF_SC_TRACE; + caller_ptr->p_misc_flags |= MF_SC_DEFER; + + /* Signal the "enter system call" event. Block the process. */ + cause_sig(proc_nr(caller_ptr), SIGTRAP); + + /* Preserve the return register's value. */ + return caller_ptr->p_reg.retreg; + } + + /* If the MF_SC_DEFER flag is set, the syscall is now being resumed. */ + caller_ptr->p_misc_flags &= ~MF_SC_DEFER; + + assert (!(caller_ptr->p_misc_flags & MF_SC_ACTIVE)); + + /* Set a flag to allow reliable tracing of leaving the system call. */ + caller_ptr->p_misc_flags |= MF_SC_ACTIVE; + } + + if(caller_ptr->p_misc_flags & MF_DELIVERMSG) { + panic("sys_call: MF_DELIVERMSG on for %s / %d\n", + caller_ptr->p_name, caller_ptr->p_endpoint); + } + + /* Clear IPC status code. */ + IPC_STATUS_CLEAR(caller_ptr); + + /* Now check if the call is known and try to perform the request. The only + * system calls that exist in MINIX are sending and receiving messages. + * - SENDREC: combines SEND and RECEIVE in a single system call + * - SEND: sender blocks until its message has been delivered + * - RECEIVE: receiver blocks until an acceptable message has arrived + * - NOTIFY: asynchronous call; deliver notification or mark pending + * - SENDA: list of asynchronous send requests + */ + switch(call_nr) { + case SENDREC: + case SEND: + case RECEIVE: + case NOTIFY: + case SENDNB: + return do_sync_ipc(caller_ptr, call_nr, (endpoint_t) r2, + (message *) r3); + case SENDA: + { + /* + * Get and check the size of the argument in bytes as it is a + * table + */ + size_t msg_size = (size_t) r2; + + /* Limit size to something reasonable. An arbitrary choice is 16 + * times the number of process table entries. + */ + if (msg_size > 16*(NR_TASKS + NR_PROCS)) + return EDOM; + return mini_senda(caller_ptr, (asynmsg_t *) r3, msg_size); + } + default: + return EBADCALL; /* illegal system call */ + } +} + /*===========================================================================* * deadlock * *===========================================================================*/ diff --git a/kernel/proto.h b/kernel/proto.h index 8a0040e4f..58fed5f6e 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -35,8 +35,8 @@ _PROTOTYPE( void prepare_shutdown, (int how) ); _PROTOTYPE( void minix_shutdown, (struct timer *tp) ); /* proc.c */ -_PROTOTYPE( int do_ipc, (int call_nr, endpoint_t src_dst, - message *m_ptr, long bit_map) ); + +_PROTOTYPE( int do_ipc, (reg_t r1, reg_t r2, reg_t r3) ); _PROTOTYPE( int mini_notify, (const struct proc *src, endpoint_t dst) ); _PROTOTYPE( void enqueue, (struct proc *rp) ); _PROTOTYPE( void dequeue, (const struct proc *rp) );