From 549b94d34ce4e9ec0e7450e518bc0989f61a2387 Mon Sep 17 00:00:00 2001 From: janis Date: Tue, 4 Aug 2026 18:16:55 +0200 Subject: [PATCH] kernel: pmm: allocate pages --- kernel/src/boot.rs | 13 ++++++++++++ kernel/src/memory.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/kernel/src/boot.rs b/kernel/src/boot.rs index b1ad0fd..9cc0915 100644 --- a/kernel/src/boot.rs +++ b/kernel/src/boot.rs @@ -39,6 +39,10 @@ impl MemoryRegionType { pub fn is_usable(&self) -> bool { matches!(self, Self::Usable | Self::AcpiReclaimable) } + + pub fn mapped_non_usable(&self) -> bool { + matches!(self, Self::Framebuffer | Self::FirmwareReserved) + } } #[derive(Debug, Clone, Copy)] @@ -48,6 +52,15 @@ pub struct MemoryRegion { pub region_type: MemoryRegionType, } +impl MemoryRegion { + pub fn overlaps(&self, other: &Self) -> bool { + let self_end = self.start + self.length; + let other_end = other.start + other.length; + + !(self_end <= other.start || other_end <= self.start) + } +} + impl From for MemoryRegion { fn from(entry: limine::MemMapEntry) -> Self { Self { diff --git a/kernel/src/memory.rs b/kernel/src/memory.rs index 8e71ebe..50200e0 100644 --- a/kernel/src/memory.rs +++ b/kernel/src/memory.rs @@ -183,6 +183,49 @@ impl PhysicalMemoryManager { pmm } + pub fn allocate_pages(&mut self, count: usize) -> Option<(PhyAddr, usize)> { + let bin = count.next_power_of_two().trailing_zeros() as usize; + + if let Some(chunk) = self.buddies[bin].pop_min() { + return unsafe { chunk.as_ref().phy().map(|phy| (phy, 1 << bin)) }; + } + + // the bin is empty, try to find a larger chunk and split it into two smaller chunks + let mut bin_offs = 1; + + let chunk = loop { + if bin + bin_offs >= self.buddies.len() { + return None; + } + + match self.buddies[bin + bin_offs].pop_min() { + Some(chunk) => break chunk, + None => bin_offs += 1, + } + }; + + // the chunk is too big; split it into two smaller chunks recursively until we have a chunk of the desired size. + for bin_offs in (1..=bin_offs).rev() { + // the chunk is size 2^(bin + bin_offs), it can be split into two + // chunks of size 2^(bin + bin_offs - 1), where the first chunk + // starts at `chunk` and the second chunk starts at `chunk + 2^(bin + // + bin_offs - 1)`. + let buddy_index = PhysicalPageNode::page_index(chunk) + (1 << (bin + bin_offs - 1)); + + let buddy = PhysicalPageNode::new_from_page_index(buddy_index); + + let None = self.buddies[bin + bin_offs - 1].insert_node(buddy) else { + panic!( + "Attempted to free a region that is already free: page_index = {}, count = {}", + buddy_index, + 1 << (bin + bin_offs - 1) + ) + }; + } + + unsafe { chunk.as_ref().phy().map(|phy| (phy, 1 << bin)) } + } + fn free_region(&mut self, page_index: usize, mut count: usize) { serial_println!( "Freeing region: page_index = {:#x}, count = {:#x}", @@ -309,8 +352,13 @@ impl Debug for PhysicalMemoryAllocator { impl PhysicalMemoryAllocator { pub fn from_memory_map(memory_map: &[crate::boot::MemoryRegion]) -> Self { + let mapped_non_usable_regions = memory_map + .iter() + .filter(|region| region.region_type.mapped_non_usable()); + let usable_regions = memory_map .iter() + .copied() .filter(|region| region.region_type.is_usable()); let mut pmm = PhysicalMemoryAllocator {