mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-05 18:20:34 +00:00
aarch64: Provide the maximum supported IPA size as the machine type
The value 0 passed to KVM_CREATE_VM has a special meaning for KVM/arm64. It indicates that the VM is configured with a 40bit IPA space. However, not all HW support such an IPA space, and the KVM_CREATE_VM call fails on these systems. In order to maximize compatibility, we can ask KVM for the maximum supported IPA size, and use that as an input to KVM_CREATE_VM, at which point the kernel will instantiate a VM with that IPA size. This enables crosvm on exotic hardware such as the Apple-M1. TEST=tools/run_tests Change-Id: I7ea39ac6e5de6a1389c0c30cdfeb7c970c411589 Signed-off-by: Marc Zyngier <mzyngier@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3124677 Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
This commit is contained in:
parent
d80eabc803
commit
17b1e02fb6
4 changed files with 51 additions and 4 deletions
|
@ -5,17 +5,36 @@
|
|||
use libc::{EINVAL, ENOMEM, ENOSYS, ENXIO};
|
||||
|
||||
use base::{
|
||||
errno_result, error, ioctl_with_mut_ref, ioctl_with_ref, Error, MemoryMappingBuilder, Result,
|
||||
errno_result, error, ioctl_with_mut_ref, ioctl_with_ref, ioctl_with_val, Error,
|
||||
MemoryMappingBuilder, Result,
|
||||
};
|
||||
use kvm_sys::*;
|
||||
use std::os::raw::c_ulong;
|
||||
use vm_memory::GuestAddress;
|
||||
|
||||
use super::{KvmCap, KvmVcpu, KvmVm};
|
||||
use super::{Kvm, KvmCap, KvmVcpu, KvmVm};
|
||||
use crate::{
|
||||
ClockState, DeviceKind, Hypervisor, IrqSourceChip, PsciVersion, VcpuAArch64, VcpuFeature, Vm,
|
||||
VmAArch64, VmCap,
|
||||
};
|
||||
|
||||
impl Kvm {
|
||||
// Compute the machine type, which should be the IPA range for the VM
|
||||
// Ideally, this would take a description of the memory map and return
|
||||
// the closest machine type for this VM. Here, we just return the maximum
|
||||
// the kernel support.
|
||||
pub fn get_vm_type(&self) -> c_ulong {
|
||||
// Safe because we know self is a real kvm fd
|
||||
match unsafe { ioctl_with_val(self, KVM_CHECK_EXTENSION(), KVM_CAP_ARM_VM_IPA_SIZE.into()) }
|
||||
{
|
||||
// Not supported? Use 0 as the machine type, which implies 40bit IPA
|
||||
ret if ret < 0 => 0,
|
||||
// Use the lower 8 bits representing the IPA space as the machine type
|
||||
ipa => (ipa & 0xff) as c_ulong,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl KvmVm {
|
||||
/// Checks if a particular `VmCap` is available, or returns None if arch-independent
|
||||
/// Vm.check_capability() should handle the check.
|
||||
|
|
|
@ -166,7 +166,7 @@ impl KvmVm {
|
|||
pub fn new(kvm: &Kvm, guest_mem: GuestMemory) -> Result<KvmVm> {
|
||||
// Safe because we know kvm is a real kvm fd as this module is the only one that can make
|
||||
// Kvm objects.
|
||||
let ret = unsafe { ioctl_with_val(kvm, KVM_CREATE_VM(), 0) };
|
||||
let ret = unsafe { ioctl_with_val(kvm, KVM_CREATE_VM(), kvm.get_vm_type()) };
|
||||
if ret < 0 {
|
||||
return errno_result();
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ use base::{
|
|||
};
|
||||
use data_model::vec_with_array_field;
|
||||
use kvm_sys::*;
|
||||
use std::os::raw::c_ulong;
|
||||
use vm_memory::GuestAddress;
|
||||
|
||||
use super::{Kvm, KvmVcpu, KvmVm};
|
||||
|
@ -64,6 +65,11 @@ impl Kvm {
|
|||
const KVM_MAX_ENTRIES: usize = 256;
|
||||
get_cpuid_with_initial_capacity(self, kind, KVM_MAX_ENTRIES)
|
||||
}
|
||||
|
||||
// The x86 machine type is always 0
|
||||
pub fn get_vm_type(&self) -> c_ulong {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
impl HypervisorX86_64 for Kvm {
|
||||
|
|
|
@ -198,6 +198,28 @@ impl Kvm {
|
|||
|
||||
Ok(indices.to_vec())
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
// The x86 machine type is always 0
|
||||
pub fn get_vm_type(&self) -> c_ulong {
|
||||
0
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
|
||||
// Compute the machine type, which should be the IPA range for the VM
|
||||
// Ideally, this would take a description of the memory map and return
|
||||
// the closest machine type for this VM. Here, we just return the maximum
|
||||
// the kernel support.
|
||||
pub fn get_vm_type(&self) -> c_ulong {
|
||||
// Safe because we know self is a real kvm fd
|
||||
match unsafe { ioctl_with_val(self, KVM_CHECK_EXTENSION(), KVM_CAP_ARM_VM_IPA_SIZE.into()) }
|
||||
{
|
||||
// Not supported? Use 0 as the machine type, which implies 40bit IPA
|
||||
ret if ret < 0 => 0,
|
||||
// Use the lower 8 bits representing the IPA space as the machine type
|
||||
ipa => (ipa & 0xff) as c_ulong,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawDescriptor for Kvm {
|
||||
|
@ -274,7 +296,7 @@ impl Vm {
|
|||
pub fn new(kvm: &Kvm, guest_mem: GuestMemory) -> Result<Vm> {
|
||||
// Safe because we know kvm is a real kvm fd as this module is the only one that can make
|
||||
// Kvm objects.
|
||||
let ret = unsafe { ioctl_with_val(kvm, KVM_CREATE_VM(), 0) };
|
||||
let ret = unsafe { ioctl_with_val(kvm, KVM_CREATE_VM(), kvm.get_vm_type()) };
|
||||
if ret >= 0 {
|
||||
// Safe because we verify the value of ret and we are the owners of the fd.
|
||||
let vm_file = unsafe { File::from_raw_descriptor(ret) };
|
||||
|
|
Loading…
Reference in a new issue