crosvm/hypervisor/src/x86_64.rs
Zach Reizner 304e731cdb make hypervisor traits object safe
This allows code to create references to traits such as `&dyn Vcpu` for
`&dyn IrqChip`. This also allows keeping such traits inside of opaque
`Box` like wrappers.

To achieve this, trait methods referencing `Self` have an additonal
`where` clause that restricts them to sized types. Associated types are
removed and replaced with their trait equivalents (as parameters) or an
opaque Box (as return values).

To work around certain cases where a concrete type is needed, such as
for KVM based `IrqChip` impls, the `downcast_rs` trait is used to allow
`dynamic_cast` style casting.

The binary size impact of this change is small. For comparison, here is
the size change with this commit:

armv7a  -0.49% (-9 kiB)
aarch64 -0.17% (-3 kiB)
x86_64  +1.77% (+40 KiB)

BUG=None
TEST=build_test

Cq-Depend: chromium:2466660
Change-Id: I1a408734832d2971ea2979c1bc64b2ffe051b02d
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2439298
Reviewed-by: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Zach Reizner <zachr@chromium.org>
2020-10-15 14:31:20 +00:00

553 lines
17 KiB
Rust

// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use base::{error, Result};
use bit_field::*;
use downcast_rs::impl_downcast;
use msg_socket::MsgOnSocket;
use vm_memory::GuestAddress;
use crate::{Hypervisor, IrqRoute, IrqSource, IrqSourceChip, Vcpu, Vm};
/// A trait for managing cpuids for an x86_64 hypervisor and for checking its capabilities.
pub trait HypervisorX86_64: Hypervisor {
/// Get the system supported CPUID values.
fn get_supported_cpuid(&self) -> Result<CpuId>;
/// Get the system emulated CPUID values.
fn get_emulated_cpuid(&self) -> Result<CpuId>;
/// Gets the list of supported MSRs.
fn get_msr_index_list(&self) -> Result<Vec<u32>>;
}
/// A wrapper for using a VM on x86_64 and getting/setting its state.
pub trait VmX86_64: Vm {
/// Gets the `HypervisorX86_64` that created this VM.
fn get_hypervisor(&self) -> &dyn HypervisorX86_64;
/// Create a Vcpu with the specified Vcpu ID.
fn create_vcpu(&self, id: usize) -> Result<Box<dyn VcpuX86_64>>;
/// Sets the address of the three-page region in the VM's address space.
fn set_tss_addr(&self, addr: GuestAddress) -> Result<()>;
/// Sets the address of a one-page region in the VM's address space.
fn set_identity_map_addr(&self, addr: GuestAddress) -> Result<()>;
}
/// A wrapper around creating and using a VCPU on x86_64.
pub trait VcpuX86_64: Vcpu {
/// Request the VCPU to exit when it becomes possible to inject interrupts into the guest.
fn request_interrupt_window(&self);
/// Checks if we can inject an interrupt into the VCPU.
fn ready_for_interrupt(&self) -> bool;
/// Injects interrupt vector `irq` into the VCPU.
fn interrupt(&self, irq: u32) -> Result<()>;
/// Gets the VCPU general purpose registers.
fn get_regs(&self) -> Result<Regs>;
/// Sets the VCPU general purpose registers.
fn set_regs(&self, regs: &Regs) -> Result<()>;
/// Gets the VCPU special registers.
fn get_sregs(&self) -> Result<Sregs>;
/// Sets the VCPU special registers.
fn set_sregs(&self, sregs: &Sregs) -> Result<()>;
/// Gets the VCPU FPU registers.
fn get_fpu(&self) -> Result<Fpu>;
/// Sets the VCPU FPU registers.
fn set_fpu(&self, fpu: &Fpu) -> Result<()>;
/// Gets the VCPU debug registers.
fn get_debugregs(&self) -> Result<DebugRegs>;
/// Sets the VCPU debug registers.
fn set_debugregs(&self, debugregs: &DebugRegs) -> Result<()>;
/// Gets the VCPU extended control registers.
fn get_xcrs(&self) -> Result<Vec<Register>>;
/// Sets the VCPU extended control registers.
fn set_xcrs(&self, xcrs: &[Register]) -> Result<()>;
/// Gets the model-specific registers. `msrs` specifies the MSR indexes to be queried, and
/// on success contains their indexes and values.
fn get_msrs(&self, msrs: &mut Vec<Register>) -> Result<()>;
/// Sets the model-specific registers.
fn set_msrs(&self, msrs: &[Register]) -> Result<()>;
/// Sets up the data returned by the CPUID instruction.
fn set_cpuid(&self, cpuid: &CpuId) -> Result<()>;
/// Gets the system emulated hyper-v CPUID values.
fn get_hyperv_cpuid(&self) -> Result<CpuId>;
}
impl_downcast!(VcpuX86_64);
/// A CpuId Entry contains supported feature information for the given processor.
/// This can be modified by the hypervisor to pass additional information to the guest kernel
/// about the hypervisor or vm. Information is returned in the eax, ebx, ecx and edx registers
/// by the cpu for a given function and index/subfunction (passed into the cpu via the eax and ecx
/// register respectively).
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct CpuIdEntry {
pub function: u32,
pub index: u32,
// flags is needed for KVM. We store it on CpuIdEntry to preserve the flags across
// get_supported_cpuids() -> kvm_cpuid2 -> CpuId -> kvm_cpuid2 -> set_cpuid().
pub flags: u32,
pub eax: u32,
pub ebx: u32,
pub ecx: u32,
pub edx: u32,
}
/// A container for the list of cpu id entries for the hypervisor and underlying cpu.
pub struct CpuId {
pub cpu_id_entries: Vec<CpuIdEntry>,
}
impl CpuId {
/// Constructs a new CpuId, with space allocated for `initial_capacity` CpuIdEntries.
pub fn new(initial_capacity: usize) -> Self {
CpuId {
cpu_id_entries: Vec::with_capacity(initial_capacity),
}
}
}
#[bitfield]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DestinationMode {
Physical = 0,
Logical = 1,
}
#[bitfield]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TriggerMode {
Edge = 0,
Level = 1,
}
#[bitfield]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DeliveryMode {
Fixed = 0b000,
Lowest = 0b001,
SMI = 0b010, // System management interrupt
RemoteRead = 0b011, // This is no longer supported by intel.
NMI = 0b100, // Non maskable interrupt
Init = 0b101,
Startup = 0b110,
External = 0b111,
}
#[bitfield]
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct MsiAddressMessage {
pub reserved: BitField2,
#[bits = 1]
pub destination_mode: DestinationMode,
pub redirection_hint: BitField1,
pub reserved_2: BitField8,
pub destination_id: BitField8,
// According to Intel's implementation of MSI, these bits must always be 0xfee.
pub always_0xfee: BitField12,
}
#[bitfield]
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct MsiDataMessage {
pub vector: BitField8,
#[bits = 3]
pub delivery_mode: DeliveryMode,
pub reserved: BitField3,
pub level: BitField1,
#[bits = 1]
pub trigger: TriggerMode,
pub reserved2: BitField16,
}
#[bitfield]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DeliveryStatus {
Idle = 0,
Pending = 1,
}
/// Represents a IOAPIC redirection table entry.
#[bitfield]
#[derive(Clone, Copy, Default, PartialEq, Eq)]
pub struct IoapicRedirectionTableEntry {
vector: BitField8,
#[bits = 3]
delivery_mode: DeliveryMode,
#[bits = 1]
dest_mode: DestinationMode,
#[bits = 1]
delivery_status: DeliveryStatus,
polarity: BitField1,
remote_irr: bool,
#[bits = 1]
trigger_mode: TriggerMode,
interrupt_mask: bool, // true iff interrupts are masked.
reserved: BitField39,
dest_id: BitField8,
}
/// Number of pins on the IOAPIC.
pub const NUM_IOAPIC_PINS: usize = 24;
/// Represents the state of the IOAPIC.
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct IoapicState {
/// base_address is the memory base address for this IOAPIC. It cannot be changed.
pub base_address: u64,
/// ioregsel register. Used for selecting which entry of the redirect table to read/write.
pub ioregsel: u8,
/// ioapicid register. Bits 24 - 27 contain the APIC ID for this device.
pub ioapicid: u32,
/// current_interrupt_level_bitmap represents a bitmap of the state of all of the irq lines
pub current_interrupt_level_bitmap: u32,
/// redirect_table contains the irq settings for each irq line
pub redirect_table: [IoapicRedirectionTableEntry; 24],
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PicSelect {
Primary = 0,
Secondary = 1,
}
#[repr(C)]
#[derive(enumn::N, Debug, Clone, Copy, PartialEq, Eq)]
pub enum PicInitState {
Icw1 = 0,
Icw2 = 1,
Icw3 = 2,
Icw4 = 3,
}
/// Convenience implementation for converting from a u8
impl From<u8> for PicInitState {
fn from(item: u8) -> Self {
PicInitState::n(item).unwrap_or_else(|| {
error!("Invalid PicInitState {}, setting to 0", item);
PicInitState::Icw1
})
}
}
impl Default for PicInitState {
fn default() -> Self {
PicInitState::Icw1
}
}
/// Represents the state of the PIC.
#[repr(C)]
#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)]
pub struct PicState {
/// Edge detection.
pub last_irr: u8,
/// Interrupt Request Register.
pub irr: u8,
/// Interrupt Mask Register.
pub imr: u8,
/// Interrupt Service Register.
pub isr: u8,
/// Highest priority, for priority rotation.
pub priority_add: u8,
pub irq_base: u8,
pub read_reg_select: bool,
pub poll: bool,
pub special_mask: bool,
pub init_state: PicInitState,
pub auto_eoi: bool,
pub rotate_on_auto_eoi: bool,
pub special_fully_nested_mode: bool,
/// PIC takes either 3 or 4 bytes of initialization command word during
/// initialization. use_4_byte_icw is true if 4 bytes of ICW are needed.
pub use_4_byte_icw: bool,
/// "Edge/Level Control Registers", for edge trigger selection.
/// When a particular bit is set, the corresponding IRQ is in level-triggered mode. Otherwise it
/// is in edge-triggered mode.
pub elcr: u8,
pub elcr_mask: u8,
}
/// The LapicState represents the state of an x86 CPU's Local APIC.
/// The Local APIC consists of 64 128-bit registers, but only the first 32-bits of each register
/// can be used, so this structure only stores the first 32-bits of each register.
#[repr(C)]
#[derive(Clone, Copy)]
pub struct LapicState {
pub regs: [LapicRegister; 64],
}
pub type LapicRegister = u32;
// rust arrays longer than 32 need custom implementations of Debug
impl std::fmt::Debug for LapicState {
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
self.regs[..].fmt(formatter)
}
}
// rust arrays longer than 32 need custom implementations of PartialEq
impl PartialEq for LapicState {
fn eq(&self, other: &LapicState) -> bool {
self.regs[..] == other.regs[..]
}
}
// Lapic equality is reflexive, so we impl Eq
impl Eq for LapicState {}
/// The PitState represents the state of the PIT (aka the Programmable Interval Timer).
/// The state is simply the state of it's three channels.
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct PitState {
pub channels: [PitChannelState; 3],
/// Hypervisor-specific flags for setting the pit state.
pub flags: u32,
}
/// The PitRWMode enum represents the access mode of a PIT channel.
/// Reads and writes to the Pit happen over Port-mapped I/O, which happens one byte at a time,
/// but the count values and latch values are two bytes. So the access mode controls which of the
/// two bytes will be read when.
#[repr(C)]
#[derive(enumn::N, Clone, Copy, Debug, PartialEq, Eq)]
pub enum PitRWMode {
/// None mode means that no access mode has been set.
None = 0,
/// Least mode means all reads/writes will read/write the least significant byte.
Least = 1,
/// Most mode means all reads/writes will read/write the most significant byte.
Most = 2,
/// Both mode means first the least significant byte will be read/written, then the
/// next read/write will read/write the most significant byte.
Both = 3,
}
/// Convenience implementation for converting from a u8
impl From<u8> for PitRWMode {
fn from(item: u8) -> Self {
PitRWMode::n(item).unwrap_or_else(|| {
error!("Invalid PitRWMode value {}, setting to 0", item);
PitRWMode::None
})
}
}
/// The PitRWState enum represents the state of reading to or writing from a channel.
/// This is related to the PitRWMode, it mainly gives more detail about the state of the channel
/// with respect to PitRWMode::Both.
#[repr(C)]
#[derive(enumn::N, Clone, Copy, Debug, PartialEq, Eq)]
pub enum PitRWState {
/// None mode means that no access mode has been set.
None = 0,
/// LSB means that the channel is in PitRWMode::Least access mode.
LSB = 1,
/// MSB means that the channel is in PitRWMode::Most access mode.
MSB = 2,
/// Word0 means that the channel is in PitRWMode::Both mode, and the least sginificant byte
/// has not been read/written yet.
Word0 = 3,
/// Word1 means that the channel is in PitRWMode::Both mode and the least significant byte
/// has already been read/written, and the next byte to be read/written will be the most
/// significant byte.
Word1 = 4,
}
/// Convenience implementation for converting from a u8
impl From<u8> for PitRWState {
fn from(item: u8) -> Self {
PitRWState::n(item).unwrap_or_else(|| {
error!("Invalid PitRWState value {}, setting to 0", item);
PitRWState::None
})
}
}
/// The PitChannelState represents the state of one of the PIT's three counters.
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct PitChannelState {
/// The starting value for the counter.
pub count: u32,
/// Stores the channel count from the last time the count was latched.
pub latched_count: u16,
/// Indicates the PitRWState state of reading the latch value.
pub count_latched: PitRWState,
/// Indicates whether ReadBack status has been latched.
pub status_latched: bool,
/// Stores the channel status from the last time the status was latched. The status contains
/// information about the access mode of this channel, but changing those bits in the status
/// will not change the behavior of the pit.
pub status: u8,
/// Indicates the PitRWState state of reading the counter.
pub read_state: PitRWState,
/// Indicates the PitRWState state of writing the counter.
pub write_state: PitRWState,
/// Stores the value with which the counter was initialized. Counters are 16-
/// bit values with an effective range of 1-65536 (65536 represented by 0).
pub reload_value: u16,
/// The command access mode of this channel.
pub rw_mode: PitRWMode,
/// The operation mode of this channel.
pub mode: u8,
/// Whether or not we are in bcd mode. Not supported by KVM or crosvm's PIT implementation.
pub bcd: bool,
/// Value of the gate input pin. This only applies to channel 2.
pub gate: bool,
/// Nanosecond timestamp of when the count value was loaded.
pub count_load_time: u64,
}
// Convenience constructors for IrqRoutes
impl IrqRoute {
pub fn ioapic_irq_route(irq_num: u32) -> IrqRoute {
IrqRoute {
gsi: irq_num,
source: IrqSource::Irqchip {
chip: IrqSourceChip::Ioapic,
pin: irq_num,
},
}
}
pub fn pic_irq_route(id: IrqSourceChip, irq_num: u32) -> IrqRoute {
IrqRoute {
gsi: irq_num,
source: IrqSource::Irqchip {
chip: id,
pin: irq_num % 8,
},
}
}
}
/// State of a VCPU's general purpose registers.
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct Regs {
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,
}
/// State of a memory segment.
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct Segment {
pub base: u64,
pub limit: u32,
pub selector: u16,
pub type_: u8,
pub present: u8,
pub dpl: u8,
pub db: u8,
pub s: u8,
pub l: u8,
pub g: u8,
pub avl: u8,
}
/// State of a global descriptor table or interrupt descriptor table.
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct DescriptorTable {
pub base: u64,
pub limit: u16,
}
/// State of a VCPU's special registers.
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct Sregs {
pub cs: Segment,
pub ds: Segment,
pub es: Segment,
pub fs: Segment,
pub gs: Segment,
pub ss: Segment,
pub tr: Segment,
pub ldt: Segment,
pub gdt: DescriptorTable,
pub idt: DescriptorTable,
pub cr0: u64,
pub cr2: u64,
pub cr3: u64,
pub cr4: u64,
pub cr8: u64,
pub efer: u64,
pub apic_base: u64,
/// A bitmap of pending external interrupts. At most one bit may be set. This interrupt has
/// been acknowledged by the APIC but not yet injected into the cpu core.
pub interrupt_bitmap: [u64; 4usize],
}
/// State of a VCPU's floating point unit.
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct Fpu {
pub fpr: [[u8; 16usize]; 8usize],
pub fcw: u16,
pub fsw: u16,
pub ftwx: u8,
pub last_opcode: u16,
pub last_ip: u64,
pub last_dp: u64,
pub xmm: [[u8; 16usize]; 16usize],
pub mxcsr: u32,
}
/// State of a VCPU's debug registers.
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct DebugRegs {
pub db: [u64; 4usize],
pub dr6: u64,
pub dr7: u64,
}
/// State of one VCPU register. Currently used for MSRs and XCRs.
#[derive(Debug, Default, Copy, Clone, MsgOnSocket)]
pub struct Register {
pub id: u32,
pub value: u64,
}