From a774cc832fe0b622622fea0fcf7518159856cb51 Mon Sep 17 00:00:00 2001 From: Tomas Hruby Date: Tue, 6 Apr 2010 11:24:26 +0000 Subject: [PATCH] do_ipc() rearrangements this patch does not add or change any functionality of do_ipc(), it only makes things a little cleaner (hopefully). Until now do_ipc() was responsible for handling all ipc calls. The catch is that SENDA is fairly different which results in some ugly code like this typecasting and variables naming which does not make much sense for SENDA and makes the code hard to read. result = mini_senda(caller_ptr, (asynmsg_t *)m_ptr, (size_t)src_dst_e); As it is called directly from assembly, the new do_ipc() takes as input values of 3 registers in reg_t variables (it used to be 4, however, bit_map wasn't used so I removed it), does the checks common to all ipc calls and call the appropriate handler either for do_sync_ipc() (all except SENDA) or mini_senda() (for SENDA) while typecasting the reg_t values correctly. As a result, handling SENDA differences in do_sync_ipc() is no more needed. Also the code that uses msg_size variable is improved a little bit. arch_do_syscall() is simplified too. --- kernel/arch/i386/arch_system.c | 18 +--- kernel/arch/i386/mpx.S | 3 +- kernel/proc.c | 191 ++++++++++++++++----------------- kernel/proto.h | 4 +- 4 files changed, 103 insertions(+), 113 deletions(-) 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) );