New syscall entry implementation based on the Alpha version

as hacked by mycroft.
- Use syscall_intern() to give a process a plain or fancy
  syscall based on ktrace flags.
- Avoid copying from the trapframe into a local array as much
  as possible.

Yields roughly 5% improvement on a 25MHz R3000 (DECstation 5000/200)
on a simple syscall benchmark.

There's still some work that can be done using __HAVE_MINIMAL_EMUL.
This commit is contained in:
thorpej 2001-01-16 06:01:26 +00:00
parent f20b78bb5d
commit 9f5a22b3ee
8 changed files with 418 additions and 142 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: files.mips,v 1.29 2000/10/31 22:46:35 jeffs Exp $
# $NetBSD: files.mips,v 1.30 2001/01/16 06:01:26 thorpej Exp $
#
defopt opt_cputype.h NOTYET # MIPS1 MIPS2 MIPS3 MIPS4 MIPS5
@ -20,6 +20,7 @@ file arch/mips/mips/kgdb_machdep.c kgdb
file arch/mips/mips/mem.c
file arch/mips/mips/mips_mcclock.c mcclock # CPU speed via mcclock
file arch/mips/mips/pmap.c
file arch/mips/mips/syscall.c # syscalls
file arch/mips/mips/trap.c # interrupt, trap handlers
file arch/mips/mips/vm_machdep.c
file arch/mips/mips/mips_machdep.c # shared mips machdep.c

View File

@ -1,4 +1,4 @@
/* $NetBSD: proc.h,v 1.11 2001/01/14 21:18:39 thorpej Exp $ */
/* $NetBSD: proc.h,v 1.12 2001/01/16 06:01:26 thorpej Exp $ */
/*
* Copyright (c) 1992, 1993
@ -40,6 +40,9 @@
#ifndef _MIPS_PROC_H_
#define _MIPS_PROC_H_
struct proc;
/*
* Machine-dependent part of the proc structure for MIPS
*/
@ -50,6 +53,8 @@ struct mdproc {
int md_ss_addr; /* single step address for ptrace */
int md_ss_instr; /* single step instruction for ptrace */
__volatile int md_astpending; /* AST pending on return to userland */
/* syscall entry for this process */
void (*md_syscall)(struct proc *, u_int, u_int, u_int);
};
/* md_flags */

View File

