1#![no_std]
9#![cfg_attr(feature = "buddy-slab", feature(extern_item_impls))]
10
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
22mod page;
23pub use page::GlobalPage;
24
25#[cfg(feature = "tracking")]
27pub mod tracking;
28
29#[repr(u8)]
31#[derive(Debug, Clone, Copy, PartialEq, Eq, VariantArray, IntoStaticStr)]
32pub enum UsageKind {
33 RustHeap,
35 VirtMem,
37 PageCache,
39 PageTable,
41 Dma,
43 Global,
45}
46
47#[derive(Clone, Copy)]
49pub struct Usages([usize; UsageKind::VARIANTS.len()]);
50
51impl Usages {
52 const fn new() -> Self {
53 Self([0; UsageKind::VARIANTS.len()])
54 }
55
56 fn alloc(&mut self, kind: UsageKind, size: usize) {
57 self.0[kind as usize] += size;
58 }
59
60 fn dealloc(&mut self, kind: UsageKind, size: usize) {
61 self.0[kind as usize] -= size;
62 }
63
64 pub fn get(&self, kind: UsageKind) -> usize {
66 self.0[kind as usize]
67 }
68}
69
70impl fmt::Debug for Usages {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 let mut d = f.debug_struct("UsageStats");
73 for &kind in UsageKind::VARIANTS {
74 d.field(kind.into(), &self.0[kind as usize]);
75 }
76 d.finish()
77 }
78}
79
80#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82pub enum AllocError {
83 InvalidParam,
85 AlreadyInitialized,
87 MemoryOverlap,
89 NoMemory,
91 NotAllocated,
93 NotInitialized,
95 NotFound,
97}
98
99pub type AllocResult<T = ()> = Result<T, AllocError>;
101
102impl From<AllocError> for AxError {
103 fn from(value: AllocError) -> Self {
104 match value {
105 AllocError::NoMemory => AxError::NoMemory,
106 AllocError::NotFound => AxError::NotFound,
107 AllocError::NotInitialized | AllocError::AlreadyInitialized => AxError::BadState,
108 AllocError::MemoryOverlap => AxError::AlreadyExists,
109 AllocError::InvalidParam | AllocError::NotAllocated => AxError::InvalidInput,
110 }
111 }
112}
113
114#[cfg(feature = "buddy-slab")]
115pub mod eii {
117 #[eii(ax_alloc_virt_to_phys_impl)]
119 pub fn virt_to_phys(vaddr: usize) -> usize;
120}
121
122pub trait AllocatorOps {
124 fn name(&self) -> &'static str;
126
127 fn init(&self, start_vaddr: usize, size: usize) -> AllocResult;
129
130 fn add_memory(&self, start_vaddr: usize, size: usize) -> AllocResult;
132
133 fn alloc(&self, layout: Layout) -> AllocResult<NonNull<u8>>;
135
136 fn dealloc(&self, pos: NonNull<u8>, layout: Layout);
138
139 fn alloc_pages(&self, num_pages: usize, align: usize, kind: UsageKind) -> AllocResult<usize>;
144
145 fn alloc_dma32_pages(
150 &self,
151 num_pages: usize,
152 align: usize,
153 kind: UsageKind,
154 ) -> AllocResult<usize>;
155
156 fn alloc_pages_at(
161 &self,
162 start: usize,
163 num_pages: usize,
164 align: usize,
165 kind: UsageKind,
166 ) -> AllocResult<usize>;
167
168 fn dealloc_pages(&self, pos: usize, num_pages: usize, kind: UsageKind);
170
171 fn used_bytes(&self) -> usize;
173
174 fn available_bytes(&self) -> usize;
176
177 fn used_pages(&self) -> usize;
179
180 fn available_pages(&self) -> usize;
182
183 fn usages(&self) -> Usages;
185}
186
187#[cfg(feature = "buddy-slab")]
189mod buddy_slab;
190#[cfg(feature = "buddy-slab")]
191use buddy_slab as imp;
192
193#[cfg(not(feature = "buddy-slab"))]
194mod default_impl;
195#[cfg(not(feature = "buddy-slab"))]
196use default_impl as imp;
197#[cfg(feature = "buddy-slab")]
198pub use imp::init_precpu_slab;
199pub use imp::{DefaultByteAllocator, GlobalAllocator, global_add_memory, global_init};
200
201pub fn global_allocator() -> &'static GlobalAllocator {
203 imp::global_allocator()
204}