]> Zhao Yanbai Git Server - minix.git/commitdiff
kernel/arm: do not treat all data aborts as pagefaults 14/3514/1
authorArne Welzel <arne.welzel@gmail.com>
Wed, 21 Mar 2018 21:01:17 +0000 (22:01 +0100)
committerLionel Sambuc <lionel.sambuc@gmail.com>
Sun, 25 Mar 2018 09:22:35 +0000 (11:22 +0200)
For now, distinguish alignment, translation and permission faults.
The first kind of faults cause the kernel to send SIGBUS to the
process causing the fault, the latter two are forwarded to `vm' as
pagefaults. Previously, any data abort was forwarded to `vm' as
a pagefault, resulting in hard to debug issue #104.

Any unhandled fault status results in a disaster. This seems
better than naively hoping `vm' can do something about it.

Change-Id: I526f575bb2681e087e20fd49c5c0846cdd450c31

minix/kernel/arch/earm/exception.c
minix/kernel/arch/earm/include/archconst.h

index 19c400822bdc7975c3faa7cf7ddaf1ac72313848..1930b24accc26e9531d42ff73b1193848d585f15 100644 (file)
@@ -109,6 +109,34 @@ static void pagefault( struct proc *pr,
        return;
 }
 
+static void
+data_abort(int is_nested, struct proc *pr, reg_t *saved_lr,
+                      struct ex_s *ep, u32_t dfar, u32_t dfsr)
+{
+       /* Extract fault status bit [0:3, 10] from DFSR */
+       u32_t fs = dfsr & 0x0F;
+       fs |= ((dfsr >> 6) & 0x10);
+       if (is_alignment_fault(fs)) {
+               if (is_nested) {
+                       printf("KERNEL: alignment fault dfar=0x%lx\n", dfar);
+                       inkernel_disaster(pr, saved_lr, ep, is_nested);
+               }
+               /* Send SIGBUS to violating process. */
+               cause_sig(proc_nr(pr), SIGBUS);
+               return;
+       } else if (is_translation_fault(fs) || is_permission_fault(fs)) {
+               /* Ask VM to handle translation and permission faults as pagefaults */
+               pagefault(pr, saved_lr, is_nested, dfar, dfsr);
+               return;
+       } else {
+               /* Die on unknown things... */
+               printf("KERNEL: unhandled data abort dfar=0x%lx dfsr=0x%lx "
+                       "fs=0x%lx is_nested=%d\n", dfar, dfsr, fs, is_nested);
+               panic("unhandled data abort");
+       }
+       NOT_REACHABLE;
+}
+
 static void inkernel_disaster(struct proc *saved_proc,
        reg_t *saved_lr, struct ex_s *ep,
        int is_nested)
@@ -171,7 +199,7 @@ void exception_handler(int is_nested, reg_t *saved_lr, int vector)
   }
 
   if (vector == DATA_ABORT_VECTOR) {
-       pagefault(saved_proc, saved_lr, is_nested, read_dfar(), read_dfsr());
+       data_abort(is_nested, saved_proc, saved_lr, ep, read_dfar(), read_dfsr());
        return;
   }
 
index 8d2edf967c27c48746d0ba2d7b18ab2649f1188c..b52fe6a591c1a6f2135fe25c0ab673c985e0239f 100644 (file)
 #define INTERRUPT_VECTOR              6
 #define FAST_INTERRUPT_VECTOR         7
 
+
+/* Known fault status bits */
+#define DFSR_FS_ALIGNMENT_FAULT                        0x01
+#define DFSR_FS_TRANSLATION_FAULT_PAGE         0x07
+#define DFSR_FS_TRANSLATION_FAULT_SECTION      0x05
+#define DFSR_FS_PERMISSION_FAULT_PAGE          0x0F
+#define DFSR_FS_PERMISSION_FAULT_SECTION       0x0D
+
+#define is_alignment_fault(fault_status) \
+       ((fault_status) == DFSR_FS_ALIGNMENT_FAULT)
+
+#define is_translation_fault(fault_status) \
+       (((fault_status) == DFSR_FS_TRANSLATION_FAULT_PAGE) \
+               || ((fault_status) == DFSR_FS_TRANSLATION_FAULT_SECTION))
+
+#define is_permission_fault(fault_status) \
+       (((fault_status) == DFSR_FS_PERMISSION_FAULT_PAGE) \
+               || ((fault_status) == DFSR_FS_PERMISSION_FAULT_SECTION))
+
 /*
  * defines how many bytes are reserved at the top of the kernel stack for global
  * information like currently scheduled process or current cpu id