hypervisor x86: provide a generic LapicState structure

This requires making get/set_lapic_reg part of the type.

For the moment we cannot provide a default variant for the new type,
because picking one will be wrong for the other hypervisor, so I just
drop the test cases that requires LapicState::default().

Signed-off-by: Wei Liu <liuwe@microsoft.com>
This commit is contained in:
Wei Liu
2022-07-18 15:47:51 +00:00
committed by Liu Wei
parent d461daa7fa
commit 05e5106b9b
10 changed files with 132 additions and 86 deletions

View File

@@ -254,3 +254,68 @@ pub struct FpuState {
pub xmm: [[u8; 16usize]; 16usize],
pub mxcsr: u32,
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub enum LapicState {
#[cfg(feature = "kvm")]
Kvm(kvm_bindings::kvm_lapic_state),
#[cfg(feature = "mshv")]
Mshv(mshv_bindings::LapicState),
}
#[cfg(any(feature = "kvm", feature = "mshv"))]
impl LapicState {
pub fn get_klapic_reg(&self, reg_offset: usize) -> u32 {
use byteorder::{LittleEndian, ReadBytesExt};
use std::io::Cursor;
use std::mem;
let sliceu8 = match self {
#[cfg(feature = "kvm")]
LapicState::Kvm(s) => unsafe {
// This array is only accessed as parts of a u32 word, so interpret it as a u8 array.
// Cursors are only readable on arrays of u8, not i8(c_char).
mem::transmute::<&[i8], &[u8]>(&s.regs[reg_offset..])
},
#[cfg(feature = "mshv")]
LapicState::Mshv(s) => unsafe {
// This array is only accessed as parts of a u32 word, so interpret it as a u8 array.
// Cursors are only readable on arrays of u8, not i8(c_char).
mem::transmute::<&[i8], &[u8]>(&s.regs[reg_offset..])
},
};
let mut reader = Cursor::new(sliceu8);
// Following call can't fail if the offsets defined above are correct.
reader
.read_u32::<LittleEndian>()
.expect("Failed to read klapic register")
}
pub fn set_klapic_reg(&mut self, reg_offset: usize, value: u32) {
use byteorder::{LittleEndian, WriteBytesExt};
use std::io::Cursor;
use std::mem;
let sliceu8 = match self {
#[cfg(feature = "kvm")]
LapicState::Kvm(s) => unsafe {
// This array is only accessed as parts of a u32 word, so interpret it as a u8 array.
// Cursors are only readable on arrays of u8, not i8(c_char).
mem::transmute::<&mut [i8], &mut [u8]>(&mut s.regs[reg_offset..])
},
#[cfg(feature = "mshv")]
LapicState::Mshv(s) => unsafe {
// This array is only accessed as parts of a u32 word, so interpret it as a u8 array.
// Cursors are only readable on arrays of u8, not i8(c_char).
mem::transmute::<&mut [i8], &mut [u8]>(&mut s.regs[reg_offset..])
},
};
let mut writer = Cursor::new(sliceu8);
// Following call can't fail if the offsets defined above are correct.
writer
.write_u32::<LittleEndian>(value)
.expect("Failed to write klapic register")
}
}

View File

@@ -13,12 +13,10 @@ use crate::aarch64::VcpuInit;
#[cfg(target_arch = "aarch64")]
use crate::aarch64::{RegList, Register, StandardRegisters};
#[cfg(target_arch = "x86_64")]
use crate::arch::x86::{CpuIdEntry, FpuState, SpecialRegisters, StandardRegisters};
use crate::arch::x86::{CpuIdEntry, FpuState, LapicState, SpecialRegisters, StandardRegisters};
#[cfg(feature = "tdx")]
use crate::kvm::{TdxExitDetails, TdxExitStatus};
#[cfg(target_arch = "x86_64")]
use crate::x86_64::LapicState;
#[cfg(target_arch = "x86_64")]
use crate::x86_64::MsrEntries;
use crate::CpuState;
#[cfg(target_arch = "aarch64")]

View File

@@ -47,7 +47,7 @@ use vmm_sys_util::eventfd::EventFd;
pub mod x86_64;
#[cfg(target_arch = "x86_64")]
use crate::arch::x86::{
CpuIdEntry, FpuState, SpecialRegisters, StandardRegisters, NUM_IOAPIC_PINS,
CpuIdEntry, FpuState, LapicState, SpecialRegisters, StandardRegisters, NUM_IOAPIC_PINS,
};
#[cfg(target_arch = "x86_64")]
use crate::ClockData;
@@ -65,7 +65,7 @@ use kvm_bindings::{
#[cfg(target_arch = "x86_64")]
use x86_64::check_required_kvm_extensions;
#[cfg(target_arch = "x86_64")]
pub use x86_64::{CpuId, ExtendedControlRegisters, LapicState, MsrEntries, VcpuKvmState, Xsave};
pub use x86_64::{CpuId, ExtendedControlRegisters, MsrEntries, VcpuKvmState, Xsave};
// aarch64 dependencies
#[cfg(target_arch = "aarch64")]
pub mod aarch64;
@@ -1374,17 +1374,20 @@ impl cpu::Vcpu for KvmVcpu {
/// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
///
fn get_lapic(&self) -> cpu::Result<LapicState> {
self.fd
Ok(self
.fd
.get_lapic()
.map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into()))
.map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into()))?
.into())
}
#[cfg(target_arch = "x86_64")]
///
/// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
///
fn set_lapic(&self, klapic: &LapicState) -> cpu::Result<()> {
let klapic: kvm_bindings::kvm_lapic_state = (*klapic).clone().into();
self.fd
.set_lapic(klapic)
.set_lapic(&klapic)
.map_err(|e| cpu::HypervisorCpuError::SetLapicState(e.into()))
}
#[cfg(target_arch = "x86_64")]

