点击(此处)折叠或打开
- PUBLIC int do_ipc(reg_t r1, reg_t r2, reg_t r3)
- {
- struct proc *const caller_ptr = get_cpulocal_var(proc_ptr); /* get pointer to caller */
- int call_nr = (int) r1;
- assert(!RTS_ISSET(caller_ptr, RTS_SLOT_FREE));
- /* bill kernel time to this process. */
- kbill_ipc = caller_ptr;
- /* 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);
- }
- /* 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:
- {
- /* Process accounting for scheduling */
- caller_ptr->p_accounting.ipc_sync++;
- 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;
-
- /* Process accounting for scheduling */
- caller_ptr->p_accounting.ipc_async++;
-
- /* 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 */
- }
- }
点击(此处)折叠或打开
- PRIVATE 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 */
- char *callname;
- /* 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.
- */
- assert(call_nr != SENDA);
- /* Only allow non-negative call_nr values less than 32 */
- if (call_nr < 0 || call_nr > IPCNO_HIGHEST || call_nr >= 32
- || !(callname = ipc_call_names[call_nr])) {
- #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_p);
- #endif
- return(ETRAPDENIED); /* trap denied by mask or kernel */
- }
- if (src_dst_e == ANY)
- {
- if (call_nr != RECEIVE)
- {
- #if 0
- printf("sys_call: %s by %d with bad endpoint %d\n",
- callname,
- proc_nr(caller_ptr), src_dst_e);
- #endif
- return EINVAL;
- }
- src_dst_p = (int) src_dst_e;
- }
- else
- {
- /* Require a valid source and/or destination process. */
- if(!isokendpt(src_dst_e, &src_dst_p)) {
- #if 0
- printf("sys_call: %s by %d with bad endpoint %d\n",
- callname,
- proc_nr(caller_ptr), src_dst_e);
- #endif
- return EDEADSRCDST;
- }
- /* If the call is to send to a process, i.e., for SEND, SENDNB,
- * SENDREC or NOTIFY, verify that the caller is allowed to send to
- * the given destination.
- */
- if (call_nr != RECEIVE)
- {
- if (!may_send_to(caller_ptr, src_dst_p)) {
- #if DEBUG_ENABLE_IPC_WARNINGS
- printf(
- "sys_call: ipc mask denied %s from %d to %d\n",
- callname,
- caller_ptr->p_endpoint, src_dst_e);
- #endif
- return(ECALLDENIED); /* call denied by ipc mask */
- }
- }
- }
- /* Check if the process has privileges for the requested call. Calls to the
- * kernel may only be SENDREC, because tasks always reply and may not block
- * if the caller doesn't do receive().
- */
- if (!(priv(caller_ptr)->s_trap_mask & (1 << call_nr))) {
- #if DEBUG_ENABLE_IPC_WARNINGS
- printf("sys_call: %s not allowed, caller %d, src_dst %d\n",
- callname, proc_nr(caller_ptr), src_dst_p);
- #endif
- return(ETRAPDENIED); /* trap denied by mask or kernel */
- }
- if (call_nr != SENDREC && call_nr != RECEIVE && iskerneln(src_dst_p)) {
- #if DEBUG_ENABLE_IPC_WARNINGS
- printf("sys_call: trap %s not allowed, caller %d, src_dst %d\n",
- callname, proc_nr(caller_ptr), src_dst_e);
- #endif
- return(ETRAPDENIED); /* trap denied by mask or kernel */
- }
- switch(call_nr) {
- case SENDREC:
- /* A flag is set so that notifications cannot interrupt SENDREC. */
- caller_ptr->p_misc_flags |= MF_REPLY_PEND;
- /* fall through */
- case SEND:
- result = mini_send(caller_ptr, src_dst_e, m_ptr, 0);
- if (call_nr == SEND || result != OK)
- break; /* done, or SEND failed */
- /* fall through for SENDREC */
- case RECEIVE:
- if (call_nr == RECEIVE) {
- caller_ptr->p_misc_flags &= ~MF_REPLY_PEND;
- IPC_STATUS_CLEAR(caller_ptr); /* clear IPC status code */
- }
- result = mini_receive(caller_ptr, src_dst_e, m_ptr, 0);
- break;
- case NOTIFY:
- result = mini_notify(caller_ptr, src_dst_e);
- break;
- case SENDNB:
- result = mini_send(caller_ptr, src_dst_e, m_ptr, NON_BLOCKING);
- break;
- default:
- result = EBADCALL; /* illegal system call */
- }
- /* Now, return the result of the system call to the caller. */
- return(result);
- }
点击(此处)折叠或打开
- /*===========================================================================*
- * mini_send *
- *===========================================================================*/
- PUBLIC int mini_send(
- register struct proc *caller_ptr, /* who is trying to send a message? */
- endpoint_t dst_e, /* to whom is message being sent? */
- message *m_ptr, /* pointer to message buffer */
- const int flags
- )
- {
- /* Send a message from 'caller_ptr' to 'dst'. If 'dst' is blocked waiting
- * for this message, copy the message to it and unblock 'dst'. If 'dst' is
- * not waiting at all, or is waiting for another source, queue 'caller_ptr'.
- */
- register struct proc *dst_ptr;
- register struct proc **xpp;
- int dst_p;
- dst_p = _ENDPOINT_P(dst_e);
- dst_ptr = proc_addr(dst_p);
- if (RTS_ISSET(dst_ptr, RTS_NO_ENDPOINT))
- {
- return EDEADSRCDST;
- }
- /* Check if 'dst' is blocked waiting for this message. The destination's
- * RTS_SENDING flag may be set when its SENDREC call blocked while sending.
- */
- if (WILLRECEIVE(dst_ptr, caller_ptr->p_endpoint)) {
- int call;
- /* Destination is indeed waiting for this message. */
- assert(!(dst_ptr->p_misc_flags & MF_DELIVERMSG));
- if (!(flags & FROM_KERNEL)) {
- if(copy_msg_from_user(caller_ptr, m_ptr, &dst_ptr->p_delivermsg))
- return EFAULT;
- } else {
- dst_ptr->p_delivermsg = *m_ptr;
- IPC_STATUS_ADD_FLAGS(dst_ptr, IPC_FLG_MSG_FROM_KERNEL);
- }
- dst_ptr->p_delivermsg.m_source = caller_ptr->p_endpoint;
- dst_ptr->p_misc_flags |= MF_DELIVERMSG;
- call = (caller_ptr->p_misc_flags & MF_REPLY_PEND ? SENDREC
- : (flags & NON_BLOCKING ? SENDNB : SEND));
- IPC_STATUS_ADD_CALL(dst_ptr, call);
- if (dst_ptr->p_misc_flags & MF_REPLY_PEND)
- dst_ptr->p_misc_flags &= ~MF_REPLY_PEND;
- RTS_UNSET(dst_ptr, RTS_RECEIVING)