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 <sameo@linux.intel.com>
This commit is contained in:
Samuel Ortiz 2020-11-13 11:15:38 +01:00
parent ae96aeda65
commit f0360aff83
2 changed files with 124 additions and 0 deletions

View File

@ -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<T: Debug> {
vector: T,
ip: u64,
error: Option<u32>,
payload: Option<u64>,
}
impl<T: Debug> Display for Exception<T> {
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<T: Debug> {
#[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<T>),
#[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<Self::CpuState, PlatformError>;
/// 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<u64, PlatformError>;
}
pub type EmulationResult<S, E> = std::result::Result<S, EmulationError<E>>;

View File

@ -11,5 +11,7 @@
// Copyright © 2020, Microsoft Corporation
//
pub mod emulator;
#[cfg(target_arch = "x86_64")]
pub mod x86;