kernel/arch/x86_64/mm/
pmm.rs1#[cfg(feature = "debug-logging")]
7use crate::kdebug;
8
9use crate::kinfo;
12use crate::lib::addr::PhysAddr;
13use crate::state::kstate::KSTATE;
14use limine::memmap;
15
16pub const FRAME_SIZE: u64 = 4096;
17const MAX_ORDER: usize = 10;
18const NUM_ORDERS: usize = MAX_ORDER + 1;
19
20pub struct Pmm {
22 head: [Option<PhysAddr>; 11],
23 total_mem: u64
24}
25
26impl Pmm {
27 pub fn init(entries: &[&memmap::Entry]) -> Self {
29 let mut pmm = Pmm {
30 head: [None; NUM_ORDERS],
31 total_mem: 0
32 };
33
34 #[cfg(feature = "debug-logging")]
35 {
36 let mut total_usable = 0u64;
37 let mut total_reclaimable = 0u64;
38 let mut count_usable = 0u64;
39 let mut count_reclaimable = 0u64;
40 let mut count_reserved = 0u64;
41 let mut count_acpi = 0u64;
42
43 for &entry in entries {
44 match entry.type_ {
45 memmap::MEMMAP_USABLE => { count_usable += 1; total_usable += entry.length; }
46 memmap::MEMMAP_BOOTLOADER_RECLAIMABLE => { count_reclaimable += 1; total_reclaimable += entry.length; }
47 memmap::MEMMAP_RESERVED => { count_reserved += 1; }
48 memmap::MEMMAP_ACPI_RECLAIMABLE => { count_acpi += 1; }
49 _ => {}
50 }
51 }
52
53 kdebug!("[PMM] total entries: {}", entries.len());
54 kdebug!("[PMM] usable: {} regions, {} MiB", count_usable, total_usable / 1024 / 1024);
55 kdebug!("[PMM] reclaimable: {} regions, {} MiB", count_reclaimable, total_reclaimable / 1024 / 1024);
56 kdebug!("[PMM] reserved: {} regions", count_reserved);
57 kdebug!("[PMM] acpi: {} regions", count_acpi);
58 }
59
60 let mut total_mem = 0u64;
61
62 for &entry in entries {
63 if entry.type_ == memmap::MEMMAP_USABLE || entry.type_ == memmap::MEMMAP_BOOTLOADER_RECLAIMABLE {
64 total_mem = total_mem.max(entry.base + entry.length);
65 }
66
67 if entry.type_ != memmap::MEMMAP_USABLE { continue; }
68
69 let mut addr = entry.base;
70 let mut remaining = entry.length;
71
72 if addr == 0 {
73 addr += FRAME_SIZE;
74 remaining -= FRAME_SIZE;
75 }
76
77 while remaining >= FRAME_SIZE {
78 let mut order = MAX_ORDER;
79 while order > 0 {
80 let block_size = FRAME_SIZE << order;
81 if remaining >= block_size && addr % (FRAME_SIZE << order) == 0 { break; }
82 order -= 1;
83 }
84
85 pmm.free(PhysAddr::new(addr), order);
86
87 let block_size = FRAME_SIZE << order;
88 addr += block_size;
89 remaining -= block_size;
90 }
91 }
92
93 kinfo!("Initialized PMM");
94
95 pmm.total_mem = total_mem;
96 pmm
97 }
98
99 pub fn get_total_mem(&self) -> u64 {
101 self.total_mem
102 }
103
104 pub fn alloc(&mut self, order: usize) -> Option<PhysAddr> {
106 if order > 10 { return None; }
107
108 if self.head[order] != None {
109 return self.pop(order);
110 }
111
112 let mut current: usize = MAX_ORDER;
113 for o in order..=MAX_ORDER {
114 if self.head[o] != None {
115 current = o;
116 break;
117 }
118 if o == MAX_ORDER {
119 return None;
120 }
121 }
122
123 let addr = self.pop(current)?;
124 while current > order {
125 current -= 1;
126 let buddy = PhysAddr::new(addr.as_u64() + (FRAME_SIZE << current));
127 self.push(current, buddy);
128 }
129
130 Some(addr)
131 }
132
133 pub fn alloc_frame(&mut self) -> Option<PhysAddr> {
135 self.alloc(0)
136 }
137
138 pub fn alloc_frame_zeroed(&mut self) -> Option<PhysAddr> {
140 let frame = self.alloc_frame()?;
141 unsafe { core::ptr::write_bytes(frame.as_mut_hhdm_ptr::<u8>(), 0x00, FRAME_SIZE as usize); }
142 Some(frame)
143 }
144
145 pub fn free(&mut self, mut addr: PhysAddr, mut order: usize) {
147 'outer: while order < MAX_ORDER {
148 if self.head[order].is_none() {
149 break;
150 }
151
152 let buddy = PhysAddr::new(addr.as_u64() ^ (FRAME_SIZE << order));
153 let mut current_node_addr = self.head[order].unwrap();
154 let mut prev_node_addr = PhysAddr::null();
155
156 loop {
157 let next_node_addr: u64 = unsafe { core::ptr::read(current_node_addr.as_hhdm_ptr()) };
158
159 if current_node_addr == buddy {
160 if prev_node_addr.as_u64() == 0 {
161 self.head[order] = Some(PhysAddr::new(next_node_addr));
162 }
163 else {
164 unsafe { core::ptr::write(prev_node_addr.as_mut_hhdm_ptr(), next_node_addr) };
165 }
166 break;
167 }
168
169 if next_node_addr == 0 {
170 break 'outer;
171 }
172 prev_node_addr = current_node_addr;
173 current_node_addr = PhysAddr::new(next_node_addr);
174 }
175
176 order += 1;
177 addr = PhysAddr::new(core::cmp::min(addr.as_u64(), buddy.as_u64()));
178 }
179
180 self.push(order, addr);
181 }
182
183 pub fn free_frame(&mut self, addr: PhysAddr) {
185 self.free(addr, 0)
186 }
187
188
189 fn pop(&mut self, order: usize) -> Option<PhysAddr> {
191 let hhdm_offset = &KSTATE.mm.hhdm_offset();
192 let head = self.head[order]?;
193 let result;
194
195 unsafe {
196 result = core::ptr::read(
199 (head.as_u64() + hhdm_offset) as *const u64
200 );
201 }
202 if result == 0 {
203 self.head[order] = None;
204 } else {
205 self.head[order] = Some(PhysAddr::new(result));
206 }
207
208 Some(head)
209 }
210
211 fn push(&mut self, order: usize, addr: PhysAddr) {
213 let hhdm_offset = &KSTATE.mm.hhdm_offset();
214
215 unsafe {
218 core::ptr::write(
219 (addr.as_u64() + hhdm_offset) as *mut u64,
220 self.head[order].map_or(0, |addr| addr.as_u64())
221 );
222 }
223
224 self.head[order] = Some(addr);
225 }
226}