[Zion] Add a way to unwind the stack and recover from user-space faults.
This commit is contained in:
parent
8ceab2ad23
commit
941d7c8d59
|
@ -6,6 +6,7 @@ add_executable(zion
|
||||||
common/gdt.cpp
|
common/gdt.cpp
|
||||||
common/load_gdt.s
|
common/load_gdt.s
|
||||||
common/msr.cpp
|
common/msr.cpp
|
||||||
|
common/stack_unwind.cpp
|
||||||
debug/debug.cpp
|
debug/debug.cpp
|
||||||
interrupt/apic.cpp
|
interrupt/apic.cpp
|
||||||
interrupt/apic_timer.cpp
|
interrupt/apic_timer.cpp
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
#include "common/stack_unwind.h"
|
||||||
|
|
||||||
|
#include "debug/debug.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool IsValid(uint64_t* rbp) { return rbp && *rbp != kStackBaseSentinel; }
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void StackUnwind(uint64_t rbp) {
|
||||||
|
dbgln("-- Begin Stack --");
|
||||||
|
uint64_t* rbp_ptr = reinterpret_cast<uint64_t*>(rbp);
|
||||||
|
while (IsValid(rbp_ptr)) {
|
||||||
|
uint64_t rip = *(rbp_ptr + 1);
|
||||||
|
dbgln("RIP: {x}", rip);
|
||||||
|
rbp_ptr = reinterpret_cast<uint64_t*>(*rbp_ptr);
|
||||||
|
}
|
||||||
|
dbgln("-- End Stack --");
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
const uint64_t kStackBaseSentinel = 0xABBACDCD'12345678;
|
||||||
|
|
||||||
|
void StackUnwind(uint64_t rbp);
|
|
@ -3,6 +3,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "common/port.h"
|
#include "common/port.h"
|
||||||
|
#include "common/stack_unwind.h"
|
||||||
#include "debug/debug.h"
|
#include "debug/debug.h"
|
||||||
#include "interrupt/apic.h"
|
#include "interrupt/apic.h"
|
||||||
#include "interrupt/apic_timer.h"
|
#include "interrupt/apic_timer.h"
|
||||||
|
@ -69,15 +70,29 @@ struct InterruptFrame {
|
||||||
uint64_t ss;
|
uint64_t ss;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool IsUserSpace(uint64_t addr) { return (addr & (1l << 63)) == 0; }
|
||||||
|
|
||||||
extern "C" void isr_divide_by_zero();
|
extern "C" void isr_divide_by_zero();
|
||||||
extern "C" void interrupt_divide_by_zero(InterruptFrame* frame) {
|
extern "C" void interrupt_divide_by_zero(InterruptFrame* frame) {
|
||||||
dbgln("RIP: {x}", frame->rip);
|
dbgln("RIP: {x}", frame->rip);
|
||||||
|
StackUnwind(frame->rbp);
|
||||||
|
|
||||||
|
if (IsUserSpace(frame->rip)) {
|
||||||
|
gScheduler->CurrentProcess().Exit();
|
||||||
|
UNREACHABLE
|
||||||
|
}
|
||||||
panic("DIV0");
|
panic("DIV0");
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void isr_invalid_opcode();
|
extern "C" void isr_invalid_opcode();
|
||||||
extern "C" void interrupt_invalid_opcode(InterruptFrame* frame) {
|
extern "C" void interrupt_invalid_opcode(InterruptFrame* frame) {
|
||||||
dbgln("RIP: {x}", frame->rip);
|
dbgln("RIP: {x}", frame->rip);
|
||||||
|
StackUnwind(frame->rbp);
|
||||||
|
|
||||||
|
if (IsUserSpace(frame->rip)) {
|
||||||
|
gScheduler->CurrentProcess().Exit();
|
||||||
|
UNREACHABLE
|
||||||
|
}
|
||||||
panic("INVALID OPCODE");
|
panic("INVALID OPCODE");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +111,12 @@ extern "C" void interrupt_protection_fault(InterruptFrame* frame) {
|
||||||
dbgln("Index: {}", err >> 3);
|
dbgln("Index: {}", err >> 3);
|
||||||
dbgln("RIP: {x}", frame->rip);
|
dbgln("RIP: {x}", frame->rip);
|
||||||
dbgln("RSP: {x}", frame->rsp);
|
dbgln("RSP: {x}", frame->rsp);
|
||||||
|
StackUnwind(frame->rbp);
|
||||||
|
|
||||||
|
if (IsUserSpace(frame->rip)) {
|
||||||
|
gScheduler->CurrentProcess().Exit();
|
||||||
|
UNREACHABLE
|
||||||
|
}
|
||||||
panic("GP");
|
panic("GP");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,11 +153,23 @@ extern "C" void interrupt_page_fault(InterruptFrame* frame) {
|
||||||
|
|
||||||
dbgln("rip: {x}", frame->rip);
|
dbgln("rip: {x}", frame->rip);
|
||||||
dbgln("addr: {x}", frame->cr2);
|
dbgln("addr: {x}", frame->cr2);
|
||||||
|
StackUnwind(frame->rbp);
|
||||||
|
|
||||||
|
if (IsUserSpace(frame->rip)) {
|
||||||
|
gScheduler->CurrentProcess().Exit();
|
||||||
|
UNREACHABLE
|
||||||
|
}
|
||||||
|
|
||||||
panic("PF");
|
panic("PF");
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void isr_fpe_fault();
|
extern "C" void isr_fpe_fault();
|
||||||
extern "C" void interrupt_fpe_fault(InterruptFrame* frame) {
|
extern "C" void interrupt_fpe_fault(InterruptFrame* frame) {
|
||||||
|
dbgln("Floating point exception.");
|
||||||
|
if (IsUserSpace(frame->rip)) {
|
||||||
|
gScheduler->CurrentProcess().Exit();
|
||||||
|
UNREACHABLE
|
||||||
|
}
|
||||||
panic("Floating point exception");
|
panic("Floating point exception");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "object/thread.h"
|
#include "object/thread.h"
|
||||||
|
|
||||||
#include "common/gdt.h"
|
#include "common/gdt.h"
|
||||||
|
#include "common/stack_unwind.h"
|
||||||
#include "debug/debug.h"
|
#include "debug/debug.h"
|
||||||
#include "memory/kernel_vmm.h"
|
#include "memory/kernel_vmm.h"
|
||||||
#include "memory/paging_util.h"
|
#include "memory/paging_util.h"
|
||||||
|
@ -71,6 +72,7 @@ void Thread::Init() {
|
||||||
// will emit movaps calls to non-16-bit-aligned stack
|
// will emit movaps calls to non-16-bit-aligned stack
|
||||||
// addresses.
|
// addresses.
|
||||||
rsp -= 0x8;
|
rsp -= 0x8;
|
||||||
|
*reinterpret_cast<uint64_t*>(rsp) = kStackBaseSentinel;
|
||||||
SetRsp0(rsp0_start_);
|
SetRsp0(rsp0_start_);
|
||||||
jump_user_space(rip_, rsp, arg1_, arg2_);
|
jump_user_space(rip_, rsp, arg1_, arg2_);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ jump_user_space:
|
||||||
mov %ax, %fs
|
mov %ax, %fs
|
||||||
mov %ax, %gs
|
mov %ax, %gs
|
||||||
|
|
||||||
|
mov %rsi, %rbp
|
||||||
pushq $0x23 # ss
|
pushq $0x23 # ss
|
||||||
pushq %rsi
|
pushq %rsi
|
||||||
pushq $0x202 # Bit 9 enables interrupts.
|
pushq $0x202 # Bit 9 enables interrupts.
|
||||||
|
|
Loading…
Reference in New Issue