allocator that can have a custom start point

This commit is contained in:
Corwin 2022-02-07 21:19:56 +00:00
parent 5761093f19
commit 3c6c7efc79
3 changed files with 32 additions and 35 deletions

View file

@ -49,9 +49,9 @@ pub(crate) struct BlockAllocator {
} }
impl BlockAllocator { impl BlockAllocator {
pub(super) const unsafe fn new() -> Self { pub(super) const unsafe fn new(start: fn() -> usize) -> Self {
Self { Self {
inner_allocator: BumpAllocator::new(), inner_allocator: BumpAllocator::new(start),
state: Mutex::new(RefCell::new(BlockAllocatorState { state: Mutex::new(RefCell::new(BlockAllocatorState {
first_free_block: None, first_free_block: None,
})), })),

View file

@ -8,12 +8,14 @@ use bare_metal::{CriticalSection, Mutex};
pub(crate) struct BumpAllocator { pub(crate) struct BumpAllocator {
current_ptr: Mutex<RefCell<Option<SendNonNull<u8>>>>, current_ptr: Mutex<RefCell<Option<SendNonNull<u8>>>>,
start: Mutex<fn() -> usize>,
} }
impl BumpAllocator { impl BumpAllocator {
pub const fn new() -> Self { pub const fn new(start: fn() -> usize) -> Self {
Self { Self {
current_ptr: Mutex::new(RefCell::new(None)), current_ptr: Mutex::new(RefCell::new(None)),
start: Mutex::new(start),
} }
} }
} }
@ -25,7 +27,7 @@ impl BumpAllocator {
let ptr = if let Some(c) = *current_ptr { let ptr = if let Some(c) = *current_ptr {
c.as_ptr() as usize c.as_ptr() as usize
} else { } else {
get_data_end() self.start.borrow(*cs)()
}; };
let alignment_bitmask = layout.align() - 1; let alignment_bitmask = layout.align() - 1;
@ -56,33 +58,3 @@ unsafe impl GlobalAlloc for BumpAllocator {
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
} }
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
}
#[cfg(test)]
mod tests {
use super::*;
#[test_case]
fn should_return_data_end_somewhere_in_ewram(_gba: &mut crate::Gba) {
let data_end = get_data_end();
assert!(
0x0200_0000 <= data_end,
"data end should be bigger than 0x0200_0000, got {}",
data_end
);
assert!(
0x0204_0000 > data_end,
"data end should be smaller than 0x0203_0000"
);
}
}

View file

@ -33,7 +33,7 @@ impl<T> DerefMut for SendNonNull<T> {
const EWRAM_END: usize = 0x0204_0000; const EWRAM_END: usize = 0x0204_0000;
#[global_allocator] #[global_allocator]
static GLOBAL_ALLOC: BlockAllocator = unsafe { BlockAllocator::new() }; static GLOBAL_ALLOC: BlockAllocator = unsafe { BlockAllocator::new(get_data_end) };
#[cfg(test)] #[cfg(test)]
pub unsafe fn number_of_blocks() -> u32 { pub unsafe fn number_of_blocks() -> u32 {
@ -49,6 +49,16 @@ fn alloc_error(layout: Layout) -> ! {
); );
} }
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
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
const EWRAM_START: usize = 0x0200_0000; const EWRAM_START: usize = 0x0200_0000;
@ -118,4 +128,19 @@ mod test {
assert_eq!(v1[40], 137); assert_eq!(v1[40], 137);
assert_eq!(v2[78], 1075); assert_eq!(v2[78], 1075);
} }
#[test_case]
fn should_return_data_end_somewhere_in_ewram(_gba: &mut crate::Gba) {
let data_end = get_data_end();
assert!(
0x0200_0000 <= data_end,
"data end should be bigger than 0x0200_0000, got {}",
data_end
);
assert!(
0x0204_0000 > data_end,
"data end should be smaller than 0x0203_0000"
);
}
} }