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 strum::{IntoStaticStr, VariantArray};
18
19const PAGE_SIZE: usize = 0x1000;
20
21pub type PageReclaimFn = fn(num_pages: usize) -> usize;
24
25static PAGE_RECLAIM_FN: ax_sync::SpinLock<Option<PageReclaimFn>> = ax_sync::SpinLock::new(None);
26
27pub fn register_page_reclaim_fn(f: PageReclaimFn) {
30 *PAGE_RECLAIM_FN.lock_irqsave() = Some(f);
31}
32
33pub fn try_page_reclaim(num_pages: usize) -> usize {
40 let reclaim_fn = { *PAGE_RECLAIM_FN.lock_irqsave() };
41 reclaim_fn.map_or(0, |f| f(num_pages))
42}
43
44mod page;
45pub use page::GlobalPage;
46
47#[cfg(feature = "tracking")]
49pub mod tracking;
50
51#[repr(u8)]
53#[derive(Debug, Clone, Copy, PartialEq, Eq, VariantArray, IntoStaticStr)]
54pub enum UsageKind {
55 RustHeap,
57 VirtMem,
59 PageCache,
61 PageTable,
63 Dma,
65 Global,
67}
68
69#[derive(Clone, Copy)]
71pub struct Usages([usize; UsageKind::VARIANTS.len()]);
72
73impl Usages {
74 const fn new() -> Self {
75 Self([0; UsageKind::VARIANTS.len()])
76 }
77
78 #[allow(dead_code)]
79 fn alloc(&mut self, kind: UsageKind, size: usize) {
80 self.0[kind as usize] += size;
81 }
82
83 #[allow(dead_code)]
84 fn dealloc(&mut self, kind: UsageKind, size: usize) {
85 self.0[kind as usize] -= size;
86 }
87
88 pub fn get(&self, kind: UsageKind) -> usize {
90 self.0[kind as usize]
91 }
92}
93
94impl fmt::Debug for Usages {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 let mut d = f.debug_struct("UsageStats");
97 for &kind in UsageKind::VARIANTS {
98 d.field(kind.into(), &self.0[kind as usize]);
99 }
100 d.finish()
101 }
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
106pub enum AllocError {
107 #[error("invalid allocation parameter")]
109 InvalidParam,
110 #[error("allocator is already initialized")]
112 AlreadyInitialized,
113 #[error("memory region overlaps an existing allocation region")]
115 MemoryOverlap,
116 #[error("not enough memory")]
118 NoMemory,
119 #[error("memory was not allocated by this allocator")]
121 NotAllocated,
122 #[error("allocator is not initialized")]
124 NotInitialized,
125 #[error("allocation was not found")]
127 NotFound,
128}
129
130pub type AllocResult<T = ()> = Result<T, AllocError>;
132
133pub trait AllocatorOps {
135 fn name(&self) -> &'static str;
137
138 fn init(&self, start_vaddr: usize, size: usize) -> AllocResult;
140
141 fn add_memory(&self, start_vaddr: usize, size: usize) -> AllocResult;
143
144 fn alloc(&self, layout: Layout) -> AllocResult<NonNull<u8>>;
146
147 fn dealloc(&self, pos: NonNull<u8>, layout: Layout);
149
150 fn alloc_pages(&self, num_pages: usize, align: usize, kind: UsageKind) -> AllocResult<usize>;
155
156 fn alloc_dma32_pages(
161 &self,
162 num_pages: usize,
163 align: usize,
164 kind: UsageKind,
165 ) -> AllocResult<usize>;
166
167 fn alloc_pages_at(
172 &self,
173 start: usize,
174 num_pages: usize,
175 align: usize,
176 kind: UsageKind,
177 ) -> AllocResult<usize>;
178
179 fn dealloc_pages(&self, pos: usize, num_pages: usize, kind: UsageKind);
181
182 fn used_bytes(&self) -> usize;
184
185 fn available_bytes(&self) -> usize;
187
188 fn used_pages(&self) -> usize;
190
191 fn available_pages(&self) -> usize;
193
194 fn usages(&self) -> Usages;
196}
197
198#[cfg(buddy_slab)]
200mod buddy_slab;
201#[cfg(not(any(tlsf, buddy_slab)))]
202mod stub_impl;
203#[cfg(tlsf)]
204mod tlsf_impl;
205
206#[cfg(buddy_slab)]
207use buddy_slab as imp;
208pub use imp::{
209 DefaultByteAllocator, GlobalAllocator, global_add_memory, global_init, init_percpu_slab,
210};
211#[cfg(not(any(tlsf, buddy_slab)))]
212use stub_impl as imp;
213#[cfg(tlsf)]
214use tlsf_impl as imp;
215
216pub fn global_allocator() -> &'static GlobalAllocator {
218 imp::global_allocator()
219}