hypervisor: x86: provide a generic StandardRegisters structure

We only need to do this for x86 since MSHV does not have aarch64 support
yet. This reduces unnecessary code churn.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
This commit is contained in:
Wei Liu 2022-07-14 20:59:27 +00:00 committed by Liu Wei
parent d20f647b32
commit 8b7781e267
9 changed files with 165 additions and 27 deletions

View File

@ -10,7 +10,8 @@ use crate::layout::{BOOT_GDT_START, BOOT_IDT_START, PVH_INFO_START};
use crate::GuestMemoryMmap;
use hypervisor::arch::x86::gdt::{gdt_entry, segment_from_gdt};
use hypervisor::arch::x86::regs::CR0_PE;
use hypervisor::x86_64::{FpuState, SpecialRegisters, StandardRegisters};
use hypervisor::arch::x86::StandardRegisters;
use hypervisor::x86_64::{FpuState, SpecialRegisters};
use std::sync::Arc;
use std::{mem, result};
use vm_memory::{Address, Bytes, GuestMemory, GuestMemoryError};

View File

@ -7,8 +7,10 @@
use crate::arch::emulator::{EmulationError, EmulationResult, PlatformEmulator, PlatformError};
use crate::arch::x86::emulator::instructions::*;
use crate::arch::x86::regs::{CR0_PE, EFER_LMA};
use crate::arch::x86::{segment_type_expand_down, segment_type_ro, Exception, SegmentRegisterOps};
use crate::x86_64::{SegmentRegister, SpecialRegisters, StandardRegisters};
use crate::arch::x86::{
segment_type_expand_down, segment_type_ro, Exception, SegmentRegisterOps, StandardRegisters,
};
use crate::x86_64::{SegmentRegister, SpecialRegisters};
use anyhow::Context;
use iced_x86::*;

View File

@ -129,3 +129,26 @@ macro_rules! msr_data {
}
};
}
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "with-serde", derive(Deserialize, Serialize))]
pub struct StandardRegisters {
pub rax: u64,
pub rbx: u64,
pub rcx: u64,
pub rdx: u64,
pub rsi: u64,
pub rdi: u64,
pub rsp: u64,
pub rbp: u64,
pub r8: u64,
pub r9: u64,
pub r10: u64,
pub r11: u64,
pub r12: u64,
pub r13: u64,
pub r14: u64,
pub r15: u64,
pub rip: u64,
pub rflags: u64,
}

View File

@ -12,6 +12,8 @@
use crate::aarch64::VcpuInit;
#[cfg(target_arch = "aarch64")]
use crate::aarch64::{RegList, Register, StandardRegisters};
#[cfg(target_arch = "x86_64")]
use crate::arch::x86::StandardRegisters;
#[cfg(feature = "tdx")]
use crate::kvm::{TdxExitDetails, TdxExitStatus};
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
@ -21,9 +23,7 @@ use crate::x86_64::Xsave;
#[cfg(target_arch = "x86_64")]
use crate::x86_64::{CpuId, LapicState};
#[cfg(target_arch = "x86_64")]
use crate::x86_64::{
ExtendedControlRegisters, FpuState, MsrEntries, SpecialRegisters, StandardRegisters, VcpuEvents,
};
use crate::x86_64::{ExtendedControlRegisters, FpuState, MsrEntries, SpecialRegisters, VcpuEvents};
use crate::CpuState;
#[cfg(target_arch = "aarch64")]
use crate::DeviceAttr;

View File

