hypervisor: x86: Add a CpuStateManager interface

For efficiently emulating x86 instructions, we need to build and pass a
CPU state copy/reference to instruction emulation handlers. Those handlers
will typically modify the CPU state and let the caller commit those
changes back through the PlatformEmulator trait set_cpu_state method.

Hypervisors typically have internal CPU state structures, that maps back
to the correspinding kernel APIs. By implementing the CpuState trait,
instruction emulators will be able to directly work on CPU state
instances that are directly consumable by the underlying hypervisor and
its kernel APIs.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
Samuel Ortiz 2020-11-13 12:30:25 +01:00
parent f0360aff83
commit 546778ebfb
4 changed files with 135 additions and 0 deletions

42
Cargo.lock generated
View File

@ -502,6 +502,7 @@ version = "0.1.0"
dependencies = [
"anyhow",
"arc-swap",
"iced-x86",
"kvm-bindings",
"kvm-ioctls",
"libc",
@ -515,6 +516,17 @@ dependencies = [
"vmm-sys-util",
]
[[package]]
name = "iced-x86"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "248ce8ff0784d2b15f3c3d8b01f529be0e18aa693a2ba7415df76857967c8fc3"
dependencies = [
"lazy_static",
"rustc_version",
"static_assertions",
]
[[package]]
name = "idna"
version = "0.2.0"
@ -1126,6 +1138,15 @@ version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [
"semver",
]
[[package]]
name = "ryu"
version = "1.0.5"
@ -1146,6 +1167,21 @@ dependencies = [
"libc",
]
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "1.0.117"
@ -1217,6 +1253,12 @@ dependencies = [
"parking_lot",
]
[[package]]
name = "static_assertions"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3"
[[package]]
name = "strsim"
version = "0.8.0"

View File

@ -25,3 +25,8 @@ vmm-sys-util = { version = ">=0.5.0", features = ["with-serde"] }
[dependencies.linux-loader]
git = "https://github.com/rust-vmm/linux-loader"
features = ["elf", "bzimage"]
[dependencies.iced-x86]
version = "1.9.1"
default-features = false
features = ["std", "decoder", "op_code_info", "instr_info"]

View File

@ -0,0 +1,86 @@
//
// Copyright © 2020 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
extern crate iced_x86;
use crate::arch::emulator::PlatformError;
use crate::x86_64::SegmentRegister;
use iced_x86::*;
/// CpuStateManager manages an x86 CPU state.
///
/// Instruction emulation handlers get a mutable reference to
/// a `CpuStateManager` implementation, representing the current state of the
/// CPU they have to emulate an instruction stream against. Usually those
/// handlers will modify the CPU state by modifying `CpuState` and it is up to
/// the handler caller to commit those changes back by invoking a
/// `PlatformEmulator` implementation `set_state()` method.
///
pub trait CpuStateManager: Clone {
/// Reads a CPU register.
///
/// # Arguments
///
/// * `reg` - A general purpose, control or debug register.
fn read_reg(&self, reg: Register) -> Result<u64, PlatformError>;
/// Write to a CPU register.
///
/// # Arguments
///
/// * `reg` - A general purpose, control or debug register.
/// * `val` - The value to load.
fn write_reg(&mut self, reg: Register, val: u64) -> Result<(), PlatformError>;
/// Reads a segment register.
///
/// # Arguments
///
/// * `reg` - A segment register.
fn read_segment(&self, reg: Register) -> Result<SegmentRegister, PlatformError>;
/// Write to a segment register.
///
/// # Arguments
///
/// * `reg` - A segment register.
/// * `segment_reg` - The segment register value to load.
fn write_segment(
&mut self,
reg: Register,
segment_reg: SegmentRegister,
) -> Result<(), PlatformError>;
/// Get the CPU instruction pointer.
fn ip(&self) -> u64;
/// Set the CPU instruction pointer.
///
/// # Arguments
///
/// * `ip` - The CPU instruction pointer.
fn set_ip(&mut self, ip: u64);
/// Get the CPU Extended Feature Enable Register.
fn efer(&self) -> u64;
/// Set the CPU Extended Feature Enable Register.
///
/// # Arguments
///
/// * `efer` - The CPU EFER value.
fn set_efer(&mut self, efer: u64);
/// Get the CPU flags.
fn flags(&self) -> u64;
/// Set the CPU flags.
///
/// # Arguments
///
/// * `flags` - The CPU flags
fn set_flags(&mut self, flags: u64);
}

View File

@ -30,6 +30,8 @@ pub mod gdt;
)]
pub mod msr_index;
pub mod emulator;
// MTRR constants
pub const MTRR_ENABLE: u64 = 0x800; // IA32_MTRR_DEF_TYPE MSR: E (MTRRs enabled) flag, bit 11
pub const MTRR_MEM_TYPE_WB: u64 = 0x6;