xref: /cloud-hypervisor/hypervisor/src/arch/emulator/mod.rs (revision 5e52729453cb62edbe4fb3a4aa24f8cca31e667e)
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 {e:x}"))
28                 .unwrap_or_else(|| "".to_owned()),
29             self.payload
30                 .map(|payload| format!(": payload {payload:x}"))
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 {
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