@ -1,4 +1,4 @@
/* $NetBSD: types.h,v 1.26 2001/01/14 22:32:57 thorpej Exp $ */
/* $NetBSD: types.h,v 1.27 2001/01/16 06:01:26 thorpej Exp $ */
/*-
* Copyright (c) 1992, 1993
@ -44,8 +44,6 @@
#include <sys/cdefs.h>
#include <machine/int_types.h>
#define __HAVE_AST_PERPROC
/*
* Note that mips_reg_t is distinct from the register_t defined
* in <types.h> to allow these structures to be as hidden from
@ -103,6 +101,8 @@ typedef int32_t register_t;
#define __SWAP_BROKEN
#define __HAVE_AST_PERPROC
#define __HAVE_SYSCALL_INTERN
#ifdef MIPS3
#define __HAVE_CPU_COUNTER
#endif

View File

@ -1,4 +1,4 @@
# $NetBSD: genassym.cf,v 1.22 2001/01/14 21:18:39 thorpej Exp $
# $NetBSD: genassym.cf,v 1.23 2001/01/16 06:01:26 thorpej Exp $
#
# Copyright (c) 1997
# Jonathan Stone. All rights reserved.
@ -65,6 +65,7 @@ define P_MD_REGS offsetof(struct proc, p_md.md_regs)
define P_MD_UPTE_0 offsetof(struct proc, p_md.md_upte[0])
define P_MD_UPTE_1 offsetof(struct proc, p_md.md_upte[1])
define P_MD_ASTPENDING offsetof(struct proc, p_md.md_astpending)
define P_MD_SYSCALL offsetof(struct proc, p_md.md_syscall)
define U_PCB_FPREGS offsetof(struct user, u_pcb.pcb_fpregs)
define U_PCB_CONTEXT offsetof(struct user, u_pcb.pcb_context)

View File

@ -1,4 +1,4 @@
/* $NetBSD: locore_mips1.S,v 1.50 2001/01/14 21:18:39 thorpej Exp $ */
/* $NetBSD: locore_mips1.S,v 1.51 2001/01/16 06:01:26 thorpej Exp $ */
/*
* Copyright (c) 1992, 1993
@ -404,22 +404,23 @@ NESTED_NOPROFILE(mips1_SystemCall, CALLFRAME_SIZ, ra)
sw a1, FRAME_A1(k1)
sw a2, FRAME_A2(k1)
sw a3, FRAME_A3(k1)
lw a0, _C_LABEL(curproc) # 1st arg is curproc
mfhi v1
#sw t0, FRAME_T0(k1) # no need to save temp regs
#sw t1, FRAME_T1(k1)
#sw t2, FRAME_T2(k1)
#sw t3, FRAME_T3(k1)
mfc0 a0, MIPS_COP_0_STATUS # 1st arg is STATUS
mfc0 a1, MIPS_COP_0_STATUS # 2nd arg is STATUS
#sw t4, FRAME_T4(k1)
#sw t5, FRAME_T5(k1)
#sw t6, FRAME_T6(k1)
sw t7, FRAME_T7(k1)
mfc0 a1, MIPS_COP_0_CAUSE # 2nd arg is CAUSE
mfc0 a2, MIPS_COP_0_CAUSE # 3rd arg is CAUSE
sw s0, FRAME_S0(k1)
sw s1, FRAME_S1(k1)
sw s2, FRAME_S2(k1)
sw s3, FRAME_S3(k1)
mfc0 a2, MIPS_COP_0_EXC_PC # 3rd arg is PC
mfc0 a3, MIPS_COP_0_EXC_PC # 4th arg is PC
sw s4, FRAME_S4(k1)
sw s5, FRAME_S5(k1)
sw s6, FRAME_S6(k1)
@ -430,24 +431,25 @@ NESTED_NOPROFILE(mips1_SystemCall, CALLFRAME_SIZ, ra)
sw sp, FRAME_SP(k1)
sw s8, FRAME_S8(k1)
sw ra, FRAME_RA(k1)
sw a0, FRAME_SR(k1)
sw a1, FRAME_SR(k1)
sw v0, FRAME_MULLO(k1)
sw v1, FRAME_MULHI(k1)
sw a2, FRAME_EPC(k1)
sw a3, FRAME_EPC(k1)
addu sp, k1, -CALLFRAME_SIZ # switch to kernel SP
#ifdef __GP_SUPPORT__
la gp, _C_LABEL(_gp) # switch to kernel GP
#endif
#if defined(DDB) || defined(DEBUG) || defined(KGDB)
move ra, a2
move ra, a3
sw ra, CALLFRAME_RA(sp)
#endif
ori t0, a0, MIPS_SR_INT_IE # turn on IEc, enable intr.
lw t1, P_MD_SYSCALL(a0) # t1 = syscall
ori t0, a1, MIPS_SR_INT_IE # turn on IEc, enable intr.
and t0, t0, ~MIPS_SR_COP_1_BIT # turn off FPU
/*
* Call the system call handler.
*/
jal _C_LABEL(syscall)
jal t1
mtc0 t0, MIPS_COP_0_STATUS
/*
* Check pending asynchronous traps.

View File

@ -1,4 +1,4 @@
/* $NetBSD: locore_mips3.S,v 1.64 2001/01/14 21:18:40 thorpej Exp $ */
/* $NetBSD: locore_mips3.S,v 1.65 2001/01/16 06:01:26 thorpej Exp $ */
/*
* Copyright (c) 1997 Jonathan Stone (hereinafter referred to as the author)
@ -654,22 +654,23 @@ NESTED_NOPROFILE(mips3_SystemCall, CALLFRAME_SIZ, ra)
REG_S a1, FRAME_A1(k1)
REG_S a2, FRAME_A2(k1)
REG_S a3, FRAME_A3(k1)
lw a0, _C_LABEL(curproc) # 1st arg is curproc
mfhi v1
#REG_S t0, FRAME_T0(k1) # no need to save temp regs
#REG_S t1, FRAME_T1(k1)
#REG_S t2, FRAME_T2(k1)
#REG_S t3, FRAME_T3(k1)
mfc0 a0, MIPS_COP_0_STATUS # 1st arg is STATUS
mfc0 a1, MIPS_COP_0_STATUS # 2nd arg is STATUS
#REG_S t4, FRAME_T4(k1)
#REG_S t5, FRAME_T5(k1)
#REG_S t6, FRAME_T6(k1)
#REG_S t7, FRAME_T7(k1)
mfc0 a1, MIPS_COP_0_CAUSE # 2nd arg is CAUSE
mfc0 a2, MIPS_COP_0_CAUSE # 3rd arg is CAUSE
REG_S s0, FRAME_S0(k1)
REG_S s1, FRAME_S1(k1)
REG_S s2, FRAME_S2(k1)
REG_S s3, FRAME_S3(k1)
mfc0 a2, MIPS_COP_0_EXC_PC # 3rd arg is PC
mfc0 a3, MIPS_COP_0_EXC_PC # 4th arg is PC
REG_S s4, FRAME_S4(k1)
REG_S s5, FRAME_S5(k1)
REG_S s6, FRAME_S6(k1)
@ -680,10 +681,10 @@ NESTED_NOPROFILE(mips3_SystemCall, CALLFRAME_SIZ, ra)
REG_S sp, FRAME_SP(k1)
REG_S s8, FRAME_S8(k1)
REG_S ra, FRAME_RA(k1)
REG_S a0, FRAME_SR(k1)
REG_S a1, FRAME_SR(k1)
REG_S v0, FRAME_MULLO(k1)
REG_S v1, FRAME_MULHI(k1)
REG_S a2, FRAME_EPC(k1)
REG_S a3, FRAME_EPC(k1)
addu sp, k1, -CALLFRAME_SIZ
#ifdef __GP_SUPPORT__
la gp, _C_LABEL(_gp) # switch to kernel GP
@ -692,17 +693,18 @@ NESTED_NOPROFILE(mips3_SystemCall, CALLFRAME_SIZ, ra)
* Turn off fpu and enter kernel mode
*/
.set at
and t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_KSU_MASK)
lw t1, P_MD_SYSCALL(a0) # t1 = syscall
and t0, a1, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_KSU_MASK)
.set noat
#if defined(DDB) || defined(DEBUG) || defined(KGDB)
move ra, a2
move ra, a3
sw ra, CALLFRAME_RA(sp)
#endif
/*
* Call the system call handler.
*/
mtc0 t0, MIPS_COP_0_STATUS # re-enable interrupts
jal _C_LABEL(syscall)
jal t1
nop
/*
* Check pending asynchronous traps.

View File

@ -0,0 +1,381 @@
/* $NetBSD: syscall.c,v 1.1 2001/01/16 06:01:27 thorpej Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe and by Charles M. Hannum.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1988 University of Utah.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* the Systems Programming Group of the University of Utah Computer
* Science Department and Ralph Campbell.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* from: Utah Hdr: trap.c 1.32 91/04/06
*
* @(#)trap.c 8.5 (Berkeley) 1/11/94
*/
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.1 2001/01/16 06:01:27 thorpej Exp $");
#include "opt_ktrace.h"
#include "opt_syscall_debug.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/signal.h>
#ifdef KTRACE
#include <sys/ktrace.h>
#endif
#include <sys/syscall.h>
#include <uvm/uvm_extern.h>
#include <machine/cpu.h>
#include <mips/trap.h>
#include <mips/reg.h>
#include <mips/regnum.h> /* symbolic register indices */
#include <mips/userret.h>
void syscall_intern(struct proc *);
void syscall_plain(struct proc *, u_int, u_int, u_int);
void syscall_fancy(struct proc *, u_int, u_int, u_int);
vaddr_t MachEmulateBranch(struct frame *, vaddr_t, u_int, int);
#define DELAYBRANCH(x) ((int)(x)<0)
void
syscall_intern(struct proc *p)
{
#ifdef KTRACE
if (p->p_traceflag & (KTRFAC_SYSCALL | KTRFAC_SYSRET))
p->p_md.md_syscall = syscall_fancy;
else
#endif
p->p_md.md_syscall = syscall_plain;
}
/*
* Process a system call.
*
* System calls are strange beasts. They are passed the syscall number
* in v0, and the arguments in the registers (as normal). They return
* an error flag in a3 (if a3 != 0 on return, the syscall had an error),
* and the return value (if any) in v0 and possibly v1.
*
* XXX Needs to be heavily rototilled for N32 or LP64 support.
*/
void
syscall_plain(struct proc *p, u_int status, u_int cause, u_int opc)
{
struct frame *frame = (struct frame *)p->p_md.md_regs;
mips_reg_t *args, copyargs[8];
size_t code, numsys, nsaved, nargs;
const struct sysent *callp;
int error;
uvmexp.syscalls++;
if (DELAYBRANCH(cause))
frame->f_regs[PC] = MachEmulateBranch(frame, opc, 0, 0);
else
frame->f_regs[PC] = opc + sizeof(int);
callp = p->p_emul->e_sysent;
numsys = p->p_emul->e_nsysent;
code = frame->f_regs[V0];
switch (code) {
case SYS_syscall:
case SYS___syscall:
args = copyargs;
if (code == SYS_syscall) {
/*
* Code is first argument, followed by actual args.
*/
code = frame->f_regs[A0];
args[0] = frame->f_regs[A1];
args[1] = frame->f_regs[A2];
args[2] = frame->f_regs[A3];
nsaved = 3;
} else {
/*
* Like syscall, but code is a quad, so as to maintain
* quad alignment for the rest of the arguments.
*/
code = frame->f_regs[A0 + _QUAD_LOWWORD];
args[0] = frame->f_regs[A2];
args[1] = frame->f_regs[A3];
nsaved = 2;
}
if (code >= p->p_emul->e_nsysent)
callp += p->p_emul->e_nosys;
else
callp += code;
nargs = callp->sy_argsize / sizeof(mips_reg_t);
if (nargs > nsaved) {
error = copyin(
((mips_reg_t *)(vaddr_t)frame->f_regs[SP] + 4),
(args + nsaved),
(nargs - nsaved) * sizeof(mips_reg_t));
if (error)
goto bad;
}
break;
default:
if (code >= p->p_emul->e_nsysent)
callp += p->p_emul->e_nosys;
else
callp += code;
nargs = callp->sy_narg;
if (nargs < 5)
args = &frame->f_regs[A0];
else {
args = copyargs;
error = copyin(
((mips_reg_t *)(vaddr_t)frame->f_regs[SP] + 4),
(&copyargs[4]),
(nargs - 4) * sizeof(mips_reg_t));
if (error)
goto bad;
args[0] = frame->f_regs[A0];
args[1] = frame->f_regs[A1];
args[2] = frame->f_regs[A2];
args[3] = frame->f_regs[A3];
}
break;
}
#ifdef SYSCALL_DEBUG
scdebug_call(p, code, args);
#endif
frame->f_regs[V0] = 0;
/* XXX register_t vs. mips_reg_t */
error = (*callp->sy_call)(p, args, (register_t *)&frame->f_regs[V0]);
switch (error) {
case 0:
frame->f_regs[A3] = 0;
break;
case ERESTART:
frame->f_regs[PC] = opc;
break;
case EJUSTRETURN:
break; /* nothing to do */
default:
bad:
frame->f_regs[V0] = error;
frame->f_regs[A3] = 1;
break;
}
#ifdef SYSCALL_DEBUG
scdebug_ret(p, code, error, rval);
#endif
userret(p);
}
void
syscall_fancy(struct proc *p, u_int status, u_int cause, u_int opc)
{
struct frame *frame = (struct frame *)p->p_md.md_regs;
mips_reg_t *args, copyargs[8];
size_t code, numsys, nsaved, nargs;
const struct sysent *callp;
int error;
uvmexp.syscalls++;
if (DELAYBRANCH(cause))
frame->f_regs[PC] = MachEmulateBranch(frame, opc, 0, 0);
else
frame->f_regs[PC] = opc + sizeof(int);
callp = p->p_emul->e_sysent;
numsys = p->p_emul->e_nsysent;
code = frame->f_regs[V0];
switch (code) {
case SYS_syscall:
case SYS___syscall:
args = copyargs;
if (code == SYS_syscall) {
/*
* Code is first argument, followed by actual args.
*/
code = frame->f_regs[A0];
args[0] = frame->f_regs[A1];
args[1] = frame->f_regs[A2];
args[2] = frame->f_regs[A3];
nsaved = 3;
} else {
/*
* Like syscall, but code is a quad, so as to maintain
* quad alignment for the rest of the arguments.
*/
code = frame->f_regs[A0 + _QUAD_LOWWORD];
args[0] = frame->f_regs[A2];
args[1] = frame->f_regs[A3];
nsaved = 2;
}
if (code >= p->p_emul->e_nsysent)
callp += p->p_emul->e_nosys;
else
callp += code;
nargs = callp->sy_argsize / sizeof(mips_reg_t);
if (nargs > nsaved) {
error = copyin(
((mips_reg_t *)(vaddr_t)frame->f_regs[SP] + 4),
(args + nsaved),
(nargs - nsaved) * sizeof(mips_reg_t));
if (error)
goto bad;
}
break;
default:
if (code >= p->p_emul->e_nsysent)
callp += p->p_emul->e_nosys;
else
callp += code;
nargs = callp->sy_narg;
if (nargs < 5)
args = &frame->f_regs[A0];
else {
args = copyargs;
error = copyin(
((mips_reg_t *)(vaddr_t)frame->f_regs[SP] + 4),
(&copyargs[4]),
(nargs - 4) * sizeof(mips_reg_t));
if (error)
goto bad;
args[0] = frame->f_regs[A0];
args[1] = frame->f_regs[A1];
args[2] = frame->f_regs[A2];
args[3] = frame->f_regs[A3];
}
break;
}
#ifdef SYSCALL_DEBUG
scdebug_call(p, code, args);
#endif
#ifdef KTRACE
if (KTRPOINT(p, KTR_SYSCALL)) {
/* XXX register_t vs. mips_reg_t */
ktrsyscall(p, code, callp->sy_argsize, (register_t *)args);
}
#endif
frame->f_regs[V0] = 0;
/* XXX register_t vs. mips_reg_t */
error = (*callp->sy_call)(p, args, (register_t *)&frame->f_regs[V0]);
switch (error) {
case 0:
frame->f_regs[A3] = 0;
break;
case ERESTART:
frame->f_regs[PC] = opc;
break;
case EJUSTRETURN:
break; /* nothing to do */
default:
bad:
frame->f_regs[V0] = error;
frame->f_regs[A3] = 1;
break;
}
#ifdef SYSCALL_DEBUG
scdebug_ret(p, code, error, rval);
#endif
userret(p);
#ifdef KTRACE
if (KTRPOINT(p, KTR_SYSRET))
ktrsysret(p, code, error, frame->f_regs[V0]);
#endif
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: trap.c,v 1.159 2001/01/14 21:22:57 thorpej Exp $ */
/* $NetBSD: trap.c,v 1.160 2001/01/16 06:01:27 thorpej Exp $ */
/*
* Copyright (c) 1988 University of Utah.
@ -44,12 +44,11 @@
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.159 2001/01/14 21:22:57 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.160 2001/01/16 06:01:27 thorpej Exp $");
#include "opt_cputype.h" /* which mips CPU levels do we support? */
#include "opt_ktrace.h"
#include "opt_ddb.h"
#include "opt_syscall_debug.h"
#if !defined(MIPS1) && !defined(MIPS3)
#error Neither "MIPS1" (r2000 family), "MIPS3" (r4000 family) was configured.
@ -129,7 +128,6 @@ const char *trap_type[] = {
};
void trap __P((unsigned, unsigned, unsigned, unsigned, struct trapframe *));
void syscall __P((unsigned, unsigned, unsigned));
void ast __P((unsigned));
vaddr_t MachEmulateBranch __P((struct frame *, vaddr_t, unsigned, int));
@ -137,120 +135,6 @@ extern void MachEmulateFP __P((unsigned));
extern void MachFPInterrupt __P((unsigned, unsigned, unsigned, struct frame *));
#define DELAYBRANCH(x) ((int)(x)<0)
/*
* Process a system call.
*
* System calls are strange beasts. They are passed the syscall number
* in v0, and the arguments in the registers (as normal). They return
* an error flag in a3 (if a3 != 0 on return, the syscall had an error),
* and the return value (if any) in v0 and possibly v1.
*/
void
syscall(status, cause, opc)
unsigned status;
unsigned cause;
unsigned opc;
{
struct proc *p = curproc;
struct frame *frame = (struct frame *)p->p_md.md_regs;
int args[8], rval[2], error;
size_t code, numsys, nsaved, argsiz;
const struct sysent *callp;
uvmexp.syscalls++;
if (DELAYBRANCH(cause))
frame->f_regs[PC] = MachEmulateBranch(frame, opc, 0, 0);
else
frame->f_regs[PC] = opc + sizeof(int);
callp = p->p_emul->e_sysent;
numsys = p->p_emul->e_nsysent;
code = frame->f_regs[V0];
switch (code) {
case SYS_syscall:
/*
* Code is first argument, followed by actual args.
*/
code = frame->f_regs[A0];
args[0] = frame->f_regs[A1];
args[1] = frame->f_regs[A2];
args[2] = frame->f_regs[A3];
nsaved = 3;
break;
case SYS___syscall:
/*
* Like syscall, but code is a quad, so as to maintain
* quad alignment for the rest of the arguments.
*/
code = frame->f_regs[A0 + _QUAD_LOWWORD];
args[0] = frame->f_regs[A2];
args[1] = frame->f_regs[A3];
nsaved = 2;
break;
default:
args[0] = frame->f_regs[A0];
args[1] = frame->f_regs[A1];
args[2] = frame->f_regs[A2];
args[3] = frame->f_regs[A3];
nsaved = 4;
break;
}
if (code >= p->p_emul->e_nsysent)
callp += p->p_emul->e_nosys;
else
callp += code;
argsiz = callp->sy_argsize / sizeof(int);
if (argsiz > nsaved) {
error = copyin(
(void *)((int *)(vaddr_t)frame->f_regs[SP] + 4),
(void *)(args + nsaved),
(argsiz - nsaved) * sizeof(int));
if (error)
goto bad;
}
#ifdef SYSCALL_DEBUG
scdebug_call(p, code, args);
#endif
#ifdef KTRACE
if (KTRPOINT(p, KTR_SYSCALL))
ktrsyscall(p, code, callp->sy_argsize, args);
#endif
rval[0] = 0;
rval[1] = frame->f_regs[V1];
#ifdef DEBUG
/* XXX save code */
#endif
error = (*callp->sy_call)(p, args, rval);
#ifdef DEBUG
/* XXX save syscall result in trapdebug */
#endif
switch (error) {
case 0:
frame->f_regs[V0] = rval[0];
frame->f_regs[V1] = rval[1];
frame->f_regs[A3] = 0;
break;
case ERESTART:
frame->f_regs[PC] = opc;
break;
case EJUSTRETURN:
break; /* nothing to do */
default:
bad:
frame->f_regs[V0] = error;
frame->f_regs[A3] = 1;
break;
}
#ifdef SYSCALL_DEBUG
scdebug_ret(p, code, error, rval);
#endif
userret(p);
#ifdef KTRACE
if (KTRPOINT(p, KTR_SYSRET))
ktrsysret(p, code, error, rval[0]);
#endif
}
/*
* fork syscall returns directly to user process via proc_trampoline,