Switch to atomalloc for pmm

This commit is contained in:
Evie Viau-Chow-Stuart 2025-07-01 16:56:24 -07:00
parent 6481b85163
commit 62ab97f354
Signed by: evie
GPG key ID: 928652CDFCEC8099
3 changed files with 38 additions and 167 deletions

2
Cargo.lock generated
View file

@ -11,7 +11,7 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "atomalloc"
version = "0.1.0"
source = "git+https://forge.gaycatgirl.sex/hypericum/atomalloc.git?rev=6f6687429e5e89c16e813dbeab4af30e05e2e8a2#6f6687429e5e89c16e813dbeab4af30e05e2e8a2"
source = "git+https://forge.gaycatgirl.sex/hypericum/atomalloc.git?rev=c87a434ce7d3301782f1e141e39eedac467f2709#c87a434ce7d3301782f1e141e39eedac467f2709"
[[package]]
name = "autocfg"

View file

@ -6,7 +6,7 @@ license = "GPL-2.0-only"
[dependencies]
libgoatweed = { git = "https://forge.gaycatgirl.sex/hypericum/libgoatweed.git", rev = "31ac8671a3cfb338ae66957c963a9ced72fa2251" , default-features = false }
atomalloc = { git = "https://forge.gaycatgirl.sex/hypericum/atomalloc.git", rev = "6f6687429e5e89c16e813dbeab4af30e05e2e8a2", default-features = false, features = ["no_alloc"] }
atomalloc = { git = "https://forge.gaycatgirl.sex/hypericum/atomalloc.git", rev = "c87a434ce7d3301782f1e141e39eedac467f2709", default-features = false, features = ["no_alloc"] }
# bootloader info structs
limine = "0.5.0"

View file

