vmm: decouple vCPU init from configure_vcpus

Since calling `KVM_GET_ONE_REG` before `KVM_VCPU_INIT` will
result in an error: Exec format error (os error 8). This commit
decouples the vCPU init process from `configure_vcpus`. Therefore
in the process of restoring the vCPUs, these vCPUs can be
initialized separately before started.

Signed-off-by: Henry Wang <Henry.Wang@arm.com>
This commit is contained in:
Henry Wang 2020-09-06 10:23:39 +08:00 committed by Rob Bradford
parent 47e65cd341
commit 970a5a410d
2 changed files with 30 additions and 24 deletions

View File

@ -15,7 +15,6 @@ pub use self::fdt::DeviceInfoForFDT;
use crate::DeviceType;
use crate::RegionType;
use aarch64::gic::GICDevice;
use hypervisor::kvm::kvm_bindings;
use std::collections::HashMap;
use std::ffi::CStr;
use std::fmt::Debug;
@ -42,12 +41,6 @@ pub enum Error {
/// Error configuring the MPIDR register
VcpuRegMPIDR(hypervisor::HypervisorCpuError),
/// Error fetching prefered target
VcpuArmPreferredTarget(hypervisor::HypervisorVmError),
/// Error doing Vcpu Init on Arm.
VcpuArmInit(hypervisor::HypervisorCpuError),
}
impl From<Error> for super::Error {
@ -68,23 +61,9 @@ pub struct EntryPoint {
pub fn configure_vcpu(
fd: &Arc<dyn hypervisor::Vcpu>,
id: u8,
vm: &Arc<dyn hypervisor::Vm>,
kernel_entry_point: Option<EntryPoint>,
vm_memory: &GuestMemoryAtomic<GuestMemoryMmap>,
) -> super::Result<u64> {
let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default();
// This reads back the kernel's preferred target type.
vm.get_preferred_target(&mut kvi)
.map_err(Error::VcpuArmPreferredTarget)?;
// We already checked that the capability is supported.
kvi.features[0] |= 1 << kvm_bindings::KVM_ARM_VCPU_PSCI_0_2;
// Non-boot cpus are powered off initially.
if id > 0 {
kvi.features[0] |= 1 << kvm_bindings::KVM_ARM_VCPU_POWER_OFF;
}
fd.vcpu_init(&kvi).map_err(Error::VcpuArmInit)?;
if let Some(kernel_entry_point) = kernel_entry_point {
regs::setup_regs(
fd,

View File

@ -29,6 +29,8 @@ use arch::EntryPoint;
#[cfg(target_arch = "x86_64")]
use arch::{CpuidPatch, CpuidReg};
use devices::interrupt_controller::InterruptController;
#[cfg(target_arch = "aarch64")]
use hypervisor::kvm::kvm_bindings;
#[cfg(target_arch = "x86_64")]
use hypervisor::CpuId;
use hypervisor::{CpuState, VmExit};
@ -127,6 +129,14 @@ pub enum Error {
/// Error configuring VCPU
VcpuConfiguration(arch::Error),
#[cfg(target_arch = "aarch64")]
/// Error fetching prefered target
VcpuArmPreferredTarget(hypervisor::HypervisorVmError),
#[cfg(target_arch = "aarch64")]
/// Error doing vCPU init on Arm.
VcpuArmInit(hypervisor::HypervisorCpuError),
/// Failed to join on vCPU threads
ThreadCleanup(std::boxed::Box<dyn std::any::Any + std::marker::Send>),
@ -303,9 +313,9 @@ impl Vcpu {
) -> Result<()> {
#[cfg(target_arch = "aarch64")]
{
self.mpidr =
arch::configure_vcpu(&self.vcpu, self.id, vm, kernel_entry_point, vm_memory)
.map_err(Error::VcpuConfiguration)?;
self.init(vm)?;
self.mpidr = arch::configure_vcpu(&self.vcpu, self.id, kernel_entry_point, vm_memory)
.map_err(Error::VcpuConfiguration)?;
}
#[cfg(target_arch = "x86_64")]
@ -334,6 +344,23 @@ impl Vcpu {
self.saved_state.clone()
}
/// Initializes an aarch64 specific vcpu for booting Linux.
#[cfg(target_arch = "aarch64")]
pub fn init(&self, vm: &Arc<dyn hypervisor::Vm>) -> Result<()> {
let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default();
// This reads back the kernel's preferred target type.
vm.get_preferred_target(&mut kvi)
.map_err(Error::VcpuArmPreferredTarget)?;
// We already checked that the capability is supported.
kvi.features[0] |= 1 << kvm_bindings::KVM_ARM_VCPU_PSCI_0_2;
// 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)
}
/// Runs the VCPU until it exits, returning the reason.
///
/// Note that the state of the VCPU and associated VM must be setup first for this to do