1use super::{Alloc, Slab, SlabFlags, SlabHdr, Uma, UmaFlags, small_alloc};
2use crate::config::{PAGE_MASK, PAGE_SHIFT, PAGE_SIZE};
3use crate::vm::{PageObj, Vm, kaddr_to_phys};
4use alloc::collections::vec_deque::VecDeque;
5use core::alloc::Layout;
6use core::cmp::{max, min};
7use core::num::NonZero;
8use core::ptr::NonNull;
9
10pub struct UmaKeg {
12 vm: &'static Vm,
13 size: NonZero<usize>, rsize: usize, pgoff: usize, ppera: usize, ipers: usize, alloc: fn(&'static Vm, Alloc) -> (*mut u8, SlabFlags), init: Option<fn()>, max_pages: usize, pages: usize, pub(super) free: usize, recurse: u32, partial_slabs: VecDeque<NonNull<Slab>>, flags: UmaFlags, }
27
28impl UmaKeg {
29 pub(super) fn new(
39 vm: &'static Vm,
40 size: NonZero<usize>,
41 align: usize,
42 init: Option<fn()>,
43 mut flags: UmaFlags,
44 ) -> Self {
45 if flags.has_any(UmaFlags::Vm) {
46 todo!()
47 }
48
49 if flags.has_any(UmaFlags::ZInit) {
50 todo!()
51 }
52
53 if flags.has_any(UmaFlags::Malloc) {
54 flags |= UmaFlags::VToSlab;
55 }
56
57 let hdr = Layout::new::<SlabHdr>();
59 let (mut hdr, off) = hdr.extend(Layout::new::<u8>()).unwrap();
60
61 hdr = hdr.pad_to_align();
62
63 let free_item = hdr.size() - off;
65 let available = PAGE_SIZE.get() - hdr.size();
66
67 let (rsize, ppera, ipers) = if flags.has_any(UmaFlags::CacheSpread) {
69 let rsize = size.get().next_multiple_of(align + 1);
71 let align = align + 1;
72 let rsize = if (rsize & align) == 0 {
73 rsize + align
75 } else {
76 rsize
77 };
78
79 let pages = (PAGE_SIZE.get() / align * rsize) >> PAGE_SHIFT;
81 let ppera = min(pages, (128 * 1024) / PAGE_SIZE);
82
83 let ipers = (ppera * PAGE_SIZE.get() + (rsize - size.get())) / rsize;
85
86 (rsize, ppera, ipers)
87 } else {
88 if (size.get() + free_item) > available {
90 if !flags.has_any(UmaFlags::Internal) {
92 flags |= UmaFlags::Offpage;
93
94 if !flags.has_any(UmaFlags::VToSlab) {
95 flags |= UmaFlags::Hash;
96 }
97 }
98
99 let mut ppera = size.get() >> PAGE_SHIFT;
101
102 if size.get() > (size.get() & !PAGE_MASK.get()) {
103 ppera += 1;
104 }
105
106 (size.get(), ppera, 1)
107 } else {
108 let rsize = max(size, Uma::SMALLEST_UNIT);
110 let rsize = rsize.get().next_multiple_of(align + 1);
111
112 let mut ipers = available / (rsize + free_item);
114
115 if !flags.has_any(UmaFlags::Internal | UmaFlags::CacheOnly)
117 && (available % (rsize + free_item)) >= Uma::MAX_WASTE.get()
118 && (PAGE_SIZE.get() / rsize) > ipers
119 {
120 ipers = PAGE_SIZE.get() / rsize;
121
122 if flags.has_any(UmaFlags::VToSlab) {
123 flags |= UmaFlags::Offpage;
124 } else {
125 flags |= UmaFlags::Offpage | UmaFlags::Hash;
126 }
127 }
128
129 (rsize, 1, ipers)
130 }
131 };
132
133 if flags.has_any(UmaFlags::Offpage) {
134 }
136
137 let alloc = if ppera == 1 {
139 small_alloc
141 } else {
142 Self::page_alloc
143 };
144
145 if flags.has_any(UmaFlags::MtxClass) {
146 todo!()
147 }
148
149 let mut pgoff = 0;
151
152 if !flags.has_any(UmaFlags::Offpage) {
153 let space = ppera * PAGE_SIZE.get();
154
155 pgoff = (space - hdr.size()) - ipers * free_item;
157
158 if space < pgoff + hdr.size() + ipers * free_item {
160 panic!("UMA slab won't fit");
161 }
162 }
163
164 if flags.has_any(UmaFlags::Hash) {
165 todo!()
166 }
167
168 Self {
171 vm,
172 size,
173 rsize,
174 pgoff,
175 ppera,
176 ipers,
177 alloc,
178 init,
179 max_pages: 0,
180 pages: 0,
181 free: 0,
182 recurse: 0,
183 partial_slabs: VecDeque::new(),
184 flags,
185 }
186 }
187
188 pub fn size(&self) -> NonZero<usize> {
189 self.size
190 }
191
192 pub fn allocated_size(&self) -> usize {
193 self.rsize
194 }
195
196 pub fn item_per_slab(&self) -> usize {
197 self.ipers
198 }
199
200 pub fn recurse(&self) -> u32 {
201 self.recurse
202 }
203
204 pub fn flags(&self) -> UmaFlags {
205 self.flags
206 }
207
208 fn page_alloc(_: &'static Vm, _: Alloc) -> (*mut u8, SlabFlags) {
215 todo!()
216 }
217
218 pub unsafe fn fetch_slab(&mut self, mut flags: Alloc) -> Option<NonNull<Slab>> {
225 while self.free == 0 {
226 if flags.has_any(Alloc::NoVm) {
227 return None;
228 }
229
230 #[allow(clippy::while_immutable_condition)] while self.max_pages != 0 && self.max_pages <= self.pages {
232 todo!()
233 }
234
235 self.recurse += 1;
236 let slab = self.alloc_slab(flags);
237 self.recurse -= 1;
238
239 if let Some(slab) = slab {
240 self.partial_slabs.push_front(slab);
241 return Some(slab);
242 }
243
244 flags |= Alloc::NoVm;
245 }
246
247 if let Some(v) = self.partial_slabs.front().copied() {
248 return Some(v);
249 }
250
251 todo!()
252 }
253
254 fn alloc_slab(&mut self, flags: Alloc) -> Option<NonNull<Slab>> {
261 if self.flags.has_any(UmaFlags::Offpage) {
262 todo!()
263 } else {
264 let flags = if self.flags.has_any(UmaFlags::Malloc) {
266 flags & !Alloc::Zero
267 } else {
268 flags | Alloc::Zero
269 };
270
271 let (mem, slab_flags) = (self.alloc)(self.vm, flags);
273
274 if !mem.is_null() {
275 let hdr = unsafe { mem.byte_add(self.pgoff).cast::<SlabHdr>() };
278
279 unsafe { hdr.write(SlabHdr::new(slab_flags, mem, self.ipers)) };
284
285 let (_, off) = Layout::new::<SlabHdr>()
287 .extend(Layout::new::<u8>())
288 .unwrap();
289 let free = unsafe { hdr.byte_add(off).cast::<u8>() };
290
291 for i in 0..self.ipers {
292 let item = (i + 1).try_into().unwrap();
293
294 unsafe { free.add(i).write(item) };
295 }
296
297 if self.init.is_some() {
298 todo!()
299 }
300
301 if self.flags.has_any(UmaFlags::Hash) {
302 todo!()
303 }
304
305 self.pages += self.ppera;
306 self.free += self.ipers;
307
308 let slab = core::ptr::slice_from_raw_parts_mut(hdr, self.ipers) as *mut Slab;
311 let slab = unsafe { NonNull::new_unchecked(slab) };
312
313 if self.flags.has_any(UmaFlags::VToSlab) {
314 let mut next = mem as usize;
315
316 for _ in 0..self.ppera {
317 let p = unsafe { kaddr_to_phys(next) };
318 let p = self.vm.phys_to_page(p).unwrap(); let mut s = p.state.lock();
320
321 s.object = Some(PageObj::Slab(slab));
325
326 drop(s);
327
328 next += PAGE_SIZE.get();
329 }
330 }
331
332 return Some(slab);
333 }
334
335 todo!()
336 }
337 }
338}