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.
This commit is contained in:
Arne Welzel 2018-03-21 22:01:17 +01:00
parent b2ee0702ff
commit 8c5683006d
2 changed files with 48 additions and 1 deletions

View 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;
}

View File

@ -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