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:
@@ -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),
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user