From 546778ebfbd85bb078a47d6de9e3a5248862a597 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 13 Nov 2020 12:30:25 +0100 Subject: [PATCH] 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 --- Cargo.lock | 42 ++++++++++++ hypervisor/Cargo.toml | 5 ++ hypervisor/src/arch/x86/emulator/mod.rs | 86 +++++++++++++++++++++++++ hypervisor/src/arch/x86/mod.rs | 2 + 4 files changed, 135 insertions(+) create mode 100644 hypervisor/src/arch/x86/emulator/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 33d4426fb..e933199b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/hypervisor/Cargo.toml b/hypervisor/Cargo.toml index 40a928173..815ff480b 100644 --- a/hypervisor/Cargo.toml +++ b/hypervisor/Cargo.toml @@ -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"] diff --git a/hypervisor/src/arch/x86/emulator/mod.rs b/hypervisor/src/arch/x86/emulator/mod.rs new file mode 100644 index 000000000..366a8509c --- /dev/null +++ b/hypervisor/src/arch/x86/emulator/mod.rs @@ -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; + + /// 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; + + /// 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); +} diff --git a/hypervisor/src/arch/x86/mod.rs b/hypervisor/src/arch/x86/mod.rs index 6d445d886..ac0e8c69f 100644 --- a/hypervisor/src/arch/x86/mod.rs +++ b/hypervisor/src/arch/x86/mod.rs @@ -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;