X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/143464d58d2bd6378e74eec636961ceb0d32fb91..fe8ab488e9161c46dd9885d58fc52996dc0249ff:/bsd/dev/i386/systemcalls.c?ds=sidebyside diff --git a/bsd/dev/i386/systemcalls.c b/bsd/dev/i386/systemcalls.c index 77ecfba3a..8b2c8ab98 100644 --- a/bsd/dev/i386/systemcalls.c +++ b/bsd/dev/i386/systemcalls.c @@ -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 *)(®s->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 *)(®s->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 ? ®s->rdi : ®s->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 *)®s->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