blob: f5e6ab81d429c88d04a8d96d1cd9917844f870c9 [file] [log] [blame]
Imre Kis703482d2023-11-30 15:51:26 +01001// SPDX-FileCopyrightText: Copyright 2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Module for handling physical and virtual memory regions
5//!
6//! A region is a continuous memory area in the given memory space.
7
8use alloc::vec::Vec;
9use log::debug;
10
11use super::{
12 page_pool::{PagePool, Pages},
13 region_pool::Region,
14};
15
16/// Physical region
17///
18/// A physical memory region can be in three different state
19/// * Unused
20/// * Points to a page pool allocated address
21/// * Points to a physical address without allocation
22pub enum PhysicalRegion {
23 Unused,
24 Allocated(PagePool, Pages),
25 PhysicalAddress(usize),
26}
27
28impl PhysicalRegion {
29 /// Get physical memory address
30 fn get_pa(&self) -> usize {
31 match self {
32 PhysicalRegion::Unused => panic!("Unused area has no PA"),
33 PhysicalRegion::Allocated(_page_pool, pages) => pages.get_pa(),
34 PhysicalRegion::PhysicalAddress(pa) => *pa,
35 }
36 }
37}
38
39/// Virtual region
40///
41/// A virtual memory region has a virtual address, a length and a physical region.
42pub struct VirtualRegion {
43 va: usize,
44 length: usize,
45 physical_region: PhysicalRegion,
46}
47
48impl VirtualRegion {
49 /// Create new virtual memory region without a physical region
50 pub fn new(va: usize, length: usize) -> Self {
51 Self::new_from_fields(va, length, PhysicalRegion::Unused)
52 }
53
54 /// Create virtual region with points to a given physical address
55 pub fn new_with_pa(pa: usize, va: usize, length: usize) -> Self {
56 Self::new_from_fields(va, length, PhysicalRegion::PhysicalAddress(pa))
57 }
58
59 /// Create virtual region by defining all the fields of the object
60 fn new_from_fields(va: usize, length: usize, physical_region: PhysicalRegion) -> Self {
61 Self {
62 va,
63 length,
64 physical_region,
65 }
66 }
67
68 /// Get the base address of the linked physical region
69 pub fn get_pa(&self) -> usize {
70 self.physical_region.get_pa()
71 }
72
73 /// Get physical address for a virtual address
74 pub fn get_pa_for_va(&self, va: usize) -> usize {
75 let offset = va.checked_sub(self.va).unwrap();
76
77 assert!(offset < self.length);
78 self.get_pa().checked_add(offset).unwrap()
79 }
80}
81
82impl Region for VirtualRegion {
83 type Resource = PhysicalRegion;
84
85 fn base(&self) -> usize {
86 self.va
87 }
88
89 fn length(&self) -> usize {
90 self.length
91 }
92
93 fn used(&self) -> bool {
94 !matches!(self.physical_region, PhysicalRegion::Unused)
95 }
96
97 fn contains(&self, base: usize, length: usize) -> bool {
98 if let (Some(end), Some(self_end)) =
99 (base.checked_add(length), self.va.checked_add(self.length))
100 {
101 self.va <= base && end <= self_end
102 } else {
103 false
104 }
105 }
106
107 fn try_append(&mut self, other: &Self) -> bool {
108 if let (Some(self_end), Some(new_length)) = (
109 self.va.checked_add(self.length),
110 self.length.checked_add(other.length),
111 ) {
112 if self_end == other.va {
113 // VA is consecutive
114 match (&self.physical_region, &other.physical_region) {
115 (PhysicalRegion::Unused, PhysicalRegion::Unused) => {
116 // Unused range can be merged without further conditions
117 self.length = new_length;
118 return true;
119 }
120 (
121 PhysicalRegion::PhysicalAddress(self_pa),
122 PhysicalRegion::PhysicalAddress(other_pa),
123 ) => {
124 // Used ranges can be only merged if the PA doesn't overflow and it is
125 // consecutive
126 if let Some(self_end_pa) = self_pa.checked_add(self.length) {
127 if self_end_pa == *other_pa {
128 self.length = new_length;
129 return true;
130 }
131 }
132 }
133
134 // PhyisicalRegion::Allocated instances cannot be merged at the moment. Not sure
135 // if it's a valid use case. If needed the pages has to be merged which might
136 // require tricks to invalidate the pages of 'other'.
137 _ => {}
138 }
139 }
140 }
141
142 false
143 }
144
145 fn create_split(
146 &self,
147 base: usize,
148 length: usize,
149 resource: Option<Self::Resource>,
150 ) -> (Self, Vec<Self>) {
151 assert!(self.contains(base, length));
152 assert!(self.used() != resource.is_some());
153
154 if let Some(physical_region) = resource {
155 // Self is unused, setting part of it to used
156 let pa = physical_region.get_pa();
157
158 let mut res = Vec::new();
159 if self.va != base {
160 res.push(Self::new(self.va, base.checked_sub(self.va).unwrap()));
161 }
162
163 res.push(Self::new_from_fields(base, length, physical_region));
164
165 let end = base.checked_add(length).unwrap();
166 let self_end = self.va.checked_add(self.length).unwrap();
167 if end != self_end {
168 res.push(Self::new(end, self_end.checked_sub(end).unwrap()));
169 }
170
171 (
172 Self::new_from_fields(base, length, PhysicalRegion::PhysicalAddress(pa)),
173 res,
174 )
175 } else {
176 // Self is used, mark part of it unused
177 let mut res = Vec::new();
178 if self.va != base {
179 let physical_region = match &self.physical_region {
180 PhysicalRegion::Allocated(_page_pool, _pages) => {
181 todo!("Implement Pages::split");
182 }
183 PhysicalRegion::PhysicalAddress(pa) => PhysicalRegion::PhysicalAddress(*pa),
184 _ => {
185 panic!("Splitting unused region by other unused")
186 }
187 };
188
189 res.push(Self::new_from_fields(
190 self.va,
191 base.checked_sub(self.va).unwrap(),
192 physical_region,
193 ));
194 }
195
196 res.push(Self::new(base, length));
197
198 let end = base.checked_add(length).unwrap();
199 let self_end = self.va.checked_add(self.length).unwrap();
200 if end != self_end {
201 let physical_region = match &self.physical_region {
202 PhysicalRegion::Allocated(_page_pool, _pages) => {
203 todo!("Implement Pages::split");
204 }
205 PhysicalRegion::PhysicalAddress(pa) => {
206 let offset = end.checked_sub(self.va).unwrap();
207 PhysicalRegion::PhysicalAddress(pa.checked_add(offset).unwrap())
208 }
209 _ => {
210 panic!("Splitting unused region by other unused")
211 }
212 };
213
214 res.push(Self::new_from_fields(
215 end,
216 self_end.checked_sub(end).unwrap(),
217 physical_region,
218 ));
219 }
220
221 (Self::new(base, length), res)
222 }
223 }
224}
225
226impl Drop for VirtualRegion {
227 /// If the virtual region has a linked physical region which was allocated then release the
228 /// allocated pages.
229 fn drop(&mut self) {
230 let mut physical_region = PhysicalRegion::Unused;
231
232 core::mem::swap(&mut self.physical_region, &mut physical_region);
233
234 if let PhysicalRegion::Allocated(page_pool, pages) = physical_region {
235 debug!(
236 "Dropping physical region with pages: PA={:#010x} VA={:#010x}",
237 pages.get_pa(),
238 self.base(),
239 );
240
241 page_pool.release_pages(pages).unwrap();
242 }
243 }
244}
245
246#[cfg(test)]
Imre Kis42935a22024-10-17 11:30:16 +0200247mod tests {
248 use super::super::page_pool::PagePoolArea;
249 use super::*;
Imre Kis703482d2023-11-30 15:51:26 +0100250
Imre Kis42935a22024-10-17 11:30:16 +0200251 #[test]
252 #[should_panic]
253 fn test_physical_region_unused() {
254 let region = PhysicalRegion::Unused;
255 region.get_pa();
256 }
Imre Kis703482d2023-11-30 15:51:26 +0100257
Imre Kis42935a22024-10-17 11:30:16 +0200258 #[test]
259 fn test_physical_region() {
260 const PA: usize = 0x0123_4567_89ab_cdef;
261 const LENGTH: usize = 0x8000_0000_0000;
Imre Kis703482d2023-11-30 15:51:26 +0100262
Imre Kis42935a22024-10-17 11:30:16 +0200263 static PAGE_POOL_AREA: PagePoolArea<16> = PagePoolArea::new();
264 let region =
265 PhysicalRegion::Allocated(PagePool::new(&PAGE_POOL_AREA), Pages::new(PA, LENGTH, true));
266 assert_eq!(PA, region.get_pa());
Imre Kis703482d2023-11-30 15:51:26 +0100267
Imre Kis42935a22024-10-17 11:30:16 +0200268 let region = PhysicalRegion::PhysicalAddress(PA);
269 assert_eq!(PA, region.get_pa());
270 }
Imre Kis703482d2023-11-30 15:51:26 +0100271
Imre Kis42935a22024-10-17 11:30:16 +0200272 #[test]
273 fn test_virtual_region() {
274 const VA: usize = 0x0123_4567_89ab_cdef;
275 const PA: usize = 0xfedc_ba98_7654_3210;
276 const LENGTH: usize = 0x8000_0000_0000;
Imre Kis703482d2023-11-30 15:51:26 +0100277
Imre Kis42935a22024-10-17 11:30:16 +0200278 let region = VirtualRegion::new(VA, LENGTH);
279 assert_eq!(VA, region.va);
280 assert_eq!(VA, region.base());
281 assert_eq!(LENGTH, region.length);
282 assert_eq!(LENGTH, region.length());
283 assert!(matches!(region.physical_region, PhysicalRegion::Unused));
284 assert!(!region.used());
Imre Kis703482d2023-11-30 15:51:26 +0100285
Imre Kis42935a22024-10-17 11:30:16 +0200286 let region = VirtualRegion::new_with_pa(PA, VA, LENGTH);
287 assert_eq!(VA, region.va);
288 assert_eq!(VA, region.base());
289 assert_eq!(LENGTH, region.length);
290 assert_eq!(LENGTH, region.length());
291 assert!(matches!(
292 region.physical_region,
293 PhysicalRegion::PhysicalAddress(_)
294 ));
295 assert_eq!(PA, region.get_pa());
296 assert!(region.used());
297 }
Imre Kis703482d2023-11-30 15:51:26 +0100298
Imre Kis42935a22024-10-17 11:30:16 +0200299 #[test]
300 fn test_virtual_region_get_pa_for_va() {
301 let region =
302 VirtualRegion::new_with_pa(0x8000_0000_0000_0000, 0x4000_0000_0000_0000, 0x1000);
303 assert_eq!(
304 0x8000_0000_0000_0000,
305 region.get_pa_for_va(0x4000_0000_0000_0000)
306 );
307 assert_eq!(
308 0x8000_0000_0000_0001,
309 region.get_pa_for_va(0x4000_0000_0000_0001)
310 );
311 assert_eq!(
312 0x8000_0000_0000_0fff,
313 region.get_pa_for_va(0x4000_0000_0000_0fff)
314 );
315 }
Imre Kis703482d2023-11-30 15:51:26 +0100316
Imre Kis42935a22024-10-17 11:30:16 +0200317 #[test]
318 #[should_panic]
319 fn test_virtual_region_get_pa_for_va_low_va() {
320 let region =
321 VirtualRegion::new_with_pa(0x8000_0000_0000_0000, 0x4000_0000_0000_0000, 0x1000);
322 region.get_pa_for_va(0x3fff_ffff_ffff_ffff);
323 }
Imre Kis703482d2023-11-30 15:51:26 +0100324
Imre Kis42935a22024-10-17 11:30:16 +0200325 #[test]
326 #[should_panic]
327 fn test_virtual_region_get_pa_for_va_high_va() {
328 let region =
329 VirtualRegion::new_with_pa(0x8000_0000_0000_0000, 0x4000_0000_0000_0000, 0x1000);
330 region.get_pa_for_va(0x4000_0000_0000_1000);
331 }
Imre Kis703482d2023-11-30 15:51:26 +0100332
Imre Kis42935a22024-10-17 11:30:16 +0200333 #[test]
334 fn test_virtual_region_contains() {
335 const VA: usize = 0x8000_0000_0000_0000;
336 const LENGTH: usize = 0x8000_0000_0000;
Imre Kis703482d2023-11-30 15:51:26 +0100337
Imre Kis42935a22024-10-17 11:30:16 +0200338 let region_overflow_end = VirtualRegion::new(0x8000_0000_0000_0000, 0x8000_0000_0000_0000);
339 assert!(!region_overflow_end.contains(0x8000_0000_0000_0000, 1));
Imre Kis703482d2023-11-30 15:51:26 +0100340
Imre Kis42935a22024-10-17 11:30:16 +0200341 let region = VirtualRegion::new(0x4000_0000_0000_0000, 0x8000_0000_0000_0000);
342 assert!(!region.contains(0x8000_0000_0000_0000, 0x8000_0000_0000_0000));
Imre Kis703482d2023-11-30 15:51:26 +0100343
Imre Kis42935a22024-10-17 11:30:16 +0200344 assert!(!region.contains(0x4000_0000_0000_0000, 0x8000_0000_0000_0001));
345 assert!(!region.contains(0x3fff_ffff_ffff_ffff, 0x8000_0000_0000_0000));
346 assert!(region.contains(0x4000_0000_0000_0000, 0x8000_0000_0000_0000));
347 assert!(region.contains(0x4000_0000_0000_0000, 0x7fff_ffff_ffff_ffff));
348 assert!(region.contains(0x4000_0000_0000_0001, 0x7fff_ffff_ffff_ffff));
349 }
Imre Kis703482d2023-11-30 15:51:26 +0100350
Imre Kis42935a22024-10-17 11:30:16 +0200351 #[test]
352 fn test_virtual_region_try_append() {
353 // Both unused
354 let mut region_unused0 = VirtualRegion::new(0x4000_0000, 0x1000);
355 let mut region_unused1 = VirtualRegion::new(0x4000_1000, 0x1000);
Imre Kis703482d2023-11-30 15:51:26 +0100356
Imre Kis42935a22024-10-17 11:30:16 +0200357 assert!(!region_unused1.try_append(&region_unused0));
358 assert_eq!(0x4000_0000, region_unused0.va);
359 assert_eq!(0x1000, region_unused0.length);
360 assert_eq!(0x4000_1000, region_unused1.va);
361 assert_eq!(0x1000, region_unused1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100362
Imre Kis42935a22024-10-17 11:30:16 +0200363 assert!(region_unused0.try_append(&region_unused1));
364 assert_eq!(0x4000_0000, region_unused0.va);
365 assert_eq!(0x2000, region_unused0.length);
366 assert_eq!(0x4000_1000, region_unused1.va);
367 assert_eq!(0x1000, region_unused1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100368
Imre Kis42935a22024-10-17 11:30:16 +0200369 // Unused and PA region
370 let mut region_unused = VirtualRegion::new(0x4000_0000, 0x1000);
371 let region_physical = VirtualRegion::new_with_pa(0x8000_0000, 0x4000_1000, 0x1000);
372 assert!(!region_unused.try_append(&region_physical));
373 assert_eq!(0x4000_0000, region_unused.va);
374 assert_eq!(0x1000, region_unused.length);
375 assert_eq!(0x4000_1000, region_physical.va);
376 assert_eq!(0x1000, region_physical.length);
Imre Kis703482d2023-11-30 15:51:26 +0100377
Imre Kis42935a22024-10-17 11:30:16 +0200378 // Both PA regions but non-consecutive PA ranges
379 let mut region_physical0 = VirtualRegion::new_with_pa(0x8000_0000, 0x4000_0000, 0x1000);
380 let region_physical1 = VirtualRegion::new_with_pa(0x9000_0000, 0x4000_1000, 0x1000);
381 assert!(!region_physical0.try_append(&region_physical1));
382 assert_eq!(0x4000_0000, region_physical0.va);
383 assert_eq!(0x1000, region_physical0.length);
384 assert_eq!(0x4000_1000, region_physical1.va);
385 assert_eq!(0x1000, region_physical1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100386
Imre Kis42935a22024-10-17 11:30:16 +0200387 // Both PA regions with consecutive PA ranges
388 let mut region_physical0 = VirtualRegion::new_with_pa(0x8000_0000, 0x4000_0000, 0x1000);
389 let region_physical1 = VirtualRegion::new_with_pa(0x8000_1000, 0x4000_1000, 0x1000);
390 assert!(region_physical0.try_append(&region_physical1));
391 assert_eq!(0x4000_0000, region_physical0.va);
392 assert_eq!(0x2000, region_physical0.length);
393 assert_eq!(0x4000_1000, region_physical1.va);
394 assert_eq!(0x1000, region_physical1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100395
Imre Kis42935a22024-10-17 11:30:16 +0200396 // VA overflow
397 let mut region_unused0 = VirtualRegion::new(0x8000_0000_0000_0000, 0x8000_0000_0000_0000);
398 let mut region_unused1 = VirtualRegion::new(0x4000_1000, 0x1000);
Imre Kis703482d2023-11-30 15:51:26 +0100399
Imre Kis42935a22024-10-17 11:30:16 +0200400 assert!(!region_unused0.try_append(&region_unused1));
401 assert_eq!(0x8000_0000_0000_0000, region_unused0.va);
402 assert_eq!(0x8000_0000_0000_0000, region_unused0.length);
403 assert_eq!(0x4000_1000, region_unused1.va);
404 assert_eq!(0x1000, region_unused1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100405
Imre Kis42935a22024-10-17 11:30:16 +0200406 assert!(!region_unused1.try_append(&region_unused0));
407 assert_eq!(0x8000_0000_0000_0000, region_unused0.va);
408 assert_eq!(0x8000_0000_0000_0000, region_unused0.length);
409 assert_eq!(0x4000_1000, region_unused1.va);
410 assert_eq!(0x1000, region_unused1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100411
Imre Kis42935a22024-10-17 11:30:16 +0200412 // PA overflow
413 let mut region_physical0 =
414 VirtualRegion::new_with_pa(0x8000_0000_0000_0000, 0x4000_0000, 0x8000_0000_0000_0000);
415 let region_physical1 =
416 VirtualRegion::new_with_pa(0x9000_0000, 0x8000_0000_4000_0000, 0x1000);
417 assert!(!region_physical0.try_append(&region_physical1));
418 assert_eq!(0x4000_0000, region_physical0.va);
419 assert_eq!(0x8000_0000_0000_0000, region_physical0.length);
420 assert_eq!(0x8000_0000_4000_0000, region_physical1.va);
421 assert_eq!(0x1000, region_physical1.length);
422 }
Imre Kis703482d2023-11-30 15:51:26 +0100423
Imre Kis42935a22024-10-17 11:30:16 +0200424 #[test]
425 fn test_virtual_region_create_split_by_used() {
426 let region_unused = VirtualRegion::new(0x4000_0000, 0x4000);
Imre Kis703482d2023-11-30 15:51:26 +0100427
Imre Kis42935a22024-10-17 11:30:16 +0200428 // New region at the start
429 let (new_region, splitted_regions) = region_unused.create_split(
430 0x4000_0000,
431 0x1000,
432 Some(PhysicalRegion::PhysicalAddress(0x8000_0000)),
433 );
Imre Kis703482d2023-11-30 15:51:26 +0100434
Imre Kis42935a22024-10-17 11:30:16 +0200435 assert_eq!(0x4000_0000, new_region.va);
436 assert_eq!(0x1000, new_region.length);
437 assert_eq!(0x8000_0000, new_region.get_pa());
438 assert!(matches!(
439 new_region.physical_region,
440 PhysicalRegion::PhysicalAddress(_)
441 ));
Imre Kis703482d2023-11-30 15:51:26 +0100442
Imre Kis42935a22024-10-17 11:30:16 +0200443 assert_eq!(0x4000_0000, splitted_regions[0].va);
444 assert_eq!(0x1000, splitted_regions[0].length);
445 assert_eq!(0x8000_0000, splitted_regions[0].get_pa());
446 assert!(matches!(
447 splitted_regions[0].physical_region,
448 PhysicalRegion::PhysicalAddress(_)
449 ));
Imre Kis703482d2023-11-30 15:51:26 +0100450
Imre Kis42935a22024-10-17 11:30:16 +0200451 assert_eq!(0x4000_1000, splitted_regions[1].va);
452 assert_eq!(0x3000, splitted_regions[1].length);
453 assert!(matches!(
454 splitted_regions[1].physical_region,
455 PhysicalRegion::Unused
456 ));
Imre Kis703482d2023-11-30 15:51:26 +0100457
Imre Kis42935a22024-10-17 11:30:16 +0200458 // New region in the middle
459 let (new_region, splitted_regions) = region_unused.create_split(
460 0x4000_1000,
461 0x1000,
462 Some(PhysicalRegion::PhysicalAddress(0x8000_0000)),
463 );
Imre Kis703482d2023-11-30 15:51:26 +0100464
Imre Kis42935a22024-10-17 11:30:16 +0200465 assert_eq!(0x4000_1000, new_region.va);
466 assert_eq!(0x1000, new_region.length);
467 assert_eq!(0x8000_0000, new_region.get_pa());
468 assert!(matches!(
469 new_region.physical_region,
470 PhysicalRegion::PhysicalAddress(_)
471 ));
Imre Kis703482d2023-11-30 15:51:26 +0100472
Imre Kis42935a22024-10-17 11:30:16 +0200473 assert_eq!(0x4000_0000, splitted_regions[0].va);
474 assert_eq!(0x1000, splitted_regions[0].length);
475 assert!(matches!(
476 splitted_regions[0].physical_region,
477 PhysicalRegion::Unused
478 ));
Imre Kis703482d2023-11-30 15:51:26 +0100479
Imre Kis42935a22024-10-17 11:30:16 +0200480 assert_eq!(0x4000_1000, splitted_regions[1].va);
481 assert_eq!(0x1000, splitted_regions[1].length);
482 assert_eq!(0x8000_0000, splitted_regions[1].get_pa());
483 assert!(matches!(
484 splitted_regions[1].physical_region,
485 PhysicalRegion::PhysicalAddress(_)
486 ));
Imre Kis703482d2023-11-30 15:51:26 +0100487
Imre Kis42935a22024-10-17 11:30:16 +0200488 assert_eq!(0x4000_2000, splitted_regions[2].va);
489 assert_eq!(0x2000, splitted_regions[2].length);
490 assert!(matches!(
491 splitted_regions[2].physical_region,
492 PhysicalRegion::Unused
493 ));
Imre Kis703482d2023-11-30 15:51:26 +0100494
Imre Kis42935a22024-10-17 11:30:16 +0200495 // New region at the end
496 let (new_region, splitted_regions) = region_unused.create_split(
497 0x4000_3000,
498 0x1000,
499 Some(PhysicalRegion::PhysicalAddress(0x8000_0000)),
500 );
Imre Kis703482d2023-11-30 15:51:26 +0100501
Imre Kis42935a22024-10-17 11:30:16 +0200502 assert_eq!(0x4000_3000, new_region.va);
503 assert_eq!(0x1000, new_region.length);
504 assert_eq!(0x8000_0000, new_region.get_pa());
505 assert!(matches!(
506 new_region.physical_region,
507 PhysicalRegion::PhysicalAddress(_)
508 ));
Imre Kis703482d2023-11-30 15:51:26 +0100509
Imre Kis42935a22024-10-17 11:30:16 +0200510 assert_eq!(0x4000_0000, splitted_regions[0].va);
511 assert_eq!(0x3000, splitted_regions[0].length);
512 assert!(matches!(
513 splitted_regions[0].physical_region,
514 PhysicalRegion::Unused
515 ));
Imre Kis703482d2023-11-30 15:51:26 +0100516
Imre Kis42935a22024-10-17 11:30:16 +0200517 assert_eq!(0x4000_3000, splitted_regions[1].va);
518 assert_eq!(0x1000, splitted_regions[1].length);
519 assert_eq!(0x8000_0000, splitted_regions[1].get_pa());
520 assert!(matches!(
521 splitted_regions[1].physical_region,
522 PhysicalRegion::PhysicalAddress(_)
523 ));
524 }
Imre Kis703482d2023-11-30 15:51:26 +0100525
Imre Kis42935a22024-10-17 11:30:16 +0200526 #[test]
527 fn test_virtual_region_create_split_by_unused() {
528 let region_unused = VirtualRegion::new_with_pa(0x8000_0000, 0x4000_0000, 0x4000);
Imre Kis703482d2023-11-30 15:51:26 +0100529
Imre Kis42935a22024-10-17 11:30:16 +0200530 // New region at the start
531 let (new_region, splitted_regions) = region_unused.create_split(0x4000_0000, 0x1000, None);
Imre Kis703482d2023-11-30 15:51:26 +0100532
Imre Kis42935a22024-10-17 11:30:16 +0200533 assert_eq!(0x4000_0000, new_region.va);
534 assert_eq!(0x1000, new_region.length);
535 assert!(matches!(new_region.physical_region, PhysicalRegion::Unused));
Imre Kis703482d2023-11-30 15:51:26 +0100536
Imre Kis42935a22024-10-17 11:30:16 +0200537 assert_eq!(0x4000_0000, splitted_regions[0].va);
538 assert_eq!(0x1000, splitted_regions[0].length);
539 assert!(matches!(
540 splitted_regions[0].physical_region,
541 PhysicalRegion::Unused
542 ));
Imre Kis703482d2023-11-30 15:51:26 +0100543
Imre Kis42935a22024-10-17 11:30:16 +0200544 assert_eq!(0x4000_1000, splitted_regions[1].va);
545 assert_eq!(0x3000, splitted_regions[1].length);
546 assert_eq!(0x8000_1000, splitted_regions[1].get_pa());
547 assert!(matches!(
548 splitted_regions[1].physical_region,
549 PhysicalRegion::PhysicalAddress(_)
550 ));
Imre Kis703482d2023-11-30 15:51:26 +0100551
Imre Kis42935a22024-10-17 11:30:16 +0200552 // New region in the middle
553 let (new_region, splitted_regions) = region_unused.create_split(0x4000_1000, 0x1000, None);
Imre Kis703482d2023-11-30 15:51:26 +0100554
Imre Kis42935a22024-10-17 11:30:16 +0200555 assert_eq!(0x4000_1000, new_region.va);
556 assert_eq!(0x1000, new_region.length);
557 assert!(matches!(new_region.physical_region, PhysicalRegion::Unused));
Imre Kis703482d2023-11-30 15:51:26 +0100558
Imre Kis42935a22024-10-17 11:30:16 +0200559 assert_eq!(0x4000_0000, splitted_regions[0].va);
560 assert_eq!(0x1000, splitted_regions[0].length);
561 assert_eq!(0x8000_0000, splitted_regions[0].get_pa());
562 assert!(matches!(
563 splitted_regions[0].physical_region,
564 PhysicalRegion::PhysicalAddress(_)
565 ));
Imre Kis703482d2023-11-30 15:51:26 +0100566
Imre Kis42935a22024-10-17 11:30:16 +0200567 assert_eq!(0x4000_1000, splitted_regions[1].va);
568 assert_eq!(0x1000, splitted_regions[1].length);
569 assert!(matches!(
570 splitted_regions[1].physical_region,
571 PhysicalRegion::Unused
572 ));
Imre Kis703482d2023-11-30 15:51:26 +0100573
Imre Kis42935a22024-10-17 11:30:16 +0200574 assert_eq!(0x4000_2000, splitted_regions[2].va);
575 assert_eq!(0x2000, splitted_regions[2].length);
576 assert_eq!(0x8000_2000, splitted_regions[2].get_pa());
577 assert!(matches!(
578 splitted_regions[2].physical_region,
579 PhysicalRegion::PhysicalAddress(_)
580 ));
Imre Kis703482d2023-11-30 15:51:26 +0100581
Imre Kis42935a22024-10-17 11:30:16 +0200582 // New region at the end
583 let (new_region, splitted_regions) = region_unused.create_split(0x4000_3000, 0x1000, None);
Imre Kis703482d2023-11-30 15:51:26 +0100584
Imre Kis42935a22024-10-17 11:30:16 +0200585 assert_eq!(0x4000_3000, new_region.va);
586 assert_eq!(0x1000, new_region.length);
587 assert!(matches!(new_region.physical_region, PhysicalRegion::Unused));
Imre Kis703482d2023-11-30 15:51:26 +0100588
Imre Kis42935a22024-10-17 11:30:16 +0200589 assert_eq!(0x4000_0000, splitted_regions[0].va);
590 assert_eq!(0x3000, splitted_regions[0].length);
591 assert_eq!(0x8000_0000, splitted_regions[0].get_pa());
592 assert!(matches!(
593 splitted_regions[0].physical_region,
594 PhysicalRegion::PhysicalAddress(_)
595 ));
Imre Kis703482d2023-11-30 15:51:26 +0100596
Imre Kis42935a22024-10-17 11:30:16 +0200597 assert_eq!(0x4000_3000, splitted_regions[1].va);
598 assert_eq!(0x1000, splitted_regions[1].length);
Imre Kis703482d2023-11-30 15:51:26 +0100599
Imre Kis42935a22024-10-17 11:30:16 +0200600 assert!(matches!(
601 splitted_regions[1].physical_region,
602 PhysicalRegion::Unused
603 ));
604 }
Imre Kis703482d2023-11-30 15:51:26 +0100605
Imre Kis42935a22024-10-17 11:30:16 +0200606 #[test]
607 #[should_panic]
608 fn test_virtual_region_does_not_contain() {
609 let region = VirtualRegion::new(0x4000_0000, 0x1000);
610 region.create_split(
611 0x8000_0000,
612 0x1000,
613 Some(PhysicalRegion::PhysicalAddress(0xc000_0000)),
614 );
615 }
Imre Kis703482d2023-11-30 15:51:26 +0100616
Imre Kis42935a22024-10-17 11:30:16 +0200617 #[test]
618 #[should_panic]
619 fn test_virtual_region_create_split_same_used() {
620 let region = VirtualRegion::new(0x4000_0000, 0x1000);
621 region.create_split(0x4000_0000, 0x1000, Some(PhysicalRegion::Unused));
622 }
Imre Kis703482d2023-11-30 15:51:26 +0100623
Imre Kis42935a22024-10-17 11:30:16 +0200624 #[test]
625 fn test_virtual_region_drop() {
626 const PA: usize = 0x0123_4567_89ab_cdef;
627 const LENGTH: usize = 0x8000_0000_0000;
Imre Kis703482d2023-11-30 15:51:26 +0100628
Imre Kis42935a22024-10-17 11:30:16 +0200629 static PAGE_POOL_AREA: PagePoolArea<8192> = PagePoolArea::new();
630 let page_pool = PagePool::new(&PAGE_POOL_AREA);
631 let page = page_pool.allocate_pages(4096).unwrap();
Imre Kis703482d2023-11-30 15:51:26 +0100632
Imre Kis42935a22024-10-17 11:30:16 +0200633 let physical_region = PhysicalRegion::Allocated(page_pool, page);
Imre Kis703482d2023-11-30 15:51:26 +0100634
Imre Kis42935a22024-10-17 11:30:16 +0200635 // Testing physical region drop through virtualregion
636 let virtual_region = VirtualRegion::new_from_fields(0x4000_0000, 1000, physical_region);
637 drop(virtual_region);
638 }
Imre Kis703482d2023-11-30 15:51:26 +0100639}