vmm: Add support for enabling SVE in vm guests

This change enables SVE automatically if the host support SVE/SVE2.

Signed-off-by: Wenyu Huang <huangwenyuu@outlook.com>
This commit is contained in:
Wenyu Huang 2024-08-23 07:12:17 -04:00 committed by Rob Bradford
parent 2049b2c377
commit d2a364c5c0
4 changed files with 45 additions and 2 deletions

View File

@ -158,6 +158,11 @@ pub enum HypervisorCpuError {
#[error("Failed to init vcpu: {0}")]
VcpuInit(#[source] anyhow::Error),
///
/// Vcpu Finalize error
///
#[error("Failed to finalize vcpu: {0}")]
VcpuFinalize(#[source] anyhow::Error),
///
/// Setting one reg error
///
#[error("Failed to init vcpu: {0}")]
@ -416,6 +421,10 @@ pub trait Vcpu: Send + Sync {
///
#[cfg(target_arch = "aarch64")]
fn vcpu_init(&self, kvi: &VcpuInit) -> Result<()>;
#[cfg(target_arch = "aarch64")]
fn vcpu_finalize(&self, feature: i32) -> Result<()>;
///
/// Gets a list of the guest registers that are supported for the
/// KVM_GET_ONE_REG/KVM_SET_ONE_REG calls.

View File

@ -1881,6 +1881,15 @@ impl cpu::Vcpu for KvmVcpu {
.map_err(|e| cpu::HypervisorCpuError::VcpuInit(e.into()))
}
#[cfg(target_arch = "aarch64")]
fn vcpu_finalize(&self, feature: i32) -> cpu::Result<()> {
self.fd
.lock()
.unwrap()
.vcpu_finalize(&feature)
.map_err(|e| cpu::HypervisorCpuError::VcpuFinalize(e.into()))
}
///
/// Gets a list of the guest registers that are supported for the
/// KVM_GET_ONE_REG/KVM_SET_ONE_REG calls.

View File

@ -140,6 +140,10 @@ pub enum Error {
#[error("Error initialising vCPU: {0}")]
VcpuArmInit(#[source] hypervisor::HypervisorCpuError),
#[cfg(target_arch = "aarch64")]
#[error("Error finalising vCPU: {0}")]
VcpuArmFinalize(#[source] hypervisor::HypervisorCpuError),
#[error("Failed to join on vCPU threads: {0:?}")]
ThreadCleanup(std::boxed::Box<dyn std::any::Any + std::marker::Send>),
@ -415,8 +419,10 @@ impl Vcpu {
/// Initializes an aarch64 specific vcpu for booting Linux.
#[cfg(target_arch = "aarch64")]
pub fn init(&self, vm: &Arc<dyn hypervisor::Vm>) -> Result<()> {
use std::arch::is_aarch64_feature_detected;
let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default();
let sve_supported =
is_aarch64_feature_detected!("sve") || is_aarch64_feature_detected!("sve2");
// This reads back the kernel's preferred target type.
vm.get_preferred_target(&mut kvi)
.map_err(Error::VcpuArmPreferredTarget)?;
@ -430,11 +436,28 @@ impl Vcpu {
{
kvi.features[0] |= 1 << kvm_bindings::KVM_ARM_VCPU_PMU_V3;
}
if sve_supported
&& vm
.as_any()
.downcast_ref::<hypervisor::kvm::KvmVm>()
.unwrap()
.check_extension(Cap::ArmSve)
{
kvi.features[0] |= 1 << kvm_bindings::KVM_ARM_VCPU_SVE;
}
// Non-boot cpus are powered off initially.
if self.id > 0 {
kvi.features[0] |= 1 << kvm_bindings::KVM_ARM_VCPU_POWER_OFF;
}
self.vcpu.vcpu_init(&kvi).map_err(Error::VcpuArmInit)
self.vcpu.vcpu_init(&kvi).map_err(Error::VcpuArmInit)?;
if sve_supported {
self.vcpu
.vcpu_finalize(kvm_bindings::KVM_ARM_VCPU_SVE as i32)
.map_err(Error::VcpuArmFinalize)?;
}
Ok(())
}
/// Runs the VCPU until it exits, returning the reason.

View File

@ -427,12 +427,14 @@ fn create_vmm_ioctl_seccomp_rule_kvm() -> Result<Vec<SeccompRule>, BackendError>
const KVM_ARM_PREFERRED_TARGET: u64 = 0x8020_aeaf;
const KVM_ARM_VCPU_INIT: u64 = 0x4020_aeae;
const KVM_SET_GUEST_DEBUG: u64 = 0x4208_ae9b;
const KVM_ARM_VCPU_FINALIZE: u64 = 0x4004_aec2;
let common_rules = create_vmm_ioctl_seccomp_rule_common(HypervisorType::Kvm)?;
let mut arch_rules = or![
and![Cond::new(1, ArgLen::Dword, Eq, KVM_ARM_PREFERRED_TARGET,)?],
and![Cond::new(1, ArgLen::Dword, Eq, KVM_ARM_VCPU_INIT,)?],
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_GUEST_DEBUG,)?],
and![Cond::new(1, ArgLen::Dword, Eq, KVM_ARM_VCPU_FINALIZE,)?],
];
arch_rules.extend(common_rules);