• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 use anyhow::anyhow;
9 use base::Error;
10 use base::Result;
11 use cros_fdt::Fdt;
12 use downcast_rs::impl_downcast;
13 #[cfg(feature = "gdb")]
14 use gdbstub::arch::Arch;
15 #[cfg(feature = "gdb")]
16 use gdbstub_arch::aarch64::AArch64 as GdbArch;
17 use libc::EINVAL;
18 use serde::Deserialize;
19 use serde::Serialize;
20 use vm_memory::GuestAddress;
21 
22 use crate::Hypervisor;
23 use crate::IrqRoute;
24 use crate::IrqSource;
25 use crate::IrqSourceChip;
26 use crate::Vcpu;
27 use crate::Vm;
28 
29 /// Represents a version of Power State Coordination Interface (PSCI).
30 #[derive(Eq, Ord, PartialEq, PartialOrd)]
31 pub struct PsciVersion {
32     pub major: u16,
33     pub minor: u16,
34 }
35 
36 impl PsciVersion {
new(major: u16, minor: u16) -> Result<Self>37     pub fn new(major: u16, minor: u16) -> Result<Self> {
38         if (major as i16) < 0 {
39             Err(Error::new(EINVAL))
40         } else {
41             Ok(Self { major, minor })
42         }
43     }
44 }
45 
46 impl TryFrom<u32> for PsciVersion {
47     type Error = base::Error;
48 
try_from(item: u32) -> Result<Self>49     fn try_from(item: u32) -> Result<Self> {
50         Self::new((item >> 16) as u16, item as u16)
51     }
52 }
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 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
58 pub enum VcpuRegAArch64 {
59     X(u8),
60     Sp,
61     Pc,
62     Pstate,
63 }
64 
65 /// A wrapper for using a VM on aarch64 and getting/setting its state.
66 pub trait VmAArch64: Vm {
67     /// Gets the `Hypervisor` that created this VM.
get_hypervisor(&self) -> &dyn Hypervisor68     fn get_hypervisor(&self) -> &dyn Hypervisor;
69 
70     /// Load pVM firmware for the VM, creating a memslot for it as needed.
71     ///
72     /// 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<()>73     fn load_protected_vm_firmware(&mut self, fw_addr: GuestAddress, fw_max_size: u64)
74         -> Result<()>;
75 
76     /// Create a Vcpu with the specified Vcpu ID.
create_vcpu(&self, id: usize) -> Result<Box<dyn VcpuAArch64>>77     fn create_vcpu(&self, id: usize) -> Result<Box<dyn VcpuAArch64>>;
78 
79     /// Create DT configuration node for the hypervisor.
80     /// `fdt` - Fdt initialized at the root node.
81     /// `phandles` - Map of strings to a phandle.
create_fdt(&self, fdt: &mut Fdt, phandles: &BTreeMap<&str, u32>) -> cros_fdt::Result<()>82     fn create_fdt(&self, fdt: &mut Fdt, phandles: &BTreeMap<&str, u32>) -> cros_fdt::Result<()>;
83 
84     // 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<()>85     fn init_arch(
86         &self,
87         payload_entry_address: GuestAddress,
88         fdt_address: GuestAddress,
89         fdt_size: usize,
90     ) -> Result<()>;
91 }
92 
93 /// A wrapper around creating and using a VCPU on aarch64.
94 pub trait VcpuAArch64: Vcpu {
95     /// Does ARM-specific initialization of this VCPU.  Inits the VCPU with the preferred target
96     /// VCPU type and the specified `features`, and resets the value of all registers to defaults.
97     /// All VCPUs should be created before calling this function.
init(&self, features: &[VcpuFeature]) -> Result<()>98     fn init(&self, features: &[VcpuFeature]) -> Result<()>;
99 
100     /// Initializes the ARM Performance Monitor Unit v3 on this VCPU, with overflow interrupt number
101     /// `irq`.
init_pmu(&self, irq: u64) -> Result<()>102     fn init_pmu(&self, irq: u64) -> Result<()>;
103 
104     /// Checks if ARM ParaVirtualized Time is supported on this VCPU
has_pvtime_support(&self) -> bool105     fn has_pvtime_support(&self) -> bool;
106 
107     /// Initializes the ARM ParaVirtualized Time on this VCPU, with base address of the stolen time
108     /// structure as `pvtime_ipa`.
init_pvtime(&self, pvtime_ipa: u64) -> Result<()>109     fn init_pvtime(&self, pvtime_ipa: u64) -> Result<()>;
110 
111     /// Sets the value of a register on this VCPU.
set_one_reg(&self, reg_id: VcpuRegAArch64, data: u64) -> Result<()>112     fn set_one_reg(&self, reg_id: VcpuRegAArch64, data: u64) -> Result<()>;
113 
114     /// Gets the value of a register on this VCPU.
get_one_reg(&self, reg_id: VcpuRegAArch64) -> Result<u64>115     fn get_one_reg(&self, reg_id: VcpuRegAArch64) -> Result<u64>;
116 
117     /// Sets the value of a Neon vector register (V0-V31) on this VCPU.
set_vector_reg(&self, reg_num: u8, data: u128) -> Result<()>118     fn set_vector_reg(&self, reg_num: u8, data: u128) -> Result<()>;
119 
120     /// Gets the value of a Neon vector register (V0-V31) on this VCPU.
get_vector_reg(&self, reg_num: u8) -> Result<u128>121     fn get_vector_reg(&self, reg_num: u8) -> Result<u128>;
122 
123     /// Gets the value of MPIDR_EL1 on this VCPU.
get_mpidr(&self) -> Result<u64>124     fn get_mpidr(&self) -> Result<u64> {
125         const RES1: u64 = 1 << 31;
126 
127         // Assume that MPIDR_EL1.{U,MT} = {0,0}.
128 
129         let aff = u64::try_from(self.id()).unwrap();
130 
131         Ok(RES1 | aff)
132     }
133 
134     /// Gets the current PSCI version.
get_psci_version(&self) -> Result<PsciVersion>135     fn get_psci_version(&self) -> Result<PsciVersion>;
136 
137     #[cfg(feature = "gdb")]
138     /// Sets up debug registers and configure vcpu for handling guest debug events.
set_guest_debug(&self, addrs: &[GuestAddress], enable_singlestep: bool) -> Result<()>139     fn set_guest_debug(&self, addrs: &[GuestAddress], enable_singlestep: bool) -> Result<()>;
140 
141     #[cfg(feature = "gdb")]
142     /// Sets the VCPU general registers used by GDB 'G' packets.
set_gdb_registers(&self, regs: &<GdbArch as Arch>::Registers) -> Result<()>143     fn set_gdb_registers(&self, regs: &<GdbArch as Arch>::Registers) -> Result<()>;
144 
145     #[cfg(feature = "gdb")]
146     /// Gets the VCPU general registers used by GDB 'g' packets.
get_gdb_registers(&self, regs: &mut <GdbArch as Arch>::Registers) -> Result<()>147     fn get_gdb_registers(&self, regs: &mut <GdbArch as Arch>::Registers) -> Result<()>;
148 
149     #[cfg(feature = "gdb")]
150     /// Gets the max number of hardware breakpoints.
get_max_hw_bps(&self) -> Result<usize>151     fn get_max_hw_bps(&self) -> Result<usize>;
152 
153     #[cfg(feature = "gdb")]
154     /// Sets the value of a single register on this VCPU.
set_gdb_register(&self, reg: <GdbArch as Arch>::RegId, data: &[u8]) -> Result<()>155     fn set_gdb_register(&self, reg: <GdbArch as Arch>::RegId, data: &[u8]) -> Result<()>;
156 
157     #[cfg(feature = "gdb")]
158     /// Gets the value of a single register on this VCPU.
get_gdb_register(&self, reg: <GdbArch as Arch>::RegId, data: &mut [u8]) -> Result<usize>159     fn get_gdb_register(&self, reg: <GdbArch as Arch>::RegId, data: &mut [u8]) -> Result<usize>;
160 
161     /// Snapshot VCPU
snapshot(&self) -> anyhow::Result<VcpuSnapshot>162     fn snapshot(&self) -> anyhow::Result<VcpuSnapshot> {
163         Err(anyhow!("not yet implemented"))
164     }
165 
166     /// Restore VCPU
restore(&self, _snapshot: &VcpuSnapshot) -> anyhow::Result<()>167     fn restore(&self, _snapshot: &VcpuSnapshot) -> anyhow::Result<()> {
168         Err(anyhow!("not yet implemented"))
169     }
170 }
171 
172 /// Aarch64 specific vCPU snapshot.
173 ///
174 /// Not implemented yet.
175 #[derive(Clone, Debug, Serialize, Deserialize)]
176 pub struct VcpuSnapshot {
177     pub vcpu_id: usize,
178 }
179 
180 impl_downcast!(VcpuAArch64);
181 
182 /// Initial register state for AArch64 VCPUs.
183 #[derive(Clone, Default)]
184 pub struct VcpuInitAArch64 {
185     /// Initial register state as a map of register name to value pairs. Registers that do not have
186     /// a value specified in this map will retain the original value provided by the hypervisor.
187     pub regs: BTreeMap<VcpuRegAArch64, u64>,
188 }
189 
190 #[derive(Clone, Debug, PartialEq, Eq)]
191 pub struct CpuConfigAArch64 {}
192 
193 // Convenience constructors for IrqRoutes
194 impl IrqRoute {
gic_irq_route(irq_num: u32) -> IrqRoute195     pub fn gic_irq_route(irq_num: u32) -> IrqRoute {
196         IrqRoute {
197             gsi: irq_num,
198             source: IrqSource::Irqchip {
199                 chip: IrqSourceChip::Gic,
200                 pin: irq_num,
201             },
202         }
203     }
204 }
205 
206 /// A feature that can be enabled on a VCPU with `VcpuAArch64::init`.
207 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
208 pub enum VcpuFeature {
209     /// Emulate PSCI v0.2 (or a future revision backward compatible with v0.2) for the VCPU.
210     PsciV0_2,
211     /// Emulate Performance Monitor Unit v3 for the VCPU.
212     PmuV3,
213     /// Starts the VCPU in a power-off state.
214     PowerOff,
215 }
216