Source to machdep/ppc/systemcalls.c


Enter a symbol's name here to quickly find it.

/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  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 1.0 (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.
 * 
 * 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 OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License."
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

/*
 * Copyright (c) 1997 Apple Computer, Inc.
 *
 * PowerPC Family:	System Call handlers.
 *
 * HISTORY
 * 18-Aug-97   Umesh Vaishampayan  ([email protected])
 *	Added syscalltrace filtering. 
 * 27-July-97  Umesh Vaishampayan  ([email protected])
 *	Debug printf() changed to kprintf(). Cleanup unused system timing.
 */
 
#include <mach/mach_types.h>
#include <mach/exception.h>
#include <mach/error.h>

#include <kern/syscall_sw.h>
#include <kern/kdp.h>
#include <kern/kdebug.h>

#include <machdep/ppc/frame.h>
#include <machdep/ppc/thread.h>
#include <machdep/ppc/asm.h>
#include <machdep/ppc/proc_reg.h>
#include <machdep/ppc/trap.h>
#include <machdep/ppc/exception.h>
#include <machdep/ppc/pcb_flags.h>

#include <sys/param.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/systm.h>

#if DIAGNOSTIC
/* syscalltrace defines */
#define _SCT_NUM_PIDS	8

#define _SCT_OFF	0x00
#define	_SCT_MACHCALLS	0x01
#define	_SCT_UNIXCALLS	0x02
#define	_SCT_ALL	(_SCT_MACHCALLS | _SCT_UNIXCALLS)

int syscalltrace = 0;
int usepids = 0;		/* 1 enables pid filtering */
int pidstraced[_SCT_NUM_PIDS];	/* can specify upto _SCT_NUM_PIDS to filter */

static int
matchpid( int pid )
{
	int i;
	for(i=0; i<_SCT_NUM_PIDS; i++)
		if( pidstraced[i] == pid )
			return 1; /* match! */
	return 0; /* not found */
}

#endif /* DIAGNOSTIC */

/*
** Function:	mach_syscall
**
** Inputs:	pcb	- pointer to Process Control Block
**		arg1	- arguments to mach system calls
**		arg2
**		arg3
**		arg4
**		arg5
**		arg6
**		arg7
**
** Outputs:	none
**
** Notes:	There may be additional arguments to the mach calls
**		that will be read in from user space if necessary
*/
void
mach_syscall(
    struct pcb * pcb,
    int arg1,
    int arg2,
    int arg3,
    int arg4,
    int arg5,
    int arg6,
    int arg7
    )
{
    struct ppc_saved_state	*regs;
    int				error;	/* error code */
    struct uthread		*uthread;
    struct proc			*p;
    
    /* the mach trap number supplied by libmach */
    int				mach_trap;
    mach_trap_t			*trapp;
    thread_t			thread;
    int				arg0;
    struct stack_frame		*usfp;
    int				sbargs[4], uasfp, *argp;
    extern char			*mach_callnames[];  


    if (!USERMODE(pcb->ss.srr1))
	panic("mach_syscall");

    regs = &pcb->ss;

    thread = current_thread();
    uthread = thread->_uthread;
    uthread->uu_ar0 = (int *)pcb;
    p = current_proc();

    /* get the mach trap number */
    mach_trap = -(regs->r0);

    /* get the first argument to the mach trap call */
    arg0 = regs->r3;

    error = 0;

    /* find mach trap table entry */
    if (mach_trap >= mach_trap_count  ||  mach_trap < 0)
    {
	error = KERN_FAILURE;
    }
    else
    {
    	trapp = &mach_trap_table[mach_trap];

	if (trapp->mach_trap_arg_count > MAXREGARGS)
	{
	    int i, word;

	    /*
	    **  This code gets executed when there are more than MAXREGARGS
	    ** worth of parameters expected for the call.  The additional
	    ** parameters are passed on the users stack and must be copies
	    ** in from user space.
	    */
	    if (trapp->mach_trap_arg_count > NARGS)
		panic("mach_syscall: max arg count exceeded");

	    /* get the user stack frame pointer from saved state r1 */
	    usfp = (struct stack_frame *)regs->r1;

	    /* set up a pointer to the user arguments stack frame pointer */
	    uasfp = (int)&usfp->pa.spa.saved_p8;

	    /* setup the pointer for the stack based args */
	    argp = sbargs;

	    for (i = 0; i < (trapp->mach_trap_arg_count - MAXREGARGS); i++ )
	    {
		if (copyin ((void *)uasfp++, (void *)&word, sizeof(int)))
		{
 		    regs->r3 = -1;
		    thread_exception_return();
		}
		*argp++ = word;
	    }
	}

#if DIAGNOSTIC
	if ((syscalltrace == _SCT_MACHCALLS) || (syscalltrace == _SCT_ALL)) {
		int trpid = ((p) ? p->p_pid : -1);
		if((!usepids) || (usepids && matchpid(trpid)))
			kprintf("%s (%d) mach_syscall[%d = %s] --",
			((p) ? p->p_comm : "no-proc"),
			trpid, mach_trap, mach_callnames[mach_trap]);
	}
#endif /* DIAGNOSTIC */
	/*
	** Notice that there are always NARGS passed into the mach_trap
	** regardless whether they are needed or not.
	**
	** If NARGS changes this function call must be changed as well!!
	*/
	KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_EXCP_SC, 0) | DBG_FUNC_START,
		                             mach_trap, arg0, arg1, arg2, arg3);

    	error = (*(trapp->mach_trap_function))(	arg0, arg1,
						arg2, arg3,
						arg4, arg5,
						arg6, arg7,
						sbargs[0], sbargs[1],
						sbargs[2], sbargs[3] );

	KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_EXCP_SC, 0) | DBG_FUNC_END,
		                             mach_trap, error, 0, 0, 0);
