curiOS/kernel/tests/stack_overflow.rs

81 lines
2.4 KiB
Rust

#![no_main]
#![no_std]
#![feature(abi_x86_interrupt)]
use core::{cell::UnsafeCell, mem::offset_of};
use kernel::{
sync::LazyLock,
x86_64::{
gdt::{DF_STACK, GlobalDescriptorTable, RING0},
idt::{self, Entry, InterruptDescriptorTable},
},
};
pub static GDT: LazyLock<GlobalDescriptorTable> = LazyLock::new(GlobalDescriptorTable::new);
#[unsafe(export_name = "_start")]
pub extern "C" fn main() -> ! {
kernel::serial_println!("Hello, world!");
GDT.load();
kernel::serial_println!("[ok] GDT loaded");
extern "x86-interrupt" fn double_fault_handler(
_stack_frame: &mut idt::InterruptStackFrame,
_error_code: u64,
) -> ! {
kernel::serial_println!("[ok] Fault handler called");
kernel::testing::exit_qemu(kernel::testing::QemuExitCode::Success)
}
static IDT: LazyLock<InterruptDescriptorTable> = LazyLock::new(|| {
let mut idt = InterruptDescriptorTable::new_default();
idt.double_fault = unsafe {
Entry::new(
double_fault_handler as *const (),
offset_of!(GlobalDescriptorTable, kernel_code) as u16,
idt::EntryOptions::empty_interrupt_gate()
.with_present(true)
.with_privilege_level(RING0)
.with_interrupt_stack_table_index(kernel::x86_64::gdt::DF_STACK),
)
};
// this should fire #PF since we have it installed anways in the default idt
idt.page_fault = unsafe {
Entry::new(
double_fault_handler as *const (),
offset_of!(GlobalDescriptorTable, kernel_code) as u16,
idt::EntryOptions::empty_interrupt_gate()
.with_present(true)
.with_privilege_level(RING0)
.with_interrupt_stack_table_index(kernel::x86_64::gdt::PF_STACK),
)
};
idt
});
IDT.load();
stack_overflow();
panic!("Triggering a stack overflow to test double fault handling");
}
#[allow(unconditional_recursion)]
fn stack_overflow() {
stack_overflow(); // for each recursion, the return address is pushed
unsafe {
let cell = UnsafeCell::new(0);
cell.get().write_volatile(0);
}; // prevent tail recursion optimizations
}
#[panic_handler]
fn panic_thunk(info: &core::panic::PanicInfo) -> ! {
kernel::testing::test_panic_handler(info)
}