blob: 09958e8a1bfaa3c0b8a5105eab0e46a28b7ecc9c [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::{
Imre Kisd5b96fd2024-09-11 17:04:32 +020012 address::{PhysicalAddress, VirtualAddress},
Imre Kis703482d2023-11-30 15:51:26 +010013 page_pool::{PagePool, Pages},
14 region_pool::Region,
15};
16
17/// Physical region
18///
19/// A physical memory region can be in three different state
20/// * Unused
21/// * Points to a page pool allocated address
22/// * Points to a physical address without allocation
23pub enum PhysicalRegion {
24 Unused,
25 Allocated(PagePool, Pages),
Imre Kisd5b96fd2024-09-11 17:04:32 +020026 PhysicalAddress(PhysicalAddress),
Imre Kis703482d2023-11-30 15:51:26 +010027}
28
29impl PhysicalRegion {
30 /// Get physical memory address
Imre Kisd5b96fd2024-09-11 17:04:32 +020031 fn get_pa(&self) -> PhysicalAddress {
Imre Kis703482d2023-11-30 15:51:26 +010032 match self {
33 PhysicalRegion::Unused => panic!("Unused area has no PA"),
34 PhysicalRegion::Allocated(_page_pool, pages) => pages.get_pa(),
35 PhysicalRegion::PhysicalAddress(pa) => *pa,
36 }
37 }
38}
39
40/// Virtual region
41///
42/// A virtual memory region has a virtual address, a length and a physical region.
43pub struct VirtualRegion {
Imre Kisd5b96fd2024-09-11 17:04:32 +020044 va: VirtualAddress,
Imre Kis703482d2023-11-30 15:51:26 +010045 length: usize,
46 physical_region: PhysicalRegion,
47}
48
49impl VirtualRegion {
50 /// Create new virtual memory region without a physical region
Imre Kisd5b96fd2024-09-11 17:04:32 +020051 pub fn new(va: VirtualAddress, length: usize) -> Self {
Imre Kis703482d2023-11-30 15:51:26 +010052 Self::new_from_fields(va, length, PhysicalRegion::Unused)
53 }
54
55 /// Create virtual region with points to a given physical address
Imre Kisd5b96fd2024-09-11 17:04:32 +020056 pub fn new_with_pa(pa: PhysicalAddress, va: VirtualAddress, length: usize) -> Self {
Imre Kis703482d2023-11-30 15:51:26 +010057 Self::new_from_fields(va, length, PhysicalRegion::PhysicalAddress(pa))
58 }
59
60 /// Create virtual region by defining all the fields of the object
Imre Kisd5b96fd2024-09-11 17:04:32 +020061 fn new_from_fields(va: VirtualAddress, length: usize, physical_region: PhysicalRegion) -> Self {
Imre Kis703482d2023-11-30 15:51:26 +010062 Self {
63 va,
64 length,
65 physical_region,
66 }
67 }
68
69 /// Get the base address of the linked physical region
Imre Kisd5b96fd2024-09-11 17:04:32 +020070 pub fn get_pa(&self) -> PhysicalAddress {
Imre Kis703482d2023-11-30 15:51:26 +010071 self.physical_region.get_pa()
72 }
73
74 /// Get physical address for a virtual address
Imre Kisd5b96fd2024-09-11 17:04:32 +020075 pub fn get_pa_for_va(&self, va: VirtualAddress) -> PhysicalAddress {
76 let offset = va.diff(self.va).unwrap();
Imre Kis703482d2023-11-30 15:51:26 +010077
78 assert!(offset < self.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +020079 self.get_pa().add_offset(offset).unwrap()
Imre Kis703482d2023-11-30 15:51:26 +010080 }
81}
82
83impl Region for VirtualRegion {
84 type Resource = PhysicalRegion;
Imre Kisd5b96fd2024-09-11 17:04:32 +020085 type Base = VirtualAddress;
Imre Kis589aa052024-09-10 20:19:47 +020086 type Length = usize;
Imre Kisf0370e82024-11-18 16:24:55 +010087 type Alignment = usize;
Imre Kis703482d2023-11-30 15:51:26 +010088
Imre Kisd5b96fd2024-09-11 17:04:32 +020089 fn base(&self) -> Self::Base {
Imre Kis703482d2023-11-30 15:51:26 +010090 self.va
91 }
92
Imre Kisd5b96fd2024-09-11 17:04:32 +020093 fn length(&self) -> Self::Length {
Imre Kis703482d2023-11-30 15:51:26 +010094 self.length
95 }
96
97 fn used(&self) -> bool {
98 !matches!(self.physical_region, PhysicalRegion::Unused)
99 }
100
Imre Kisd5b96fd2024-09-11 17:04:32 +0200101 fn contains(&self, base: Self::Base, length: Self::Length) -> bool {
Imre Kis703482d2023-11-30 15:51:26 +0100102 if let (Some(end), Some(self_end)) =
Imre Kisd5b96fd2024-09-11 17:04:32 +0200103 (base.add_offset(length), self.va.add_offset(self.length))
Imre Kis703482d2023-11-30 15:51:26 +0100104 {
105 self.va <= base && end <= self_end
106 } else {
107 false
108 }
109 }
110
Imre Kisf0370e82024-11-18 16:24:55 +0100111 fn try_alloc_aligned(
112 &self,
113 length: Self::Length,
114 alignment: Self::Alignment,
115 ) -> Option<Self::Base> {
116 let aligned_base = self.va.align_up(alignment);
117 let base_offset = aligned_base.diff(self.va)?;
118
119 let required_length = base_offset.checked_add(length)?;
120 if required_length <= self.length {
121 Some(aligned_base)
122 } else {
123 None
124 }
125 }
126
Imre Kis703482d2023-11-30 15:51:26 +0100127 fn try_append(&mut self, other: &Self) -> bool {
128 if let (Some(self_end), Some(new_length)) = (
Imre Kisd5b96fd2024-09-11 17:04:32 +0200129 self.va.add_offset(self.length),
Imre Kis703482d2023-11-30 15:51:26 +0100130 self.length.checked_add(other.length),
131 ) {
132 if self_end == other.va {
133 // VA is consecutive
134 match (&self.physical_region, &other.physical_region) {
135 (PhysicalRegion::Unused, PhysicalRegion::Unused) => {
136 // Unused range can be merged without further conditions
137 self.length = new_length;
138 return true;
139 }
140 (
141 PhysicalRegion::PhysicalAddress(self_pa),
142 PhysicalRegion::PhysicalAddress(other_pa),
143 ) => {
144 // Used ranges can be only merged if the PA doesn't overflow and it is
145 // consecutive
Imre Kisd5b96fd2024-09-11 17:04:32 +0200146 if let Some(self_end_pa) = self_pa.add_offset(self.length) {
Imre Kis703482d2023-11-30 15:51:26 +0100147 if self_end_pa == *other_pa {
148 self.length = new_length;
149 return true;
150 }
151 }
152 }
153
154 // PhyisicalRegion::Allocated instances cannot be merged at the moment. Not sure
155 // if it's a valid use case. If needed the pages has to be merged which might
156 // require tricks to invalidate the pages of 'other'.
157 _ => {}
158 }
159 }
160 }
161
162 false
163 }
164
165 fn create_split(
166 &self,
Imre Kisd5b96fd2024-09-11 17:04:32 +0200167 base: Self::Base,
168 length: Self::Length,
Imre Kis703482d2023-11-30 15:51:26 +0100169 resource: Option<Self::Resource>,
170 ) -> (Self, Vec<Self>) {
171 assert!(self.contains(base, length));
172 assert!(self.used() != resource.is_some());
173
174 if let Some(physical_region) = resource {
175 // Self is unused, setting part of it to used
176 let pa = physical_region.get_pa();
177
178 let mut res = Vec::new();
179 if self.va != base {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200180 res.push(Self::new(self.va, base.diff(self.va).unwrap()));
Imre Kis703482d2023-11-30 15:51:26 +0100181 }
182
183 res.push(Self::new_from_fields(base, length, physical_region));
184
Imre Kisd5b96fd2024-09-11 17:04:32 +0200185 let end = base.add_offset(length).unwrap();
186 let self_end = self.va.add_offset(self.length).unwrap();
Imre Kis703482d2023-11-30 15:51:26 +0100187 if end != self_end {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200188 res.push(Self::new(end, self_end.diff(end).unwrap()));
Imre Kis703482d2023-11-30 15:51:26 +0100189 }
190
191 (
192 Self::new_from_fields(base, length, PhysicalRegion::PhysicalAddress(pa)),
193 res,
194 )
195 } else {
196 // Self is used, mark part of it unused
197 let mut res = Vec::new();
198 if self.va != base {
199 let physical_region = match &self.physical_region {
200 PhysicalRegion::Allocated(_page_pool, _pages) => {
201 todo!("Implement Pages::split");
202 }
203 PhysicalRegion::PhysicalAddress(pa) => PhysicalRegion::PhysicalAddress(*pa),
204 _ => {
205 panic!("Splitting unused region by other unused")
206 }
207 };
208
209 res.push(Self::new_from_fields(
210 self.va,
Imre Kisd5b96fd2024-09-11 17:04:32 +0200211 base.diff(self.va).unwrap(),
Imre Kis703482d2023-11-30 15:51:26 +0100212 physical_region,
213 ));
214 }
215
216 res.push(Self::new(base, length));
217
Imre Kisd5b96fd2024-09-11 17:04:32 +0200218 let end = base.add_offset(length).unwrap();
219 let self_end = self.va.add_offset(self.length).unwrap();
Imre Kis703482d2023-11-30 15:51:26 +0100220 if end != self_end {
221 let physical_region = match &self.physical_region {
222 PhysicalRegion::Allocated(_page_pool, _pages) => {
223 todo!("Implement Pages::split");
224 }
225 PhysicalRegion::PhysicalAddress(pa) => {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200226 let offset = end.diff(self.va).unwrap();
227 PhysicalRegion::PhysicalAddress(pa.add_offset(offset).unwrap())
Imre Kis703482d2023-11-30 15:51:26 +0100228 }
229 _ => {
230 panic!("Splitting unused region by other unused")
231 }
232 };
233
234 res.push(Self::new_from_fields(
235 end,
Imre Kisd5b96fd2024-09-11 17:04:32 +0200236 self_end.diff(end).unwrap(),
Imre Kis703482d2023-11-30 15:51:26 +0100237 physical_region,
238 ));
239 }
240
241 (Self::new(base, length), res)
242 }
243 }
244}
245
246impl Drop for VirtualRegion {
247 /// If the virtual region has a linked physical region which was allocated then release the
248 /// allocated pages.
249 fn drop(&mut self) {
250 let mut physical_region = PhysicalRegion::Unused;
251
252 core::mem::swap(&mut self.physical_region, &mut physical_region);
253
254 if let PhysicalRegion::Allocated(page_pool, pages) = physical_region {
255 debug!(
Imre Kisd5b96fd2024-09-11 17:04:32 +0200256 "Dropping physical region with pages: PA={:#08x} VA={:#08x}",
257 pages.get_pa().0,
258 self.base().0,
Imre Kis703482d2023-11-30 15:51:26 +0100259 );
260
261 page_pool.release_pages(pages).unwrap();
262 }
263 }
264}
265
266#[cfg(test)]
Imre Kis42935a22024-10-17 11:30:16 +0200267mod tests {
Imre Kis42935a22024-10-17 11:30:16 +0200268 use super::*;
Imre Kisd5b96fd2024-09-11 17:04:32 +0200269 use crate::page_pool::PagePoolArea;
Imre Kis703482d2023-11-30 15:51:26 +0100270
Imre Kis42935a22024-10-17 11:30:16 +0200271 #[test]
272 #[should_panic]
273 fn test_physical_region_unused() {
274 let region = PhysicalRegion::Unused;
275 region.get_pa();
276 }
Imre Kis703482d2023-11-30 15:51:26 +0100277
Imre Kis42935a22024-10-17 11:30:16 +0200278 #[test]
279 fn test_physical_region() {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200280 const PA: PhysicalAddress = PhysicalAddress(0x0123_4567_89ab_cdef);
Imre Kis42935a22024-10-17 11:30:16 +0200281 const LENGTH: usize = 0x8000_0000_0000;
Imre Kis703482d2023-11-30 15:51:26 +0100282
Imre Kis42935a22024-10-17 11:30:16 +0200283 static PAGE_POOL_AREA: PagePoolArea<16> = PagePoolArea::new();
Imre Kisd5b96fd2024-09-11 17:04:32 +0200284 let region = PhysicalRegion::Allocated(
285 PagePool::new(&PAGE_POOL_AREA),
286 Pages::new(PA.0, LENGTH, true),
287 );
Imre Kis42935a22024-10-17 11:30:16 +0200288 assert_eq!(PA, region.get_pa());
Imre Kis703482d2023-11-30 15:51:26 +0100289
Imre Kis42935a22024-10-17 11:30:16 +0200290 let region = PhysicalRegion::PhysicalAddress(PA);
291 assert_eq!(PA, region.get_pa());
292 }
Imre Kis703482d2023-11-30 15:51:26 +0100293
Imre Kis42935a22024-10-17 11:30:16 +0200294 #[test]
295 fn test_virtual_region() {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200296 const VA: VirtualAddress = VirtualAddress(0x0123_4567_89ab_cdef);
297 const PA: PhysicalAddress = PhysicalAddress(0xfedc_ba98_7654_3210);
Imre Kis42935a22024-10-17 11:30:16 +0200298 const LENGTH: usize = 0x8000_0000_0000;
Imre Kis703482d2023-11-30 15:51:26 +0100299
Imre Kis42935a22024-10-17 11:30:16 +0200300 let region = VirtualRegion::new(VA, LENGTH);
301 assert_eq!(VA, region.va);
302 assert_eq!(VA, region.base());
303 assert_eq!(LENGTH, region.length);
304 assert_eq!(LENGTH, region.length());
305 assert!(matches!(region.physical_region, PhysicalRegion::Unused));
306 assert!(!region.used());
Imre Kis703482d2023-11-30 15:51:26 +0100307
Imre Kis42935a22024-10-17 11:30:16 +0200308 let region = VirtualRegion::new_with_pa(PA, VA, LENGTH);
309 assert_eq!(VA, region.va);
310 assert_eq!(VA, region.base());
311 assert_eq!(LENGTH, region.length);
312 assert_eq!(LENGTH, region.length());
313 assert!(matches!(
314 region.physical_region,
315 PhysicalRegion::PhysicalAddress(_)
316 ));
317 assert_eq!(PA, region.get_pa());
318 assert!(region.used());
319 }
Imre Kis703482d2023-11-30 15:51:26 +0100320
Imre Kis42935a22024-10-17 11:30:16 +0200321 #[test]
322 fn test_virtual_region_get_pa_for_va() {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200323 let region = VirtualRegion::new_with_pa(
324 PhysicalAddress(0x8000_0000_0000_0000),
325 VirtualAddress(0x4000_0000_0000_0000),
326 0x1000,
Imre Kis42935a22024-10-17 11:30:16 +0200327 );
328 assert_eq!(
Imre Kisd5b96fd2024-09-11 17:04:32 +0200329 PhysicalAddress(0x8000_0000_0000_0000),
330 region.get_pa_for_va(VirtualAddress(0x4000_0000_0000_0000))
Imre Kis42935a22024-10-17 11:30:16 +0200331 );
332 assert_eq!(
Imre Kisd5b96fd2024-09-11 17:04:32 +0200333 PhysicalAddress(0x8000_0000_0000_0001),
334 region.get_pa_for_va(VirtualAddress(0x4000_0000_0000_0001))
335 );
336 assert_eq!(
337 PhysicalAddress(0x8000_0000_0000_0fff),
338 region.get_pa_for_va(VirtualAddress(0x4000_0000_0000_0fff))
Imre Kis42935a22024-10-17 11:30:16 +0200339 );
340 }
Imre Kis703482d2023-11-30 15:51:26 +0100341
Imre Kis42935a22024-10-17 11:30:16 +0200342 #[test]
343 #[should_panic]
344 fn test_virtual_region_get_pa_for_va_low_va() {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200345 let region = VirtualRegion::new_with_pa(
346 PhysicalAddress(0x8000_0000_0000_0000),
347 VirtualAddress(0x4000_0000_0000_0000),
348 0x1000,
349 );
350 region.get_pa_for_va(VirtualAddress(0x3fff_ffff_ffff_ffff));
Imre Kis42935a22024-10-17 11:30:16 +0200351 }
Imre Kis703482d2023-11-30 15:51:26 +0100352
Imre Kis42935a22024-10-17 11:30:16 +0200353 #[test]
354 #[should_panic]
355 fn test_virtual_region_get_pa_for_va_high_va() {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200356 let region = VirtualRegion::new_with_pa(
357 PhysicalAddress(0x8000_0000_0000_0000),
358 VirtualAddress(0x4000_0000_0000_0000),
359 0x1000,
360 );
361 region.get_pa_for_va(VirtualAddress(0x4000_0000_0000_1000));
Imre Kis42935a22024-10-17 11:30:16 +0200362 }
Imre Kis703482d2023-11-30 15:51:26 +0100363
Imre Kis42935a22024-10-17 11:30:16 +0200364 #[test]
Imre Kisf0370e82024-11-18 16:24:55 +0100365 fn test_virtual_region_try_alloc() {
366 let region = VirtualRegion::new_with_pa(
367 PhysicalAddress(0x8000_1000),
368 VirtualAddress(0x4000_1000),
369 0x10000,
370 );
371
372 assert_eq!(
373 Some(VirtualAddress(0x4000_1000)),
374 region.try_alloc(0x1000, None)
375 );
376 assert_eq!(
377 Some(VirtualAddress(0x4000_2000)),
378 region.try_alloc(0x1000, Some(0x2000))
379 );
380 assert_eq!(None, region.try_alloc(0x1000, Some(0x10_0000)));
381 }
382
383 #[test]
Imre Kis42935a22024-10-17 11:30:16 +0200384 fn test_virtual_region_contains() {
385 const VA: usize = 0x8000_0000_0000_0000;
386 const LENGTH: usize = 0x8000_0000_0000;
Imre Kis703482d2023-11-30 15:51:26 +0100387
Imre Kisd5b96fd2024-09-11 17:04:32 +0200388 let region_overflow_end =
389 VirtualRegion::new(VirtualAddress(0x8000_0000_0000_0000), 0x8000_0000_0000_0000);
390 assert!(!region_overflow_end.contains(VirtualAddress(0x8000_0000_0000_0000), 1));
Imre Kis703482d2023-11-30 15:51:26 +0100391
Imre Kisd5b96fd2024-09-11 17:04:32 +0200392 let region =
393 VirtualRegion::new(VirtualAddress(0x4000_0000_0000_0000), 0x8000_0000_0000_0000);
394 assert!(!region.contains(VirtualAddress(0x8000_0000_0000_0000), 0x8000_0000_0000_0000));
Imre Kis703482d2023-11-30 15:51:26 +0100395
Imre Kisd5b96fd2024-09-11 17:04:32 +0200396 assert!(!region.contains(VirtualAddress(0x4000_0000_0000_0000), 0x8000_0000_0000_0001));
397 assert!(!region.contains(VirtualAddress(0x3fff_ffff_ffff_ffff), 0x8000_0000_0000_0000));
398 assert!(region.contains(VirtualAddress(0x4000_0000_0000_0000), 0x8000_0000_0000_0000));
399 assert!(region.contains(VirtualAddress(0x4000_0000_0000_0000), 0x7fff_ffff_ffff_ffff));
400 assert!(region.contains(VirtualAddress(0x4000_0000_0000_0001), 0x7fff_ffff_ffff_ffff));
Imre Kis42935a22024-10-17 11:30:16 +0200401 }
Imre Kis703482d2023-11-30 15:51:26 +0100402
Imre Kis42935a22024-10-17 11:30:16 +0200403 #[test]
404 fn test_virtual_region_try_append() {
405 // Both unused
Imre Kisd5b96fd2024-09-11 17:04:32 +0200406 let mut region_unused0 = VirtualRegion::new(VirtualAddress(0x4000_0000), 0x1000);
407 let mut region_unused1 = VirtualRegion::new(VirtualAddress(0x4000_1000), 0x1000);
Imre Kis703482d2023-11-30 15:51:26 +0100408
Imre Kis42935a22024-10-17 11:30:16 +0200409 assert!(!region_unused1.try_append(&region_unused0));
Imre Kisd5b96fd2024-09-11 17:04:32 +0200410 assert_eq!(VirtualAddress(0x4000_0000), region_unused0.va);
Imre Kis42935a22024-10-17 11:30:16 +0200411 assert_eq!(0x1000, region_unused0.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200412 assert_eq!(VirtualAddress(0x4000_1000), region_unused1.va);
Imre Kis42935a22024-10-17 11:30:16 +0200413 assert_eq!(0x1000, region_unused1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100414
Imre Kis42935a22024-10-17 11:30:16 +0200415 assert!(region_unused0.try_append(&region_unused1));
Imre Kisd5b96fd2024-09-11 17:04:32 +0200416 assert_eq!(VirtualAddress(0x4000_0000), region_unused0.va);
Imre Kis42935a22024-10-17 11:30:16 +0200417 assert_eq!(0x2000, region_unused0.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200418 assert_eq!(VirtualAddress(0x4000_1000), region_unused1.va);
Imre Kis42935a22024-10-17 11:30:16 +0200419 assert_eq!(0x1000, region_unused1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100420
Imre Kis42935a22024-10-17 11:30:16 +0200421 // Unused and PA region
Imre Kisd5b96fd2024-09-11 17:04:32 +0200422 let mut region_unused = VirtualRegion::new(VirtualAddress(0x4000_0000), 0x1000);
423 let region_physical = VirtualRegion::new_with_pa(
424 PhysicalAddress(0x8000_0000),
425 VirtualAddress(0x4000_1000),
426 0x1000,
427 );
Imre Kis42935a22024-10-17 11:30:16 +0200428 assert!(!region_unused.try_append(&region_physical));
Imre Kisd5b96fd2024-09-11 17:04:32 +0200429 assert_eq!(VirtualAddress(0x4000_0000), region_unused.va);
Imre Kis42935a22024-10-17 11:30:16 +0200430 assert_eq!(0x1000, region_unused.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200431 assert_eq!(VirtualAddress(0x4000_1000), region_physical.va);
Imre Kis42935a22024-10-17 11:30:16 +0200432 assert_eq!(0x1000, region_physical.length);
Imre Kis703482d2023-11-30 15:51:26 +0100433
Imre Kis42935a22024-10-17 11:30:16 +0200434 // Both PA regions but non-consecutive PA ranges
Imre Kisd5b96fd2024-09-11 17:04:32 +0200435 let mut region_physical0 = VirtualRegion::new_with_pa(
436 PhysicalAddress(0x8000_0000),
437 VirtualAddress(0x4000_0000),
438 0x1000,
439 );
440 let region_physical1 = VirtualRegion::new_with_pa(
441 PhysicalAddress(0x9000_0000),
442 VirtualAddress(0x4000_1000),
443 0x1000,
444 );
Imre Kis42935a22024-10-17 11:30:16 +0200445 assert!(!region_physical0.try_append(&region_physical1));
Imre Kisd5b96fd2024-09-11 17:04:32 +0200446 assert_eq!(VirtualAddress(0x4000_0000), region_physical0.va);
Imre Kis42935a22024-10-17 11:30:16 +0200447 assert_eq!(0x1000, region_physical0.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200448 assert_eq!(VirtualAddress(0x4000_1000), region_physical1.va);
Imre Kis42935a22024-10-17 11:30:16 +0200449 assert_eq!(0x1000, region_physical1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100450
Imre Kis42935a22024-10-17 11:30:16 +0200451 // Both PA regions with consecutive PA ranges
Imre Kisd5b96fd2024-09-11 17:04:32 +0200452 let mut region_physical0 = VirtualRegion::new_with_pa(
453 PhysicalAddress(0x8000_0000),
454 VirtualAddress(0x4000_0000),
455 0x1000,
456 );
457 let region_physical1 = VirtualRegion::new_with_pa(
458 PhysicalAddress(0x8000_1000),
459 VirtualAddress(0x4000_1000),
460 0x1000,
461 );
Imre Kis42935a22024-10-17 11:30:16 +0200462 assert!(region_physical0.try_append(&region_physical1));
Imre Kisd5b96fd2024-09-11 17:04:32 +0200463 assert_eq!(VirtualAddress(0x4000_0000), region_physical0.va);
Imre Kis42935a22024-10-17 11:30:16 +0200464 assert_eq!(0x2000, region_physical0.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200465 assert_eq!(VirtualAddress(0x4000_1000), region_physical1.va);
Imre Kis42935a22024-10-17 11:30:16 +0200466 assert_eq!(0x1000, region_physical1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100467
Imre Kis42935a22024-10-17 11:30:16 +0200468 // VA overflow
Imre Kisd5b96fd2024-09-11 17:04:32 +0200469 let mut region_unused0: VirtualRegion =
470 VirtualRegion::new(VirtualAddress(0x8000_0000_0000_0000), 0x8000_0000_0000_0000);
471 let mut region_unused1 = VirtualRegion::new(VirtualAddress(0x4000_1000), 0x1000);
Imre Kis703482d2023-11-30 15:51:26 +0100472
Imre Kis42935a22024-10-17 11:30:16 +0200473 assert!(!region_unused0.try_append(&region_unused1));
Imre Kisd5b96fd2024-09-11 17:04:32 +0200474 assert_eq!(VirtualAddress(0x8000_0000_0000_0000), region_unused0.va);
Imre Kis42935a22024-10-17 11:30:16 +0200475 assert_eq!(0x8000_0000_0000_0000, region_unused0.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200476 assert_eq!(VirtualAddress(0x4000_1000), region_unused1.va);
Imre Kis42935a22024-10-17 11:30:16 +0200477 assert_eq!(0x1000, region_unused1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100478
Imre Kis42935a22024-10-17 11:30:16 +0200479 assert!(!region_unused1.try_append(&region_unused0));
Imre Kisd5b96fd2024-09-11 17:04:32 +0200480 assert_eq!(VirtualAddress(0x8000_0000_0000_0000), region_unused0.va);
Imre Kis42935a22024-10-17 11:30:16 +0200481 assert_eq!(0x8000_0000_0000_0000, region_unused0.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200482 assert_eq!(VirtualAddress(0x4000_1000), region_unused1.va);
Imre Kis42935a22024-10-17 11:30:16 +0200483 assert_eq!(0x1000, region_unused1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100484
Imre Kis42935a22024-10-17 11:30:16 +0200485 // PA overflow
Imre Kisd5b96fd2024-09-11 17:04:32 +0200486 let mut region_physical0 = VirtualRegion::new_with_pa(
487 PhysicalAddress(0x8000_0000_0000_0000),
488 VirtualAddress(0x4000_0000),
489 0x8000_0000_0000_0000,
490 );
491 let region_physical1 = VirtualRegion::new_with_pa(
492 PhysicalAddress(0x9000_0000),
493 VirtualAddress(0x8000_0000_4000_0000),
494 0x1000,
495 );
Imre Kis42935a22024-10-17 11:30:16 +0200496 assert!(!region_physical0.try_append(&region_physical1));
Imre Kisd5b96fd2024-09-11 17:04:32 +0200497 assert_eq!(VirtualAddress(0x4000_0000), region_physical0.va);
Imre Kis42935a22024-10-17 11:30:16 +0200498 assert_eq!(0x8000_0000_0000_0000, region_physical0.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200499 assert_eq!(VirtualAddress(0x8000_0000_4000_0000), region_physical1.va);
Imre Kis42935a22024-10-17 11:30:16 +0200500 assert_eq!(0x1000, region_physical1.length);
501 }
Imre Kis703482d2023-11-30 15:51:26 +0100502
Imre Kis42935a22024-10-17 11:30:16 +0200503 #[test]
504 fn test_virtual_region_create_split_by_used() {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200505 let region_unused = VirtualRegion::new(VirtualAddress(0x4000_0000), 0x4000);
Imre Kis703482d2023-11-30 15:51:26 +0100506
Imre Kis42935a22024-10-17 11:30:16 +0200507 // New region at the start
508 let (new_region, splitted_regions) = region_unused.create_split(
Imre Kisd5b96fd2024-09-11 17:04:32 +0200509 VirtualAddress(0x4000_0000),
Imre Kis42935a22024-10-17 11:30:16 +0200510 0x1000,
Imre Kisd5b96fd2024-09-11 17:04:32 +0200511 Some(PhysicalRegion::PhysicalAddress(PhysicalAddress(
512 0x8000_0000,
513 ))),
Imre Kis42935a22024-10-17 11:30:16 +0200514 );
Imre Kis703482d2023-11-30 15:51:26 +0100515
Imre Kisd5b96fd2024-09-11 17:04:32 +0200516 assert_eq!(VirtualAddress(0x4000_0000), new_region.va);
Imre Kis42935a22024-10-17 11:30:16 +0200517 assert_eq!(0x1000, new_region.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200518 assert_eq!(PhysicalAddress(0x8000_0000), new_region.get_pa());
Imre Kis42935a22024-10-17 11:30:16 +0200519 assert!(matches!(
520 new_region.physical_region,
521 PhysicalRegion::PhysicalAddress(_)
522 ));
Imre Kis703482d2023-11-30 15:51:26 +0100523
Imre Kisd5b96fd2024-09-11 17:04:32 +0200524 assert_eq!(VirtualAddress(0x4000_0000), splitted_regions[0].va);
Imre Kis42935a22024-10-17 11:30:16 +0200525 assert_eq!(0x1000, splitted_regions[0].length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200526 assert_eq!(PhysicalAddress(0x8000_0000), splitted_regions[0].get_pa());
Imre Kis42935a22024-10-17 11:30:16 +0200527 assert!(matches!(
528 splitted_regions[0].physical_region,
529 PhysicalRegion::PhysicalAddress(_)
530 ));
Imre Kis703482d2023-11-30 15:51:26 +0100531
Imre Kisd5b96fd2024-09-11 17:04:32 +0200532 assert_eq!(VirtualAddress(0x4000_1000), splitted_regions[1].va);
Imre Kis42935a22024-10-17 11:30:16 +0200533 assert_eq!(0x3000, splitted_regions[1].length);
534 assert!(matches!(
535 splitted_regions[1].physical_region,
536 PhysicalRegion::Unused
537 ));
Imre Kis703482d2023-11-30 15:51:26 +0100538
Imre Kis42935a22024-10-17 11:30:16 +0200539 // New region in the middle
540 let (new_region, splitted_regions) = region_unused.create_split(
Imre Kisd5b96fd2024-09-11 17:04:32 +0200541 VirtualAddress(0x4000_1000),
Imre Kis42935a22024-10-17 11:30:16 +0200542 0x1000,
Imre Kisd5b96fd2024-09-11 17:04:32 +0200543 Some(PhysicalRegion::PhysicalAddress(PhysicalAddress(
544 0x8000_0000,
545 ))),
Imre Kis42935a22024-10-17 11:30:16 +0200546 );
Imre Kis703482d2023-11-30 15:51:26 +0100547
Imre Kisd5b96fd2024-09-11 17:04:32 +0200548 assert_eq!(VirtualAddress(0x4000_1000), new_region.va);
Imre Kis42935a22024-10-17 11:30:16 +0200549 assert_eq!(0x1000, new_region.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200550 assert_eq!(PhysicalAddress(0x8000_0000), new_region.get_pa());
Imre Kis42935a22024-10-17 11:30:16 +0200551 assert!(matches!(
552 new_region.physical_region,
553 PhysicalRegion::PhysicalAddress(_)
554 ));
Imre Kis703482d2023-11-30 15:51:26 +0100555
Imre Kisd5b96fd2024-09-11 17:04:32 +0200556 assert_eq!(VirtualAddress(0x4000_0000), splitted_regions[0].va);
Imre Kis42935a22024-10-17 11:30:16 +0200557 assert_eq!(0x1000, splitted_regions[0].length);
558 assert!(matches!(
559 splitted_regions[0].physical_region,
560 PhysicalRegion::Unused
561 ));
Imre Kis703482d2023-11-30 15:51:26 +0100562
Imre Kisd5b96fd2024-09-11 17:04:32 +0200563 assert_eq!(VirtualAddress(0x4000_1000), splitted_regions[1].va);
Imre Kis42935a22024-10-17 11:30:16 +0200564 assert_eq!(0x1000, splitted_regions[1].length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200565 assert_eq!(PhysicalAddress(0x8000_0000), splitted_regions[1].get_pa());
Imre Kis42935a22024-10-17 11:30:16 +0200566 assert!(matches!(
567 splitted_regions[1].physical_region,
568 PhysicalRegion::PhysicalAddress(_)
569 ));
Imre Kis703482d2023-11-30 15:51:26 +0100570
Imre Kisd5b96fd2024-09-11 17:04:32 +0200571 assert_eq!(VirtualAddress(0x4000_2000), splitted_regions[2].va);
Imre Kis42935a22024-10-17 11:30:16 +0200572 assert_eq!(0x2000, splitted_regions[2].length);
573 assert!(matches!(
574 splitted_regions[2].physical_region,
575 PhysicalRegion::Unused
576 ));
Imre Kis703482d2023-11-30 15:51:26 +0100577
Imre Kis42935a22024-10-17 11:30:16 +0200578 // New region at the end
579 let (new_region, splitted_regions) = region_unused.create_split(
Imre Kisd5b96fd2024-09-11 17:04:32 +0200580 VirtualAddress(0x4000_3000),
Imre Kis42935a22024-10-17 11:30:16 +0200581 0x1000,
Imre Kisd5b96fd2024-09-11 17:04:32 +0200582 Some(PhysicalRegion::PhysicalAddress(PhysicalAddress(
583 0x8000_0000,
584 ))),
Imre Kis42935a22024-10-17 11:30:16 +0200585 );
Imre Kis703482d2023-11-30 15:51:26 +0100586
Imre Kisd5b96fd2024-09-11 17:04:32 +0200587 assert_eq!(VirtualAddress(0x4000_3000), new_region.va);
Imre Kis42935a22024-10-17 11:30:16 +0200588 assert_eq!(0x1000, new_region.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200589 assert_eq!(PhysicalAddress(0x8000_0000), new_region.get_pa());
Imre Kis42935a22024-10-17 11:30:16 +0200590 assert!(matches!(
591 new_region.physical_region,
592 PhysicalRegion::PhysicalAddress(_)
593 ));
Imre Kis703482d2023-11-30 15:51:26 +0100594
Imre Kisd5b96fd2024-09-11 17:04:32 +0200595 assert_eq!(VirtualAddress(0x4000_0000), splitted_regions[0].va);
Imre Kis42935a22024-10-17 11:30:16 +0200596 assert_eq!(0x3000, splitted_regions[0].length);
597 assert!(matches!(
598 splitted_regions[0].physical_region,
599 PhysicalRegion::Unused
600 ));
Imre Kis703482d2023-11-30 15:51:26 +0100601
Imre Kisd5b96fd2024-09-11 17:04:32 +0200602 assert_eq!(VirtualAddress(0x4000_3000), splitted_regions[1].va);
Imre Kis42935a22024-10-17 11:30:16 +0200603 assert_eq!(0x1000, splitted_regions[1].length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200604 assert_eq!(PhysicalAddress(0x8000_0000), splitted_regions[1].get_pa());
Imre Kis42935a22024-10-17 11:30:16 +0200605 assert!(matches!(
606 splitted_regions[1].physical_region,
607 PhysicalRegion::PhysicalAddress(_)
608 ));
609 }
Imre Kis703482d2023-11-30 15:51:26 +0100610
Imre Kis42935a22024-10-17 11:30:16 +0200611 #[test]
612 fn test_virtual_region_create_split_by_unused() {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200613 let region_unused = VirtualRegion::new_with_pa(
614 PhysicalAddress(0x8000_0000),
615 VirtualAddress(0x4000_0000),
616 0x4000,
617 );
Imre Kis703482d2023-11-30 15:51:26 +0100618
Imre Kis42935a22024-10-17 11:30:16 +0200619 // New region at the start
Imre Kisd5b96fd2024-09-11 17:04:32 +0200620 let (new_region, splitted_regions) =
621 region_unused.create_split(VirtualAddress(0x4000_0000), 0x1000, None);
Imre Kis703482d2023-11-30 15:51:26 +0100622
Imre Kisd5b96fd2024-09-11 17:04:32 +0200623 assert_eq!(VirtualAddress(0x4000_0000), new_region.va); // TODO: why do we need explicit type here?
Imre Kis42935a22024-10-17 11:30:16 +0200624 assert_eq!(0x1000, new_region.length);
625 assert!(matches!(new_region.physical_region, PhysicalRegion::Unused));
Imre Kis703482d2023-11-30 15:51:26 +0100626
Imre Kisd5b96fd2024-09-11 17:04:32 +0200627 assert_eq!(VirtualAddress(0x4000_0000), splitted_regions[0].va);
Imre Kis42935a22024-10-17 11:30:16 +0200628 assert_eq!(0x1000, splitted_regions[0].length);
629 assert!(matches!(
630 splitted_regions[0].physical_region,
631 PhysicalRegion::Unused
632 ));
Imre Kis703482d2023-11-30 15:51:26 +0100633
Imre Kisd5b96fd2024-09-11 17:04:32 +0200634 assert_eq!(VirtualAddress(0x4000_1000), splitted_regions[1].va);
Imre Kis42935a22024-10-17 11:30:16 +0200635 assert_eq!(0x3000, splitted_regions[1].length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200636 assert_eq!(PhysicalAddress(0x8000_1000), splitted_regions[1].get_pa());
Imre Kis42935a22024-10-17 11:30:16 +0200637 assert!(matches!(
638 splitted_regions[1].physical_region,
639 PhysicalRegion::PhysicalAddress(_)
640 ));
Imre Kis703482d2023-11-30 15:51:26 +0100641
Imre Kis42935a22024-10-17 11:30:16 +0200642 // New region in the middle
Imre Kisd5b96fd2024-09-11 17:04:32 +0200643 let (new_region, splitted_regions) =
644 region_unused.create_split(VirtualAddress(0x4000_1000), 0x1000, None);
Imre Kis703482d2023-11-30 15:51:26 +0100645
Imre Kisd5b96fd2024-09-11 17:04:32 +0200646 assert_eq!(VirtualAddress(0x4000_1000), new_region.va);
Imre Kis42935a22024-10-17 11:30:16 +0200647 assert_eq!(0x1000, new_region.length);
648 assert!(matches!(new_region.physical_region, PhysicalRegion::Unused));
Imre Kis703482d2023-11-30 15:51:26 +0100649
Imre Kisd5b96fd2024-09-11 17:04:32 +0200650 assert_eq!(VirtualAddress(0x4000_0000), splitted_regions[0].va);
Imre Kis42935a22024-10-17 11:30:16 +0200651 assert_eq!(0x1000, splitted_regions[0].length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200652 assert_eq!(PhysicalAddress(0x8000_0000), splitted_regions[0].get_pa());
Imre Kis42935a22024-10-17 11:30:16 +0200653 assert!(matches!(
654 splitted_regions[0].physical_region,
655 PhysicalRegion::PhysicalAddress(_)
656 ));
Imre Kis703482d2023-11-30 15:51:26 +0100657
Imre Kisd5b96fd2024-09-11 17:04:32 +0200658 assert_eq!(VirtualAddress(0x4000_1000), splitted_regions[1].va);
Imre Kis42935a22024-10-17 11:30:16 +0200659 assert_eq!(0x1000, splitted_regions[1].length);
660 assert!(matches!(
661 splitted_regions[1].physical_region,
662 PhysicalRegion::Unused
663 ));
Imre Kis703482d2023-11-30 15:51:26 +0100664
Imre Kisd5b96fd2024-09-11 17:04:32 +0200665 assert_eq!(VirtualAddress(0x4000_2000), splitted_regions[2].va);
Imre Kis42935a22024-10-17 11:30:16 +0200666 assert_eq!(0x2000, splitted_regions[2].length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200667 assert_eq!(PhysicalAddress(0x8000_2000), splitted_regions[2].get_pa());
Imre Kis42935a22024-10-17 11:30:16 +0200668 assert!(matches!(
669 splitted_regions[2].physical_region,
670 PhysicalRegion::PhysicalAddress(_)
671 ));
Imre Kis703482d2023-11-30 15:51:26 +0100672
Imre Kis42935a22024-10-17 11:30:16 +0200673 // New region at the end
Imre Kisd5b96fd2024-09-11 17:04:32 +0200674 let (new_region, splitted_regions) =
675 region_unused.create_split(VirtualAddress(0x4000_3000), 0x1000, None);
Imre Kis703482d2023-11-30 15:51:26 +0100676
Imre Kisd5b96fd2024-09-11 17:04:32 +0200677 assert_eq!(VirtualAddress(0x4000_3000), new_region.va);
Imre Kis42935a22024-10-17 11:30:16 +0200678 assert_eq!(0x1000, new_region.length);
679 assert!(matches!(new_region.physical_region, PhysicalRegion::Unused));
Imre Kis703482d2023-11-30 15:51:26 +0100680
Imre Kisd5b96fd2024-09-11 17:04:32 +0200681 assert_eq!(VirtualAddress(0x4000_0000), splitted_regions[0].va);
Imre Kis42935a22024-10-17 11:30:16 +0200682 assert_eq!(0x3000, splitted_regions[0].length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200683 assert_eq!(PhysicalAddress(0x8000_0000), splitted_regions[0].get_pa());
Imre Kis42935a22024-10-17 11:30:16 +0200684 assert!(matches!(
685 splitted_regions[0].physical_region,
686 PhysicalRegion::PhysicalAddress(_)
687 ));
Imre Kis703482d2023-11-30 15:51:26 +0100688
Imre Kisd5b96fd2024-09-11 17:04:32 +0200689 assert_eq!(VirtualAddress(0x4000_3000), splitted_regions[1].va);
Imre Kis42935a22024-10-17 11:30:16 +0200690 assert_eq!(0x1000, splitted_regions[1].length);
Imre Kis703482d2023-11-30 15:51:26 +0100691
Imre Kis42935a22024-10-17 11:30:16 +0200692 assert!(matches!(
693 splitted_regions[1].physical_region,
694 PhysicalRegion::Unused
695 ));
696 }
Imre Kis703482d2023-11-30 15:51:26 +0100697
Imre Kis42935a22024-10-17 11:30:16 +0200698 #[test]
699 #[should_panic]
700 fn test_virtual_region_does_not_contain() {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200701 let region = VirtualRegion::new(VirtualAddress(0x4000_0000), 0x1000);
Imre Kis42935a22024-10-17 11:30:16 +0200702 region.create_split(
Imre Kisd5b96fd2024-09-11 17:04:32 +0200703 VirtualAddress(0x8000_0000),
Imre Kis42935a22024-10-17 11:30:16 +0200704 0x1000,
Imre Kisd5b96fd2024-09-11 17:04:32 +0200705 Some(PhysicalRegion::PhysicalAddress(PhysicalAddress(
706 0xc000_0000,
707 ))),
Imre Kis42935a22024-10-17 11:30:16 +0200708 );
709 }
Imre Kis703482d2023-11-30 15:51:26 +0100710
Imre Kis42935a22024-10-17 11:30:16 +0200711 #[test]
712 #[should_panic]
713 fn test_virtual_region_create_split_same_used() {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200714 let region = VirtualRegion::new(VirtualAddress(0x4000_0000), 0x1000);
715 region.create_split(
716 VirtualAddress(0x4000_0000),
717 0x1000,
718 Some(PhysicalRegion::Unused),
719 );
Imre Kis42935a22024-10-17 11:30:16 +0200720 }
Imre Kis703482d2023-11-30 15:51:26 +0100721
Imre Kis42935a22024-10-17 11:30:16 +0200722 #[test]
723 fn test_virtual_region_drop() {
Imre Kis42935a22024-10-17 11:30:16 +0200724 static PAGE_POOL_AREA: PagePoolArea<8192> = PagePoolArea::new();
725 let page_pool = PagePool::new(&PAGE_POOL_AREA);
726 let page = page_pool.allocate_pages(4096).unwrap();
Imre Kis703482d2023-11-30 15:51:26 +0100727
Imre Kis42935a22024-10-17 11:30:16 +0200728 let physical_region = PhysicalRegion::Allocated(page_pool, page);
Imre Kis703482d2023-11-30 15:51:26 +0100729
Imre Kis42935a22024-10-17 11:30:16 +0200730 // Testing physical region drop through virtualregion
Imre Kisd5b96fd2024-09-11 17:04:32 +0200731 let virtual_region =
732 VirtualRegion::new_from_fields(VirtualAddress(0x4000_0000), 1000, physical_region);
Imre Kis42935a22024-10-17 11:30:16 +0200733 drop(virtual_region);
734 }
Imre Kis703482d2023-11-30 15:51:26 +0100735}