kernel: pmm: allocate pages
This commit is contained in:
parent
9c3a795a61
commit
549b94d34c
|
|
@ -39,6 +39,10 @@ impl MemoryRegionType {
|
||||||
pub fn is_usable(&self) -> bool {
|
pub fn is_usable(&self) -> bool {
|
||||||
matches!(self, Self::Usable | Self::AcpiReclaimable)
|
matches!(self, Self::Usable | Self::AcpiReclaimable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mapped_non_usable(&self) -> bool {
|
||||||
|
matches!(self, Self::Framebuffer | Self::FirmwareReserved)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
|
@ -48,6 +52,15 @@ pub struct MemoryRegion {
|
||||||
pub region_type: MemoryRegionType,
|
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<limine::MemMapEntry> for MemoryRegion {
|
impl From<limine::MemMapEntry> for MemoryRegion {
|
||||||
fn from(entry: limine::MemMapEntry) -> Self {
|
fn from(entry: limine::MemMapEntry) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
|
||||||
|
|
@ -183,6 +183,49 @@ impl PhysicalMemoryManager {
|
||||||
pmm
|
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) {
|
fn free_region(&mut self, page_index: usize, mut count: usize) {
|
||||||
serial_println!(
|
serial_println!(
|
||||||
"Freeing region: page_index = {:#x}, count = {:#x}",
|
"Freeing region: page_index = {:#x}, count = {:#x}",
|
||||||
|
|
@ -309,8 +352,13 @@ impl Debug for PhysicalMemoryAllocator {
|
||||||
|
|
||||||
impl PhysicalMemoryAllocator {
|
impl PhysicalMemoryAllocator {
|
||||||
pub fn from_memory_map(memory_map: &[crate::boot::MemoryRegion]) -> Self {
|
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
|
let usable_regions = memory_map
|
||||||
.iter()
|
.iter()
|
||||||
|
.copied()
|
||||||
.filter(|region| region.region_type.is_usable());
|
.filter(|region| region.region_type.is_usable());
|
||||||
|
|
||||||
let mut pmm = PhysicalMemoryAllocator {
|
let mut pmm = PhysicalMemoryAllocator {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue