Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/arm Overhaul arm32's abort handlers:
details: https://anonhg.NetBSD.org/src/rev/b129322bdfe5
branches: trunk
changeset: 554669:b129322bdfe5
user: scw <scw%NetBSD.org@localhost>
date: Fri Oct 31 16:30:15 2003 +0000
description:
Overhaul arm32's abort handlers:
- Assume a permission fault is always the result of an attempted
write, so no need to disassemble the opcode.
(as discussed with Richard Earnshaw/Jason Thorpe a week or two ago)
- Split out non-MMU data aborts into separate functions, and deal
correctly with XScale imprecise aborts. Specifically, the old code
made no attempt to handle the double abort faults which can occur
as a result of two consecutive external (imprecise) aborts. This
was easy to provoke by read(2)ing from a /dev/mem offset which caused
an external abort. With the old code, this would bring the system
down instantly, with little clue as to why. (hint: tf_spsr held
PSR_ABT32_MODE...)
- Re-write badaddr_read() to use pcb_onfault instead of adding extra
overhead to data_abort_handler(). A side effect of this is that it
now benefits from the XScale double abort recovery.
- Invoke the cpu-specific prefetch/data abort fixup routines only if
the host cpu actually needs it. On other cpus, the code is optimised
away.
- Sprinkle __predict_{false,true} in all the right places.
- G/C some excess debugging baggage.
diffstat:
sys/arch/arm/arm/bcopyinout.S | 90 +++-
sys/arch/arm/arm32/exception.S | 47 +-
sys/arch/arm/arm32/fault.c | 1030 ++++++++++++++++++++-------------------
sys/arch/arm/include/armreg.h | 4 +-
4 files changed, 646 insertions(+), 525 deletions(-)
diffs (truncated from 1399 to 300 lines):
diff -r a2ab9d2099da -r b129322bdfe5 sys/arch/arm/arm/bcopyinout.S
--- a/sys/arch/arm/arm/bcopyinout.S Fri Oct 31 14:38:44 2003 +0000
+++ b/sys/arch/arm/arm/bcopyinout.S Fri Oct 31 16:30:15 2003 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: bcopyinout.S,v 1.11 2003/10/13 21:22:40 scw Exp $ */
+/* $NetBSD: bcopyinout.S,v 1.12 2003/10/31 16:30:15 scw Exp $ */
/*
* Copyright (c) 2002 Wasabi Systems, Inc.
@@ -45,7 +45,7 @@
#include "bcopyinout_xscale.S"
#else
-RCSID("$NetBSD: bcopyinout.S,v 1.11 2003/10/13 21:22:40 scw Exp $")
+RCSID("$NetBSD: bcopyinout.S,v 1.12 2003/10/31 16:30:15 scw Exp $")
.text
.align 0
@@ -712,3 +712,89 @@
mov pc, lr
#endif /* !__XSCALE__ */
+
+#ifdef __PROG32
+/*
+ * int badaddr_read_1(const uint8_t *src, uint8_t *dest)
+ *
+ * Copies a single 8-bit value from src to dest, returning 0 on success,
+ * else EFAULT if a page fault occurred.
+ */
+ENTRY(badaddr_read_1)
+#ifdef MULTIPROCESSOR
+ /* XXX Probably not appropriate for non-Hydra SMPs */
+ stmfd sp!, {r0-r1, r14}
+ bl _C_LABEL(cpu_number)
+ ldr r2, .Lcpu_info
+ ldr r2, [r2, r0, lsl #2]
+ ldr r2, [r2, #CI_CURPCB]
+ ldmfd sp!, {r0-r1, r14}
+#else
+ ldr r2, .Lcurpcb
+ ldr r2, [r2]
+#endif
+ ldr ip, [r2, #PCB_ONFAULT]
+ adr r3, 1f
+ str r3, [r2, #PCB_ONFAULT]
+ ldrb r3, [r0]
+ strb r3, [r1]
+ mov r0, #0 /* No fault */
+1: str ip, [r2, #PCB_ONFAULT]
+ mov pc, lr
+
+/*
+ * int badaddr_read_2(const uint16_t *src, uint16_t *dest)
+ *
+ * Copies a single 16-bit value from src to dest, returning 0 on success,
+ * else EFAULT if a page fault occurred.
+ */
+ENTRY(badaddr_read_2)
+#ifdef MULTIPROCESSOR
+ /* XXX Probably not appropriate for non-Hydra SMPs */
+ stmfd sp!, {r0-r1, r14}
+ bl _C_LABEL(cpu_number)
+ ldr r2, .Lcpu_info
+ ldr r2, [r2, r0, lsl #2]
+ ldr r2, [r2, #CI_CURPCB]
+ ldmfd sp!, {r0-r1, r14}
+#else
+ ldr r2, .Lcurpcb
+ ldr r2, [r2]
+#endif
+ ldr ip, [r2, #PCB_ONFAULT]
+ adr r3, 1f
+ str r3, [r2, #PCB_ONFAULT]
+ ldrh r3, [r0]
+ strh r3, [r1]
+ mov r0, #0 /* No fault */
+1: str ip, [r2, #PCB_ONFAULT]
+ mov pc, lr
+
+/*
+ * int badaddr_read_4(const uint32_t *src, uint32_t *dest)
+ *
+ * Copies a single 32-bit value from src to dest, returning 0 on success,
+ * else EFAULT if a page fault occurred.
+ */
+ENTRY(badaddr_read_4)
+#ifdef MULTIPROCESSOR
+ /* XXX Probably not appropriate for non-Hydra SMPs */
+ stmfd sp!, {r0-r1, r14}
+ bl _C_LABEL(cpu_number)
+ ldr r2, .Lcpu_info
+ ldr r2, [r2, r0, lsl #2]
+ ldr r2, [r2, #CI_CURPCB]
+ ldmfd sp!, {r0-r1, r14}
+#else
+ ldr r2, .Lcurpcb
+ ldr r2, [r2]
+#endif
+ ldr ip, [r2, #PCB_ONFAULT]
+ adr r3, 1f
+ str r3, [r2, #PCB_ONFAULT]
+ ldr r3, [r0]
+ str r3, [r1]
+ mov r0, #0 /* No fault */
+1: str ip, [r2, #PCB_ONFAULT]
+ mov pc, lr
+#endif /* __PROG32 */
diff -r a2ab9d2099da -r b129322bdfe5 sys/arch/arm/arm32/exception.S
--- a/sys/arch/arm/arm32/exception.S Fri Oct 31 14:38:44 2003 +0000
+++ b/sys/arch/arm/arm32/exception.S Fri Oct 31 16:30:15 2003 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: exception.S,v 1.12 2003/10/30 08:57:24 scw Exp $ */
+/* $NetBSD: exception.S,v 1.13 2003/10/31 16:30:15 scw Exp $ */
/*
* Copyright (c) 1994-1997 Mark Brinicombe.
@@ -57,24 +57,6 @@
AST_ALIGNMENT_FAULT_LOCALS
/*
- * General exception exit handler
- *
- * It exits straight away if not returning to USR mode.
- * This loops around delivering any pending ASTs.
- * Interrupts are disabled at suitable points to avoid ASTs
- * being posted between testing and exit to user mode.
- *
- * This function uses PULLFRAMEFROMSVCANDEXIT and
- * DO_AST_AND_RESTORE_ALIGNMENT_FAULTS thus should
- * only be called if the exception handler used PUSHFRAMEINSVC
- * followed by ENABLE_ALIGNMENT_FAULTS.
- */
-
-exception_exit:
- DO_AST_AND_RESTORE_ALIGNMENT_FAULTS
- PULLFRAMEFROMSVCANDEXIT
-
-/*
* reset_entry:
*
* Handler for Reset exception.
@@ -110,6 +92,10 @@
* Handler for the Prefetch Abort exception.
*/
ASENTRY_NP(prefetch_abort_entry)
+#ifdef __XSCALE__
+ nop /* Make absolutely sure any pending */
+ nop /* imprecise aborts have occurred. */
+#endif
sub lr, lr, #0x00000004 /* Adjust the lr */
PUSHFRAMEINSVC
@@ -144,6 +130,10 @@
* Handler for the Data Abort exception.
*/
ASENTRY_NP(data_abort_entry)
+#ifdef __XSCALE__
+ nop /* Make absolutely sure any pending */
+ nop /* imprecise aborts have occurred. */
+#endif
sub lr, lr, #0x00000008 /* Adjust the lr */
PUSHFRAMEINSVC /* Push trap frame and switch */
@@ -193,6 +183,25 @@
.balign 4
/*
+ * General exception exit handler
+ * (Placed here to be within range of all the references to it)
+ *
+ * It exits straight away if not returning to USR mode.
+ * This loops around delivering any pending ASTs.
+ * Interrupts are disabled at suitable points to avoid ASTs
+ * being posted between testing and exit to user mode.
+ *
+ * This function uses PULLFRAMEFROMSVCANDEXIT and
+ * DO_AST_AND_RESTORE_ALIGNMENT_FAULTS thus should
+ * only be called if the exception handler used PUSHFRAMEINSVC
+ * followed by ENABLE_ALIGNMENT_FAULTS.
+ */
+
+exception_exit:
+ DO_AST_AND_RESTORE_ALIGNMENT_FAULTS
+ PULLFRAMEFROMSVCANDEXIT
+
+/*
* undefined_entry:
*
* Handler for the Undefined Instruction exception.
diff -r a2ab9d2099da -r b129322bdfe5 sys/arch/arm/arm32/fault.c
--- a/sys/arch/arm/arm32/fault.c Fri Oct 31 14:38:44 2003 +0000
+++ b/sys/arch/arm/arm32/fault.c Fri Oct 31 16:30:15 2003 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: fault.c,v 1.38 2003/10/25 19:44:42 scw Exp $ */
+/* $NetBSD: fault.c,v 1.39 2003/10/31 16:30:15 scw Exp $ */
/*
* Copyright 2003 Wasabi Systems, Inc.
@@ -79,10 +79,9 @@
#include "opt_ddb.h"
#include "opt_kgdb.h"
-#include "opt_pmap_debug.h"
#include <sys/types.h>
-__KERNEL_RCSID(0, "$NetBSD: fault.c,v 1.38 2003/10/25 19:44:42 scw Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fault.c,v 1.39 2003/10/31 16:30:15 scw Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -118,360 +117,177 @@
int last_fault_code; /* For the benefit of pmap_fault_fixup() */
#endif
-static void report_abort __P((const char *, u_int, u_int, u_int));
-
-/* Abort code */
-
-/* Define text descriptions of the different aborts */
+#if defined(CPU_ARM3) || defined(CPU_ARM6) || \
+ defined(CPU_ARM7) || defined(CPU_ARM7TDMI)
+/* These CPUs may need data/prefetch abort fixups */
+#define CPU_ABORT_FIXUP_REQUIRED
+#endif
-static const char *aborts[16] = {
- "Write buffer fault",
- "Alignment fault",
- "Write buffer fault",
- "Alignment fault",
- "Bus error (LF section)",
- "Translation fault (section)",
- "Bus error (page)",
- "Translation fault (page)",
- "Bus error (section)",
- "Domain error (section)",
- "Bus error (page)",
- "Domain error (page)",
- "Bus error trans (L1)",
- "Permission error (section)",
- "Bus error trans (L2)",
- "Permission error (page)"
+struct data_abort {
+ int (*func)(trapframe_t *, u_int, u_int, struct lwp *, ksiginfo_t *);
+ const char *desc;
};
-static void
-report_abort(prefix, fault_status, fault_address, fault_pc)
- const char *prefix;
- u_int fault_status;
- u_int fault_address;
- u_int fault_pc;
+static int dab_fatal(trapframe_t *, u_int, u_int, struct lwp *, ksiginfo_t *);
+static int dab_align(trapframe_t *, u_int, u_int, struct lwp *, ksiginfo_t *);
+static int dab_buserr(trapframe_t *, u_int, u_int, struct lwp *, ksiginfo_t *);
+
+static const struct data_abort data_aborts[] = {
+ {dab_fatal, "Vector Exception"},
+ {dab_align, "Alignment Fault 1"},
+ {dab_fatal, "Terminal Exception"},
+ {dab_align, "Alignment Fault 3"},
+ {dab_buserr, "External Linefetch Abort (S)"},
+ {NULL, "Translation Fault (S)"},
+ {dab_buserr, "External Linefetch Abort (P)"},
+ {NULL, "Translation Fault (P)"},
+ {dab_buserr, "External Non-Linefetch Abort (S)"},
+ {NULL, "Domain Fault (S)"},
+ {dab_buserr, "External Non-Linefetch Abort (P)"},
+ {NULL, "Domain Fault (P)"},
+ {dab_buserr, "External Translation Abort (L1)"},
+ {NULL, "Permission Fault (S)"},
+ {dab_buserr, "External Translation Abort (L2)"},
+ {NULL, "Permission Fault (P)"}
+};
+
+/* Determine if a fault came from user mode */
+#define TRAP_USERMODE(tf) ((tf->tf_spsr & PSR_MODE) == PSR_USR32_MODE)
+
+/* Determine if 'x' is a permission fault */
+#define IS_PERMISSION_FAULT(x) \
+ (((1 << ((x) & FAULT_TYPE_MASK)) & \
+ ((1 << FAULT_PERM_P) | (1 << FAULT_PERM_S))) != 0)
+
+#if 0
+/* maybe one day we'll do emulations */
+#define TRAPSIGNAL(l,k) (*(l)->l_proc->p_emul->e_trapsignal)((l), (k))
+#else
+#define TRAPSIGNAL(l,k) trapsignal((l), (k))
+#endif
+
+static __inline void
+call_trapsignal(struct lwp *l, ksiginfo_t *ksi)
{
-#ifndef DEBUG
- if (prefix == NULL) {
-#endif
- if (prefix)
- printf("%s ", prefix);
Home |
Main Index |
Thread Index |
Old Index