1use crate::{kdebug, kemerg, kinfo};
8use crate::panic::kernel_panic;
9use crate::types::panic_codes::PanicCode;
10use x86_64::PhysAddr;
11use limine::memmap;
12use limine::memmap::MEMMAP_USABLE;
13
14pub static FRAME_SIZE: u64 = 4096;
15
16pub struct Pmm {
18 bitmap_ptr: *mut u8,
19 total_frames: u64,
20 bitmap_start_frame: u64,
21 bitmap_end_frame: u64,
22}
23
24unsafe impl Send for Pmm {}
26unsafe impl Sync for Pmm {}
27
28impl Pmm {
29 pub fn init(entries: &[&memmap::Entry], hhdm_offset: u64) -> Self {
34 let mut max_entry = 0;
35
36 for entry in entries {
37 if entry.type_ != MEMMAP_USABLE {
38 continue;
39 }
40
41 if entry.base + entry.length > max_entry {
42 max_entry = entry.base + entry.length;
43 }
44 }
45
46 let total_frames = max_entry / FRAME_SIZE;
47 let bitmap_bytes = total_frames.div_ceil(8);
48
49 kdebug!("[PMM] total_frames={total_frames}");
50 kdebug!("[PMM] bitmap_bytes={bitmap_bytes}");
51
52 let mut _bitmap_physical_base_addr: Option<u64> = None;
53 let mut _bitmap_base_addr: Option<*mut u8> = None;
54
55 for entry in entries {
56 if entry.type_ != MEMMAP_USABLE {
57 continue;
58 }
59
60 if entry.length >= bitmap_bytes {
61 _bitmap_physical_base_addr = Some(entry.base);
62 _bitmap_base_addr = Some((entry.base + hhdm_offset) as *mut u8);
63 break;
64 }
65 }
66
67 if _bitmap_physical_base_addr.is_none()
68 || _bitmap_base_addr.is_none()
69 {
70 kernel_panic(
71 PanicCode::NoValidMemMapEntry,
72 "Could not find a usable memmap entry to place PMM bitmap in",
73 );
74 }
75
76 let bitmap_physical_base_addr = _bitmap_physical_base_addr.unwrap();
77 let bitmap_base_addr = _bitmap_base_addr.unwrap();
78
79 kdebug!("[PMM] bitmap_physical_base_addr={bitmap_physical_base_addr}");
80 kdebug!("[PMM] bitmap_base_addr={bitmap_base_addr:p}");
81
82 unsafe {
85 core::ptr::write_bytes(bitmap_base_addr, 0xFF, bitmap_bytes as usize);
86 }
87
88 let bitmap_start_frame = bitmap_physical_base_addr / FRAME_SIZE;
89
90 let bitmap_end_frame = ((bitmap_physical_base_addr + bitmap_bytes).div_ceil(FRAME_SIZE)) - 1;
92
93 kdebug!("[PMM] bitmap_start_frame={bitmap_start_frame}");
94 kdebug!("[PMM] bitmap_end_frame={bitmap_end_frame}");
95
96 for entry in entries {
97 if entry.type_ != MEMMAP_USABLE {
98 continue;
99 }
100
101 let first_frame = entry.base / FRAME_SIZE;
102 let frame_count = entry.length / FRAME_SIZE;
103
104 for frame in first_frame..(first_frame + frame_count) {
105 let frame_byte_offset = frame as usize / 8;
106 let frame_bit_offset = frame % 8;
107
108 if frame == 0 || (frame >= bitmap_start_frame && frame <= bitmap_end_frame) {
109 continue;
110 }
111
112 unsafe {
115 *bitmap_base_addr.add(frame_byte_offset) &= !(1 << (frame_bit_offset));
116 }
117 }
118 }
119
120 kinfo!("Initialized PMM");
121
122 Pmm {
123 bitmap_ptr: bitmap_base_addr,
124 total_frames: total_frames,
125 bitmap_start_frame: bitmap_start_frame,
126 bitmap_end_frame: bitmap_end_frame,
127 }
128 }
129
130 pub fn alloc(&self) -> Option<PhysAddr> {
132 for byte_index in 0..self.total_frames.div_ceil(8) {
133 unsafe {
135 let byte = *self.bitmap_ptr.add(byte_index as usize);
136
137 if byte == 0xFF {
138 continue;
139 }
140
141 let bit_position = u8::trailing_ones(byte);
142 *self.bitmap_ptr.add(byte_index as usize) |= 1 << bit_position;
143
144 let frame_index = byte_index * 8 + bit_position as u64;
145 let frame_address = frame_index * FRAME_SIZE;
146
147 return Some(PhysAddr::new_truncate(frame_address));
148 }
149 }
150
151 kemerg!("[PMM] unable to alloc() a frame, out of memory");
152
153 None
154 }
155
156 pub fn free(&self, addr: PhysAddr) {
162 let frame_index = addr.as_u64() / FRAME_SIZE;
163
164 if frame_index == 0 {
165 kernel_panic(
166 PanicCode::IllegalFree,
167 "Attempting to Pmm::free() frame 0",
168 );
169 }
170
171 if frame_index >= self.bitmap_start_frame && frame_index <= self.bitmap_end_frame {
172 kernel_panic(
173 PanicCode::IllegalFree,
174 "Attempting to Pmm::free() in the range of the pmm bitmap",
175 );
176 }
177
178 if frame_index >= self.total_frames {
179 kernel_panic(
180 PanicCode::IllegalFree,
181 "Attempting to Pmm::free() outside of usable memory",
182 );
183 }
184
185 let byte_offset = frame_index / 8;
186 let bit_offset = frame_index % 8;
187
188 unsafe {
190 let byte = *self.bitmap_ptr.add(byte_offset as usize);
191
192 if byte & (1 << bit_offset) == 0u8 {
193 kernel_panic(
194 PanicCode::DoubleFree,
195 "Attempting to Pmm::free() a frame which is already freed",
196 );
197 }
198
199 *self.bitmap_ptr.add(byte_offset as usize) &= !(1 << bit_offset);
200 }
201 }
202}