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;