1#![no_std]
9
10#[allow(unused_imports)]
11#[macro_use]
12extern crate log;
13extern crate alloc;
14
15use core::{alloc::Layout, fmt, ptr::NonNull};
16
17use ax_errno::AxError;
18use strum::{IntoStaticStr, VariantArray};
19
20const PAGE_SIZE: usize = 0x1000;
21
22pub type PageReclaimFn = fn(num_pages: usize) -> usize;
25
26static PAGE_RECLAIM_FN: ax_kspin::SpinNoIrq<Option<PageReclaimFn>> = ax_kspin::SpinNoIrq::new(None);
27
28pub fn register_page_reclaim_fn(f: PageReclaimFn) {
31 *PAGE_RECLAIM_FN.lock() = Some(f);
32}
33
34pub fn try_page_reclaim(num_pages: usize) -> usize {
41 let reclaim_fn = { *PAGE_RECLAIM_FN.lock() };
42 reclaim_fn.map_or(0, |f| f(num_pages))
43}
44
45mod page;
46pub use page::GlobalPage;
47
48#[cfg(feature = "tracking")]
50pub mod tracking;
51
52#[repr(u8)]
54#[derive(Debug, Clone, Copy, PartialEq, Eq, VariantArray, IntoStaticStr)]
55pub enum UsageKind {
56 RustHeap,
58 VirtMem,
60 PageCache,
62 PageTable,
64 Dma,
66 Global,
68}
69
70#[derive(Clone, Copy)]
72pub struct Usages([usize; UsageKind::VARIANTS.len()]);
73
74impl Usages {
75 const fn new() -> Self {
76 Self([0; UsageKind::VARIANTS.len()])
77 }
78
79 #[allow(dead_code)]
80 fn alloc(&mut self, kind: UsageKind, size: usize) {
81 self.0[kind as usize] += size;
82 }
83
84 #[allow(dead_code)]
85 fn dealloc(&mut self, kind: UsageKind, size: usize) {
86 self.0[kind as usize] -= size;
87 }
88
89 pub fn get(&self, kind: UsageKind) -> usize {
91 self.0[kind as usize]
92 }
93}
94
95impl fmt::Debug for Usages {
96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97 let mut d = f.debug_struct("UsageStats");
98 for &kind in UsageKind::VARIANTS {
99 d.field(kind.into(), &self.0[kind as usize]);
100 }
101 d.finish()
102 }
103}
104
105#[derive(Debug, Clone, Copy, PartialEq, Eq)]
107pub enum AllocError {
108 InvalidParam,
110 AlreadyInitialized,
112 MemoryOverlap,
114 NoMemory,
116 NotAllocated,
118 NotInitialized,
120 NotFound,
122}
123
124pub type AllocResult<T = ()> = Result<T, AllocError>;
126
127impl From<AllocError> for AxError {
128 fn from(value: AllocError) -> Self {
129 match value {
130 AllocError::NoMemory => AxError::NoMemory,
131 AllocError::NotFound => AxError::NotFound,
132 AllocError::NotInitialized | AllocError::AlreadyInitialized => AxError::BadState,
133 AllocError::MemoryOverlap => AxError::AlreadyExists,
134 AllocError::InvalidParam | AllocError::NotAllocated => AxError::InvalidInput,
135 }
136 }
137}
138
139pub trait AllocatorOps {
141 fn name(&self) -> &'static str;
143
144 fn init(&self, start_vaddr: usize, size: usize) -> AllocResult;
146
147 fn add_memory(&self, start_vaddr: usize, size: usize) -> AllocResult;
149
150 fn alloc(&self, layout: Layout) -> AllocResult<NonNull<u8>>;
152
153 fn dealloc(&self, pos: NonNull<u8>, layout: Layout);
155
156 fn alloc_pages(&self, num_pages: usize, align: usize, kind: UsageKind) -> AllocResult<usize>;
161
162 fn alloc_dma32_pages(
167 &self,
168 num_pages: usize,
169 align: usize,
170 kind: UsageKind,
171 ) -> AllocResult<usize>;
172
173 fn alloc_pages_at(
178 &self,
179 start: usize,
180 num_pages: usize,
181 align: usize,
182 kind: UsageKind,
183 ) -> AllocResult<usize>;
184
185 fn dealloc_pages(&self, pos: usize, num_pages: usize, kind: UsageKind);
187
188 fn used_bytes(&self) -> usize;
190
191 fn available_bytes(&self) -> usize;
193
194 fn used_pages(&self) -> usize;
196
197 fn available_pages(&self) -> usize;
199
200 fn usages(&self) -> Usages;
202}
203
204#[cfg(buddy_slab)]
206mod buddy_slab;
207#[cfg(not(any(tlsf, buddy_slab)))]
208mod stub_impl;
209#[cfg(tlsf)]
210mod tlsf_impl;
211
212#[cfg(buddy_slab)]
213use buddy_slab as imp;
214pub use imp::{
215 DefaultByteAllocator, GlobalAllocator, global_add_memory, global_init, init_percpu_slab,
216};
217#[cfg(not(any(tlsf, buddy_slab)))]
218use stub_impl as imp;
219#[cfg(tlsf)]
220use tlsf_impl as imp;
221
222pub fn global_allocator() -> &'static GlobalAllocator {
224 imp::global_allocator()
225}