Skip to content

Commit 959ba8e

Browse files
Handle double faults (#7)
1 parent dc4e6ff commit 959ba8e

File tree

6 files changed

+116
-3
lines changed

6 files changed

+116
-3
lines changed

Cargo.toml

+5-1
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,8 @@ test-success-exit-code = 33 # (0x10 << 1) | 1
2222

2323
[[test]]
2424
name = "should_panic"
25-
harness = false
25+
harness = false
26+
27+
[[test]]
28+
name = "stack_overflow"
29+
harness = false

src/gdt.rs

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use x86_64::VirtAddr;
2+
use x86_64::structures::tss::TaskStateSegment;
3+
use x86_64::structures::gdt::{GlobalDescriptorTable, Descriptor, SegmentSelector};
4+
use lazy_static::lazy_static;
5+
6+
pub const DOUBLE_FAULT_IST_INDEX: u16 = 0;
7+
8+
lazy_static! {
9+
static ref TSS: TaskStateSegment = {
10+
let mut tss = TaskStateSegment::new();
11+
tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = {
12+
const STACK_SIZE: usize = 4096 * 5;
13+
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
14+
15+
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
16+
let stack_end = stack_start + STACK_SIZE;
17+
stack_end
18+
};
19+
tss
20+
};
21+
}
22+
23+
struct Selectors {
24+
code_selector: SegmentSelector,
25+
tss_selector: SegmentSelector,
26+
}
27+
28+
lazy_static! {
29+
static ref GDT: (GlobalDescriptorTable, Selectors) = {
30+
let mut gdt = GlobalDescriptorTable::new();
31+
let code_selector = gdt.add_entry(Descriptor::kernel_code_segment());
32+
let tss_selector = gdt.add_entry(Descriptor::tss_segment(&TSS));
33+
(gdt, Selectors { code_selector, tss_selector })
34+
};
35+
}
36+
37+
pub fn init() {
38+
use x86_64::instructions::tables::load_tss;
39+
use x86_64::instructions::segmentation::{CS, Segment};
40+
GDT.0.load();
41+
unsafe {
42+
CS::set_reg(GDT.1.code_selector);
43+
load_tss(GDT.1.tss_selector);
44+
}
45+
}

src/interrupts.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
22
use crate::println;
3+
use crate::gdt;
34
use lazy_static::lazy_static;
45

56
lazy_static! {
67
static ref IDT: InterruptDescriptorTable = {
78
let mut idt = InterruptDescriptorTable::new();
89
idt.breakpoint.set_handler_fn(breakpoint_handler);
10+
unsafe {
11+
idt.double_fault.set_handler_fn(double_fault_handler)
12+
.set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX);
13+
}
914
idt
1015
};
1116
}
@@ -18,6 +23,10 @@ extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
1823
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
1924
}
2025

26+
extern "x86-interrupt" fn double_fault_handler(stack_frame: InterruptStackFrame, _error_code: u64) -> ! {
27+
panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
28+
}
29+
2130
#[test_case]
2231
fn test_breakpoint_exceptions() {
2332
x86_64::instructions::interrupts::int3();

src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ use core::panic::PanicInfo;
1010
pub mod serial;
1111
pub mod vga_buffer;
1212
pub mod interrupts;
13+
pub mod gdt;
1314

1415
pub fn init() {
16+
gdt::init();
1517
interrupts::init_idt();
1618
}
1719

src/main.rs

-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ pub extern "C" fn _start() -> ! {
2121

2222
os::init();
2323

24-
x86_64::instructions::interrupts::int3();
25-
2624
#[cfg(test)]
2725
test_main();
2826

tests/stack_overflow.rs

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#![feature(abi_x86_interrupt)]
2+
#![no_std]
3+
#![no_main]
4+
5+
use core::panic::PanicInfo;
6+
use os::{exit_qemu, QemuExitCode, serial_println, serial_print};
7+
use lazy_static::lazy_static;
8+
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
9+
10+
#[no_mangle]
11+
pub extern "C" fn _start() -> ! {
12+
serial_print!("stack_overflow::stack_overflow...\t");
13+
os::gdt::init();
14+
init_test_idt();
15+
stack_overflow();
16+
17+
panic!("Execution continued after stack overflow");
18+
}
19+
20+
lazy_static! {
21+
static ref TEST_IDT: InterruptDescriptorTable = {
22+
let mut idt = InterruptDescriptorTable::new();
23+
unsafe {
24+
idt.double_fault
25+
.set_handler_fn(test_double_fault_handler)
26+
.set_stack_index(os::gdt::DOUBLE_FAULT_IST_INDEX);
27+
}
28+
29+
idt
30+
};
31+
}
32+
33+
extern "x86-interrupt" fn test_double_fault_handler(_stack_frame: InterruptStackFrame, _error_code: u64) -> ! {
34+
serial_println!("[ok]");
35+
exit_qemu(QemuExitCode::Success);
36+
loop {}
37+
}
38+
39+
pub fn init_test_idt() {
40+
TEST_IDT.load();
41+
}
42+
43+
#[allow(unconditional_recursion)]
44+
fn stack_overflow() {
45+
// for each recursion, the return address is pushed
46+
stack_overflow();
47+
48+
// prevent tail recursion optimizations
49+
volatile::Volatile::new(0).read();
50+
}
51+
52+
#[panic_handler]
53+
fn panic(info: &PanicInfo) -> ! {
54+
os::test_panic_handler(info);
55+
}

0 commit comments

Comments
 (0)