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,