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