#![feature(allocator_api)]
#![no_std]
extern crate alloc;
extern crate sync_irq;
extern crate spin;
extern crate memory;
extern crate kernel_config;
extern crate block_allocator;
use alloc::alloc::{GlobalAlloc, Layout};
use memory::PteFlags;
use kernel_config::memory::{KERNEL_HEAP_START, KERNEL_HEAP_INITIAL_SIZE};
use sync_irq::IrqSafeMutex;
use spin::Once;
use alloc::boxed::Box;
use block_allocator::FixedSizeBlockAllocator;
#[global_allocator]
pub static GLOBAL_ALLOCATOR: Heap = Heap::empty();
#[cfg(direct_access_to_multiple_heaps)]
pub static DEFAULT_ALLOCATOR: Once<Box<dyn GlobalAlloc + Send + Sync>> = Once::new();
#[cfg(not(direct_access_to_multiple_heaps))]
static DEFAULT_ALLOCATOR: Once<Box<dyn GlobalAlloc + Send + Sync>> = Once::new();
pub const HEAP_FLAGS: PteFlags = PteFlags::from_bits_truncate(
PteFlags::new().bits()
| PteFlags::VALID.bits()
| PteFlags::WRITABLE.bits()
);
const INITIAL_HEAP_END_ADDR: usize = KERNEL_HEAP_START + KERNEL_HEAP_INITIAL_SIZE;
pub fn init_single_heap(start_virt_addr: usize, size_in_bytes: usize) {
unsafe { GLOBAL_ALLOCATOR.initial_allocator.lock().init(start_virt_addr, size_in_bytes); }
}
pub fn set_allocator(allocator: Box<dyn GlobalAlloc + Send + Sync>) {
DEFAULT_ALLOCATOR.call_once(|| allocator);
}
pub struct Heap {
initial_allocator: IrqSafeMutex<block_allocator::FixedSizeBlockAllocator>,
}
impl Heap {
pub const fn empty() -> Heap {
Heap {
initial_allocator: IrqSafeMutex::new(FixedSizeBlockAllocator::new()),
}
}
}
unsafe impl GlobalAlloc for Heap {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
match DEFAULT_ALLOCATOR.get() {
Some(allocator) => {
allocator.alloc(layout)
}
None => {
self.initial_allocator.lock().allocate(layout)
}
}
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
if KERNEL_HEAP_START <= (ptr as usize) && (ptr as usize) < INITIAL_HEAP_END_ADDR {
self.initial_allocator.lock().deallocate(ptr, layout);
}
else {
DEFAULT_ALLOCATOR.get()
.expect("Ptr passed to dealloc is not within the initial allocator's range, and another allocator has not been set up")
.dealloc(ptr, layout);
}
}
}