Add a dynamic growing frame stack

This commit is contained in:
Philipp Oppermann
2015-10-08 01:54:46 +02:00
parent 10ddcead2d
commit abd6e48c08
4 changed files with 120 additions and 15 deletions

View File

@@ -14,6 +14,7 @@
#![feature(no_std, lang_items, asm)]
#![feature(core_str_ext, const_fn, range_inclusive)]
#![feature(unique, core_intrinsics)]
#![no_std]
extern crate rlibc;

73
src/memory/core_map.rs Normal file
View File

@@ -0,0 +1,73 @@
use core::ptr::Unique;
use core::mem;
use super::{Page, FrameStack};
pub type Frame = super::Frame;
pub struct DynamicFrameStack {
head: Unique<Frame>, // TODO invariant
length: usize,
capacity: usize,
}
impl DynamicFrameStack {
pub fn new(at: *mut Frame) -> DynamicFrameStack {
DynamicFrameStack {
head: unsafe{ Unique::new(at) },
length: 0,
capacity: 0,
}
}
fn capacity_per_frame() -> usize {
(super::PAGE_SIZE as usize) / mem::size_of::<Frame>()
}
}
impl FrameStack for DynamicFrameStack {
fn push<F>(&mut self, frame: Frame, map_to: F)
where F: FnOnce(Page, Frame),
{
use core::intrinsics::offset;
if self.length < self.capacity {
// add frame to frame stack
unsafe {
let new_frame = offset(*self.head, self.length as isize) as *mut _;
mem::forget(mem::replace(&mut *new_frame, frame));
}
self.length += 1;
} else {
// frame stack is full, use passed frame to expand it
let page_address = unsafe{ offset(*self.head, self.capacity as isize) } as usize;
map_to(Page::containing_address(page_address), frame);
self.capacity += Self::capacity_per_frame();
}
}
fn pop<F>(&mut self, unmap_page: F) -> Option<Frame>
where F: FnOnce(Page) -> Frame,
{
use core::intrinsics::offset;
if self.length == 0 {
// no frames left but maybe we can decrease the capacity and use that frame
if self.capacity == 0 {
None
} else {
// decrease capacity and thus free a frame used as backing store
self.capacity -= Self::capacity_per_frame();
let page_address = unsafe{ offset(*self.head, self.capacity as isize) } as usize;
Some(unmap_page(Page::containing_address(page_address)))
}
} else {
// pop the last frame from the stack
self.length -= 1;
unsafe {
let frame = offset(*self.head, self.length as isize) as *mut _;
Some(mem::replace(&mut *frame, mem::zeroed()))
}
}
}
}

View File

@@ -3,6 +3,9 @@ use core::iter::range_inclusive;
use core::cmp::max;
mod paging;
mod core_map;
pub const PAGE_SIZE: u64 = 4096;
pub fn init(multiboot: &Multiboot) {
// ATTENTION: we have a very small stack and no guard page

View File

@@ -1,11 +1,9 @@
use super::{VirtualAddress, Frame};
use super::{VirtualAddress, Frame, PAGE_SIZE, FrameStack};
use core::ops::Deref;
pub type FrameAllocator = super::FrameAllocator;
//pub type FrameAllocator = super::FrameStack;
pub type Page = super::Page;
pub const PAGE_SIZE: u64 = 4096;
bitflags! {
flags PageTableFieldFlags: u64 {
const PRESENT = 1 << 0,
@@ -21,18 +19,18 @@ bitflags! {
}
}
pub struct Controller {
allocator: FrameAllocator,
pub struct Controller<'a, A> where A: 'a {
allocator: &'a mut A,
}
impl Controller {
pub unsafe fn new(allocator: FrameAllocator) -> Controller {
impl<'a, A> Controller<'a, A> where A: FrameStack {
pub unsafe fn new(allocator: &mut A) -> Controller<A> {
Controller {
allocator: allocator,
}
}
pub fn identity_map(&mut self, page: Page, writable: bool, executable: bool) {
pub fn map_to(&mut self, page: Page, frame:Frame, writable: bool, executable: bool) {
let mut flags = PRESENT;
if writable {
flags = flags | WRITABLE;
@@ -41,11 +39,19 @@ impl Controller {
flags = flags | NO_EXECUTE;
}
page.map_to(Frame{number: page.number}, flags, &mut self.allocator)
page.map_to(frame, flags, || {self.allocate_frame()})
}
pub fn identity_map(&mut self, page: Page, writable: bool, executable: bool) {
self.map_to(page, Frame{number: page.number}, writable, executable)
}
pub fn unmap(&mut self, page: Page) -> Frame {
page.unmap()
}
pub fn begin_new_table(&mut self) {
let new_p4_frame = self.allocator.allocate_frame().unwrap();
let new_p4_frame = self.allocate_frame();
let new_p4_page = &mut PageTablePage(Page{number: new_p4_frame.number});
unsafe{new_p4_page.zero()};
new_p4_page.field(511).set(new_p4_frame, PRESENT | WRITABLE);
@@ -67,6 +73,13 @@ impl Controller {
}
}
fn allocate_frame(&mut self) -> Frame {
let unmap_page = |page: Page| {
page.unmap()
};
self.allocator.pop(unmap_page).expect("no more frames available")
}
fn flush_tlb() {
unsafe{asm!("mov rax, cr3
mov cr3, rax" ::: "{rax}" : "intel")}
@@ -128,20 +141,22 @@ impl Page {
})
}
pub fn map_to(&self, frame: Frame, flags: PageTableFieldFlags, allocator: &mut FrameAllocator) {
fn map_to<F>(&self, frame: Frame, flags: PageTableFieldFlags, mut allocate_frame: F)
where F: FnMut() -> Frame,
{
let p4_field = self.p4_page().field(self.p4_index());
if p4_field.is_free() {
p4_field.set(allocator.allocate_frame().expect("no frame allocated"), PRESENT | WRITABLE);
p4_field.set(allocate_frame(), PRESENT | WRITABLE);
unsafe{self.p3_page().zero()};
}
let p3_field = self.p3_page().field(self.p3_index());
if p3_field.is_free() {
p3_field.set(allocator.allocate_frame().expect("no frame allocated"), PRESENT | WRITABLE);
p3_field.set(allocate_frame(), PRESENT | WRITABLE);
unsafe{self.p2_page().zero()};
}
let p2_field = self.p2_page().field(self.p2_index());
if p2_field.is_free() {
p2_field.set(allocator.allocate_frame().expect("no frame allocated"), PRESENT | WRITABLE);
p2_field.set(allocate_frame(), PRESENT | WRITABLE);
unsafe{self.p1_page().zero()};
}
let p1_field = self.p1_page().field(self.p1_index());
@@ -149,6 +164,14 @@ impl Page {
p1_field.set(frame, flags);
}
fn unmap(self) -> Frame {
let p1_field = self.p1_page().field(self.p1_index());
let frame = p1_field.pointed_frame();
p1_field.set_free();
// TODO free p(1,2,3) table if empty
frame
}
unsafe fn zero(&self) {
let page = self.start_address().0 as *mut [u64; (PAGE_SIZE/64) as usize];
*page = [0; (PAGE_SIZE/64) as usize];
@@ -210,6 +233,11 @@ impl PageTableField {
free
}
fn set_free(&self) {
//TODO
unsafe{ *(self.0 as *mut _)= 0 };
}
fn pointed_frame(&self) -> Frame {
Frame {
number: ((unsafe{(*self.0)} & 0x000fffff_fffff000) >> 12) as usize,