Reorganize kernel memory mappings

This commit is contained in:
Jeremy Soller 2016-09-10 18:48:27 -06:00
commit ce717ff277
3 changed files with 105 additions and 64 deletions

View file

@ -0,0 +1,81 @@
//! # Area frame allocator
//! Some code was borrowed from [Phil Opp's Blog](http://os.phil-opp.com/allocating-frames.html)
use paging::PhysicalAddress;
use super::{Frame, FrameAllocator, MemoryArea, MemoryAreaIter};
pub struct AreaFrameAllocator {
next_free_frame: Frame,
current_area: Option<&'static MemoryArea>,
areas: MemoryAreaIter,
kernel_start: Frame,
kernel_end: Frame
}
impl AreaFrameAllocator {
pub fn new(kernel_start: usize, kernel_end: usize, memory_areas: MemoryAreaIter) -> AreaFrameAllocator {
let mut allocator = AreaFrameAllocator {
next_free_frame: Frame::containing_address(PhysicalAddress::new(0)),
current_area: None,
areas: memory_areas,
kernel_start: Frame::containing_address(PhysicalAddress::new(kernel_start)),
kernel_end: Frame::containing_address(PhysicalAddress::new(kernel_end))
};
allocator.choose_next_area();
allocator
}
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(PhysicalAddress::new(address as usize)) >= self.next_free_frame
}).min_by_key(|area| area.base_addr);
if let Some(area) = self.current_area {
let start_frame = Frame::containing_address(PhysicalAddress::new(area.base_addr as usize));
if self.next_free_frame < start_frame {
self.next_free_frame = start_frame;
}
}
}
}
impl FrameAllocator for AreaFrameAllocator {
fn allocate_frame(&mut self) -> Option<Frame> {
if let Some(area) = self.current_area {
// "Clone" the frame to return it if it's free. Frame doesn't
// implement Clone, but we can construct an identical frame.
let frame = Frame{ number: self.next_free_frame.number };
// the last frame of the current area
let current_area_last_frame = {
let address = area.base_addr + area.length - 1;
Frame::containing_address(PhysicalAddress::new(address as usize))
};
if frame > current_area_last_frame {
// all frames of current area are used, switch to next area
self.choose_next_area();
} else if frame >= self.kernel_start && frame <= self.kernel_end {
// `frame` is used by the kernel
self.next_free_frame = Frame {
number: self.kernel_end.number + 1
};
} else {
// frame is unused, increment `next_free_frame` and return it
self.next_free_frame.number += 1;
return Some(frame);
}
// `frame` was not valid, try it again with the updated `next_free_frame`
self.allocate_frame()
} else {
None // no free frames left
}
}
fn deallocate_frame(&mut self, frame: Frame) {
//panic!("AreaFrameAllocator::deallocate_frame: not supported: {:?}", frame);
}
}

View file

@ -0,0 +1,39 @@
use super::AreaFrameAllocator;
const BITMAP_RESERVED: usize = 0;
const BITMAP_FREE: usize = 1;
const BITMAP_USED: usize = 2;
pub struct BitmapAllocator {
bitmap: &'static mut [u8]
}
impl BitmapAllocator {
pub fn new(area_frame_allocator: AreaFrameAllocator) -> BitmapAllocator {
BitmapAllocator {
bitmap: &mut []
}
}
}
impl FrameAllocator for BitmapAllocator {
fn allocate_frame(&mut self) -> Option<Frame> {
let mut i = 0;
while i < self.bitmap.len() {
if self.bitmap[i] == BITMAP_FREE {
self.bitmap[i] = BITMAP_USED;
return Some(Frame::containing_address(PhysicalAddress::new(i * 4096)));
}
}
None
}
fn deallocate_frame(&mut self, frame: Frame) {
let i = frame.starting_address().get()/4096;
if i < self.bitmap.len() && self.bitmap[i] == BITMAP_USED {
self.bitmap[i] = BITMAP_FREE;
} else {
panic!("BitmapAllocator::deallocate_frame: unowned frame {:?}", frame);
}
}
}

View file

@ -3,11 +3,11 @@
pub use paging::{PAGE_SIZE, PhysicalAddress};
use self::area_frame_alloc::AreaFrameAllocator;
use self::area_frame_allocator::AreaFrameAllocator;
use spin::Mutex;
pub mod area_frame_alloc;
pub mod area_frame_allocator;
/// The current memory map. It's size is maxed out to 512 entries, due to it being
/// from 0x500 to 0x5000 (800 is the absolute total)