From e89e4f5277e47741d9dd683d0823b2a7eeed76b1 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Sun, 19 Nov 2017 15:17:14 +0100 Subject: [PATCH] Rewrite bump allocator and integrate it in main crate --- Cargo.toml | 4 +- libs/bump_allocator/Cargo.toml | 7 -- libs/bump_allocator/src/lib.rs | 141 ---------------------------- libs/hole_list_allocator/.gitignore | 2 - libs/hole_list_allocator/Cargo.toml | 12 --- libs/hole_list_allocator/src/lib.rs | 55 ----------- src/lib.rs | 40 ++++---- src/memory/heap_allocator.rs | 62 ++++++++++++ src/memory/mod.rs | 7 +- 9 files changed, 86 insertions(+), 244 deletions(-) delete mode 100644 libs/bump_allocator/Cargo.toml delete mode 100644 libs/bump_allocator/src/lib.rs delete mode 100644 libs/hole_list_allocator/.gitignore delete mode 100644 libs/hole_list_allocator/Cargo.toml delete mode 100644 libs/hole_list_allocator/src/lib.rs create mode 100644 src/memory/heap_allocator.rs diff --git a/Cargo.toml b/Cargo.toml index 2ad01f9f..74109d7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,9 +12,7 @@ rlibc = "1.0" spin = "0.4.5" volatile = "0.1.0" x86_64 = "0.1.2" - -[dependencies.hole_list_allocator] -path = "libs/hole_list_allocator" +linked_list_allocator = "0.4.2" [dependencies.lazy_static] features = ["spin_no_std"] diff --git a/libs/bump_allocator/Cargo.toml b/libs/bump_allocator/Cargo.toml deleted file mode 100644 index a7b910cb..00000000 --- a/libs/bump_allocator/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -authors = ["Philipp Oppermann "] -name = "bump_allocator" -version = "0.1.0" - -[dependencies] -spin = "0.4.5" diff --git a/libs/bump_allocator/src/lib.rs b/libs/bump_allocator/src/lib.rs deleted file mode 100644 index 51e5bdde..00000000 --- a/libs/bump_allocator/src/lib.rs +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2016 Philipp Oppermann. See the README.md -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(const_fn)] -#![feature(allocator_api)] -#![feature(alloc)] -#![feature(global_allocator)] - -#![no_std] - -use alloc::heap::{Alloc, AllocErr, Layout}; -use spin::Mutex; - -extern crate alloc; -extern crate spin; - - -struct LockedHeap { - heap: Mutex, -} - - -#[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, - } - } - - /// 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; - } - - /// 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 { - 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. -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) -} - - diff --git a/libs/hole_list_allocator/.gitignore b/libs/hole_list_allocator/.gitignore deleted file mode 100644 index 49d4fed9..00000000 --- a/libs/hole_list_allocator/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Generated by Cargo -/target/ diff --git a/libs/hole_list_allocator/Cargo.toml b/libs/hole_list_allocator/Cargo.toml deleted file mode 100644 index a3c185f7..00000000 --- a/libs/hole_list_allocator/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -authors = ["Philipp Oppermann "] -name = "hole_list_allocator" -version = "0.1.0" - -[dependencies] -linked_list_allocator = { git = "https://github.com/phil-opp/linked-list-allocator.git"} -spin = "0.4.5" - -[dependencies.lazy_static] -version = "0.2.1" -features = ["spin_no_std"] diff --git a/libs/hole_list_allocator/src/lib.rs b/libs/hole_list_allocator/src/lib.rs deleted file mode 100644 index 1e6e9f96..00000000 --- a/libs/hole_list_allocator/src/lib.rs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2016 Philipp Oppermann. See the README.md -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(const_fn)] -#![feature(allocator_api)] -#![feature(alloc)] -#![feature(global_allocator)] -#![no_std] -#![deny(warnings)] - -extern crate alloc; -extern crate spin; -extern crate linked_list_allocator; - -use alloc::heap::{Alloc, AllocErr, Layout}; -use spin::Mutex; -use linked_list_allocator::Heap; - - -static HEAP: Mutex> = Mutex::new(None); - -//Set up the heap -pub unsafe fn init(offset: usize, size: usize) { - *HEAP.lock() = Some(Heap::new(offset, size)); -} - -pub struct Allocator; - -unsafe impl<'a> Alloc for &'a Allocator { - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - if let Some(ref mut heap) = *HEAP.lock() { - heap.allocate_first_fit(layout) - } else { - panic!("Heap not initialized!"); - } - } - - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - if let Some(ref mut heap) = *HEAP.lock() { - heap.deallocate(ptr, layout) - } else { - panic!("heap not initalized"); - } - } -} - -//Our allocator static -#[global_allocator] -static GLOBAL_ALLOC: Allocator = Allocator; diff --git a/src/lib.rs b/src/lib.rs index c96f75a0..418f80c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,9 +13,13 @@ #![feature(asm)] #![feature(naked_functions)] #![feature(abi_x86_interrupt)] -#![feature(const_unique_new)] +#![feature(const_unique_new, const_atomic_usize_new)] +#![feature(allocator_api)] +#![feature(global_allocator)] #![no_std] +#[macro_use] +extern crate alloc; extern crate rlibc; extern crate volatile; extern crate spin; @@ -25,25 +29,15 @@ extern crate bitflags; extern crate x86_64; #[macro_use] extern crate once; -extern crate bit_field; +extern crate linked_list_allocator; #[macro_use] extern crate lazy_static; - -extern crate hole_list_allocator as allocator; -#[macro_use] -extern crate alloc; - +extern crate bit_field; #[macro_use] mod vga_buffer; 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 @@ -57,9 +51,13 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) { // set up guard page and map the heap pages let mut memory_controller = memory::init(boot_info); + unsafe { + HEAP_ALLOCATOR.lock().init(HEAP_START, HEAP_START + HEAP_SIZE); + } + // initialize our IDT interrupts::init(&mut memory_controller); - + fn stack_overflow() { stack_overflow(); // for each recursion, the return address is pushed } @@ -67,6 +65,7 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) { // trigger a stack overflow stack_overflow(); + println!("It did not crash!"); loop {} } @@ -101,8 +100,13 @@ pub extern "C" fn panic_fmt(fmt: core::fmt::Arguments, file: &'static str, line: loop {} } -#[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn _Unwind_Resume() -> ! { - loop {} -} +pub extern "C" fn _Unwind_Resume() -> ! { loop {} } + +use linked_list_allocator::LockedHeap; + +pub const HEAP_START: usize = 0o_000_001_000_000_0000; +pub const HEAP_SIZE: usize = 100 * 1024; // 100 KiB + +#[global_allocator] +static HEAP_ALLOCATOR: LockedHeap = LockedHeap::empty(); diff --git a/src/memory/heap_allocator.rs b/src/memory/heap_allocator.rs new file mode 100644 index 00000000..0a232f92 --- /dev/null +++ b/src/memory/heap_allocator.rs @@ -0,0 +1,62 @@ +use alloc::heap::{Alloc, AllocErr, Layout}; + +use core::sync::atomic::{AtomicUsize, Ordering}; + +/// A simple allocator that allocates memory linearly and ignores freed memory. +#[derive(Debug)] +pub struct BumpAllocator { + heap_start: usize, + heap_end: usize, + next: AtomicUsize, +} + +impl BumpAllocator { + pub const fn new(heap_start: usize, heap_end: usize) -> Self { + Self { heap_start, heap_end, next: AtomicUsize::new(heap_start) } + } +} + +unsafe impl<'a> Alloc for &'a BumpAllocator { + unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + loop { + // load current state of the `next` field + let current_next = self.next.load(Ordering::Relaxed); + let alloc_start = align_up(current_next, layout.align()); + let alloc_end = alloc_start.saturating_add(layout.size()); + + if alloc_end <= self.heap_end { + // update the `next` pointer if it still has the value `current_next` + let next_now = self.next.compare_and_swap(current_next, alloc_end, + Ordering::Relaxed); + if next_now == current_next { + // next address was successfully updated, allocation succeeded + return Ok(alloc_start as *mut u8); + } + } else { + return Err(AllocErr::Exhausted{ request: layout }) + } + } + } + + unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + // do nothing, leak memory + } +} + +/// 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) +} diff --git a/src/memory/mod.rs b/src/memory/mod.rs index 0ee7ad02..fc1a7dce 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -12,9 +12,9 @@ pub use self::paging::remap_the_kernel; pub use self::stack_allocator::Stack; use self::paging::PhysicalAddress; use multiboot2::BootInformation; -use allocator; mod area_frame_allocator; +pub mod heap_allocator; mod paging; mod stack_allocator; @@ -72,11 +72,6 @@ pub fn init(boot_info: &BootInformation) -> MemoryController { active_table.map(page, paging::WRITABLE, &mut frame_allocator); } - //Init the heap - unsafe { - allocator::init(HEAP_START, HEAP_SIZE); - } - let stack_allocator = { let stack_alloc_start = heap_end_page + 1; let stack_alloc_end = stack_alloc_start + 100;