Skip to content
This repository was archived by the owner on Jan 1, 2024. It is now read-only.

Commit e28370f

Browse files
committed
Implement CPU exception handling
Currently the x86-interrupt calling convention seems to be broken; see rust-lang/rust#109918. This results in junk values when printing the InterruptStackFrame.
1 parent 0eefada commit e28370f

File tree

2 files changed

+137
-0
lines changed

2 files changed

+137
-0
lines changed

src/interrupt.rs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,131 @@ pub fn end_interrupt_disable() {
7272
assert!(prev_count > 0);
7373
interrupts::enable();
7474
}
75+
76+
macro_rules! exception {
77+
($id:ident, $name:literal) => {
78+
extern "x86-interrupt" fn $id(frame: InterruptStackFrame) {
79+
cpu_exception(frame, $name);
80+
}
81+
};
82+
}
83+
84+
macro_rules! exception_errcode {
85+
($id:ident, $name:literal) => {
86+
extern "x86-interrupt" fn $id(frame: InterruptStackFrame, errcode: u64) {
87+
cpu_exception_errcode(frame, $name, errcode);
88+
}
89+
};
90+
}
91+
92+
macro_rules! exception_diverging {
93+
($id:ident, $name:literal) => {
94+
extern "x86-interrupt" fn $id(frame: InterruptStackFrame) -> ! {
95+
cpu_exception(frame, $name);
96+
}
97+
};
98+
}
99+
100+
macro_rules! exception_diverging_errcode {
101+
($id:ident, $name:literal) => {
102+
extern "x86-interrupt" fn $id(frame: InterruptStackFrame, errcode: u64) -> ! {
103+
cpu_exception_errcode(frame, $name, errcode);
104+
}
105+
};
106+
}
107+
108+
exception!(handler_divide_error, "Divide error");
109+
exception!(handler_debug, "Debug exception");
110+
exception!(handler_non_maskable_interrupt, "Non-maskable interrupt");
111+
exception!(handler_breakpoint, "Breakpoint exception");
112+
exception!(handler_overflow, "Overflow exception");
113+
exception!(handler_bound_range_exceeded, "Bound range exceeded");
114+
exception!(handler_invalid_opcode, "Invalid opcode");
115+
exception!(handler_device_not_available, "Device not available");
116+
exception_diverging_errcode!(handler_double_fault, "Double fault");
117+
exception_errcode!(handler_invalid_tss, "Invalid TSS");
118+
exception_errcode!(handler_segment_not_present, "Segment not present");
119+
exception_errcode!(handler_stack_segment_fault, "Stack segment exception");
120+
exception_errcode!(handler_general_protection_fault, "General protection fault");
121+
// See below for page fault handler
122+
exception!(handler_x87_floating_point, "x87 floating-point exception");
123+
exception_errcode!(handler_alignment_check, "Alignment check exception");
124+
exception_diverging!(handler_machine_check, "Machine check exception");
125+
exception!(handler_simd_floating_point, "SIMD floating-point exception");
126+
exception!(handler_virtualization, "Virtualization exception");
127+
exception_errcode!(
128+
handler_vmm_communication_exception,
129+
"VMM communication exception"
130+
);
131+
exception_errcode!(handler_security_exception, "Security exception");
132+
133+
fn cpu_exception(frame: InterruptStackFrame, name: &'static str) -> ! {
134+
IN_KERNEL_INTERRUPT_HANDLER.store(true, Ordering::Relaxed);
135+
IN_KERNEL_EXCEPTION_HANDLER.store(true, Ordering::Relaxed);
136+
panic!("CPU exception: {}, stack frame: {:?}", name, frame);
137+
}
138+
139+
fn cpu_exception_errcode(frame: InterruptStackFrame, name: &'static str, errcode: u64) -> ! {
140+
IN_KERNEL_INTERRUPT_HANDLER.store(true, Ordering::Relaxed);
141+
IN_KERNEL_EXCEPTION_HANDLER.store(true, Ordering::Relaxed);
142+
panic!(
143+
"CPU exception: {}, error code: {}, stack frame: {:?}",
144+
name, errcode, frame
145+
);
146+
}
147+
148+
extern "x86-interrupt" fn handler_page_fault(
149+
frame: InterruptStackFrame,
150+
errcode: idt::PageFaultErrorCode,
151+
) {
152+
IN_KERNEL_INTERRUPT_HANDLER.store(true, Ordering::Relaxed);
153+
IN_KERNEL_EXCEPTION_HANDLER.store(true, Ordering::Relaxed);
154+
panic!(
155+
"CPU exception: Page fault, error code: {:?}, address: {:?}, stack frame: {:?}",
156+
errcode,
157+
Cr2::read(),
158+
frame
159+
);
160+
}
161+
162+
/// Initializes interrupt handling.
163+
///
164+
/// This requires heap allocation to be initialized first.
165+
pub fn init() {
166+
let idt = Box::leak(
167+
Box::try_new(InterruptDescriptorTable::new()).expect("Allocation should succeed"),
168+
);
169+
idt.divide_error.set_handler_fn(handler_divide_error);
170+
idt.debug.set_handler_fn(handler_debug);
171+
idt.non_maskable_interrupt
172+
.set_handler_fn(handler_non_maskable_interrupt);
173+
idt.breakpoint.set_handler_fn(handler_breakpoint);
174+
idt.overflow.set_handler_fn(handler_overflow);
175+
idt.bound_range_exceeded
176+
.set_handler_fn(handler_bound_range_exceeded);
177+
idt.invalid_opcode.set_handler_fn(handler_invalid_opcode);
178+
idt.device_not_available
179+
.set_handler_fn(handler_device_not_available);
180+
idt.double_fault.set_handler_fn(handler_double_fault);
181+
idt.invalid_tss.set_handler_fn(handler_invalid_tss);
182+
idt.segment_not_present
183+
.set_handler_fn(handler_segment_not_present);
184+
idt.stack_segment_fault
185+
.set_handler_fn(handler_stack_segment_fault);
186+
idt.general_protection_fault
187+
.set_handler_fn(handler_general_protection_fault);
188+
idt.page_fault.set_handler_fn(handler_page_fault);
189+
idt.x87_floating_point
190+
.set_handler_fn(handler_x87_floating_point);
191+
idt.alignment_check.set_handler_fn(handler_alignment_check);
192+
idt.machine_check.set_handler_fn(handler_machine_check);
193+
idt.simd_floating_point
194+
.set_handler_fn(handler_simd_floating_point);
195+
idt.virtualization.set_handler_fn(handler_virtualization);
196+
idt.vmm_communication_exception
197+
.set_handler_fn(handler_vmm_communication_exception);
198+
idt.security_exception
199+
.set_handler_fn(handler_security_exception);
200+
201+
idt.load();
202+
}

src/main.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
#![deny(missing_docs)]
44
#![deny(unsafe_op_in_unsafe_fn)]
55
#![feature(vec_push_within_capacity)]
6+
#![feature(allocator_api)]
67
#![feature(const_mut_refs)]
8+
#![feature(abi_x86_interrupt)]
79

810
//! # Doors
911
//!
@@ -93,11 +95,18 @@ pub extern "C" fn _start() -> ! {
9395
}
9496

9597
gdt::load();
98+
interrupt::init();
99+
96100
let mut v: Vec<i32> = Vec::new();
97101
v.try_reserve(1).unwrap();
98102
v.push_within_capacity(1).unwrap();
99103
kprintln!("{}", v[0]);
100104

105+
unsafe {
106+
let _: i32 = core::ptr::read_volatile(0x0000067812345678 as *const i32);
107+
}
108+
//x86_64::instructions::interrupts::int3();
109+
101110
panic!("We did it!");
102111
}
103112

0 commit comments

Comments
 (0)