@ -46,7 +46,7 @@ use vmm_sys_util::eventfd::EventFd;
#[cfg(target_arch = "x86_64")]
pub mod x86_64;
#[cfg(target_arch = "x86_64")]
use crate::arch::x86::NUM_IOAPIC_PINS;
use crate::arch::x86::{StandardRegisters, NUM_IOAPIC_PINS};
#[cfg(target_arch = "x86_64")]
use crate::ClockData;
use crate::{
@ -61,7 +61,7 @@ use kvm_bindings::{
KVM_CAP_SPLIT_IRQCHIP, KVM_GUESTDBG_ENABLE, KVM_GUESTDBG_SINGLESTEP, KVM_GUESTDBG_USE_HW_BP,
};
#[cfg(target_arch = "x86_64")]
use x86_64::{check_required_kvm_extensions, FpuState, SpecialRegisters, StandardRegisters};
use x86_64::{check_required_kvm_extensions, FpuState, SpecialRegisters};
#[cfg(target_arch = "x86_64")]
pub use x86_64::{
CpuId, CpuIdEntry, ExtendedControlRegisters, LapicState, MsrEntries, VcpuKvmState, Xsave,
@ -1052,9 +1052,11 @@ impl cpu::Vcpu for KvmVcpu {
/// Returns the vCPU general purpose registers.
///
fn get_regs(&self) -> cpu::Result<StandardRegisters> {
self.fd
Ok(self
.fd
.get_regs()
.map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into()))
.map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into()))?
.into())
}
///
/// Returns the vCPU general purpose registers.
@ -1158,8 +1160,9 @@ impl cpu::Vcpu for KvmVcpu {
/// Sets the vCPU general purpose registers using the `KVM_SET_REGS` ioctl.
///
fn set_regs(&self, regs: &StandardRegisters) -> cpu::Result<()> {
let regs = (*regs).into();
self.fd
.set_regs(regs)
.set_regs(&regs)
.map_err(|e| cpu::HypervisorCpuError::SetStandardRegs(e.into()))
}
@ -1869,7 +1872,7 @@ impl cpu::Vcpu for KvmVcpu {
cpuid,
msrs,
vcpu_events,
regs,
regs: regs.into(),
sregs,
fpu,
lapic_state,
@ -1938,7 +1941,7 @@ impl cpu::Vcpu for KvmVcpu {
let state: VcpuKvmState = state.clone().into();
self.set_cpuid2(&state.cpuid)?;
self.set_mp_state(state.mp_state.into())?;
self.set_regs(&state.regs)?;
self.set_regs(&state.regs.into())?;
self.set_sregs(&state.sregs)?;
self.set_xsave(&state.xsave)?;
self.set_xcrs(&state.xcrs)?;

View File

@ -8,7 +8,7 @@
//
//
use crate::arch::x86::SegmentRegisterOps;
use crate::arch::x86::{SegmentRegisterOps, StandardRegisters};
use crate::kvm::{Cap, Kvm, KvmError, KvmResult};
use serde::{Deserialize, Serialize};
@ -19,7 +19,7 @@ pub use {
kvm_bindings::kvm_cpuid_entry2 as CpuIdEntry, kvm_bindings::kvm_dtable as DescriptorTable,
kvm_bindings::kvm_fpu as FpuState, kvm_bindings::kvm_lapic_state as LapicState,
kvm_bindings::kvm_mp_state as MpState, kvm_bindings::kvm_msr_entry as MsrEntry,
kvm_bindings::kvm_regs as StandardRegisters, kvm_bindings::kvm_segment as SegmentRegister,
kvm_bindings::kvm_regs, kvm_bindings::kvm_segment as SegmentRegister,
kvm_bindings::kvm_sregs as SpecialRegisters, kvm_bindings::kvm_vcpu_events as VcpuEvents,
kvm_bindings::kvm_xcrs as ExtendedControlRegisters, kvm_bindings::kvm_xsave as Xsave,
kvm_bindings::CpuId, kvm_bindings::MsrList, kvm_bindings::Msrs as MsrEntries,
@ -120,7 +120,7 @@ pub struct VcpuKvmState {
pub cpuid: CpuId,
pub msrs: MsrEntries,
pub vcpu_events: VcpuEvents,
pub regs: StandardRegisters,
pub regs: kvm_regs,
pub sregs: SpecialRegisters,
pub fpu: FpuState,
pub lapic_state: LapicState,
@ -128,3 +128,53 @@ pub struct VcpuKvmState {
pub xcrs: ExtendedControlRegisters,
pub mp_state: MpState,
}
impl From<StandardRegisters> for kvm_regs {
fn from(regs: StandardRegisters) -> Self {
Self {
rax: regs.rax,
rbx: regs.rbx,
rcx: regs.rcx,
rdx: regs.rdx,
rsi: regs.rsi,
rdi: regs.rdi,
rsp: regs.rsp,
rbp: regs.rbp,
r8: regs.r8,
r9: regs.r9,
r10: regs.r10,
r11: regs.r11,
r12: regs.r12,
r13: regs.r13,
r14: regs.r14,
r15: regs.r15,
rip: regs.rip,
rflags: regs.rflags,
}
}
}
impl From<kvm_regs> for StandardRegisters {
fn from(regs: kvm_regs) -> Self {
Self {
rax: regs.rax,
rbx: regs.rbx,
rcx: regs.rcx,
rdx: regs.rdx,
rsi: regs.rsi,
rdi: regs.rdi,
rsp: regs.rsp,
rbp: regs.rbp,
r8: regs.r8,
r9: regs.r9,
r10: regs.r10,
r11: regs.r11,
r12: regs.r12,
r13: regs.r13,
r14: regs.r14,
r15: regs.r15,
rip: regs.rip,
rflags: regs.rflags,
}
}
}

View File

@ -36,6 +36,9 @@ pub use x86_64::*;
use std::fs::File;
use std::os::unix::io::AsRawFd;
#[cfg(target_arch = "x86_64")]
use crate::arch::x86::StandardRegisters;
const DIRTY_BITMAP_CLEAR_DIRTY: u64 = 0x4;
const DIRTY_BITMAP_SET_DIRTY: u64 = 0x8;
@ -272,17 +275,20 @@ impl cpu::Vcpu for MshvVcpu {
/// Returns the vCPU general purpose registers.
///
fn get_regs(&self) -> cpu::Result<StandardRegisters> {
self.fd
Ok(self
.fd
.get_regs()
.map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into()))
.map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into()))?
.into())
}
#[cfg(target_arch = "x86_64")]
///
/// Sets the vCPU general purpose registers.
///
fn set_regs(&self, regs: &StandardRegisters) -> cpu::Result<()> {
let regs = (*regs).into();
self.fd
.set_regs(regs)
.set_regs(&regs)
.map_err(|e| cpu::HypervisorCpuError::SetStandardRegs(e.into()))
}
#[cfg(target_arch = "x86_64")]
@ -619,7 +625,7 @@ impl cpu::Vcpu for MshvVcpu {
let state: VcpuMshvState = state.clone().into();
self.set_msrs(&state.msrs)?;
self.set_vcpu_events(&state.vcpu_events)?;
self.set_regs(&state.regs)?;
self.set_regs(&state.regs.into())?;
self.set_sregs(&state.sregs)?;
self.set_fpu(&state.fpu)?;
self.set_xcrs(&state.xcrs)?;
@ -662,7 +668,7 @@ impl cpu::Vcpu for MshvVcpu {
Ok(VcpuMshvState {
msrs,
vcpu_events,
regs,
regs: regs.into(),
sregs,
fpu,
xcrs,

View File

@ -7,7 +7,7 @@
// Copyright 2018-2019 CrowdStrike, Inc.
//
//
use crate::arch::x86::SegmentRegisterOps;
use crate::arch::x86::{SegmentRegisterOps, StandardRegisters};
use serde::{Deserialize, Serialize};
use std::fmt;
@ -21,7 +21,7 @@ pub use {
mshv_bindings::FloatingPointUnit as FpuState, mshv_bindings::LapicState,
mshv_bindings::MiscRegs as MiscRegisters, mshv_bindings::MsrList,
mshv_bindings::Msrs as MsrEntries, mshv_bindings::Msrs, mshv_bindings::SegmentRegister,
mshv_bindings::SpecialRegisters, mshv_bindings::StandardRegisters,
mshv_bindings::SpecialRegisters, mshv_bindings::StandardRegisters as MshvStandardRegisters,
mshv_bindings::SuspendRegisters, mshv_bindings::VcpuEvents, mshv_bindings::XSave as Xsave,
mshv_bindings::Xcrs as ExtendedControlRegisters,
};
@ -32,7 +32,7 @@ pub const CPUID_FLAG_VALID_INDEX: u32 = 0;
pub struct VcpuMshvState {
pub msrs: MsrEntries,
pub vcpu_events: VcpuEvents,
pub regs: StandardRegisters,
pub regs: MshvStandardRegisters,
pub sregs: SpecialRegisters,
pub fpu: FpuState,
pub xcrs: ExtendedControlRegisters,
@ -130,3 +130,53 @@ impl SegmentRegisterOps for SegmentRegister {
self.db = val;
}
}
impl From<StandardRegisters> for MshvStandardRegisters {
fn from(regs: StandardRegisters) -> Self {
Self {
rax: regs.rax,
rbx: regs.rbx,
rcx: regs.rcx,
rdx: regs.rdx,
rsi: regs.rsi,
rdi: regs.rdi,
rsp: regs.rsp,
rbp: regs.rbp,
r8: regs.r8,
r9: regs.r9,
r10: regs.r10,
r11: regs.r11,
r12: regs.r12,
r13: regs.r13,
r14: regs.r14,
r15: regs.r15,
rip: regs.rip,
rflags: regs.rflags,
}
}
}
impl From<MshvStandardRegisters> for StandardRegisters {
fn from(regs: MshvStandardRegisters) -> Self {
Self {
rax: regs.rax,
rbx: regs.rbx,
rcx: regs.rcx,
rdx: regs.rdx,
rsi: regs.rsi,
rdi: regs.rdi,
rsp: regs.rsp,
rbp: regs.rbp,
r8: regs.r8,
r9: regs.r9,
r10: regs.r10,
r11: regs.r11,
r12: regs.r12,
r13: regs.r13,
r14: regs.r14,
r15: regs.r15,
rip: regs.rip,
rflags: regs.rflags,
}
}
}

View File

@ -36,16 +36,18 @@ use devices::interrupt_controller::InterruptController;
use gdbstub_arch::x86::reg::{X86SegmentRegs, X86_64CoreRegs};
#[cfg(feature = "guest_debug")]
use hypervisor::arch::x86::msr_index;
#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
use hypervisor::arch::x86::StandardRegisters;
#[cfg(target_arch = "aarch64")]
use hypervisor::kvm::kvm_bindings;
#[cfg(feature = "tdx")]
use hypervisor::kvm::{TdxExitDetails, TdxExitStatus};
#[cfg(target_arch = "x86_64")]
use hypervisor::x86_64::CpuId;
#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
use hypervisor::x86_64::SpecialRegisters;
#[cfg(feature = "guest_debug")]
use hypervisor::x86_64::{MsrEntries, MsrEntry};
#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
use hypervisor::x86_64::{SpecialRegisters, StandardRegisters};
use hypervisor::{CpuState, HypervisorCpuError, VmExit, VmOps};
use libc::{c_void, siginfo_t};
#[cfg(feature = "guest_debug")]
@ -2336,7 +2338,8 @@ impl CpuElf64Writable for CpuManager {
mod tests {
use arch::x86_64::interrupts::*;
use arch::x86_64::regs::*;
use hypervisor::x86_64::{FpuState, LapicState, StandardRegisters};
use hypervisor::arch::x86::StandardRegisters;
use hypervisor::x86_64::{FpuState, LapicState};
#[test]
fn test_setlint() {