Source to osfmk/ppc/bsd_ppc.c
/*
* Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_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@
*/
#include <mach/mach_types.h>
#include <mach/exception_types.h>
#include <mach/error.h>
#include <kern/counters.h>
#include <kern/syscall_sw.h>
#include <kern/task.h>
#include <kern/thread.h>
#include <ppc/thread.h>
#include <kern/thread_act.h>
#include <ppc/thread_act.h>
#include <ppc/asm.h>
#include <ppc/proc_reg.h>
#include <ppc/trap.h>
#include <ppc/exception.h>
#include <kern/assert.h>
#include <sys/kdebug.h>
#define ERESTART -1 /* restart syscall */
#define EJUSTRETURN -2 /* don't modify regs, just return */
struct unix_syscallargs {
int flavor;
int r3;
int arg1, arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9;
};
struct sysent { /* system call table */
unsigned short sy_narg; /* number of args */
unsigned short sy_parallel; /* can execute in parallel */
unsigned long (*sy_call)(void *, void *, int *); /* implementing function */
};
extern struct sysent sysent[];
void *get_bsdtask_info(
task_t);
int set_bsduthreadargs (
thread_act_t, struct pcb *,
struct unix_syscallargs *);
void * get_bsduthreadarg(
thread_act_t);
void
unix_syscall(
struct pcb * pcb,
int, int, int, int, int, int, int );
/*
* Function: unix_syscall
*
* Inputs: pcb - pointer to Process Control Block
* arg1 - arguments to mach system calls
* arg2
* arg3
* arg4
* arg5
* arg6
* arg7
*
* Outputs: none
*/
void
unix_syscall(
struct pcb * pcb,
int arg1,
int arg2,
int arg3,
int arg4,
int arg5,
int arg6,
int arg7
)
{
struct ppc_saved_state *regs;
thread_act_t thread;
struct sysent *callp;
int nargs, error;
unsigned short code;
void * p, *vt;
int * vtint;
int *rval;
struct unix_syscallargs sarg;
extern int nsysent;
(void) thread_set_funneled(TRUE);
regs = &pcb->ss;
thread = current_act();
p = get_bsdtask_info(current_task());
rval = (int *)get_bsduthreadrval(thread);
/*
** Get index into sysent table
*/
code = regs->r0;
/*
** Set up call pointer
*/
callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
sarg. flavor = (callp == sysent)? 1: 0;
if (sarg.flavor) {
code = regs->r3;
callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
}
else
sarg. r3 = regs->r3;
sarg. arg1 = arg1;
sarg. arg2 = arg2;
sarg. arg3 = arg3;
sarg. arg4 = arg4;
sarg. arg5 = arg5;
sarg. arg6 = arg6;
sarg. arg7 = arg7;
set_bsduthreadargs(thread,pcb,&sarg);
if (callp->sy_narg > 8)
panic("unix_syscall: max arg count exceeded");
rval[0] = 0;
/* r4 is volatile, if we set it to regs->r4 here the child
* will have parents r4 after execve */
rval[1] = 0;
error = 0; /* Start with a good value */
/*
** the PPC runtime calls cerror after every unix system call, so
** assume no error and adjust the "pc" to skip this call.
** It will be set back to the cerror call if an error is detected.
*/
regs->srr0 += 4;
vt = get_bsduthreadarg(thread);
if (code != 180) {
vtint = (int *) vt;
KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
vtint[0],vtint[1], vtint[2], vtint[3], 0);
}
counter_always(c_syscalls_unix++);
current_task()->syscalls_unix++;
error = (*(callp->sy_call))(p, (void *)vt, rval);
if (code != 180) {
KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
error, rval[0], rval[1], 0, 0);
}
if (error == ERESTART) {
regs->srr0 -= 8;
}
else if (error != EJUSTRETURN) {
if (error)
{
regs->r3 = error;
/* set the "pc" to execute cerror routine */
regs->srr0 -= 4;
} else { /* (not error) */
regs->r3 = rval[0];
regs->r4 = rval[1];
}
}
/* else (error == EJUSTRETURN) { nothing } */
(void) thread_set_funneled(FALSE);
thread_exception_return();
/* NOTREACHED */
}
unix_syscall_return(error)
{
struct ppc_saved_state *regs;
thread_act_t thread;
struct sysent *callp;
int nargs;
unsigned short code;
int *rval;
void * p, *vt;
int * vtint;
struct pcb *pcb;
struct unix_syscallargs sarg;
extern int nsysent;
thread = current_act();
p = get_bsdtask_info(current_task());
rval = (int *)get_bsduthreadrval(thread);
pcb = thread->mact.pcb;
regs = &pcb->ss;
/*
** Get index into sysent table
*/
code = regs->r0;
if (code != 180) {
KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
error, rval[0], rval[1], 0, 0);
}
if (error == ERESTART) {
regs->srr0 -= 8;
}
else if (error != EJUSTRETURN) {
if (error)
{
regs->r3 = error;
/* set the "pc" to execute cerror routine */
regs->srr0 -= 4;
} else { /* (not error) */
regs->r3 = rval[0];
regs->r4 = rval[1];
}
}
/* else (error == EJUSTRETURN) { nothing } */
(void) thread_set_funneled(FALSE);
thread_exception_return();
/* NOTREACHED */
}