Combined syscall handler for all ARM ports. This is basically the arm32

version, made readable and compatible with arm26.  In addition, this adds
support for NetBSD/arm's newly allocated SWI range.
This commit is contained in:
bjh21 2002-01-12 20:02:13 +00:00
parent 7fed4934b8
commit 9fe68c4f64
3 changed files with 92 additions and 216 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: syscall.c,v 1.3 2002/01/05 22:41:47 chris Exp $ */
/* $NetBSD: syscall.c,v 1.1 2002/01/12 20:02:13 bjh21 Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -80,11 +80,15 @@
#include "opt_syscall_debug.h"
#include <sys/param.h>
__RCSID("$NetBSD: syscall.c,v 1.1 2002/01/12 20:02:13 bjh21 Exp $");
#include <sys/device.h>
#include <sys/errno.h>
#include <sys/signalvar.h>
#include <sys/systm.h>
#include <sys/reboot.h>
#include <sys/signalvar.h>
#include <sys/syscall.h>
#include <sys/systm.h>
#include <sys/user.h>
#ifdef KTRACE
#include <sys/ktrace.h>
@ -94,42 +98,50 @@
#include <machine/cpu.h>
#include <machine/frame.h>
#include <arm/arm32/katelib.h>
#include <machine/pcb.h>
u_int arm700bugcount = 0;
void syscall __P((trapframe_t *, int));
#ifdef arm26
#include <machine/machdep.h>
#endif
#ifdef CPU_ARM7
struct evcnt arm700bugcount =
EVCNT_INITIALISER(EVCNT_TYPE_MISC, NULL, "cpu", "arm700swibug");
#endif
/*
* syscall(frame):
*
* System call request from POSIX system call gate interface to kernel.
*/
void
syscall(frame, code)
trapframe_t *frame;
int code;
syscall(trapframe_t *frame)
{
caddr_t stackargs;
const struct sysent *callp;
struct proc *p;
int error;
u_int argsize;
int *args, copyargs[8], rval[2];
int regparams;
u_int32_t insn;
int code, error;
u_int nap, nargs;
register_t *ap, *args, copyargs[8], rval[2];
/*
* Enable interrupts if they were enabled before the exception.
* Since all syscalls *should* come from user mode it will always
* be safe to enable them, but check anyway.
*/
#ifdef arm26
if ((frame->tf_r15 & R15_IRQ_DISABLE) == 0)
int_on();
#else
if (!(frame->tf_spsr & I32_bit))
enable_interrupts(I32_bit);
#endif
#ifdef DEBUG
if ((GetCPSR() & PSR_MODE) != PSR_SVC32_MODE)
panic("syscall: not in SVC32 mode");
#endif /* DEBUG */
#ifdef arm26
frame->tf_pc += INSN_SIZE;
#endif
/* XXX fuword? */
#ifdef __PROG32
insn = *(u_int32_t *)(frame->tf_pc - INSN_SIZE);
#else
insn = *(u_int32_t *)((frame->tf_r15 & R15_PC) - INSN_SIZE);
#endif
uvmexp.syscalls++;
p = curproc;
@ -152,22 +164,22 @@ syscall(frame, code)
* If the instruction that caused the exception is not a SWI
* then we hit the bug.
*/
if ((ReadWord(frame->tf_pc - INSN_SIZE) & 0x0f000000) != 0x0f000000) {
if ((insn & 0x0f000000) != 0x0f000000) {
frame->tf_pc -= INSN_SIZE;
++arm700bugcount;
/*
* Yuck. arm700bugcount should be per-CPU and
* attached at the same time as the CPU.
*/
if (!cold && arm700bugcount.ev_list.tqe_next == NULL)
evcnt_attach_static(&arm700bugcount);
++arm700bugcount.ev_count;
userret(p);
return;
}
#endif /* CPU_ARM7 */
/*
* Support for architecture dependant SWIs
*/
if (code & 0x00f00000) {
/*
* Support for the Architecture defined SWI's in case the
* processor does not support them.
*/
switch (insn & 0xf00000) { /* Which OS is the SWI from? */
case 0xf00000: /* ARM-defined SWIs */
switch (code) {
case 0x00f00000 : /* IMB */
case 0x00f00001 : /* IMB_range */
@ -178,59 +190,61 @@ syscall(frame, code)
break;
default:
/* Undefined so illegal instruction */
trapsignal(p, SIGILL, ReadWord(frame->tf_pc - INSN_SIZE));
trapsignal(p, SIGILL, insn);
break;
}
userret(p);
return;
case 0x000000: /* Old unofficial NetBSD range. */
case 0xa00000: /* New official NetBSD range. */
break;
default:
/* Undefined so illegal instruction */
trapsignal(p, SIGILL, insn);
userret(p);
return;
}
stackargs = (caddr_t)&frame->tf_r0;
regparams = 4 * sizeof(int);
code = insn & 0x000fffff;
ap = &frame->tf_r0;
nap = 4;
callp = p->p_emul->e_sysent;
switch (code) {
case SYS_syscall:
/* Don't have to look in user space, we have it in the trapframe */
/* code = fuword(stackargs);*/
code = ReadWord(stackargs);
stackargs += sizeof(int);
regparams -= sizeof(int);
code = *ap++;
nap--;
break;
case SYS___syscall:
if (callp != sysent)
#if 0
if (!(p->p_emul->e_flags & EMUL_HAS_SYS___syscall))
break;
#endif
/* Since this will be a register we look in the trapframe not user land */
/* code = fuword(stackargs + _QUAD_LOWWORD * sizeof(int));*/
code = ReadWord(stackargs + _QUAD_LOWWORD * sizeof(int));
stackargs += sizeof(quad_t);
regparams -= sizeof(quad_t);
break;
default:
/* do nothing by default */
code = ap[_QUAD_LOWWORD];
ap += 2;
nap -= 2;
break;
}
code &= (SYS_NSYSENT - 1);
callp += code;
argsize = callp->sy_argsize;
if (argsize <= regparams)
args = (int *)stackargs;
nargs = callp->sy_argsize / sizeof(register_t);
if (nargs <= nap)
args = ap;
else {
args = copyargs;
bcopy(stackargs, (caddr_t)args, regparams);
error = copyin((caddr_t)frame->tf_usr_sp,
(caddr_t)args + regparams, argsize - regparams);
memcpy(copyargs, ap, nap * sizeof(register_t));
error = copyin((void *)frame->tf_usr_sp, copyargs + nap,
(nargs - nap) * sizeof(register_t));
if (error)
goto bad;
args = copyargs;
}
#ifdef SYSCALL_DEBUG
scdebug_call(p, code, callp->sy_narg, args);
scdebug_call(p, code, args);
#endif
#ifdef KTRACE
if (KTRPOINT(p, KTR_SYSCALL))
@ -245,7 +259,12 @@ syscall(frame, code)
case 0:
frame->tf_r0 = rval[0];
frame->tf_r1 = rval[1];
#ifdef __PROG32
frame->tf_spsr &= ~PSR_C_bit; /* carry bit */
#else
frame->tf_r15 &= ~R15_FLAG_C; /* carry bit */
#endif
break;
case ERESTART:
@ -262,7 +281,11 @@ syscall(frame, code)
default:
bad:
frame->tf_r0 = error;
#ifdef __PROG32
frame->tf_spsr |= PSR_C_bit; /* carry bit */
#else
frame->tf_r15 |= R15_FLAG_C; /* carry bit */
#endif
break;
}
@ -284,7 +307,11 @@ child_return(arg)
struct trapframe *frame = p->p_addr->u_pcb.pcb_tf;
frame->tf_r0 = 0;
frame->tf_spsr &= ~PSR_C_bit; /* carry bit */
#ifdef __PROG32
frame->tf_spsr &= ~PSR_C_bit; /* carry bit */
#else
frame->tf_r15 &= ~R15_FLAG_C; /* carry bit */
#endif
userret(p);
#ifdef KTRACE

View File

@ -1,4 +1,4 @@
# $NetBSD: files.arm,v 1.49 2002/01/07 21:15:50 bjh21 Exp $
# $NetBSD: files.arm,v 1.50 2002/01/12 20:02:14 bjh21 Exp $
# temporary define to allow easy moving to ../arch/arm/arm32
defflag ARM32
@ -70,6 +70,7 @@ file arch/arm/arm/process_machdep.c
file arch/arm/arm/procfs_machdep.c procfs
file arch/arm/arm/sig_machdep.c
file arch/arm/arm/sigcode.S
file arch/arm/arm/syscall.c
file arch/arm/arm/undefined.c
# vectors.S gets included manually by Makefile.arm26, since it needs
# to be at the start of the text segment on those machines.
@ -89,7 +90,6 @@ file arch/arm/arm32/pmap.c arm32
file arch/arm/arm32/setcpsr.S arm32
file arch/arm/arm32/setstack.S arm32
file arch/arm/arm32/stubs.c arm32
file arch/arm/arm32/syscall.c arm32
file arch/arm/arm32/sys_machdep.c arm32
file arch/arm/arm32/vm_machdep.c arm32

View File

@ -1,4 +1,4 @@
/* $NetBSD: except.c,v 1.39 2001/12/21 22:56:17 bjh21 Exp $ */
/* $NetBSD: except.c,v 1.40 2002/01/12 20:02:15 bjh21 Exp $ */
/*-
* Copyright (c) 1998, 1999, 2000 Ben Harris
* All rights reserved.
@ -32,16 +32,14 @@
#include <sys/param.h>
__KERNEL_RCSID(0, "$NetBSD: except.c,v 1.39 2001/12/21 22:56:17 bjh21 Exp $");
__KERNEL_RCSID(0, "$NetBSD: except.c,v 1.40 2002/01/12 20:02:15 bjh21 Exp $");
#include "opt_cputypes.h"
#include "opt_ddb.h"
#include "opt_ktrace.h"
#include "opt_syscall_debug.h"
#include <sys/errno.h>
#include <sys/kernel.h>
#include <sys/syscall.h>
#include <sys/syslog.h>
#include <sys/systm.h>
#include <sys/user.h>
@ -103,155 +101,6 @@ swi_handler(struct trapframe *tf)
(*(void (*)(struct trapframe *))(curproc->p_emul->e_syscall))(tf);
}
void
syscall(struct trapframe *tf)
{
struct proc *p;
vaddr_t pc;
int code, nargs, nregargs, nextreg, nstkargs;
const struct sysent *sy;
register_t args[8]; /* XXX just enough for mmap... */
register_t rval[2], or15;
int error;
/* Enable interrupts if they were enabled before the trap. */
if ((tf->tf_r15 & R15_IRQ_DISABLE) == 0)
int_on();
uvmexp.traps++;
uvmexp.syscalls++;
p = curproc;
if (p == NULL)
p = &proc0;
if ((tf->tf_r15 & R15_MODE) == R15_MODE_USR)
p->p_addr->u_pcb.pcb_tf = tf;
if ((tf->tf_r15 & R15_MODE) != R15_MODE_USR) {
#ifdef DEBUG
printf("SWI:\n");
printregs(tf);
printf("pc -> ");
disassemble(tf->tf_r15 & R15_PC);
#endif
panic("SWI in kernel mode");
}
pc = tf->tf_r15 & R15_PC;
#ifdef DIAGNOSTIC
if ((*(u_int32_t *)pc & 0x0f000000) != 0x0f000000) {
disassemble(pc);
panic("SWI on non-SWI instruction");
}
#endif
/* Look up the system call and see if it's magic. */
code = *(register_t *)pc & 0x00ffffff;
switch (code) {
case SYS_syscall: /* Indirect system call. First arg is new code */
code = tf->tf_r0;
nregargs = 3; nextreg = 1;
break;
case SYS___syscall: /* As above, but quad_t arg */
if (p->p_emul->e_sysent == sysent) { /* NetBSD emulation */
code = tf->tf_r0; /* XXX assume little-endian */
nregargs = 2; nextreg = 2;
break;
}
/* FALLTHROUGH */
default:
nregargs = 4; nextreg = 0;
}
code &= (SYS_NSYSENT - 1);
sy = &p->p_emul->e_sysent[code];
nargs = sy->sy_argsize / sizeof(register_t);
nregargs = min(nregargs, nargs);
nstkargs = nargs - nregargs;
if (nregargs > 0)
bcopy(&tf->tf_r0 + nextreg, args,
nregargs * sizeof(register_t));
if (nstkargs > 0) {
error = copyin((caddr_t)tf->tf_r13, args + nregargs,
nstkargs * sizeof(register_t));
if (error) {
#ifdef SYSCALL_DEBUG
scdebug_call(p, code, (register_t *)args);
#endif
goto bad;
}
}
#ifdef SYSCALL_DEBUG
scdebug_call(p, code, args);
#endif
#ifdef KTRACE
if (KTRPOINT(p, KTR_SYSCALL))
ktrsyscall(p, code, nargs * sizeof(register_t), args);
#endif
rval[0] = 0;
rval[1] = tf->tf_r1;
/* Set return address */
or15 = tf->tf_r15;
tf->tf_r15 += 4;
error = sy->sy_call(p, args, rval);
switch (error) {
case 0:
tf->tf_r0 = rval[0];
tf->tf_r1 = rval[1];
tf->tf_r15 &= ~R15_FLAG_C;
break;
case ERESTART:
tf->tf_r15 = or15;
break;
case EJUSTRETURN:
/* nothing to do */
break;
default:
bad:
tf->tf_r0 = rval[0] = error;
tf->tf_r15 |= R15_FLAG_C;
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
}
/*
* Return from fork(2) in the child. This is effectively the tail end of
* a normal successful syscall return.
*/
void
child_return(void *arg)
{
struct proc *p = arg;
struct trapframe *tf;
tf = p->p_addr->u_pcb.pcb_tf;
tf->tf_r0 = 0;
tf->tf_r15 &= ~R15_FLAG_C;
#ifdef SYSCALL_DEBUG
scdebug_ret(p, SYS_fork /* XXX */, 0, &tf->tf_r0);
#endif
userret(p);
#ifdef KTRACE
if (KTRPOINT(p, KTR_SYSRET))
ktrsysret(p, SYS_fork /* XXX */, 0, tf->tf_r0);
#endif
}
void
prefetch_abort_handler(struct trapframe *tf)
{