mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-17 06:47:49 +00:00
Add an AreaFrameAllocator
This commit is contained in:
67
src/memory/area_frame_allocator.rs
Normal file
67
src/memory/area_frame_allocator.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
use memory::Frame;
|
||||
use multiboot2::{MemoryAreaIter, MemoryArea};
|
||||
|
||||
/// A frame allocator that uses the memory areas from the multiboot information structure as
|
||||
/// source. The {kernel, multiboot}_{start, end} fields are used to avoid returning memory that is
|
||||
/// already in use.
|
||||
///
|
||||
/// `kernel_end` and `multiboot_end` are _inclusive_ bounds.
|
||||
pub struct AreaFrameAllocator {
|
||||
next_free_frame: Frame,
|
||||
current_area: Option<&'static MemoryArea>,
|
||||
areas: MemoryAreaIter,
|
||||
kernel_start: Frame,
|
||||
kernel_end: Frame,
|
||||
multiboot_start: Frame,
|
||||
multiboot_end: Frame,
|
||||
}
|
||||
|
||||
impl AreaFrameAllocator {
|
||||
pub fn new(kernel_start: usize, kernel_end: usize, multiboot_start: usize, multiboot_end: usize,
|
||||
memory_areas: MemoryAreaIter) -> AreaFrameAllocator
|
||||
{
|
||||
let mut allocator = AreaFrameAllocator {
|
||||
next_free_frame: Frame::containing_address(0),
|
||||
current_area: None,
|
||||
areas: memory_areas,
|
||||
kernel_start: Frame::containing_address(kernel_start),
|
||||
kernel_end: Frame::containing_address(kernel_end),
|
||||
multiboot_start: Frame::containing_address(multiboot_start),
|
||||
multiboot_end: Frame::containing_address(multiboot_end),
|
||||
};
|
||||
allocator.choose_next_area();
|
||||
allocator
|
||||
}
|
||||
|
||||
pub fn allocate_frame(&mut self) -> Option<Frame> {
|
||||
match self.current_area {
|
||||
None => None,
|
||||
Some(area) => {
|
||||
let frame = self.next_free_frame;
|
||||
let current_area_last_frame = {
|
||||
let address = area.base_addr + area.length - 1;
|
||||
Frame::containing_address(address as usize)
|
||||
};
|
||||
|
||||
if frame > current_area_last_frame {
|
||||
self.choose_next_area()
|
||||
} else if frame >= self.kernel_start && frame <= self.kernel_end {
|
||||
self.next_free_frame = Frame{ number: self.kernel_end.number + 1 }
|
||||
} else if frame >= self.multiboot_start && frame <= self.multiboot_end {
|
||||
self.next_free_frame = Frame{ number: self.multiboot_end.number + 1 }
|
||||
} else {
|
||||
self.next_free_frame.number += 1;
|
||||
return Some(frame);
|
||||
}
|
||||
self.allocate_frame()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn choose_next_area(&mut self) {
|
||||
self.current_area = self.areas.clone().filter(|area| {
|
||||
let address = area.base_addr + area.length - 1;
|
||||
Frame::containing_address(address as usize) >= self.next_free_frame
|
||||
}).min_by(|area| area.base_addr);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,7 @@
|
||||
pub use self::area_frame_allocator::AreaFrameAllocator;
|
||||
|
||||
mod area_frame_allocator;
|
||||
|
||||
pub const PAGE_SIZE: usize = 4096;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
||||
Reference in New Issue
Block a user