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;