mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-22 13:45:20 +00:00
vmm: support injecting NMI
Inject NMI interrupt when needed, by call ioctl KVM_NMI. Signed-off-by: Yi Wang <foxywang@tencent.com>
This commit is contained in:
parent
f40dd4a993
commit
c72bf0b32d
@ -278,6 +278,11 @@ pub enum HypervisorCpuError {
|
|||||||
#[cfg(feature = "sev_snp")]
|
#[cfg(feature = "sev_snp")]
|
||||||
#[error("Failed to set sev control register: {0}")]
|
#[error("Failed to set sev control register: {0}")]
|
||||||
SetSevControlRegister(#[source] anyhow::Error),
|
SetSevControlRegister(#[source] anyhow::Error),
|
||||||
|
|
||||||
|
/// Error injecting NMI
|
||||||
|
///
|
||||||
|
#[error("Failed to inject NMI")]
|
||||||
|
Nmi(#[source] anyhow::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -505,4 +510,12 @@ pub trait Vcpu: Send + Sync {
|
|||||||
fn set_sev_control_register(&self, _reg: u64) -> Result<()> {
|
fn set_sev_control_register(&self, _reg: u64) -> Result<()> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
///
|
||||||
|
/// Trigger NMI interrupt
|
||||||
|
///
|
||||||
|
fn nmi(&self) -> Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,6 +105,15 @@ pub use {
|
|||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
const KVM_CAP_SGX_ATTRIBUTE: u32 = 196;
|
const KVM_CAP_SGX_ATTRIBUTE: u32 = 196;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
use vmm_sys_util::ioctl_io_nr;
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "tdx"), target_arch = "x86_64"))]
|
||||||
|
use vmm_sys_util::ioctl_ioc_nr;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
ioctl_io_nr!(KVM_NMI, kvm_bindings::KVMIO, 0x9a);
|
||||||
|
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
const KVM_EXIT_TDX: u32 = 50;
|
const KVM_EXIT_TDX: u32 = 50;
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
@ -2312,6 +2321,23 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
///
|
||||||
|
/// Trigger NMI interrupt
|
||||||
|
///
|
||||||
|
fn nmi(&self) -> cpu::Result<()> {
|
||||||
|
match self.fd.nmi() {
|
||||||
|
Err(e) => {
|
||||||
|
if e.errno() == libc::EIO {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(cpu::HypervisorCpuError::Nmi(e.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KvmVcpu {
|
impl KvmVcpu {
|
||||||
|
@ -405,6 +405,13 @@ paths:
|
|||||||
405:
|
405:
|
||||||
description: The VM instance could not be coredumped because it is not booted.
|
description: The VM instance could not be coredumped because it is not booted.
|
||||||
|
|
||||||
|
/vmm.nmi:
|
||||||
|
put:
|
||||||
|
summary: Inject an NMI.
|
||||||
|
responses:
|
||||||
|
204:
|
||||||
|
description: The NMI successfully injected.
|
||||||
|
|
||||||
/vm.restore:
|
/vm.restore:
|
||||||
put:
|
put:
|
||||||
summary: Restore a VM from a snapshot.
|
summary: Restore a VM from a snapshot.
|
||||||
|
@ -188,6 +188,10 @@ pub enum Error {
|
|||||||
#[cfg(feature = "sev_snp")]
|
#[cfg(feature = "sev_snp")]
|
||||||
#[error("Failed to set sev control register: {0}")]
|
#[error("Failed to set sev control register: {0}")]
|
||||||
SetSevControlRegister(#[source] hypervisor::HypervisorCpuError),
|
SetSevControlRegister(#[source] hypervisor::HypervisorCpuError),
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
#[error("Failed to inject NMI")]
|
||||||
|
NmiError(hypervisor::HypervisorCpuError),
|
||||||
}
|
}
|
||||||
pub type Result<T> = result::Result<T, Error>;
|
pub type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
@ -477,6 +481,7 @@ pub struct CpuManager {
|
|||||||
vm: Arc<dyn hypervisor::Vm>,
|
vm: Arc<dyn hypervisor::Vm>,
|
||||||
vcpus_kill_signalled: Arc<AtomicBool>,
|
vcpus_kill_signalled: Arc<AtomicBool>,
|
||||||
vcpus_pause_signalled: Arc<AtomicBool>,
|
vcpus_pause_signalled: Arc<AtomicBool>,
|
||||||
|
vcpus_kick_signalled: Arc<AtomicBool>,
|
||||||
exit_evt: EventFd,
|
exit_evt: EventFd,
|
||||||
#[cfg_attr(target_arch = "aarch64", allow(dead_code))]
|
#[cfg_attr(target_arch = "aarch64", allow(dead_code))]
|
||||||
reset_evt: EventFd,
|
reset_evt: EventFd,
|
||||||
@ -721,6 +726,7 @@ impl CpuManager {
|
|||||||
vm,
|
vm,
|
||||||
vcpus_kill_signalled: Arc::new(AtomicBool::new(false)),
|
vcpus_kill_signalled: Arc::new(AtomicBool::new(false)),
|
||||||
vcpus_pause_signalled: Arc::new(AtomicBool::new(false)),
|
vcpus_pause_signalled: Arc::new(AtomicBool::new(false)),
|
||||||
|
vcpus_kick_signalled: Arc::new(AtomicBool::new(false)),
|
||||||
vcpu_states,
|
vcpu_states,
|
||||||
exit_evt,
|
exit_evt,
|
||||||
reset_evt,
|
reset_evt,
|
||||||
@ -934,6 +940,7 @@ impl CpuManager {
|
|||||||
let panic_exit_evt = self.exit_evt.try_clone().unwrap();
|
let panic_exit_evt = self.exit_evt.try_clone().unwrap();
|
||||||
let vcpu_kill_signalled = self.vcpus_kill_signalled.clone();
|
let vcpu_kill_signalled = self.vcpus_kill_signalled.clone();
|
||||||
let vcpu_pause_signalled = self.vcpus_pause_signalled.clone();
|
let vcpu_pause_signalled = self.vcpus_pause_signalled.clone();
|
||||||
|
let vcpu_kick_signalled = self.vcpus_kick_signalled.clone();
|
||||||
|
|
||||||
let vcpu_kill = self.vcpu_states[usize::from(vcpu_id)].kill.clone();
|
let vcpu_kill = self.vcpu_states[usize::from(vcpu_id)].kill.clone();
|
||||||
let vcpu_run_interrupted = self.vcpu_states[usize::from(vcpu_id)]
|
let vcpu_run_interrupted = self.vcpu_states[usize::from(vcpu_id)]
|
||||||
@ -1058,6 +1065,18 @@ impl CpuManager {
|
|||||||
vcpu_run_interrupted.store(false, Ordering::SeqCst);
|
vcpu_run_interrupted.store(false, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if vcpu_kick_signalled.load(Ordering::SeqCst) {
|
||||||
|
vcpu_run_interrupted.store(true, Ordering::SeqCst);
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
match vcpu.lock().as_ref().unwrap().vcpu.nmi() {
|
||||||
|
Ok(()) => {},
|
||||||
|
Err(e) => {
|
||||||
|
error!("Error when inject nmi {}", e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We've been told to terminate
|
// We've been told to terminate
|
||||||
if vcpu_kill_signalled.load(Ordering::SeqCst)
|
if vcpu_kill_signalled.load(Ordering::SeqCst)
|
||||||
|| vcpu_kill.load(Ordering::SeqCst)
|
|| vcpu_kill.load(Ordering::SeqCst)
|
||||||
@ -1848,6 +1867,18 @@ impl CpuManager {
|
|||||||
pub(crate) fn sev_snp_enabled(&self) -> bool {
|
pub(crate) fn sev_snp_enabled(&self) -> bool {
|
||||||
self.sev_snp_enabled
|
self.sev_snp_enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn nmi(&self) -> Result<()> {
|
||||||
|
self.vcpus_kick_signalled.store(true, Ordering::SeqCst);
|
||||||
|
|
||||||
|
for state in self.vcpu_states.iter() {
|
||||||
|
state.signal_thread();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.vcpus_kick_signalled.store(false, Ordering::SeqCst);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Cpu {
|
struct Cpu {
|
||||||
|
@ -1842,8 +1842,7 @@ impl RequestHandler for Vmm {
|
|||||||
|
|
||||||
fn vm_nmi(&mut self) -> result::Result<(), VmError> {
|
fn vm_nmi(&mut self) -> result::Result<(), VmError> {
|
||||||
if let Some(ref mut vm) = self.vm {
|
if let Some(ref mut vm) = self.vm {
|
||||||
info!("nmi");
|
vm.nmi()
|
||||||
vm.power_button()
|
|
||||||
} else {
|
} else {
|
||||||
Err(VmError::VmNotRunning)
|
Err(VmError::VmNotRunning)
|
||||||
}
|
}
|
||||||
|
@ -145,6 +145,7 @@ mod kvm {
|
|||||||
pub const KVM_CREATE_DEVICE: u64 = 0xc00c_aee0;
|
pub const KVM_CREATE_DEVICE: u64 = 0xc00c_aee0;
|
||||||
pub const KVM_GET_REG_LIST: u64 = 0xc008_aeb0;
|
pub const KVM_GET_REG_LIST: u64 = 0xc008_aeb0;
|
||||||
pub const KVM_MEMORY_ENCRYPT_OP: u64 = 0xc008_aeba;
|
pub const KVM_MEMORY_ENCRYPT_OP: u64 = 0xc008_aeba;
|
||||||
|
pub const KVM_NMI: u64 = 0xae9a;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "kvm")]
|
#[cfg(feature = "kvm")]
|
||||||
@ -275,6 +276,7 @@ fn create_vmm_ioctl_seccomp_rule_common_kvm() -> Result<Vec<SeccompRule>, Backen
|
|||||||
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_REGS)?],
|
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_REGS)?],
|
||||||
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_USER_MEMORY_REGION,)?],
|
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_USER_MEMORY_REGION,)?],
|
||||||
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_VCPU_EVENTS,)?],
|
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_VCPU_EVENTS,)?],
|
||||||
|
and![Cond::new(1, ArgLen::Dword, Eq, KVM_NMI)?],
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -688,6 +690,7 @@ fn create_vcpu_ioctl_seccomp_rule_kvm() -> Result<Vec<SeccompRule>, BackendError
|
|||||||
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_GSI_ROUTING,)?],
|
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_GSI_ROUTING,)?],
|
||||||
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_USER_MEMORY_REGION,)?],
|
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_USER_MEMORY_REGION,)?],
|
||||||
and![Cond::new(1, ArgLen::Dword, Eq, KVM_RUN,)?],
|
and![Cond::new(1, ArgLen::Dword, Eq, KVM_RUN,)?],
|
||||||
|
and![Cond::new(1, ArgLen::Dword, Eq, KVM_NMI)?],
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,6 +316,9 @@ pub enum Error {
|
|||||||
#[cfg(feature = "igvm")]
|
#[cfg(feature = "igvm")]
|
||||||
#[error("Cannot load the igvm into memory: {0}")]
|
#[error("Cannot load the igvm into memory: {0}")]
|
||||||
IgvmLoad(#[source] igvm_loader::Error),
|
IgvmLoad(#[source] igvm_loader::Error),
|
||||||
|
|
||||||
|
#[error("Error injecting NMI")]
|
||||||
|
ErrorNmi,
|
||||||
}
|
}
|
||||||
pub type Result<T> = result::Result<T, Error>;
|
pub type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
@ -2446,6 +2449,15 @@ impl Vm {
|
|||||||
+ note_size as u64
|
+ note_size as u64
|
||||||
+ size_of::<elf::Elf64_Phdr>() as u64 * phdr_num as u64
|
+ size_of::<elf::Elf64_Phdr>() as u64 * phdr_num as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn nmi(&self) -> Result<()> {
|
||||||
|
return self
|
||||||
|
.cpu_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.nmi()
|
||||||
|
.map_err(|_| Error::ErrorNmi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pausable for Vm {
|
impl Pausable for Vm {
|
||||||
|
Loading…
Reference in New Issue
Block a user