@ -1,27 +1,19 @@
use crate::print;
use crate::println;
use core::ptr::slice_from_raw_parts_mut;
use core::sync::atomic::{AtomicUsize, Ordering};
use atomalloc::noalloc::AtomAlloc;
use limine::memory_map::{Entry, EntryType};
use spin::{Mutex, Once};
use x86_64::structures::paging::{FrameAllocator, FrameDeallocator, PhysFrame, Size4KiB};
use x86_64::PhysAddr;
use x86_64::structures::paging::{FrameAllocator, FrameDeallocator, PhysFrame, Size4KiB};
use crate::println;
// TODO: remake this entire thing
// TODO: rethink this
static FRAME_ALLOCATOR: Once<Mutex<PFrameAllocator>> = Once::new();
// TODO: rethink this
static mut FRAME_BITMAP: [u8; BITMAP_SIZE] = [0; BITMAP_SIZE];
pub const MAX_ATOMS: usize = 1024;
static ATOMS: Mutex<AtomAlloc<MAX_ATOMS, 4096>> = Mutex::new(AtomAlloc::new());
// TODO: rethink this
const BITMAP_SIZE: usize = 16384 * 4096 * 4;
pub const MAX_REGIONS: usize = 64;
static TOTAL_MEMORY: AtomicUsize = AtomicUsize::new(0);
static ALLOCATED_FRAMES: AtomicUsize = AtomicUsize::new(0);
#[repr(C)]
#[derive(PartialEq, Eq, Clone, Copy)]
@ -36,195 +28,74 @@ pub struct Region {
pub entry_type: EntryType,
}
pub struct PFrameAllocator {
usable_regions: [Option<Region>; MAX_REGIONS],
bitmap_base: u64,
last_allocated: usize,
}
pub struct PFrameAllocator {}
impl PFrameAllocator {
pub unsafe fn init(memory_map: &[&Entry]) {
let mut i = 0;
let mut usable_regions = [None; MAX_REGIONS];
let mut total_memory: usize = 0;
let mut min_addr = u64::MAX;
// lock atoms so we can add to it
let mut atoms = ATOMS.lock();
for e in memory_map {
let region = Region {
base: e.base,
end: e.base + e.length,
length: e.length,
entry_type: e.entry_type,
};
if e.entry_type == EntryType::USABLE {
usable_regions[i] = Some(region);
total_memory += e.length as usize;
min_addr = min_addr.min(e.base);
i += 1;
atoms.add_memory(e.base as usize, e.length.div_ceil(4096) as usize);
}
}
let bitmap_base = (min_addr / 4096) * 4096;
// we dont need it anymore, drop
drop(atoms);
TOTAL_MEMORY.store(total_memory, Ordering::Relaxed);
#[allow(static_mut_refs)]
FRAME_BITMAP.fill(0);
FRAME_ALLOCATOR.call_once(|| {
Mutex::new(PFrameAllocator {
usable_regions,
bitmap_base,
last_allocated: 0,
})
Mutex::new(PFrameAllocator {})
});
}
/// Convert physical address to bitmap index
fn addr_to_bitmap_index(&self, addr: u64) -> Option<usize> {
if addr < self.bitmap_base {
return None;
}
pub fn allocate_single_frame(&mut self) -> Option<PhysFrame<Size4KiB>> {
let mut atoms = ATOMS.lock();
let frame_number = (addr - self.bitmap_base) / 4096;
let bit_index = frame_number as usize;
if bit_index >= BITMAP_SIZE * 8 {
None
let frame = if let Some(frame) = atoms.allocate(1) {
frame
} else {
Some(bit_index)
}
}
// out of memory? lets defrag first
atoms.defragment();
/// Convert bitmap index to physical address
fn bitmap_index_to_addr(&self, index: usize) -> u64 {
self.bitmap_base + (index as u64 * 4096)
}
if let Some(frame) = atoms.allocate(1) {
frame
} else {
println!("Out of memory!");
/// Check if a frame is allocated in the bitmap
fn is_frame_allocated(&self, bit_index: usize) -> bool {
let byte_index = bit_index / 8;
let bit_offset = bit_index % 8;
if byte_index >= BITMAP_SIZE {
return true;
}
unsafe {
(FRAME_BITMAP[byte_index] & (1 << bit_offset)) != 0
}
}
/// Set a frame as allocated in the bitmap
fn set_frame_allocated(&mut self, bit_index: usize) {
let byte_index = bit_index / 8;
let bit_offset = bit_index % 8;
if byte_index < BITMAP_SIZE {
unsafe {
FRAME_BITMAP[byte_index] |= 1 << bit_offset;
return None;
}
}
};
drop(atoms);
PhysFrame::from_start_address(PhysAddr::new(frame as u64)).ok()
}
/// Set a frame as free in the bitmap
fn set_frame_free(&mut self, bit_index: usize) {
let byte_index = bit_index / 8;
let bit_offset = bit_index % 8;
if byte_index < BITMAP_SIZE {
unsafe {
FRAME_BITMAP[byte_index] &= !(1 << bit_offset);
}
}
pub fn deallocate_single_frame(&mut self, frame: PhysFrame<Size4KiB>) {
ATOMS.lock().deallocate(frame.start_address().as_u64() as usize, 1)
}
/// Check if an address is in any usable region
fn is_addr_usable(&self, addr: u64) -> bool {
for region_opt in &self.usable_regions {
if let Some(region) = region_opt {
if addr >= region.base && addr < region.end {
return true;
}
}
}
false
}
fn find_free_frame(&mut self) -> Option<PhysFrame<Size4KiB>> {
let max_frames = BITMAP_SIZE * 8;
for offset in 0..max_frames {
let index = (self.last_allocated + offset) % max_frames;
if !self.is_frame_allocated(index) {
let addr = self.bitmap_index_to_addr(index);
if self.is_addr_usable(addr) {
self.last_allocated = index;
return Some(PhysFrame::containing_address(PhysAddr::new(addr)));
}
}
}
None
pub fn total_memory() -> usize {
TOTAL_MEMORY.load(Ordering::Relaxed)
}
}
unsafe impl FrameAllocator<Size4KiB> for PFrameAllocator {
fn allocate_frame(&mut self) -> Option<PhysFrame<Size4KiB>> {
if let Some(frame) = self.find_free_frame() {
let addr = frame.start_address().as_u64();
if let Some(bit_index) = self.addr_to_bitmap_index(addr) {
print!(
"Found frame at {:#x} ({} bytes)",
addr,
frame.size()
);
self.set_frame_allocated(bit_index);
ALLOCATED_FRAMES.fetch_add(1, Ordering::Relaxed);
// ensure memory is cleared
unsafe {
print!("! Clearing memory...");
slice_from_raw_parts_mut(addr as *mut u8, frame.size() as usize).as_mut()?.fill(0);
}
print!(" Allocated!\n");
Some(frame)
} else {
println!("cant convert address to bitmap?");
None
}
} else {
println!("no free frame :(");
None
}
self.allocate_single_frame()
}
}
impl FrameDeallocator<Size4KiB> for PFrameAllocator {
unsafe fn deallocate_frame(&mut self, frame: PhysFrame<Size4KiB>) {
let addr = frame.start_address().as_u64();
if !self.is_addr_usable(addr) {
return;
}
if let Some(bit_index) = self.addr_to_bitmap_index(addr) {
if self.is_frame_allocated(bit_index) {
self.set_frame_free(bit_index);
ALLOCATED_FRAMES.fetch_sub(1, Ordering::Relaxed);
self.last_allocated = bit_index;
}
}
self.deallocate_single_frame(frame);
}
}