1use crate::config::{PAGE_MASK, PAGE_SHIFT, PAGE_SIZE};
2use crate::context::{CpuLocal, current_thread, uma};
3use crate::uma::{Alloc, SlabFlags, UmaFlags, UmaZone};
4use crate::vm::{PageObj, Vm, kaddr_to_phys};
5use alloc::string::ToString;
6use alloc::sync::Arc;
7use alloc::vec::Vec;
8use core::alloc::Layout;
9use core::cell::RefCell;
10use core::num::NonZero;
11use core::ptr::null_mut;
12
13pub struct VmHeap {
16 vm: &'static Vm,
17 zones: [Vec<Arc<UmaZone>>; PAGE_SHIFT + 1], stats: CpuLocal<RefCell<Stats>>, }
20
21impl VmHeap {
22 const KMEM_ZSHIFT: usize = 4;
23 const KMEM_ZBASE: usize = 16;
24 const KMEM_ZMASK: usize = Self::KMEM_ZBASE - 1;
25 const KMEM_ZSIZE: usize = PAGE_SIZE.get() >> Self::KMEM_ZSHIFT;
26
27 pub fn new(vm: &'static Vm) -> Self {
34 let uma = uma().unwrap();
35 let zones = core::array::from_fn(|align| {
36 let mut zones = Vec::with_capacity(Self::KMEM_ZSIZE + 1);
37 let mut last = 0;
38 let align = align
39 .try_into()
40 .ok()
41 .and_then(|align| 1usize.checked_shl(align))
42 .unwrap();
43
44 for i in Self::KMEM_ZSHIFT.. {
45 let size = NonZero::new(1usize << i).unwrap();
47
48 if size > PAGE_SIZE {
49 break;
50 }
51
52 let zone = Arc::new(uma.into_owned().create_zone(
54 size.to_string(),
55 size,
56 Some(align - 1),
57 None,
58 None,
59 None,
60 UmaFlags::Malloc,
61 ));
62
63 while last <= size.get() {
64 zones.push(zone.clone());
65 last += Self::KMEM_ZBASE;
66 }
67 }
68
69 zones
70 });
71
72 Self {
73 vm,
74 zones,
75 stats: CpuLocal::new(|_| RefCell::default()),
76 }
77 }
78
79 pub unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
91 let td = current_thread();
93
94 if !td.can_sleep() {
95 panic!("heap allocation in a non-sleeping context is not supported");
96 }
97
98 let lock = td.disable_vm_heap();
100 let size = layout.size();
101 let mem = if size <= PAGE_SIZE.get() {
102 let zone = match self.zone_for_layout(layout) {
104 Some(v) => v,
105 None => return null_mut(),
106 };
107
108 let mem = zone.alloc(Alloc::Wait | Alloc::Zero);
110 let stats = self.stats.lock();
111 let mut stats = stats.borrow_mut();
112 let size = if mem.is_null() { 0 } else { zone.size().get() };
113
114 if size != 0 {
115 stats.alloc_bytes = stats
116 .alloc_bytes
117 .checked_add(size.try_into().unwrap())
118 .unwrap();
119 stats.alloc_count += 1;
120 }
121
122 mem
124 } else {
125 todo!()
126 };
127
128 drop(lock);
129
130 mem
131 }
132
133 pub unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
144 let page = (ptr as usize) & !PAGE_MASK.get();
145 let page = unsafe { kaddr_to_phys(page) };
146 let page = self.vm.phys_to_page(page).unwrap(); let ps = page.state.lock();
148 let obj = ps.object.as_ref().unwrap(); let PageObj::Slab(slab) = obj;
150
151 if slab.flags().has_any(SlabFlags::Malloc) {
152 todo!()
153 } else {
154 let zone = self.zone_for_layout(layout).unwrap(); unsafe { zone.free(ptr) };
157 }
158
159 todo!()
160 }
161
162 fn zone_for_layout(&self, layout: Layout) -> Option<&UmaZone> {
167 let align = layout.align().trailing_zeros() as usize;
169 let zones = self.zones.get(align)?;
170
171 let size = layout.size();
173 let size = if (size & Self::KMEM_ZMASK) != 0 {
174 (size + Self::KMEM_ZBASE) & !Self::KMEM_ZMASK
176 } else {
177 size
178 };
179
180 Some(&zones[size >> Self::KMEM_ZSHIFT])
181 }
182}
183
184#[derive(Default)]
186struct Stats {
187 alloc_bytes: u64, alloc_count: u64, }