kernel/arch/x86_64/mm/vmm/paging/
map_page.rs1use super::super::page_type::PageType;
7use crate::lib::addr::{PhysAddr, VirtAddr};
8use crate::mm::pmm::Pmm;
9use crate::mm::vmm::{VmmError, VmmResult};
10use crate::state::kstate::KSTATE;
11use x86_64::structures::paging::{PageTable, PageTableFlags, PageTableIndex, PhysFrame};
12
13pub unsafe fn map_page(
14 pmm: &mut Pmm,
15 page_ptr: VirtAddr,
16 virt: VirtAddr,
17 phys: PhysAddr,
18 page_type: PageType,
19 flags: PageTableFlags,
20) -> VmmResult {
21 #[cfg(feature = "debug-checks")]
22 {
23 use super::helpers::misaligned_address_panic;
24 let align = &(page_type as u64);
25 if phys.as_u64() % align != 0 || virt.as_u64() % align != 0 {
26 misaligned_address_panic(page_type);
27 }
28 }
29
30 let hhdm_offset = &KSTATE.mm.hhdm_offset();
31
32 let lowest_iter_page = match page_type {
33 PageType::Normal => 2,
34 PageType::HugePage2MiB => 3,
35 PageType::HugePage1GiB => 4
36 };
37
38 let mut current_pagetable: *mut PageTable = page_ptr.as_mut_ptr::<PageTable>();
39 let intermediate_flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE | (flags & PageTableFlags::USER_ACCESSIBLE);
40
41 for level in (lowest_iter_page..=4).rev() {
42 let index: PageTableIndex = match level {
43 4 => virt.p4_index(),
44 3 => virt.p3_index(),
45 2 => virt.p2_index(),
46 _ => unreachable!()
47 };
48
49 let entry = unsafe { &mut current_pagetable.as_mut().unwrap()[index] };
50
51 if !entry.flags().contains(PageTableFlags::PRESENT) {
52 let frame = pmm.alloc_frame_zeroed().ok_or(VmmError::OutOfMemory)?;
53 entry.set_frame(
54 PhysFrame::containing_address(frame.as_x86_64()),
55 intermediate_flags,
56 );
57 }
58
59 current_pagetable = (entry.frame().unwrap().start_address().as_u64() + hhdm_offset) as *mut PageTable;
60 }
61
62 let entry = unsafe {
64 &mut current_pagetable.as_mut().unwrap()[match page_type {
65 PageType::Normal => virt.p1_index(),
66 PageType::HugePage2MiB => virt.p2_index(),
67 PageType::HugePage1GiB => virt.p3_index(),
68 }]
69 };
70
71 if page_type == PageType::Normal {
72 entry.set_frame(PhysFrame::containing_address(phys.as_x86_64()), flags | PageTableFlags::PRESENT);
73 } else {
74 entry.set_addr(phys.as_x86_64(), flags | PageTableFlags::PRESENT | PageTableFlags::HUGE_PAGE);
75 }
76
77 #[cfg(feature = "vmm-debug-logging")]
78 crate::kdebug!("[VMM] map new page at virt {virt:#x}, phys {phys:#x}, type {page_type}, flags {flags:?}");
79
80 Ok(())
81}