From: Arne Welzel Date: Wed, 21 Mar 2018 21:01:17 +0000 (+0100) Subject: kernel/arm: do not treat all data aborts as pagefaults X-Git-Url: http://zhaoyanbai.com/repos/?a=commitdiff_plain;h=7c3424c244a54c191c45d2fcfe666588cbf6d11a;p=minix.git kernel/arm: do not treat all data aborts as pagefaults 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 --- diff --git a/minix/kernel/arch/earm/exception.c b/minix/kernel/arch/earm/exception.c index 19c400822..1930b24ac 100644 --- a/minix/kernel/arch/earm/exception.c +++ b/minix/kernel/arch/earm/exception.c @@ -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; } diff --git a/minix/kernel/arch/earm/include/archconst.h b/minix/kernel/arch/earm/include/archconst.h index 8d2edf967..b52fe6a59 100644 --- a/minix/kernel/arch/earm/include/archconst.h +++ b/minix/kernel/arch/earm/include/archconst.h @@ -21,6 +21,25 @@ #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