1 // Copyright 2020 The Chromium OS Authors. All rights reserved.
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 libc::{EINVAL, ENOMEM, ENOSYS, ENXIO};
6 
7 use base::{
8     errno_result, error, ioctl_with_mut_ref, ioctl_with_ref, Error, MemoryMappingBuilder, Result,
9 };
10 use kvm_sys::*;
11 use vm_memory::GuestAddress;
12 
13 use super::{KvmCap, KvmVcpu, KvmVm};
14 use crate::{
15     ClockState, DeviceKind, Hypervisor, IrqSourceChip, PsciVersion, VcpuAArch64, VcpuFeature, Vm,
16     VmAArch64, VmCap,
17 };
18 
19 impl KvmVm {
20     /// Checks if a particular `VmCap` is available, or returns None if arch-independent
21     /// Vm.check_capability() should handle the check.
check_capability_arch(&self, _c: VmCap) -> Option<bool>22     pub fn check_capability_arch(&self, _c: VmCap) -> Option<bool> {
23         None
24     }
25 
26     /// Returns the params to pass to KVM_CREATE_DEVICE for a `kind` device on this arch, or None to
27     /// let the arch-independent `KvmVm::create_device` handle it.
get_device_params_arch(&self, kind: DeviceKind) -> Option<kvm_create_device>28     pub fn get_device_params_arch(&self, kind: DeviceKind) -> Option<kvm_create_device> {
29         match kind {
30             DeviceKind::ArmVgicV2 => Some(kvm_create_device {
31                 type_: kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2,
32                 fd: 0,
33                 flags: 0,
34             }),
35             DeviceKind::ArmVgicV3 => Some(kvm_create_device {
36                 type_: kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3,
37                 fd: 0,
38                 flags: 0,
39             }),
40             _ => None,
41         }
42     }
43 
44     /// Arch-specific implementation of `Vm::get_pvclock`.  Always returns an error on AArch64.
get_pvclock_arch(&self) -> Result<ClockState>45     pub fn get_pvclock_arch(&self) -> Result<ClockState> {
46         Err(Error::new(ENXIO))
47     }
48 
49     /// Arch-specific implementation of `Vm::set_pvclock`.  Always returns an error on AArch64.
set_pvclock_arch(&self, _state: &ClockState) -> Result<()>50     pub fn set_pvclock_arch(&self, _state: &ClockState) -> Result<()> {
51         Err(Error::new(ENXIO))
52     }
53 
get_protected_vm_info(&self) -> Result<KvmProtectedVmInfo>54     fn get_protected_vm_info(&self) -> Result<KvmProtectedVmInfo> {
55         let mut info = KvmProtectedVmInfo {
56             firmware_size: 0,
57             reserved: [0; 7],
58         };
59         // Safe because we allocated the struct and we know the kernel won't write beyond the end of
60         // the struct or keep a pointer to it.
61         unsafe {
62             self.enable_raw_capability(
63                 KvmCap::ArmProtectedVm,
64                 KVM_CAP_ARM_PROTECTED_VM_FLAGS_INFO,
65                 &[&mut info as *mut KvmProtectedVmInfo as u64, 0, 0, 0],
66             )
67         }?;
68         Ok(info)
69     }
70 }
71 
72 #[repr(C)]
73 struct KvmProtectedVmInfo {
74     firmware_size: u64,
75     reserved: [u64; 7],
76 }
77 
78 impl VmAArch64 for KvmVm {
get_hypervisor(&self) -> &dyn Hypervisor79     fn get_hypervisor(&self) -> &dyn Hypervisor {
80         &self.kvm
81     }
82 
enable_protected_vm(&mut self, fw_addr: GuestAddress, fw_max_size: u64) -> Result<()>83     fn enable_protected_vm(&mut self, fw_addr: GuestAddress, fw_max_size: u64) -> Result<()> {
84         if !self.check_capability(VmCap::Protected) {
85             return Err(Error::new(ENOSYS));
86         }
87         let info = self.get_protected_vm_info()?;
88         let memslot = if info.firmware_size == 0 {
89             u64::MAX
90         } else {
91             if info.firmware_size > fw_max_size {
92                 return Err(Error::new(ENOMEM));
93             }
94             let mem = MemoryMappingBuilder::new(info.firmware_size as usize)
95                 .build()
96                 .map_err(|_| Error::new(EINVAL))?;
97             self.add_memory_region(fw_addr, Box::new(mem), false, false)? as u64
98         };
99         // Safe because none of the args are pointers.
100         unsafe {
101             self.enable_raw_capability(
102                 KvmCap::ArmProtectedVm,
103                 KVM_CAP_ARM_PROTECTED_VM_FLAGS_ENABLE,
104                 &[memslot, 0, 0, 0],
105             )
106         }
107     }
108 
create_vcpu(&self, id: usize) -> Result<Box<dyn VcpuAArch64>>109     fn create_vcpu(&self, id: usize) -> Result<Box<dyn VcpuAArch64>> {
110         // create_vcpu is declared separately in VmAArch64 and VmX86, so it can return VcpuAArch64
111         // or VcpuX86.  But both use the same implementation in KvmVm::create_vcpu.
112         Ok(Box::new(KvmVm::create_vcpu(self, id)?))
113     }
114 }
115 
116 impl KvmVcpu {
117     /// Arch-specific implementation of `Vcpu::pvclock_ctrl`.  Always returns an error on AArch64.
pvclock_ctrl_arch(&self) -> Result<()>118     pub fn pvclock_ctrl_arch(&self) -> Result<()> {
119         Err(Error::new(ENXIO))
120     }
121 }
122 
123 impl VcpuAArch64 for KvmVcpu {
init(&self, features: &[VcpuFeature]) -> Result<()>124     fn init(&self, features: &[VcpuFeature]) -> Result<()> {
125         let mut kvi = kvm_vcpu_init {
126             target: KVM_ARM_TARGET_GENERIC_V8,
127             features: [0; 7],
128         };
129         // Safe because we allocated the struct and we know the kernel will write exactly the size
130         // of the struct.
131         let ret = unsafe { ioctl_with_mut_ref(&self.vm, KVM_ARM_PREFERRED_TARGET(), &mut kvi) };
132         if ret != 0 {
133             return errno_result();
134         }
135 
136         for f in features {
137             let shift = match f {
138                 VcpuFeature::PsciV0_2 => KVM_ARM_VCPU_PSCI_0_2,
139                 VcpuFeature::PmuV3 => KVM_ARM_VCPU_PMU_V3,
140                 VcpuFeature::PowerOff => KVM_ARM_VCPU_POWER_OFF,
141             };
142             kvi.features[0] |= 1 << shift;
143         }
144 
145         // Safe because we allocated the struct and we know the kernel will read exactly the size of
146         // the struct.
147         let ret = unsafe { ioctl_with_ref(self, KVM_ARM_VCPU_INIT(), &kvi) };
148         if ret == 0 {
149             Ok(())
150         } else {
151             errno_result()
152         }
153     }
154 
init_pmu(&self, irq: u64) -> Result<()>155     fn init_pmu(&self, irq: u64) -> Result<()> {
156         let irq_addr = &irq as *const u64;
157 
158         // The in-kernel PMU virtualization is initialized by setting the irq
159         // with KVM_ARM_VCPU_PMU_V3_IRQ and then by KVM_ARM_VCPU_PMU_V3_INIT.
160 
161         let irq_attr = kvm_device_attr {
162             group: KVM_ARM_VCPU_PMU_V3_CTRL,
163             attr: KVM_ARM_VCPU_PMU_V3_IRQ as u64,
164             addr: irq_addr as u64,
165             flags: 0,
166         };
167         // Safe because we allocated the struct and we know the kernel will read exactly the size of
168         // the struct.
169         let ret = unsafe { ioctl_with_ref(self, kvm_sys::KVM_HAS_DEVICE_ATTR(), &irq_attr) };
170         if ret < 0 {
171             return errno_result();
172         }
173 
174         // Safe because we allocated the struct and we know the kernel will read exactly the size of
175         // the struct.
176         let ret = unsafe { ioctl_with_ref(self, kvm_sys::KVM_SET_DEVICE_ATTR(), &irq_attr) };
177         if ret < 0 {
178             return errno_result();
179         }
180 
181         let init_attr = kvm_device_attr {
182             group: KVM_ARM_VCPU_PMU_V3_CTRL,
183             attr: KVM_ARM_VCPU_PMU_V3_INIT as u64,
184             addr: 0,
185             flags: 0,
186         };
187         // Safe because we allocated the struct and we know the kernel will read exactly the size of
188         // the struct.
189         let ret = unsafe { ioctl_with_ref(self, kvm_sys::KVM_SET_DEVICE_ATTR(), &init_attr) };
190         if ret < 0 {
191             return errno_result();
192         }
193 
194         Ok(())
195     }
196 
set_one_reg(&self, reg_id: u64, data: u64) -> Result<()>197     fn set_one_reg(&self, reg_id: u64, data: u64) -> Result<()> {
198         let data_ref = &data as *const u64;
199         let onereg = kvm_one_reg {
200             id: reg_id,
201             addr: data_ref as u64,
202         };
203         // Safe because we allocated the struct and we know the kernel will read exactly the size of
204         // the struct.
205         let ret = unsafe { ioctl_with_ref(self, KVM_SET_ONE_REG(), &onereg) };
206         if ret == 0 {
207             Ok(())
208         } else {
209             errno_result()
210         }
211     }
212 
get_one_reg(&self, reg_id: u64) -> Result<u64>213     fn get_one_reg(&self, reg_id: u64) -> Result<u64> {
214         let val: u64 = 0;
215         let mut onereg = kvm_one_reg {
216             id: reg_id,
217             addr: (&val as *const u64) as u64,
218         };
219 
220         // Safe because we allocated the struct and we know the kernel will read exactly the size of
221         // the struct.
222         let ret = unsafe { ioctl_with_ref(self, KVM_GET_ONE_REG(), &mut onereg) };
223         if ret == 0 {
224             Ok(val)
225         } else {
226             return errno_result();
227         }
228     }
229 
get_psci_version(&self) -> Result<PsciVersion>230     fn get_psci_version(&self) -> Result<PsciVersion> {
231         // The definition of KVM_REG_ARM_PSCI_VERSION is in arch/arm64/include/uapi/asm/kvm.h.
232         const KVM_REG_ARM_PSCI_VERSION: u64 =
233             KVM_REG_ARM64 | (KVM_REG_SIZE_U64 as u64) | (KVM_REG_ARM_FW as u64);
234 
235         match self.get_one_reg(KVM_REG_ARM_PSCI_VERSION) {
236             Ok(v) => {
237                 let major = (v >> PSCI_VERSION_MAJOR_SHIFT) as u32;
238                 let minor = (v as u32) & PSCI_VERSION_MINOR_MASK;
239                 Ok(PsciVersion { major, minor })
240             }
241             Err(_) => {
242                 // When `KVM_REG_ARM_PSCI_VERSION` is not supported, we can return PSCI 0.2, as vCPU
243                 // has been initialized with `KVM_ARM_VCPU_PSCI_0_2` successfully.
244                 Ok(PsciVersion { major: 0, minor: 2 })
245             }
246         }
247     }
248 }
249 
250 // This function translates an IrqSrouceChip to the kvm u32 equivalent. It has a different
251 // implementation between x86_64 and aarch64 because the irqchip KVM constants are not defined on
252 // all architectures.
chip_to_kvm_chip(chip: IrqSourceChip) -> u32253 pub(super) fn chip_to_kvm_chip(chip: IrqSourceChip) -> u32 {
254     match chip {
255         // ARM does not have a constant for this, but the default routing
256         // setup seems to set this to 0
257         IrqSourceChip::Gic => 0,
258         _ => {
259             error!("Invalid IrqChipSource for ARM {:?}", chip);
260             0
261         }
262     }
263 }
264 
265 #[cfg(test)]
266 mod tests {
267     use super::super::Kvm;
268     use super::*;
269     use crate::{IrqRoute, IrqSource, IrqSourceChip};
270     use vm_memory::{GuestAddress, GuestMemory};
271 
272     #[test]
set_gsi_routing()273     fn set_gsi_routing() {
274         let kvm = Kvm::new().unwrap();
275         let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
276         let vm = KvmVm::new(&kvm, gm).unwrap();
277         vm.create_irq_chip().unwrap();
278         vm.set_gsi_routing(&[]).unwrap();
279         vm.set_gsi_routing(&[IrqRoute {
280             gsi: 1,
281             source: IrqSource::Irqchip {
282                 chip: IrqSourceChip::Gic,
283                 pin: 3,
284             },
285         }])
286         .unwrap();
287         vm.set_gsi_routing(&[IrqRoute {
288             gsi: 1,
289             source: IrqSource::Msi {
290                 address: 0xf000000,
291                 data: 0xa0,
292             },
293         }])
294         .unwrap();
295         vm.set_gsi_routing(&[
296             IrqRoute {
297                 gsi: 1,
298                 source: IrqSource::Irqchip {
299                     chip: IrqSourceChip::Gic,
300                     pin: 3,
301                 },
302             },
303             IrqRoute {
304                 gsi: 2,
305                 source: IrqSource::Msi {
306                     address: 0xf000000,
307                     data: 0xa0,
308                 },
309             },
310         ])
311         .unwrap();
312     }
313 }
314