atmos/kernel/
allocator.rs1#![allow(dead_code)]
17
18use core::alloc::{GlobalAlloc, Layout};
19use core::ptr::{null_mut, NonNull};
20use core::sync::atomic::{AtomicBool, Ordering};
21use rlsf::Tlsf;
22
23type TheTlsf = Tlsf<'static, u32, u16, 25, 16>;
28
29struct TlsfHeap {
31 tlsf: TheTlsf,
32 total: usize,
33 used: usize,
34}
35
36impl TlsfHeap {
37 const fn empty() -> Self {
39 Self {
40 tlsf: Tlsf::new(),
41 total: 0,
42 used: 0,
43 }
44 }
45
46 unsafe fn init(&mut self, start: usize, size: usize) {
51 self.total = size;
52 self.used = 0;
53 let slice = core::ptr::slice_from_raw_parts_mut(start as *mut u8, size);
54 if let Some(nn) = NonNull::new(slice) {
55 self.tlsf.insert_free_block_ptr(nn);
56 }
57 }
58
59 unsafe fn alloc(&mut self, layout: Layout) -> *mut u8 {
60 match self.tlsf.allocate(layout) {
61 Some(p) => {
62 self.used = self.used.saturating_add(layout.size());
63 p.as_ptr()
64 }
65 None => null_mut(),
66 }
67 }
68
69 unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
70 self.tlsf.deallocate(ptr, layout.align());
72 self.used = self.used.saturating_sub(layout.size());
73 }
74
75 fn free_space(&self) -> usize {
76 self.total.saturating_sub(self.used)
77 }
78}
79
80#[global_allocator]
82static ALLOCATOR: Locked<TlsfHeap> = Locked::new(TlsfHeap::empty());
83
84pub const KERNEL_HEAP_SIZE: usize = 512 * 1024 * 1024;
96
97static mut TOTAL_HEAP_SIZE: usize = 0;
99
100pub fn init(start: usize, size: usize) {
102 unsafe {
103 TOTAL_HEAP_SIZE = size;
104 ALLOCATOR.lock().init(start, size);
105 }
106}
107
108pub fn get_heap_stats() -> (usize, usize) {
112 let total = unsafe { TOTAL_HEAP_SIZE };
113 let free = ALLOCATOR.lock().free_space();
114 (total.saturating_sub(free), total)
115}
116
117pub fn check_heap_integrity() -> bool {
122 false
123}
124
125pub fn force_release_lock(cid: i16) {
128 unsafe {
129 ALLOCATOR.force_release_if_core(cid);
130 }
131}
132
133unsafe impl GlobalAlloc for Locked<TlsfHeap> {
134 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
135 self.lock().alloc(layout)
136 }
137
138 unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
139 if let Some(nn) = NonNull::new(ptr) {
140 self.lock().dealloc(nn, layout);
141 }
142 }
143}
144
145pub struct Locked<A> {
152 inner: spin::Mutex<A>,
153 holder: core::sync::atomic::AtomicI16,
155}
156
157impl<A> Locked<A> {
158 pub const fn new(inner: A) -> Self {
160 Self {
161 inner: spin::Mutex::new(inner),
162 holder: core::sync::atomic::AtomicI16::new(-1),
163 }
164 }
165
166 pub fn lock(&self) -> LockedGuard<'_, A> {
180 let guard = self.inner.lock();
181 self.holder.store(
182 crate::kernel::scheduler::core_id() as i16,
183 Ordering::Relaxed,
184 );
185 LockedGuard {
186 guard: Some(guard),
187 holder: &self.holder,
188 }
189 }
190
191 pub unsafe fn force_release_if_core(&self, cid: i16) {
198 if self.holder.load(Ordering::Relaxed) == cid {
199 self.holder.store(-1, Ordering::Relaxed);
200 self.inner.force_unlock();
201 }
202 }
203}
204
205pub struct LockedGuard<'a, A> {
206 guard: Option<spin::MutexGuard<'a, A>>,
207 holder: &'a core::sync::atomic::AtomicI16,
208}
209
210impl<'a, A> Drop for LockedGuard<'a, A> {
211 fn drop(&mut self) {
212 self.holder.store(-1, Ordering::Relaxed);
213 self.guard.take(); }
215}
216
217impl<'a, A> core::ops::Deref for LockedGuard<'a, A> {
218 type Target = A;
219 fn deref(&self) -> &A {
220 match self.guard.as_ref() {
221 Some(g) => g,
222 None => loop {
223 core::hint::spin_loop();
224 },
225 }
226 }
227}
228
229impl<'a, A> core::ops::DerefMut for LockedGuard<'a, A> {
230 fn deref_mut(&mut self) -> &mut A {
231 match self.guard.as_mut() {
232 Some(g) => g,
233 None => loop {
234 core::hint::spin_loop();
235 },
236 }
237 }
238}
239
240mod spin {
245 use super::*;
246
247 pub struct Mutex<T> {
248 lock: AtomicBool,
249 data: core::cell::UnsafeCell<T>,
250 }
251
252 unsafe impl<T: Send> Sync for Mutex<T> {}
253 unsafe impl<T: Send> Send for Mutex<T> {}
254
255 pub struct MutexGuard<'a, T> {
256 mutex: &'a Mutex<T>,
257 interrupt_state: bool,
258 }
259
260 impl<T> Mutex<T> {
261 pub const fn new(value: T) -> Self {
262 Self {
263 lock: AtomicBool::new(false),
264 data: core::cell::UnsafeCell::new(value),
265 }
266 }
267
268 pub fn lock(&self) -> MutexGuard<'_, T> {
269 let irq_enabled = is_interrupt_enabled();
270 if irq_enabled {
271 disable_interrupts();
272 }
273
274 while self
275 .lock
276 .compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed)
277 .is_err()
278 {
279 core::hint::spin_loop();
280 }
281
282 MutexGuard {
283 mutex: self,
284 interrupt_state: irq_enabled,
285 }
286 }
287
288 pub unsafe fn force_unlock(&self) {
294 self.lock.store(false, Ordering::Release);
295 }
296 }
297
298 impl<'a, T> core::ops::Deref for MutexGuard<'a, T> {
299 type Target = T;
300 fn deref(&self) -> &Self::Target {
301 unsafe { &*self.mutex.data.get() }
302 }
303 }
304
305 impl<'a, T> core::ops::DerefMut for MutexGuard<'a, T> {
306 fn deref_mut(&mut self) -> &mut Self::Target {
307 unsafe { &mut *self.mutex.data.get() }
308 }
309 }
310
311 impl<'a, T> Drop for MutexGuard<'a, T> {
312 fn drop(&mut self) {
313 self.mutex.lock.store(false, Ordering::Release);
314 if self.interrupt_state {
315 enable_interrupts();
316 }
317 }
318 }
319
320 pub(super) fn is_interrupt_enabled() -> bool {
321 let daif: u64;
322 unsafe {
323 core::arch::asm!("mrs {}, daif", out(reg) daif);
324 }
325 (daif & (1 << 7)) == 0
326 }
327
328 pub(super) fn disable_interrupts() {
329 unsafe {
330 core::arch::asm!("msr daifset, #2", options(nomem, nostack));
331 }
332 }
333
334 pub(super) fn enable_interrupts() {
335 unsafe {
336 core::arch::asm!("msr daifclr, #2", options(nomem, nostack));
337 }
338 }
339}