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:
parent
7fed4934b8
commit
9fe68c4f64
@ -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
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user