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