]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/dev/i386/systemcalls.c
xnu-2782.1.97.tar.gz
[apple/xnu.git] / bsd / dev / i386 / systemcalls.c
index 77ecfba3a70c91585faafe684d09ad953578ebb7..8b2c8ab98f2ba24b17cdcb9999aee9d491cf4c25 100644 (file)
@@ -69,15 +69,6 @@ extern void *find_user_regs(thread_t);
 /* dynamically generated at build time based on syscalls.master */
 extern const char *syscallnames[];
 
-/*
- * This needs to be a single switch so that it's "all on" or "all off",
- * rather than being turned on for some code paths and not others, as this
- * has a tendency to introduce "blame the next guy" bugs.
- */
-#if DEBUG
-#define        FUNNEL_DEBUG    1       /* Check for funnel held on exit */
-#endif
-
 /*
  * Function:   unix_syscall
  *
@@ -141,10 +132,13 @@ unix_syscall(x86_saved_state_t *state)
        }
 
        vt = (void *)uthread->uu_arg;
-       uthread->uu_ap = vt;
 
        if (callp->sy_arg_bytes != 0) {
+#if CONFIG_REQUIRES_U32_MUNGING
                sy_munge_t      *mungerp;
+#else
+#error U32 syscalls on x86_64 kernel requires munging
+#endif
                uint32_t         nargs;
 
                assert((unsigned) callp->sy_arg_bytes <= sizeof (uthread->uu_arg));
@@ -164,17 +158,13 @@ unix_syscall(x86_saved_state_t *state)
                                BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
                                *ip, *(ip+1), *(ip+2), *(ip+3), 0);
                }
+
+#if CONFIG_REQUIRES_U32_MUNGING
                mungerp = callp->sy_arg_munge32;
 
-               /*
-                * If non-NULL, then call the syscall argument munger to
-                * copy in arguments (see xnu/bsd/dev/{i386|x86_64}/munge.s); the
-                * first argument is NULL because we are munging in place
-                * after a copyin because the ABI currently doesn't use
-                * registers to pass system call arguments.
-                */
                if (mungerp != NULL)
-                       (*mungerp)(NULL, vt);
+                       (*mungerp)(vt);
+#endif
        } else
                KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, 
                        BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
@@ -187,9 +177,9 @@ unix_syscall(x86_saved_state_t *state)
        kauth_cred_uthread_update(uthread, p);
 
        uthread->uu_rval[0] = 0;
-       uthread->uu_rval[1] = regs->edx;
+       uthread->uu_rval[1] = 0;
        uthread->uu_flag |= UT_NOTCANCELPT;
-
+       uthread->syscall_code = code;
 
 #ifdef JOE_DEBUG
         uthread->uu_iocount = 0;
@@ -198,7 +188,7 @@ unix_syscall(x86_saved_state_t *state)
 
        AUDIT_SYSCALL_ENTER(code, p, uthread);
        error = (*(callp->sy_call))((void *) p, (void *) vt, &(uthread->uu_rval[0]));
-        AUDIT_SYSCALL_EXIT(code, p, uthread, error);
+       AUDIT_SYSCALL_EXIT(code, p, uthread, error);
 
 #ifdef JOE_DEBUG
         if (uthread->uu_iocount)
@@ -223,6 +213,11 @@ unix_syscall(x86_saved_state_t *state)
                    regs->eax = error;
                    regs->efl |= EFL_CF;        /* carry bit */
                } else { /* (not error) */
+                       /*
+                        * We split retval across two registers, in case the
+                        * syscall had a 64-bit return value, in which case
+                        * eax/edx matches the function call ABI.
+                        */
                    regs->eax = uthread->uu_rval[0];
                    regs->edx = uthread->uu_rval[1];
                } 
@@ -233,12 +228,6 @@ unix_syscall(x86_saved_state_t *state)
                error, regs->eax, regs->edx);
 
        uthread->uu_flag &= ~UT_NOTCANCELPT;
-#if FUNNEL_DEBUG
-       /*
-        * if we're holding the funnel panic
-        */
-       syscall_exit_funnelcheck();
-#endif /* FUNNEL_DEBUG */
 
        if (__improbable(uthread->uu_lowpri_window)) {
                /*
@@ -268,10 +257,11 @@ void
 unix_syscall64(x86_saved_state_t *state)
 {
        thread_t        thread;
+       void                    *vt;
        unsigned int    code;
        struct sysent   *callp;
-       void            *uargp;
        int             args_in_regs;
+       boolean_t       args_start_at_rdi;
        int             error;
        struct proc     *p;
        struct uthread  *uthread;
@@ -300,43 +290,50 @@ unix_syscall64(x86_saved_state_t *state)
                thread_exception_return();
                /* NOTREACHED */
        }
-       args_in_regs = 6;
 
        code = regs->rax & SYSCALL_NUMBER_MASK;
        DEBUG_KPRINT_SYSCALL_UNIX(
                "unix_syscall64: code=%d(%s) rip=%llx\n",
                code, syscallnames[code >= NUM_SYSENT ? 63 : code], regs->isf.rip);
        callp = (code >= NUM_SYSENT) ? &sysent[63] : &sysent[code];
-       uargp = (void *)(&regs->rdi);
+
+       vt = (void *)uthread->uu_arg;
 
        if (__improbable(callp == sysent)) {
                /*
                 * indirect system call... system call number
                 * passed as 'arg0'
                 */
-               code = regs->rdi;
+               code = regs->rdi;
                callp = (code >= NUM_SYSENT) ? &sysent[63] : &sysent[code];
-               uargp = (void *)(&regs->rsi);
+               args_start_at_rdi = FALSE;
                args_in_regs = 5;
+       } else {
+               args_start_at_rdi = TRUE;
+               args_in_regs = 6;
        }
