kernel/arch/x86_64/mm/vmm/paging/
setup_kernel_paging.rs1use crate::lib::addr::{PhysAddr, VirtAddr};
7use crate::lib::panic::kernel_panic;
8use crate::lib::panic_codes::PanicCode;
9use crate::lib::types::boot_info::KernelSectionInfo;
10use crate::mm::layout;
11use crate::mm::pmm::{Pmm, FRAME_SIZE};
12use crate::mm::vmm::boot_mapping::{build_boot_mappings, BootMappings};
13use crate::mm::vmm::traits::VmmPaging;
14use crate::mm::vmm::Vmm;
15use crate::state::kstate::KSTATE;
16use crate::kinfo;
17use x86_64::registers::control::{Cr3, Efer, EferFlags};
18use x86_64::structures::paging::{PageTable, PageTableFlags, PhysFrame};
19
20pub fn setup_kernel_paging(sections: &KernelSectionInfo) -> (VirtAddr, BootMappings) {
24 unsafe {
26 Efer::update(|efer| efer.insert(EferFlags::NO_EXECUTE_ENABLE));
27 }
28
29 let mut pmm = unsafe { KSTATE.mm.pmm().lock() };
30
31 let pml4_frame = pmm.alloc_frame_zeroed().unwrap_or_else(
32 || kernel_panic(
33 PanicCode::OutOfMemory,
34 "Could not allocate a PML4 for the kernel, out of memory"
35 )
36 );
37
38 let page_ptr = VirtAddr::from_phys(pml4_frame);
39 let total_mem = pmm.get_total_mem();
40
41 let boot_mappings = build_boot_mappings(sections, total_mem);
42
43 for mapping in &boot_mappings {
44 unsafe {
47 Vmm::map_range(
48 &mut pmm,
49 page_ptr,
50 mapping.virt,
51 mapping.phys,
52 mapping.size,
53 Vmm::vma_flags_to_page_flags(mapping.flags),
54 mapping.can_overmap
55 ).unwrap_or_else(
56 |_| kernel_panic(
57 PanicCode::OutOfMemory,
58 "Could not build the kernel page tables, out of memory"
59 )
60 );
61 }
62 }
63
64 create_zeroed_pdpts(&mut pmm, page_ptr);
65 verify_against_bootloader(page_ptr, sections);
66
67 unsafe {
70 Cr3::write(
71 PhysFrame::containing_address(pml4_frame.as_x86_64()),
72 Cr3::read().1
73 );
74 }
75
76 kinfo!("Initialized kernel paging (PML4 is at phys {:#x})", pml4_frame.as_u64());
77
78 (page_ptr, boot_mappings)
79}
80
81fn create_zeroed_pdpts(pmm: &mut Pmm, page_ptr: VirtAddr) {
87 let pml4 = unsafe { &mut *page_ptr.as_mut_ptr::<PageTable>() };
90
91 for index in 256..512 {
92 let entry = &mut (*pml4)[index];
93
94 if !entry.is_unused() {
95 continue;
96 }
97
98 let pdpt_frame = pmm.alloc_frame_zeroed().unwrap_or_else(
99 || kernel_panic(
100 PanicCode::OutOfMemory,
101 "Could not allocate a PDPT while prepopulating the kernel PML4, out of memory"
102 )
103 );
104
105 entry.set_addr(
106 pdpt_frame.as_x86_64(),
107 PageTableFlags::PRESENT | PageTableFlags::WRITABLE
108 );
109 }
110}
111
112fn verify_against_bootloader(page_ptr: VirtAddr, sections: &KernelSectionInfo) {
115 let old_page_ptr = VirtAddr::from_phys(
116 PhysAddr::new(Cr3::read().0.start_address().as_u64())
117 );
118
119 let rsp: u64;
120 unsafe { core::arch::asm!("mov {}, rsp", out(reg) rsp, options(nostack, nomem)) };
121
122 let probes = [
123 rsp,
124 sections.kernel_start,
125 sections.kernel_text_end - 1,
126 sections.kernel_rodata_end - 1,
127 sections.kernel_end - 1,
128 layout::KERNEL_HHDM_BASE.as_u64() + FRAME_SIZE
129 ];
130
131 for probe in probes {
132 let old = Vmm::translate(old_page_ptr, VirtAddr::new(probe));
133 let new = Vmm::translate(page_ptr, VirtAddr::new(probe));
134
135 if old != new {
136 kernel_panic(
137 PanicCode::InitFailure,
138 "New kernel-owned page tables do not match with the bootloader's, which would triple-fault on CR3 switch"
139 );
140 }
141 }
142}