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
This commit is contained in:
Arne Welzel 2018-03-21 22:01:17 +01:00 committed by Lionel Sambuc
parent a27e58e1f7
commit 7c3424c244
2 changed files with 48 additions and 1 deletions

View File

@ -109,6 +109,34 @@ static void pagefault( struct proc *pr,
return; 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, static void inkernel_disaster(struct proc *saved_proc,
reg_t *saved_lr, struct ex_s *ep, reg_t *saved_lr, struct ex_s *ep,
int is_nested) int is_nested)
@ -171,7 +199,7 @@ void exception_handler(int is_nested, reg_t *saved_lr, int vector)
} }
if (vector == DATA_ABORT_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; return;
} }

View File

@ -21,6 +21,25 @@
#define INTERRUPT_VECTOR 6 #define INTERRUPT_VECTOR 6
#define FAST_INTERRUPT_VECTOR 7 #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 * defines how many bytes are reserved at the top of the kernel stack for global
* information like currently scheduled process or current cpu id * information like currently scheduled process or current cpu id