diff --git a/src/lib.rs b/src/lib.rs
index 93f26c69..d4375b90 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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;
diff --git a/src/memory/core_map.rs b/src/memory/core_map.rs
new file mode 100644
index 00000000..673ba1e9
--- /dev/null
+++ b/src/memory/core_map.rs
@@ -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, // 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::()
+ }
+}
+
+impl FrameStack for DynamicFrameStack {
+ fn push(&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(&mut self, unmap_page: F) -> Option
+ 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()))
+ }
+ }
+ }
+}
diff --git a/src/memory/mod.rs b/src/memory/mod.rs
index 0684880a..41fd32ac 100644
--- a/src/memory/mod.rs
+++ b/src/memory/mod.rs
@@ -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
diff --git a/src/memory/paging.rs b/src/memory/paging.rs
index 21a51f4d..bd36a891 100644
--- a/src/memory/paging.rs
+++ b/src/memory/paging.rs
@@ -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 {
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(&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,