vmm: Handle hypervisor VCPU run result from Vcpu to VcpuManager

Now Vcpu::run() returns a boolean value to VcpuManager, indicating
whether the VM is going to reboot (false) or just continue (true).
Moving the handling of hypervisor VCPU run result from Vcpu to
VcpuManager gives us the flexibility to handle more scenarios like
shutting down on AArch64.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
This commit is contained in:
Michael Zhao 2020-10-30 21:01:53 +08:00 committed by Rob Bradford
parent 0f5e5d9e6d
commit 69394c9c35

View File

@ -34,7 +34,7 @@ use devices::interrupt_controller::InterruptController;
use hypervisor::kvm::kvm_bindings; use hypervisor::kvm::kvm_bindings;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use hypervisor::CpuId; use hypervisor::CpuId;
use hypervisor::{CpuState, VmExit}; use hypervisor::{CpuState, HypervisorCpuError, VmExit};
use seccomp::{SeccompAction, SeccompFilter}; use seccomp::{SeccompAction, SeccompFilter};
use libc::{c_void, siginfo_t}; use libc::{c_void, siginfo_t};
@ -213,8 +213,6 @@ pub struct Vcpu {
// The hypervisor abstracted CPU. // The hypervisor abstracted CPU.
vcpu: Arc<dyn hypervisor::Vcpu>, vcpu: Arc<dyn hypervisor::Vcpu>,
id: u8, id: u8,
#[cfg_attr(target_arch = "aarch64", allow(dead_code))]
interrupt_controller: Option<Arc<Mutex<dyn InterruptController>>>,
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
mpidr: u64, mpidr: u64,
saved_state: Option<CpuState>, saved_state: Option<CpuState>,
@ -227,11 +225,7 @@ impl Vcpu {
/// ///
/// * `id` - Represents the CPU number between [0, max vcpus). /// * `id` - Represents the CPU number between [0, max vcpus).
/// * `vm` - The virtual machine this vcpu will get attached to. /// * `vm` - The virtual machine this vcpu will get attached to.
pub fn new( pub fn new(id: u8, vm: &Arc<dyn hypervisor::Vm>) -> Result<Arc<Mutex<Self>>> {
id: u8,
vm: &Arc<dyn hypervisor::Vm>,
interrupt_controller: Option<Arc<Mutex<dyn InterruptController>>>,
) -> Result<Arc<Mutex<Self>>> {
let vcpu = vm let vcpu = vm
.create_vcpu(id) .create_vcpu(id)
.map_err(|e| Error::VcpuCreate(e.into()))?; .map_err(|e| Error::VcpuCreate(e.into()))?;
@ -239,7 +233,6 @@ impl Vcpu {
Ok(Arc::new(Mutex::new(Vcpu { Ok(Arc::new(Mutex::new(Vcpu {
vcpu, vcpu,
id, id,
interrupt_controller,
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
mpidr: 0, mpidr: 0,
saved_state: None, saved_state: None,
@ -323,28 +316,8 @@ impl Vcpu {
/// ///
/// Note that the state of the VCPU and associated VM must be setup first for this to do /// Note that the state of the VCPU and associated VM must be setup first for this to do
/// anything useful. /// anything useful.
pub fn run(&self) -> Result<bool> { pub fn run(&self) -> std::result::Result<VmExit, HypervisorCpuError> {
match self.vcpu.run() { self.vcpu.run()
Ok(run) => match run {
#[cfg(target_arch = "x86_64")]
VmExit::IoapicEoi(vector) => {
if let Some(interrupt_controller) = &self.interrupt_controller {
interrupt_controller
.lock()
.unwrap()
.end_of_interrupt(vector);
}
Ok(true)
}
VmExit::Ignore => Ok(true),
VmExit::Reset => Ok(false),
// No need to handle anything from a KVM HyperV exit
VmExit::Hyperv => Ok(true),
_ => Err(Error::UnexpectedVmExit),
},
Err(e) => Err(Error::VcpuRun(e.into())),
}
} }
} }
@ -679,13 +652,7 @@ impl CpuManager {
) -> Result<Arc<Mutex<Vcpu>>> { ) -> Result<Arc<Mutex<Vcpu>>> {
info!("Creating vCPU: cpu_id = {}", cpu_id); info!("Creating vCPU: cpu_id = {}", cpu_id);
let interrupt_controller = if let Some(interrupt_controller) = &self.interrupt_controller { let vcpu = Vcpu::new(cpu_id, &self.vm)?;
Some(interrupt_controller.clone())
} else {
None
};
let vcpu = Vcpu::new(cpu_id, &self.vm, interrupt_controller)?;
if let Some(snapshot) = snapshot { if let Some(snapshot) = snapshot {
// AArch64 vCPUs should be initialized after created. // AArch64 vCPUs should be initialized after created.
@ -770,6 +737,14 @@ impl CpuManager {
let vcpu_seccomp_filter = get_seccomp_filter(&self.seccomp_action, Thread::Vcpu) let vcpu_seccomp_filter = get_seccomp_filter(&self.seccomp_action, Thread::Vcpu)
.map_err(Error::CreateSeccompFilter)?; .map_err(Error::CreateSeccompFilter)?;
#[cfg(target_arch = "x86_64")]
let interrupt_controller_clone =
if let Some(interrupt_controller) = &self.interrupt_controller {
Some(interrupt_controller.clone())
} else {
None
};
let handle = Some( let handle = Some(
thread::Builder::new() thread::Builder::new()
.name(format!("vcpu{}", cpu_id)) .name(format!("vcpu{}", cpu_id))
@ -816,16 +791,35 @@ impl CpuManager {
// vcpu.run() returns false on a triple-fault so trigger a reset // vcpu.run() returns false on a triple-fault so trigger a reset
match vcpu.lock().unwrap().run() { match vcpu.lock().unwrap().run() {
Err(e) => { Ok(run) => match run {
error!("VCPU generated error: {:?}", e); #[cfg(target_arch = "x86_64")]
break; VmExit::IoapicEoi(vector) => {
if let Some(interrupt_controller) = &interrupt_controller_clone
{
interrupt_controller
.lock()
.unwrap()
.end_of_interrupt(vector);
} }
Ok(true) => {} }
Ok(false) => { VmExit::Ignore => {}
VmExit::Hyperv => {}
VmExit::Reset => {
debug!("VmExit::Reset");
vcpu_run_interrupted.store(true, Ordering::SeqCst); vcpu_run_interrupted.store(true, Ordering::SeqCst);
reset_evt.write(1).unwrap(); reset_evt.write(1).unwrap();
break; break;
} }
_ => {
error!("VCPU generated error: {:?}", Error::UnexpectedVmExit);
break;
}
},
Err(e) => {
error!("VCPU generated error: {:?}", Error::VcpuRun(e.into()));
break;
}
} }
// We've been told to terminate // We've been told to terminate