#include <kern/task.h>
#include <kern/thread.h>
#include <kern/thread_act.h>
#include <kern/assert.h>
#include <kern/clock.h>
#include <mach/machine/thread_status.h>
#include <ppc/savearea.h>
#include <sys/kernel.h>
#include <sys/vm.h>
#include <sys/proc.h>
#include <sys/syscall.h>
#include <sys/systm.h>
#include <sys/user.h>
#include <sys/errno.h>
#include <sys/ktrace.h>
#include <sys/kdebug.h>
#include <sys/kern_audit.h>
extern void
unix_syscall(
struct savearea *regs
);
extern struct savearea *
find_user_regs(
thread_act_t act);
extern void enter_funnel_section(funnel_t *funnel_lock);
extern void exit_funnel_section(void);
void
unix_syscall(
struct savearea *regs
)
{
thread_act_t thread_act;
struct uthread *uthread;
struct proc *proc;
struct sysent *callp;
int error;
unsigned short code;
boolean_t flavor;
int funnel_type;
flavor = (((unsigned int)regs->save_r0) == NULL)? 1: 0;
if (flavor)
code = regs->save_r3;
else
code = regs->save_r0;
if (kdebug_enable && (code != 180)) {
if (flavor)
KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
regs->save_r4, regs->save_r5, regs->save_r6, regs->save_r7, 0);
else
KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
regs->save_r3, regs->save_r4, regs->save_r5, regs->save_r6, 0);
}
thread_act = current_act();
uthread = get_bsdthread_info(thread_act);
if (!(uthread->uu_flag & P_VFORK))
proc = (struct proc *)get_bsdtask_info(current_task());
else
proc = current_proc();
uthread->uu_ar0 = (int *)regs;
callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
#ifdef DEBUG
if (callp->sy_narg > 8)
panic("unix_syscall: max arg count exceeded");
#endif
if (callp->sy_narg != 0) {
if ( !flavor) {
uthread->uu_arg[0] = regs->save_r3;
uthread->uu_arg[1] = regs->save_r4;
uthread->uu_arg[2] = regs->save_r5;
uthread->uu_arg[3] = regs->save_r6;
uthread->uu_arg[4] = regs->save_r7;
uthread->uu_arg[5] = regs->save_r8;
uthread->uu_arg[6] = regs->save_r9;
uthread->uu_arg[7] = regs->save_r10;
} else {
uthread->uu_arg[0] = regs->save_r4;
uthread->uu_arg[1] = regs->save_r5;
uthread->uu_arg[2] = regs->save_r6;
uthread->uu_arg[3] = regs->save_r7;
uthread->uu_arg[4] = regs->save_r8;
uthread->uu_arg[5] = regs->save_r9;
uthread->uu_arg[7] = regs->save_r10;
}
}
funnel_type = (int)callp->sy_funnel;
if (funnel_type == KERNEL_FUNNEL)
enter_funnel_section(kernel_flock);
else if (funnel_type == NETWORK_FUNNEL)
enter_funnel_section(network_flock);
uthread->uu_rval[0] = 0;
uthread->uu_rval[1] = 0;
error = 0;
regs->save_srr0 += 4;
if (KTRPOINT(proc, KTR_SYSCALL))
ktrsyscall(proc, code, callp->sy_narg, uthread->uu_arg, funnel_type);
AUDIT_CMD(audit_syscall_enter(code, proc, uthread));
error = (*(callp->sy_call))(proc, (void *)uthread->uu_arg, &(uthread->uu_rval[0]));
AUDIT_CMD(audit_syscall_exit(error, proc, uthread));
regs = find_user_regs(thread_act);
if (error == ERESTART) {
regs->save_srr0 -= 8;
} else if (error != EJUSTRETURN) {
if (error) {
regs->save_r3 = (long long)error;
regs->save_srr0 -= 4;
} else {
regs->save_r3 = uthread->uu_rval[0];
regs->save_r4 = uthread->uu_rval[1];
}
}
if (KTRPOINT(proc, KTR_SYSRET))
ktrsysret(proc, code, error, uthread->uu_rval[0], funnel_type);
exit_funnel_section();
if (kdebug_enable && (code != 180)) {
KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
error, uthread->uu_rval[0], uthread->uu_rval[1], 0, 0);
}
thread_exception_return();
}
unix_syscall_return(error)
{
thread_act_t thread_act;
struct uthread *uthread;
struct proc *proc;
struct savearea *regs;
unsigned short code;
struct sysent *callp;
int funnel_type;
thread_act = current_act();
proc = current_proc();
uthread = get_bsdthread_info(thread_act);
regs = find_user_regs(thread_act);
if (error == ERESTART) {
regs->save_srr0 -= 8;
} else if (error != EJUSTRETURN) {
if (error) {
regs->save_r3 = (long long)error;
regs->save_srr0 -= 4;
} else {
regs->save_r3 = uthread->uu_rval[0];
regs->save_r4 = uthread->uu_rval[1];
}
}
if (regs->save_r0 != NULL)
code = regs->save_r0;
else
code = regs->save_r3;
callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
funnel_type = (int)callp->sy_funnel;
if (KTRPOINT(proc, KTR_SYSRET))
ktrsysret(proc, code, error, uthread->uu_rval[0], funnel_type);
exit_funnel_section();
if (kdebug_enable && (code != 180)) {
KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
error, uthread->uu_rval[0], uthread->uu_rval[1], 0, 0);
}
thread_exception_return();
}
struct gettimeofday_args{
struct timeval *tp;
struct timezone *tzp;
};
int
ppc_gettimeofday(p, uap, retval)
struct proc *p;
register struct gettimeofday_args *uap;
register_t *retval;
{
int error = 0;
if (uap->tp)
clock_gettimeofday(&retval[0], &retval[1]);
if (uap->tzp) {
struct timezone ltz;
extern simple_lock_data_t tz_slock;
usimple_lock(&tz_slock);
ltz = tz;
usimple_unlock(&tz_slock);
error = copyout((caddr_t)<z, (caddr_t)uap->tzp, sizeof (tz));
}
return (error);
}