diff --git a/arch/src/aarch64/layout.rs b/arch/src/aarch64/layout.rs index 8a7fc25cb..a0f617782 100644 --- a/arch/src/aarch64/layout.rs +++ b/arch/src/aarch64/layout.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 // -// Memory layout of Aarch64 guest: +// Memory layout of AArch64 guest: // // Physical +---------------------------------------------------------------+ // address | | @@ -20,6 +20,13 @@ // | DRAM | // | | // | | +// 4GB +---------------------------------------------------------------+ +// | 32-bit devices hole | +// 4GB-64M +---------------------------------------------------------------+ +// | | +// | | +// | DRAM | +// | | // | | // 1GB +---------------------------------------------------------------+ // | | @@ -88,6 +95,13 @@ pub const PCI_MMIO_CONFIG_SIZE_PER_SEGMENT: u64 = 4096 * 256; /// Start of RAM. pub const RAM_START: GuestAddress = GuestAddress(0x4000_0000); +/// 32-bit reserved area: 64MiB before 4GiB +pub const MEM_32BIT_RESERVED_START: GuestAddress = GuestAddress(0xfc00_0000); +pub const MEM_32BIT_RESERVED_SIZE: u64 = 0x0400_0000; + +/// Start of 64-bit RAM. +pub const RAM_64BIT_START: GuestAddress = GuestAddress(0x1_0000_0000); + /// Kernel command line maximum size. /// As per `arch/arm64/include/uapi/asm/setup.h`. pub const CMDLINE_MAX_SIZE: usize = 2048; diff --git a/arch/src/aarch64/mod.rs b/arch/src/aarch64/mod.rs index 71724c04a..c941e069b 100644 --- a/arch/src/aarch64/mod.rs +++ b/arch/src/aarch64/mod.rs @@ -78,14 +78,7 @@ pub fn configure_vcpu( } pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> { - // Normally UEFI should be loaded to a flash area at the beginning of memory. - // But now flash memory type is not supported. - // As a workaround, we take 4 MiB memory from the main RAM for UEFI. - // As a result, the RAM that the guest can see is less than what has been - // assigned in command line, when ACPI and UEFI is enabled. - let ram_deduction = layout::UEFI_SIZE; - - vec![ + let mut regions = vec![ // 0 ~ 4 MiB: Reserved for UEFI space (GuestAddress(0), layout::UEFI_SIZE as usize, RegionType::Ram), // 4 MiB ~ 256 MiB: Gic and legacy devices @@ -106,13 +99,45 @@ pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, Region layout::PCI_MMCONFIG_SIZE as usize, RegionType::Reserved, ), - // 1 GiB ~ : Ram - ( + ]; + + // Normally UEFI should be loaded to a flash area at the beginning of memory. + // But now flash memory type is not supported. + // As a workaround, we take 4 MiB memory from the main RAM for UEFI. + // As a result, the RAM that the guest can see is less than what has been + // assigned in command line, when ACPI and UEFI is enabled. + let ram_size = size - layout::UEFI_SIZE; + 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 ram_size as u64 <= ram_32bit_space_size { + regions.push((layout::RAM_START, ram_size as usize, RegionType::Ram)); + // Case2: guest memory extends beyond the gap + } else { + // Push memory before the gap + regions.push(( layout::RAM_START, - (size - ram_deduction) as usize, + ram_32bit_space_size as usize, RegionType::Ram, - ), - ] + )); + // Other memory is placed after 4GiB + regions.push(( + layout::RAM_64BIT_START, + (ram_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 } /// Configures the system and should be called once per vm before starting vcpu threads. diff --git a/vmm/src/memory_manager.rs b/vmm/src/memory_manager.rs index 6309e55d3..51a2499bb 100644 --- a/vmm/src/memory_manager.rs +++ b/vmm/src/memory_manager.rs @@ -1327,7 +1327,7 @@ impl MemoryManager { // If memory hotplug is allowed, the start address needs to be aligned // (rounded-up) to 128MiB boundary. // If memory hotplug is not allowed, there is no alignment required. - // On x86_64, it must also start at the 64bit start. + // And it must also start at the 64bit start. fn start_addr(mem_end: GuestAddress, allow_mem_hotplug: bool) -> Result { let mut start_addr = if allow_mem_hotplug { GuestAddress(mem_end.0 | ((128 << 20) - 1)) @@ -1339,7 +1339,6 @@ impl MemoryManager { .checked_add(1) .ok_or(Error::GuestAddressOverFlow)?; - #[cfg(target_arch = "x86_64")] if mem_end < arch::layout::MEM_32BIT_RESERVED_START { return Ok(arch::layout::RAM_64BIT_START); }