mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-16 14:27:49 +00:00
Add a dynamic growing frame stack
This commit is contained in:
@@ -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
73
src/memory/core_map.rs
Normal 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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user