xref: /aosp_15_r20/external/crosvm/hypervisor/src/aarch64.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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 base::Error;
10 use base::Result;
11 use cros_fdt::Fdt;
12 use downcast_rs::impl_downcast;
13 use libc::EINVAL;
14 use serde::Deserialize;
15 use serde::Serialize;
16 use vm_memory::GuestAddress;
17 
18 use crate::Hypervisor;
19 use crate::IrqRoute;
20 use crate::IrqSource;
21 use crate::IrqSourceChip;
22 use crate::Vcpu;
23 use crate::Vm;
24 
25 /// Represents a version of Power State Coordination Interface (PSCI).
26 #[derive(Eq, Ord, PartialEq, PartialOrd)]
27 pub struct PsciVersion {
28     pub major: u16,
29     pub minor: u16,
30 }
31 
32 impl PsciVersion {
new(major: u16, minor: u16) -> Result<Self>33     pub fn new(major: u16, minor: u16) -> Result<Self> {
34         if (major as i16) < 0 {
35             Err(Error::new(EINVAL))
36         } else {
37             Ok(Self { major, minor })
38         }
39     }
40 }
41 
42 impl TryFrom<u32> for PsciVersion {
43     type Error = base::Error;
44 
try_from(item: u32) -> Result<Self>45     fn try_from(item: u32) -> Result<Self> {
46         Self::new((item >> 16) as u16, item as u16)
47     }
48 }
49 
50 // Aarch64 does not provide a concrete number as to how many registers exist.
51 // The list of registers available exceeds 600 registers
52 pub const AARCH64_MAX_REG_COUNT: usize = 1024;
53 
54 pub const PSCI_0_2: PsciVersion = PsciVersion { major: 0, minor: 2 };
55 pub const PSCI_1_0: PsciVersion = PsciVersion { major: 1, minor: 0 };
56 
57 /// AArch64 system register as used in MSR/MRS instructions.
58 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Deserialize, Serialize)]
59 #[serde(transparent)]
60 pub struct AArch64SysRegId(u16);
61 
62 impl AArch64SysRegId {
63     /// Construct a system register ID from Op0, Op1, CRn, CRm, Op2.
64     ///
65     /// The meanings of the arguments are described in the ARMv8 Architecture Reference Manual
66     /// "System instruction class encoding overview" section.
new(op0: u8, op1: u8, crn: u8, crm: u8, op2: u8) -> Result<Self>67     pub fn new(op0: u8, op1: u8, crn: u8, crm: u8, op2: u8) -> Result<Self> {
68         if op0 > 0b11 || op1 > 0b111 || crn > 0b1111 || crm > 0b1111 || op2 > 0b111 {
69             return Err(Error::new(EINVAL));
70         }
71 
72         Ok(Self::new_unchecked(op0, op1, crn, crm, op2))
73     }
74 
75     /// Construct a system register ID from Op0, Op1, CRn, CRm, Op2.
76     ///
77     /// Out-of-range values will be silently truncated.
new_unchecked(op0: u8, op1: u8, crn: u8, crm: u8, op2: u8) -> Self78     pub const fn new_unchecked(op0: u8, op1: u8, crn: u8, crm: u8, op2: u8) -> Self {
79         let op0 = (op0 as u16 & 0b11) << 14;
80         let op1 = (op1 as u16 & 0b111) << 11;
81         let crn = (crn as u16 & 0b1111) << 7;
82         let crm = (crm as u16 & 0b1111) << 3;
83         let op2 = op2 as u16 & 0b111;
84         Self(op0 | op1 | crn | crm | op2)
85     }
86 
from_encoded(v: u16) -> Self87     pub fn from_encoded(v: u16) -> Self {
88         Self(v)
89     }
90 
91     #[inline]
op0(&self) -> u892     pub const fn op0(&self) -> u8 {
93         ((self.0 >> 14) & 0b11) as u8
94     }
95 
96     #[inline]
op1(&self) -> u897     pub const fn op1(&self) -> u8 {
98         ((self.0 >> 11) & 0b111) as u8
99     }
100 
101     #[inline]
crn(&self) -> u8102     pub const fn crn(&self) -> u8 {
103         ((self.0 >> 7) & 0b1111) as u8
104     }
105 
106     #[inline]
crm(&self) -> u8107     pub const fn crm(&self) -> u8 {
108         ((self.0 >> 3) & 0b1111) as u8
109     }
110 
111     #[inline]
op2(&self) -> u8112     pub const fn op2(&self) -> u8 {
113         (self.0 & 0b111) as u8
114     }
115 
116     /// Returns the system register as encoded in bits 5-20 of MRS and MSR instructions.
encoded(&self) -> u16117     pub const fn encoded(&self) -> u16 {
118         self.0
119     }
120 }
121 
122 impl Debug for AArch64SysRegId {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result123     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124         f.debug_struct("AArch64SysRegId")
125             .field("Op0", &self.op0())
126             .field("Op1", &self.op1())
127             .field("CRn", &self.crn())
128             .field("CRm", &self.crm())
129             .field("Op2", &self.op2())
130             .finish()
131     }
132 }
133 
134 #[rustfmt::skip]
135 #[allow(non_upper_case_globals)]
136 impl AArch64SysRegId {
137     //                                                         Op0    Op1     CRn     CRm    Op2
138     pub const MPIDR_EL1: Self           = Self::new_unchecked(0b11, 0b000, 0b0000, 0b0000, 0b101);
139     pub const CCSIDR_EL1: Self          = Self::new_unchecked(0b11, 0b001, 0b0000, 0b0000, 0b000);
140     pub const CSSELR_EL1: Self          = Self::new_unchecked(0b11, 0b010, 0b0000, 0b0000, 0b000);
141     pub const FPCR: Self                = Self::new_unchecked(0b11, 0b011, 0b0100, 0b0100, 0b000);
142     pub const FPSR: Self                = Self::new_unchecked(0b11, 0b011, 0b0100, 0b0100, 0b001);
143     pub const SPSR_EL1: Self            = Self::new_unchecked(0b11, 0b000, 0b0100, 0b0000, 0b000);
144     pub const SPSR_irq: Self            = Self::new_unchecked(0b11, 0b100, 0b0100, 0b0011, 0b000);
145     pub const SPSR_abt: Self            = Self::new_unchecked(0b11, 0b100, 0b0100, 0b0011, 0b001);
146     pub const SPSR_und: Self            = Self::new_unchecked(0b11, 0b100, 0b0100, 0b0011, 0b010);
147     pub const SPSR_fiq: Self            = Self::new_unchecked(0b11, 0b100, 0b0100, 0b0011, 0b011);
148     pub const ELR_EL1: Self             = Self::new_unchecked(0b11, 0b000, 0b0100, 0b0000, 0b001);
149     pub const SP_EL1: Self              = Self::new_unchecked(0b11, 0b100, 0b0100, 0b0001, 0b000);
150     pub const CNTVCT_EL0: Self          = Self::new_unchecked(0b11, 0b011, 0b1110, 0b0000, 0b010);
151     pub const CNTV_CVAL_EL0: Self       = Self::new_unchecked(0b11, 0b011, 0b1110, 0b0011, 0b010);
152 }
153 
154 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
155 pub enum VcpuRegAArch64 {
156     X(u8),
157     Sp,
158     Pc,
159     Pstate,
160     System(AArch64SysRegId),
161 }
162 
163 /// A wrapper for using a VM on aarch64 and getting/setting its state.
164 pub trait VmAArch64: Vm {
165     /// Gets the `Hypervisor` that created this VM.
get_hypervisor(&self) -> &dyn Hypervisor166     fn get_hypervisor(&self) -> &dyn Hypervisor;
167 
168     /// Load pVM firmware for the VM, creating a memslot for it as needed.
169     ///
170     /// Only works on protected VMs (i.e. those that support `VmCap::Protected`).
load_protected_vm_firmware(&mut self, fw_addr: GuestAddress, fw_max_size: u64) -> Result<()>171     fn load_protected_vm_firmware(&mut self, fw_addr: GuestAddress, fw_max_size: u64)
172         -> Result<()>;
173 
174     /// Create a Vcpu with the specified Vcpu ID.
create_vcpu(&self, id: usize) -> Result<Box<dyn VcpuAArch64>>175     fn create_vcpu(&self, id: usize) -> Result<Box<dyn VcpuAArch64>>;
176 
177     /// Create DT configuration node for the hypervisor.
178     /// `fdt` - Fdt initialized at the root node.
179     /// `phandles` - Map of strings to a phandle.
create_fdt(&self, fdt: &mut Fdt, phandles: &BTreeMap<&str, u32>) -> cros_fdt::Result<()>180     fn create_fdt(&self, fdt: &mut Fdt, phandles: &BTreeMap<&str, u32>) -> cros_fdt::Result<()>;
181 
182     // Initialize a VM. Called after building the VM. Presently called before vCPUs are initialized.
init_arch( &self, payload_entry_address: GuestAddress, fdt_address: GuestAddress, fdt_size: usize, ) -> Result<()>183     fn init_arch(
184         &self,
185         payload_entry_address: GuestAddress,
186         fdt_address: GuestAddress,
187         fdt_size: usize,
188     ) -> Result<()>;
189 
190     /// Set an offset that describes a number of counter cycles that are subtracted from both
191     /// virtual and physical counter views.
set_counter_offset(&self, _offset: u64) -> Result<()>192     fn set_counter_offset(&self, _offset: u64) -> Result<()> {
193         Err(Error::new(libc::ENOSYS))
194     }
195 }
196 
197 /// A wrapper around creating and using a VCPU on aarch64.
198 pub trait VcpuAArch64: Vcpu {
199     /// Does ARM-specific initialization of this VCPU.  Inits the VCPU with the preferred target
200     /// VCPU type and the specified `features`, and resets the value of all registers to defaults.
201     /// All VCPUs should be created before calling this function.
init(&self, features: &[VcpuFeature]) -> Result<()>202     fn init(&self, features: &[VcpuFeature]) -> Result<()>;
203 
204     /// Initializes the ARM Performance Monitor Unit v3 on this VCPU, with overflow interrupt number
205     /// `irq`.
init_pmu(&self, irq: u64) -> Result<()>206     fn init_pmu(&self, irq: u64) -> Result<()>;
207 
208     /// Checks if ARM ParaVirtualized Time is supported on this VCPU
has_pvtime_support(&self) -> bool209     fn has_pvtime_support(&self) -> bool;
210 
211     /// Initializes the ARM ParaVirtualized Time on this VCPU, with base address of the stolen time
212     /// structure as `pvtime_ipa`.
init_pvtime(&self, pvtime_ipa: u64) -> Result<()>213     fn init_pvtime(&self, pvtime_ipa: u64) -> Result<()>;
214 
215     /// Sets the value of a register on this VCPU.
set_one_reg(&self, reg_id: VcpuRegAArch64, data: u64) -> Result<()>216     fn set_one_reg(&self, reg_id: VcpuRegAArch64, data: u64) -> Result<()>;
217 
218     /// Gets the value of a register on this VCPU.
get_one_reg(&self, reg_id: VcpuRegAArch64) -> Result<u64>219     fn get_one_reg(&self, reg_id: VcpuRegAArch64) -> Result<u64>;
220 
221     /// Sets the value of a Neon vector register (V0-V31) on this VCPU.
set_vector_reg(&self, reg_num: u8, data: u128) -> Result<()>222     fn set_vector_reg(&self, reg_num: u8, data: u128) -> Result<()>;
223 
224     /// Gets the value of a Neon vector register (V0-V31) on this VCPU.
get_vector_reg(&self, reg_num: u8) -> Result<u128>225     fn get_vector_reg(&self, reg_num: u8) -> Result<u128>;
226 
227     /// Gets the set of system registers accessible by the hypervisor
get_system_regs(&self) -> Result<BTreeMap<AArch64SysRegId, u64>>228     fn get_system_regs(&self) -> Result<BTreeMap<AArch64SysRegId, u64>>;
229 
230     /// Gets the hypervisor specific data for snapshot
hypervisor_specific_snapshot(&self) -> anyhow::Result<serde_json::Value>231     fn hypervisor_specific_snapshot(&self) -> anyhow::Result<serde_json::Value>;
232 
233     /// Restores the hypervisor specific data
hypervisor_specific_restore(&self, _data: serde_json::Value) -> anyhow::Result<()>234     fn hypervisor_specific_restore(&self, _data: serde_json::Value) -> anyhow::Result<()>;
235 
236     /// Gets the value of MPIDR_EL1 on this VCPU.
get_mpidr(&self) -> Result<u64>237     fn get_mpidr(&self) -> Result<u64> {
238         const RES1: u64 = 1 << 31;
239 
240         // Assume that MPIDR_EL1.{U,MT} = {0,0}.
241 
242         let aff = u64::try_from(self.id()).unwrap();
243 
244         Ok(RES1 | aff)
245     }
246 
247     /// Gets the current PSCI version.
get_psci_version(&self) -> Result<PsciVersion>248     fn get_psci_version(&self) -> Result<PsciVersion>;
249 
250     /// Sets up debug registers and configure vcpu for handling guest debug events.
set_guest_debug(&self, addrs: &[GuestAddress], enable_singlestep: bool) -> Result<()>251     fn set_guest_debug(&self, addrs: &[GuestAddress], enable_singlestep: bool) -> Result<()>;
252 
253     /// Gets the max number of hardware breakpoints.
get_max_hw_bps(&self) -> Result<usize>254     fn get_max_hw_bps(&self) -> Result<usize>;
255 
256     /// Gets the cache architecture information for all cache levels.
257     /// The keys of the map are the lower 4 lower significant bits of CSSELR_EL1, which represents
258     /// the cache level. cache level is actually located in bits [3:1], but the value saves also
259     /// if the cache is an instruction or data.
260     /// The values of the map are CCSIDR_EL1, which is the configuration of the cache.
get_cache_info(&self) -> Result<BTreeMap<u8, u64>>261     fn get_cache_info(&self) -> Result<BTreeMap<u8, u64>>;
262 
263     /// Sets the cache architecture information for all cache levels.
set_cache_info(&self, cache_info: BTreeMap<u8, u64>) -> Result<()>264     fn set_cache_info(&self, cache_info: BTreeMap<u8, u64>) -> Result<()>;
265 
snapshot(&self) -> anyhow::Result<VcpuSnapshot>266     fn snapshot(&self) -> anyhow::Result<VcpuSnapshot> {
267         let mut snap = VcpuSnapshot {
268             vcpu_id: self.id(),
269             sp: self.get_one_reg(VcpuRegAArch64::Sp)?,
270             pc: self.get_one_reg(VcpuRegAArch64::Pc)?,
271             pstate: self.get_one_reg(VcpuRegAArch64::Pstate)?,
272             hypervisor_data: self.hypervisor_specific_snapshot()?,
273             sys: self.get_system_regs()?,
274             cache_arch_info: self.get_cache_info()?,
275             ..Default::default()
276         };
277 
278         for (n, xn) in snap.x.iter_mut().enumerate() {
279             *xn = self.get_one_reg(VcpuRegAArch64::X(n as u8))?;
280         }
281 
282         for (n, vn) in snap.v.iter_mut().enumerate() {
283             *vn = self.get_vector_reg(n as u8)?;
284         }
285 
286         Ok(snap)
287     }
288 
289     /// Restore VCPU
restore(&self, snapshot: &VcpuSnapshot) -> anyhow::Result<()>290     fn restore(&self, snapshot: &VcpuSnapshot) -> anyhow::Result<()> {
291         self.set_one_reg(VcpuRegAArch64::Sp, snapshot.sp)?;
292         self.set_one_reg(VcpuRegAArch64::Pc, snapshot.pc)?;
293         self.set_one_reg(VcpuRegAArch64::Pstate, snapshot.pstate)?;
294 
295         for (n, xn) in snapshot.x.iter().enumerate() {
296             self.set_one_reg(VcpuRegAArch64::X(n as u8), *xn)?;
297         }
298         for (n, vn) in snapshot.v.iter().enumerate() {
299             self.set_vector_reg(n as u8, *vn)?;
300         }
301         for (id, val) in &snapshot.sys {
302             self.set_one_reg(VcpuRegAArch64::System(*id), *val)?;
303         }
304         self.set_cache_info(snapshot.cache_arch_info.clone())?;
305         self.hypervisor_specific_restore(snapshot.hypervisor_data.clone())?;
306         Ok(())
307     }
308 }
309 
310 /// Aarch64 specific vCPU snapshot.
311 #[derive(Clone, Debug, Default, Serialize, Deserialize)]
312 pub struct VcpuSnapshot {
313     pub vcpu_id: usize,
314     pub sp: u64,
315     pub pc: u64,
316     pub pstate: u64,
317     pub x: [u64; 31],
318     pub v: [u128; 32],
319     pub sys: BTreeMap<AArch64SysRegId, u64>,
320     pub cache_arch_info: BTreeMap<u8, u64>,
321     pub hypervisor_data: serde_json::Value,
322 }
323 
324 impl_downcast!(VcpuAArch64);
325 
326 /// Initial register state for AArch64 VCPUs.
327 #[derive(Clone, Default)]
328 pub struct VcpuInitAArch64 {
329     /// Initial register state as a map of register name to value pairs. Registers that do not have
330     /// a value specified in this map will retain the original value provided by the hypervisor.
331     pub regs: BTreeMap<VcpuRegAArch64, u64>,
332 }
333 
334 #[derive(Clone, Debug, PartialEq, Eq)]
335 pub struct CpuConfigAArch64 {}
336 
337 // Convenience constructors for IrqRoutes
338 impl IrqRoute {
gic_irq_route(irq_num: u32) -> IrqRoute339     pub fn gic_irq_route(irq_num: u32) -> IrqRoute {
340         IrqRoute {
341             gsi: irq_num,
342             source: IrqSource::Irqchip {
343                 chip: IrqSourceChip::Gic,
344                 pin: irq_num,
345             },
346         }
347     }
348 }
349 
350 /// A feature that can be enabled on a VCPU with `VcpuAArch64::init`.
351 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
352 pub enum VcpuFeature {
353     /// Emulate PSCI v0.2 (or a future revision backward compatible with v0.2) for the VCPU.
354     PsciV0_2,
355     /// Emulate Performance Monitor Unit v3 for the VCPU.
356     PmuV3,
357     /// Starts the VCPU in a power-off state.
358     PowerOff,
359     /// Scalable Vector Extension support
360     Sve,
361 }
362 
363 #[cfg(test)]
364 mod tests {
365     use super::*;
366 
367     #[test]
sysreg_new()368     fn sysreg_new() {
369         let sysreg = AArch64SysRegId::new(1, 2, 3, 4, 5).unwrap();
370         assert_eq!(sysreg.op0(), 1);
371         assert_eq!(sysreg.op1(), 2);
372         assert_eq!(sysreg.crn(), 3);
373         assert_eq!(sysreg.crm(), 4);
374         assert_eq!(sysreg.op2(), 5);
375         assert_eq!(sysreg.encoded(), 0x51A5);
376     }
377 
378     #[test]
sysreg_new_max()379     fn sysreg_new_max() {
380         let sysreg = AArch64SysRegId::new(0b11, 0b111, 0b1111, 0b1111, 0b111).unwrap();
381         assert_eq!(sysreg.op0(), 3);
382         assert_eq!(sysreg.op1(), 7);
383         assert_eq!(sysreg.crn(), 15);
384         assert_eq!(sysreg.crm(), 15);
385         assert_eq!(sysreg.op2(), 7);
386         assert_eq!(sysreg.encoded(), 0xFFFF);
387     }
388 
389     #[test]
sysreg_new_out_of_range()390     fn sysreg_new_out_of_range() {
391         AArch64SysRegId::new(4, 0, 0, 0, 0).expect_err("invalid Op0");
392         AArch64SysRegId::new(0, 8, 0, 0, 0).expect_err("invalid Op1");
393         AArch64SysRegId::new(0, 0, 16, 0, 0).expect_err("invalid CRn");
394         AArch64SysRegId::new(0, 0, 0, 16, 0).expect_err("invalid CRm");
395         AArch64SysRegId::new(0, 0, 0, 0, 8).expect_err("invalid Op2");
396     }
397 
398     #[test]
sysreg_encoding_mpidr_el1()399     fn sysreg_encoding_mpidr_el1() {
400         assert_eq!(AArch64SysRegId::MPIDR_EL1.op0(), 3);
401         assert_eq!(AArch64SysRegId::MPIDR_EL1.op1(), 0);
402         assert_eq!(AArch64SysRegId::MPIDR_EL1.crn(), 0);
403         assert_eq!(AArch64SysRegId::MPIDR_EL1.crm(), 0);
404         assert_eq!(AArch64SysRegId::MPIDR_EL1.op2(), 5);
405         assert_eq!(AArch64SysRegId::MPIDR_EL1.encoded(), 0xC005);
406         assert_eq!(
407             AArch64SysRegId::MPIDR_EL1,
408             AArch64SysRegId::new(3, 0, 0, 0, 5).unwrap()
409         );
410     }
411 
412     #[test]
sysreg_encoding_cntvct_el0()413     fn sysreg_encoding_cntvct_el0() {
414         assert_eq!(AArch64SysRegId::CNTVCT_EL0.op0(), 3);
415         assert_eq!(AArch64SysRegId::CNTVCT_EL0.op1(), 3);
416         assert_eq!(AArch64SysRegId::CNTVCT_EL0.crn(), 14);
417         assert_eq!(AArch64SysRegId::CNTVCT_EL0.crm(), 0);
418         assert_eq!(AArch64SysRegId::CNTVCT_EL0.op2(), 2);
419         assert_eq!(AArch64SysRegId::CNTVCT_EL0.encoded(), 0xDF02);
420         assert_eq!(
421             AArch64SysRegId::CNTVCT_EL0,
422             AArch64SysRegId::new(3, 3, 14, 0, 2).unwrap()
423         );
424     }
425 
426     #[test]
sysreg_encoding_cntv_cval_el0()427     fn sysreg_encoding_cntv_cval_el0() {
428         assert_eq!(AArch64SysRegId::CNTV_CVAL_EL0.op0(), 3);
429         assert_eq!(AArch64SysRegId::CNTV_CVAL_EL0.op1(), 3);
430         assert_eq!(AArch64SysRegId::CNTV_CVAL_EL0.crn(), 14);
431         assert_eq!(AArch64SysRegId::CNTV_CVAL_EL0.crm(), 3);
432         assert_eq!(AArch64SysRegId::CNTV_CVAL_EL0.op2(), 2);
433         assert_eq!(AArch64SysRegId::CNTV_CVAL_EL0.encoded(), 0xDF1A);
434         assert_eq!(
435             AArch64SysRegId::CNTV_CVAL_EL0,
436             AArch64SysRegId::new(3, 3, 14, 3, 2).unwrap()
437         );
438     }
439 
440     #[test]
sysreg_debug()441     fn sysreg_debug() {
442         assert_eq!(
443             format!("{:?}", AArch64SysRegId::MPIDR_EL1),
444             "AArch64SysRegId { Op0: 3, Op1: 0, CRn: 0, CRm: 0, Op2: 5 }"
445         );
446     }
447 }
448