aarch64: limit high MMIO addresses to VM phys addr range

The high MMIO region of the system allocator was previously set up with
the upper limit of 2**64 - 1, but physical addresses on actual systems
are not that large. Now that pmem allocates from the upper end of the
high MMIO region, the size of the allocator actually matters.

Limit the aarch64 high MMIO allocator to the VM's physical address size
so that addresses at the end of the allocation range are usable and pmem
devices can be created on aarch64.

BUG=b:210727578
TEST=Boot with pmem device on aarch64

Change-Id: I67962c2b03f0f265349ae889c988eb69ef526f4a
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3366858
Reviewed-by: Dmitry Torokhov <dtor@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Andrew Walbran <qwandor@google.com>
Commit-Queue: Daniel Verkamp <dverkamp@chromium.org>
This commit is contained in:
Daniel Verkamp 2022-01-04 12:35:55 -08:00 committed by Commit Bot
parent 3c2abaf838
commit 891ea3e88a
8 changed files with 24 additions and 11 deletions

View file

@ -246,7 +246,7 @@ impl arch::LinuxArch for AArch64 {
}
fn create_system_allocator<V: Vm>(vm: &V) -> SystemAllocator {
Self::get_resource_allocator(vm.get_memory().memory_size())
Self::get_resource_allocator(vm.get_memory().memory_size(), vm.get_guest_phys_addr_bits())
}
fn build_vm<V, Vcpu>(
@ -539,13 +539,26 @@ impl AArch64 {
}
/// Returns a system resource allocator.
fn get_resource_allocator(mem_size: u64) -> SystemAllocator {
///
/// # Arguments
///
/// * `mem_size` - Size of guest memory (RAM) in bytes.
/// * `guest_phys_addr_bits` - Size of guest physical addresses (IPA) in bits.
fn get_resource_allocator(mem_size: u64, guest_phys_addr_bits: u8) -> SystemAllocator {
let guest_phys_end = 1u64 << guest_phys_addr_bits;
// The platform MMIO region is immediately past the end of RAM.
let plat_mmio_base = AARCH64_PHYS_MEM_START + mem_size;
let plat_mmio_size = AARCH64_PLATFORM_MMIO_SIZE;
// The high MMIO region is the rest of the address space after the platform MMIO region.
let high_mmio_base = plat_mmio_base + plat_mmio_size;
let high_mmio_size = u64::max_value() - high_mmio_base;
let high_mmio_size = guest_phys_end
.checked_sub(high_mmio_base)
.unwrap_or_else(|| {
panic!(
"guest_phys_end {:#x} < high_mmio_base {:#x}",
guest_phys_end, high_mmio_base,
);
});
SystemAllocator::builder()
.add_low_mmio_addresses(AARCH64_MMIO_BASE, AARCH64_MMIO_SIZE)
.add_platform_mmio_addresses(plat_mmio_base, plat_mmio_size)

View file

@ -42,7 +42,7 @@ impl Kvm {
}
/// Get the size of guest physical addresses (IPA) in bits.
pub fn get_guest_phys_addr_size(&self) -> u8 {
pub fn get_guest_phys_addr_bits(&self) -> u8 {
// Safe because we know self is a real kvm fd
let vm_ipa_size = match unsafe {
ioctl_with_val(self, KVM_CHECK_EXTENSION(), KVM_CAP_ARM_VM_IPA_SIZE.into())

View file

@ -453,8 +453,8 @@ impl Vm for KvmVm {
}
}
fn get_guest_phys_addr_size(&self) -> u8 {
self.kvm.get_guest_phys_addr_size()
fn get_guest_phys_addr_bits(&self) -> u8 {
self.kvm.get_guest_phys_addr_bits()
}
fn get_memory(&self) -> &GuestMemory {

View file

@ -78,7 +78,7 @@ impl Kvm {
}
/// Get the size of guest physical addresses in bits.
pub fn get_guest_phys_addr_size(&self) -> u8 {
pub fn get_guest_phys_addr_bits(&self) -> u8 {
// Get host cpu max physical address bits.
// Assume the guest physical address size is the same as the host.
let highest_ext_function = unsafe { __cpuid(0x80000000) };

View file

@ -53,7 +53,7 @@ pub trait Vm: Send {
fn check_capability(&self, c: VmCap) -> bool;
/// Get the guest physical address size in bits.
fn get_guest_phys_addr_size(&self) -> u8;
fn get_guest_phys_addr_bits(&self) -> u8;
/// Gets the guest-mapped memory for the Vm.
fn get_memory(&self) -> &GuestMemory;

View file

@ -2789,7 +2789,7 @@ where
None => None,
};
let phys_max_addr = (1u64 << vm.get_guest_phys_addr_size()) - 1;
let phys_max_addr = (1u64 << vm.get_guest_phys_addr_bits()) - 1;
let mut devices = create_devices(
&cfg,
&mut vm,

View file

@ -1115,7 +1115,7 @@ impl X8664arch {
///
/// * `vm`: The virtual machine
fn get_high_mmio_size<V: Vm>(vm: &V) -> u64 {
let phys_mem_end = 1u64 << vm.get_guest_phys_addr_size();
let phys_mem_end = 1u64 << vm.get_guest_phys_addr_bits();
let high_mmio_end = std::cmp::min(phys_mem_end, HIGH_MMIO_MAX_END);
high_mmio_end - Self::get_high_mmio_base(vm.get_memory())
}

View file

@ -122,7 +122,7 @@ fn append_mtrr_entries(
return;
}
let phys_mask: u64 = (1 << vm.get_guest_phys_addr_size()) - 1;
let phys_mask: u64 = (1 << vm.get_guest_phys_addr_bits()) - 1;
for (idx, (base, len)) in vecs.iter().enumerate() {
let reg_idx = idx as u32 * 2;
entries.push(Register {