diff --git a/alloc/bump_allocator/Cargo.toml b/alloc/bump_allocator/Cargo.toml index 0c55184..08a64cf 100644 --- a/alloc/bump_allocator/Cargo.toml +++ b/alloc/bump_allocator/Cargo.toml @@ -1,3 +1,6 @@ [package] name = "bump_allocator" version = "0.1.0" + +[dependencies] +"spin" = "*" diff --git a/alloc/bump_allocator/src/lib.rs b/alloc/bump_allocator/src/lib.rs index 937a6b4..ad9a408 100644 --- a/alloc/bump_allocator/src/lib.rs +++ b/alloc/bump_allocator/src/lib.rs @@ -1,24 +1,23 @@ //! A simple allocator that never frees, for testing +//! Some code borrowed from [Phil Opp's Blog](http://os.phil-opp.com/kernel-heap.html) #![feature(allocator)] +#![feature(const_fn)] #![allocator] #![no_std] -pub static mut HEAP: usize = 10*1024*1024; +use spin::Mutex; + +extern crate spin; + +pub const HEAP_START: usize = 0o_000_001_000_000_0000; +pub const HEAP_SIZE: usize = 100 * 1024; // 100 KiB + +static BUMP_ALLOCATOR: Mutex = Mutex::new(BumpAllocator::new(HEAP_START, HEAP_SIZE)); #[no_mangle] pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 { - unsafe { - let mut ret = HEAP; - if align.is_power_of_two() { - ret += (align - 1); - ret &= !(align - 1); - } else { - assert_eq!(align, 0); - } - HEAP = ret + size; - ret as *mut u8 - } + BUMP_ALLOCATOR.lock().allocate(size, align).expect("out of memory") } #[no_mangle] @@ -45,3 +44,53 @@ pub extern fn __rust_reallocate(ptr: *mut u8, size: usize, new_size: usize, alig pub extern fn __rust_reallocate_inplace(ptr: *mut u8, size: usize, new_size: usize, align: usize) -> usize { size } + +/// Align downwards. Returns the greatest x with alignment `align` +/// so that x <= addr. The alignment must be a power of 2. +pub fn align_down(addr: usize, align: usize) -> usize { + if align.is_power_of_two() { + addr & !(align - 1) + } else if align == 0 { + addr + } else { + panic!("`align` must be a power of 2"); + } +} + +/// Align upwards. Returns the smallest x with alignment `align` +/// so that x >= addr. The alignment must be a power of 2. +pub fn align_up(addr: usize, align: usize) -> usize { + align_down(addr + align - 1, align) +} + +#[derive(Debug)] +struct BumpAllocator { + heap_start: usize, + heap_size: usize, + next: usize, +} + +impl BumpAllocator { + /// Create a new allocator, which uses the memory in the + /// range [heap_start, heap_start + heap_size). + const fn new(heap_start: usize, heap_size: usize) -> BumpAllocator { + BumpAllocator { + heap_start: heap_start, + heap_size: heap_size, + next: heap_start, + } + } + + /// Allocates a block of memory with the given size and alignment. + fn allocate(&mut self, size: usize, align: usize) -> Option<*mut u8> { + let alloc_start = align_up(self.next, align); + let alloc_end = alloc_start + size; + + if alloc_end <= self.heap_start + self.heap_size { + self.next = alloc_end; + Some(alloc_start as *mut u8) + } else { + None + } + } +} diff --git a/arch/x86_64/Cargo.toml b/arch/x86_64/Cargo.toml index b58aadd..6d6fb27 100644 --- a/arch/x86_64/Cargo.toml +++ b/arch/x86_64/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" [dependencies] bitflags = "*" +bump_allocator = { path = "../../alloc/bump_allocator"} [dependencies.x86] default-features = false diff --git a/arch/x86_64/src/lib.rs b/arch/x86_64/src/lib.rs index f9d88dd..faf6e9d 100644 --- a/arch/x86_64/src/lib.rs +++ b/arch/x86_64/src/lib.rs @@ -11,6 +11,7 @@ #[macro_use] extern crate bitflags; +extern crate bump_allocator; extern crate x86; /// Print to console diff --git a/arch/x86_64/src/main.rs b/arch/x86_64/src/main.rs index dd5370b..60e86ce 100644 --- a/arch/x86_64/src/main.rs +++ b/arch/x86_64/src/main.rs @@ -3,11 +3,12 @@ /// It must create the IDT with the correct entries, those entries are /// defined in other files inside of the `arch` module +use bump_allocator::{HEAP_START, HEAP_SIZE}; use externs::memset; use gdt; use idt; -use memory::{self, Frame}; -use paging::{self, entry, Page, PhysicalAddress}; +use memory; +use paging::{self, Page, VirtualAddress}; /// Test of zero values in BSS. static BSS_TEST_ZERO: usize = 0; @@ -54,6 +55,14 @@ pub unsafe extern fn kstart() -> ! { // Initialize paging let mut active_table = paging::init(&mut allocator); + // Initialize heap + let heap_start_page = Page::containing_address(VirtualAddress::new(HEAP_START)); + let heap_end_page = Page::containing_address(VirtualAddress::new(HEAP_START + HEAP_SIZE-1)); + + for page in Page::range_inclusive(heap_start_page, heap_end_page) { + active_table.map(page, paging::entry::WRITABLE, &mut allocator); + } + asm!("xchg bx, bx" : : : : "intel", "volatile"); kmain(); } diff --git a/arch/x86_64/src/memory/mod.rs b/arch/x86_64/src/memory/mod.rs index d9e9e47..7435413 100644 --- a/arch/x86_64/src/memory/mod.rs +++ b/arch/x86_64/src/memory/mod.rs @@ -84,13 +84,6 @@ pub struct Frame { } impl Frame { - /// Create a frame containing `address` - pub fn containing_address(address: PhysicalAddress) -> Frame { - Frame { - number: address.get() / PAGE_SIZE - } - } - /// Get the address of this frame pub fn start_address(&self) -> PhysicalAddress { PhysicalAddress::new(self.number * PAGE_SIZE) @@ -102,8 +95,42 @@ impl Frame { number: self.number } } + + /// Create a frame containing `address` + pub fn containing_address(address: PhysicalAddress) -> Frame { + Frame { + number: address.get() / PAGE_SIZE + } + } + + //TODO: Set private + pub fn range_inclusive(start: Frame, end: Frame) -> FrameIter { + FrameIter { + start: start, + end: end, + } + } } +pub struct FrameIter { + start: Frame, + end: Frame, +} + +impl Iterator for FrameIter { + type Item = Frame; + + fn next(&mut self) -> Option { + if self.start <= self.end { + let frame = self.start.clone(); + self.start.number += 1; + Some(frame) + } else { + None + } + } + } + pub trait FrameAllocator { fn allocate_frame(&mut self) -> Option; fn deallocate_frame(&mut self, frame: Frame); diff --git a/arch/x86_64/src/paging/mod.rs b/arch/x86_64/src/paging/mod.rs index 409e109..4caa25d 100644 --- a/arch/x86_64/src/paging/mod.rs +++ b/arch/x86_64/src/paging/mod.rs @@ -5,9 +5,8 @@ use core::ops::{Deref, DerefMut}; use memory::{Frame, FrameAllocator}; -use self::entry::{PRESENT, WRITABLE, EntryFlags}; +use self::entry::{PRESENT, WRITABLE}; use self::mapper::Mapper; -use self::table::{Table, Level4}; use self::temporary_page::TemporaryPage; pub mod entry; @@ -44,7 +43,7 @@ pub unsafe fn init(allocator: &mut A) -> ActivePageTable where A: FrameAlloca let mut active_table = ActivePageTable::new(); - let mut temporary_page = TemporaryPage::new(Page { number: 0xcafebabe }, + let mut temporary_page = TemporaryPage::new(Page { number: 0x80000000 }, allocator); let mut new_table = { @@ -54,6 +53,11 @@ pub unsafe fn init(allocator: &mut A) -> ActivePageTable where A: FrameAlloca active_table.with(&mut new_table, &mut temporary_page, |mapper| { let mut remap = |start: usize, end: usize, flags: entry::EntryFlags| { + /* TODO + let start_frame = Frame::containing_address(PhysicalAddress::new(start)); + let end_frame = Frame::containing_address(PhysicalAddress::new(end)); + for frame in Frame::range_inclusive(start_frame, end_frame) {} + */ for i in 0..(end - start + PAGE_SIZE - 1)/PAGE_SIZE { let frame = Frame::containing_address(PhysicalAddress::new(start + i * PAGE_SIZE)); mapper.identity_map(frame, flags, allocator); @@ -197,7 +201,7 @@ impl VirtualAddress { } /// Page -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Page { number: usize } @@ -228,4 +232,30 @@ impl Page { "invalid address: 0x{:x}", address.get()); Page { number: address.get() / PAGE_SIZE } } + + pub fn range_inclusive(start: Page, end: Page) -> PageIter { + PageIter { + start: start, + end: end, + } + } +} + +pub struct PageIter { + start: Page, + end: Page, +} + +impl Iterator for PageIter { + type Item = Page; + + fn next(&mut self) -> Option { + if self.start <= self.end { + let page = self.start; + self.start.number += 1; + Some(page) + } else { + None + } + } } diff --git a/arch/x86_64/src/panic.rs b/arch/x86_64/src/panic.rs index 9630428..df0101f 100644 --- a/arch/x86_64/src/panic.rs +++ b/arch/x86_64/src/panic.rs @@ -18,7 +18,7 @@ extern "C" fn panic_fmt(fmt: ::core::fmt::Arguments, file: &str, line: u32) -> ! println!("LINE: {}", line); println!("TRACE: {:>016X}", rbp); - for i in 0..10 { + for _frame in 0..16 { //Maximum 16 frames unsafe { let rip = *(rbp as *const usize).offset(1); println!(" {:>016X}: {:>016X}", rbp, rip); diff --git a/kernel/lib.rs b/kernel/lib.rs index e1db70c..257c9dd 100644 --- a/kernel/lib.rs +++ b/kernel/lib.rs @@ -85,10 +85,6 @@ extern crate arch_test as arch; #[macro_use] extern crate arch_x86_64 as arch; -/// Bump allocator -#[cfg(all(not(test), target_arch = "x86_64"))] -extern crate bump_allocator; - extern crate alloc; #[macro_use] extern crate collections;