aarch64: Reserve a hole in 32-bit space

The reserved space is for devices.
Some devices (like TPM) require arbitrary addresses close to 4GiB.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
This commit is contained in:
Michael Zhao 2022-03-30 10:22:26 +08:00 committed by Xin Wang
parent a3dbc3b415
commit 848d88c122
3 changed files with 54 additions and 16 deletions

View File

@ -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;

View File

@ -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.

View File

@ -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<GuestAddress, Error> {
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);
}