diff --git a/agb/examples/allocation.rs b/agb/examples/allocation.rs index 64f0ddd3..a9e9b80d 100644 --- a/agb/examples/allocation.rs +++ b/agb/examples/allocation.rs @@ -1,5 +1,6 @@ #![no_std] #![no_main] +#![feature(allocator_api)] extern crate alloc; @@ -8,7 +9,11 @@ use alloc::boxed::Box; #[agb::entry] fn main(_gba: agb::Gba) -> ! { loop { + let a = Box::new_in(1, agb::agb_alloc::EWRAM_ALLOC); let b = Box::new(1); - agb::println!("dynamic allocation made to {:?}", &*b as *const _); + let c = Box::new_in(3, agb::agb_alloc::IWRAM_ALLOC); + agb::println!("ewram allocation made to {:?}", &*a as *const _); + agb::println!("global allocation made to {:?}", &*b as *const _); + agb::println!("iwram allocation made to {:?}", &*c as *const _); } } diff --git a/agb/src/agb_alloc/block_allocator.rs b/agb/src/agb_alloc/block_allocator.rs index a601131e..5e7b45f8 100644 --- a/agb/src/agb_alloc/block_allocator.rs +++ b/agb/src/agb_alloc/block_allocator.rs @@ -3,7 +3,7 @@ //! the linked list in order of pointer. Blocks are then merged after every //! free. -use core::alloc::{GlobalAlloc, Layout}; +use core::alloc::{Allocator, GlobalAlloc, Layout}; use core::cell::RefCell; use core::convert::TryInto; @@ -43,13 +43,13 @@ struct BlockAllocatorState { first_free_block: Option>, } -pub(crate) struct BlockAllocator { +pub struct BlockAllocator { inner_allocator: BumpAllocator, state: Mutex>, } impl BlockAllocator { - pub const unsafe fn new(start: StartEnd) -> Self { + pub(crate) const unsafe fn new(start: StartEnd) -> Self { Self { inner_allocator: BumpAllocator::new(start), state: Mutex::new(RefCell::new(BlockAllocatorState { @@ -216,3 +216,21 @@ unsafe impl GlobalAlloc for BlockAllocator { self.dealloc(ptr, layout); } } + +unsafe impl Allocator for BlockAllocator { + fn allocate(&self, layout: Layout) -> Result, core::alloc::AllocError> { + match unsafe { self.alloc(layout) } { + None => Err(core::alloc::AllocError), + Some(p) => Ok(unsafe { + NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( + p.as_ptr(), + layout.size(), + )) + }), + } + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + self.dealloc(ptr.as_ptr(), layout); + } +} diff --git a/agb/src/agb_alloc/mod.rs b/agb/src/agb_alloc/mod.rs index ecffeb72..28d40bda 100644 --- a/agb/src/agb_alloc/mod.rs +++ b/agb/src/agb_alloc/mod.rs @@ -33,6 +33,7 @@ impl DerefMut for SendNonNull { } const EWRAM_END: usize = 0x0204_0000; +const IWRAM_END: usize = 0x0300_8000; #[global_allocator] static GLOBAL_ALLOC: BlockAllocator = unsafe { @@ -42,7 +43,17 @@ static GLOBAL_ALLOC: BlockAllocator = unsafe { }) }; +pub static EWRAM_ALLOC: &BlockAllocator = &GLOBAL_ALLOC; +pub static IWRAM_ALLOC: &BlockAllocator = &__IWRAM_ALLOC; +static __IWRAM_ALLOC: BlockAllocator = unsafe { + BlockAllocator::new(StartEnd { + start: iwram_data_end, + end: || IWRAM_END, + }) +}; + #[cfg(any(test, feature = "testing"))] +#[cfg(test)] pub unsafe fn number_of_blocks() -> u32 { GLOBAL_ALLOC.number_of_blocks() } @@ -56,6 +67,16 @@ fn alloc_error(layout: Layout) -> ! { ); } +fn iwram_data_end() -> usize { + extern "C" { + static __iwram_data_end: usize; + } + + // TODO: This seems completely wrong, but without the &, rust generates + // a double dereference :/. Maybe a bug in nightly? + (unsafe { &__iwram_data_end }) as *const _ as usize +} + fn data_end() -> usize { extern "C" { static __ewram_data_end: usize; diff --git a/agb/src/lib.rs b/agb/src/lib.rs index 16fb1044..7b6448c5 100644 --- a/agb/src/lib.rs +++ b/agb/src/lib.rs @@ -11,6 +11,7 @@ reexport_test_harness_main = "test_main" )] #![feature(alloc_error_handler)] +#![feature(allocator_api)] #![warn(clippy::all)] #![deny(clippy::must_use_candidate)] #![deny(clippy::trivially_copy_pass_by_ref)] @@ -161,7 +162,7 @@ pub use agb_macros::entry; pub use agb_sound_converter::include_wav; extern crate alloc; -mod agb_alloc; +pub mod agb_alloc; mod agbabi; mod bitarray;