Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/hypervisor/src/aarch64.rs
5394 views
1
// Copyright 2020 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
use std::collections::BTreeMap;
6
use std::convert::TryFrom;
7
use std::fmt::Debug;
8
9
use aarch64_sys_reg::AArch64SysRegId;
10
use anyhow::Context;
11
use base::Error;
12
use base::Result;
13
use cros_fdt::Fdt;
14
use downcast_rs::impl_downcast;
15
use libc::EINVAL;
16
use serde::Deserialize;
17
use serde::Serialize;
18
use snapshot::AnySnapshot;
19
use vm_memory::GuestAddress;
20
21
use crate::Hypervisor;
22
use crate::IrqRoute;
23
use crate::IrqSource;
24
use crate::IrqSourceChip;
25
use crate::Vcpu;
26
use crate::Vm;
27
28
/// Represents a version of Power State Coordination Interface (PSCI).
29
#[derive(Eq, Ord, PartialEq, PartialOrd)]
30
pub struct PsciVersion {
31
pub major: u16,
32
pub minor: u16,
33
}
34
35
impl PsciVersion {
36
pub fn new(major: u16, minor: u16) -> Result<Self> {
37
if (major as i16) < 0 {
38
Err(Error::new(EINVAL))
39
} else {
40
Ok(Self { major, minor })
41
}
42
}
43
}
44
45
impl TryFrom<u32> for PsciVersion {
46
type Error = base::Error;
47
48
fn try_from(item: u32) -> Result<Self> {
49
Self::new((item >> 16) as u16, item as u16)
50
}
51
}
52
53
// Aarch64 does not provide a concrete number as to how many registers exist.
54
// The list of registers available exceeds 600 registers
55
pub const AARCH64_MAX_REG_COUNT: usize = 1024;
56
57
pub const PSCI_0_2: PsciVersion = PsciVersion { major: 0, minor: 2 };
58
pub const PSCI_1_0: PsciVersion = PsciVersion { major: 1, minor: 0 };
59
60
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
61
pub enum VcpuRegAArch64 {
62
X(u8),
63
Sp,
64
Pc,
65
Pstate,
66
System(AArch64SysRegId),
67
}
68
69
/// A wrapper for using a VM on aarch64 and getting/setting its state.
70
pub trait VmAArch64: Vm {
71
/// Gets the `Hypervisor` that created this VM.
72
fn get_hypervisor(&self) -> &dyn Hypervisor;
73
74
/// Load pVM firmware for the VM, creating a memslot for it as needed.
75
///
76
/// Only works on protected VMs (i.e. those that support `VmCap::Protected`).
77
fn load_protected_vm_firmware(&mut self, fw_addr: GuestAddress, fw_max_size: u64)
78
-> Result<()>;
79
80
/// Create a Vcpu with the specified Vcpu ID.
81
fn create_vcpu(&self, id: usize) -> Result<Box<dyn VcpuAArch64>>;
82
83
/// Create DT configuration node for the hypervisor.
84
/// `fdt` - Fdt initialized at the root node.
85
/// `phandles` - Map of strings to a phandle.
86
fn create_fdt(&self, fdt: &mut Fdt, phandles: &BTreeMap<&str, u32>) -> cros_fdt::Result<()>;
87
88
// Initialize a VM. Called after building the VM. Presently called before vCPUs are initialized.
89
fn init_arch(
90
&self,
91
payload_entry_address: GuestAddress,
92
fdt_address: GuestAddress,
93
fdt_size: usize,
94
) -> anyhow::Result<()>;
95
96
/// Set an offset that describes a number of counter cycles that are subtracted from both
97
/// virtual and physical counter views.
98
fn set_counter_offset(&self, _offset: u64) -> Result<()> {
99
Err(Error::new(libc::ENOSYS))
100
}
101
}
102
103
/// A wrapper around creating and using a VCPU on aarch64.
104
pub trait VcpuAArch64: Vcpu {
105
/// Does ARM-specific initialization of this VCPU. Inits the VCPU with the preferred target
106
/// VCPU type and the specified `features`, and resets the value of all registers to defaults.
107
/// All VCPUs should be created before calling this function.
108
fn init(&self, features: &[VcpuFeature]) -> Result<()>;
109
110
/// Initializes the ARM Performance Monitor Unit v3 on this VCPU, with overflow interrupt number
111
/// `irq`.
112
fn init_pmu(&self, irq: u64) -> Result<()>;
113
114
/// Checks if ARM ParaVirtualized Time is supported on this VCPU
115
fn has_pvtime_support(&self) -> bool;
116
117
/// Initializes the ARM ParaVirtualized Time on this VCPU, with base address of the stolen time
118
/// structure as `pvtime_ipa`.
119
fn init_pvtime(&self, pvtime_ipa: u64) -> Result<()>;
120
121
/// Sets the value of a register on this VCPU.
122
fn set_one_reg(&self, reg_id: VcpuRegAArch64, data: u64) -> Result<()>;
123
124
/// Gets the value of a register on this VCPU.
125
fn get_one_reg(&self, reg_id: VcpuRegAArch64) -> Result<u64>;
126
127
/// Sets the value of a Neon vector register (V0-V31) on this VCPU.
128
fn set_vector_reg(&self, reg_num: u8, data: u128) -> Result<()>;
129
130
/// Gets the value of a Neon vector register (V0-V31) on this VCPU.
131
fn get_vector_reg(&self, reg_num: u8) -> Result<u128>;
132
133
/// Gets the set of system registers accessible by the hypervisor
134
fn get_system_regs(&self) -> Result<BTreeMap<AArch64SysRegId, u64>>;
135
136
/// Gets the hypervisor specific data for snapshot
137
fn hypervisor_specific_snapshot(&self) -> anyhow::Result<AnySnapshot>;
138
139
/// Restores the hypervisor specific data
140
fn hypervisor_specific_restore(&self, _data: AnySnapshot) -> anyhow::Result<()>;
141
142
/// Gets the value of MPIDR_EL1 on this VCPU.
143
fn get_mpidr(&self) -> Result<u64> {
144
const RES1: u64 = 1 << 31;
145
146
// Assume that MPIDR_EL1.{U,MT} = {0,0}.
147
148
let aff = u64::try_from(self.id()).unwrap();
149
150
Ok(RES1 | aff)
151
}
152
153
/// Gets the current PSCI version.
154
fn get_psci_version(&self) -> Result<PsciVersion>;
155
156
/// Sets up debug registers and configure vcpu for handling guest debug events.
157
fn set_guest_debug(&self, addrs: &[GuestAddress], enable_singlestep: bool) -> Result<()>;
158
159
/// Gets the max number of hardware breakpoints.
160
fn get_max_hw_bps(&self) -> Result<usize>;
161
162
/// Gets the cache architecture information for all cache levels.
163
/// The keys of the map are the lower 4 lower significant bits of CSSELR_EL1, which represents
164
/// the cache level. cache level is actually located in bits [3:1], but the value saves also
165
/// if the cache is an instruction or data.
166
/// The values of the map are CCSIDR_EL1, which is the configuration of the cache.
167
fn get_cache_info(&self) -> Result<BTreeMap<u8, u64>>;
168
169
/// Sets the cache architecture information for all cache levels.
170
fn set_cache_info(&self, cache_info: BTreeMap<u8, u64>) -> Result<()>;
171
172
fn snapshot(&self) -> anyhow::Result<VcpuSnapshot> {
173
let mut snap = VcpuSnapshot {
174
vcpu_id: self.id(),
175
sp: self
176
.get_one_reg(VcpuRegAArch64::Sp)
177
.context("Failed to get SP")?,
178
pc: self
179
.get_one_reg(VcpuRegAArch64::Pc)
180
.context("Failed to get PC")?,
181
pstate: self
182
.get_one_reg(VcpuRegAArch64::Pstate)
183
.context("Failed to get PState")?,
184
x: Default::default(),
185
v: Default::default(),
186
hypervisor_data: self
187
.hypervisor_specific_snapshot()
188
.context("Failed to get hyprevisor specific data")?,
189
sys: self
190
.get_system_regs()
191
.context("Failed to read system registers")?,
192
cache_arch_info: self.get_cache_info().context("Failed to get cache info")?,
193
};
194
195
for (n, xn) in snap.x.iter_mut().enumerate() {
196
*xn = self
197
.get_one_reg(VcpuRegAArch64::X(n as u8))
198
.with_context(|| format!("Failed to get X{n}"))?;
199
}
200
201
for (n, vn) in snap.v.iter_mut().enumerate() {
202
*vn = self
203
.get_vector_reg(n as u8)
204
.with_context(|| format!("Failed to get V{n}"))?;
205
}
206
207
Ok(snap)
208
}
209
210
/// Restore VCPU
211
fn restore(&self, snapshot: &VcpuSnapshot) -> anyhow::Result<()> {
212
self.set_one_reg(VcpuRegAArch64::Sp, snapshot.sp)
213
.context("Failed to restore SP register")?;
214
self.set_one_reg(VcpuRegAArch64::Pc, snapshot.pc)
215
.context("Failed to restore PC register")?;
216
self.set_one_reg(VcpuRegAArch64::Pstate, snapshot.pstate)
217
.context("Failed to restore PState register")?;
218
219
for (n, xn) in snapshot.x.iter().enumerate() {
220
self.set_one_reg(VcpuRegAArch64::X(n as u8), *xn)
221
.with_context(|| format!("Failed to restore X{n}"))?;
222
}
223
for (n, vn) in snapshot.v.iter().enumerate() {
224
self.set_vector_reg(n as u8, *vn)
225
.with_context(|| format!("Failed to restore V{n}"))?;
226
}
227
for (id, val) in &snapshot.sys {
228
self.set_one_reg(VcpuRegAArch64::System(*id), *val)
229
.with_context(|| format!("Failed to restore system register {id:?}"))?;
230
}
231
self.set_cache_info(snapshot.cache_arch_info.clone())
232
.context("Failed to restore cache info")?;
233
self.hypervisor_specific_restore(snapshot.hypervisor_data.clone())
234
.context("Failed to restore hypervisor specific data")?;
235
Ok(())
236
}
237
}
238
239
/// Aarch64 specific vCPU snapshot.
240
#[derive(Clone, Debug, Serialize, Deserialize)]
241
pub struct VcpuSnapshot {
242
pub vcpu_id: usize,
243
pub sp: u64,
244
pub pc: u64,
245
pub pstate: u64,
246
pub x: [u64; 31],
247
pub v: [u128; 32],
248
pub sys: BTreeMap<AArch64SysRegId, u64>,
249
pub cache_arch_info: BTreeMap<u8, u64>,
250
pub hypervisor_data: AnySnapshot,
251
}
252
253
impl_downcast!(VcpuAArch64);
254
255
/// Initial register state for AArch64 VCPUs.
256
#[derive(Clone, Default)]
257
pub struct VcpuInitAArch64 {
258
/// Initial register state as a map of register name to value pairs. Registers that do not have
259
/// a value specified in this map will retain the original value provided by the hypervisor.
260
pub regs: BTreeMap<VcpuRegAArch64, u64>,
261
}
262
263
#[derive(Clone, Debug, PartialEq, Eq)]
264
pub struct CpuConfigAArch64 {}
265
266
// Convenience constructors for IrqRoutes
267
impl IrqRoute {
268
pub fn gic_irq_route(irq_num: u32) -> IrqRoute {
269
IrqRoute {
270
gsi: irq_num,
271
source: IrqSource::Irqchip {
272
chip: IrqSourceChip::Gic,
273
pin: irq_num,
274
},
275
}
276
}
277
}
278
279
/// A feature that can be enabled on a VCPU with `VcpuAArch64::init`.
280
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
281
pub enum VcpuFeature {
282
/// Emulate PSCI v0.2 (or a future revision backward compatible with v0.2) for the VCPU.
283
PsciV0_2,
284
/// Emulate Performance Monitor Unit v3 for the VCPU.
285
PmuV3,
286
/// Starts the VCPU in a power-off state.
287
PowerOff,
288
/// Scalable Vector Extension support
289
Sve,
290
}
291
292