1use super::vmm_helpers::*;
8use crate::{kdebug, kinfo};
9use crate::mem::pmm::Pmm;
10use x86_64::registers::control::Cr3;
11use x86_64::structures::paging::{PageTable, PageTableFlags, PageTableIndex, PhysFrame};
12use x86_64::{PhysAddr, VirtAddr};
13
14pub struct Vmm {
16 pub plm4_ptr: *mut PageTable,
18 pub hhdm_offset: u64,
20}
21
22unsafe impl Send for Vmm {}
25unsafe impl Sync for Vmm {}
26
27impl Vmm {
28 pub fn init(pmm: &Pmm, hhdm_offset: u64) -> Self {
33 let limine_plm4_ptr = (Cr3::read().0.start_address().as_u64() + hhdm_offset) as *const PageTable;
34
35 let plm4_ptr = (
36 pmm.alloc().unwrap_or_else(|| out_of_memory_panic()).as_u64() + hhdm_offset
37 ) as *mut PageTable;
38
39 unsafe {
41 core::ptr::write_bytes(plm4_ptr, 0x00, 1);
42 }
43
44 for entry in 256..512 {
45 unsafe {
47 (&mut (*plm4_ptr))[entry] = (&(*limine_plm4_ptr))[entry].clone();
48 }
49 }
50
51 let phys_addr_u64 = plm4_ptr as u64 - hhdm_offset;
52 let phys_frame = PhysFrame::containing_address(PhysAddr::new(phys_addr_u64));
53 let current_cr3_flags = Cr3::read().1;
54
55 unsafe {
58 Cr3::write(phys_frame, current_cr3_flags);
59 }
60
61 kdebug!("[VMM] allocated frame for plm4 at phys addr {phys_addr_u64:#x}");
62 kinfo!("Initialized VMM");
63
64 Vmm { plm4_ptr, hhdm_offset }
65 }
66
67 pub unsafe fn map_page(&self, pmm: &Pmm, virt: VirtAddr, phys: PhysAddr, flags: PageTableFlags) {
76 let mut current_pagetable: *mut PageTable = self.plm4_ptr;
77 let intermediate_flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE | (flags & PageTableFlags::USER_ACCESSIBLE);
78
79 for level in (2..5).rev() {
80 let index: PageTableIndex;
81
82 match level {
83 4 => { index = virt.p4_index() }
84 3 => { index = virt.p3_index() }
85 2 => { index = virt.p2_index() }
86 _ => unreachable!()
87 }
88
89 let entry = &mut (&mut (*current_pagetable))[index];
90
91 if !entry.flags().contains(PageTableFlags::PRESENT) {
92 let frame = alloc_zeroed_frame(pmm, self.hhdm_offset);
93 entry.set_frame(frame, intermediate_flags);
94 }
95
96 current_pagetable = (entry.frame().unwrap().start_address().as_u64() + self.hhdm_offset) as *mut PageTable;
97 }
98
99 let entry = &mut (&mut (*current_pagetable))[virt.p1_index()];
100 entry.set_frame(PhysFrame::containing_address(phys), flags | PageTableFlags::PRESENT);
101 }
102
103 pub unsafe fn unmap_page(&self, virt: VirtAddr) {
112 let mut current_pagetable: *mut PageTable = self.plm4_ptr;
113
114 for level in (2..5).rev() {
115 let index: PageTableIndex;
116
117 match level {
118 4 => { index = virt.p4_index() }
119 3 => { index = virt.p3_index() }
120 2 => { index = virt.p2_index() }
121 _ => unreachable!()
122 }
123
124 let entry = &mut (&mut (*current_pagetable))[index];
125
126 if !entry.flags().contains(PageTableFlags::PRESENT) {
127 invalid_unmap_panic();
128 }
129
130 current_pagetable = (entry.frame().unwrap().start_address().as_u64() + self.hhdm_offset) as *mut PageTable;
131 }
132
133 let entry = &mut (&mut (*current_pagetable))[virt.p1_index()];
134
135 if !entry.flags().contains(PageTableFlags::PRESENT) {
136 invalid_unmap_panic();
137 }
138
139 entry.set_unused();
140 x86_64::instructions::tlb::flush(virt);
141 }
142}