blob: 34428a21585538e36d86db1671aab0c46c5daaff [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;
Imre Kis589aa052024-09-10 20:19:47 +020084 type Base = usize;
85 type Length = usize;
Imre Kis703482d2023-11-30 15:51:26 +010086
87 fn base(&self) -> usize {
88 self.va
89 }
90
91 fn length(&self) -> usize {
92 self.length
93 }
94
95 fn used(&self) -> bool {
96 !matches!(self.physical_region, PhysicalRegion::Unused)
97 }
98
99 fn contains(&self, base: usize, length: usize) -> bool {
100 if let (Some(end), Some(self_end)) =
101 (base.checked_add(length), self.va.checked_add(self.length))
102 {
103 self.va <= base && end <= self_end
104 } else {
105 false
106 }
107 }
108
109 fn try_append(&mut self, other: &Self) -> bool {
110 if let (Some(self_end), Some(new_length)) = (
111 self.va.checked_add(self.length),
112 self.length.checked_add(other.length),
113 ) {
114 if self_end == other.va {
115 // VA is consecutive
116 match (&self.physical_region, &other.physical_region) {
117 (PhysicalRegion::Unused, PhysicalRegion::Unused) => {
118 // Unused range can be merged without further conditions
119 self.length = new_length;
120 return true;
121 }
122 (
123 PhysicalRegion::PhysicalAddress(self_pa),
124 PhysicalRegion::PhysicalAddress(other_pa),
125 ) => {
126 // Used ranges can be only merged if the PA doesn't overflow and it is
127 // consecutive
128 if let Some(self_end_pa) = self_pa.checked_add(self.length) {
129 if self_end_pa == *other_pa {
130 self.length = new_length;
131 return true;
132 }
133 }
134 }
135
136 // PhyisicalRegion::Allocated instances cannot be merged at the moment. Not sure
137 // if it's a valid use case. If needed the pages has to be merged which might
138 // require tricks to invalidate the pages of 'other'.
139 _ => {}
140 }
141 }
142 }
143
144 false
145 }
146
147 fn create_split(
148 &self,
149 base: usize,
150 length: usize,
151 resource: Option<Self::Resource>,
152 ) -> (Self, Vec<Self>) {
153 assert!(self.contains(base, length));
154 assert!(self.used() != resource.is_some());
155
156 if let Some(physical_region) = resource {
157 // Self is unused, setting part of it to used
158 let pa = physical_region.get_pa();
159
160 let mut res = Vec::new();
161 if self.va != base {
162 res.push(Self::new(self.va, base.checked_sub(self.va).unwrap()));
163 }
164
165 res.push(Self::new_from_fields(base, length, physical_region));
166
167 let end = base.checked_add(length).unwrap();
168 let self_end = self.va.checked_add(self.length).unwrap();
169 if end != self_end {
170 res.push(Self::new(end, self_end.checked_sub(end).unwrap()));
171 }
172
173 (
174 Self::new_from_fields(base, length, PhysicalRegion::PhysicalAddress(pa)),
175 res,
176 )
177 } else {
178 // Self is used, mark part of it unused
179 let mut res = Vec::new();
180 if self.va != base {
181 let physical_region = match &self.physical_region {
182 PhysicalRegion::Allocated(_page_pool, _pages) => {
183 todo!("Implement Pages::split");
184 }
185 PhysicalRegion::PhysicalAddress(pa) => PhysicalRegion::PhysicalAddress(*pa),
186 _ => {
187 panic!("Splitting unused region by other unused")
188 }
189 };
190
191 res.push(Self::new_from_fields(
192 self.va,
193 base.checked_sub(self.va).unwrap(),
194 physical_region,
195 ));
196 }
197
198 res.push(Self::new(base, length));
199
200 let end = base.checked_add(length).unwrap();
201 let self_end = self.va.checked_add(self.length).unwrap();
202 if end != self_end {
203 let physical_region = match &self.physical_region {
204 PhysicalRegion::Allocated(_page_pool, _pages) => {
205 todo!("Implement Pages::split");
206 }
207 PhysicalRegion::PhysicalAddress(pa) => {
208 let offset = end.checked_sub(self.va).unwrap();
209 PhysicalRegion::PhysicalAddress(pa.checked_add(offset).unwrap())
210 }
211 _ => {
212 panic!("Splitting unused region by other unused")
213 }
214 };
215
216 res.push(Self::new_from_fields(
217 end,
218 self_end.checked_sub(end).unwrap(),
219 physical_region,
220 ));
221 }
222
223 (Self::new(base, length), res)
224 }
225 }
226}
227
228impl Drop for VirtualRegion {
229 /// If the virtual region has a linked physical region which was allocated then release the
230 /// allocated pages.
231 fn drop(&mut self) {
232 let mut physical_region = PhysicalRegion::Unused;
233
234 core::mem::swap(&mut self.physical_region, &mut physical_region);
235
236 if let PhysicalRegion::Allocated(page_pool, pages) = physical_region {
237 debug!(
238 "Dropping physical region with pages: PA={:#010x} VA={:#010x}",
239 pages.get_pa(),
240 self.base(),
241 );
242
243 page_pool.release_pages(pages).unwrap();
244 }
245 }
246}
247
248#[cfg(test)]
Imre Kis42935a22024-10-17 11:30:16 +0200249mod tests {
250 use super::super::page_pool::PagePoolArea;
251 use super::*;
Imre Kis703482d2023-11-30 15:51:26 +0100252
Imre Kis42935a22024-10-17 11:30:16 +0200253 #[test]
254 #[should_panic]
255 fn test_physical_region_unused() {
256 let region = PhysicalRegion::Unused;
257 region.get_pa();
258 }
Imre Kis703482d2023-11-30 15:51:26 +0100259
Imre Kis42935a22024-10-17 11:30:16 +0200260 #[test]
261 fn test_physical_region() {
262 const PA: usize = 0x0123_4567_89ab_cdef;
263 const LENGTH: usize = 0x8000_0000_0000;
Imre Kis703482d2023-11-30 15:51:26 +0100264
Imre Kis42935a22024-10-17 11:30:16 +0200265 static PAGE_POOL_AREA: PagePoolArea<16> = PagePoolArea::new();
266 let region =
267 PhysicalRegion::Allocated(PagePool::new(&PAGE_POOL_AREA), Pages::new(PA, LENGTH, true));
268 assert_eq!(PA, region.get_pa());
Imre Kis703482d2023-11-30 15:51:26 +0100269
Imre Kis42935a22024-10-17 11:30:16 +0200270 let region = PhysicalRegion::PhysicalAddress(PA);
271 assert_eq!(PA, region.get_pa());
272 }
Imre Kis703482d2023-11-30 15:51:26 +0100273
Imre Kis42935a22024-10-17 11:30:16 +0200274 #[test]
275 fn test_virtual_region() {
276 const VA: usize = 0x0123_4567_89ab_cdef;
277 const PA: usize = 0xfedc_ba98_7654_3210;
278 const LENGTH: usize = 0x8000_0000_0000;
Imre Kis703482d2023-11-30 15:51:26 +0100279
Imre Kis42935a22024-10-17 11:30:16 +0200280 let region = VirtualRegion::new(VA, LENGTH);
281 assert_eq!(VA, region.va);
282 assert_eq!(VA, region.base());
283 assert_eq!(LENGTH, region.length);
284 assert_eq!(LENGTH, region.length());
285 assert!(matches!(region.physical_region, PhysicalRegion::Unused));
286 assert!(!region.used());
Imre Kis703482d2023-11-30 15:51:26 +0100287
Imre Kis42935a22024-10-17 11:30:16 +0200288 let region = VirtualRegion::new_with_pa(PA, VA, LENGTH);
289 assert_eq!(VA, region.va);
290 assert_eq!(VA, region.base());
291 assert_eq!(LENGTH, region.length);
292 assert_eq!(LENGTH, region.length());
293 assert!(matches!(
294 region.physical_region,
295 PhysicalRegion::PhysicalAddress(_)
296 ));
297 assert_eq!(PA, region.get_pa());
298 assert!(region.used());
299 }
Imre Kis703482d2023-11-30 15:51:26 +0100300
Imre Kis42935a22024-10-17 11:30:16 +0200301 #[test]
302 fn test_virtual_region_get_pa_for_va() {
303 let region =
304 VirtualRegion::new_with_pa(0x8000_0000_0000_0000, 0x4000_0000_0000_0000, 0x1000);
305 assert_eq!(
306 0x8000_0000_0000_0000,
307 region.get_pa_for_va(0x4000_0000_0000_0000)
308 );
309 assert_eq!(
310 0x8000_0000_0000_0001,
311 region.get_pa_for_va(0x4000_0000_0000_0001)
312 );
313 assert_eq!(
314 0x8000_0000_0000_0fff,
315 region.get_pa_for_va(0x4000_0000_0000_0fff)
316 );
317 }
Imre Kis703482d2023-11-30 15:51:26 +0100318
Imre Kis42935a22024-10-17 11:30:16 +0200319 #[test]
320 #[should_panic]
321 fn test_virtual_region_get_pa_for_va_low_va() {
322 let region =
323 VirtualRegion::new_with_pa(0x8000_0000_0000_0000, 0x4000_0000_0000_0000, 0x1000);
324 region.get_pa_for_va(0x3fff_ffff_ffff_ffff);
325 }
Imre Kis703482d2023-11-30 15:51:26 +0100326
Imre Kis42935a22024-10-17 11:30:16 +0200327 #[test]
328 #[should_panic]
329 fn test_virtual_region_get_pa_for_va_high_va() {
330 let region =
331 VirtualRegion::new_with_pa(0x8000_0000_0000_0000, 0x4000_0000_0000_0000, 0x1000);
332 region.get_pa_for_va(0x4000_0000_0000_1000);
333 }
Imre Kis703482d2023-11-30 15:51:26 +0100334
Imre Kis42935a22024-10-17 11:30:16 +0200335 #[test]
336 fn test_virtual_region_contains() {
337 const VA: usize = 0x8000_0000_0000_0000;
338 const LENGTH: usize = 0x8000_0000_0000;
Imre Kis703482d2023-11-30 15:51:26 +0100339
Imre Kis42935a22024-10-17 11:30:16 +0200340 let region_overflow_end = VirtualRegion::new(0x8000_0000_0000_0000, 0x8000_0000_0000_0000);
341 assert!(!region_overflow_end.contains(0x8000_0000_0000_0000, 1));
Imre Kis703482d2023-11-30 15:51:26 +0100342
Imre Kis42935a22024-10-17 11:30:16 +0200343 let region = VirtualRegion::new(0x4000_0000_0000_0000, 0x8000_0000_0000_0000);
344 assert!(!region.contains(0x8000_0000_0000_0000, 0x8000_0000_0000_0000));
Imre Kis703482d2023-11-30 15:51:26 +0100345
Imre Kis42935a22024-10-17 11:30:16 +0200346 assert!(!region.contains(0x4000_0000_0000_0000, 0x8000_0000_0000_0001));
347 assert!(!region.contains(0x3fff_ffff_ffff_ffff, 0x8000_0000_0000_0000));
348 assert!(region.contains(0x4000_0000_0000_0000, 0x8000_0000_0000_0000));
349 assert!(region.contains(0x4000_0000_0000_0000, 0x7fff_ffff_ffff_ffff));
350 assert!(region.contains(0x4000_0000_0000_0001, 0x7fff_ffff_ffff_ffff));
351 }
Imre Kis703482d2023-11-30 15:51:26 +0100352
Imre Kis42935a22024-10-17 11:30:16 +0200353 #[test]
354 fn test_virtual_region_try_append() {
355 // Both unused
356 let mut region_unused0 = VirtualRegion::new(0x4000_0000, 0x1000);
357 let mut region_unused1 = VirtualRegion::new(0x4000_1000, 0x1000);
Imre Kis703482d2023-11-30 15:51:26 +0100358
Imre Kis42935a22024-10-17 11:30:16 +0200359 assert!(!region_unused1.try_append(&region_unused0));
360 assert_eq!(0x4000_0000, region_unused0.va);
361 assert_eq!(0x1000, region_unused0.length);
362 assert_eq!(0x4000_1000, region_unused1.va);
363 assert_eq!(0x1000, region_unused1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100364
Imre Kis42935a22024-10-17 11:30:16 +0200365 assert!(region_unused0.try_append(&region_unused1));
366 assert_eq!(0x4000_0000, region_unused0.va);
367 assert_eq!(0x2000, region_unused0.length);
368 assert_eq!(0x4000_1000, region_unused1.va);
369 assert_eq!(0x1000, region_unused1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100370
Imre Kis42935a22024-10-17 11:30:16 +0200371 // Unused and PA region
372 let mut region_unused = VirtualRegion::new(0x4000_0000, 0x1000);
373 let region_physical = VirtualRegion::new_with_pa(0x8000_0000, 0x4000_1000, 0x1000);
374 assert!(!region_unused.try_append(&region_physical));
375 assert_eq!(0x4000_0000, region_unused.va);
376 assert_eq!(0x1000, region_unused.length);
377 assert_eq!(0x4000_1000, region_physical.va);
378 assert_eq!(0x1000, region_physical.length);
Imre Kis703482d2023-11-30 15:51:26 +0100379
Imre Kis42935a22024-10-17 11:30:16 +0200380 // Both PA regions but non-consecutive PA ranges
381 let mut region_physical0 = VirtualRegion::new_with_pa(0x8000_0000, 0x4000_0000, 0x1000);
382 let region_physical1 = VirtualRegion::new_with_pa(0x9000_0000, 0x4000_1000, 0x1000);
383 assert!(!region_physical0.try_append(&region_physical1));
384 assert_eq!(0x4000_0000, region_physical0.va);
385 assert_eq!(0x1000, region_physical0.length);
386 assert_eq!(0x4000_1000, region_physical1.va);
387 assert_eq!(0x1000, region_physical1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100388
Imre Kis42935a22024-10-17 11:30:16 +0200389 // Both PA regions with consecutive PA ranges
390 let mut region_physical0 = VirtualRegion::new_with_pa(0x8000_0000, 0x4000_0000, 0x1000);
391 let region_physical1 = VirtualRegion::new_with_pa(0x8000_1000, 0x4000_1000, 0x1000);
392 assert!(region_physical0.try_append(&region_physical1));
393 assert_eq!(0x4000_0000, region_physical0.va);
394 assert_eq!(0x2000, region_physical0.length);
395 assert_eq!(0x4000_1000, region_physical1.va);
396 assert_eq!(0x1000, region_physical1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100397
Imre Kis42935a22024-10-17 11:30:16 +0200398 // VA overflow
399 let mut region_unused0 = VirtualRegion::new(0x8000_0000_0000_0000, 0x8000_0000_0000_0000);
400 let mut region_unused1 = VirtualRegion::new(0x4000_1000, 0x1000);
Imre Kis703482d2023-11-30 15:51:26 +0100401
Imre Kis42935a22024-10-17 11:30:16 +0200402 assert!(!region_unused0.try_append(&region_unused1));
403 assert_eq!(0x8000_0000_0000_0000, region_unused0.va);
404 assert_eq!(0x8000_0000_0000_0000, region_unused0.length);
405 assert_eq!(0x4000_1000, region_unused1.va);
406 assert_eq!(0x1000, region_unused1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100407
Imre Kis42935a22024-10-17 11:30:16 +0200408 assert!(!region_unused1.try_append(&region_unused0));
409 assert_eq!(0x8000_0000_0000_0000, region_unused0.va);
410 assert_eq!(0x8000_0000_0000_0000, region_unused0.length);
411 assert_eq!(0x4000_1000, region_unused1.va);
412 assert_eq!(0x1000, region_unused1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100413
Imre Kis42935a22024-10-17 11:30:16 +0200414 // PA overflow
415 let mut region_physical0 =
416 VirtualRegion::new_with_pa(0x8000_0000_0000_0000, 0x4000_0000, 0x8000_0000_0000_0000);
417 let region_physical1 =
418 VirtualRegion::new_with_pa(0x9000_0000, 0x8000_0000_4000_0000, 0x1000);
419 assert!(!region_physical0.try_append(&region_physical1));
420 assert_eq!(0x4000_0000, region_physical0.va);
421 assert_eq!(0x8000_0000_0000_0000, region_physical0.length);
422 assert_eq!(0x8000_0000_4000_0000, region_physical1.va);
423 assert_eq!(0x1000, region_physical1.length);
424 }
Imre Kis703482d2023-11-30 15:51:26 +0100425
Imre Kis42935a22024-10-17 11:30:16 +0200426 #[test]
427 fn test_virtual_region_create_split_by_used() {
428 let region_unused = VirtualRegion::new(0x4000_0000, 0x4000);
Imre Kis703482d2023-11-30 15:51:26 +0100429
Imre Kis42935a22024-10-17 11:30:16 +0200430 // New region at the start
431 let (new_region, splitted_regions) = region_unused.create_split(
432 0x4000_0000,
433 0x1000,
434 Some(PhysicalRegion::PhysicalAddress(0x8000_0000)),
435 );
Imre Kis703482d2023-11-30 15:51:26 +0100436
Imre Kis42935a22024-10-17 11:30:16 +0200437 assert_eq!(0x4000_0000, new_region.va);
438 assert_eq!(0x1000, new_region.length);
439 assert_eq!(0x8000_0000, new_region.get_pa());
440 assert!(matches!(
441 new_region.physical_region,
442 PhysicalRegion::PhysicalAddress(_)
443 ));
Imre Kis703482d2023-11-30 15:51:26 +0100444
Imre Kis42935a22024-10-17 11:30:16 +0200445 assert_eq!(0x4000_0000, splitted_regions[0].va);
446 assert_eq!(0x1000, splitted_regions[0].length);
447 assert_eq!(0x8000_0000, splitted_regions[0].get_pa());
448 assert!(matches!(
449 splitted_regions[0].physical_region,
450 PhysicalRegion::PhysicalAddress(_)
451 ));
Imre Kis703482d2023-11-30 15:51:26 +0100452
Imre Kis42935a22024-10-17 11:30:16 +0200453 assert_eq!(0x4000_1000, splitted_regions[1].va);
454 assert_eq!(0x3000, splitted_regions[1].length);
455 assert!(matches!(
456 splitted_regions[1].physical_region,
457 PhysicalRegion::Unused
458 ));
Imre Kis703482d2023-11-30 15:51:26 +0100459
Imre Kis42935a22024-10-17 11:30:16 +0200460 // New region in the middle
461 let (new_region, splitted_regions) = region_unused.create_split(
462 0x4000_1000,
463 0x1000,
464 Some(PhysicalRegion::PhysicalAddress(0x8000_0000)),
465 );
Imre Kis703482d2023-11-30 15:51:26 +0100466
Imre Kis42935a22024-10-17 11:30:16 +0200467 assert_eq!(0x4000_1000, new_region.va);
468 assert_eq!(0x1000, new_region.length);
469 assert_eq!(0x8000_0000, new_region.get_pa());
470 assert!(matches!(
471 new_region.physical_region,
472 PhysicalRegion::PhysicalAddress(_)
473 ));
Imre Kis703482d2023-11-30 15:51:26 +0100474
Imre Kis42935a22024-10-17 11:30:16 +0200475 assert_eq!(0x4000_0000, splitted_regions[0].va);
476 assert_eq!(0x1000, splitted_regions[0].length);
477 assert!(matches!(
478 splitted_regions[0].physical_region,
479 PhysicalRegion::Unused
480 ));
Imre Kis703482d2023-11-30 15:51:26 +0100481
Imre Kis42935a22024-10-17 11:30:16 +0200482 assert_eq!(0x4000_1000, splitted_regions[1].va);
483 assert_eq!(0x1000, splitted_regions[1].length);
484 assert_eq!(0x8000_0000, splitted_regions[1].get_pa());
485 assert!(matches!(
486 splitted_regions[1].physical_region,
487 PhysicalRegion::PhysicalAddress(_)
488 ));
Imre Kis703482d2023-11-30 15:51:26 +0100489
Imre Kis42935a22024-10-17 11:30:16 +0200490 assert_eq!(0x4000_2000, splitted_regions[2].va);
491 assert_eq!(0x2000, splitted_regions[2].length);
492 assert!(matches!(
493 splitted_regions[2].physical_region,
494 PhysicalRegion::Unused
495 ));
Imre Kis703482d2023-11-30 15:51:26 +0100496
Imre Kis42935a22024-10-17 11:30:16 +0200497 // New region at the end
498 let (new_region, splitted_regions) = region_unused.create_split(
499 0x4000_3000,
500 0x1000,
501 Some(PhysicalRegion::PhysicalAddress(0x8000_0000)),
502 );
Imre Kis703482d2023-11-30 15:51:26 +0100503
Imre Kis42935a22024-10-17 11:30:16 +0200504 assert_eq!(0x4000_3000, new_region.va);
505 assert_eq!(0x1000, new_region.length);
506 assert_eq!(0x8000_0000, new_region.get_pa());
507 assert!(matches!(
508 new_region.physical_region,
509 PhysicalRegion::PhysicalAddress(_)
510 ));
Imre Kis703482d2023-11-30 15:51:26 +0100511
Imre Kis42935a22024-10-17 11:30:16 +0200512 assert_eq!(0x4000_0000, splitted_regions[0].va);
513 assert_eq!(0x3000, splitted_regions[0].length);
514 assert!(matches!(
515 splitted_regions[0].physical_region,
516 PhysicalRegion::Unused
517 ));
Imre Kis703482d2023-11-30 15:51:26 +0100518
Imre Kis42935a22024-10-17 11:30:16 +0200519 assert_eq!(0x4000_3000, splitted_regions[1].va);
520 assert_eq!(0x1000, splitted_regions[1].length);
521 assert_eq!(0x8000_0000, splitted_regions[1].get_pa());
522 assert!(matches!(
523 splitted_regions[1].physical_region,
524 PhysicalRegion::PhysicalAddress(_)
525 ));
526 }
Imre Kis703482d2023-11-30 15:51:26 +0100527
Imre Kis42935a22024-10-17 11:30:16 +0200528 #[test]
529 fn test_virtual_region_create_split_by_unused() {
530 let region_unused = VirtualRegion::new_with_pa(0x8000_0000, 0x4000_0000, 0x4000);
Imre Kis703482d2023-11-30 15:51:26 +0100531
Imre Kis42935a22024-10-17 11:30:16 +0200532 // New region at the start
533 let (new_region, splitted_regions) = region_unused.create_split(0x4000_0000, 0x1000, None);
Imre Kis703482d2023-11-30 15:51:26 +0100534
Imre Kis42935a22024-10-17 11:30:16 +0200535 assert_eq!(0x4000_0000, new_region.va);
536 assert_eq!(0x1000, new_region.length);
537 assert!(matches!(new_region.physical_region, PhysicalRegion::Unused));
Imre Kis703482d2023-11-30 15:51:26 +0100538
Imre Kis42935a22024-10-17 11:30:16 +0200539 assert_eq!(0x4000_0000, splitted_regions[0].va);
540 assert_eq!(0x1000, splitted_regions[0].length);
541 assert!(matches!(
542 splitted_regions[0].physical_region,
543 PhysicalRegion::Unused
544 ));
Imre Kis703482d2023-11-30 15:51:26 +0100545
Imre Kis42935a22024-10-17 11:30:16 +0200546 assert_eq!(0x4000_1000, splitted_regions[1].va);
547 assert_eq!(0x3000, splitted_regions[1].length);
548 assert_eq!(0x8000_1000, splitted_regions[1].get_pa());
549 assert!(matches!(
550 splitted_regions[1].physical_region,
551 PhysicalRegion::PhysicalAddress(_)
552 ));
Imre Kis703482d2023-11-30 15:51:26 +0100553
Imre Kis42935a22024-10-17 11:30:16 +0200554 // New region in the middle
555 let (new_region, splitted_regions) = region_unused.create_split(0x4000_1000, 0x1000, None);
Imre Kis703482d2023-11-30 15:51:26 +0100556
Imre Kis42935a22024-10-17 11:30:16 +0200557 assert_eq!(0x4000_1000, new_region.va);
558 assert_eq!(0x1000, new_region.length);
559 assert!(matches!(new_region.physical_region, PhysicalRegion::Unused));
Imre Kis703482d2023-11-30 15:51:26 +0100560
Imre Kis42935a22024-10-17 11:30:16 +0200561 assert_eq!(0x4000_0000, splitted_regions[0].va);
562 assert_eq!(0x1000, splitted_regions[0].length);
563 assert_eq!(0x8000_0000, splitted_regions[0].get_pa());
564 assert!(matches!(
565 splitted_regions[0].physical_region,
566 PhysicalRegion::PhysicalAddress(_)
567 ));
Imre Kis703482d2023-11-30 15:51:26 +0100568
Imre Kis42935a22024-10-17 11:30:16 +0200569 assert_eq!(0x4000_1000, splitted_regions[1].va);
570 assert_eq!(0x1000, splitted_regions[1].length);
571 assert!(matches!(
572 splitted_regions[1].physical_region,
573 PhysicalRegion::Unused
574 ));
Imre Kis703482d2023-11-30 15:51:26 +0100575
Imre Kis42935a22024-10-17 11:30:16 +0200576 assert_eq!(0x4000_2000, splitted_regions[2].va);
577 assert_eq!(0x2000, splitted_regions[2].length);
578 assert_eq!(0x8000_2000, splitted_regions[2].get_pa());
579 assert!(matches!(
580 splitted_regions[2].physical_region,
581 PhysicalRegion::PhysicalAddress(_)
582 ));
Imre Kis703482d2023-11-30 15:51:26 +0100583
Imre Kis42935a22024-10-17 11:30:16 +0200584 // New region at the end
585 let (new_region, splitted_regions) = region_unused.create_split(0x4000_3000, 0x1000, None);
Imre Kis703482d2023-11-30 15:51:26 +0100586
Imre Kis42935a22024-10-17 11:30:16 +0200587 assert_eq!(0x4000_3000, new_region.va);
588 assert_eq!(0x1000, new_region.length);
589 assert!(matches!(new_region.physical_region, PhysicalRegion::Unused));
Imre Kis703482d2023-11-30 15:51:26 +0100590
Imre Kis42935a22024-10-17 11:30:16 +0200591 assert_eq!(0x4000_0000, splitted_regions[0].va);
592 assert_eq!(0x3000, splitted_regions[0].length);
593 assert_eq!(0x8000_0000, splitted_regions[0].get_pa());
594 assert!(matches!(
595 splitted_regions[0].physical_region,
596 PhysicalRegion::PhysicalAddress(_)
597 ));
Imre Kis703482d2023-11-30 15:51:26 +0100598
Imre Kis42935a22024-10-17 11:30:16 +0200599 assert_eq!(0x4000_3000, splitted_regions[1].va);
600 assert_eq!(0x1000, splitted_regions[1].length);
Imre Kis703482d2023-11-30 15:51:26 +0100601
Imre Kis42935a22024-10-17 11:30:16 +0200602 assert!(matches!(
603 splitted_regions[1].physical_region,
604 PhysicalRegion::Unused
605 ));
606 }
Imre Kis703482d2023-11-30 15:51:26 +0100607
Imre Kis42935a22024-10-17 11:30:16 +0200608 #[test]
609 #[should_panic]
610 fn test_virtual_region_does_not_contain() {
611 let region = VirtualRegion::new(0x4000_0000, 0x1000);
612 region.create_split(
613 0x8000_0000,
614 0x1000,
615 Some(PhysicalRegion::PhysicalAddress(0xc000_0000)),
616 );
617 }
Imre Kis703482d2023-11-30 15:51:26 +0100618
Imre Kis42935a22024-10-17 11:30:16 +0200619 #[test]
620 #[should_panic]
621 fn test_virtual_region_create_split_same_used() {
622 let region = VirtualRegion::new(0x4000_0000, 0x1000);
623 region.create_split(0x4000_0000, 0x1000, Some(PhysicalRegion::Unused));
624 }
Imre Kis703482d2023-11-30 15:51:26 +0100625
Imre Kis42935a22024-10-17 11:30:16 +0200626 #[test]
627 fn test_virtual_region_drop() {
628 const PA: usize = 0x0123_4567_89ab_cdef;
629 const LENGTH: usize = 0x8000_0000_0000;
Imre Kis703482d2023-11-30 15:51:26 +0100630
Imre Kis42935a22024-10-17 11:30:16 +0200631 static PAGE_POOL_AREA: PagePoolArea<8192> = PagePoolArea::new();
632 let page_pool = PagePool::new(&PAGE_POOL_AREA);
633 let page = page_pool.allocate_pages(4096).unwrap();
Imre Kis703482d2023-11-30 15:51:26 +0100634
Imre Kis42935a22024-10-17 11:30:16 +0200635 let physical_region = PhysicalRegion::Allocated(page_pool, page);
Imre Kis703482d2023-11-30 15:51:26 +0100636
Imre Kis42935a22024-10-17 11:30:16 +0200637 // Testing physical region drop through virtualregion
638 let virtual_region = VirtualRegion::new_from_fields(0x4000_0000, 1000, physical_region);
639 drop(virtual_region);
640 }
Imre Kis703482d2023-11-30 15:51:26 +0100641}