kernel/arch/x86_64/mm/vmm/paging/
remap.rs1use super::helpers::{advance_current_pagetable, is_huge_page, is_present};
7use crate::lib::addr::VirtAddr;
8use crate::mm::vmm::{VmmError, VmmResult};
9use x86_64::instructions::tlb;
10use x86_64::structures::paging::page_table::PageTableEntry;
11use x86_64::structures::paging::{PageTable, PageTableFlags, PhysFrame};
12
13pub unsafe fn remap_page(
14 page_ptr: VirtAddr,
15 virt: VirtAddr,
16 new_flags: PageTableFlags
17) -> VmmResult {
18 #[cfg(feature = "debug-checks")]
19 {
20 use crate::mm::pmm::FRAME_SIZE;
21 use super::super::page_type::PageType;
22 use super::helpers::misaligned_address_panic;
23
24 if virt.as_u64() % FRAME_SIZE != 0 {
25 misaligned_address_panic(PageType::Normal);
26 }
27 }
28
29 let mut current_pagetable: *mut PageTable = page_ptr.as_mut_ptr::<PageTable>();
30
31 let entry = unsafe { &mut current_pagetable.as_mut().unwrap()[virt.p4_index()] };
37 if !is_present(entry) { return Err(VmmError::InvalidRemap) };
38 current_pagetable = advance_current_pagetable(entry);
39
40 let entry = unsafe { &mut current_pagetable.as_mut().unwrap()[virt.p3_index()] };
46 if !is_present(entry) { return Err(VmmError::InvalidRemap) };
47 if is_huge_page(entry) {
48 remap_huge_page(entry, virt, new_flags);
49 return Ok(())
50 }
51 current_pagetable = advance_current_pagetable(entry);
52
53 let entry = unsafe { &mut current_pagetable.as_mut().unwrap()[virt.p2_index()] };
59 if !is_present(entry) { return Err(VmmError::InvalidRemap) };
60 if is_huge_page(entry) {
61 remap_huge_page(entry, virt, new_flags);
62 return Ok(())
63 }
64 current_pagetable = advance_current_pagetable(entry);
65
66 let entry = unsafe { &mut current_pagetable.as_mut().unwrap()[virt.p1_index()] };
72 if !is_present(entry) { return Err(VmmError::InvalidRemap) };
73 entry.set_frame(
74 PhysFrame::containing_address(entry.frame().unwrap().start_address()),
75 new_flags | PageTableFlags::PRESENT
76 );
77 tlb::flush(virt.as_x86_64());
78 debug_log(virt, new_flags);
79
80 Ok(())
81}
82
83fn remap_huge_page(entry: &mut PageTableEntry, virt: VirtAddr, new_flags: PageTableFlags) {
85 entry.set_addr(entry.addr(), new_flags | PageTableFlags::PRESENT | PageTableFlags::HUGE_PAGE);
86 tlb::flush(virt.as_x86_64());
87 debug_log(virt, new_flags);
88}
89
90#[allow(unused_variables)]
92fn debug_log(virt: VirtAddr, flags: PageTableFlags) {
93 #[cfg(feature = "vmm-debug-logging")]
94 crate::kdebug!("[VMM] remap page at virt {virt:#x} to flags {flags:?}");
95}