1use crate::host_params::MAX_NUMA_NODES;
7use crate::host_params::MAX_VTL2_RAM_RANGES;
8use crate::single_threaded::off_stack;
9use arrayvec::ArrayVec;
10use host_fdt_parser::MemoryEntry;
11#[cfg(test)]
12use igvm_defs::MemoryMapEntryType;
13use loader_defs::shim::MemoryVtlType;
14use memory_range::MemoryRange;
15use memory_range::RangeWalkResult;
16use memory_range::walk_ranges;
17use thiserror::Error;
18
19const PAGE_SIZE_4K: u64 = 4096;
20
21pub const MAX_RESERVED_MEM_RANGES: usize = 6 + sidecar_defs::MAX_NODES;
24
25const MAX_MEMORY_RANGES: usize = MAX_VTL2_RAM_RANGES + MAX_RESERVED_MEM_RANGES;
26
27const MAX_ADDRESS_RANGES: usize = MAX_MEMORY_RANGES * 2;
30
31#[derive(Clone, Copy, Debug, PartialEq, Eq)]
32pub enum ReservedMemoryType {
33 Vtl2Config,
35 Vtl2Reserved,
38 SidecarImage,
40 SidecarNode,
42 Vtl2GpaPool,
45 TdxPageTables,
47 BootshimLogBuffer,
49 PersistedStateHeader,
51 PersistedStatePayload,
53}
54
55impl From<ReservedMemoryType> for MemoryVtlType {
56 fn from(r: ReservedMemoryType) -> Self {
57 match r {
58 ReservedMemoryType::Vtl2Config => MemoryVtlType::VTL2_CONFIG,
59 ReservedMemoryType::SidecarImage => MemoryVtlType::VTL2_SIDECAR_IMAGE,
60 ReservedMemoryType::SidecarNode => MemoryVtlType::VTL2_SIDECAR_NODE,
61 ReservedMemoryType::Vtl2Reserved => MemoryVtlType::VTL2_RESERVED,
62 ReservedMemoryType::Vtl2GpaPool => MemoryVtlType::VTL2_GPA_POOL,
63 ReservedMemoryType::TdxPageTables => MemoryVtlType::VTL2_TDX_PAGE_TABLES,
64 ReservedMemoryType::BootshimLogBuffer => MemoryVtlType::VTL2_BOOTSHIM_LOG_BUFFER,
65 ReservedMemoryType::PersistedStateHeader => MemoryVtlType::VTL2_PERSISTED_STATE_HEADER,
66 ReservedMemoryType::PersistedStatePayload => {
67 MemoryVtlType::VTL2_PERSISTED_STATE_PROTOBUF
68 }
69 }
70 }
71}
72
73#[derive(Clone, Copy, Debug, PartialEq, Eq)]
74enum AddressUsage {
75 Free,
77 Used,
79 Reserved(ReservedMemoryType),
81}
82
83#[derive(Debug)]
84struct AddressRange {
85 range: MemoryRange,
86 vnode: u32,
87 usage: AddressUsage,
88}
89
90impl From<AddressUsage> for MemoryVtlType {
91 fn from(usage: AddressUsage) -> Self {
92 match usage {
93 AddressUsage::Free => MemoryVtlType::VTL2_RAM,
94 AddressUsage::Used => MemoryVtlType::VTL2_RAM,
95 AddressUsage::Reserved(r) => r.into(),
96 }
97 }
98}
99
100#[derive(Debug, Clone, Copy)]
101pub struct AllocatedRange {
102 pub range: MemoryRange,
103 pub vnode: u32,
104}
105
106#[derive(Debug, Error)]
107pub enum Error {
108 #[error("ram len {len} greater than maximum {max}")]
109 RamLen { len: u64, max: u64 },
110 #[error("already initialized")]
111 AlreadyInitialized,
112 #[error(
113 "reserved range {reserved:#x?}, type {typ:?} outside of bootshim used {bootshim_used:#x?}"
114 )]
115 ReservedRangeOutsideBootshimUsed {
116 reserved: MemoryRange,
117 typ: ReservedMemoryType,
118 bootshim_used: MemoryRange,
119 },
120}
121
122#[derive(Debug)]
123pub struct AddressSpaceManager {
124 address_space: ArrayVec<AddressRange, MAX_ADDRESS_RANGES>,
126
127 vtl2_pool: bool,
129}
130
131pub struct AddressSpaceManagerBuilder<'a, I: Iterator<Item = MemoryRange>> {
133 manager: &'a mut AddressSpaceManager,
134 vtl2_ram: &'a [MemoryEntry],
135 bootshim_used: MemoryRange,
136 persisted_state_region: MemoryRange,
137 vtl2_config: I,
138 reserved_range: Option<MemoryRange>,
139 sidecar_image: Option<MemoryRange>,
140 page_tables: Option<MemoryRange>,
141 log_buffer: Option<MemoryRange>,
142 pool_ranges: ArrayVec<MemoryRange, MAX_NUMA_NODES>,
143}
144
145impl<'a, I: Iterator<Item = MemoryRange>> AddressSpaceManagerBuilder<'a, I> {
146 pub fn new(
159 manager: &'a mut AddressSpaceManager,
160 vtl2_ram: &'a [MemoryEntry],
161 bootshim_used: MemoryRange,
162 persisted_state_region: MemoryRange,
163 vtl2_config: I,
164 ) -> AddressSpaceManagerBuilder<'a, I> {
165 AddressSpaceManagerBuilder {
166 manager,
167 vtl2_ram,
168 bootshim_used,
169 persisted_state_region,
170 vtl2_config,
171 reserved_range: None,
172 sidecar_image: None,
173 page_tables: None,
174 log_buffer: None,
175 pool_ranges: ArrayVec::new(),
176 }
177 }
178
179 pub fn with_reserved_range(mut self, reserved_range: MemoryRange) -> Self {
181 self.reserved_range = Some(reserved_range);
182 self
183 }
184
185 pub fn with_sidecar_image(mut self, sidecar_image: MemoryRange) -> Self {
187 self.sidecar_image = Some(sidecar_image);
188 self
189 }
190
191 pub fn with_log_buffer(mut self, log_buffer: MemoryRange) -> Self {
193 self.log_buffer = Some(log_buffer);
194 self
195 }
196
197 pub fn with_pool_ranges(mut self, pool_ranges: impl Iterator<Item = MemoryRange>) -> Self {
203 assert!(
204 self.pool_ranges.is_empty(),
205 "pool ranges already set on builder"
206 );
207 self.pool_ranges.extend(pool_ranges);
208 self
209 }
210
211 pub fn init(self) -> Result<&'a mut AddressSpaceManager, Error> {
213 let Self {
214 manager,
215 vtl2_ram,
216 bootshim_used,
217 persisted_state_region,
218 vtl2_config,
219 reserved_range,
220 sidecar_image,
221 page_tables,
222 log_buffer,
223 pool_ranges,
224 } = self;
225
226 if vtl2_ram.len() > MAX_VTL2_RAM_RANGES {
227 return Err(Error::RamLen {
228 len: vtl2_ram.len() as u64,
229 max: MAX_VTL2_RAM_RANGES as u64,
230 });
231 }
232
233 if !manager.address_space.is_empty() {
234 return Err(Error::AlreadyInitialized);
235 }
236
237 let (persisted_header, persisted_payload) =
241 persisted_state_region.split_at_offset(PAGE_SIZE_4K);
242
243 const MAX_RESERVED_RANGES: usize = 20;
245 let mut reserved = off_stack!(ArrayVec<(MemoryRange, ReservedMemoryType), MAX_RESERVED_RANGES>, ArrayVec::new_const());
246 reserved.clear();
247 reserved.push((persisted_header, ReservedMemoryType::PersistedStateHeader));
248 reserved.push((persisted_payload, ReservedMemoryType::PersistedStatePayload));
249 reserved.extend(vtl2_config.map(|r| (r, ReservedMemoryType::Vtl2Config)));
250 reserved.extend(
251 reserved_range
252 .into_iter()
253 .map(|r| (r, ReservedMemoryType::Vtl2Reserved)),
254 );
255 reserved.extend(
256 sidecar_image
257 .into_iter()
258 .map(|r| (r, ReservedMemoryType::SidecarImage)),
259 );
260 reserved.extend(
261 page_tables
262 .into_iter()
263 .map(|r| (r, ReservedMemoryType::TdxPageTables)),
264 );
265 reserved.extend(
266 log_buffer
267 .into_iter()
268 .map(|r| (r, ReservedMemoryType::BootshimLogBuffer)),
269 );
270 reserved.sort_unstable_by_key(|(r, _)| r.start());
271
272 const MAX_USED_RANGES: usize = MAX_RESERVED_RANGES + MAX_NUMA_NODES;
275 let mut used_ranges = off_stack!(ArrayVec<(MemoryRange, AddressUsage), MAX_USED_RANGES>, ArrayVec::new_const());
276 used_ranges.clear();
277
278 for (entry, r) in walk_ranges(
281 core::iter::once((bootshim_used, AddressUsage::Used)),
282 reserved.iter().cloned(),
283 ) {
284 match r {
285 RangeWalkResult::Left(_) => {
286 used_ranges.push((entry, AddressUsage::Used));
287 }
288 RangeWalkResult::Both(_, reserved_type) => {
289 used_ranges.push((entry, AddressUsage::Reserved(reserved_type)));
290 }
291 RangeWalkResult::Right(typ) => {
292 return Err(Error::ReservedRangeOutsideBootshimUsed {
293 reserved: entry,
294 typ,
295 bootshim_used,
296 });
297 }
298 RangeWalkResult::Neither => {}
299 }
300 }
301
302 for range in pool_ranges {
304 used_ranges.push((
305 range,
306 AddressUsage::Reserved(ReservedMemoryType::Vtl2GpaPool),
307 ));
308 manager.vtl2_pool = true;
309 }
310 used_ranges.sort_unstable_by_key(|(r, _)| r.start());
311
312 assert!(manager.address_space.is_empty());
314 for (entry, r) in walk_ranges(
315 vtl2_ram.iter().map(|e| (e.range, e.vnode)),
316 used_ranges.iter().map(|(r, usage)| (*r, usage)),
317 ) {
318 match r {
319 RangeWalkResult::Left(vnode) => {
320 manager.address_space.push(AddressRange {
322 range: entry,
323 vnode,
324 usage: AddressUsage::Free,
325 });
326 }
327 RangeWalkResult::Both(vnode, usage) => {
328 manager.address_space.push(AddressRange {
330 range: entry,
331 vnode,
332 usage: *usage,
333 });
334 }
335 RangeWalkResult::Right(usage) => {
336 panic!("vtl2 range {entry:#x?} used by {usage:?} not contained in vtl2 ram");
337 }
338 RangeWalkResult::Neither => {}
339 }
340 }
341
342 Ok(manager)
343 }
344}
345
346impl AddressSpaceManager {
347 pub const fn new_const() -> Self {
348 Self {
349 address_space: ArrayVec::new_const(),
350 vtl2_pool: false,
351 }
352 }
353
354 fn allocate_range(
360 &mut self,
361 index: usize,
362 len: u64,
363 usage: AddressUsage,
364 allocation_policy: AllocationPolicy,
365 alignment: Option<u64>,
366 ) -> AllocatedRange {
367 assert!(usage != AddressUsage::Free);
368 let range = self.address_space.get_mut(index).expect("valid index");
369 assert_eq!(range.usage, AddressUsage::Free);
370
371 let subrange = if let Some(alignment) = alignment {
372 range.range.aligned_subrange(alignment)
373 } else {
374 range.range
375 };
376
377 assert!(subrange.len() >= len);
378 assert_ne!(subrange, MemoryRange::EMPTY);
379
380 let used = match allocation_policy {
381 AllocationPolicy::LowMemory => {
382 let (used, _) = subrange.split_at_offset(len);
384 used
385 }
386 AllocationPolicy::HighMemory => {
387 let offset = subrange.len() - len;
389 let (_, used) = subrange.split_at_offset(offset);
390 used
391 }
392 };
393
394 let left = MemoryRange::new(range.range.start()..used.start());
395 let right = MemoryRange::new(used.end()..range.range.end());
396
397 let to_address_range = |r: MemoryRange| -> Option<AddressRange> {
398 if !r.is_empty() {
399 Some(AddressRange {
400 range: r,
401 vnode: range.vnode,
402 usage: AddressUsage::Free,
403 })
404 } else {
405 None
406 }
407 };
408
409 let left = to_address_range(left);
410 let right = to_address_range(right);
411
412 range.usage = usage;
414 range.range = used;
415 let allocated = AllocatedRange {
416 range: used,
417 vnode: range.vnode,
418 };
419
420 if let Some(right) = right {
421 self.address_space.insert(index + 1, right);
422 }
423
424 if let Some(left) = left {
425 self.address_space.insert(index, left);
426 }
427
428 allocated
429 }
430
431 fn allocate_inner(
432 &mut self,
433 required_vnode: Option<u32>,
434 len: u64,
435 allocation_type: AllocationType,
436 allocation_policy: AllocationPolicy,
437 alignment: Option<u64>,
438 ) -> Option<AllocatedRange> {
439 if len == 0 {
440 return None;
441 }
442
443 let len = len.div_ceil(PAGE_SIZE_4K) * PAGE_SIZE_4K;
446
447 fn find_index<'a>(
448 mut iter: impl Iterator<Item = (usize, &'a AddressRange)>,
449 preferred_vnode: Option<u32>,
450 len: u64,
451 alignment: Option<u64>,
452 ) -> Option<usize> {
453 iter.find_map(|(index, range)| {
454 let is_aligned: bool = alignment.is_none()
455 || (alignment.is_some()
456 && range.range.aligned_subrange(alignment.unwrap()).len() >= len);
457 if range.usage == AddressUsage::Free
458 && range.range.len() >= len
459 && preferred_vnode.map(|pv| pv == range.vnode).unwrap_or(true)
460 && is_aligned
461 {
462 Some(index)
463 } else {
464 None
465 }
466 })
467 }
468
469 let index = {
471 let iter = self.address_space.iter().enumerate();
472 match allocation_policy {
473 AllocationPolicy::LowMemory => find_index(iter, required_vnode, len, alignment),
474 AllocationPolicy::HighMemory => {
475 find_index(iter.rev(), required_vnode, len, alignment)
476 }
477 }
478 };
479
480 let address_usage = match allocation_type {
481 AllocationType::GpaPool => AddressUsage::Reserved(ReservedMemoryType::Vtl2GpaPool),
482 AllocationType::SidecarNode => AddressUsage::Reserved(ReservedMemoryType::SidecarNode),
483 AllocationType::TdxPageTables => {
484 AddressUsage::Reserved(ReservedMemoryType::TdxPageTables)
485 }
486 };
487
488 let alloc = index.map(|index| {
489 self.allocate_range(index, len, address_usage, allocation_policy, alignment)
490 });
491
492 if allocation_type == AllocationType::GpaPool && alloc.is_some() {
493 self.vtl2_pool = true;
494 }
495
496 alloc
497 }
498
499 pub fn allocate(
509 &mut self,
510 required_vnode: Option<u32>,
511 len: u64,
512 allocation_type: AllocationType,
513 allocation_policy: AllocationPolicy,
514 ) -> Option<AllocatedRange> {
515 self.allocate_inner(
516 required_vnode,
517 len,
518 allocation_type,
519 allocation_policy,
520 None,
521 )
522 }
523
524 #[cfg_attr(all(target_arch = "aarch64", not(test)), expect(dead_code))]
537 pub fn allocate_aligned(
538 &mut self,
539 required_vnode: Option<u32>,
540 len: u64,
541 allocation_type: AllocationType,
542 allocation_policy: AllocationPolicy,
543 alignment: u64,
544 ) -> Option<AllocatedRange> {
545 self.allocate_inner(
546 required_vnode,
547 len,
548 allocation_type,
549 allocation_policy,
550 Some(alignment),
551 )
552 }
553
554 pub fn vtl2_ranges(&self) -> impl Iterator<Item = (MemoryRange, MemoryVtlType)> + use<'_> {
556 memory_range::merge_adjacent_ranges(
557 self.address_space.iter().map(|r| (r.range, r.usage.into())),
558 )
559 }
560
561 pub fn reserved_vtl2_ranges(
564 &self,
565 ) -> impl Iterator<Item = (MemoryRange, ReservedMemoryType)> + use<'_> {
566 self.address_space.iter().filter_map(|r| match r.usage {
567 AddressUsage::Reserved(typ) => Some((r.range, typ)),
568 _ => None,
569 })
570 }
571
572 pub fn free_ranges(&self, vnode: u32) -> impl Iterator<Item = MemoryRange> + use<'_> {
575 self.address_space.iter().filter_map(move |r| {
576 if r.usage == AddressUsage::Free && r.vnode == vnode {
577 Some(r.range)
578 } else {
579 None
580 }
581 })
582 }
583
584 pub fn has_vtl2_pool(&self) -> bool {
586 self.vtl2_pool
587 }
588}
589
590#[derive(Debug, Clone, Copy, PartialEq, Eq)]
591pub enum AllocationType {
592 GpaPool,
593 SidecarNode,
594 #[cfg_attr(target_arch = "aarch64", expect(dead_code))]
595 TdxPageTables,
596}
597
598pub enum AllocationPolicy {
599 LowMemory,
601 HighMemory,
603}
604
605#[cfg(test)]
606mod tests {
607 use super::*;
608
609 #[test]
610 fn test_allocate() {
611 let mut address_space = AddressSpaceManager::new_const();
612 let vtl2_ram = &[MemoryEntry {
613 range: MemoryRange::new(0x0..0x20000),
614 vnode: 0,
615 mem_type: MemoryMapEntryType::MEMORY,
616 }];
617
618 AddressSpaceManagerBuilder::new(
619 &mut address_space,
620 vtl2_ram,
621 MemoryRange::new(0x0..0xF000),
622 MemoryRange::new(0x0..0x2000),
623 [
624 MemoryRange::new(0x3000..0x4000),
625 MemoryRange::new(0x5000..0x6000),
626 ]
627 .iter()
628 .cloned(),
629 )
630 .with_reserved_range(MemoryRange::new(0x8000..0xA000))
631 .with_sidecar_image(MemoryRange::new(0xA000..0xC000))
632 .init()
633 .unwrap();
634
635 let range = address_space
636 .allocate(
637 None,
638 0x1000,
639 AllocationType::GpaPool,
640 AllocationPolicy::HighMemory,
641 )
642 .unwrap();
643 assert_eq!(range.range, MemoryRange::new(0x1F000..0x20000));
644 assert!(address_space.has_vtl2_pool());
645
646 let range = address_space
647 .allocate(
648 None,
649 0x2000,
650 AllocationType::GpaPool,
651 AllocationPolicy::HighMemory,
652 )
653 .unwrap();
654 assert_eq!(range.range, MemoryRange::new(0x1D000..0x1F000));
655
656 let range = address_space
657 .allocate(
658 None,
659 0x3000,
660 AllocationType::GpaPool,
661 AllocationPolicy::LowMemory,
662 )
663 .unwrap();
664 assert_eq!(range.range, MemoryRange::new(0xF000..0x12000));
665
666 let range = address_space
667 .allocate(
668 None,
669 0x1000,
670 AllocationType::GpaPool,
671 AllocationPolicy::LowMemory,
672 )
673 .unwrap();
674 assert_eq!(range.range, MemoryRange::new(0x12000..0x13000));
675
676 let free_ranges: Vec<MemoryRange> = address_space.free_ranges(0).collect();
677 assert_eq!(free_ranges, vec![MemoryRange::new(0x13000..0x1D000)]);
678 }
679
680 #[test]
681 fn test_allocate_aligned() {
682 let mut address_space = AddressSpaceManager::new_const();
683 let vtl2_ram = &[MemoryEntry {
684 range: MemoryRange::new(0x0..0x20000),
685 vnode: 0,
686 mem_type: MemoryMapEntryType::MEMORY,
687 }];
688
689 AddressSpaceManagerBuilder::new(
690 &mut address_space,
691 vtl2_ram,
692 MemoryRange::new(0x0..0xF000),
693 MemoryRange::new(0x0..0x2000),
694 [
695 MemoryRange::new(0x3000..0x4000),
696 MemoryRange::new(0x5000..0x6000),
697 ]
698 .iter()
699 .cloned(),
700 )
701 .with_reserved_range(MemoryRange::new(0x8000..0xA000))
702 .with_sidecar_image(MemoryRange::new(0xA000..0xC000))
703 .init()
704 .unwrap();
705
706 let alignment = 4096 * 16;
707 let range = address_space
708 .allocate_aligned(
709 None,
710 0x1000,
711 AllocationType::GpaPool,
712 AllocationPolicy::LowMemory,
713 alignment,
714 )
715 .unwrap();
716
717 assert_eq!(0, range.range.start() % alignment);
718
719 let alignment = 4096 * 4;
720 let range = address_space
721 .allocate_aligned(
722 None,
723 0x1000,
724 AllocationType::GpaPool,
725 AllocationPolicy::HighMemory,
726 alignment,
727 )
728 .unwrap();
729
730 assert_eq!(0, range.range.end() % alignment);
731 }
732
733 #[test]
734 fn test_failed_alignment() {
735 let mut address_space = AddressSpaceManager::new_const();
736 let vtl2_ram = &[MemoryEntry {
737 range: MemoryRange::new(0x0..0x20000),
738 vnode: 0,
739 mem_type: MemoryMapEntryType::MEMORY,
740 }];
741
742 AddressSpaceManagerBuilder::new(
743 &mut address_space,
744 vtl2_ram,
745 MemoryRange::new(0x0..0xF000),
746 MemoryRange::new(0x0..0x2000),
747 [
748 MemoryRange::new(0x3000..0x4000),
749 MemoryRange::new(0x5000..0x6000),
750 ]
751 .iter()
752 .cloned(),
753 )
754 .with_reserved_range(MemoryRange::new(0x8000..0xA000))
755 .with_sidecar_image(MemoryRange::new(0xA000..0xC000))
756 .init()
757 .unwrap();
758
759 let alignment = 1024 * 1024 * 2;
760 let range = address_space.allocate_aligned(
761 None,
762 0x1000,
763 AllocationType::GpaPool,
764 AllocationPolicy::LowMemory,
765 alignment,
766 );
767 assert!(range.is_none());
768 }
769
770 #[test]
772 fn test_allocate_numa() {
773 let mut address_space = AddressSpaceManager::new_const();
774 let vtl2_ram = &[
775 MemoryEntry {
776 range: MemoryRange::new(0x0..0x20000),
777 vnode: 0,
778 mem_type: MemoryMapEntryType::MEMORY,
779 },
780 MemoryEntry {
781 range: MemoryRange::new(0x20000..0x40000),
782 vnode: 1,
783 mem_type: MemoryMapEntryType::MEMORY,
784 },
785 MemoryEntry {
786 range: MemoryRange::new(0x40000..0x60000),
787 vnode: 2,
788 mem_type: MemoryMapEntryType::MEMORY,
789 },
790 MemoryEntry {
791 range: MemoryRange::new(0x60000..0x80000),
792 vnode: 3,
793 mem_type: MemoryMapEntryType::MEMORY,
794 },
795 ];
796
797 AddressSpaceManagerBuilder::new(
798 &mut address_space,
799 vtl2_ram,
800 MemoryRange::new(0x0..0x10000),
801 MemoryRange::new(0x0..0x2000),
802 [
803 MemoryRange::new(0x3000..0x4000),
804 MemoryRange::new(0x5000..0x6000),
805 ]
806 .iter()
807 .cloned(),
808 )
809 .with_reserved_range(MemoryRange::new(0x8000..0xA000))
810 .with_sidecar_image(MemoryRange::new(0xA000..0xC000))
811 .init()
812 .unwrap();
813
814 let range = address_space
815 .allocate(
816 Some(0),
817 0x1000,
818 AllocationType::GpaPool,
819 AllocationPolicy::HighMemory,
820 )
821 .unwrap();
822 assert_eq!(range.range, MemoryRange::new(0x1F000..0x20000));
823 assert_eq!(range.vnode, 0);
824
825 let range = address_space
826 .allocate(
827 Some(0),
828 0x2000,
829 AllocationType::SidecarNode,
830 AllocationPolicy::HighMemory,
831 )
832 .unwrap();
833 assert_eq!(range.range, MemoryRange::new(0x1D000..0x1F000));
834 assert_eq!(range.vnode, 0);
835
836 let range = address_space
837 .allocate(
838 Some(2),
839 0x3000,
840 AllocationType::GpaPool,
841 AllocationPolicy::HighMemory,
842 )
843 .unwrap();
844 assert_eq!(range.range, MemoryRange::new(0x5D000..0x60000));
845 assert_eq!(range.vnode, 2);
846
847 let range = address_space
849 .allocate(
850 Some(3),
851 0x20000,
852 AllocationType::SidecarNode,
853 AllocationPolicy::HighMemory,
854 )
855 .unwrap();
856 assert_eq!(range.range, MemoryRange::new(0x60000..0x80000));
857 assert_eq!(range.vnode, 3);
858
859 let range = address_space.allocate(
860 Some(3),
861 0x1000,
862 AllocationType::SidecarNode,
863 AllocationPolicy::HighMemory,
864 );
865 assert!(
866 range.is_none(),
867 "allocation should fail, no space left for node 3"
868 );
869 }
870
871 #[test]
873 fn test_unaligned_allocations() {
874 let mut address_space = AddressSpaceManager::new_const();
875 let vtl2_ram = &[MemoryEntry {
876 range: MemoryRange::new(0x0..0x20000),
877 vnode: 0,
878 mem_type: MemoryMapEntryType::MEMORY,
879 }];
880
881 AddressSpaceManagerBuilder::new(
882 &mut address_space,
883 vtl2_ram,
884 MemoryRange::new(0x0..0xF000),
885 MemoryRange::new(0x0..0x2000),
886 [
887 MemoryRange::new(0x3000..0x4000),
888 MemoryRange::new(0x5000..0x6000),
889 ]
890 .iter()
891 .cloned(),
892 )
893 .with_reserved_range(MemoryRange::new(0x8000..0xA000))
894 .with_sidecar_image(MemoryRange::new(0xA000..0xC000))
895 .init()
896 .unwrap();
897
898 let range = address_space
899 .allocate(
900 None,
901 0x1001,
902 AllocationType::GpaPool,
903 AllocationPolicy::HighMemory,
904 )
905 .unwrap();
906 assert_eq!(range.range, MemoryRange::new(0x1E000..0x20000));
907
908 let range = address_space
909 .allocate(
910 None,
911 0xFFF,
912 AllocationType::GpaPool,
913 AllocationPolicy::HighMemory,
914 )
915 .unwrap();
916 assert_eq!(range.range, MemoryRange::new(0x1D000..0x1E000));
917
918 let range = address_space.allocate(
919 None,
920 0,
921 AllocationType::GpaPool,
922 AllocationPolicy::HighMemory,
923 );
924 assert!(range.is_none());
925 }
926
927 #[test]
929 fn test_invalid_init_ranges() {
930 let vtl2_ram = [MemoryEntry {
931 range: MemoryRange::new(0x0..0x20000),
932 vnode: 0,
933 mem_type: MemoryMapEntryType::MEMORY,
934 }];
935 let bootshim_used = MemoryRange::new(0x0..0xF000);
936
937 let mut address_space = AddressSpaceManager::new_const();
939
940 let result = AddressSpaceManagerBuilder::new(
941 &mut address_space,
942 &vtl2_ram,
943 bootshim_used,
944 MemoryRange::new(0x0..0x2000),
945 [MemoryRange::new(0x10000..0x11000)].iter().cloned(), )
947 .init();
948
949 assert!(matches!(
950 result,
951 Err(Error::ReservedRangeOutsideBootshimUsed { .. })
952 ));
953
954 let mut address_space = AddressSpaceManager::new_const();
957 let result = AddressSpaceManagerBuilder::new(
958 &mut address_space,
959 &vtl2_ram,
960 bootshim_used,
961 MemoryRange::new(0x0..0x2000),
962 [MemoryRange::new(0xE000..0x10000)].iter().cloned(), )
964 .init();
965
966 assert!(matches!(
967 result,
968 Err(Error::ReservedRangeOutsideBootshimUsed { .. })
969 ));
970
971 let mut address_space = AddressSpaceManager::new_const();
973 let result = AddressSpaceManagerBuilder::new(
974 &mut address_space,
975 &vtl2_ram,
976 bootshim_used,
977 MemoryRange::new(0x10000..0x14000), [MemoryRange::new(0xE000..0xF000)].iter().cloned(),
979 )
980 .init();
981
982 assert!(matches!(
983 result,
984 Err(Error::ReservedRangeOutsideBootshimUsed { .. })
985 ));
986 }
987
988 #[test]
989 fn test_persisted_range() {
990 let vtl2_ram = [MemoryEntry {
991 range: MemoryRange::new(0x0..0x20000),
992 vnode: 0,
993 mem_type: MemoryMapEntryType::MEMORY,
994 }];
995 let bootshim_used = MemoryRange::new(0x0..0xF000);
996
997 let mut address_space = AddressSpaceManager::new_const();
998 AddressSpaceManagerBuilder::new(
999 &mut address_space,
1000 &vtl2_ram,
1001 bootshim_used,
1002 MemoryRange::new(0x0..0xE000),
1003 [MemoryRange::new(0xE000..0xF000)].iter().cloned(),
1004 )
1005 .init()
1006 .unwrap();
1007
1008 let expected = [
1009 (
1010 MemoryRange::new(0x0..0x1000),
1011 MemoryVtlType::VTL2_PERSISTED_STATE_HEADER,
1012 ),
1013 (
1014 MemoryRange::new(0x1000..0xE000),
1015 MemoryVtlType::VTL2_PERSISTED_STATE_PROTOBUF,
1016 ),
1017 (MemoryRange::new(0xE000..0xF000), MemoryVtlType::VTL2_CONFIG),
1018 (MemoryRange::new(0xF000..0x20000), MemoryVtlType::VTL2_RAM),
1019 ];
1020
1021 for (expected, actual) in expected.iter().zip(address_space.vtl2_ranges()) {
1022 assert_eq!(*expected, actual);
1023 }
1024
1025 let mut address_space = AddressSpaceManager::new_const();
1027 AddressSpaceManagerBuilder::new(
1028 &mut address_space,
1029 &vtl2_ram,
1030 bootshim_used,
1031 MemoryRange::new(0x0..0xA000),
1032 [MemoryRange::new(0xE000..0xF000)].iter().cloned(),
1033 )
1034 .init()
1035 .unwrap();
1036
1037 let expected = [
1038 (
1039 MemoryRange::new(0x0..0x1000),
1040 MemoryVtlType::VTL2_PERSISTED_STATE_HEADER,
1041 ),
1042 (
1043 MemoryRange::new(0x1000..0xA000),
1044 MemoryVtlType::VTL2_PERSISTED_STATE_PROTOBUF,
1045 ),
1046 (MemoryRange::new(0xA000..0xE000), MemoryVtlType::VTL2_RAM),
1047 (MemoryRange::new(0xE000..0xF000), MemoryVtlType::VTL2_CONFIG),
1048 (MemoryRange::new(0xF000..0x20000), MemoryVtlType::VTL2_RAM),
1049 ];
1050
1051 for (expected, actual) in expected.iter().zip(address_space.vtl2_ranges()) {
1052 assert_eq!(*expected, actual);
1053 }
1054 }
1055
1056 #[test]
1059 fn test_single_pool_range() {
1060 let mut address_space = AddressSpaceManager::new_const();
1061 let vtl2_ram = &[MemoryEntry {
1062 range: MemoryRange::new(0x0..0x20000),
1063 vnode: 0,
1064 mem_type: MemoryMapEntryType::MEMORY,
1065 }];
1066
1067 AddressSpaceManagerBuilder::new(
1068 &mut address_space,
1069 vtl2_ram,
1070 MemoryRange::new(0x0..0x4000),
1071 MemoryRange::new(0x0..0x2000),
1072 core::iter::empty(),
1073 )
1074 .with_pool_ranges([MemoryRange::new(0x10000..0x18000)].into_iter())
1075 .init()
1076 .unwrap();
1077
1078 assert!(address_space.has_vtl2_pool());
1079
1080 let reserved: Vec<_> = address_space.reserved_vtl2_ranges().collect();
1082 assert!(
1083 reserved
1084 .iter()
1085 .any(|(r, t)| *r == MemoryRange::new(0x10000..0x18000)
1086 && *t == ReservedMemoryType::Vtl2GpaPool)
1087 );
1088 }
1089
1090 #[test]
1091 fn test_multiple_pool_ranges() {
1092 let mut address_space = AddressSpaceManager::new_const();
1093 let vtl2_ram = &[
1094 MemoryEntry {
1095 range: MemoryRange::new(0x0..0x20000),
1096 vnode: 0,
1097 mem_type: MemoryMapEntryType::MEMORY,
1098 },
1099 MemoryEntry {
1100 range: MemoryRange::new(0x100000..0x120000),
1101 vnode: 1,
1102 mem_type: MemoryMapEntryType::MEMORY,
1103 },
1104 ];
1105
1106 AddressSpaceManagerBuilder::new(
1107 &mut address_space,
1108 vtl2_ram,
1109 MemoryRange::new(0x0..0x4000),
1110 MemoryRange::new(0x0..0x2000),
1111 core::iter::empty(),
1112 )
1113 .with_pool_ranges(
1114 [
1115 MemoryRange::new(0x10000..0x18000),
1116 MemoryRange::new(0x110000..0x118000),
1117 ]
1118 .into_iter(),
1119 )
1120 .init()
1121 .unwrap();
1122
1123 assert!(address_space.has_vtl2_pool());
1124
1125 let reserved: Vec<_> = address_space
1127 .reserved_vtl2_ranges()
1128 .filter(|(_, t)| *t == ReservedMemoryType::Vtl2GpaPool)
1129 .collect();
1130 assert_eq!(reserved.len(), 2);
1131 assert_eq!(reserved[0].0, MemoryRange::new(0x10000..0x18000));
1132 assert_eq!(reserved[1].0, MemoryRange::new(0x110000..0x118000));
1133 }
1134
1135 #[test]
1136 fn test_allocate_pool_single_numa_node() {
1137 let mut address_space = AddressSpaceManager::new_const();
1140 let vtl2_ram = &[MemoryEntry {
1141 range: MemoryRange::new(0x0..0x100000),
1142 vnode: 0,
1143 mem_type: MemoryMapEntryType::MEMORY,
1144 }];
1145
1146 AddressSpaceManagerBuilder::new(
1147 &mut address_space,
1148 vtl2_ram,
1149 MemoryRange::new(0x0..0x4000),
1150 MemoryRange::new(0x0..0x2000),
1151 core::iter::empty(),
1152 )
1153 .init()
1154 .unwrap();
1155
1156 let pool = address_space
1158 .allocate(
1159 Some(0),
1160 0x10000,
1161 AllocationType::GpaPool,
1162 AllocationPolicy::HighMemory,
1163 )
1164 .unwrap();
1165 assert_eq!(pool.vnode, 0);
1166 assert_eq!(pool.range.len(), 0x10000);
1167 assert!(address_space.has_vtl2_pool());
1168 }
1169
1170 #[test]
1171 fn test_allocate_pool_two_numa_nodes_node0_fits() {
1172 let mut address_space = AddressSpaceManager::new_const();
1175 let vtl2_ram = &[
1176 MemoryEntry {
1177 range: MemoryRange::new(0x0..0x100000),
1178 vnode: 0,
1179 mem_type: MemoryMapEntryType::MEMORY,
1180 },
1181 MemoryEntry {
1182 range: MemoryRange::new(0x200000..0x300000),
1183 vnode: 1,
1184 mem_type: MemoryMapEntryType::MEMORY,
1185 },
1186 ];
1187
1188 AddressSpaceManagerBuilder::new(
1189 &mut address_space,
1190 vtl2_ram,
1191 MemoryRange::new(0x0..0x4000),
1192 MemoryRange::new(0x0..0x2000),
1193 core::iter::empty(),
1194 )
1195 .init()
1196 .unwrap();
1197
1198 let pool = address_space
1200 .allocate(
1201 Some(0),
1202 0x10000,
1203 AllocationType::GpaPool,
1204 AllocationPolicy::HighMemory,
1205 )
1206 .unwrap();
1207 assert_eq!(pool.vnode, 0);
1208 assert_eq!(pool.range.len(), 0x10000);
1209 }
1210
1211 #[test]
1212 fn test_allocate_pool_two_numa_nodes_node0_exhausted() {
1213 let mut address_space = AddressSpaceManager::new_const();
1215 let vtl2_ram = &[
1216 MemoryEntry {
1217 range: MemoryRange::new(0x0..0x4000),
1218 vnode: 0,
1219 mem_type: MemoryMapEntryType::MEMORY,
1220 },
1221 MemoryEntry {
1222 range: MemoryRange::new(0x200000..0x300000),
1223 vnode: 1,
1224 mem_type: MemoryMapEntryType::MEMORY,
1225 },
1226 ];
1227
1228 AddressSpaceManagerBuilder::new(
1229 &mut address_space,
1230 vtl2_ram,
1231 MemoryRange::new(0x0..0x4000),
1232 MemoryRange::new(0x0..0x2000),
1233 core::iter::empty(),
1234 )
1235 .init()
1236 .unwrap();
1237
1238 assert!(
1240 address_space
1241 .allocate(
1242 Some(0),
1243 0x10000,
1244 AllocationType::GpaPool,
1245 AllocationPolicy::HighMemory,
1246 )
1247 .is_none()
1248 );
1249
1250 let pool = address_space
1252 .allocate(
1253 Some(1),
1254 0x10000,
1255 AllocationType::GpaPool,
1256 AllocationPolicy::HighMemory,
1257 )
1258 .unwrap();
1259 assert_eq!(pool.vnode, 1);
1260 assert_eq!(pool.range.len(), 0x10000);
1261 }
1262}