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