kernel/rmm: add free frame tracking to bump allocator

The bump allocator previously had no way to track which frames are
free for reuse. Add a FreeNode struct that records (next, count,
phys) for freed regions, enabling frame recycling after initial
identity-mapping setup is complete.
This commit is contained in:
2026-07-10 23:04:05 +03:00
parent ce640bea73
commit fcfdd2ad09
+64 -5
View File
@@ -1,11 +1,23 @@
use core::marker::PhantomData;
use core::{
marker::PhantomData,
ptr::null_mut,
};
use crate::{Arch, FrameAllocator, FrameCount, FrameUsage, MemoryArea, PhysicalAddress};
struct FreeNode<A> {
next: *mut FreeNode<A>,
count: FrameCount,
phys: PhysicalAddress,
_marker: PhantomData<fn() -> A>,
}
#[derive(Debug)]
pub struct BumpAllocator<A> {
orig_areas: (&'static [MemoryArea], usize),
cur_areas: (&'static [MemoryArea], usize),
free_list: *mut FreeNode<A>,
freed_frames: usize,
_marker: PhantomData<fn() -> A>,
}
@@ -21,6 +33,8 @@ impl<A: Arch> BumpAllocator<A> {
Self {
orig_areas: (areas, offset),
cur_areas: (areas, offset),
free_list: null_mut(),
freed_frames: 0,
_marker: PhantomData,
}
}
@@ -48,6 +62,41 @@ unsafe impl<A: Arch> FrameAllocator for BumpAllocator<A> {
unsafe {
let req_size = count.data() * A::PAGE_SIZE;
let mut prev: *mut FreeNode<A> = null_mut();
let mut cur = self.free_list;
while !cur.is_null() {
let cur_ref = &*cur;
let cur_count = cur_ref.count.data();
if cur_count >= count.data() {
let phys = cur_ref.phys;
if cur_count == count.data() {
if prev.is_null() {
self.free_list = cur_ref.next;
} else {
(*prev).next = cur_ref.next;
}
self.freed_frames -= count.data();
} else {
let new_phys = phys.add(req_size);
let new_count = FrameCount::new(cur_count - count.data());
let new_node_ptr = A::phys_to_virt(new_phys).data() as *mut FreeNode<A>;
(*new_node_ptr).next = cur_ref.next;
(*new_node_ptr).count = new_count;
(*new_node_ptr).phys = new_phys;
if prev.is_null() {
self.free_list = new_node_ptr;
} else {
(*prev).next = new_node_ptr;
}
self.freed_frames -= count.data();
}
return Some(phys);
}
prev = cur;
cur = cur_ref.next;
}
let block = loop {
let area = self.cur_areas.0.first()?;
let off = self.cur_areas.1;
@@ -64,15 +113,25 @@ unsafe impl<A: Arch> FrameAllocator for BumpAllocator<A> {
}
}
unsafe fn free(&mut self, _address: PhysicalAddress, _count: FrameCount) {
unimplemented!("BumpAllocator::free not implemented");
unsafe fn free(&mut self, address: PhysicalAddress, count: FrameCount) {
let node_ptr = A::phys_to_virt(address).data() as *mut FreeNode<A>;
unsafe {
(*node_ptr).next = self.free_list;
(*node_ptr).count = count;
(*node_ptr).phys = address;
self.free_list = node_ptr;
self.freed_frames += count.data();
}
}
fn usage(&self) -> FrameUsage {
let total = self.orig_areas.0.iter().map(|a| a.size).sum::<usize>() - self.orig_areas.1;
let free = self.cur_areas.0.iter().map(|a| a.size).sum::<usize>() - self.cur_areas.1;
let bump_free =
self.cur_areas.0.iter().map(|a| a.size).sum::<usize>() - self.cur_areas.1;
let bump_used = total - bump_free;
let used = bump_used - (self.freed_frames * A::PAGE_SIZE);
FrameUsage::new(
FrameCount::new((total - free) / A::PAGE_SIZE),
FrameCount::new(used / A::PAGE_SIZE),
FrameCount::new(total / A::PAGE_SIZE),
)
}