mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-11-24 20:48:55 +00:00
hypervisor: snapshot interrupt state for WHPX.
When snapshotting, the interrupt state (pending or otherwise) needs to be saved from the VCPU. Every hypervisor has its own implementation of how this is exposed to VMMs (KVM uses vcpu_events). This CL adds an implementation for WHPX's VCPU. BUG=b:270734340 TEST=builds (we can't test the full WHPX snapshot flow yet; need to reach critical mass on implementation first). Change-Id: Ic97ad15391f277967bd7b19a7ff6b55c57f3a00b Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/4428057 Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Reviewed-by: Elie Kheirallah <khei@google.com> Reviewed-by: Vaibhav Nagarnaik <vnagarnaik@google.com> Commit-Queue: Noah Gold <nkgold@google.com>
This commit is contained in:
parent
f897fb4f54
commit
307b57809a
2 changed files with 86 additions and 5 deletions
|
@ -5,6 +5,8 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
use super::whpx_sys::*;
|
||||
use crate::CpuIdEntry;
|
||||
|
@ -587,6 +589,54 @@ impl From<&WhpxDebugRegs> for DebugRegs {
|
|||
}
|
||||
}
|
||||
|
||||
/// Registers that store pending interrupts and interrupt state.
|
||||
#[derive(Default)]
|
||||
pub(super) struct WhpxInterruptRegs {
|
||||
register_values: [WHV_REGISTER_VALUE; 2],
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub(super) struct SerializedWhpxInterruptRegs {
|
||||
pending_interruption: u64,
|
||||
interrupt_state: u64,
|
||||
}
|
||||
|
||||
impl WhpxInterruptRegs {
|
||||
pub(super) fn get_register_names() -> &'static [WHV_REGISTER_NAME; 2] {
|
||||
const REG_NAMES: [WHV_REGISTER_NAME; 2] = [
|
||||
WHV_REGISTER_NAME_WHvRegisterPendingInterruption,
|
||||
WHV_REGISTER_NAME_WHvRegisterInterruptState,
|
||||
];
|
||||
®_NAMES
|
||||
}
|
||||
pub(super) fn as_ptr(&self) -> *const WHV_REGISTER_VALUE {
|
||||
self.register_values.as_ptr()
|
||||
}
|
||||
pub(super) fn as_mut_ptr(&mut self) -> *mut WHV_REGISTER_VALUE {
|
||||
self.register_values.as_mut_ptr()
|
||||
}
|
||||
|
||||
pub(super) fn into_serializable(self) -> SerializedWhpxInterruptRegs {
|
||||
SerializedWhpxInterruptRegs {
|
||||
// SAFETY: This register is a valid u64.
|
||||
pending_interruption: unsafe { self.register_values[0].PendingInterruption.AsUINT64 },
|
||||
// SAFETY: This register is a valid u64.
|
||||
interrupt_state: unsafe { self.register_values[1].InterruptState.AsUINT64 },
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn from_serializable(serialized_regs: SerializedWhpxInterruptRegs) -> Self {
|
||||
let mut whpx_interrupt_regs: WhpxInterruptRegs = Default::default();
|
||||
whpx_interrupt_regs.register_values[0]
|
||||
.PendingInterruption
|
||||
.AsUINT64 = serialized_regs.pending_interruption;
|
||||
whpx_interrupt_regs.register_values[1]
|
||||
.InterruptState
|
||||
.AsUINT64 = serialized_regs.interrupt_state;
|
||||
whpx_interrupt_regs
|
||||
}
|
||||
}
|
||||
|
||||
// list of MSR registers for whpx, and their actual ids
|
||||
pub(super) const MSR_TSC: u32 = 0x00000010;
|
||||
pub(super) const MSR_EFER: u32 = 0xc0000080;
|
||||
|
|
|
@ -1101,14 +1101,45 @@ impl VcpuX86_64 for WhpxVcpu {
|
|||
})
|
||||
}
|
||||
|
||||
// TODO: b/270734340 implement
|
||||
fn get_interrupt_state(&self) -> Result<serde_json::Value> {
|
||||
Err(Error::new(EOPNOTSUPP))
|
||||
let mut whpx_interrupt_regs: WhpxInterruptRegs = Default::default();
|
||||
let reg_names = WhpxInterruptRegs::get_register_names();
|
||||
// SAFETY: we have enough space for all the registers & the memory lives for the duration
|
||||
// of the FFI call.
|
||||
check_whpx!(unsafe {
|
||||
WHvGetVirtualProcessorRegisters(
|
||||
self.vm_partition.partition,
|
||||
self.index,
|
||||
reg_names as *const WHV_REGISTER_NAME,
|
||||
reg_names.len() as u32,
|
||||
whpx_interrupt_regs.as_mut_ptr(),
|
||||
)
|
||||
})?;
|
||||
|
||||
serde_json::to_value(whpx_interrupt_regs.into_serializable()).map_err(|e| {
|
||||
error!("failed to serialize interrupt state: {:?}", e);
|
||||
Error::new(EIO)
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: b/270734340 implement
|
||||
fn set_interrupt_state(&self, _data: serde_json::Value) -> Result<()> {
|
||||
Err(Error::new(EOPNOTSUPP))
|
||||
fn set_interrupt_state(&self, data: serde_json::Value) -> Result<()> {
|
||||
let whpx_interrupt_regs =
|
||||
WhpxInterruptRegs::from_serializable(serde_json::from_value(data).map_err(|e| {
|
||||
error!("failed to serialize interrupt state: {:?}", e);
|
||||
Error::new(EIO)
|
||||
})?);
|
||||
let reg_names = WhpxInterruptRegs::get_register_names();
|
||||
// SAFETY: we have enough space for all the registers & the memory lives for the duration
|
||||
// of the FFI call.
|
||||
check_whpx!(unsafe {
|
||||
WHvSetVirtualProcessorRegisters(
|
||||
self.vm_partition.partition,
|
||||
self.index,
|
||||
reg_names as *const WHV_REGISTER_NAME,
|
||||
reg_names.len() as u32,
|
||||
whpx_interrupt_regs.as_ptr(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Gets the VCPU debug registers.
|
||||
|
|
Loading…
Reference in a new issue