#![no_std]
#[macro_use]
extern crate log;
extern crate alloc;
use core::{alloc::Layout, fmt, ptr::NonNull};
use ax_errno::AxError;
use strum::{IntoStaticStr, VariantArray};
const PAGE_SIZE: usize = 0x1000;
mod page;
pub use page::GlobalPage;
#[cfg(feature = "tracking")]
pub mod tracking;
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, VariantArray, IntoStaticStr)]
pub enum UsageKind {
RustHeap,
VirtMem,
PageCache,
PageTable,
Dma,
Global,
}
#[derive(Clone, Copy)]
pub struct Usages([usize; UsageKind::VARIANTS.len()]);
impl Usages {
const fn new() -> Self {
Self([0; UsageKind::VARIANTS.len()])
}
fn alloc(&mut self, kind: UsageKind, size: usize) {
self.0[kind as usize] += size;
}
fn dealloc(&mut self, kind: UsageKind, size: usize) {
self.0[kind as usize] -= size;
}
pub fn get(&self, kind: UsageKind) -> usize {
self.0[kind as usize]
}
}
impl fmt::Debug for Usages {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_struct("UsageStats");
for &kind in UsageKind::VARIANTS {
d.field(kind.into(), &self.0[kind as usize]);
}
d.finish()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AllocError {
InvalidParam,
AlreadyInitialized,
MemoryOverlap,
NoMemory,
NotAllocated,
NotInitialized,
NotFound,
}
pub type AllocResult<T = ()> = Result<T, AllocError>;
impl From<AllocError> for AxError {
fn from(value: AllocError) -> Self {
match value {
AllocError::NoMemory => AxError::NoMemory,
AllocError::NotFound => AxError::NotFound,
AllocError::NotInitialized | AllocError::AlreadyInitialized => AxError::BadState,
AllocError::MemoryOverlap => AxError::AlreadyExists,
AllocError::InvalidParam | AllocError::NotAllocated => AxError::InvalidInput,
}
}
}
pub trait AllocatorOps {
fn name(&self) -> &'static str;
fn init(&self, start_vaddr: usize, size: usize) -> AllocResult;
fn add_memory(&self, start_vaddr: usize, size: usize) -> AllocResult;
fn alloc(&self, layout: Layout) -> AllocResult<NonNull<u8>>;
fn dealloc(&self, pos: NonNull<u8>, layout: Layout);
fn alloc_pages(&self, num_pages: usize, align: usize, kind: UsageKind) -> AllocResult<usize>;
fn alloc_dma32_pages(
&self,
num_pages: usize,
align: usize,
kind: UsageKind,
) -> AllocResult<usize>;
fn alloc_pages_at(
&self,
start: usize,
num_pages: usize,
align: usize,
kind: UsageKind,
) -> AllocResult<usize>;
fn dealloc_pages(&self, pos: usize, num_pages: usize, kind: UsageKind);
fn used_bytes(&self) -> usize;
fn available_bytes(&self) -> usize;
fn used_pages(&self) -> usize;
fn available_pages(&self) -> usize;
fn usages(&self) -> Usages;
}
#[cfg(feature = "buddy-slab")]
mod buddy_slab;
#[cfg(feature = "buddy-slab")]
use buddy_slab as imp;
#[cfg(not(feature = "buddy-slab"))]
mod default_impl;
#[cfg(not(feature = "buddy-slab"))]
use default_impl as imp;
#[cfg(feature = "buddy-slab")]
pub use imp::init_percpu_slab;
pub use imp::{DefaultByteAllocator, GlobalAllocator, global_add_memory, global_init};
pub fn global_allocator() -> &'static GlobalAllocator {
imp::global_allocator()
}