Switch to atomalloc for pmm
This commit is contained in:
parent
6481b85163
commit
62ab97f354
3 changed files with 38 additions and 167 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue