From c6ae501bc6e7b15c69f11f175e61a482391723a5 Mon Sep 17 00:00:00 2001 From: Erin Date: Tue, 31 Oct 2017 22:10:54 -0500 Subject: [PATCH] x86_64::memory: implement an allocator for stacks --- src/arch/x86_64/memory/mod.rs | 2 + src/arch/x86_64/memory/stack_allocator.rs | 79 +++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 src/arch/x86_64/memory/stack_allocator.rs diff --git a/src/arch/x86_64/memory/mod.rs b/src/arch/x86_64/memory/mod.rs index 25e6a96..d761900 100644 --- a/src/arch/x86_64/memory/mod.rs +++ b/src/arch/x86_64/memory/mod.rs @@ -3,6 +3,7 @@ //! Heavly inspired/lovingly ripped off from Phil Oppermann's [os.phil-opp.com](http://os.phil-opp.com/). mod area_frame_allocator; +mod stack_allocator; mod paging; use multiboot2::BootInformation; @@ -11,6 +12,7 @@ use ::alloca; pub use self::area_frame_allocator::AreaFrameAllocator; use self::paging::Page; +pub use self::stack_allocator::{Stack, StackAllocator}; /// The physical size of each frame. pub const PAGE_SIZE: usize = 4096; diff --git a/src/arch/x86_64/memory/stack_allocator.rs b/src/arch/x86_64/memory/stack_allocator.rs new file mode 100644 index 0000000..0ccdcb1 --- /dev/null +++ b/src/arch/x86_64/memory/stack_allocator.rs @@ -0,0 +1,79 @@ +use memory::paging::{self, Page, PageIter, ActivePageTable}; +use memory::{PAGE_SIZE, FrameAllocator}; + +#[derive(Debug)] +pub struct Stack { + top: usize, + bottom: usize, +} + +impl Stack { + fn new(top: usize, bottom: usize) -> Stack { + assert!(top > bottom, + "Stack top must be higher in memory than the bottom"); + + Stack { + top: top, + bottom: bottom, + } + } + + pub fn top(&self) -> usize { self.top } + pub fn bottom(&self) -> usize { self.bottom } +} + + +pub struct StackAllocator { + range: PageIter, +} + +impl StackAllocator { + pub fn new(page_range: PageIter) -> StackAllocator { + StackAllocator { range: page_range } + } + + /// Allocate a stack. + /// + /// Note: `size` is given in pages. + pub fn alloc_stack(&mut self, + active_table: &mut ActivePageTable, + frame_alloc: &mut A, + size: usize) -> Option + where A: FrameAllocator + { + // zero-size stacks are nonsensical + if size == 0 { + return None; + } + + let mut range = self.range.clone(); + + // try to alloc stack, guard pages + let guard_page = range.next(); + let stack_start = range.next(); + let stack_end = if size == 1 { + stack_start + } else { + range.nth(size - 2) + }; + + match (guard_page, stack_start, stack_end) { + (Some(_), Some(start), Some(end)) => { + // writeback + self.range = range; + + // map stack pages -> physical frames + for page in Page::range_inclusive(start, end) { + active_table.map(page, paging::WRITABLE, frame_alloc); + } + + // create a new stack + + let top = end.start_address() + PAGE_SIZE; + + Some(Stack::new(top, start.start_address())) + } + _ => None, // whoops not enough frames + } + } +}