From 94d5a710074bc11367e3307da30f94cc9a58b167 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Mon, 16 Aug 2021 21:14:28 +0100 Subject: [PATCH] Split out bump_allocator --- agb/src/agb_alloc/bump_allocator.rs | 86 ++++++++++++++++++++++++++++ agb/src/agb_alloc/mod.rs | 87 +---------------------------- 2 files changed, 88 insertions(+), 85 deletions(-) create mode 100644 agb/src/agb_alloc/bump_allocator.rs diff --git a/agb/src/agb_alloc/bump_allocator.rs b/agb/src/agb_alloc/bump_allocator.rs new file mode 100644 index 00000000..631fa217 --- /dev/null +++ b/agb/src/agb_alloc/bump_allocator.rs @@ -0,0 +1,86 @@ +use core::alloc::{GlobalAlloc, Layout}; + +use crate::interrupt::Mutex; + +fn get_data_end() -> usize { + extern "C" { + static __ewram_data_end: usize; + } + + // TODO: This seems completely wrong, but without the &, rust generates + // a double dereference :/. Maybe a bug in nightly? + (unsafe { &__ewram_data_end }) as *const _ as usize +} + +pub(super) struct BumpAllocator { + current_ptr: Mutex<*mut u8>, +} + +impl BumpAllocator { + pub const fn new() -> Self { + Self { + current_ptr: Mutex::new(core::ptr::null_mut()), + } + } +} + +impl BumpAllocator { + fn alloc_safe(&self, layout: Layout) -> *mut u8 { + let mut current_ptr = self.current_ptr.lock(); + + let ptr = if current_ptr.is_null() { + get_data_end() + } else { + *current_ptr as usize + }; + + let alignment_bitmask = layout.align() - 1; + let fixup = ptr & alignment_bitmask; + + let amount_to_add = layout.align() - fixup; + + let resulting_ptr = ptr + amount_to_add; + *current_ptr = (resulting_ptr + layout.size()) as *mut _; + + resulting_ptr as *mut _ + } +} + +unsafe impl GlobalAlloc for BumpAllocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + self.alloc_safe(layout) + } + + unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} +} + +#[alloc_error_handler] +fn alloc_error(layout: Layout) -> ! { + panic!( + "Failed to allocate size {} with alignment {}", + layout.size(), + layout.align() + ); +} + +#[cfg(test)] +mod test { + use alloc::boxed::Box; + + #[test_case] + fn test_box(_gba: &mut crate::Gba) { + let first_box = Box::new(1); + let second_box = Box::new(2); + + assert!(&*first_box as *const _ < &*second_box as *const _); + assert_eq!(*first_box, 1); + assert_eq!(*second_box, 2); + + let address = &*first_box as *const _ as usize; + assert!( + address >= 0x0200_0000 && address < 0x0204_0000, + "ewram is located between 0x0200_0000 and 0x0204_0000, address was actually found to be {:#010X}", + address + ); + } +} diff --git a/agb/src/agb_alloc/mod.rs b/agb/src/agb_alloc/mod.rs index 88d75c2d..6d26da3f 100644 --- a/agb/src/agb_alloc/mod.rs +++ b/agb/src/agb_alloc/mod.rs @@ -1,89 +1,6 @@ -use core::alloc::{GlobalAlloc, Layout}; +mod bump_allocator; -use super::interrupt::Mutex; - -fn get_data_end() -> usize { - extern "C" { - static __ewram_data_end: usize; - } - - // TODO: This seems completely wrong, but without the &, rust generates - // a double dereference :/. Maybe a bug in nightly? - (unsafe { &__ewram_data_end }) as *const _ as usize -} - -struct BumpAllocator { - current_ptr: Mutex<*mut u8>, -} - -impl BumpAllocator { - pub const fn new() -> Self { - Self { - current_ptr: Mutex::new(core::ptr::null_mut()), - } - } -} - -impl BumpAllocator { - fn alloc_safe(&self, layout: Layout) -> *mut u8 { - let mut current_ptr = self.current_ptr.lock(); - - let ptr = if current_ptr.is_null() { - get_data_end() - } else { - *current_ptr as usize - }; - - let alignment_bitmask = layout.align() - 1; - let fixup = ptr & alignment_bitmask; - - let amount_to_add = layout.align() - fixup; - - let resulting_ptr = ptr + amount_to_add; - *current_ptr = (resulting_ptr + layout.size()) as *mut _; - - resulting_ptr as *mut _ - } -} - -unsafe impl GlobalAlloc for BumpAllocator { - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - self.alloc_safe(layout) - } - - unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} -} - -#[alloc_error_handler] -fn alloc_error(layout: Layout) -> ! { - panic!( - "Failed to allocate size {} with alignment {}", - layout.size(), - layout.align() - ); -} +use bump_allocator::BumpAllocator; #[global_allocator] static GLOBAL_ALLOC: BumpAllocator = BumpAllocator::new(); - -#[cfg(test)] -mod test { - use alloc::boxed::Box; - - #[test_case] - fn test_box(_gba: &mut crate::Gba) { - let first_box = Box::new(1); - let second_box = Box::new(2); - - assert!(&*first_box as *const _ < &*second_box as *const _); - assert_eq!(*first_box, 1); - assert_eq!(*second_box, 2); - - let address = &*first_box as *const _ as usize; - assert!( - address >= 0x0200_0000 && address < 0x0204_0000, - "ewram is located between 0x0200_0000 and 0x0204_0000, address was actually found to be {:#010X}", - address - ); - } -}