1pub use self::slab::*;
2pub use self::zone::*;
3
4pub(self) use self::arch::*;
5pub(self) use self::bucket::*;
6pub(self) use self::keg::*;
7
8use crate::config::PAGE_SIZE;
9use crate::vm::Vm;
10use alloc::format;
11use alloc::string::String;
12use alloc::sync::Arc;
13use alloc::vec::Vec;
14use core::alloc::Layout;
15use core::num::NonZero;
16use core::sync::atomic::AtomicBool;
17use macros::bitflag;
18
19#[cfg_attr(target_arch = "aarch64", path = "aarch64.rs")]
20#[cfg_attr(target_arch = "x86_64", path = "x86_64.rs")]
21mod arch;
22mod bucket;
23mod keg;
24mod slab;
25mod zone;
26
27pub struct Uma {
29 vm: &'static Vm,
30 bucket_enable: Arc<AtomicBool>,
31 bucket_keys: Arc<Vec<usize>>, bucket_zones: Arc<Vec<UmaZone>>, }
34
35impl Uma {
36 const SMALLEST_UNIT: NonZero<usize> = NonZero::new(PAGE_SIZE.get() / 256).unwrap();
38
39 const MAX_WASTE: NonZero<usize> = NonZero::new(PAGE_SIZE.get() / 10).unwrap();
41 const BUCKET_MAX: usize = 128;
42 const BUCKET_SHIFT: usize = 4;
43
44 const BUCKET_SIZES: [usize; 4] = [16, 32, 64, 128];
46
47 pub fn new(vm: &'static Vm) -> Arc<Self> {
54 let bucket_enable = Arc::new(AtomicBool::new(true)); let mut bucket_keys = Vec::new();
56 let mut bucket_zones = Vec::with_capacity(Self::BUCKET_SIZES.len());
57 let mut ki = 0;
58
59 for (si, size) in Self::BUCKET_SIZES.into_iter().enumerate() {
61 let items = Layout::array::<*mut u8>(size).unwrap();
62 let layout = Layout::new::<BucketHdr>()
63 .extend(items)
64 .unwrap()
65 .0
66 .pad_to_align();
67
68 bucket_zones.push(UmaZone::new(
69 vm,
70 bucket_enable.clone(),
71 Arc::default(),
72 Arc::default(),
73 ZoneArgs {
74 name: format!("{size} Bucket"),
75 keg: None,
76 size: layout.size().try_into().unwrap(),
77 align: Some(layout.align() - 1),
78 init: None,
79 ctor: None,
80 dtor: None,
81 flags: UmaFlags::Bucket | UmaFlags::Internal,
82 },
83 ));
84
85 while ki <= size {
86 bucket_keys.push(si);
87 ki += 1 << Self::BUCKET_SHIFT;
88 }
89 }
90
91 Arc::new(Self {
92 vm,
93 bucket_enable,
94 bucket_keys: Arc::new(bucket_keys),
95 bucket_zones: Arc::new(bucket_zones),
96 })
97 }
98
99 #[allow(clippy::too_many_arguments)] pub fn create_zone(
107 &self,
108 name: impl Into<String>,
109 size: NonZero<usize>,
110 align: Option<usize>,
111 init: Option<fn()>,
112 ctor: Option<fn(*mut u8, NonZero<usize>, Alloc) -> bool>,
113 dtor: Option<fn()>,
114 flags: impl Into<UmaFlags>,
115 ) -> UmaZone {
116 UmaZone::new(
119 self.vm,
120 self.bucket_enable.clone(),
121 self.bucket_keys.clone(),
122 self.bucket_zones.clone(),
123 ZoneArgs {
124 name: name.into(),
125 keg: None,
126 size,
127 align,
128 init,
129 ctor,
130 dtor,
131 flags: flags.into(),
132 },
133 )
134 }
135}
136
137#[bitflag(u32)]
139pub enum UmaFlags {
140 ZInit = 0x2,
142 Offpage = 0x8,
144 Malloc = 0x10,
146 MtxClass = 0x40,
148 Vm = 0x80,
150 Hash = 0x100,
152 Secondary = 0x200,
154 MaxBucket = 0x800,
156 CacheSpread = 0x1000,
158 VToSlab = 0x2000,
160 Bucket = 0x2000000,
162 Internal = 0x20000000,
164 Full = 0x40000000,
166 CacheOnly = 0x80000000,
168}
169
170#[bitflag(u32)]
172pub enum Alloc {
173 NoWait = 0x1,
175 Wait = 0x2,
177 Zero = 0x100,
179 NoVm = 0x200,
181}