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