1 // 2 // Copyright © 2020 Intel Corporation 3 // 4 // SPDX-License-Identifier: Apache-2.0 5 // 6 7 extern crate thiserror; 8 9 use core::fmt::Debug; 10 use std::fmt::{self, Display}; 11 use thiserror::Error; 12 13 #[derive(Clone, Copy, Error, Debug)] 14 pub struct Exception<T: Debug> { 15 vector: T, 16 ip: u64, 17 error: Option<u32>, 18 payload: Option<u64>, 19 } 20 21 impl<T: Debug> Display for Exception<T> { 22 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 23 write!(f, "Exception {:?} at IP {:#x}", self.vector, self.ip) 24 } 25 } 26 27 #[derive(Error, Debug)] 28 pub enum PlatformError { 29 #[error("Invalid address: {0}")] 30 InvalidAddress(#[source] anyhow::Error), 31 32 #[error("Invalid register: {0}")] 33 InvalidRegister(#[source] anyhow::Error), 34 35 #[error("Invalid state: {0}")] 36 InvalidState(#[source] anyhow::Error), 37 38 #[error("Memory read failure: {0}")] 39 MemoryReadFailure(#[source] anyhow::Error), 40 41 #[error("Memory write failure: {0}")] 42 MemoryWriteFailure(#[source] anyhow::Error), 43 44 #[error("Get CPU state failure: {0}")] 45 GetCpuStateFailure(#[source] anyhow::Error), 46 47 #[error("Set CPU state failure: {0}")] 48 SetCpuStateFailure(#[source] anyhow::Error), 49 50 #[error("Translate virtual address: {0}")] 51 TranslateVirtualAddress(#[source] anyhow::Error), 52 53 #[error("Unsupported CPU Mode: {0}")] 54 UnsupportedCpuMode(#[source] anyhow::Error), 55 56 #[error("Invalid instruction operand: {0}")] 57 InvalidOperand(#[source] anyhow::Error), 58 } 59 60 #[derive(Error, Debug)] 61 pub enum EmulationError<T: Debug> { 62 #[error("Unsupported instruction: {0}")] 63 UnsupportedInstruction(#[source] anyhow::Error), 64 65 #[error("Unsupported memory size: {0}")] 66 UnsupportedMemorySize(#[source] anyhow::Error), 67 68 #[error("Invalid operand: {0}")] 69 InvalidOperand(#[source] anyhow::Error), 70 71 #[error("Wrong number of operands: {0}")] 72 WrongNumberOperands(#[source] anyhow::Error), 73 74 #[error("Instruction Exception: {0}")] 75 InstructionException(Exception<T>), 76 77 #[error("Instruction fetching error: {0}")] 78 InstructionFetchingError(#[source] anyhow::Error), 79 80 #[error("Platform emulation error: {0}")] 81 PlatformEmulationError(PlatformError), 82 83 #[error(transparent)] 84 EmulationError(#[from] anyhow::Error), 85 } 86 87 /// The PlatformEmulator trait emulates a guest platform. 88 /// It's mostly a guest resources (memory and CPU state) getter and setter. 89 /// 90 /// A CpuState is an architecture specific type, representing a CPU state. 91 /// The emulator and its instruction handlers modify a given CPU state and 92 /// eventually ask the platform to commit it back through `set_cpu_state`. 93 pub trait PlatformEmulator: Send + Sync { 94 type CpuState: Clone; 95 96 /// Read guest memory into a u8 slice. 97 /// 98 /// # Arguments 99 /// 100 /// * `gva` - Guest virtual address to read from. 101 /// * `data` - Data slice to read into. 102 /// 103 fn read_memory(&self, gva: u64, data: &mut [u8]) -> Result<(), PlatformError>; 104 105 /// Write a u8 slice into guest memory. 106 /// 107 /// # Arguments 108 /// 109 /// * `gva` - Guest virtual address to write into. 110 /// * `data` - Data slice to be written. 111 /// 112 fn write_memory(&mut self, gva: u64, data: &[u8]) -> Result<(), PlatformError>; 113 114 /// Get a CPU state from the guest. 115 /// 116 /// # Arguments 117 /// 118 /// * `cpu_id` - Logical CPU ID. 119 /// 120 fn cpu_state(&self, cpu_id: usize) -> Result<Self::CpuState, PlatformError>; 121 122 /// Set a guest CPU state. 123 /// 124 /// # Arguments 125 /// 126 /// * `cpu_id` - Logical CPU ID. 127 /// * `state` - State to set the CPU into. 128 /// 129 fn set_cpu_state(&self, cpu_id: usize, state: Self::CpuState) -> Result<(), PlatformError>; 130 131 /// Translate a guest virtual address into a physical one 132 /// 133 /// # Arguments 134 /// 135 /// * `gva` - Guest virtual address to translate. 136 /// 137 fn gva_to_gpa(&self, gva: u64) -> Result<u64, PlatformError>; 138 139 /// Fetch instruction bytes from memory. 140 /// 141 /// # Arguments 142 /// 143 /// * `ip` - Instruction pointer virtual address to start fetching instructions from. 144 /// 145 fn fetch(&self, ip: u64, instruction_bytes: &mut [u8]) -> Result<(), PlatformError>; 146 } 147 148 pub type EmulationResult<S, E> = std::result::Result<S, EmulationError<E>>; 149