1#![no_std]
9
10#[macro_use]
11extern crate log;
12extern crate alloc;
13
14use core::{alloc::Layout, fmt, ptr::NonNull};
15
16use ax_errno::AxError;
17use strum::{IntoStaticStr, VariantArray};
18
19const PAGE_SIZE: usize = 0x1000;
20
21mod page;
22pub use page::GlobalPage;
23
24#[cfg(feature = "tracking")]
26pub mod tracking;
27
28#[repr(u8)]
30#[derive(Debug, Clone, Copy, PartialEq, Eq, VariantArray, IntoStaticStr)]
31pub enum UsageKind {
32 RustHeap,
34 VirtMem,
36 PageCache,
38 PageTable,
40 Dma,
42 Global,
44}
45
46#[derive(Clone, Copy)]
48pub struct Usages([usize; UsageKind::VARIANTS.len()]);
49
50impl Usages {
51 const fn new() -> Self {
52 Self([0; UsageKind::VARIANTS.len()])
53 }
54
55 fn alloc(&mut self, kind: UsageKind, size: usize) {
56 self.0[kind as usize] += size;
57 }
58
59 fn dealloc(&mut self, kind: UsageKind, size: usize) {
60 self.0[kind as usize] -= size;
61 }
62
63 pub fn get(&self, kind: UsageKind) -> usize {
65 self.0[kind as usize]
66 }
67}
68
69impl fmt::Debug for Usages {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 let mut d = f.debug_struct("UsageStats");
72 for &kind in UsageKind::VARIANTS {
73 d.field(kind.into(), &self.0[kind as usize]);
74 }
75 d.finish()
76 }
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81pub enum AllocError {
82 InvalidParam,
84 AlreadyInitialized,
86 MemoryOverlap,
88 NoMemory,
90 NotAllocated,
92 NotInitialized,
94 NotFound,
96}
97
98pub type AllocResult<T = ()> = Result<T, AllocError>;
100
101impl From<AllocError> for AxError {
102 fn from(value: AllocError) -> Self {
103 match value {
104 AllocError::NoMemory => AxError::NoMemory,
105 AllocError::NotFound => AxError::NotFound,
106 AllocError::NotInitialized | AllocError::AlreadyInitialized => AxError::BadState,
107 AllocError::MemoryOverlap => AxError::AlreadyExists,
108 AllocError::InvalidParam | AllocError::NotAllocated => AxError::InvalidInput,
109 }
110 }
111}
112
113pub trait AllocatorOps {
115 fn name(&self) -> &'static str;
117
118 fn init(&self, start_vaddr: usize, size: usize) -> AllocResult;
120
121 fn add_memory(&self, start_vaddr: usize, size: usize) -> AllocResult;
123
124 fn alloc(&self, layout: Layout) -> AllocResult<NonNull<u8>>;
126
127 fn dealloc(&self, pos: NonNull<u8>, layout: Layout);
129
130 fn alloc_pages(&self, num_pages: usize, align: usize, kind: UsageKind) -> AllocResult<usize>;
135
136 fn alloc_dma32_pages(
141 &self,
142 num_pages: usize,
143 align: usize,
144 kind: UsageKind,
145 ) -> AllocResult<usize>;
146
147 fn alloc_pages_at(
152 &self,
153 start: usize,
154 num_pages: usize,
155 align: usize,
156 kind: UsageKind,
157 ) -> AllocResult<usize>;
158
159 fn dealloc_pages(&self, pos: usize, num_pages: usize, kind: UsageKind);
161
162 fn used_bytes(&self) -> usize;
164
165 fn available_bytes(&self) -> usize;
167
168 fn used_pages(&self) -> usize;
170
171 fn available_pages(&self) -> usize;
173
174 fn usages(&self) -> Usages;
176}
177
178#[cfg(feature = "buddy-slab")]
180mod buddy_slab;
181#[cfg(feature = "buddy-slab")]
182use buddy_slab as imp;
183
184#[cfg(not(feature = "buddy-slab"))]
185mod default_impl;
186#[cfg(not(feature = "buddy-slab"))]
187use default_impl as imp;
188#[cfg(feature = "buddy-slab")]
189pub use imp::init_percpu_slab;
190pub use imp::{DefaultByteAllocator, GlobalAllocator, global_add_memory, global_init};
191
192pub fn global_allocator() -> &'static GlobalAllocator {
194 imp::global_allocator()
195}