From f0360aff8306d2a32adacb46e5557bd6bb98659a Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 13 Nov 2020 11:15:38 +0100 Subject: [PATCH] hypervisor: Architecture agnostic instruction emulation interface In order to emulate instructions, we need a way to get access to some of the guest resources. The PlatformEmulator interface provides guest memory and CPU state access to emulator implementations. Typically, an hypervisor will implement PlatformEmulator for architecture specific instruction emulators to build their framework on top of. Signed-off-by: Samuel Ortiz --- hypervisor/src/arch/emulator/mod.rs | 122 ++++++++++++++++++++++++++++ hypervisor/src/arch/mod.rs | 2 + 2 files changed, 124 insertions(+) create mode 100644 hypervisor/src/arch/emulator/mod.rs diff --git a/hypervisor/src/arch/emulator/mod.rs b/hypervisor/src/arch/emulator/mod.rs new file mode 100644 index 000000000..678b57cd8 --- /dev/null +++ b/hypervisor/src/arch/emulator/mod.rs @@ -0,0 +1,122 @@ +// +// Copyright © 2020 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +extern crate thiserror; + +use core::fmt::Debug; +use std::fmt::{self, Display}; +use thiserror::Error; + +#[derive(Clone, Copy, Error, Debug)] +pub struct Exception { + vector: T, + ip: u64, + error: Option, + payload: Option, +} + +impl Display for Exception { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Exception {:?} at IP {:#x}", self.vector, self.ip) + } +} + +#[derive(Error, Debug)] +pub enum PlatformError { + #[error("Invalid register: {0}")] + InvalidRegister(#[source] anyhow::Error), + + #[error("Memory read failure: {0}")] + MemoryReadFailure(#[source] anyhow::Error), + + #[error("Memory write failure: {0}")] + MemoryWriteFailure(#[source] anyhow::Error), + + #[error("Get CPU state failure: {0}")] + GetCpuStateFailure(#[source] anyhow::Error), + + #[error("Set CPU state failure: {0}")] + SetCpuStateFailure(#[source] anyhow::Error), + + #[error("Unmapped virtual address: {0}")] + UnmappedGVA(#[source] anyhow::Error), +} + +#[derive(Error, Debug)] +pub enum EmulationError { + #[error("Unsupported instruction: {0}")] + UnsupportedInstruction(#[source] anyhow::Error), + + #[error("Unsupported memory size: {0}")] + UnsupportedMemorySize(#[source] anyhow::Error), + + #[error("Invalid operand: {0}")] + InvalidOperand(#[source] anyhow::Error), + + #[error("Wrong number of operands: {0}")] + WrongNumberOperands(#[source] anyhow::Error), + + #[error("Instruction Exception: {0}")] + InstructionException(Exception), + + #[error("Platform emulation error: {0}")] + PlatformEmulationError(PlatformError), +} + +/// The PlatformEmulator trait emulates a guest platform. +/// It's mostly a guest resources (memory and CPU state) getter and setter. +/// +/// A CpuState is an architecture specific type, representing a CPU state. +/// The emulator and its instruction handlers modify a given CPU state and +/// eventually ask the platform to commit it back through `set_cpu_state`. +pub trait PlatformEmulator: Send + Sync { + type CpuState: Clone; + + /// Read guest memory into a u8 slice. + /// + /// # Arguments + /// + /// * `gva` - Guest virtual address to read from. + /// * `data` - Data slice to read into. + /// + fn read_memory(&self, gva: u64, data: &mut [u8]) -> Result<(), PlatformError>; + + /// Write a u8 slice into guest memory. + /// + /// # Arguments + /// + /// * `gva` - Guest virtual address to write into. + /// * `data` - Data slice to be written. + /// + fn write_memory(&mut self, gva: u64, data: &[u8]) -> Result<(), PlatformError>; + + /// Get a CPU state from the guest. + /// + /// # Arguments + /// + /// * `cpu_id` - Logical CPU ID. + /// + fn cpu_state(&self, cpu_id: usize) -> Result; + + /// Set a guest CPU state. + /// + /// # Arguments + /// + /// * `cpu_id` - Logical CPU ID. + /// * `state` - State to set the CPU into. + /// + fn set_cpu_state(&self, cpu_id: usize, state: Self::CpuState) -> Result<(), PlatformError>; + + /// Translate a guest virtual address into a physical one + /// + /// # Arguments + /// + /// * `gva` - Guest virtual address to translate. + /// + fn gva_to_gpa(&self, gva: u64) -> Result; +} + +pub type EmulationResult = std::result::Result>; diff --git a/hypervisor/src/arch/mod.rs b/hypervisor/src/arch/mod.rs index b77d2630a..a919f0ee1 100644 --- a/hypervisor/src/arch/mod.rs +++ b/hypervisor/src/arch/mod.rs @@ -11,5 +11,7 @@ // Copyright © 2020, Microsoft Corporation // +pub mod emulator; + #[cfg(target_arch = "x86_64")] pub mod x86;