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 <michael.zhao@arm.com>
This commit is contained in:
Michael Zhao 2020-10-30 21:34:16 +08:00 committed by Rob Bradford
parent 69394c9c35
commit 093a581ee1
5 changed files with 19 additions and 4 deletions

View File

@ -194,6 +194,7 @@ pub enum VmExit<'a> {
MmioWrite(u64 /* address */, &'a [u8]),
Ignore,
Reset,
Shutdown,
Hyperv,
}

View File

@ -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}",

View File

@ -398,6 +398,7 @@ pub struct CpuManager {
vm: Arc<dyn hypervisor::Vm>,
vcpus_kill_signalled: Arc<AtomicBool>,
vcpus_pause_signalled: Arc<AtomicBool>,
exit_evt: EventFd,
#[cfg_attr(target_arch = "aarch64", allow(dead_code))]
reset_evt: EventFd,
vcpu_states: Vec<VcpuState>,
@ -523,11 +524,13 @@ impl VcpuState {
impl CpuManager {
#[allow(unused_variables)]
#[allow(clippy::too_many_arguments)]
pub fn new(
config: &CpusConfig,
device_manager: &Arc<Mutex<DeviceManager>>,
memory_manager: &Arc<Mutex<MemoryManager>>,
vm: Arc<dyn hypervisor::Vm>,
exit_evt: EventFd,
reset_evt: EventFd,
hypervisor: Arc<dyn hypervisor::Hypervisor>,
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;

View File

@ -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();

View File

@ -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(),