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 <liyu.yukiteru@bytedance.com>
This commit is contained in:
Yu Li
2023-06-07 12:01:17 +08:00
committed by Bo Chen
parent c10de48f08
commit e5835fdc75
3 changed files with 51 additions and 140 deletions

View File

@@ -19,7 +19,7 @@ use std::collections::HashMap;
use std::convert::TryInto; use std::convert::TryInto;
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::{Arc, Mutex}; 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; pub const _NSIG: i32 = 65;
@@ -83,8 +83,8 @@ pub fn configure_vcpu(
Ok(mpidr) Ok(mpidr)
} }
pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> { pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> {
let mut regions = vec![ vec![
// 0 MiB ~ 256 MiB: UEFI, GIC and legacy devices // 0 MiB ~ 256 MiB: UEFI, GIC and legacy devices
( (
GuestAddress(0), GuestAddress(0),
@@ -103,39 +103,21 @@ pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, Region
layout::PCI_MMCONFIG_SIZE as usize, layout::PCI_MMCONFIG_SIZE as usize,
RegionType::Reserved, RegionType::Reserved,
), ),
]; // 1GiB ~ 4032 MiB: RAM before the gap
(
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((
layout::RAM_START, layout::RAM_START,
ram_32bit_space_size as usize, layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START) as usize,
RegionType::Ram, RegionType::Ram,
)); ),
// Other memory is placed after 4GiB // 4GiB ~ inf: RAM after the gap
regions.push(( (layout::RAM_64BIT_START, usize::MAX, RegionType::Ram),
layout::RAM_64BIT_START, // Add the 32-bit reserved memory hole as a reserved region
(size - ram_32bit_space_size) as usize, (
RegionType::Ram, layout::MEM_32BIT_RESERVED_START,
)); layout::MEM_32BIT_RESERVED_SIZE as usize,
} RegionType::Reserved,
),
// 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
} }
/// Configures the system and should be called once per vm before starting vcpu threads. /// Configures the system and should be called once per vm before starting vcpu threads.
@@ -217,26 +199,12 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn test_arch_memory_regions_dram_2gb() { fn test_arch_memory_regions_dram() {
let regions = arch_memory_regions((1usize << 31) as u64); //2GB let regions = arch_memory_regions();
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;
assert_eq!(6, regions.len()); assert_eq!(6, regions.len());
assert_eq!(layout::RAM_START, regions[3].0); 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::Ram, regions[3].2);
assert_eq!(RegionType::Reserved, regions[5].2); assert_eq!(RegionType::Reserved, regions[5].2);
assert_eq!(RegionType::Ram, regions[4].2); assert_eq!(RegionType::Ram, regions[4].2);
assert_eq!(((1usize << 32) - ram_32bit_space_size), regions[4].1);
} }
} }

View File

@@ -834,47 +834,29 @@ pub fn configure_vcpu(
/// These should be used to configure the GuestMemory structure for the platform. /// 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 /// For x86_64 all addresses are valid from the start of the kernel except a
/// carve out at the end of 32bit address space. /// carve out at the end of 32bit address space.
pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> { pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> {
let reserved_memory_gap_start = layout::MEM_32BIT_RESERVED_START vec![
.checked_add(layout::MEM_32BIT_DEVICES_SIZE) // 0 GiB ~ 3GiB: memory before the gap
.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((
GuestAddress(0), GuestAddress(0),
layout::MEM_32BIT_RESERVED_START.raw_value() as usize, layout::MEM_32BIT_RESERVED_START.raw_value() as usize,
RegionType::Ram, RegionType::Ram,
)); ),
regions.push(( // 4 GiB ~ inf: memory after the gap
layout::RAM_64BIT_START, (layout::RAM_64BIT_START, usize::MAX, RegionType::Ram),
requested_memory_size.unchecked_offset_from(layout::MEM_32BIT_RESERVED_START) as usize, // 3 GiB ~ 3712 MiB: 32-bit device memory hole
RegionType::Ram, (
)); layout::MEM_32BIT_RESERVED_START,
} layout::MEM_32BIT_DEVICES_SIZE as usize,
RegionType::SubRegion,
// Add the 32-bit device memory hole as a sub region. ),
regions.push(( // 3712 MiB ~ 3968 MiB: 32-bit reserved memory hole
layout::MEM_32BIT_RESERVED_START, (
layout::MEM_32BIT_DEVICES_SIZE as usize, layout::MEM_32BIT_RESERVED_START.unchecked_add(layout::MEM_32BIT_DEVICES_SIZE),
RegionType::SubRegion, (layout::MEM_32BIT_RESERVED_SIZE - layout::MEM_32BIT_DEVICES_SIZE) as usize,
)); RegionType::Reserved,
),
// 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
} }
/// Configures the system and should be called once per vm before starting vcpu threads. /// Configures the system and should be called once per vm before starting vcpu threads.
@@ -1256,16 +1238,8 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn regions_lt_4gb() { fn regions_base_addr() {
let regions = arch_memory_regions(1 << 29); let regions = arch_memory_regions();
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);
assert_eq!(4, regions.len()); assert_eq!(4, regions.len());
assert_eq!(GuestAddress(0), regions[0].0); assert_eq!(GuestAddress(0), regions[0].0);
assert_eq!(GuestAddress(1 << 32), regions[1].0); assert_eq!(GuestAddress(1 << 32), regions[1].0);
@@ -1289,11 +1263,10 @@ mod tests {
assert!(config_err.is_err()); assert!(config_err.is_err());
// Now assigning some memory that falls before the 32bit memory hole. // Now assigning some memory that falls before the 32bit memory hole.
let mem_size = 128 << 20; let arch_mem_regions = arch_memory_regions();
let arch_mem_regions = arch_memory_regions(mem_size);
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
.iter() .iter()
.filter(|r| r.2 == RegionType::Ram) .filter(|r| r.2 == RegionType::Ram && r.1 != usize::MAX)
.map(|r| (r.0, r.1)) .map(|r| (r.0, r.1))
.collect(); .collect();
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap(); let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
@@ -1311,48 +1284,18 @@ mod tests {
) )
.unwrap(); .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. // Now assigning some memory that falls after the 32bit memory hole.
let mem_size = 3330 << 20; let arch_mem_regions = arch_memory_regions();
let arch_mem_regions = arch_memory_regions(mem_size);
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
.iter() .iter()
.filter(|r| r.2 == RegionType::Ram) .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(); .collect();
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap(); let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
configure_system( configure_system(

View File

@@ -933,7 +933,7 @@ impl MemoryManager {
) )
} else { } else {
// Init guest memory // 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 let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
.iter() .iter()