xref: /cloud-hypervisor/hypervisor/src/arch/emulator/mod.rs (revision 9af2968a7dc47b89bf07ea9dc5e735084efcfa3a)
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