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