From 093a581ee1962851caf6aedbc91b43b0cf616c1a Mon Sep 17 00:00:00 2001 From: Michael Zhao Date: Fri, 30 Oct 2020 21:34:16 +0800 Subject: [PATCH] vmm: Implement VM rebooting on AArch64 The logic to handle AArch64 system event was: SHUTDOWN and RESET were all treated as RESET. Now we handle them differently: - RESET event will trigger Vmm::vm_reboot(), - SHUTDOWN event will trigger Vmm::vm_shutdown(). Signed-off-by: Michael Zhao --- hypervisor/src/cpu.rs | 1 + hypervisor/src/kvm/mod.rs | 6 +++--- vmm/src/cpu.rs | 11 +++++++++++ vmm/src/lib.rs | 3 ++- vmm/src/vm.rs | 2 ++ 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/hypervisor/src/cpu.rs b/hypervisor/src/cpu.rs index b3c30fbab..4d7497e9d 100644 --- a/hypervisor/src/cpu.rs +++ b/hypervisor/src/cpu.rs @@ -194,6 +194,7 @@ pub enum VmExit<'a> { MmioWrite(u64 /* address */, &'a [u8]), Ignore, Reset, + Shutdown, Hyperv, } diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index 6c1fd0631..fe533443d 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs @@ -738,10 +738,10 @@ impl cpu::Vcpu for KvmVcpu { use kvm_bindings::{KVM_SYSTEM_EVENT_RESET, KVM_SYSTEM_EVENT_SHUTDOWN}; // On Aarch64, when the VM is shutdown, run() returns // VcpuExit::SystemEvent with reason KVM_SYSTEM_EVENT_SHUTDOWN - if event_type == KVM_SYSTEM_EVENT_SHUTDOWN - || event_type == KVM_SYSTEM_EVENT_RESET - { + if event_type == KVM_SYSTEM_EVENT_RESET { Ok(cpu::VmExit::Reset) + } else if event_type == KVM_SYSTEM_EVENT_SHUTDOWN { + Ok(cpu::VmExit::Shutdown) } else { Err(cpu::HypervisorCpuError::RunVcpu(anyhow!( "Unexpected system event with type 0x{:x}, flags 0x{:x}", diff --git a/vmm/src/cpu.rs b/vmm/src/cpu.rs index 332988e3f..742c8627e 100644 --- a/vmm/src/cpu.rs +++ b/vmm/src/cpu.rs @@ -398,6 +398,7 @@ pub struct CpuManager { vm: Arc, vcpus_kill_signalled: Arc, vcpus_pause_signalled: Arc, + exit_evt: EventFd, #[cfg_attr(target_arch = "aarch64", allow(dead_code))] reset_evt: EventFd, vcpu_states: Vec, @@ -523,11 +524,13 @@ impl VcpuState { impl CpuManager { #[allow(unused_variables)] + #[allow(clippy::too_many_arguments)] pub fn new( config: &CpusConfig, device_manager: &Arc>, memory_manager: &Arc>, vm: Arc, + exit_evt: EventFd, reset_evt: EventFd, hypervisor: Arc, seccomp_action: SeccompAction, @@ -557,6 +560,7 @@ impl CpuManager { vcpus_kill_signalled: Arc::new(AtomicBool::new(false)), vcpus_pause_signalled: Arc::new(AtomicBool::new(false)), vcpu_states, + exit_evt, reset_evt, selected_cpu: 0, vcpus: Vec::with_capacity(usize::from(config.max_vcpus)), @@ -723,6 +727,7 @@ impl CpuManager { ) -> Result<()> { let cpu_id = vcpu.lock().unwrap().id; let reset_evt = self.reset_evt.try_clone().unwrap(); + let exit_evt = self.exit_evt.try_clone().unwrap(); let vcpu_kill_signalled = self.vcpus_kill_signalled.clone(); let vcpu_pause_signalled = self.vcpus_pause_signalled.clone(); @@ -810,6 +815,12 @@ impl CpuManager { reset_evt.write(1).unwrap(); break; } + VmExit::Shutdown => { + debug!("VmExit::Shutdown"); + vcpu_run_interrupted.store(true, Ordering::SeqCst); + exit_evt.write(1).unwrap(); + break; + } _ => { error!("VCPU generated error: {:?}", Error::UnexpectedVmExit); break; diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 0c6e79b97..6399acedf 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -432,7 +432,8 @@ impl Vmm { fn vm_reboot(&mut self) -> result::Result<(), VmError> { // Without ACPI, a reset is equivalent to a shutdown - #[cfg(not(feature = "acpi"))] + // On AArch64, before ACPI is supported, we simply jump over this check and continue to reset. + #[cfg(all(target_arch = "x86_64", not(feature = "acpi")))] { if self.vm.is_some() { self.exit_evt.write(1).unwrap(); diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 2f09afd03..7fa40bb36 100644 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -512,11 +512,13 @@ impl Vm { }); vm.set_vmmops(vm_ops).map_err(Error::SetVmmOpsInterface)?; + let exit_evt_clone = exit_evt.try_clone().map_err(Error::EventFdClone)?; let cpu_manager = cpu::CpuManager::new( &config.lock().unwrap().cpus.clone(), &device_manager, &memory_manager, vm.clone(), + exit_evt_clone, reset_evt, hypervisor, seccomp_action.clone(),