Implement a badaddr_read() routine which performs a load of the

specified size for the caller, and returns true or false indicating
whether or not a Data Abort occurred (i.e. the address was "bad").
This commit is contained in:
thorpej 2001-11-09 17:58:00 +00:00
parent d16c00cfb2
commit 42a10f6cd4
2 changed files with 83 additions and 2 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: fault.c,v 1.2 2001/09/05 16:17:35 matt Exp $ */
/* $NetBSD: fault.c,v 1.3 2001/11/09 17:58:01 thorpej Exp $ */
/*
* Copyright (c) 1994-1997 Mark Brinicombe.
@ -113,6 +113,73 @@ report_abort(prefix, fault_status, fault_address, fault_pc)
#endif
}
static __volatile int data_abort_expected;
static __volatile int data_abort_received;
int
badaddr_read(void *addr, size_t size, void *rptr)
{
u_long rcpt;
int rv;
/* Tell the Data Abort handler that we're expecting one. */
data_abort_received = 0;
data_abort_expected = 1;
cpu_drain_writebuf();
/* Read from the test address. */
switch (size) {
case sizeof(uint8_t):
__asm __volatile("ldrb %0, [%1]"
: "=r" (rcpt)
: "r" (addr));
break;
case sizeof(uint16_t):
__asm __volatile("ldrh %0, [%1]"
: "=r" (rcpt)
: "r" (addr));
break;
case sizeof(uint32_t):
__asm __volatile("ldr %0, [%1]"
: "=r" (rcpt)
: "r" (addr));
break;
default:
data_abort_expected = 0;
panic("badaddr: invalid size (%lu)\n", (u_long) size);
}
/* Disallow further Data Aborts. */
data_abort_expected = 0;
rv = data_abort_received;
data_abort_received = 0;
/* Copy the data back if no fault occurred. */
if (rptr != NULL && rv == 0) {
switch (size) {
case sizeof(uint8_t):
*(uint8_t *) rptr = rcpt;
break;
case sizeof(uint16_t):
*(uint16_t *) rptr = rcpt;
break;
case sizeof(uint32_t):
*(uint32_t *) rptr = rcpt;
break;
}
}
/* Return true if the address was invalid. */
return (rv);
}
/*
* void data_abort_handler(trapframe_t *frame)
*
@ -138,6 +205,17 @@ data_abort_handler(frame)
int error;
void *onfault;
/*
* If we were expecting a Data Abort, signal that we got
* one, adjust the PC to skip the faulting insn, and
* return.
*/
if (data_abort_expected) {
data_abort_received = 1;
frame->tf_pc += INSN_SIZE;
return;
}
/*
* Must get fault address and status from the CPU before
* re-enabling interrupts. (Interrupt handlers may take

View File

@ -1,4 +1,4 @@
/* $NetBSD: cpu.h,v 1.15 2001/07/10 20:43:57 bjh21 Exp $ */
/* $NetBSD: cpu.h,v 1.16 2001/11/09 17:58:00 thorpej Exp $ */
/*
* Copyright (c) 1994-1996 Mark Brinicombe.
@ -252,6 +252,9 @@ void userret __P((register struct proc *p));
/* machdep.h */
void bootsync __P((void));
/* fault.c */
int badaddr_read __P((void *, size_t, void *));
#endif /* !_LOCORE */
#endif /* _KERNEL */