X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/9bccf70c0258c7cac2dcb80011b2a964d884c552..8ad349bb6ed4a0be06e34c92be0d98b92e078db4:/osfmk/i386/bsd_i386.c diff --git a/osfmk/i386/bsd_i386.c b/osfmk/i386/bsd_i386.c index 0a96e3cb8..2cf2f670d 100644 --- a/osfmk/i386/bsd_i386.c +++ b/osfmk/i386/bsd_i386.c @@ -1,31 +1,39 @@ /* - * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_LICENSE_OSREFERENCE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the + * License may not be used to create, or enable the creation or + * redistribution of, unlawful or unlicensed copies of an Apple operating + * system, or to circumvent, violate, or enable the circumvention or + * violation of, any terms of an Apple operating system software license + * agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_OSREFERENCE_HEADER_END@ */ #ifdef MACH_BSD -#include #include #include #include #include +#include #include #include @@ -34,15 +42,17 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include +#include +#include #include #include #include @@ -52,10 +62,17 @@ #include #include #include - +#include +#include +#include +#include +#include #include +#include #include -struct proc; +#include <../bsd/sys/sysent.h> + +extern struct proc *current_proc(void); kern_return_t thread_userstack( @@ -63,7 +80,7 @@ thread_userstack( int, thread_state_t, unsigned int, - vm_offset_t *, + mach_vm_offset_t *, int * ); @@ -73,25 +90,20 @@ thread_entrypoint( int, thread_state_t, unsigned int, - vm_offset_t * + mach_vm_offset_t * ); -struct i386_saved_state * -get_user_regs( - thread_act_t); - -void -act_thread_dup( - thread_act_t, - thread_act_t -); - unsigned int get_msr_exportmask(void); unsigned int get_msr_nbits(void); unsigned int get_msr_rbits(void); +kern_return_t +thread_compose_cthread_desc(unsigned int addr, pcb_t pcb); + +void IOSleep(int); + /* * thread_userstack: * @@ -100,11 +112,11 @@ unsigned int get_msr_rbits(void); */ kern_return_t thread_userstack( - thread_t thread, + __unused thread_t thread, int flavor, thread_state_t tstate, unsigned int count, - vm_offset_t *user_stack, + user_addr_t *user_stack, int *customstack ) { @@ -120,6 +132,8 @@ thread_userstack( state25 = (i386_thread_state_t *) tstate; if (state25->esp) *user_stack = state25->esp; + else + *user_stack = USRSTACK; if (customstack && state25->esp) *customstack = 1; else @@ -137,6 +151,8 @@ thread_userstack( /* If a valid user stack is specified, use it. */ if (uesp) *user_stack = uesp; + else + *user_stack = USRSTACK; if (customstack && uesp) *customstack = 1; else @@ -151,11 +167,11 @@ thread_userstack( kern_return_t thread_entrypoint( - thread_t thread, + __unused thread_t thread, int flavor, thread_state_t tstate, unsigned int count, - vm_offset_t *entry_point + mach_vm_offset_t *entry_point ) { struct i386_saved_state *state; @@ -191,9 +207,9 @@ thread_entrypoint( } struct i386_saved_state * -get_user_regs(thread_act_t th) +get_user_regs(thread_t th) { - if (th->mact.pcb) + if (th->machine.pcb) return(USER_REGS(th)); else { printf("[get_user_regs: thread does not have pcb]"); @@ -205,39 +221,33 @@ get_user_regs(thread_act_t th) * Duplicate parent state in child * for U**X fork. */ -void -act_thread_dup( - thread_act_t parent, - thread_act_t child +kern_return_t +machine_thread_dup( + thread_t parent, + thread_t child ) { - struct i386_saved_state *parent_state, *child_state; - struct i386_machine_state *ims; struct i386_float_state floatregs; #ifdef XXX /* Save the FPU state */ - if ((pcb_t)(per_proc_info[cpu_number()].fpu_pcb) == parent->mact.pcb) { + if ((pcb_t)(per_proc_info[cpu_number()].fpu_pcb) == parent->machine.pcb) { fp_state_save(parent); } #endif - if (child->mact.pcb == NULL - || parent->mact.pcb == NULL) { - panic("[thread_dup, child (%x) or parent (%x) is NULL!]", - child->mact.pcb, parent->mact.pcb); - return; - } + if (child->machine.pcb == NULL || parent->machine.pcb == NULL) + return (KERN_FAILURE); /* Copy over the i386_saved_state registers */ - child->mact.pcb->iss = parent->mact.pcb->iss; + child->machine.pcb->iss = parent->machine.pcb->iss; /* Check to see if parent is using floating point * and if so, copy the registers to the child * FIXME - make sure this works. */ - if (parent->mact.pcb->ims.ifps) { + if (parent->machine.pcb->ims.ifps) { if (fpu_get_state(parent, &floatregs) == KERN_SUCCESS) fpu_set_state(child, &floatregs); } @@ -245,45 +255,41 @@ act_thread_dup( /* FIXME - should a user specified LDT, TSS and V86 info * be duplicated as well?? - probably not. */ + // duplicate any use LDT entry that was set I think this is appropriate. +#ifdef MACH_BSD + if (parent->machine.pcb->uldt_selector!= 0) { + child->machine.pcb->uldt_selector = parent->machine.pcb->uldt_selector; + child->machine.pcb->uldt_desc = parent->machine.pcb->uldt_desc; + } +#endif + + + return (KERN_SUCCESS); } /* * FIXME - thread_set_child */ -void thread_set_child(thread_act_t child, int pid); +void thread_set_child(thread_t child, int pid); void -thread_set_child(thread_act_t child, int pid) +thread_set_child(thread_t child, int pid) { - child->mact.pcb->iss.eax = pid; - child->mact.pcb->iss.edx = 1; - child->mact.pcb->iss.efl &= ~EFL_CF; + child->machine.pcb->iss.eax = pid; + child->machine.pcb->iss.edx = 1; + child->machine.pcb->iss.efl &= ~EFL_CF; } -void thread_set_parent(thread_act_t parent, int pid); +void thread_set_parent(thread_t parent, int pid); void -thread_set_parent(thread_act_t parent, int pid) +thread_set_parent(thread_t parent, int pid) { - parent->mact.pcb->iss.eax = pid; - parent->mact.pcb->iss.edx = 0; - parent->mact.pcb->iss.efl &= ~EFL_CF; + parent->machine.pcb->iss.eax = pid; + parent->machine.pcb->iss.edx = 0; + parent->machine.pcb->iss.efl &= ~EFL_CF; } -/* - * Move pages from one kernel virtual address to another. - * Both addresses are assumed to reside in the Sysmap, - * and size must be a multiple of the page size. - */ -void -pagemove( - register caddr_t from, - register caddr_t to, - int size) -{ - pmap_movepage((unsigned long)from, (unsigned long)to, (vm_size_t)size); -} - /* * System Call handling code */ @@ -291,43 +297,43 @@ pagemove( #define ERESTART -1 /* restart syscall */ #define EJUSTRETURN -2 /* don't modify regs, just return */ -struct sysent { /* system call table */ - unsigned short sy_narg; /* number of args */ - char sy_parallel; /* can execute in parallel */ - char sy_funnel; /* funnel type */ - unsigned long (*sy_call)(void *, void *, int *); /* implementing function */ -}; #define NO_FUNNEL 0 #define KERNEL_FUNNEL 1 -#define NETWORK_FUNNEL 2 extern funnel_t * kernel_flock; -extern funnel_t * network_flock; -extern struct sysent sysent[]; +extern int set_bsduthreadargs (thread_t, struct i386_saved_state *, void *); +extern void * get_bsduthreadarg(thread_t); +extern int * get_bsduthreadrval(thread_t th); +extern int * get_bsduthreadlowpridelay(thread_t th); + +extern long fuword(vm_offset_t); -int set_bsduthreadargs (thread_act_t, struct i386_saved_state *, void *); +extern void unix_syscall(struct i386_saved_state *); +extern void unix_syscall_return(int); -void * get_bsduthreadarg(thread_act_t); +/* following implemented in bsd/dev/i386/unix_signal.c */ +int __pthread_cset(struct sysent *); + +void __pthread_creset(struct sysent *); -void unix_syscall(struct i386_saved_state *); void unix_syscall_return(int error) { - thread_act_t thread; + thread_t thread; volatile int *rval; struct i386_saved_state *regs; struct proc *p; - struct proc *current_proc(); unsigned short code; vm_offset_t params; struct sysent *callp; - extern int nsysent; + volatile int *lowpri_delay; - thread = current_act(); - rval = (int *)get_bsduthreadrval(thread); + thread = current_thread(); + rval = get_bsduthreadrval(thread); + lowpri_delay = get_bsduthreadlowpridelay(thread); p = current_proc(); regs = USER_REGS(thread); @@ -354,15 +360,26 @@ unix_syscall_return(int error) } } - ktrsysret(p, code, error, rval[0], callp->sy_funnel); + ktrsysret(p, code, error, rval[0], (callp->sy_funnel & FUNNEL_MASK)); - KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END, - error, rval[0], rval[1], 0, 0); + __pthread_creset(callp); - if (callp->sy_funnel != NO_FUNNEL) { - assert(thread_funnel_get() == THR_FUNNEL_NULL); + if ((callp->sy_funnel & FUNNEL_MASK) != NO_FUNNEL) (void) thread_funnel_set(current_thread()->funnel_lock, FALSE); + + if (*lowpri_delay) { + /* + * task is marked as a low priority I/O type + * and the I/O we issued while in this system call + * collided with normal I/O operations... we'll + * delay in order to mitigate the impact of this + * task on the normal operation of the system + */ + IOSleep(*lowpri_delay); + *lowpri_delay = 0; } + KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END, + error, rval[0], rval[1], 0, 0); thread_exception_return(); /* NOTREACHED */ @@ -372,21 +389,24 @@ unix_syscall_return(int error) void unix_syscall(struct i386_saved_state *regs) { - thread_act_t thread; + thread_t thread; void *vt; unsigned short code; struct sysent *callp; - int nargs, error; - volatile int *rval; + int nargs; + int error; + int *rval; int funnel_type; vm_offset_t params; - extern int nsysent; struct proc *p; - struct proc *current_proc(); + volatile int *lowpri_delay; - thread = current_act(); + thread = current_thread(); p = current_proc(); - rval = (int *)get_bsduthreadrval(thread); + rval = get_bsduthreadrval(thread); + lowpri_delay = get_bsduthreadlowpridelay(thread); + + thread->task->syscalls_unix++; /* MP-safety ignored */ //printf("[scall : eax %x]", regs->eax); code = regs->eax; @@ -401,7 +421,7 @@ unix_syscall(struct i386_saved_state *regs) vt = get_bsduthreadarg(thread); if ((nargs = (callp->sy_narg * sizeof (int))) && - (error = copyin((char *) params, (char *)vt , nargs)) != 0) { + (error = copyin((user_addr_t) params, (char *) vt, nargs)) != 0) { regs->eax = error; regs->efl |= EFL_CF; thread_exception_return(); @@ -411,13 +431,19 @@ unix_syscall(struct i386_saved_state *regs) rval[0] = 0; rval[1] = regs->edx; - funnel_type = callp->sy_funnel; + if ((error = __pthread_cset(callp))) { + /* cancelled system call; let it returned with EINTR for handling */ + regs->eax = error; + regs->efl |= EFL_CF; + thread_exception_return(); + /* NOTREACHED */ + } + + funnel_type = (callp->sy_funnel & FUNNEL_MASK); if(funnel_type == KERNEL_FUNNEL) (void) thread_funnel_set(kernel_flock, TRUE); - else if (funnel_type == NETWORK_FUNNEL) - (void) thread_funnel_set(network_flock, TRUE); - set_bsduthreadargs(thread, regs, NULL); + (void) set_bsduthreadargs(thread, regs, NULL); if (callp->sy_narg > 8) panic("unix_syscall max arg count exceeded (%d)", callp->sy_narg); @@ -430,7 +456,7 @@ unix_syscall(struct i386_saved_state *regs) *ip, *(ip+1), *(ip+2), *(ip+3), 0); } - error = (*(callp->sy_call))(p, (void *) vt, rval); + error = (*(callp->sy_call))((void *) p, (void *) vt, &rval[0]); #if 0 /* May be needed with vfork changes */ @@ -452,12 +478,25 @@ unix_syscall(struct i386_saved_state *regs) ktrsysret(p, code, error, rval[0], funnel_type); - KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END, - error, rval[0], rval[1], 0, 0); + __pthread_creset(callp); if(funnel_type != NO_FUNNEL) (void) thread_funnel_set(current_thread()->funnel_lock, FALSE); + if (*lowpri_delay) { + /* + * task is marked as a low priority I/O type + * and the I/O we issued while in this system call + * collided with normal I/O operations... we'll + * delay in order to mitigate the impact of this + * task on the normal operation of the system + */ + IOSleep(*lowpri_delay); + *lowpri_delay = 0; + } + KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END, + error, rval[0], rval[1], 0, 0); + thread_exception_return(); /* NOTREACHED */ } @@ -468,13 +507,10 @@ machdep_syscall( struct i386_saved_state *regs) { int trapno, nargs; machdep_call_t *entry; - thread_t thread; - struct proc *p; - struct proc *current_proc(); trapno = regs->eax; if (trapno < 0 || trapno >= machdep_call_count) { - regs->eax = (unsigned int)kern_invalid(); + regs->eax = (unsigned int)kern_invalid(NULL); thread_exception_return(); /* NOTREACHED */ @@ -486,7 +522,7 @@ machdep_syscall( struct i386_saved_state *regs) if (nargs > 0) { int args[nargs]; - if (copyin((char *) regs->uesp + sizeof (int), + if (copyin((user_addr_t) regs->uesp + sizeof (int), (char *) args, nargs * sizeof (int))) { @@ -496,28 +532,28 @@ machdep_syscall( struct i386_saved_state *regs) /* NOTREACHED */ } - asm volatile(" - 1: - mov (%2),%%eax; - pushl %%eax; - sub $4,%2; - dec %1; - jne 1b; - mov %3,%%eax; - call *%%eax; - mov %%eax,%0" - - : "=r" (regs->eax) - : "r" (nargs), - "r" (&args[nargs - 1]), - "g" (entry->routine) - : "ax", "cx", "dx", "sp"); + switch (nargs) { + case 1: + regs->eax = (*entry->routine.args_1)(args[0]); + break; + case 2: + regs->eax = (*entry->routine.args_2)(args[0],args[1]); + break; + case 3: + regs->eax = (*entry->routine.args_3)(args[0],args[1],args[2]); + break; + case 4: + regs->eax = (*entry->routine.args_4)(args[0],args[1],args[2],args[3]); + break; + default: + panic("machdep_syscall(): too many args"); + } } else - regs->eax = (unsigned int)(*entry->routine)(); + regs->eax = (*entry->routine.args_0)(); - if (current_thread()->funnel_lock) - (void) thread_funnel_set(current_thread()->funnel_lock, FALSE); + if (current_thread()->funnel_lock) + (void) thread_funnel_set(current_thread()->funnel_lock, FALSE); thread_exception_return(); /* NOTREACHED */ @@ -525,9 +561,31 @@ machdep_syscall( struct i386_saved_state *regs) kern_return_t -thread_set_cthread_self(int self) +thread_compose_cthread_desc(unsigned int addr, pcb_t pcb) { - current_act()->mact.pcb->cthread_self = (unsigned int)self; + struct real_descriptor desc; + + mp_disable_preemption(); + + desc.limit_low = 1; + desc.limit_high = 0; + desc.base_low = addr & 0xffff; + desc.base_med = (addr >> 16) & 0xff; + desc.base_high = (addr >> 24) & 0xff; + desc.access = ACC_P|ACC_PL_U|ACC_DATA_W; + desc.granularity = SZ_32|SZ_G; + pcb->cthread_desc = desc; + *ldt_desc_p(USER_CTHREAD) = desc; + + mp_enable_preemption(); + + return(KERN_SUCCESS); +} + +kern_return_t +thread_set_cthread_self(uint32_t self) +{ + current_thread()->machine.pcb->cthread_self = self; return (KERN_SUCCESS); } @@ -535,9 +593,86 @@ thread_set_cthread_self(int self) kern_return_t thread_get_cthread_self(void) { - return ((kern_return_t)current_act()->mact.pcb->cthread_self); + return ((kern_return_t)current_thread()->machine.pcb->cthread_self); } +kern_return_t +thread_fast_set_cthread_self(uint32_t self) +{ + pcb_t pcb; + pcb = (pcb_t)current_thread()->machine.pcb; + thread_compose_cthread_desc(self, pcb); + pcb->cthread_self = self; /* preserve old func too */ + return (USER_CTHREAD); +} + +/* + * thread_set_user_ldt routine is the interface for the user level + * settable ldt entry feature. allowing a user to create arbitrary + * ldt entries seems to be too large of a security hole, so instead + * this mechanism is in place to allow user level processes to have + * an ldt entry that can be used in conjunction with the FS register. + * + * Swapping occurs inside the pcb.c file along with initialization + * when a thread is created. The basic functioning theory is that the + * pcb->uldt_selector variable will contain either 0 meaning the + * process has not set up any entry, or the selector to be used in + * the FS register. pcb->uldt_desc contains the actual descriptor the + * user has set up stored in machine usable ldt format. + * + * Currently one entry is shared by all threads (USER_SETTABLE), but + * this could be changed in the future by changing how this routine + * allocates the selector. There seems to be no real reason at this + * time to have this added feature, but in the future it might be + * needed. + * + * address is the linear address of the start of the data area size + * is the size in bytes of the area flags should always be set to 0 + * for now. in the future it could be used to set R/W permisions or + * other functions. Currently the segment is created as a data segment + * up to 1 megabyte in size with full read/write permisions only. + * + * this call returns the segment selector or -1 if any error occurs + */ +kern_return_t +thread_set_user_ldt(uint32_t address, uint32_t size, uint32_t flags) +{ + pcb_t pcb; + struct fake_descriptor temp; + int mycpu; + + if (flags != 0) + return -1; // flags not supported + if (size > 0xFFFFF) + return -1; // size too big, 1 meg is the limit + + mp_disable_preemption(); + mycpu = cpu_number(); + + // create a "fake" descriptor so we can use fix_desc() + // to build a real one... + // 32 bit default operation size + // standard read/write perms for a data segment + pcb = (pcb_t)current_thread()->machine.pcb; + temp.offset = address; + temp.lim_or_seg = size; + temp.size_or_wdct = SZ_32; + temp.access = ACC_P|ACC_PL_U|ACC_DATA_W; + + // turn this into a real descriptor + fix_desc(&temp,1); + + // set up our data in the pcb + pcb->uldt_desc = *(struct real_descriptor*)&temp; + pcb->uldt_selector = USER_SETTABLE; // set the selector value + + // now set it up in the current table... + *ldt_desc_p(USER_SETTABLE) = *(struct real_descriptor*)&temp; + + mp_enable_preemption(); + + return USER_SETTABLE; +} void mach25_syscall(struct i386_saved_state *regs) { @@ -545,12 +680,176 @@ mach25_syscall(struct i386_saved_state *regs) regs->eip, regs->eax, -regs->eax); panic("FIXME!"); } - #endif /* MACH_BSD */ -#undef current_thread -thread_t -current_thread(void) + +/* This routine is called from assembly before each and every mach trap. + */ + +extern unsigned int mach_call_start(unsigned int, unsigned int *); + +__private_extern__ +unsigned int +mach_call_start(unsigned int call_number, unsigned int *args) { - return(current_thread_fast()); + int i, argc; + unsigned int kdarg[3]; + + current_thread()->task->syscalls_mach++; /* MP-safety ignored */ + +/* Always prepare to trace mach system calls */ + + kdarg[0]=0; + kdarg[1]=0; + kdarg[2]=0; + + argc = mach_trap_table[call_number>>4].mach_trap_arg_count; + + if (argc > 3) + argc = 3; + + for (i=0; i < argc; i++) + kdarg[i] = (int)*(args + i); + + KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC, (call_number>>4)) | DBG_FUNC_START, + kdarg[0], kdarg[1], kdarg[2], 0, 0); + + return call_number; /* pass this back thru */ } + +/* This routine is called from assembly after each mach system call + */ + +extern unsigned int mach_call_end(unsigned int, unsigned int); + +__private_extern__ +unsigned int +mach_call_end(unsigned int call_number, unsigned int retval) +{ + KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC,(call_number>>4)) | DBG_FUNC_END, + retval, 0, 0, 0, 0); + return retval; /* pass this back thru */ +} + +typedef kern_return_t (*mach_call_t)(void *); + +extern __attribute__((regparm(1))) kern_return_t +mach_call_munger(unsigned int call_number, + unsigned int arg1, + unsigned int arg2, + unsigned int arg3, + unsigned int arg4, + unsigned int arg5, + unsigned int arg6, + unsigned int arg7, + unsigned int arg8, + unsigned int arg9 +); + +struct mach_call_args { + unsigned int arg1; + unsigned int arg2; + unsigned int arg3; + unsigned int arg4; + unsigned int arg5; + unsigned int arg6; + unsigned int arg7; + unsigned int arg8; + unsigned int arg9; +}; +__private_extern__ +__attribute__((regparm(1))) kern_return_t +mach_call_munger(unsigned int call_number, + unsigned int arg1, + unsigned int arg2, + unsigned int arg3, + unsigned int arg4, + unsigned int arg5, + unsigned int arg6, + unsigned int arg7, + unsigned int arg8, + unsigned int arg9 +) +{ + int argc; + mach_call_t mach_call; + kern_return_t retval; + struct mach_call_args args = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + current_thread()->task->syscalls_mach++; /* MP-safety ignored */ + call_number >>= 4; + + argc = mach_trap_table[call_number].mach_trap_arg_count; + switch (argc) { + case 9: args.arg9 = arg9; + case 8: args.arg8 = arg8; + case 7: args.arg7 = arg7; + case 6: args.arg6 = arg6; + case 5: args.arg5 = arg5; + case 4: args.arg4 = arg4; + case 3: args.arg3 = arg3; + case 2: args.arg2 = arg2; + case 1: args.arg1 = arg1; + } + + KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC, (call_number)) | DBG_FUNC_START, + args.arg1, args.arg2, args.arg3, 0, 0); + + mach_call = (mach_call_t)mach_trap_table[call_number].mach_trap_function; + retval = mach_call(&args); + + KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC,(call_number)) | DBG_FUNC_END, + retval, 0, 0, 0, 0); + + return retval; +} + +/* + * thread_setuserstack: + * + * Sets the user stack pointer into the machine + * dependent thread state info. + */ +void +thread_setuserstack( + thread_t thread, + mach_vm_address_t user_stack) +{ + struct i386_saved_state *ss = get_user_regs(thread); + + ss->uesp = CAST_DOWN(unsigned int,user_stack); +} + +/* + * thread_adjuserstack: + * + * Returns the adjusted user stack pointer from the machine + * dependent thread state info. Used for small (<2G) deltas. + */ +uint64_t +thread_adjuserstack( + thread_t thread, + int adjust) +{ + struct i386_saved_state *ss = get_user_regs(thread); + + ss->uesp += adjust; + return CAST_USER_ADDR_T(ss->uesp); +} + +/* + * thread_setentrypoint: + * + * Sets the user PC into the machine + * dependent thread state info. + */ +void +thread_setentrypoint( + thread_t thread, + mach_vm_address_t entry) +{ + struct i386_saved_state *ss = get_user_regs(thread); + + ss->eip = CAST_DOWN(unsigned int,entry); +} +