feat: paging + cleanup across memory management and other stuff
This commit is contained in:
+48
-113
@@ -1,5 +1,3 @@
|
||||
use core::ops::Range;
|
||||
|
||||
use crate::memory::{DirectMap, MemoryRegion, MemoryRegionKind, PhysicalAddr, VirtualAddr};
|
||||
|
||||
pub const FRAME_SIZE: usize = 4096;
|
||||
@@ -13,102 +11,53 @@ pub fn align_down_to_frame(addr: usize) -> usize {
|
||||
addr & !(FRAME_SIZE - 1)
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
enum FrameState {
|
||||
Reserved = 0b00,
|
||||
Free = 0b01,
|
||||
Allocated = 0b10,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Bitmap {
|
||||
start: VirtualAddr,
|
||||
bit_count: usize,
|
||||
frame_count: usize,
|
||||
}
|
||||
|
||||
// 1 = available, 0 = unavailable
|
||||
impl Bitmap {
|
||||
fn new(start: VirtualAddr, bit_count: usize) -> Self {
|
||||
Self { start, bit_count }
|
||||
fn new(start: VirtualAddr, frame_count: usize) -> Self {
|
||||
Self { start, frame_count }
|
||||
}
|
||||
|
||||
fn is_available(&self, idx: usize) -> bool {
|
||||
assert!(idx < self.bit_count, "index out of bounds");
|
||||
fn state(&self, frame_idx: usize) -> FrameState {
|
||||
assert!(frame_idx < self.frame_count, "frame index out of bounds");
|
||||
|
||||
let byte = idx / 8;
|
||||
let bit = idx % 8;
|
||||
let byte_idx = frame_idx / 4;
|
||||
let shift = (frame_idx % 4) * 2;
|
||||
let byte = unsafe { self.start.as_ptr::<u8>().add(byte_idx).read() };
|
||||
|
||||
unsafe { self.start.as_mut_ptr::<u8>().add(byte).read() & (1 << bit) != 0 }
|
||||
}
|
||||
|
||||
fn set_available(&mut self, idx: usize, available: bool) {
|
||||
assert!(idx < self.bit_count, "index out of bounds");
|
||||
|
||||
let byte = idx / 8;
|
||||
let bit = idx % 8;
|
||||
|
||||
let val = unsafe { self.start.as_mut_ptr::<u8>().add(byte).read() };
|
||||
unsafe {
|
||||
self.start.as_mut_ptr::<u8>().add(byte).write(if available {
|
||||
val | (1 << bit)
|
||||
} else {
|
||||
val & !(1 << bit)
|
||||
});
|
||||
match (byte >> shift) & 0b11 {
|
||||
0b00 => FrameState::Reserved,
|
||||
0b01 => FrameState::Free,
|
||||
0b10 => FrameState::Allocated,
|
||||
_ => panic!("invalid frame state"),
|
||||
}
|
||||
}
|
||||
|
||||
// fn fill_available(&mut self, range: Range<usize>, available: bool) -> bool {
|
||||
// if range.start > range.end {
|
||||
// return false;
|
||||
// }
|
||||
fn set_state(&mut self, frame_idx: usize, state: FrameState) {
|
||||
assert!(frame_idx < self.frame_count, "frame index out of bounds");
|
||||
|
||||
// if range.end > self.bit_count {
|
||||
// return false;
|
||||
// }
|
||||
let byte_idx = frame_idx / 4;
|
||||
let shift = (frame_idx % 4) * 2;
|
||||
let ptr = unsafe { self.start.as_mut_ptr::<u8>().add(byte_idx) };
|
||||
let byte = unsafe { ptr.read() };
|
||||
let mask = 0b11 << shift;
|
||||
|
||||
// if range.is_empty() {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// let ptr = unsafe { self.start.as_mut_ptr::<u8>() };
|
||||
// let first_byte = range.start / 8;
|
||||
// let last_byte = (range.end - 1) / 8;
|
||||
// let start_bit = range.start % 8;
|
||||
// let end_bit = range.end % 8;
|
||||
|
||||
// unsafe {
|
||||
// if first_byte == last_byte {
|
||||
// let width = range.end - range.start;
|
||||
// let mask = (((1u16 << width) - 1) << start_bit) as u8;
|
||||
// let byte = ptr.add(first_byte).read();
|
||||
|
||||
// ptr.add(first_byte)
|
||||
// .write(if available { byte | mask } else { byte & !mask });
|
||||
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// let mut full_start = first_byte;
|
||||
|
||||
// if start_bit != 0 {
|
||||
// let mask = u8::MAX << start_bit;
|
||||
// let byte = ptr.add(first_byte).read();
|
||||
|
||||
// ptr.add(first_byte)
|
||||
// .write(if available { byte | mask } else { byte & !mask });
|
||||
|
||||
// full_start += 1;
|
||||
// }
|
||||
|
||||
// let full_end = range.end / 8;
|
||||
|
||||
// ptr.add(full_start)
|
||||
// .write_bytes(if available { u8::MAX } else { 0 }, full_end - full_start);
|
||||
|
||||
// if end_bit != 0 {
|
||||
// let mask = (1u8 << end_bit) - 1;
|
||||
// let byte = ptr.add(full_end).read();
|
||||
|
||||
// ptr.add(full_end)
|
||||
// .write(if available { byte | mask } else { byte & !mask });
|
||||
// }
|
||||
// }
|
||||
|
||||
// true
|
||||
// }
|
||||
unsafe {
|
||||
ptr.write((byte & !mask) | ((state as u8) << shift));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -123,8 +72,6 @@ pub enum FrameAllocatorInitError {
|
||||
#[derive(Debug)]
|
||||
pub struct FrameAllocator {
|
||||
bitmap: Bitmap,
|
||||
bitmap_start_frame: usize,
|
||||
bitmap_frame_count: usize,
|
||||
next_search: usize,
|
||||
allocatable_frames: usize,
|
||||
free_frames: usize,
|
||||
@@ -153,7 +100,7 @@ impl FrameAllocator {
|
||||
|
||||
let highest_frame = highest_frame.ok_or(FrameAllocatorInitError::NoUsableFrames)?;
|
||||
|
||||
let bitmap_bytes = highest_frame.div_ceil(8);
|
||||
let bitmap_bytes = highest_frame.div_ceil(4);
|
||||
let bitmap_frame_count = bitmap_bytes.div_ceil(FRAME_SIZE);
|
||||
let bitmap_storage_bytes = bitmap_frame_count
|
||||
.checked_mul(FRAME_SIZE)
|
||||
@@ -215,7 +162,7 @@ impl FrameAllocator {
|
||||
continue;
|
||||
}
|
||||
|
||||
bitmap.set_available(frame_idx, true);
|
||||
bitmap.set_state(frame_idx, FrameState::Free);
|
||||
allocatable_frames += 1;
|
||||
free_frames += 1;
|
||||
}
|
||||
@@ -223,8 +170,6 @@ impl FrameAllocator {
|
||||
|
||||
Ok(Self {
|
||||
bitmap,
|
||||
bitmap_start_frame: bitmap_start_frame,
|
||||
bitmap_frame_count,
|
||||
next_search: bitmap_start_frame + bitmap_frame_count,
|
||||
allocatable_frames,
|
||||
free_frames,
|
||||
@@ -233,11 +178,11 @@ impl FrameAllocator {
|
||||
}
|
||||
|
||||
fn find_free_in(&self, start: usize, end: usize) -> Option<usize> {
|
||||
(start..end).find(|&index| self.bitmap.is_available(index))
|
||||
(start..end).find(|&index| self.bitmap.state(index) == FrameState::Free)
|
||||
}
|
||||
|
||||
fn find_free_frame(&self) -> Option<usize> {
|
||||
self.find_free_in(self.next_search, self.bitmap.bit_count)
|
||||
self.find_free_in(self.next_search, self.bitmap.frame_count)
|
||||
.or_else(|| self.find_free_in(0, self.next_search))
|
||||
}
|
||||
|
||||
@@ -248,7 +193,7 @@ impl FrameAllocator {
|
||||
|
||||
let frame_idx = self.find_free_frame()?;
|
||||
|
||||
self.bitmap.set_available(frame_idx, false);
|
||||
self.bitmap.set_state(frame_idx, FrameState::Allocated);
|
||||
self.free_frames -= 1;
|
||||
self.next_search = frame_idx.saturating_add(1);
|
||||
|
||||
@@ -279,22 +224,17 @@ impl FrameAllocator {
|
||||
pub unsafe fn dealloc(&mut self, frame: PhysicalFrame) {
|
||||
let frame_idx = frame.index();
|
||||
|
||||
assert!(
|
||||
frame_idx < self.bitmap.bit_count,
|
||||
"frame index out of bounds"
|
||||
);
|
||||
assert!(
|
||||
!self.is_bitmap_storage(frame_idx),
|
||||
"attempted to free frame allocator bitmap"
|
||||
);
|
||||
assert!(
|
||||
!self.bitmap.is_available(frame_idx),
|
||||
"frame is already free"
|
||||
);
|
||||
|
||||
self.bitmap.set_available(frame_idx, true);
|
||||
self.free_frames += 1;
|
||||
self.next_search = self.next_search.min(frame_idx);
|
||||
match self.bitmap.state(frame_idx) {
|
||||
FrameState::Allocated => {
|
||||
self.bitmap.set_state(frame_idx, FrameState::Free);
|
||||
self.free_frames += 1;
|
||||
self.next_search = self.next_search.min(frame_idx);
|
||||
}
|
||||
FrameState::Free => panic!("attempted to free free frame"),
|
||||
FrameState::Reserved => {
|
||||
panic!("attempted to free reserved frame");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub const fn free_frames(&self) -> usize {
|
||||
@@ -305,11 +245,6 @@ impl FrameAllocator {
|
||||
self.allocatable_frames
|
||||
}
|
||||
|
||||
fn is_bitmap_storage(&self, index: usize) -> bool {
|
||||
index >= self.bitmap_start_frame
|
||||
&& index < (self.bitmap_start_frame + self.bitmap_frame_count)
|
||||
}
|
||||
|
||||
fn usable_frame_range(
|
||||
region: MemoryRegion,
|
||||
) -> Result<core::ops::Range<usize>, FrameAllocatorInitError> {
|
||||
|
||||
Reference in New Issue
Block a user