• 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::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