From e5835fdc75fc4cb73361df5967adb488f8d4c2c0 Mon Sep 17 00:00:00 2001 From: Yu Li Date: Wed, 7 Jun 2023 12:01:17 +0800 Subject: [PATCH] arch: let `arch_memory_regions` return all available regions The previous `arch_memory_regions` function will provide some memory regions with the specified memory size and fill all the previous regions before using the next one, but sometimes there may be no need to fill up the previous one, e.g., the previous one should be aligned with hugepage size. This commit make `arch_memory_regions` function not take any parameters and return the max available regions, the memory manager can use them on demand. Fixes: #5463 Signed-off-by: Yu Li --- arch/src/aarch64/mod.rs | 68 ++++++--------------- arch/src/x86_64/mod.rs | 121 ++++++++++---------------------------- vmm/src/memory_manager.rs | 2 +- 3 files changed, 51 insertions(+), 140 deletions(-) diff --git a/arch/src/aarch64/mod.rs b/arch/src/aarch64/mod.rs index 124b8cbe9..45b8114d4 100644 --- a/arch/src/aarch64/mod.rs +++ b/arch/src/aarch64/mod.rs @@ -19,7 +19,7 @@ use std::collections::HashMap; use std::convert::TryInto; use std::fmt::Debug; use std::sync::{Arc, Mutex}; -use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic, GuestUsize}; +use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic}; pub const _NSIG: i32 = 65; @@ -83,8 +83,8 @@ pub fn configure_vcpu( Ok(mpidr) } -pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> { - let mut regions = vec![ +pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> { + vec![ // 0 MiB ~ 256 MiB: UEFI, GIC and legacy devices ( GuestAddress(0), @@ -103,39 +103,21 @@ pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, Region layout::PCI_MMCONFIG_SIZE as usize, RegionType::Reserved, ), - ]; - - let ram_32bit_space_size = - layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START); - - // RAM space - // Case1: guest memory fits before the gap - if size <= ram_32bit_space_size { - regions.push((layout::RAM_START, size as usize, RegionType::Ram)); - // Case2: guest memory extends beyond the gap - } else { - // Push memory before the gap - regions.push(( + // 1GiB ~ 4032 MiB: RAM before the gap + ( layout::RAM_START, - ram_32bit_space_size as usize, + layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START) as usize, RegionType::Ram, - )); - // Other memory is placed after 4GiB - regions.push(( - layout::RAM_64BIT_START, - (size - ram_32bit_space_size) as usize, - RegionType::Ram, - )); - } - - // Add the 32-bit reserved memory hole as a reserved region - regions.push(( - layout::MEM_32BIT_RESERVED_START, - layout::MEM_32BIT_RESERVED_SIZE as usize, - RegionType::Reserved, - )); - - regions + ), + // 4GiB ~ inf: RAM after the gap + (layout::RAM_64BIT_START, usize::MAX, RegionType::Ram), + // Add the 32-bit reserved memory hole as a reserved region + ( + layout::MEM_32BIT_RESERVED_START, + layout::MEM_32BIT_RESERVED_SIZE as usize, + RegionType::Reserved, + ), + ] } /// Configures the system and should be called once per vm before starting vcpu threads. @@ -217,26 +199,12 @@ mod tests { use super::*; #[test] - fn test_arch_memory_regions_dram_2gb() { - let regions = arch_memory_regions((1usize << 31) as u64); //2GB - assert_eq!(5, regions.len()); - assert_eq!(layout::RAM_START, regions[3].0); - assert_eq!((1usize << 31), regions[3].1); - assert_eq!(RegionType::Ram, regions[3].2); - assert_eq!(RegionType::Reserved, regions[4].2); - } - - #[test] - fn test_arch_memory_regions_dram_4gb() { - let regions = arch_memory_regions((1usize << 32) as u64); //4GB - let ram_32bit_space_size = - layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START) as usize; + fn test_arch_memory_regions_dram() { + let regions = arch_memory_regions(); assert_eq!(6, regions.len()); assert_eq!(layout::RAM_START, regions[3].0); - assert_eq!(ram_32bit_space_size, regions[3].1); assert_eq!(RegionType::Ram, regions[3].2); assert_eq!(RegionType::Reserved, regions[5].2); assert_eq!(RegionType::Ram, regions[4].2); - assert_eq!(((1usize << 32) - ram_32bit_space_size), regions[4].1); } } diff --git a/arch/src/x86_64/mod.rs b/arch/src/x86_64/mod.rs index b0c9ab913..3e335035f 100644 --- a/arch/src/x86_64/mod.rs +++ b/arch/src/x86_64/mod.rs @@ -834,47 +834,29 @@ pub fn configure_vcpu( /// These should be used to configure the GuestMemory structure for the platform. /// For x86_64 all addresses are valid from the start of the kernel except a /// carve out at the end of 32bit address space. -pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> { - let reserved_memory_gap_start = layout::MEM_32BIT_RESERVED_START - .checked_add(layout::MEM_32BIT_DEVICES_SIZE) - .expect("32-bit reserved region is too large"); - - let requested_memory_size = GuestAddress(size); - let mut regions = Vec::new(); - - // case1: guest memory fits before the gap - if size <= layout::MEM_32BIT_RESERVED_START.raw_value() { - regions.push((GuestAddress(0), size as usize, RegionType::Ram)); - // case2: guest memory extends beyond the gap - } else { - // push memory before the gap - regions.push(( +pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> { + vec![ + // 0 GiB ~ 3GiB: memory before the gap + ( GuestAddress(0), layout::MEM_32BIT_RESERVED_START.raw_value() as usize, RegionType::Ram, - )); - regions.push(( - layout::RAM_64BIT_START, - requested_memory_size.unchecked_offset_from(layout::MEM_32BIT_RESERVED_START) as usize, - RegionType::Ram, - )); - } - - // Add the 32-bit device memory hole as a sub region. - regions.push(( - layout::MEM_32BIT_RESERVED_START, - layout::MEM_32BIT_DEVICES_SIZE as usize, - RegionType::SubRegion, - )); - - // Add the 32-bit reserved memory hole as a sub region. - regions.push(( - reserved_memory_gap_start, - (layout::MEM_32BIT_RESERVED_SIZE - layout::MEM_32BIT_DEVICES_SIZE) as usize, - RegionType::Reserved, - )); - - regions + ), + // 4 GiB ~ inf: memory after the gap + (layout::RAM_64BIT_START, usize::MAX, RegionType::Ram), + // 3 GiB ~ 3712 MiB: 32-bit device memory hole + ( + layout::MEM_32BIT_RESERVED_START, + layout::MEM_32BIT_DEVICES_SIZE as usize, + RegionType::SubRegion, + ), + // 3712 MiB ~ 3968 MiB: 32-bit reserved memory hole + ( + layout::MEM_32BIT_RESERVED_START.unchecked_add(layout::MEM_32BIT_DEVICES_SIZE), + (layout::MEM_32BIT_RESERVED_SIZE - layout::MEM_32BIT_DEVICES_SIZE) as usize, + RegionType::Reserved, + ), + ] } /// Configures the system and should be called once per vm before starting vcpu threads. @@ -1256,16 +1238,8 @@ mod tests { use super::*; #[test] - fn regions_lt_4gb() { - let regions = arch_memory_regions(1 << 29); - assert_eq!(3, regions.len()); - assert_eq!(GuestAddress(0), regions[0].0); - assert_eq!(1usize << 29, regions[0].1); - } - - #[test] - fn regions_gt_4gb() { - let regions = arch_memory_regions((1 << 32) + 0x8000); + fn regions_base_addr() { + let regions = arch_memory_regions(); assert_eq!(4, regions.len()); assert_eq!(GuestAddress(0), regions[0].0); assert_eq!(GuestAddress(1 << 32), regions[1].0); @@ -1289,11 +1263,10 @@ mod tests { assert!(config_err.is_err()); // Now assigning some memory that falls before the 32bit memory hole. - let mem_size = 128 << 20; - let arch_mem_regions = arch_memory_regions(mem_size); + let arch_mem_regions = arch_memory_regions(); let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions .iter() - .filter(|r| r.2 == RegionType::Ram) + .filter(|r| r.2 == RegionType::Ram && r.1 != usize::MAX) .map(|r| (r.0, r.1)) .collect(); let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap(); @@ -1311,48 +1284,18 @@ mod tests { ) .unwrap(); - // Now assigning some memory that is equal to the start of the 32bit memory hole. - let mem_size = 3328 << 20; - let arch_mem_regions = arch_memory_regions(mem_size); - let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions - .iter() - .filter(|r| r.2 == RegionType::Ram) - .map(|r| (r.0, r.1)) - .collect(); - let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap(); - configure_system( - &gm, - GuestAddress(0), - &None, - no_vcpus, - None, - None, - None, - None, - None, - ) - .unwrap(); - - configure_system( - &gm, - GuestAddress(0), - &None, - no_vcpus, - None, - None, - None, - None, - None, - ) - .unwrap(); - // Now assigning some memory that falls after the 32bit memory hole. - let mem_size = 3330 << 20; - let arch_mem_regions = arch_memory_regions(mem_size); + let arch_mem_regions = arch_memory_regions(); let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions .iter() .filter(|r| r.2 == RegionType::Ram) - .map(|r| (r.0, r.1)) + .map(|r| { + if r.1 == usize::MAX { + (r.0, 128 << 20) + } else { + (r.0, r.1) + } + }) .collect(); let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap(); configure_system( diff --git a/vmm/src/memory_manager.rs b/vmm/src/memory_manager.rs index 48d7626cf..1e9c22272 100644 --- a/vmm/src/memory_manager.rs +++ b/vmm/src/memory_manager.rs @@ -933,7 +933,7 @@ impl MemoryManager { ) } else { // Init guest memory - let arch_mem_regions = arch::arch_memory_regions(ram_size); + let arch_mem_regions = arch::arch_memory_regions(); let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions .iter()