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