Skip to main content

rustubs/arch/x86_64/paging/
fault.rs

1use crate::arch::x86_64::arch_regs::TrapFrame;
2use crate::io::*;
3use crate::proc::task::{Task, TaskState};
4use core::arch::asm;
5
6/// error code bits for the page fault exception (see AMD64 APM vol 2)
7const PF_ERR_PRESENT: u64 = 1 << 0;
8const PF_ERR_WRITE: u64 = 1 << 1;
9const PF_ERR_USER: u64 = 1 << 2;
10
11/// handle page fault.
12///
13/// If the fault originated from user mode (ring 3), we kill the task instead
14/// of hanging the whole kernel: print a diagnostic, mark the task Dead, and
15/// reschedule. Kernel-mode faults are still fatal (halt).
16pub fn page_fault_handler(frame: &mut TrapFrame, fault_addr: u64) {
17	// TODO: handle on-demand paging and COW.
18	let err_code = frame.err_code;
19	let from_user = (err_code & PF_ERR_USER) != 0;
20
21	if from_user {
22		println!(
23			"[pagefault] user task killed: fault @ {:#X} err {:#X} (rip in trap frame)",
24			fault_addr, err_code
25		);
26		// Kill the current task. The trape_gate will do reschedule before
27		// returns. Such task will never be scheduled again (like sys_exit())
28		let task = Task::current().unwrap();
29		task.state = TaskState::Dead;
30		return;
31	}
32
33	// kernel-mode fault: fatal
34	sprintln!("pagefault @ {:#X}, err {:#X?}", fault_addr, err_code);
35	sprintln!("{:#X?}", frame);
36	unsafe { asm!("hlt") };
37}
38
39/// for x86_64, return the CR2 register.
40#[inline]
41pub fn get_fault_addr() -> u64 {
42	let cr2: u64;
43	unsafe {
44		asm!("mov {}, cr2", out(reg) cr2);
45	}
46	cr2
47}