143 lines
3.3 KiB
Rust
143 lines
3.3 KiB
Rust
use core::arch::global_asm;
|
|
use core::arch::asm;
|
|
use crate::mem::vmm::KERNEL_SPACE;
|
|
use crate::mem::address::VirtAddr;
|
|
|
|
pub static mut IDT: crate::cpu::idt::InterruptDescriptorTable = crate::cpu::idt::InterruptDescriptorTable::new();
|
|
|
|
pub const TLB_SHOOTDOWN_VECTOR: u8 = 0xFD;
|
|
|
|
global_asm!(
|
|
".global page_fault_stub",
|
|
"page_fault_stub:",
|
|
"push rax",
|
|
"push rcx",
|
|
"push rdx",
|
|
"push rbx",
|
|
"push rbp",
|
|
"push rsi",
|
|
"push rdi",
|
|
"push r8",
|
|
"push r9",
|
|
"push r10",
|
|
"push r11",
|
|
"push r12",
|
|
"push r13",
|
|
"push r14",
|
|
"push r15",
|
|
|
|
".global tlb_shootdown_stub",
|
|
"tlb_shootdown_stub:",
|
|
"push rax",
|
|
"push rcx",
|
|
"push rdx",
|
|
"push rbx",
|
|
"push rbp",
|
|
"push rsi",
|
|
"push rdi",
|
|
"push r8",
|
|
"push r9",
|
|
"push r10",
|
|
"push r11",
|
|
"push r12",
|
|
"push r13",
|
|
"push r14",
|
|
"push r15",
|
|
|
|
"call rust_tlb_shootdown_handler",
|
|
|
|
"mov rdi, [rsp + 15*8]",
|
|
"call rust_page_fault_handler",
|
|
|
|
"pop r15",
|
|
"pop r14",
|
|
"pop r13",
|
|
"pop r12",
|
|
"pop r11",
|
|
"pop r10",
|
|
"pop r9",
|
|
"pop r8",
|
|
"pop rdi",
|
|
"pop rsi",
|
|
"pop rbp",
|
|
"pop rbx",
|
|
"pop rdx",
|
|
"pop rcx",
|
|
"pop rax",
|
|
|
|
"add rsp, 8",
|
|
"iretq"
|
|
);
|
|
|
|
unsafe extern "C" {
|
|
fn page_fault_stub();
|
|
fn tlb_shootdown_stub();
|
|
}
|
|
|
|
pub fn init_idt() {
|
|
unsafe {
|
|
let idt_mut_ptr = core::ptr::addr_of_mut!(IDT);
|
|
(*idt_mut_ptr).set_handler(14, page_fault_stub as u64);
|
|
|
|
(*idt_mut_ptr).set_handler(TLB_SHOOTDOWN_VECTOR, tlb_shootdown_stub as u64);
|
|
|
|
let idt_static_ref: &'static crate::cpu::idt::InterruptDescriptorTable = &*core::ptr::addr_of!(IDT);
|
|
idt_static_ref.load();
|
|
}
|
|
}
|
|
|
|
|
|
pub fn process_deferred_mmu_events() {
|
|
let mut vmm_guard = KERNEL_SPACE.lock();
|
|
if let Some(space) = vmm_guard.as_mut() {
|
|
space.process_pending_revocations();
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub extern "C" fn rust_page_fault_handler(error_code: u64) {
|
|
let fault_addr: u64;
|
|
unsafe {
|
|
asm!("mov {}, cr2", out(reg) fault_addr, options(nomem, nostack, preserves_flags));
|
|
}
|
|
|
|
let write = (error_code & 0x2) != 0;
|
|
let present = (error_code & 0x1) != 0;
|
|
let virt_addr = VirtAddr(fault_addr);
|
|
|
|
process_deferred_mmu_events();
|
|
|
|
let mut vmm_guard = KERNEL_SPACE.lock();
|
|
|
|
if let Some(space) = vmm_guard.as_mut() {
|
|
match space.handle_fault(virt_addr, write) {
|
|
Ok(_) => return,
|
|
Err(e) => {
|
|
panic!(
|
|
"KERNEL PANIC: Unprocessed failure of virtual memory (Page Fault)!\n\
|
|
Address: {:#X}\n\
|
|
Mode: {}\n\
|
|
Presence: {}\n\
|
|
Cause VMM: {:?}",
|
|
fault_addr,
|
|
if write { "WRITE" } else { "READ" },
|
|
if present { "YES (Protection Violation)" } else { "NO (Not Present)" },
|
|
e
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
panic!(
|
|
"KERNEL PANIC: Critical Page Fault before alocate global KERNEL_SPACE!\n\
|
|
Адрес сбоя: {:#X}",
|
|
fault_addr
|
|
);
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub extern "C" fn rust_tlb_shootdown_handler() {
|
|
crate::mem::vmm::handle_tlb_shootdown_ipi();
|
|
crate::cpu::lapic::send_eoi();
|
|
}
|