diff --git a/libs/bump_allocator/src/lib.rs b/libs/bump_allocator/src/lib.rs index 506d9975..51e5bdde 100644 --- a/libs/bump_allocator/src/lib.rs +++ b/libs/bump_allocator/src/lib.rs @@ -8,52 +8,117 @@ // except according to those terms. #![feature(const_fn)] -#![feature(allocator)] +#![feature(allocator_api)] +#![feature(alloc)] +#![feature(global_allocator)] -#![allocator] #![no_std] +use alloc::heap::{Alloc, AllocErr, Layout}; use spin::Mutex; +extern crate alloc; 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)); - -#[derive(Debug)] -struct BumpAllocator { - heap_start: usize, - heap_size: usize, - next: usize, +struct LockedHeap { + heap: Mutex, } -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, + +#[global_allocator] +static GLOBAL_ALLOC: LockedHeap = LockedHeap::empty(); + + +pub unsafe fn init(start: usize, size: usize) { + GLOBAL_ALLOC.init(start, size); +} + +/// The heap is protected by the LockedHeap structure. +impl LockedHeap { + /// Creates a protected empty heap. All allocate calls will return + /// 'AllocErr`. + pub const fn empty() -> LockedHeap { + LockedHeap { + heap : Mutex::new(Heap::empty()) + } + } + /// Initializes the heap. + unsafe fn init(&self, start: usize, size: usize) { + self.heap.lock().init(start, size); + } +} + +/// The interface used for all allocation of heap structures. +unsafe impl<'a> Alloc for &'a LockedHeap { + + unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + self.heap.lock().allocate(layout) + } + + unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + self.heap.lock().dealloc(ptr, layout) + } +} + + + +/// A fixed size heap with a reference to the beginning of free space. +pub struct Heap { + start: usize, + end: usize, + next: usize, +} + +impl Heap { + /// Creates an empty heap. + /// + /// All allocate calls will return `AllocErr`. + pub const fn empty() -> Heap { + Heap { + start: 0, + end: 0, + next: 0, } } - /// 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.saturating_add(size); + /// Initalizes the heap given start and size. + /// + /// # Safety + /// + /// This is unsafe, the start address must be valid and the memory + /// in the `[start, start + size)` range must not be used for + /// anything else. The function is unsafe because it can cause + /// undefined behavior if the given address or size are invalid. + unsafe fn init(&mut self, start: usize, size: usize) { + self.start = start; + self.end = start + size; + self.next = start; + } - if alloc_end <= self.heap_start + self.heap_size { - self.next = alloc_end; - Some(alloc_start as *mut u8) + /// Allocates a chunk of the given size with the given alignment. + /// + /// Returns a pointer to the beginning of that chunk if it was + /// successful, else it returns an AllocErr. + unsafe fn allocate(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + let alloc_start = align_up(self.next, layout.align()); + let alloc_end = alloc_start.saturating_add(layout.size()); + + if alloc_end <= self.end { + self.next = alloc_end; + Ok(alloc_start as *mut u8) } else { - None - } + Err(AllocErr::Exhausted{request: layout}) + } } -} + + /// Deallocates the block refered to by the given pointer and + /// described by the layout. + unsafe fn dealloc(&mut self, _ptr: *mut u8, _layout: Layout) { + // Sofar nothing - don't worry, RAM is cheap + } +} + /// Align downwards. Returns the greatest x with alignment `align` /// so that x <= addr. The alignment must be a power of 2. @@ -73,42 +138,4 @@ pub fn align_up(addr: usize, align: usize) -> usize { align_down(addr + align - 1, align) } -#[no_mangle] -pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 { - BUMP_ALLOCATOR.lock().allocate(size, align).expect("out of memory") -} - -#[no_mangle] -pub extern fn __rust_deallocate(_ptr: *mut u8, _size: usize, - _align: usize) -{ - // just leak it -} - -#[no_mangle] -pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize { - size -} - -#[no_mangle] -pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, size: usize, - _new_size: usize, _align: usize) -> usize -{ - size -} - -#[no_mangle] -pub extern fn __rust_reallocate(ptr: *mut u8, size: usize, new_size: usize, - align: usize) -> *mut u8 { - use core::{ptr, cmp}; - - // from: https://github.com/rust-lang/rust/blob/ - // c66d2380a810c9a2b3dbb4f93a830b101ee49cc2/ - // src/liballoc_system/lib.rs#L98-L101 - - let new_ptr = __rust_allocate(new_size, align); - unsafe { ptr::copy(ptr, new_ptr, cmp::min(size, new_size)) }; - __rust_deallocate(ptr, size, align); - new_ptr -} diff --git a/libs/hole_list_allocator/src/lib.rs b/libs/hole_list_allocator/src/lib.rs index 39210b35..1e6e9f96 100644 --- a/libs/hole_list_allocator/src/lib.rs +++ b/libs/hole_list_allocator/src/lib.rs @@ -22,8 +22,6 @@ use alloc::heap::{Alloc, AllocErr, Layout}; use spin::Mutex; use linked_list_allocator::Heap; -pub const HEAP_START: usize = 0o_000_001_000_000_0000; -pub const HEAP_SIZE: usize = 100 * 1024; // 100 KiB static HEAP: Mutex> = Mutex::new(None); diff --git a/src/lib.rs b/src/lib.rs index 166490f4..ab3a1447 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,6 +39,11 @@ mod memory; mod interrupts; + +pub const HEAP_START: usize = 0o_000_001_000_000_0000; +pub const HEAP_SIZE: usize = 100 * 1024; // 100 KiB + + #[no_mangle] pub extern "C" fn rust_main(multiboot_information_address: usize) { // ATTENTION: we have a very small stack and no guard page diff --git a/src/memory/mod.rs b/src/memory/mod.rs index 71eda4e0..0ee7ad02 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -63,7 +63,7 @@ pub fn init(boot_info: &BootInformation) -> MemoryController { let mut active_table = paging::remap_the_kernel(&mut frame_allocator, boot_info); use self::paging::Page; - use allocator::{HEAP_START, HEAP_SIZE}; + use super::{HEAP_START, HEAP_SIZE}; let heap_start_page = Page::containing_address(HEAP_START); let heap_end_page = Page::containing_address(HEAP_START + HEAP_SIZE - 1);