Nothing to see here, move along
1use lancer_core::bitmap::bitmap_seal::Sealed;
2use lancer_core::bitmap::{BitmapAllocator as BitmapCore, BitmapBacking};
3use limine::memory_map::{Entry, EntryType};
4use x86_64::PhysAddr;
5use x86_64::structures::paging::{FrameAllocator, PhysFrame, Size4KiB};
6
7use super::RawSlice;
8use super::addr;
9use super::frame::OwnedFrame;
10use crate::sync::IrqMutex;
11
12const PAGE_SIZE: u64 = 4096;
13
14static BITMAP_PHYS_BASE: core::sync::atomic::AtomicU64 = core::sync::atomic::AtomicU64::new(0);
15static BITMAP_BYTE_COUNT: core::sync::atomic::AtomicU64 = core::sync::atomic::AtomicU64::new(0);
16
17#[allow(dead_code)]
18pub fn bitmap_region() -> (u64, u64) {
19 (
20 BITMAP_PHYS_BASE.load(core::sync::atomic::Ordering::Relaxed),
21 BITMAP_BYTE_COUNT.load(core::sync::atomic::Ordering::Relaxed),
22 )
23}
24
25impl Sealed for RawSlice<u64> {}
26impl BitmapBacking for RawSlice<u64> {
27 fn chunks(&self) -> &[u64] {
28 self.as_slice()
29 }
30
31 fn chunks_mut(&mut self) -> &mut [u64] {
32 self.as_slice_mut()
33 }
34}
35
36static BITMAP: IrqMutex<BitmapCore<RawSlice<u64>>, 3> =
37 IrqMutex::new(BitmapCore::from_backing(RawSlice::empty()));
38
39pub struct BitmapFrameAllocator;
40
41impl BitmapFrameAllocator {
42 pub fn init(memory_map: &[&Entry]) {
43 let max_addr = memory_map
44 .iter()
45 .filter(|entry| entry.entry_type == EntryType::USABLE)
46 .map(|entry| entry.base + entry.length)
47 .fold(0u64, u64::max);
48
49 let total_frames = (max_addr / PAGE_SIZE) as usize;
50 let chunks_needed = total_frames.div_ceil(64);
51 let bitmap_bytes = chunks_needed * 8;
52 let bitmap_frames = bitmap_bytes.div_ceil(PAGE_SIZE as usize);
53
54 let bitmap_region = memory_map
55 .iter()
56 .filter(|entry| entry.entry_type == EntryType::USABLE)
57 .find(|entry| entry.length >= (bitmap_frames as u64) * PAGE_SIZE)
58 .expect("[phys] no usable region large enough for bitmap");
59
60 let bitmap_phys_base = bitmap_region.base;
61 BITMAP_PHYS_BASE.store(bitmap_phys_base, core::sync::atomic::Ordering::Relaxed);
62 BITMAP_BYTE_COUNT.store(
63 (bitmap_frames as u64) * PAGE_SIZE,
64 core::sync::atomic::Ordering::Relaxed,
65 );
66 let bitmap_virt = addr::phys_to_virt(PhysAddr::new(bitmap_phys_base));
67 assert!(
68 bitmap_virt.is_aligned(8u64),
69 "bitmap backing memory not 8-byte aligned"
70 );
71 let bitmap_ptr = bitmap_virt.as_u64() as *mut u64;
72
73 let mut bm = BITMAP.lock();
74 let mut backing = RawSlice::empty();
75 backing.init(bitmap_ptr, chunks_needed);
76 *bm = BitmapCore::from_backing(backing);
77 bm.init(total_frames);
78
79 memory_map
80 .iter()
81 .filter(|entry| entry.entry_type == EntryType::USABLE)
82 .for_each(|entry| {
83 let start_frame = (entry.base / PAGE_SIZE) as usize;
84 let end_frame = ((entry.base + entry.length) / PAGE_SIZE) as usize;
85 bm.mark_range_free(start_frame..end_frame);
86 });
87
88 let bitmap_start_frame = (bitmap_phys_base / PAGE_SIZE) as usize;
89 (bitmap_start_frame..bitmap_start_frame + bitmap_frames).for_each(|idx| bm.mark_used(idx));
90
91 bm.mark_used(0);
92 }
93
94 pub fn allocate_contiguous(&self, count: usize) -> Option<PhysAddr> {
95 BITMAP
96 .lock()
97 .allocate_contiguous(count)
98 .map(|idx| PhysAddr::new((idx as u64) * PAGE_SIZE))
99 }
100
101 pub fn allocate(&self) -> Option<OwnedFrame> {
102 let mut bm = BITMAP.lock();
103 bm.allocate().map(|idx| {
104 let phys = PhysAddr::new((idx as u64) * PAGE_SIZE);
105 OwnedFrame::new(PhysFrame::containing_address(phys))
106 })
107 }
108
109 pub(crate) fn free_frame_by_addr(phys: PhysAddr) {
110 let mut bm = BITMAP.lock();
111 let frame_idx = (phys.as_u64() / PAGE_SIZE) as usize;
112 bm.deallocate(frame_idx).unwrap_or_else(|_| {
113 panic!(
114 "[phys] invariant violation: double-free of frame {:#x}",
115 phys.as_u64()
116 )
117 });
118 }
119
120 #[allow(dead_code)]
121 pub fn deallocate(&self, frame: OwnedFrame) {
122 Self::free_frame_by_addr(frame.inner().start_address());
123 }
124
125 pub fn deallocate_frame(&self, frame: PhysFrame<Size4KiB>) {
126 Self::free_frame_by_addr(frame.start_address());
127 }
128
129 #[allow(dead_code)]
130 pub fn mark_used(idx: usize) {
131 BITMAP.lock().mark_used(idx);
132 }
133
134 #[allow(dead_code)]
135 pub fn is_used(idx: usize) -> bool {
136 BITMAP.lock().is_used(idx)
137 }
138
139 pub fn total_frames() -> usize {
140 BITMAP.lock().total_items()
141 }
142
143 #[allow(dead_code)]
144 pub fn used_frames() -> usize {
145 BITMAP.lock().used_items()
146 }
147
148 pub fn free_frames() -> usize {
149 BITMAP.lock().free_items()
150 }
151
152 pub fn for_each_used_range<F: FnMut(usize, usize)>(f: &mut F) {
153 BITMAP.lock().for_each_used_range(f);
154 }
155}
156
157unsafe impl FrameAllocator<Size4KiB> for BitmapFrameAllocator {
158 fn allocate_frame(&mut self) -> Option<PhysFrame<Size4KiB>> {
159 self.allocate().map(|tf| tf.inner())
160 }
161}
162
163#[allow(dead_code)]
164pub fn log_memory_map(memory_map: &[&Entry]) {
165 crate::kprintln!(" Memory map ({} entries):", memory_map.len());
166 memory_map.iter().for_each(|entry| {
167 let entry_type_str = match entry.entry_type {
168 EntryType::USABLE => "Usable",
169 EntryType::RESERVED => "Reserved",
170 EntryType::ACPI_RECLAIMABLE => "ACPI Reclaimable",
171 EntryType::ACPI_NVS => "ACPI NVS",
172 EntryType::BAD_MEMORY => "Bad Memory",
173 EntryType::BOOTLOADER_RECLAIMABLE => "Bootloader Reclaimable",
174 EntryType::EXECUTABLE_AND_MODULES => "Kernel/Modules",
175 EntryType::FRAMEBUFFER => "Framebuffer",
176 _ => "Unknown",
177 };
178 let size_kb = entry.length / 1024;
179 crate::kprintln!(
180 " {:#016x} - {:#016x} ({:>8} KB) {}",
181 entry.base,
182 entry.base + entry.length,
183 size_kb,
184 entry_type_str
185 );
186 });
187}
188
189pub fn frame_stats() -> (usize, usize) {
190 (
191 BitmapFrameAllocator::total_frames(),
192 BitmapFrameAllocator::free_frames(),
193 )
194}
195
196#[allow(dead_code)]
197pub fn log_frame_stats() {
198 crate::kprintln!(" Frame allocator stats:");
199 crate::kprintln!(" Total frames: {}", BitmapFrameAllocator::total_frames());
200 crate::kprintln!(" Used frames: {}", BitmapFrameAllocator::used_frames());
201 crate::kprintln!(" Free frames: {}", BitmapFrameAllocator::free_frames());
202 crate::kprintln!(
203 " Free memory: {} MB",
204 BitmapFrameAllocator::free_frames() * 4096 / (1024 * 1024)
205 );
206}