blob: 83c54abe3541a8cb7970bdc58c109ac3f1c357b2 [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 Kis703482d2023-11-30 15:51:26 +010087
Imre Kisd5b96fd2024-09-11 17:04:32 +020088 fn base(&self) -> Self::Base {
Imre Kis703482d2023-11-30 15:51:26 +010089 self.va
90 }
91
Imre Kisd5b96fd2024-09-11 17:04:32 +020092 fn length(&self) -> Self::Length {
Imre Kis703482d2023-11-30 15:51:26 +010093 self.length
94 }
95
96 fn used(&self) -> bool {
97 !matches!(self.physical_region, PhysicalRegion::Unused)
98 }
99
Imre Kisd5b96fd2024-09-11 17:04:32 +0200100 fn contains(&self, base: Self::Base, length: Self::Length) -> bool {
Imre Kis703482d2023-11-30 15:51:26 +0100101 if let (Some(end), Some(self_end)) =
Imre Kisd5b96fd2024-09-11 17:04:32 +0200102 (base.add_offset(length), self.va.add_offset(self.length))
Imre Kis703482d2023-11-30 15:51:26 +0100103 {
104 self.va <= base && end <= self_end
105 } else {
106 false
107 }
108 }
109
110 fn try_append(&mut self, other: &Self) -> bool {
111 if let (Some(self_end), Some(new_length)) = (
Imre Kisd5b96fd2024-09-11 17:04:32 +0200112 self.va.add_offset(self.length),
Imre Kis703482d2023-11-30 15:51:26 +0100113 self.length.checked_add(other.length),
114 ) {
115 if self_end == other.va {
116 // VA is consecutive
117 match (&self.physical_region, &other.physical_region) {
118 (PhysicalRegion::Unused, PhysicalRegion::Unused) => {
119 // Unused range can be merged without further conditions
120 self.length = new_length;
121 return true;
122 }
123 (
124 PhysicalRegion::PhysicalAddress(self_pa),
125 PhysicalRegion::PhysicalAddress(other_pa),
126 ) => {
127 // Used ranges can be only merged if the PA doesn't overflow and it is
128 // consecutive
Imre Kisd5b96fd2024-09-11 17:04:32 +0200129 if let Some(self_end_pa) = self_pa.add_offset(self.length) {
Imre Kis703482d2023-11-30 15:51:26 +0100130 if self_end_pa == *other_pa {
131 self.length = new_length;
132 return true;
133 }
134 }
135 }
136
137 // PhyisicalRegion::Allocated instances cannot be merged at the moment. Not sure
138 // if it's a valid use case. If needed the pages has to be merged which might
139 // require tricks to invalidate the pages of 'other'.
140 _ => {}
141 }
142 }
143 }
144
145 false
146 }
147
148 fn create_split(
149 &self,
Imre Kisd5b96fd2024-09-11 17:04:32 +0200150 base: Self::Base,
151 length: Self::Length,
Imre Kis703482d2023-11-30 15:51:26 +0100152 resource: Option<Self::Resource>,
153 ) -> (Self, Vec<Self>) {
154 assert!(self.contains(base, length));
155 assert!(self.used() != resource.is_some());
156
157 if let Some(physical_region) = resource {
158 // Self is unused, setting part of it to used
159 let pa = physical_region.get_pa();
160
161 let mut res = Vec::new();
162 if self.va != base {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200163 res.push(Self::new(self.va, base.diff(self.va).unwrap()));
Imre Kis703482d2023-11-30 15:51:26 +0100164 }
165
166 res.push(Self::new_from_fields(base, length, physical_region));
167
Imre Kisd5b96fd2024-09-11 17:04:32 +0200168 let end = base.add_offset(length).unwrap();
169 let self_end = self.va.add_offset(self.length).unwrap();
Imre Kis703482d2023-11-30 15:51:26 +0100170 if end != self_end {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200171 res.push(Self::new(end, self_end.diff(end).unwrap()));
Imre Kis703482d2023-11-30 15:51:26 +0100172 }
173
174 (
175 Self::new_from_fields(base, length, PhysicalRegion::PhysicalAddress(pa)),
176 res,
177 )
178 } else {
179 // Self is used, mark part of it unused
180 let mut res = Vec::new();
181 if self.va != base {
182 let physical_region = match &self.physical_region {
183 PhysicalRegion::Allocated(_page_pool, _pages) => {
184 todo!("Implement Pages::split");
185 }
186 PhysicalRegion::PhysicalAddress(pa) => PhysicalRegion::PhysicalAddress(*pa),
187 _ => {
188 panic!("Splitting unused region by other unused")
189 }
190 };
191
192 res.push(Self::new_from_fields(
193 self.va,
Imre Kisd5b96fd2024-09-11 17:04:32 +0200194 base.diff(self.va).unwrap(),
Imre Kis703482d2023-11-30 15:51:26 +0100195 physical_region,
196 ));
197 }
198
199 res.push(Self::new(base, length));
200
Imre Kisd5b96fd2024-09-11 17:04:32 +0200201 let end = base.add_offset(length).unwrap();
202 let self_end = self.va.add_offset(self.length).unwrap();
Imre Kis703482d2023-11-30 15:51:26 +0100203 if end != self_end {
204 let physical_region = match &self.physical_region {
205 PhysicalRegion::Allocated(_page_pool, _pages) => {
206 todo!("Implement Pages::split");
207 }
208 PhysicalRegion::PhysicalAddress(pa) => {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200209 let offset = end.diff(self.va).unwrap();
210 PhysicalRegion::PhysicalAddress(pa.add_offset(offset).unwrap())
Imre Kis703482d2023-11-30 15:51:26 +0100211 }
212 _ => {
213 panic!("Splitting unused region by other unused")
214 }
215 };
216
217 res.push(Self::new_from_fields(
218 end,
Imre Kisd5b96fd2024-09-11 17:04:32 +0200219 self_end.diff(end).unwrap(),
Imre Kis703482d2023-11-30 15:51:26 +0100220 physical_region,
221 ));
222 }
223
224 (Self::new(base, length), res)
225 }
226 }
227}
228
229impl Drop for VirtualRegion {
230 /// If the virtual region has a linked physical region which was allocated then release the
231 /// allocated pages.
232 fn drop(&mut self) {
233 let mut physical_region = PhysicalRegion::Unused;
234
235 core::mem::swap(&mut self.physical_region, &mut physical_region);
236
237 if let PhysicalRegion::Allocated(page_pool, pages) = physical_region {
238 debug!(
Imre Kisd5b96fd2024-09-11 17:04:32 +0200239 "Dropping physical region with pages: PA={:#08x} VA={:#08x}",
240 pages.get_pa().0,
241 self.base().0,
Imre Kis703482d2023-11-30 15:51:26 +0100242 );
243
244 page_pool.release_pages(pages).unwrap();
245 }
246 }
247}
248
249#[cfg(test)]
Imre Kis42935a22024-10-17 11:30:16 +0200250mod tests {
Imre Kis42935a22024-10-17 11:30:16 +0200251 use super::*;
Imre Kisd5b96fd2024-09-11 17:04:32 +0200252 use crate::page_pool::PagePoolArea;
Imre Kis703482d2023-11-30 15:51:26 +0100253
Imre Kis42935a22024-10-17 11:30:16 +0200254 #[test]
255 #[should_panic]
256 fn test_physical_region_unused() {
257 let region = PhysicalRegion::Unused;
258 region.get_pa();
259 }
Imre Kis703482d2023-11-30 15:51:26 +0100260
Imre Kis42935a22024-10-17 11:30:16 +0200261 #[test]
262 fn test_physical_region() {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200263 const PA: PhysicalAddress = PhysicalAddress(0x0123_4567_89ab_cdef);
Imre Kis42935a22024-10-17 11:30:16 +0200264 const LENGTH: usize = 0x8000_0000_0000;
Imre Kis703482d2023-11-30 15:51:26 +0100265
Imre Kis42935a22024-10-17 11:30:16 +0200266 static PAGE_POOL_AREA: PagePoolArea<16> = PagePoolArea::new();
Imre Kisd5b96fd2024-09-11 17:04:32 +0200267 let region = PhysicalRegion::Allocated(
268 PagePool::new(&PAGE_POOL_AREA),
269 Pages::new(PA.0, LENGTH, true),
270 );
Imre Kis42935a22024-10-17 11:30:16 +0200271 assert_eq!(PA, region.get_pa());
Imre Kis703482d2023-11-30 15:51:26 +0100272
Imre Kis42935a22024-10-17 11:30:16 +0200273 let region = PhysicalRegion::PhysicalAddress(PA);
274 assert_eq!(PA, region.get_pa());
275 }
Imre Kis703482d2023-11-30 15:51:26 +0100276
Imre Kis42935a22024-10-17 11:30:16 +0200277 #[test]
278 fn test_virtual_region() {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200279 const VA: VirtualAddress = VirtualAddress(0x0123_4567_89ab_cdef);
280 const PA: PhysicalAddress = PhysicalAddress(0xfedc_ba98_7654_3210);
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 let region = VirtualRegion::new(VA, LENGTH);
284 assert_eq!(VA, region.va);
285 assert_eq!(VA, region.base());
286 assert_eq!(LENGTH, region.length);
287 assert_eq!(LENGTH, region.length());
288 assert!(matches!(region.physical_region, PhysicalRegion::Unused));
289 assert!(!region.used());
Imre Kis703482d2023-11-30 15:51:26 +0100290
Imre Kis42935a22024-10-17 11:30:16 +0200291 let region = VirtualRegion::new_with_pa(PA, VA, LENGTH);
292 assert_eq!(VA, region.va);
293 assert_eq!(VA, region.base());
294 assert_eq!(LENGTH, region.length);
295 assert_eq!(LENGTH, region.length());
296 assert!(matches!(
297 region.physical_region,
298 PhysicalRegion::PhysicalAddress(_)
299 ));
300 assert_eq!(PA, region.get_pa());
301 assert!(region.used());
302 }
Imre Kis703482d2023-11-30 15:51:26 +0100303
Imre Kis42935a22024-10-17 11:30:16 +0200304 #[test]
305 fn test_virtual_region_get_pa_for_va() {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200306 let region = VirtualRegion::new_with_pa(
307 PhysicalAddress(0x8000_0000_0000_0000),
308 VirtualAddress(0x4000_0000_0000_0000),
309 0x1000,
Imre Kis42935a22024-10-17 11:30:16 +0200310 );
311 assert_eq!(
Imre Kisd5b96fd2024-09-11 17:04:32 +0200312 PhysicalAddress(0x8000_0000_0000_0000),
313 region.get_pa_for_va(VirtualAddress(0x4000_0000_0000_0000))
Imre Kis42935a22024-10-17 11:30:16 +0200314 );
315 assert_eq!(
Imre Kisd5b96fd2024-09-11 17:04:32 +0200316 PhysicalAddress(0x8000_0000_0000_0001),
317 region.get_pa_for_va(VirtualAddress(0x4000_0000_0000_0001))
318 );
319 assert_eq!(
320 PhysicalAddress(0x8000_0000_0000_0fff),
321 region.get_pa_for_va(VirtualAddress(0x4000_0000_0000_0fff))
Imre Kis42935a22024-10-17 11:30:16 +0200322 );
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_low_va() {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200328 let region = VirtualRegion::new_with_pa(
329 PhysicalAddress(0x8000_0000_0000_0000),
330 VirtualAddress(0x4000_0000_0000_0000),
331 0x1000,
332 );
333 region.get_pa_for_va(VirtualAddress(0x3fff_ffff_ffff_ffff));
Imre Kis42935a22024-10-17 11:30:16 +0200334 }
Imre Kis703482d2023-11-30 15:51:26 +0100335
Imre Kis42935a22024-10-17 11:30:16 +0200336 #[test]
337 #[should_panic]
338 fn test_virtual_region_get_pa_for_va_high_va() {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200339 let region = VirtualRegion::new_with_pa(
340 PhysicalAddress(0x8000_0000_0000_0000),
341 VirtualAddress(0x4000_0000_0000_0000),
342 0x1000,
343 );
344 region.get_pa_for_va(VirtualAddress(0x4000_0000_0000_1000));
Imre Kis42935a22024-10-17 11:30:16 +0200345 }
Imre Kis703482d2023-11-30 15:51:26 +0100346
Imre Kis42935a22024-10-17 11:30:16 +0200347 #[test]
348 fn test_virtual_region_contains() {
349 const VA: usize = 0x8000_0000_0000_0000;
350 const LENGTH: usize = 0x8000_0000_0000;
Imre Kis703482d2023-11-30 15:51:26 +0100351
Imre Kisd5b96fd2024-09-11 17:04:32 +0200352 let region_overflow_end =
353 VirtualRegion::new(VirtualAddress(0x8000_0000_0000_0000), 0x8000_0000_0000_0000);
354 assert!(!region_overflow_end.contains(VirtualAddress(0x8000_0000_0000_0000), 1));
Imre Kis703482d2023-11-30 15:51:26 +0100355
Imre Kisd5b96fd2024-09-11 17:04:32 +0200356 let region =
357 VirtualRegion::new(VirtualAddress(0x4000_0000_0000_0000), 0x8000_0000_0000_0000);
358 assert!(!region.contains(VirtualAddress(0x8000_0000_0000_0000), 0x8000_0000_0000_0000));
Imre Kis703482d2023-11-30 15:51:26 +0100359
Imre Kisd5b96fd2024-09-11 17:04:32 +0200360 assert!(!region.contains(VirtualAddress(0x4000_0000_0000_0000), 0x8000_0000_0000_0001));
361 assert!(!region.contains(VirtualAddress(0x3fff_ffff_ffff_ffff), 0x8000_0000_0000_0000));
362 assert!(region.contains(VirtualAddress(0x4000_0000_0000_0000), 0x8000_0000_0000_0000));
363 assert!(region.contains(VirtualAddress(0x4000_0000_0000_0000), 0x7fff_ffff_ffff_ffff));
364 assert!(region.contains(VirtualAddress(0x4000_0000_0000_0001), 0x7fff_ffff_ffff_ffff));
Imre Kis42935a22024-10-17 11:30:16 +0200365 }
Imre Kis703482d2023-11-30 15:51:26 +0100366
Imre Kis42935a22024-10-17 11:30:16 +0200367 #[test]
368 fn test_virtual_region_try_append() {
369 // Both unused
Imre Kisd5b96fd2024-09-11 17:04:32 +0200370 let mut region_unused0 = VirtualRegion::new(VirtualAddress(0x4000_0000), 0x1000);
371 let mut region_unused1 = VirtualRegion::new(VirtualAddress(0x4000_1000), 0x1000);
Imre Kis703482d2023-11-30 15:51:26 +0100372
Imre Kis42935a22024-10-17 11:30:16 +0200373 assert!(!region_unused1.try_append(&region_unused0));
Imre Kisd5b96fd2024-09-11 17:04:32 +0200374 assert_eq!(VirtualAddress(0x4000_0000), region_unused0.va);
Imre Kis42935a22024-10-17 11:30:16 +0200375 assert_eq!(0x1000, region_unused0.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200376 assert_eq!(VirtualAddress(0x4000_1000), region_unused1.va);
Imre Kis42935a22024-10-17 11:30:16 +0200377 assert_eq!(0x1000, region_unused1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100378
Imre Kis42935a22024-10-17 11:30:16 +0200379 assert!(region_unused0.try_append(&region_unused1));
Imre Kisd5b96fd2024-09-11 17:04:32 +0200380 assert_eq!(VirtualAddress(0x4000_0000), region_unused0.va);
Imre Kis42935a22024-10-17 11:30:16 +0200381 assert_eq!(0x2000, region_unused0.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200382 assert_eq!(VirtualAddress(0x4000_1000), region_unused1.va);
Imre Kis42935a22024-10-17 11:30:16 +0200383 assert_eq!(0x1000, region_unused1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100384
Imre Kis42935a22024-10-17 11:30:16 +0200385 // Unused and PA region
Imre Kisd5b96fd2024-09-11 17:04:32 +0200386 let mut region_unused = VirtualRegion::new(VirtualAddress(0x4000_0000), 0x1000);
387 let region_physical = VirtualRegion::new_with_pa(
388 PhysicalAddress(0x8000_0000),
389 VirtualAddress(0x4000_1000),
390 0x1000,
391 );
Imre Kis42935a22024-10-17 11:30:16 +0200392 assert!(!region_unused.try_append(&region_physical));
Imre Kisd5b96fd2024-09-11 17:04:32 +0200393 assert_eq!(VirtualAddress(0x4000_0000), region_unused.va);
Imre Kis42935a22024-10-17 11:30:16 +0200394 assert_eq!(0x1000, region_unused.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200395 assert_eq!(VirtualAddress(0x4000_1000), region_physical.va);
Imre Kis42935a22024-10-17 11:30:16 +0200396 assert_eq!(0x1000, region_physical.length);
Imre Kis703482d2023-11-30 15:51:26 +0100397
Imre Kis42935a22024-10-17 11:30:16 +0200398 // Both PA regions but non-consecutive PA ranges
Imre Kisd5b96fd2024-09-11 17:04:32 +0200399 let mut region_physical0 = VirtualRegion::new_with_pa(
400 PhysicalAddress(0x8000_0000),
401 VirtualAddress(0x4000_0000),
402 0x1000,
403 );
404 let region_physical1 = VirtualRegion::new_with_pa(
405 PhysicalAddress(0x9000_0000),
406 VirtualAddress(0x4000_1000),
407 0x1000,
408 );
Imre Kis42935a22024-10-17 11:30:16 +0200409 assert!(!region_physical0.try_append(&region_physical1));
Imre Kisd5b96fd2024-09-11 17:04:32 +0200410 assert_eq!(VirtualAddress(0x4000_0000), region_physical0.va);
Imre Kis42935a22024-10-17 11:30:16 +0200411 assert_eq!(0x1000, region_physical0.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200412 assert_eq!(VirtualAddress(0x4000_1000), region_physical1.va);
Imre Kis42935a22024-10-17 11:30:16 +0200413 assert_eq!(0x1000, region_physical1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100414
Imre Kis42935a22024-10-17 11:30:16 +0200415 // Both PA regions with consecutive PA ranges
Imre Kisd5b96fd2024-09-11 17:04:32 +0200416 let mut region_physical0 = VirtualRegion::new_with_pa(
417 PhysicalAddress(0x8000_0000),
418 VirtualAddress(0x4000_0000),
419 0x1000,
420 );
421 let region_physical1 = VirtualRegion::new_with_pa(
422 PhysicalAddress(0x8000_1000),
423 VirtualAddress(0x4000_1000),
424 0x1000,
425 );
Imre Kis42935a22024-10-17 11:30:16 +0200426 assert!(region_physical0.try_append(&region_physical1));
Imre Kisd5b96fd2024-09-11 17:04:32 +0200427 assert_eq!(VirtualAddress(0x4000_0000), region_physical0.va);
Imre Kis42935a22024-10-17 11:30:16 +0200428 assert_eq!(0x2000, region_physical0.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200429 assert_eq!(VirtualAddress(0x4000_1000), region_physical1.va);
Imre Kis42935a22024-10-17 11:30:16 +0200430 assert_eq!(0x1000, region_physical1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100431
Imre Kis42935a22024-10-17 11:30:16 +0200432 // VA overflow
Imre Kisd5b96fd2024-09-11 17:04:32 +0200433 let mut region_unused0: VirtualRegion =
434 VirtualRegion::new(VirtualAddress(0x8000_0000_0000_0000), 0x8000_0000_0000_0000);
435 let mut region_unused1 = VirtualRegion::new(VirtualAddress(0x4000_1000), 0x1000);
Imre Kis703482d2023-11-30 15:51:26 +0100436
Imre Kis42935a22024-10-17 11:30:16 +0200437 assert!(!region_unused0.try_append(&region_unused1));
Imre Kisd5b96fd2024-09-11 17:04:32 +0200438 assert_eq!(VirtualAddress(0x8000_0000_0000_0000), region_unused0.va);
Imre Kis42935a22024-10-17 11:30:16 +0200439 assert_eq!(0x8000_0000_0000_0000, region_unused0.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200440 assert_eq!(VirtualAddress(0x4000_1000), region_unused1.va);
Imre Kis42935a22024-10-17 11:30:16 +0200441 assert_eq!(0x1000, region_unused1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100442
Imre Kis42935a22024-10-17 11:30:16 +0200443 assert!(!region_unused1.try_append(&region_unused0));
Imre Kisd5b96fd2024-09-11 17:04:32 +0200444 assert_eq!(VirtualAddress(0x8000_0000_0000_0000), region_unused0.va);
Imre Kis42935a22024-10-17 11:30:16 +0200445 assert_eq!(0x8000_0000_0000_0000, region_unused0.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200446 assert_eq!(VirtualAddress(0x4000_1000), region_unused1.va);
Imre Kis42935a22024-10-17 11:30:16 +0200447 assert_eq!(0x1000, region_unused1.length);
Imre Kis703482d2023-11-30 15:51:26 +0100448
Imre Kis42935a22024-10-17 11:30:16 +0200449 // PA overflow
Imre Kisd5b96fd2024-09-11 17:04:32 +0200450 let mut region_physical0 = VirtualRegion::new_with_pa(
451 PhysicalAddress(0x8000_0000_0000_0000),
452 VirtualAddress(0x4000_0000),
453 0x8000_0000_0000_0000,
454 );
455 let region_physical1 = VirtualRegion::new_with_pa(
456 PhysicalAddress(0x9000_0000),
457 VirtualAddress(0x8000_0000_4000_0000),
458 0x1000,
459 );
Imre Kis42935a22024-10-17 11:30:16 +0200460 assert!(!region_physical0.try_append(&region_physical1));
Imre Kisd5b96fd2024-09-11 17:04:32 +0200461 assert_eq!(VirtualAddress(0x4000_0000), region_physical0.va);
Imre Kis42935a22024-10-17 11:30:16 +0200462 assert_eq!(0x8000_0000_0000_0000, region_physical0.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200463 assert_eq!(VirtualAddress(0x8000_0000_4000_0000), region_physical1.va);
Imre Kis42935a22024-10-17 11:30:16 +0200464 assert_eq!(0x1000, region_physical1.length);
465 }
Imre Kis703482d2023-11-30 15:51:26 +0100466
Imre Kis42935a22024-10-17 11:30:16 +0200467 #[test]
468 fn test_virtual_region_create_split_by_used() {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200469 let region_unused = VirtualRegion::new(VirtualAddress(0x4000_0000), 0x4000);
Imre Kis703482d2023-11-30 15:51:26 +0100470
Imre Kis42935a22024-10-17 11:30:16 +0200471 // New region at the start
472 let (new_region, splitted_regions) = region_unused.create_split(
Imre Kisd5b96fd2024-09-11 17:04:32 +0200473 VirtualAddress(0x4000_0000),
Imre Kis42935a22024-10-17 11:30:16 +0200474 0x1000,
Imre Kisd5b96fd2024-09-11 17:04:32 +0200475 Some(PhysicalRegion::PhysicalAddress(PhysicalAddress(
476 0x8000_0000,
477 ))),
Imre Kis42935a22024-10-17 11:30:16 +0200478 );
Imre Kis703482d2023-11-30 15:51:26 +0100479
Imre Kisd5b96fd2024-09-11 17:04:32 +0200480 assert_eq!(VirtualAddress(0x4000_0000), new_region.va);
Imre Kis42935a22024-10-17 11:30:16 +0200481 assert_eq!(0x1000, new_region.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200482 assert_eq!(PhysicalAddress(0x8000_0000), new_region.get_pa());
Imre Kis42935a22024-10-17 11:30:16 +0200483 assert!(matches!(
484 new_region.physical_region,
485 PhysicalRegion::PhysicalAddress(_)
486 ));
Imre Kis703482d2023-11-30 15:51:26 +0100487
Imre Kisd5b96fd2024-09-11 17:04:32 +0200488 assert_eq!(VirtualAddress(0x4000_0000), splitted_regions[0].va);
Imre Kis42935a22024-10-17 11:30:16 +0200489 assert_eq!(0x1000, splitted_regions[0].length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200490 assert_eq!(PhysicalAddress(0x8000_0000), splitted_regions[0].get_pa());
Imre Kis42935a22024-10-17 11:30:16 +0200491 assert!(matches!(
492 splitted_regions[0].physical_region,
493 PhysicalRegion::PhysicalAddress(_)
494 ));
Imre Kis703482d2023-11-30 15:51:26 +0100495
Imre Kisd5b96fd2024-09-11 17:04:32 +0200496 assert_eq!(VirtualAddress(0x4000_1000), splitted_regions[1].va);
Imre Kis42935a22024-10-17 11:30:16 +0200497 assert_eq!(0x3000, splitted_regions[1].length);
498 assert!(matches!(
499 splitted_regions[1].physical_region,
500 PhysicalRegion::Unused
501 ));
Imre Kis703482d2023-11-30 15:51:26 +0100502
Imre Kis42935a22024-10-17 11:30:16 +0200503 // New region in the middle
504 let (new_region, splitted_regions) = region_unused.create_split(
Imre Kisd5b96fd2024-09-11 17:04:32 +0200505 VirtualAddress(0x4000_1000),
Imre Kis42935a22024-10-17 11:30:16 +0200506 0x1000,
Imre Kisd5b96fd2024-09-11 17:04:32 +0200507 Some(PhysicalRegion::PhysicalAddress(PhysicalAddress(
508 0x8000_0000,
509 ))),
Imre Kis42935a22024-10-17 11:30:16 +0200510 );
Imre Kis703482d2023-11-30 15:51:26 +0100511
Imre Kisd5b96fd2024-09-11 17:04:32 +0200512 assert_eq!(VirtualAddress(0x4000_1000), new_region.va);
Imre Kis42935a22024-10-17 11:30:16 +0200513 assert_eq!(0x1000, new_region.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200514 assert_eq!(PhysicalAddress(0x8000_0000), new_region.get_pa());
Imre Kis42935a22024-10-17 11:30:16 +0200515 assert!(matches!(
516 new_region.physical_region,
517 PhysicalRegion::PhysicalAddress(_)
518 ));
Imre Kis703482d2023-11-30 15:51:26 +0100519
Imre Kisd5b96fd2024-09-11 17:04:32 +0200520 assert_eq!(VirtualAddress(0x4000_0000), splitted_regions[0].va);
Imre Kis42935a22024-10-17 11:30:16 +0200521 assert_eq!(0x1000, splitted_regions[0].length);
522 assert!(matches!(
523 splitted_regions[0].physical_region,
524 PhysicalRegion::Unused
525 ));
Imre Kis703482d2023-11-30 15:51:26 +0100526
Imre Kisd5b96fd2024-09-11 17:04:32 +0200527 assert_eq!(VirtualAddress(0x4000_1000), splitted_regions[1].va);
Imre Kis42935a22024-10-17 11:30:16 +0200528 assert_eq!(0x1000, splitted_regions[1].length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200529 assert_eq!(PhysicalAddress(0x8000_0000), splitted_regions[1].get_pa());
Imre Kis42935a22024-10-17 11:30:16 +0200530 assert!(matches!(
531 splitted_regions[1].physical_region,
532 PhysicalRegion::PhysicalAddress(_)
533 ));
Imre Kis703482d2023-11-30 15:51:26 +0100534
Imre Kisd5b96fd2024-09-11 17:04:32 +0200535 assert_eq!(VirtualAddress(0x4000_2000), splitted_regions[2].va);
Imre Kis42935a22024-10-17 11:30:16 +0200536 assert_eq!(0x2000, splitted_regions[2].length);
537 assert!(matches!(
538 splitted_regions[2].physical_region,
539 PhysicalRegion::Unused
540 ));
Imre Kis703482d2023-11-30 15:51:26 +0100541
Imre Kis42935a22024-10-17 11:30:16 +0200542 // New region at the end
543 let (new_region, splitted_regions) = region_unused.create_split(
Imre Kisd5b96fd2024-09-11 17:04:32 +0200544 VirtualAddress(0x4000_3000),
Imre Kis42935a22024-10-17 11:30:16 +0200545 0x1000,
Imre Kisd5b96fd2024-09-11 17:04:32 +0200546 Some(PhysicalRegion::PhysicalAddress(PhysicalAddress(
547 0x8000_0000,
548 ))),
Imre Kis42935a22024-10-17 11:30:16 +0200549 );
Imre Kis703482d2023-11-30 15:51:26 +0100550
Imre Kisd5b96fd2024-09-11 17:04:32 +0200551 assert_eq!(VirtualAddress(0x4000_3000), new_region.va);
Imre Kis42935a22024-10-17 11:30:16 +0200552 assert_eq!(0x1000, new_region.length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200553 assert_eq!(PhysicalAddress(0x8000_0000), new_region.get_pa());
Imre Kis42935a22024-10-17 11:30:16 +0200554 assert!(matches!(
555 new_region.physical_region,
556 PhysicalRegion::PhysicalAddress(_)
557 ));
Imre Kis703482d2023-11-30 15:51:26 +0100558
Imre Kisd5b96fd2024-09-11 17:04:32 +0200559 assert_eq!(VirtualAddress(0x4000_0000), splitted_regions[0].va);
Imre Kis42935a22024-10-17 11:30:16 +0200560 assert_eq!(0x3000, splitted_regions[0].length);
561 assert!(matches!(
562 splitted_regions[0].physical_region,
563 PhysicalRegion::Unused
564 ));
Imre Kis703482d2023-11-30 15:51:26 +0100565
Imre Kisd5b96fd2024-09-11 17:04:32 +0200566 assert_eq!(VirtualAddress(0x4000_3000), splitted_regions[1].va);
Imre Kis42935a22024-10-17 11:30:16 +0200567 assert_eq!(0x1000, splitted_regions[1].length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200568 assert_eq!(PhysicalAddress(0x8000_0000), splitted_regions[1].get_pa());
Imre Kis42935a22024-10-17 11:30:16 +0200569 assert!(matches!(
570 splitted_regions[1].physical_region,
571 PhysicalRegion::PhysicalAddress(_)
572 ));
573 }
Imre Kis703482d2023-11-30 15:51:26 +0100574
Imre Kis42935a22024-10-17 11:30:16 +0200575 #[test]
576 fn test_virtual_region_create_split_by_unused() {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200577 let region_unused = VirtualRegion::new_with_pa(
578 PhysicalAddress(0x8000_0000),
579 VirtualAddress(0x4000_0000),
580 0x4000,
581 );
Imre Kis703482d2023-11-30 15:51:26 +0100582
Imre Kis42935a22024-10-17 11:30:16 +0200583 // New region at the start
Imre Kisd5b96fd2024-09-11 17:04:32 +0200584 let (new_region, splitted_regions) =
585 region_unused.create_split(VirtualAddress(0x4000_0000), 0x1000, None);
Imre Kis703482d2023-11-30 15:51:26 +0100586
Imre Kisd5b96fd2024-09-11 17:04:32 +0200587 assert_eq!(VirtualAddress(0x4000_0000), new_region.va); // TODO: why do we need explicit type here?
Imre Kis42935a22024-10-17 11:30:16 +0200588 assert_eq!(0x1000, new_region.length);
589 assert!(matches!(new_region.physical_region, PhysicalRegion::Unused));
Imre Kis703482d2023-11-30 15:51:26 +0100590
Imre Kisd5b96fd2024-09-11 17:04:32 +0200591 assert_eq!(VirtualAddress(0x4000_0000), splitted_regions[0].va);
Imre Kis42935a22024-10-17 11:30:16 +0200592 assert_eq!(0x1000, splitted_regions[0].length);
593 assert!(matches!(
594 splitted_regions[0].physical_region,
595 PhysicalRegion::Unused
596 ));
Imre Kis703482d2023-11-30 15:51:26 +0100597
Imre Kisd5b96fd2024-09-11 17:04:32 +0200598 assert_eq!(VirtualAddress(0x4000_1000), splitted_regions[1].va);
Imre Kis42935a22024-10-17 11:30:16 +0200599 assert_eq!(0x3000, splitted_regions[1].length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200600 assert_eq!(PhysicalAddress(0x8000_1000), splitted_regions[1].get_pa());
Imre Kis42935a22024-10-17 11:30:16 +0200601 assert!(matches!(
602 splitted_regions[1].physical_region,
603 PhysicalRegion::PhysicalAddress(_)
604 ));
Imre Kis703482d2023-11-30 15:51:26 +0100605
Imre Kis42935a22024-10-17 11:30:16 +0200606 // New region in the middle
Imre Kisd5b96fd2024-09-11 17:04:32 +0200607 let (new_region, splitted_regions) =
608 region_unused.create_split(VirtualAddress(0x4000_1000), 0x1000, None);
Imre Kis703482d2023-11-30 15:51:26 +0100609
Imre Kisd5b96fd2024-09-11 17:04:32 +0200610 assert_eq!(VirtualAddress(0x4000_1000), new_region.va);
Imre Kis42935a22024-10-17 11:30:16 +0200611 assert_eq!(0x1000, new_region.length);
612 assert!(matches!(new_region.physical_region, PhysicalRegion::Unused));
Imre Kis703482d2023-11-30 15:51:26 +0100613
Imre Kisd5b96fd2024-09-11 17:04:32 +0200614 assert_eq!(VirtualAddress(0x4000_0000), splitted_regions[0].va);
Imre Kis42935a22024-10-17 11:30:16 +0200615 assert_eq!(0x1000, splitted_regions[0].length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200616 assert_eq!(PhysicalAddress(0x8000_0000), splitted_regions[0].get_pa());
Imre Kis42935a22024-10-17 11:30:16 +0200617 assert!(matches!(
618 splitted_regions[0].physical_region,
619 PhysicalRegion::PhysicalAddress(_)
620 ));
Imre Kis703482d2023-11-30 15:51:26 +0100621
Imre Kisd5b96fd2024-09-11 17:04:32 +0200622 assert_eq!(VirtualAddress(0x4000_1000), splitted_regions[1].va);
Imre Kis42935a22024-10-17 11:30:16 +0200623 assert_eq!(0x1000, splitted_regions[1].length);
624 assert!(matches!(
625 splitted_regions[1].physical_region,
626 PhysicalRegion::Unused
627 ));
Imre Kis703482d2023-11-30 15:51:26 +0100628
Imre Kisd5b96fd2024-09-11 17:04:32 +0200629 assert_eq!(VirtualAddress(0x4000_2000), splitted_regions[2].va);
Imre Kis42935a22024-10-17 11:30:16 +0200630 assert_eq!(0x2000, splitted_regions[2].length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200631 assert_eq!(PhysicalAddress(0x8000_2000), splitted_regions[2].get_pa());
Imre Kis42935a22024-10-17 11:30:16 +0200632 assert!(matches!(
633 splitted_regions[2].physical_region,
634 PhysicalRegion::PhysicalAddress(_)
635 ));
Imre Kis703482d2023-11-30 15:51:26 +0100636
Imre Kis42935a22024-10-17 11:30:16 +0200637 // New region at the end
Imre Kisd5b96fd2024-09-11 17:04:32 +0200638 let (new_region, splitted_regions) =
639 region_unused.create_split(VirtualAddress(0x4000_3000), 0x1000, None);
Imre Kis703482d2023-11-30 15:51:26 +0100640
Imre Kisd5b96fd2024-09-11 17:04:32 +0200641 assert_eq!(VirtualAddress(0x4000_3000), new_region.va);
Imre Kis42935a22024-10-17 11:30:16 +0200642 assert_eq!(0x1000, new_region.length);
643 assert!(matches!(new_region.physical_region, PhysicalRegion::Unused));
Imre Kis703482d2023-11-30 15:51:26 +0100644
Imre Kisd5b96fd2024-09-11 17:04:32 +0200645 assert_eq!(VirtualAddress(0x4000_0000), splitted_regions[0].va);
Imre Kis42935a22024-10-17 11:30:16 +0200646 assert_eq!(0x3000, splitted_regions[0].length);
Imre Kisd5b96fd2024-09-11 17:04:32 +0200647 assert_eq!(PhysicalAddress(0x8000_0000), splitted_regions[0].get_pa());
Imre Kis42935a22024-10-17 11:30:16 +0200648 assert!(matches!(
649 splitted_regions[0].physical_region,
650 PhysicalRegion::PhysicalAddress(_)
651 ));
Imre Kis703482d2023-11-30 15:51:26 +0100652
Imre Kisd5b96fd2024-09-11 17:04:32 +0200653 assert_eq!(VirtualAddress(0x4000_3000), splitted_regions[1].va);
Imre Kis42935a22024-10-17 11:30:16 +0200654 assert_eq!(0x1000, splitted_regions[1].length);
Imre Kis703482d2023-11-30 15:51:26 +0100655
Imre Kis42935a22024-10-17 11:30:16 +0200656 assert!(matches!(
657 splitted_regions[1].physical_region,
658 PhysicalRegion::Unused
659 ));
660 }
Imre Kis703482d2023-11-30 15:51:26 +0100661
Imre Kis42935a22024-10-17 11:30:16 +0200662 #[test]
663 #[should_panic]
664 fn test_virtual_region_does_not_contain() {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200665 let region = VirtualRegion::new(VirtualAddress(0x4000_0000), 0x1000);
Imre Kis42935a22024-10-17 11:30:16 +0200666 region.create_split(
Imre Kisd5b96fd2024-09-11 17:04:32 +0200667 VirtualAddress(0x8000_0000),
Imre Kis42935a22024-10-17 11:30:16 +0200668 0x1000,
Imre Kisd5b96fd2024-09-11 17:04:32 +0200669 Some(PhysicalRegion::PhysicalAddress(PhysicalAddress(
670 0xc000_0000,
671 ))),
Imre Kis42935a22024-10-17 11:30:16 +0200672 );
673 }
Imre Kis703482d2023-11-30 15:51:26 +0100674
Imre Kis42935a22024-10-17 11:30:16 +0200675 #[test]
676 #[should_panic]
677 fn test_virtual_region_create_split_same_used() {
Imre Kisd5b96fd2024-09-11 17:04:32 +0200678 let region = VirtualRegion::new(VirtualAddress(0x4000_0000), 0x1000);
679 region.create_split(
680 VirtualAddress(0x4000_0000),
681 0x1000,
682 Some(PhysicalRegion::Unused),
683 );
Imre Kis42935a22024-10-17 11:30:16 +0200684 }
Imre Kis703482d2023-11-30 15:51:26 +0100685
Imre Kis42935a22024-10-17 11:30:16 +0200686 #[test]
687 fn test_virtual_region_drop() {
Imre Kis42935a22024-10-17 11:30:16 +0200688 static PAGE_POOL_AREA: PagePoolArea<8192> = PagePoolArea::new();
689 let page_pool = PagePool::new(&PAGE_POOL_AREA);
690 let page = page_pool.allocate_pages(4096).unwrap();
Imre Kis703482d2023-11-30 15:51:26 +0100691
Imre Kis42935a22024-10-17 11:30:16 +0200692 let physical_region = PhysicalRegion::Allocated(page_pool, page);
Imre Kis703482d2023-11-30 15:51:26 +0100693
Imre Kis42935a22024-10-17 11:30:16 +0200694 // Testing physical region drop through virtualregion
Imre Kisd5b96fd2024-09-11 17:04:32 +0200695 let virtual_region =
696 VirtualRegion::new_from_fields(VirtualAddress(0x4000_0000), 1000, physical_region);
Imre Kis42935a22024-10-17 11:30:16 +0200697 drop(virtual_region);
698 }
Imre Kis703482d2023-11-30 15:51:26 +0100699}