1use core::ops::Deref;
6
7use align_ext::AlignExt;
8
9use crate::mm::{PAGE_SIZE, Paddr, Vaddr, kspace::kernel_loaded_offset};
10
11#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
13pub enum MemoryRegionType {
14 BadMemory = 0,
16 Unknown = 1,
19 NonVolatileSleep = 2,
21 Reserved = 3,
23 Kernel = 4,
25 Module = 5,
27 Framebuffer = 6,
29 Reclaimable = 7,
31 Usable = 8,
33}
34
35impl MemoryRegionType {
36 pub fn is_physical(self) -> bool {
42 !matches!(
44 self,
45 Self::BadMemory | Self::Unknown | Self::Reserved | Self::Framebuffer
46 )
47 }
48}
49
50#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
54pub struct MemoryRegion {
55 base: usize,
56 len: usize,
57 typ: MemoryRegionType,
58}
59
60impl MemoryRegion {
61 pub const fn new(base: Paddr, len: usize, typ: MemoryRegionType) -> Self {
63 MemoryRegion { base, len, typ }
64 }
65
66 pub const fn bad() -> Self {
68 MemoryRegion {
69 base: 0,
70 len: 0,
71 typ: MemoryRegionType::BadMemory,
72 }
73 }
74
75 pub fn kernel() -> Self {
80 unsafe extern "C" {
82 fn __kernel_start();
83 fn __kernel_end();
84 }
85 MemoryRegion {
86 base: __kernel_start as *const () as usize - kernel_loaded_offset(),
87 len: __kernel_end as *const () as usize - __kernel_start as *const () as usize,
88 typ: MemoryRegionType::Kernel,
89 }
90 }
91
92 pub fn framebuffer(fb: &crate::boot::BootloaderFramebufferArg) -> Self {
94 Self {
95 base: fb.address,
96 len: (fb.width * fb.height * fb.bpp).div_ceil(8), typ: MemoryRegionType::Framebuffer,
98 }
99 }
100
101 pub fn module(bytes: &[u8]) -> Self {
107 let vaddr = bytes.as_ptr() as Vaddr;
108 assert!(crate::mm::kspace::LINEAR_MAPPING_VADDR_RANGE.contains(&vaddr));
109
110 Self {
111 base: vaddr - crate::mm::kspace::LINEAR_MAPPING_BASE_VADDR,
112 len: bytes.len(),
113 typ: MemoryRegionType::Reclaimable,
114 }
115 }
116
117 pub fn base(&self) -> Paddr {
119 self.base
120 }
121
122 pub fn len(&self) -> usize {
124 self.len
125 }
126
127 pub fn end(&self) -> Paddr {
129 self.base + self.len
130 }
131
132 pub fn is_empty(&self) -> bool {
134 self.len == 0
135 }
136
137 pub fn typ(&self) -> MemoryRegionType {
139 self.typ
140 }
141
142 fn as_aligned(&self) -> Self {
143 let (base, len) = match self.typ() {
144 MemoryRegionType::Usable => {
145 let aligned_base = self.base().align_up(PAGE_SIZE);
146 let aligned_end = self.end().align_down(PAGE_SIZE);
147 (aligned_base, aligned_end.saturating_sub(aligned_base))
148 }
149 _ => {
150 let aligned_base = self.base().align_down(PAGE_SIZE);
151 let aligned_end = self.end().align_up(PAGE_SIZE);
152 (aligned_base, aligned_end - aligned_base)
153 }
154 };
155 MemoryRegion {
156 base,
157 len,
158 typ: self.typ,
159 }
160 }
161}
162
163const MAX_REGIONS: usize = 512;
170
171pub(crate) struct MemoryRegionArray<const LEN: usize = MAX_REGIONS> {
175 regions: [MemoryRegion; LEN],
176 count: usize,
177}
178
179impl<const LEN: usize> Default for MemoryRegionArray<LEN> {
180 fn default() -> Self {
181 Self::new()
182 }
183}
184
185impl<const LEN: usize> Deref for MemoryRegionArray<LEN> {
186 type Target = [MemoryRegion];
187
188 fn deref(&self) -> &Self::Target {
189 &self.regions[..self.count]
190 }
191}
192
193#[derive(Debug)]
195pub(crate) struct ArrayFullError;
196
197impl<const LEN: usize> MemoryRegionArray<LEN> {
198 pub(crate) const fn new() -> Self {
200 Self {
201 regions: [MemoryRegion::bad(); LEN],
202 count: 0,
203 }
204 }
205
206 pub(crate) fn push(&mut self, region: MemoryRegion) -> Result<(), ArrayFullError> {
210 if self.count >= self.regions.len() {
211 return Err(ArrayFullError);
212 }
213
214 self.regions[self.count] = region;
215 self.count += 1;
216
217 Ok(())
218 }
219
220 pub(crate) fn into_non_overlapping(mut self) -> Self {
236 let mut count = 0;
238 for i in 0..self.count {
239 let region = self.regions[i].as_aligned();
240 if !region.is_empty() {
241 self.regions[count] = region;
242 count += 1;
243 }
244 }
245 self.count = count;
246
247 let max_addr = self.iter().map(|r| r.end()).max().unwrap_or(0);
248
249 let mut result = MemoryRegionArray::<LEN>::new();
250
251 let mut cur_right = 0;
252
253 while cur_right < max_addr {
254 let typ = self
256 .iter()
257 .filter(|region| (region.base()..region.end()).contains(&cur_right))
258 .map(|region| region.typ())
259 .min()
260 .unwrap_or(MemoryRegionType::Unknown);
261
262 let right = self
264 .iter()
265 .filter_map(|region| {
266 if region.base() > cur_right {
267 Some(region.base())
268 } else if region.end() > cur_right {
269 Some(region.end())
270 } else {
271 None
272 }
273 })
274 .min()
275 .unwrap();
276
277 result
278 .push(MemoryRegion::new(cur_right, right - cur_right, typ))
279 .unwrap();
280
281 cur_right = right;
282 }
283
284 if result.is_empty() {
285 return result;
286 }
287
288 let mut merged_count = 1;
290 for i in 1..result.count {
291 if result[i].typ() == result.regions[merged_count - 1].typ() {
292 result.regions[merged_count - 1] = MemoryRegion::new(
293 result.regions[merged_count - 1].base(),
294 result.regions[merged_count - 1].len() + result[i].len(),
295 result.regions[merged_count - 1].typ(),
296 );
297 } else {
298 result.regions[merged_count] = result[i];
299 merged_count += 1;
300 }
301 }
302 result.count = merged_count;
303
304 result
305 }
306}
307
308#[cfg(ktest)]
309mod test {
310 use super::*;
311 use crate::prelude::ktest;
312
313 #[ktest]
314 fn sort_full_non_overlapping() {
315 let mut regions = MemoryRegionArray::<64>::new();
316 regions
318 .push(MemoryRegion::new(
319 0,
320 PAGE_SIZE + 1,
321 MemoryRegionType::Usable,
322 ))
323 .unwrap();
324 regions
325 .push(MemoryRegion::new(
326 PAGE_SIZE - 1,
327 PAGE_SIZE + 2,
328 MemoryRegionType::Usable,
329 ))
330 .unwrap();
331 regions
332 .push(MemoryRegion::new(
333 PAGE_SIZE * 2,
334 PAGE_SIZE * 5,
335 MemoryRegionType::Usable,
336 ))
337 .unwrap();
338 regions
340 .push(MemoryRegion::new(
341 PAGE_SIZE * 3 + 1,
342 PAGE_SIZE - 2,
343 MemoryRegionType::BadMemory,
344 ))
345 .unwrap();
346 regions
348 .push(MemoryRegion::new(
349 PAGE_SIZE * 9,
350 PAGE_SIZE * 2,
351 MemoryRegionType::Usable,
352 ))
353 .unwrap();
354
355 let regions = regions.into_non_overlapping();
356
357 assert_eq!(regions.count, 5);
358 assert_eq!(regions[0].base(), 0);
359 assert_eq!(regions[0].len(), PAGE_SIZE * 3);
360 assert_eq!(regions[0].typ(), MemoryRegionType::Usable);
361
362 assert_eq!(regions[1].base(), PAGE_SIZE * 3);
363 assert_eq!(regions[1].len(), PAGE_SIZE);
364 assert_eq!(regions[1].typ(), MemoryRegionType::BadMemory);
365
366 assert_eq!(regions[2].base(), PAGE_SIZE * 4);
367 assert_eq!(regions[2].len(), PAGE_SIZE * 3);
368 assert_eq!(regions[2].typ(), MemoryRegionType::Usable);
369
370 assert_eq!(regions[3].base(), PAGE_SIZE * 7);
371 assert_eq!(regions[3].len(), PAGE_SIZE * 2);
372 assert_eq!(regions[3].typ(), MemoryRegionType::Unknown);
373
374 assert_eq!(regions[4].base(), PAGE_SIZE * 9);
375 assert_eq!(regions[4].len(), PAGE_SIZE * 2);
376 assert_eq!(regions[4].typ(), MemoryRegionType::Usable);
377 }
378
379 #[ktest]
380 fn into_non_overlapping_drops_usable_subpage_regions() {
381 let mut regions = MemoryRegionArray::<64>::new();
382 let bases = [
383 100 * PAGE_SIZE, 100 * PAGE_SIZE + 123, ];
386 let subpage_lens = [0, PAGE_SIZE / 2, PAGE_SIZE - 1];
387 for base in bases {
388 for len in subpage_lens {
389 regions
390 .push(MemoryRegion::new(base, len, MemoryRegionType::Usable))
391 .unwrap();
392 }
393 }
394 let regions = regions.into_non_overlapping();
396 assert!(regions.is_empty());
397 }
398}