-       uthread->uu_ap = uargp;
 
        if (callp->sy_narg != 0) {
+               assert(callp->sy_narg <= 8); /* size of uu_arg */
+
+               args_in_regs = MIN(args_in_regs, callp->sy_narg);
+               memcpy(vt, args_start_at_rdi ? &regs->rdi : &regs->rsi, args_in_regs * sizeof(syscall_arg_t));
+
+
                if (code != 180) {
-                       uint64_t *ip = (uint64_t *)uargp;
+                       uint64_t *ip = (uint64_t *)vt;
 
                        KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, 
                                BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
                                (int)(*ip), (int)(*(ip+1)), (int)(*(ip+2)), (int)(*(ip+3)), 0);
                }
-               assert(callp->sy_narg <= 8);
 
                if (__improbable(callp->sy_narg > args_in_regs)) {
                        int copyin_count;
 
-                       copyin_count = (callp->sy_narg - args_in_regs) * sizeof(uint64_t);
+                       copyin_count = (callp->sy_narg - args_in_regs) * sizeof(syscall_arg_t);
 
-                       error = copyin((user_addr_t)(regs->isf.rsp + sizeof(user_addr_t)), (char *)&regs->v_arg6, copyin_count);
+                       error = copyin((user_addr_t)(regs->isf.rsp + sizeof(user_addr_t)), (char *)&uthread->uu_arg[args_in_regs], copyin_count);
                        if (error) {
                                regs->rax = error;
                                regs->isf.rflags |= EFL_CF;
@@ -357,9 +354,8 @@ unix_syscall64(x86_saved_state_t *state)
 
        uthread->uu_rval[0] = 0;
        uthread->uu_rval[1] = 0;
-
-       
        uthread->uu_flag |= UT_NOTCANCELPT;
+       uthread->syscall_code = code;
 
 #ifdef JOE_DEBUG
         uthread->uu_iocount = 0;
@@ -367,8 +363,8 @@ unix_syscall64(x86_saved_state_t *state)
 #endif
 
        AUDIT_SYSCALL_ENTER(code, p, uthread);
-       error = (*(callp->sy_call))((void *) p, uargp, &(uthread->uu_rval[0]));
-        AUDIT_SYSCALL_EXIT(code, p, uthread, error);
+       error = (*(callp->sy_call))((void *) p, vt, &(uthread->uu_rval[0]));
+       AUDIT_SYSCALL_EXIT(code, p, uthread, error);
 
 #ifdef JOE_DEBUG
         if (uthread->uu_iocount)
@@ -426,13 +422,6 @@ unix_syscall64(x86_saved_state_t *state)
        
        uthread->uu_flag &= ~UT_NOTCANCELPT;
 
-#if FUNNEL_DEBUG       
-       /*
-        * if we're holding the funnel panic
-        */
-       syscall_exit_funnelcheck();
-#endif /* FUNNEL_DEBUG */
-
        if (__improbable(uthread->uu_lowpri_window)) {
                /*
                 * task is marked as a low priority I/O type
@@ -460,7 +449,6 @@ unix_syscall_return(int error)
        struct uthread          *uthread;
        struct proc *p;
        unsigned int code;
-       vm_offset_t params;
        struct sysent *callp;
 
        thread = current_thread();
@@ -475,17 +463,9 @@ unix_syscall_return(int error)
 
                regs = saved_state64(find_user_regs(thread));
 
-               /* reconstruct code for tracing before blasting rax */
-               code = regs->rax & SYSCALL_NUMBER_MASK;
+               code = uthread->syscall_code;
                callp = (code >= NUM_SYSENT) ? &sysent[63] : &sysent[code];
 
-               if (callp == sysent)
-                       /*
-                        * indirect system call... system call number
-                        * passed as 'arg0'
-                        */
-                       code = regs->rdi;
-
 #if CONFIG_DTRACE
                if (callp->sy_call == dtrace_systrace_syscall)
                        dtrace_systrace_syscall_return( code, error, uthread->uu_rval );
@@ -539,8 +519,8 @@ unix_syscall_return(int error)
                regs = saved_state32(find_user_regs(thread));
 
                regs->efl &= ~(EFL_CF);
-               /* reconstruct code for tracing before blasting eax */
-               code = regs->eax & I386_SYSCALL_NUMBER_MASK;
+
+               code = uthread->syscall_code;
                callp = (code >= NUM_SYSENT) ? &sysent[63] : &sysent[code];
 
 #if CONFIG_DTRACE
@@ -549,10 +529,6 @@ unix_syscall_return(int error)
 #endif /* CONFIG_DTRACE */
                AUDIT_SYSCALL_EXIT(code, p, uthread, error);
 
-               if (callp == sysent) {
-                       params = (vm_offset_t) (regs->uesp + sizeof (int));
-                       code = fuword(params);
-               }
                if (error == ERESTART) {
                        pal_syscall_restart( thread, find_user_regs(thread) );
                }
@@ -573,13 +549,6 @@ unix_syscall_return(int error)
 
        uthread->uu_flag &= ~UT_NOTCANCELPT;
 
-#if FUNNEL_DEBUG       
-       /*
-        * if we're holding the funnel panic
-        */
-       syscall_exit_funnelcheck();
-#endif /* FUNNEL_DEBUG */
-
        if (uthread->uu_lowpri_window) {
                /*
                 * task is marked as a low priority I/O type