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::FdtWriter; 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` - FdtWriter initialized at the root node. 81 /// `phandles` - Map of strings to a phandle. create_fdt( &self, fdt: &mut FdtWriter, phandles: &BTreeMap<&str, u32>, ) -> cros_fdt::Result<()>82 fn create_fdt( 83 &self, 84 fdt: &mut FdtWriter, 85 phandles: &BTreeMap<&str, u32>, 86 ) -> cros_fdt::Result<()>; 87 88 // 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<()>89 fn init_arch( 90 &self, 91 payload_entry_address: GuestAddress, 92 fdt_address: GuestAddress, 93 fdt_size: usize, 94 ) -> Result<()>; 95 } 96 97 /// A wrapper around creating and using a VCPU on aarch64. 98 pub trait VcpuAArch64: Vcpu { 99 /// Does ARM-specific initialization of this VCPU. Inits the VCPU with the preferred target 100 /// VCPU type and the specified `features`, and resets the value of all registers to defaults. 101 /// All VCPUs should be created before calling this function. init(&self, features: &[VcpuFeature]) -> Result<()>102 fn init(&self, features: &[VcpuFeature]) -> Result<()>; 103 104 /// Initializes the ARM Performance Monitor Unit v3 on this VCPU, with overflow interrupt number 105 /// `irq`. init_pmu(&self, irq: u64) -> Result<()>106 fn init_pmu(&self, irq: u64) -> Result<()>; 107 108 /// Checks if ARM ParaVirtualized Time is supported on this VCPU has_pvtime_support(&self) -> bool109 fn has_pvtime_support(&self) -> bool; 110 111 /// Initializes the ARM ParaVirtualized Time on this VCPU, with base address of the stolen time 112 /// structure as `pvtime_ipa`. init_pvtime(&self, pvtime_ipa: u64) -> Result<()>113 fn init_pvtime(&self, pvtime_ipa: u64) -> Result<()>; 114 115 /// Sets the value of a register on this VCPU. set_one_reg(&self, reg_id: VcpuRegAArch64, data: u64) -> Result<()>116 fn set_one_reg(&self, reg_id: VcpuRegAArch64, data: u64) -> Result<()>; 117 118 /// Gets the value of a register on this VCPU. get_one_reg(&self, reg_id: VcpuRegAArch64) -> Result<u64>119 fn get_one_reg(&self, reg_id: VcpuRegAArch64) -> Result<u64>; 120 121 /// Gets the current PSCI version. get_psci_version(&self) -> Result<PsciVersion>122 fn get_psci_version(&self) -> Result<PsciVersion>; 123 124 #[cfg(feature = "gdb")] 125 /// Sets up debug registers and configure vcpu for handling guest debug events. set_guest_debug(&self, addrs: &[GuestAddress], enable_singlestep: bool) -> Result<()>126 fn set_guest_debug(&self, addrs: &[GuestAddress], enable_singlestep: bool) -> Result<()>; 127 128 #[cfg(feature = "gdb")] 129 /// Sets the VCPU general registers used by GDB 'G' packets. set_gdb_registers(&self, regs: &<GdbArch as Arch>::Registers) -> Result<()>130 fn set_gdb_registers(&self, regs: &<GdbArch as Arch>::Registers) -> Result<()>; 131 132 #[cfg(feature = "gdb")] 133 /// Gets the VCPU general registers used by GDB 'g' packets. get_gdb_registers(&self, regs: &mut <GdbArch as Arch>::Registers) -> Result<()>134 fn get_gdb_registers(&self, regs: &mut <GdbArch as Arch>::Registers) -> Result<()>; 135 136 #[cfg(feature = "gdb")] 137 /// Gets the max number of hardware breakpoints. get_max_hw_bps(&self) -> Result<usize>138 fn get_max_hw_bps(&self) -> Result<usize>; 139 140 #[cfg(feature = "gdb")] 141 /// Sets the value of a single register on this VCPU. set_gdb_register(&self, reg: <GdbArch as Arch>::RegId, data: &[u8]) -> Result<()>142 fn set_gdb_register(&self, reg: <GdbArch as Arch>::RegId, data: &[u8]) -> Result<()>; 143 144 #[cfg(feature = "gdb")] 145 /// Gets the value of a single register on this VCPU. get_gdb_register(&self, reg: <GdbArch as Arch>::RegId, data: &mut [u8]) -> Result<usize>146 fn get_gdb_register(&self, reg: <GdbArch as Arch>::RegId, data: &mut [u8]) -> Result<usize>; 147 148 /// Snapshot VCPU snapshot(&self) -> anyhow::Result<VcpuSnapshot>149 fn snapshot(&self) -> anyhow::Result<VcpuSnapshot> { 150 Err(anyhow!("not yet implemented")) 151 } 152 153 /// Restore VCPU restore(&self, _snapshot: &VcpuSnapshot) -> anyhow::Result<()>154 fn restore(&self, _snapshot: &VcpuSnapshot) -> anyhow::Result<()> { 155 Err(anyhow!("not yet implemented")) 156 } 157 } 158 159 /// Aarch64 specific vCPU snapshot. 160 /// 161 /// Not implemented yet. 162 #[derive(Clone, Debug, Serialize, Deserialize)] 163 pub struct VcpuSnapshot { 164 pub vcpu_id: usize, 165 } 166 167 impl_downcast!(VcpuAArch64); 168 169 /// Initial register state for AArch64 VCPUs. 170 #[derive(Clone, Default)] 171 pub struct VcpuInitAArch64 { 172 /// Initial register state as a map of register name to value pairs. Registers that do not have 173 /// a value specified in this map will retain the original value provided by the hypervisor. 174 pub regs: BTreeMap<VcpuRegAArch64, u64>, 175 } 176 177 #[derive(Clone, Debug, PartialEq, Eq)] 178 pub struct CpuConfigAArch64 {} 179 180 // Convenience constructors for IrqRoutes 181 impl IrqRoute { gic_irq_route(irq_num: u32) -> IrqRoute182 pub fn gic_irq_route(irq_num: u32) -> IrqRoute { 183 IrqRoute { 184 gsi: irq_num, 185 source: IrqSource::Irqchip { 186 chip: IrqSourceChip::Gic, 187 pin: irq_num, 188 }, 189 } 190 } 191 } 192 193 /// A feature that can be enabled on a VCPU with `VcpuAArch64::init`. 194 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 195 pub enum VcpuFeature { 196 /// Emulate PSCI v0.2 (or a future revision backward compatible with v0.2) for the VCPU. 197 PsciV0_2, 198 /// Emulate Performance Monitor Unit v3 for the VCPU. 199 PmuV3, 200 /// Starts the VCPU in a power-off state. 201 PowerOff, 202 } 203