#if DIAGNOSTIC
	if ((syscalltrace == _SCT_MACHCALLS) || (syscalltrace == _SCT_ALL)) {
		int trpid = ((p) ? p->p_pid : -1);
		if((!usepids) || (usepids && matchpid(trpid))) {
			if (error)
	    			kprintf("> sys=0x%X, sub=0x%X, code=0x%X\n",
				err_get_system(error), err_get_sub(error),
				err_get_code(error));
			else
    				kprintf("> error == 0x%X\n", error);
		}
	}
#endif /* DIAGNOSTIC */
    }

    regs->r3 = error;

    thread_exception_return();
    /* NOTREACHED */
}


/*
** 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_t			thread;
    struct uthread		*uthread;
    struct sysent		*callp;
    struct proc			*p;
    int				nargs, error;
    unsigned short		code;
    int				rval[2];
    extern char *syscallnames[];  

    if (!USERMODE(pcb->ss.srr1))
	panic("unix_syscall");

    regs = &pcb->ss;
    thread = current_thread();

    uthread = thread->_uthread;
    uthread->uu_ar0 = (int *)pcb;
    p = current_proc();

    /*
    ** Get index into sysent table
    */   
    code = regs->r0;

    if (code > nsysent)
    {
	error = 0;
	switch (code) {
	case 0x7FFA:
	  if ((thread->pcb->flags & PCB_BB_MASK) == 0) {
	     error = EPERM;
	     break;
	  }
	  NotifyInterruption(regs->r3,arg1,arg2,arg3,arg4,arg5,arg6,arg7);
	  break;
	case 0x7FFF:
	    mapBlueBoxShmem(regs->r3,arg1,arg2,arg3,arg4,arg5,arg6,arg7);
	    break;
	case 0x7FFD:
	    unmapBlueBoxShmem(regs->r3,arg1,arg2,arg3,arg4,arg5,arg6,arg7);
	    break;
	}
    }
    else {
	/*
	** Set up call pointer
	*/
	callp = (code >= nsysent) ? &sysent[63] : &sysent[code];

	/*
	** SPECIAL CASE function 0 to be indirect system call
	*/
	if (callp == sysent)
	{
	code = regs->r3;
	callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
	uthread->uu_arg[0] = arg1;
	uthread->uu_arg[1] = arg2;
	uthread->uu_arg[2] = arg3;
	uthread->uu_arg[3] = arg4;
	uthread->uu_arg[4] = arg5;
	uthread->uu_arg[5] = arg6;
	uthread->uu_arg[6] = arg7;
	}
	else
	{
	/*
	** Set up the args for the system call
	*/ 
	uthread->uu_arg[0] = regs->r3; 
	uthread->uu_arg[1] = arg1;
	uthread->uu_arg[2] = arg2;
	uthread->uu_arg[3] = arg3;
	uthread->uu_arg[4] = arg4;
	uthread->uu_arg[5] = arg5;
	uthread->uu_arg[6] = arg6;
	uthread->uu_arg[7] = arg7;
	}

	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;
#if DIAGNOSTIC
	if ((syscalltrace == _SCT_UNIXCALLS) || (syscalltrace == _SCT_ALL)) {
		int trpid = ((p) ? p->p_pid : -1);
		if((!usepids) || (usepids && matchpid(trpid))) {
	    		kprintf("%s(%d) unix_syscall[%d = %s] --",
			((p) ? p->p_comm : "no-proc"),
			trpid, code, syscallnames[code]);
	    		if ( (code == 5) || (code == 59) )
				kprintf(" arg0 = %x, arg1 = %d, arg2 = %d, "
				"arg3 = %d --",
				uthread->uu_arg[0], uthread->uu_arg[1],
				uthread->uu_arg[2], uthread->uu_arg[3]);
		}
	}
#endif /* DIAGNOSTIC */
#if KDEBUG
	if (code != 180) {
	        KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_EXCP_SC, 1) | DBG_FUNC_START,
		                             code, uthread->uu_arg[0], uthread->uu_arg[1],
		                                   uthread->uu_arg[2], uthread->uu_arg[3]);
	}
#endif /* KDEBUG */

	error = (*(callp->sy_call))(p, (caddr_t)uthread->uu_arg, rval);

#if KDEBUG
	if (code != 180) {
	        KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_EXCP_SC, 1) | DBG_FUNC_END,
		                             code, error, rval[0], rval[1], 0);
	}
#endif /* KDEBUG */
#if DIAGNOSTIC
	if ((syscalltrace == _SCT_UNIXCALLS) || (syscalltrace == _SCT_ALL)) {
		int trpid = ((p) ? p->p_pid : -1);
		if((!usepids) || (usepids && matchpid(trpid)))
			if (error)
    				kprintf("> error == 0x%X\n", error);
			else
				kprintf("> rval=0x%X %X\n", rval[0],rval[1]);
	}
#endif /* DIAGNOSTIC */
    }
    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 } */

    thread_exception_return();
    /* NOTREACHED */
	
}