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