View File

@@ -9,8 +9,8 @@
//
use crate::arch::x86::{
CpuIdEntry, DescriptorTable, FpuState, SegmentRegister, SpecialRegisters, StandardRegisters,
CPUID_FLAG_VALID_INDEX,
CpuIdEntry, DescriptorTable, FpuState, LapicState, SegmentRegister, SpecialRegisters,
StandardRegisters, CPUID_FLAG_VALID_INDEX,
};
use crate::kvm::{Cap, Kvm, KvmError, KvmResult};
use serde::{Deserialize, Serialize};
@@ -20,7 +20,7 @@ use serde::{Deserialize, Serialize};
///
pub use {
kvm_bindings::kvm_cpuid_entry2, kvm_bindings::kvm_dtable, kvm_bindings::kvm_fpu,
kvm_bindings::kvm_lapic_state as LapicState, kvm_bindings::kvm_mp_state as MpState,
kvm_bindings::kvm_lapic_state, kvm_bindings::kvm_mp_state as MpState,
kvm_bindings::kvm_msr_entry as MsrEntry, kvm_bindings::kvm_regs, kvm_bindings::kvm_segment,
kvm_bindings::kvm_sregs, kvm_bindings::kvm_vcpu_events as VcpuEvents,
kvm_bindings::kvm_xcrs as ExtendedControlRegisters, kvm_bindings::kvm_xsave as Xsave,
@@ -295,3 +295,20 @@ impl From<FpuState> for kvm_fpu {
}
}
}
impl From<LapicState> for kvm_lapic_state {
fn from(s: LapicState) -> Self {
match s {
LapicState::Kvm(s) => s,
/* Needed in case other hypervisors are enabled */
#[allow(unreachable_patterns)]
_ => panic!("LapicState is not valid"),
}
}
}
impl From<kvm_lapic_state> for LapicState {
fn from(s: kvm_lapic_state) -> Self {
LapicState::Kvm(s)
}
}

View File

@@ -37,7 +37,7 @@ use std::fs::File;
use std::os::unix::io::AsRawFd;
#[cfg(target_arch = "x86_64")]
use crate::arch::x86::{CpuIdEntry, FpuState, SpecialRegisters, StandardRegisters};
use crate::arch::x86::{CpuIdEntry, FpuState, LapicState, SpecialRegisters, StandardRegisters};
const DIRTY_BITMAP_CLEAR_DIRTY: u64 = 0x4;
const DIRTY_BITMAP_SET_DIRTY: u64 = 0x8;
@@ -543,17 +543,20 @@ impl cpu::Vcpu for MshvVcpu {
/// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
///
fn get_lapic(&self) -> cpu::Result<LapicState> {
self.fd
Ok(self
.fd
.get_lapic()
.map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into()))
.map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into()))?
.into())
}
#[cfg(target_arch = "x86_64")]
///
/// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
///
fn set_lapic(&self, lapic: &LapicState) -> cpu::Result<()> {
let lapic: mshv_bindings::LapicState = (*lapic).clone().into();
self.fd
.set_lapic(lapic)
.set_lapic(&lapic)
.map_err(|e| cpu::HypervisorCpuError::SetLapicState(e.into()))
}
///

View File

@@ -8,7 +8,8 @@
//
//
use crate::arch::x86::{
CpuIdEntry, DescriptorTable, FpuState, SegmentRegister, SpecialRegisters, StandardRegisters,
CpuIdEntry, DescriptorTable, FpuState, LapicState, SegmentRegister, SpecialRegisters,
StandardRegisters,
};
use serde::{Deserialize, Serialize};
use std::fmt;
@@ -19,7 +20,7 @@ use std::fmt;
pub use {
mshv_bindings::hv_cpuid_entry, mshv_bindings::mshv_user_mem_region as MemoryRegion,
mshv_bindings::msr_entry as MsrEntry, mshv_bindings::CpuId, mshv_bindings::DebugRegisters,
mshv_bindings::FloatingPointUnit, mshv_bindings::LapicState,
mshv_bindings::FloatingPointUnit, mshv_bindings::LapicState as MshvLapicState,
mshv_bindings::MiscRegs as MiscRegisters, mshv_bindings::MsrList,
mshv_bindings::Msrs as MsrEntries, mshv_bindings::Msrs,
mshv_bindings::SegmentRegister as MshvSegmentRegister,
@@ -285,3 +286,20 @@ impl From<FpuState> for FloatingPointUnit {
}
}
}
impl From<LapicState> for MshvLapicState {
fn from(s: LapicState) -> Self {
match s {
LapicState::Mshv(s) => s,
/* Needed in case other hypervisors are enabled */
#[allow(unreachable_patterns)]
_ => panic!("LapicState is not valid"),
}
}
}
impl From<MshvLapicState> for LapicState {
fn from(s: MshvLapicState) -> Self {
LapicState::Mshv(s)
}
}