kernel/arm: implement prefetch abort handler
Change-Id: I39c330a44ad36ede41c7727017dd733d07288be9 Reviewed-on: https://review.haiku-os.org/c/haiku/+/4983 Tested-by: Commit checker robot <[email protected]> Reviewed-by: Fredrik Holmqvist <[email protected]>
This commit is contained in:
committed by
Fredrik Holmqvist
parent
883858e60b
commit
4c6e7a4bca
@@ -11,6 +11,9 @@
|
|||||||
|
|
||||||
#define SPINLOCK_PAUSE() do {} while (false)
|
#define SPINLOCK_PAUSE() do {} while (false)
|
||||||
|
|
||||||
|
#define CPSR_MODE_MASK 0x1f
|
||||||
|
#define CPSR_MODE_USR 0x10
|
||||||
|
|
||||||
#define FSR_WNR 0x800
|
#define FSR_WNR 0x800
|
||||||
|
|
||||||
#endif /* _SYSTEM_ARCH_ARM_DEFS_H */
|
#endif /* _SYSTEM_ARCH_ARM_DEFS_H */
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ FUNCTION(arm_prefetch_abort):
|
|||||||
nop /* Make absolutely sure any pending */
|
nop /* Make absolutely sure any pending */
|
||||||
nop /* imprecise aborts have occurred. */
|
nop /* imprecise aborts have occurred. */
|
||||||
#endif
|
#endif
|
||||||
add lr, lr, #4
|
sub lr, lr, #4
|
||||||
PUSHFRAMEINSVC
|
PUSHFRAMEINSVC
|
||||||
|
|
||||||
mov r0, sp
|
mov r0, sp
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ extern "C" void
|
|||||||
arch_arm_data_abort(struct iframe *frame)
|
arch_arm_data_abort(struct iframe *frame)
|
||||||
{
|
{
|
||||||
Thread *thread = thread_get_current_thread();
|
Thread *thread = thread_get_current_thread();
|
||||||
bool isUser = (frame->spsr & 0x1f) == 0x10;
|
bool isUser = (frame->spsr & CPSR_MODE_MASK) == CPSR_MODE_USR;
|
||||||
int32 fsr = arm_get_fsr();
|
int32 fsr = arm_get_fsr();
|
||||||
addr_t far = arm_get_far();
|
addr_t far = arm_get_far();
|
||||||
bool isWrite = (fsr & FSR_WNR) == FSR_WNR;
|
bool isWrite = (fsr & FSR_WNR) == FSR_WNR;
|
||||||
@@ -365,12 +365,80 @@ arch_arm_data_abort(struct iframe *frame)
|
|||||||
|
|
||||||
|
|
||||||
extern "C" void
|
extern "C" void
|
||||||
arch_arm_prefetch_abort(struct iframe *iframe)
|
arch_arm_prefetch_abort(struct iframe *frame)
|
||||||
{
|
{
|
||||||
print_iframe("Prefetch Abort", iframe);
|
Thread *thread = thread_get_current_thread();
|
||||||
IFrameScope scope(iframe);
|
bool isUser = (frame->spsr & CPSR_MODE_MASK) == CPSR_MODE_USR;
|
||||||
|
addr_t newip = 0;
|
||||||
|
|
||||||
panic("not handled!");
|
#ifdef TRACE_ARCH_INT
|
||||||
|
print_iframe("Prefetch Abort", frame);
|
||||||
|
dprintf("thread: %s\n", thread->name);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
IFrameScope scope(frame);
|
||||||
|
|
||||||
|
if (debug_debugger_running()) {
|
||||||
|
// If this CPU or this thread has a fault handler, we're allowed to be
|
||||||
|
// here.
|
||||||
|
if (thread != NULL) {
|
||||||
|
cpu_ent* cpu = &gCPU[smp_get_current_cpu()];
|
||||||
|
|
||||||
|
if (cpu->fault_handler != 0) {
|
||||||
|
debug_set_page_fault_info(frame->pc, frame->pc, 0);
|
||||||
|
frame->svc_sp = cpu->fault_handler_stack_pointer;
|
||||||
|
frame->pc = cpu->fault_handler;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thread->fault_handler != 0) {
|
||||||
|
kprintf("ERROR: thread::fault_handler used in kernel "
|
||||||
|
"debugger!\n");
|
||||||
|
debug_set_page_fault_info(frame->pc, frame->pc, 0);
|
||||||
|
frame->pc = reinterpret_cast<uintptr_t>(thread->fault_handler);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, not really
|
||||||
|
panic("page fault in debugger without fault handler! Prefetch abort at %p\n",
|
||||||
|
(void *)frame->pc);
|
||||||
|
return;
|
||||||
|
} else if ((frame->spsr & (1 << 7)) != 0) {
|
||||||
|
// interrupts disabled
|
||||||
|
|
||||||
|
// If a page fault handler is installed, we're allowed to be here.
|
||||||
|
uintptr_t handler = reinterpret_cast<uintptr_t>(thread->fault_handler);
|
||||||
|
if (thread && thread->fault_handler != 0) {
|
||||||
|
if (frame->pc != handler) {
|
||||||
|
frame->pc = handler;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The fault happened at the fault handler address. This is a
|
||||||
|
// certain infinite loop.
|
||||||
|
panic("page fault, interrupts disabled, fault handler loop. "
|
||||||
|
"Prefetch abort at %p\n", (void*)frame->pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are not running the kernel startup the page fault was not
|
||||||
|
// allowed to happen and we must panic.
|
||||||
|
panic("page fault, but interrupts were disabled. Prefetch abort at %p\n",
|
||||||
|
(void *)frame->pc);
|
||||||
|
return;
|
||||||
|
} else if (thread != NULL && thread->page_faults_allowed < 1) {
|
||||||
|
panic("page fault not allowed at this place. Prefetch abort at %p\n",
|
||||||
|
(void *)frame->pc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
enable_interrupts();
|
||||||
|
|
||||||
|
vm_page_fault(frame->pc, frame->pc, false, true, isUser, &newip);
|
||||||
|
|
||||||
|
if (newip != 0) {
|
||||||
|
frame->pc = newip;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user