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(no_std, lang_items, asm)]
|
||||||
#![feature(core_str_ext, const_fn, range_inclusive)]
|
#![feature(core_str_ext, const_fn, range_inclusive)]
|
||||||
|
#![feature(unique, core_intrinsics)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
extern crate rlibc;
|
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;
|
use core::cmp::max;
|
||||||
|
|
||||||
mod paging;
|
mod paging;
|
||||||
|
mod core_map;
|
||||||
|
|
||||||
|
pub const PAGE_SIZE: u64 = 4096;
|
||||||
|
|
||||||
pub fn init(multiboot: &Multiboot) {
|
pub fn init(multiboot: &Multiboot) {
|
||||||
// ATTENTION: we have a very small stack and no guard page
|
// 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;
|
use core::ops::Deref;
|
||||||
|
|
||||||
pub type FrameAllocator = super::FrameAllocator;
|
//pub type FrameAllocator = super::FrameStack;
|
||||||
pub type Page = super::Page;
|
pub type Page = super::Page;
|
||||||
|
|
||||||
pub const PAGE_SIZE: u64 = 4096;
|
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
flags PageTableFieldFlags: u64 {
|
flags PageTableFieldFlags: u64 {
|
||||||
const PRESENT = 1 << 0,
|
const PRESENT = 1 << 0,
|
||||||
@@ -21,18 +19,18 @@ bitflags! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Controller {
|
pub struct Controller<'a, A> where A: 'a {
|
||||||
allocator: FrameAllocator,
|
allocator: &'a mut A,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Controller {
|
impl<'a, A> Controller<'a, A> where A: FrameStack {
|
||||||
pub unsafe fn new(allocator: FrameAllocator) -> Controller {
|
pub unsafe fn new(allocator: &mut A) -> Controller<A> {
|
||||||
Controller {
|
Controller {
|
||||||
allocator: allocator,
|
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;
|
let mut flags = PRESENT;
|
||||||
if writable {
|
if writable {
|
||||||
flags = flags | WRITABLE;
|
flags = flags | WRITABLE;
|
||||||
@@ -41,11 +39,19 @@ impl Controller {
|
|||||||
flags = flags | NO_EXECUTE;
|
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) {
|
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});
|
let new_p4_page = &mut PageTablePage(Page{number: new_p4_frame.number});
|
||||||
unsafe{new_p4_page.zero()};
|
unsafe{new_p4_page.zero()};
|
||||||
new_p4_page.field(511).set(new_p4_frame, PRESENT | WRITABLE);
|
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() {
|
fn flush_tlb() {
|
||||||
unsafe{asm!("mov rax, cr3
|
unsafe{asm!("mov rax, cr3
|
||||||
mov cr3, rax" ::: "{rax}" : "intel")}
|
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());
|
let p4_field = self.p4_page().field(self.p4_index());
|
||||||
if p4_field.is_free() {
|
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()};
|
unsafe{self.p3_page().zero()};
|
||||||
}
|
}
|
||||||
let p3_field = self.p3_page().field(self.p3_index());
|
let p3_field = self.p3_page().field(self.p3_index());
|
||||||
if p3_field.is_free() {
|
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()};
|
unsafe{self.p2_page().zero()};
|
||||||
}
|
}
|
||||||
let p2_field = self.p2_page().field(self.p2_index());
|
let p2_field = self.p2_page().field(self.p2_index());
|
||||||
if p2_field.is_free() {
|
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()};
|
unsafe{self.p1_page().zero()};
|
||||||
}
|
}
|
||||||
let p1_field = self.p1_page().field(self.p1_index());
|
let p1_field = self.p1_page().field(self.p1_index());
|
||||||
@@ -149,6 +164,14 @@ impl Page {
|
|||||||
p1_field.set(frame, flags);
|
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) {
|
unsafe fn zero(&self) {
|
||||||
let page = self.start_address().0 as *mut [u64; (PAGE_SIZE/64) as usize];
|
let page = self.start_address().0 as *mut [u64; (PAGE_SIZE/64) as usize];
|
||||||
*page = [0; (PAGE_SIZE/64) as usize];
|
*page = [0; (PAGE_SIZE/64) as usize];
|
||||||
@@ -210,6 +233,11 @@ impl PageTableField {
|
|||||||
free
|
free
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_free(&self) {
|
||||||
|
//TODO
|
||||||
|
unsafe{ *(self.0 as *mut _)= 0 };
|
||||||
|
}
|
||||||
|
|
||||||
fn pointed_frame(&self) -> Frame {
|
fn pointed_frame(&self) -> Frame {
|
||||||
Frame {
|
Frame {
|
||||||
number: ((unsafe{(*self.0)} & 0x000fffff_fffff000) >> 12) as usize,
|
number: ((unsafe{(*self.0)} & 0x000fffff_fffff000) >> 12) as usize,
|
||||||
|
|||||||
Reference in New Issue
Block a user