81 lines
2.4 KiB
Rust
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)
|
|
}
|