Two batches of changes:
1: Cleanup of syscall() -- treat the arguments as an array of register_t throughout. This saves a few casts, and generally makes seeing what's going on easier. 2: Be a little more careful in the handling of data aborts on kernel addresses: don't use the kernel's map unless the access was actually from a kernel mode. This is how the arm32 data abort handler behaves.
This commit is contained in:
parent
186792c5b7
commit
58e80f030f
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: except.c,v 1.20 2000/12/23 15:12:54 bjh21 Exp $ */
|
||||
/* $NetBSD: except.c,v 1.21 2000/12/27 16:57:09 bjh21 Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 1998, 1999, 2000 Ben Harris
|
||||
* All rights reserved.
|
||||
|
@ -32,7 +32,7 @@
|
|||
|
||||
#include <sys/param.h>
|
||||
|
||||
__KERNEL_RCSID(0, "$NetBSD: except.c,v 1.20 2000/12/23 15:12:54 bjh21 Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: except.c,v 1.21 2000/12/27 16:57:09 bjh21 Exp $");
|
||||
|
||||
#include "opt_cputypes.h"
|
||||
#include "opt_ddb.h"
|
||||
|
@ -68,6 +68,7 @@ void syscall(struct trapframe *);
|
|||
static void data_abort_fixup(struct trapframe *);
|
||||
static vaddr_t data_abort_address(struct trapframe *);
|
||||
static vm_prot_t data_abort_atype(struct trapframe *);
|
||||
static boolean_t data_abort_usrmode(struct trapframe *);
|
||||
#ifdef DEBUG
|
||||
static void printregs(struct trapframe *tf);
|
||||
#endif
|
||||
|
@ -195,10 +196,9 @@ syscall(struct trapframe *tf)
|
|||
u_quad_t sticks;
|
||||
struct proc *p;
|
||||
vaddr_t pc;
|
||||
int code, regparams, nextreg;
|
||||
int code, nargs, nregargs, nextreg, nstkargs;
|
||||
const struct sysent *sy;
|
||||
size_t argsize, regargsize, stkargsize;
|
||||
char args[32]; /* XXX just enough for mmap... */
|
||||
register_t args[8]; /* XXX just enough for mmap... */
|
||||
register_t rval[2], or15;
|
||||
int error;
|
||||
|
||||
|
@ -238,38 +238,34 @@ syscall(struct trapframe *tf)
|
|||
switch (code) {
|
||||
case SYS_syscall: /* Indirect system call. First arg is new code */
|
||||
code = tf->tf_r0;
|
||||
regparams = 3; nextreg = 1;
|
||||
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 */
|
||||
regparams = 2; nextreg = 2;
|
||||
nregargs = 2; nextreg = 2;
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
regparams = 4; nextreg = 0;
|
||||
nregargs = 4; nextreg = 0;
|
||||
}
|
||||
if (code > p->p_emul->e_nsysent)
|
||||
sy = p->p_emul->e_sysent + p->p_emul->e_nosys;
|
||||
else
|
||||
sy = p->p_emul->e_sysent + code;
|
||||
|
||||
argsize = sy->sy_argsize;
|
||||
if (argsize > (regparams * sizeof(int))) {
|
||||
regargsize = regparams*sizeof(int);
|
||||
stkargsize = argsize - regargsize;
|
||||
} else {
|
||||
regargsize = argsize;
|
||||
stkargsize = 0;
|
||||
}
|
||||
nargs = sy->sy_argsize / sizeof(register_t);
|
||||
nregargs = min(nregargs, nargs);
|
||||
nstkargs = nargs - nregargs;
|
||||
|
||||
if (regargsize)
|
||||
bcopy((char *)tf + nextreg * sizeof(int), args, regargsize);
|
||||
if (nregargs > 0)
|
||||
bcopy((register_t *)tf + nextreg, args,
|
||||
nregargs * sizeof(register_t));
|
||||
|
||||
if (stkargsize) {
|
||||
error = copyin((caddr_t)tf->tf_r13, args + regargsize,
|
||||
stkargsize);
|
||||
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);
|
||||
|
@ -279,11 +275,11 @@ syscall(struct trapframe *tf)
|
|||
}
|
||||
|
||||
#ifdef SYSCALL_DEBUG
|
||||
scdebug_call(p, code, (register_t *)args);
|
||||
scdebug_call(p, code, args);
|
||||
#endif
|
||||
#ifdef KTRACE
|
||||
if (KTRPOINT(p, KTR_SYSCALL))
|
||||
ktrsyscall(p, code, argsize, (register_t *)args);
|
||||
ktrsyscall(p, code, nargs * sizeof(register_t), args);
|
||||
#endif
|
||||
|
||||
rval[0] = 0;
|
||||
|
@ -360,6 +356,7 @@ prefetch_abort_handler(struct trapframe *tf)
|
|||
int_on();
|
||||
|
||||
/*
|
||||
* XXX Not done yet:
|
||||
* Check if the page being requested is already present. If
|
||||
* so, call the undefined instruction handler instead (ARM3 ds
|
||||
* p15).
|
||||
|
@ -418,6 +415,7 @@ data_abort_handler(struct trapframe *tf)
|
|||
int ret;
|
||||
struct proc *p;
|
||||
vm_prot_t atype;
|
||||
boolean_t usrmode;
|
||||
vm_map_t map;
|
||||
struct pcb *curpcb;
|
||||
|
||||
|
@ -446,7 +444,11 @@ data_abort_handler(struct trapframe *tf)
|
|||
data_abort_fixup(tf);
|
||||
va = data_abort_address(tf);
|
||||
atype = data_abort_atype(tf);
|
||||
map = va >= VM_MIN_KERNEL_ADDRESS ? kernel_map : &p->p_vmspace->vm_map;
|
||||
usrmode = data_abort_usrmode(tf);
|
||||
if (!usrmode && va >= VM_MIN_KERNEL_ADDRESS)
|
||||
map = kernel_map;
|
||||
else
|
||||
map = &p->p_vmspace->vm_map;
|
||||
if (pmap_fault(map->pmap, va, atype))
|
||||
goto out;
|
||||
for (;;) {
|
||||
|
@ -661,6 +663,23 @@ data_abort_atype(struct trapframe *tf)
|
|||
#endif
|
||||
return VM_PROT_READ;
|
||||
}
|
||||
|
||||
/*
|
||||
* Work out what effective mode was in use when a data abort occurred.
|
||||
*/
|
||||
static boolean_t
|
||||
data_abort_usrmode(struct trapframe *tf)
|
||||
{
|
||||
register_t insn;
|
||||
|
||||
if ((tf->tf_r15 & R15_MODE) == R15_MODE_USR)
|
||||
return TRUE;
|
||||
insn = *(register_t *)(tf->tf_r15 & R15_PC);
|
||||
if ((insn & 0x0d200000) == 0x04200000)
|
||||
/* LDR[B]T and STR[B]T */
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
address_exception_handler(struct trapframe *tf)
|
||||
|
|
Loading…
Reference in New Issue