From 7062610abade962824019b902532bc389e30fe35 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Mon, 16 Aug 2021 21:02:55 +0100 Subject: [PATCH] Start a basic allocator with a super simple test --- agb/src/agb_alloc/mod.rs | 76 ++++++++++++++++++++++++++++++++++++++++ agb/src/lib.rs | 6 +++- 2 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 agb/src/agb_alloc/mod.rs diff --git a/agb/src/agb_alloc/mod.rs b/agb/src/agb_alloc/mod.rs new file mode 100644 index 00000000..6908892e --- /dev/null +++ b/agb/src/agb_alloc/mod.rs @@ -0,0 +1,76 @@ +use core::alloc::{GlobalAlloc, Layout}; + +use super::interrupt::Mutex; + +extern "C" { + static __ewram_data_end: usize; +} + +fn get_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 { + fn alloc_safe(&self, layout: Layout) -> *mut u8 { + let mut current_ptr = self.current_ptr.lock(); + + let mut ptr = *current_ptr as usize; + + if ptr == 0 { + ptr = get_data_end(); + } + + 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() + ); +} + +#[global_allocator] +static GLOBAL_ALLOC: BumpAllocator = BumpAllocator { + current_ptr: Mutex::new(core::ptr::null_mut()), +}; + +#[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); + } +} diff --git a/agb/src/lib.rs b/agb/src/lib.rs index cb2a98fd..38a8f443 100644 --- a/agb/src/lib.rs +++ b/agb/src/lib.rs @@ -4,15 +4,17 @@ #![feature(asm)] #![deny(clippy::all)] #![feature(custom_test_frameworks)] +#![feature(alloc_error_handler)] #![test_runner(crate::test_runner)] #![reexport_test_harness_main = "test_main"] - //! # agb //! `agb` is a library for making games on the Game Boy Advance using the Rust //! programming language. It attempts to be a high level abstraction over the //! internal workings of the Game Boy Advance whilst still being high //! performance and memory efficient. +extern crate alloc; + /// Implements everything relating to things that are displayed on screen. pub mod display; /// Button inputs to the system. @@ -32,6 +34,8 @@ pub mod mgba; pub mod number; mod single; +mod agb_alloc; + /// System BIOS calls / syscalls. pub mod syscall;