From 8efd5fe20b7704031636903b19c57c1848e74fbd Mon Sep 17 00:00:00 2001 From: Rishi Gupta Date: Tue, 6 Oct 2026 14:17:10 +0530 Subject: [PATCH 1/7] feat: add divide-error exception handler --- kernel/src/arch/x86_64/idt.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/kernel/src/arch/x86_64/idt.rs b/kernel/src/arch/x86_64/idt.rs index 8e9d94d..daf065e 100644 --- a/kernel/src/arch/x86_64/idt.rs +++ b/kernel/src/arch/x86_64/idt.rs @@ -12,6 +12,7 @@ static IDT: Once = Once::new(); pub fn init() { let idt = IDT.call_once(|| { let mut idt = InterruptDescriptorTable::new(); + idt.divide_error.set_handler_fn(divide_error_handler); idt.breakpoint.set_handler_fn(breakpoint_handler); idt.invalid_opcode.set_handler_fn(invalid_opcode_handler); idt @@ -29,6 +30,34 @@ pub fn self_test() { x86_64::instructions::interrupts::int3(); } +/// Trigger a divide-error exception for the optional integration self-test. +/// +/// This deliberately executes an integer divide by zero. It must only be +/// called after the IDT has been loaded and only from the self-test path. +#[cfg(feature = "divide-error-self-test")] +pub fn divide_error_self_test() { + // SAFETY: This inline assembly intentionally triggers #DE to verify the + // installed handler. The feature is opt-in and the handler terminates + // through the kernel panic path instead of returning to this instruction. + unsafe { + core::arch::asm!( + "div rcx", + inlateout("rax") 1u64 => _, + inlateout("rdx") 0u64 => _, + in("rcx") 0u64, + options(nostack), + ); + } +} + +/// Handle integer divide errors as a controlled kernel failure. +extern "x86-interrupt" fn divide_error_handler(frame: InterruptStackFrame) -> ! { + crate::logger::error("DIVIDE ERROR exception (#DE)"); + crate::logger::info_u64("Divide error RIP", frame.instruction_pointer.as_u64()); + crate::logger::info_u64("Divide error CS", frame.code_segment.bits() as u64); + panic!("divide error exception"); +} + /// Handle INT3/#BP without modifying the saved execution state. extern "x86-interrupt" fn breakpoint_handler(frame: InterruptStackFrame) { crate::logger::info("BREAKPOINT exception (#BP)"); @@ -58,9 +87,11 @@ mod tests { #[test] fn idt_registers_exception_handlers() { let mut idt = InterruptDescriptorTable::new(); + idt.divide_error.set_handler_fn(divide_error_handler); idt.breakpoint.set_handler_fn(breakpoint_handler); idt.invalid_opcode.set_handler_fn(invalid_opcode_handler); + assert_ne!(idt.divide_error.handler_addr().as_u64(), 0); assert_ne!(idt.breakpoint.handler_addr().as_u64(), 0); assert_ne!(idt.invalid_opcode.handler_addr().as_u64(), 0); } From c19519798c185e72309b3c4a2c7033f98cded082 Mon Sep 17 00:00:00 2001 From: Rishi Gupta Date: Tue, 6 Oct 2026 14:17:12 +0530 Subject: [PATCH 2/7] feat: add divide-error self-test feature --- kernel/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 871c5b9..0f39443 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -6,6 +6,7 @@ license = "MIT OR Apache-2.0" [features] exception-self-test = [] +divide-error-self-test = [] [dependencies] bootloader_api = "0.11.17" From 2dc7e0d7dd2e159726e398f3f89e364283887ea0 Mon Sep 17 00:00:00 2001 From: Rishi Gupta Date: Tue, 6 Oct 2026 14:17:16 +0530 Subject: [PATCH 3/7] feat: wire divide-error self-test --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index df93081..daccb14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = ["kernel"] [features] exception-self-test = ["kernel/exception-self-test"] +divide-error-self-test = ["kernel/divide-error-self-test"] [package] name = "rustalis" From 4504d805db2177d03fd73b1050309d945794199b Mon Sep 17 00:00:00 2001 From: Rishi Gupta Date: Tue, 6 Oct 2026 14:17:18 +0530 Subject: [PATCH 4/7] test: add divide-error boot self-test --- kernel/src/main.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 7703ec0..c120cc5 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -25,6 +25,12 @@ fn kernel_main(boot_info: &'static mut BootInfo) -> ! { arch::x86_64::idt::self_test(); logger::info("Breakpoint exception self-test passed"); } + #[cfg(feature = "divide-error-self-test")] + { + logger::info("Running divide-error exception self-test"); + arch::x86_64::idt::divide_error_self_test(); + logger::info("Divide-error exception self-test passed"); + } let summary = memory::summarize(&boot_info.memory_regions); logger::info_u64("Memory regions", summary.region_count as u64); logger::info_u64("Usable memory bytes", summary.usable_bytes); From c8f20f8da57daa46650f1351693a3bdc31fce8f1 Mon Sep 17 00:00:00 2001 From: Rishi Gupta Date: Tue, 6 Oct 2026 14:17:32 +0530 Subject: [PATCH 5/7] ci: compile exception self-tests --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 40c4455..9f73652 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -39,4 +39,4 @@ jobs: - name: Install QEMU run: sudo apt-get update && sudo apt-get install -y qemu-system-x86 - name: Build boot image - run: cargo build --features exception-self-test --verbose + run: cargo build --features "exception-self-test divide-error-self-test" --verbose From b92864e97f4023324a51fcbe7561c313054a475c Mon Sep 17 00:00:00 2001 From: Rishi Gupta Date: Tue, 6 Oct 2026 14:17:34 +0530 Subject: [PATCH 6/7] docs: document divide-error handling --- docs/architecture.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture.md b/docs/architecture.md index 53394be..c779343 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -35,7 +35,7 @@ The x86_64 interrupt layer now installs a static IDT with handlers for: - Vector 3: breakpoint (`#BP` / `INT3`), which logs the saved interrupt frame and resumes execution. - Vector 6: invalid opcode (`#UD`), which logs the faulting instruction pointer and enters the kernel panic path. -The `exception-self-test` Cargo feature triggers `INT3` during boot so the breakpoint path can be exercised without making the normal boot path intentionally fault. +The `exception-self-test` Cargo feature triggers `INT3` during boot so the breakpoint path can be exercised without making the normal boot path intentionally fault. The `divide-error-self-test` feature deliberately executes an integer divide by zero to exercise the #DE path; it is opt-in because the handler intentionally terminates through the kernel panic path. ## Boot invariant From f7594861fb73bece82f3be09640a16bd76509b1a Mon Sep 17 00:00:00 2001 From: Rishi Gupta Date: Tue, 6 Oct 2026 14:17:36 +0530 Subject: [PATCH 7/7] docs: document divide-error self-test