ax_cpu/arch/x86_64/
trap.rs1use x86::{controlregs::cr2, irq::*};
2use x86_64::{registers::rflags::RFlags, structures::idt::PageFaultErrorCode};
3
4use super::context::TrapFrame;
5use crate::{TrapOrigin, trap::PageFaultFlags};
6
7type RawTrapFrame = TrapFrame;
13
14pub struct KernelTrapFrame<'a> {
21 raw: &'a mut RawTrapFrame,
22 _not_send: core::marker::PhantomData<*mut ()>,
23}
24
25impl<'a> KernelTrapFrame<'a> {
26 pub const fn origin(&self) -> TrapOrigin {
28 TrapOrigin::Kernel
29 }
30
31 pub fn snapshot(&self) -> TrapFrame {
33 *self.raw
34 }
35
36 pub fn apply_registers(&mut self, updated: &TrapFrame) {
38 self.raw.regs = updated.regs;
39 self.raw.rip = updated.rip;
40 self.raw.rflags = updated.rflags;
41 }
42
43 pub const fn ip(&self) -> usize {
45 self.raw.rip as usize
46 }
47
48 pub const fn set_ip(&mut self, ip: usize) {
50 self.raw.rip = ip as u64;
51 }
52
53 unsafe fn from_raw(raw: &'a mut RawTrapFrame) -> Self {
60 debug_assert_eq!(raw.cs & 0b11, 0);
61 Self {
62 raw,
63 _not_send: core::marker::PhantomData,
64 }
65 }
66}
67
68impl core::fmt::Debug for KernelTrapFrame<'_> {
69 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
70 self.snapshot().fmt(formatter)
71 }
72}
73
74pub(super) const LEGACY_SYSCALL_VECTOR: u8 = 0x80;
75pub(super) const IRQ_VECTOR_START: u8 = 0x20;
76pub(super) const IRQ_VECTOR_END: u8 = 0xff;
77
78fn handle_page_fault(tf: &mut KernelTrapFrame<'_>) {
79 let access_flags = err_code_to_flags(tf.raw.error_code)
80 .unwrap_or_else(|e| panic!("Invalid #PF error code: {:#x}", e));
81 let vaddr = va!(unsafe { cr2() });
82 #[cfg(feature = "exception-table")]
83 {
84 let mut updated = tf.snapshot();
85 if updated.fixup_nofault_exception() {
86 tf.apply_registers(&updated);
87 return;
88 }
89 }
90 if crate::trap::call_page_fault_handler_with_parent_irqs(
91 vaddr,
92 access_flags,
93 RFlags::from_bits_truncate(tf.raw.rflags).contains(RFlags::INTERRUPT_FLAG),
94 ) {
95 return;
96 }
97 #[cfg(feature = "exception-table")]
98 {
99 let mut updated = tf.snapshot();
100 if updated.fixup_exception() {
101 tf.apply_registers(&updated);
102 return;
103 }
104 }
105 let snapshot = tf.snapshot();
106 let bt = crate::trap::diagnostics::BacktraceDisplay(snapshot.backtrace_registers());
107 panic!(
108 "Unhandled #PF @ {:#x}, fault_vaddr={:#x}, error_code={:#x} ({:?}):\n{:#x?}\n{}",
109 tf.raw.rip, vaddr, tf.raw.error_code, access_flags, snapshot, bt
110 );
111}
112
113fn handle_breakpoint(tf: &mut KernelTrapFrame<'_>) {
114 debug!("#BP @ {:#x} ", tf.raw.rip);
115 let _ = crate::trap::breakpoint_handler(tf);
116}
117
118fn handle_debug(tf: &mut KernelTrapFrame<'_>) {
119 debug!("#DB @ {:#x} ", tf.raw.rip);
120 if crate::trap::debug_handler(tf) {
121 return;
122 }
123 warn!("Unhandled kernel #DB @ {:#x}", tf.raw.rip);
130 let snapshot = tf.snapshot();
131 let bt = crate::trap::diagnostics::BacktraceDisplay(snapshot.backtrace_registers());
132 panic!(
133 "Unhandled #DB @ {:#x}, error_code={:#x}:\n{:#x?}\n{}",
134 tf.raw.rip, tf.raw.error_code, snapshot, bt
135 );
136}
137
138#[unsafe(no_mangle)]
139unsafe extern "C" fn x86_trap_handler(raw: *mut RawTrapFrame) {
140 let raw = unsafe { &mut *raw };
143 let mut tf = unsafe { KernelTrapFrame::from_raw(raw) };
144 match tf.raw.vector as u8 {
145 PAGE_FAULT_VECTOR => handle_page_fault(&mut tf),
146 BREAKPOINT_VECTOR => handle_breakpoint(&mut tf),
147 DEBUG_VECTOR => handle_debug(&mut tf),
148 GENERAL_PROTECTION_FAULT_VECTOR => {
149 let snapshot = tf.snapshot();
150 let bt = crate::trap::diagnostics::BacktraceDisplay(snapshot.backtrace_registers());
151 panic!(
152 "#GP @ {:#x}, error_code={:#x}:\n{:#x?}\n{}",
153 tf.raw.rip, tf.raw.error_code, snapshot, bt
154 );
155 }
156 IRQ_VECTOR_START..=IRQ_VECTOR_END => {
157 crate::trap::dispatch_irq(
158 tf.raw.vector as _,
159 crate::trap::TrapOrigin::Kernel,
160 Some(tf.snapshot().interrupted_context()),
161 );
162 }
163 _ => {
164 let snapshot = tf.snapshot();
165 let bt = crate::trap::diagnostics::BacktraceDisplay(snapshot.backtrace_registers());
166 panic!(
167 "Unhandled exception {} ({}, error_code={:#x}) @ {:#x}:\n{:#x?}\n{}",
168 tf.raw.vector,
169 vec_to_str(tf.raw.vector),
170 tf.raw.error_code,
171 tf.raw.rip,
172 snapshot,
173 bt
174 );
175 }
176 }
177}
178
179#[unsafe(no_mangle)]
180unsafe extern "C" fn x86_double_fault_handler(raw: *mut RawTrapFrame) -> ! {
181 let fault_vaddr = unsafe { cr2() };
182 let raw = unsafe { &*raw };
185 panic!(
186 "Fatal #DF @ {:#x}, fault_vaddr={:#x}, error_code={:#x}, cs={:#x}, rflags={:#x}",
187 raw.rip, fault_vaddr, raw.error_code, raw.cs, raw.rflags,
188 );
189}
190
191fn vec_to_str(vec: u64) -> &'static str {
192 if vec < 32 {
193 EXCEPTIONS[vec as usize].mnemonic
194 } else {
195 "Unknown"
196 }
197}
198
199pub(super) fn err_code_to_flags(err_code: u64) -> Result<PageFaultFlags, u64> {
200 let code = PageFaultErrorCode::from_bits_truncate(err_code);
201 let reserved_bits = (PageFaultErrorCode::CAUSED_BY_WRITE
202 | PageFaultErrorCode::USER_MODE
203 | PageFaultErrorCode::INSTRUCTION_FETCH
204 | PageFaultErrorCode::PROTECTION_VIOLATION)
205 .complement();
206 if code.intersects(reserved_bits) {
207 Err(err_code)
208 } else {
209 let mut flags = PageFaultFlags::empty();
210 if code.contains(PageFaultErrorCode::CAUSED_BY_WRITE) {
211 flags |= PageFaultFlags::WRITE;
212 } else {
213 flags |= PageFaultFlags::READ;
214 }
215 if code.contains(PageFaultErrorCode::USER_MODE) {
216 flags |= PageFaultFlags::USER;
217 }
218 if code.contains(PageFaultErrorCode::INSTRUCTION_FETCH) {
219 flags |= PageFaultFlags::EXECUTE;
220 }
221 Ok(flags)
222 }
223}