Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/hypervisor/src/kvm/aarch64.rs
5394 views
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
// We have u32 constants from bindings that are passed into archiitecture-dependent functions
6
// taking u32/64 parameters. So on 32 bit platforms we may have needless casts.
7
#![allow(clippy::useless_conversion)]
8
9
use std::collections::BTreeMap;
10
use std::convert::TryFrom;
11
use std::mem::offset_of;
12
13
use aarch64_sys_reg::AArch64SysRegId;
14
use anyhow::Context;
15
use base::errno_result;
16
use base::error;
17
use base::ioctl_with_mut_ref;
18
use base::ioctl_with_ref;
19
use base::ioctl_with_val;
20
use base::warn;
21
use base::Error;
22
use base::Result;
23
use cros_fdt::Fdt;
24
use kvm_sys::*;
25
use libc::EINVAL;
26
use libc::ENOMEM;
27
use libc::ENOTSUP;
28
use libc::ENXIO;
29
use serde::Deserialize;
30
use serde::Serialize;
31
use snapshot::AnySnapshot;
32
use vm_memory::GuestAddress;
33
use zerocopy::FromZeros;
34
35
use super::Config;
36
use super::Kvm;
37
use super::KvmCap;
38
use super::KvmVcpu;
39
use super::KvmVm;
40
use crate::ClockState;
41
use crate::DeviceKind;
42
use crate::HypercallAbi;
43
use crate::Hypervisor;
44
use crate::IrqSourceChip;
45
use crate::ProtectionType;
46
use crate::PsciVersion;
47
use crate::VcpuAArch64;
48
use crate::VcpuExit;
49
use crate::VcpuFeature;
50
use crate::VcpuRegAArch64;
51
use crate::VmAArch64;
52
use crate::VmCap;
53
use crate::AARCH64_MAX_REG_COUNT;
54
use crate::PSCI_0_2;
55
56
impl Kvm {
57
// Compute the machine type, which should be the IPA range for the VM
58
// Ideally, this would take a description of the memory map and return
59
// the closest machine type for this VM. Here, we just return the maximum
60
// the kernel support.
61
pub fn get_vm_type(&self, protection_type: ProtectionType) -> Result<u32> {
62
// SAFETY:
63
// Safe because we know self is a real kvm fd
64
let ipa_size = match unsafe {
65
ioctl_with_val(self, KVM_CHECK_EXTENSION, KVM_CAP_ARM_VM_IPA_SIZE.into())
66
} {
67
// Not supported? Use 0 as the machine type, which implies 40bit IPA
68
ret if ret < 0 => 0,
69
ipa => ipa as u32,
70
};
71
let protection_flag = if protection_type.isolates_memory() {
72
KVM_VM_TYPE_ARM_PROTECTED
73
} else {
74
0
75
};
76
// Use the lower 8 bits representing the IPA space as the machine type
77
Ok((ipa_size & KVM_VM_TYPE_ARM_IPA_SIZE_MASK) | protection_flag)
78
}
79
80
/// Get the size of guest physical addresses (IPA) in bits.
81
pub fn get_guest_phys_addr_bits(&self) -> u8 {
82
// SAFETY:
83
// Safe because we know self is a real kvm fd
84
match unsafe { ioctl_with_val(self, KVM_CHECK_EXTENSION, KVM_CAP_ARM_VM_IPA_SIZE.into()) } {
85
// Default physical address size is 40 bits if the extension is not supported.
86
ret if ret <= 0 => 40,
87
ipa => ipa as u8,
88
}
89
}
90
}
91
92
impl KvmVm {
93
/// Does platform specific initialization for the KvmVm.
94
pub fn init_arch(&self, cfg: &Config) -> Result<()> {
95
if cfg.mte {
96
// SAFETY:
97
// Safe because it does not take pointer arguments.
98
unsafe { self.enable_raw_capability(KvmCap::ArmMte, 0, &[0, 0, 0, 0])? }
99
}
100
#[cfg(target_os = "android")]
101
if cfg.ffa {
102
self.set_enable_ffa(true)?;
103
}
104
105
Ok(())
106
}
107
108
/// Checks if a particular `VmCap` is available, or returns None if arch-independent
109
/// Vm.check_capability() should handle the check.
110
pub fn check_capability_arch(&self, _c: VmCap) -> Option<bool> {
111
None
112
}
113
114
/// Returns the params to pass to KVM_CREATE_DEVICE for a `kind` device on this arch, or None to
115
/// let the arch-independent `KvmVm::create_device` handle it.
116
pub fn get_device_params_arch(&self, kind: DeviceKind) -> Option<kvm_create_device> {
117
match kind {
118
DeviceKind::ArmVgicV2 => Some(kvm_create_device {
119
type_: kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2,
120
fd: 0,
121
flags: 0,
122
}),
123
DeviceKind::ArmVgicV3 => Some(kvm_create_device {
124
type_: kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3,
125
fd: 0,
126
flags: 0,
127
}),
128
DeviceKind::ArmVgicIts => Some(kvm_create_device {
129
type_: kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_ITS,
130
fd: 0,
131
flags: 0,
132
}),
133
_ => None,
134
}
135
}
136
137
pub(super) fn enable_smccc_forwarding(&mut self, base: u32, nr_functions: u32) -> Result<()> {
138
let smccc_filter = kvm_smccc_filter {
139
base,
140
nr_functions,
141
action: kvm_smccc_filter_action_KVM_SMCCC_FILTER_FWD_TO_USER as u8,
142
pad: [0; 15],
143
};
144
let dev_attr = kvm_device_attr {
145
group: KVM_ARM_VM_SMCCC_CTRL,
146
attr: KVM_ARM_VM_SMCCC_FILTER as u64,
147
addr: &smccc_filter as *const _ as u64,
148
flags: 0,
149
};
150
151
// SAFETY:
152
// Safe because we know that our file is a VM fd, we know the kernel will only read the
153
// correct amount of memory from our pointer, and we verify the return result.
154
match unsafe { ioctl_with_ref(self, KVM_SET_DEVICE_ATTR, &dev_attr) } {
155
0 => Ok(()),
156
_ => errno_result(),
157
}
158
}
159
160
/// Arch-specific implementation of `Vm::get_pvclock`. Always returns an error on AArch64.
161
pub fn get_pvclock_arch(&self) -> Result<ClockState> {
162
Err(Error::new(ENXIO))
163
}
164
165
/// Arch-specific implementation of `Vm::set_pvclock`. Always returns an error on AArch64.
166
pub fn set_pvclock_arch(&self, _state: &ClockState) -> Result<()> {
167
Err(Error::new(ENXIO))
168
}
169
170
/// Get pKVM hypervisor details, e.g. the firmware size.
171
///
172
/// Returns `Err` if not running under pKVM.
173
///
174
/// Uses `KVM_ENABLE_CAP` internally, but it is only a getter, there should be no side effects
175
/// in KVM.
176
fn get_protected_vm_info(&self) -> Result<KvmProtectedVmInfo> {
177
let mut info = KvmProtectedVmInfo {
178
firmware_size: 0,
179
reserved: [0; 7],
180
};
181
// SAFETY:
182
// Safe because we allocated the struct and we know the kernel won't write beyond the end of
183
// the struct or keep a pointer to it.
184
unsafe {
185
self.enable_raw_capability(
186
KvmCap::ArmProtectedVm,
187
KVM_CAP_ARM_PROTECTED_VM_FLAGS_INFO,
188
&[&mut info as *mut KvmProtectedVmInfo as u64, 0, 0, 0],
189
)
190
}?;
191
Ok(info)
192
}
193
194
fn set_protected_vm_firmware_ipa(&self, fw_addr: GuestAddress) -> Result<()> {
195
// SAFETY:
196
// Safe because none of the args are pointers.
197
unsafe {
198
self.enable_raw_capability(
199
KvmCap::ArmProtectedVm,
200
KVM_CAP_ARM_PROTECTED_VM_FLAGS_SET_FW_IPA,
201
&[fw_addr.0, 0, 0, 0],
202
)
203
}
204
}
205
206
#[cfg(all(target_os = "android", target_arch = "aarch64"))]
207
fn set_enable_ffa(&self, ffa_support: bool) -> Result<()> {
208
// SAFETY:
209
// Safe because none of the args are pointers.
210
unsafe {
211
self.enable_raw_capability(
212
KvmCap::ArmProtectedVm,
213
KVM_CAP_ARM_PROTECTED_VM_FLAGS_SET_FFA,
214
&[ffa_support.into(), 0, 0, 0],
215
)
216
}
217
}
218
}
219
220
#[repr(C)]
221
struct KvmProtectedVmInfo {
222
firmware_size: u64,
223
reserved: [u64; 7],
224
}
225
226
impl VmAArch64 for KvmVm {
227
fn get_hypervisor(&self) -> &dyn Hypervisor {
228
&self.kvm
229
}
230
231
fn load_protected_vm_firmware(
232
&mut self,
233
fw_addr: GuestAddress,
234
fw_max_size: u64,
235
) -> Result<()> {
236
let info = self.get_protected_vm_info()?;
237
if info.firmware_size == 0 {
238
Err(Error::new(EINVAL))
239
} else {
240
if info.firmware_size > fw_max_size {
241
return Err(Error::new(ENOMEM));
242
}
243
self.set_protected_vm_firmware_ipa(fw_addr)
244
}
245
}
246
247
fn create_vcpu(&self, id: usize) -> Result<Box<dyn VcpuAArch64>> {
248
// create_vcpu is declared separately in VmAArch64 and VmX86, so it can return VcpuAArch64
249
// or VcpuX86. But both use the same implementation in KvmVm::create_kvm_vcpu.
250
Ok(Box::new(self.create_kvm_vcpu(id)?))
251
}
252
253
fn create_fdt(&self, _fdt: &mut Fdt, _phandles: &BTreeMap<&str, u32>) -> cros_fdt::Result<()> {
254
Ok(())
255
}
256
257
fn init_arch(
258
&self,
259
_payload_entry_address: GuestAddress,
260
_fdt_address: GuestAddress,
261
_fdt_size: usize,
262
) -> anyhow::Result<()> {
263
Ok(())
264
}
265
266
fn set_counter_offset(&self, offset: u64) -> Result<()> {
267
let off = kvm_arm_counter_offset {
268
counter_offset: offset,
269
reserved: 0,
270
};
271
// SAFETY: self.vm is a valid KVM fd
272
let ret = unsafe { ioctl_with_ref(&self.vm, KVM_ARM_SET_COUNTER_OFFSET, &off) };
273
if ret != 0 {
274
return errno_result();
275
}
276
Ok(())
277
}
278
}
279
280
impl KvmVcpu {
281
/// Handles a `KVM_EXIT_SYSTEM_EVENT` with event type `KVM_SYSTEM_EVENT_RESET` with the given
282
/// event flags and returns the appropriate `VcpuExit` value for the run loop to handle.
283
///
284
/// `event_flags` should be one or more of the `KVM_SYSTEM_EVENT_RESET_FLAG_*` values defined by
285
/// KVM.
286
pub fn system_event_reset(&self, event_flags: u64) -> Result<VcpuExit> {
287
if event_flags & u64::from(KVM_SYSTEM_EVENT_RESET_FLAG_PSCI_RESET2) != 0 {
288
// Read reset_type and cookie from x1 and x2.
289
let reset_type = self.get_one_reg(VcpuRegAArch64::X(1))?;
290
let cookie = self.get_one_reg(VcpuRegAArch64::X(2))?;
291
warn!(
292
"PSCI SYSTEM_RESET2 with reset_type={:#x}, cookie={:#x}",
293
reset_type, cookie
294
);
295
}
296
Ok(VcpuExit::SystemEventReset)
297
}
298
299
fn kvm_reg_id(&self, reg: VcpuRegAArch64) -> Result<KvmVcpuRegister> {
300
match reg {
301
VcpuRegAArch64::X(n @ 0..=30) => Ok(KvmVcpuRegister::X(n)),
302
VcpuRegAArch64::Sp => Ok(KvmVcpuRegister::Sp),
303
VcpuRegAArch64::Pc => Ok(KvmVcpuRegister::Pc),
304
VcpuRegAArch64::Pstate => Ok(KvmVcpuRegister::Pstate),
305
// Special case for multiplexed KVM registers
306
VcpuRegAArch64::System(aarch64_sys_reg::CCSIDR_EL1) => {
307
let csselr =
308
self.get_one_reg(VcpuRegAArch64::System(aarch64_sys_reg::CSSELR_EL1))?;
309
Ok(KvmVcpuRegister::Ccsidr(csselr as u8))
310
}
311
VcpuRegAArch64::System(sysreg) => Ok(KvmVcpuRegister::System(sysreg)),
312
_ => Err(Error::new(EINVAL)),
313
}
314
}
315
316
fn set_one_kvm_reg_u32(&self, kvm_reg_id: KvmVcpuRegister, data: u32) -> Result<()> {
317
self.set_one_kvm_reg(kvm_reg_id, data.to_ne_bytes().as_slice())
318
}
319
320
fn set_one_kvm_reg_u64(&self, kvm_reg_id: KvmVcpuRegister, data: u64) -> Result<()> {
321
self.set_one_kvm_reg(kvm_reg_id, data.to_ne_bytes().as_slice())
322
}
323
324
fn set_one_kvm_reg_u128(&self, kvm_reg_id: KvmVcpuRegister, data: u128) -> Result<()> {
325
self.set_one_kvm_reg(kvm_reg_id, data.to_ne_bytes().as_slice())
326
}
327
328
fn set_one_kvm_reg(&self, kvm_reg_id: KvmVcpuRegister, data: &[u8]) -> Result<()> {
329
assert_eq!(kvm_reg_id.size(), data.len());
330
let id: u64 = kvm_reg_id.into();
331
let onereg = kvm_one_reg {
332
id,
333
addr: (data.as_ptr() as usize)
334
.try_into()
335
.expect("can't represent usize as u64"),
336
};
337
// SAFETY:
338
// Safe because we allocated the struct and we know the kernel will read exactly the size of
339
// the struct.
340
let ret = unsafe { ioctl_with_ref(self, KVM_SET_ONE_REG, &onereg) };
341
if ret == 0 {
342
Ok(())
343
} else {
344
errno_result()
345
}
346
}
347
348
fn get_one_kvm_reg_u32(&self, kvm_reg_id: KvmVcpuRegister) -> Result<u32> {
349
let mut bytes = 0u32.to_ne_bytes();
350
self.get_one_kvm_reg(kvm_reg_id, bytes.as_mut_slice())?;
351
Ok(u32::from_ne_bytes(bytes))
352
}
353
354
fn get_one_kvm_reg_u64(&self, kvm_reg_id: KvmVcpuRegister) -> Result<u64> {
355
let mut bytes = 0u64.to_ne_bytes();
356
self.get_one_kvm_reg(kvm_reg_id, bytes.as_mut_slice())?;
357
Ok(u64::from_ne_bytes(bytes))
358
}
359
360
fn get_one_kvm_reg_u128(&self, kvm_reg_id: KvmVcpuRegister) -> Result<u128> {
361
let mut bytes = 0u128.to_ne_bytes();
362
self.get_one_kvm_reg(kvm_reg_id, bytes.as_mut_slice())?;
363
Ok(u128::from_ne_bytes(bytes))
364
}
365
366
fn get_one_kvm_reg(&self, kvm_reg_id: KvmVcpuRegister, data: &mut [u8]) -> Result<()> {
367
assert_eq!(kvm_reg_id.size(), data.len());
368
let id: u64 = kvm_reg_id.into();
369
let onereg = kvm_one_reg {
370
id,
371
addr: (data.as_mut_ptr() as usize)
372
.try_into()
373
.expect("can't represent usize as u64"),
374
};
375
376
// SAFETY:
377
// Safe because we allocated the struct and we know the kernel will read exactly the size of
378
// the struct.
379
let ret = unsafe { ioctl_with_ref(self, KVM_GET_ONE_REG, &onereg) };
380
if ret == 0 {
381
Ok(())
382
} else {
383
errno_result()
384
}
385
}
386
387
pub(super) fn handle_smccc_call(
388
&self,
389
handle_fn: &mut dyn FnMut(&mut HypercallAbi) -> anyhow::Result<()>,
390
) -> anyhow::Result<()> {
391
const SMCCC_NOT_SUPPORTED: usize = u64::MAX as usize;
392
// SMCCC defines FID as the value in W0 with most significant bits ignored.
393
let function_id = (self.get_one_reg(VcpuRegAArch64::X(0))? as u32)
394
.try_into()
395
.unwrap();
396
let args = &[
397
self.get_one_reg(VcpuRegAArch64::X(1))?.try_into().unwrap(),
398
self.get_one_reg(VcpuRegAArch64::X(2))?.try_into().unwrap(),
399
self.get_one_reg(VcpuRegAArch64::X(3))?.try_into().unwrap(),
400
];
401
let default_res = &[SMCCC_NOT_SUPPORTED, 0, 0, 0];
402
403
let mut smccc_abi = HypercallAbi::new(function_id, args, default_res);
404
405
let err_or_ok = handle_fn(&mut smccc_abi);
406
407
for (i, value) in smccc_abi.get_results().iter().enumerate() {
408
self.set_one_reg(VcpuRegAArch64::X(i as _), (*value).try_into().unwrap())?;
409
}
410
411
err_or_ok
412
}
413
414
#[inline]
415
pub(crate) fn handle_vm_exit_arch(&self, _run: &mut kvm_run) -> Option<VcpuExit> {
416
// No aarch64-specific exits (for now)
417
None
418
}
419
420
fn get_reg_list(&self) -> Result<Vec<u64>> {
421
let mut kvm_reg_list = kvm_reg_list::<[u64; AARCH64_MAX_REG_COUNT]>::new_zeroed();
422
kvm_reg_list.n = AARCH64_MAX_REG_COUNT as u64;
423
let ret =
424
// SAFETY:
425
// We trust the kernel not to read/write past the end of kvm_reg_list struct.
426
unsafe { ioctl_with_mut_ref(self, KVM_GET_REG_LIST, &mut kvm_reg_list) };
427
if ret < 0 {
428
return errno_result();
429
}
430
let n = kvm_reg_list.n;
431
assert!(
432
n <= AARCH64_MAX_REG_COUNT as u64,
433
"Get reg list returned more registers than possible"
434
);
435
Ok(kvm_reg_list.reg[..n as usize].to_vec())
436
}
437
438
fn get_features_bitmap(&self, features: &[VcpuFeature]) -> Result<u32> {
439
let mut all_features = 0;
440
let check_extension = |ext: u32| -> bool {
441
// SAFETY:
442
// Safe because we know self.vm is a real kvm fd
443
unsafe { ioctl_with_val(&self.vm, KVM_CHECK_EXTENSION, ext.into()) == 1 }
444
};
445
446
for f in features {
447
let shift = match f {
448
VcpuFeature::PsciV0_2 => KVM_ARM_VCPU_PSCI_0_2,
449
VcpuFeature::PmuV3 => KVM_ARM_VCPU_PMU_V3,
450
VcpuFeature::PowerOff => KVM_ARM_VCPU_POWER_OFF,
451
VcpuFeature::Sve => {
452
if !check_extension(KVM_CAP_ARM_SVE) {
453
return Err(Error::new(ENOTSUP));
454
}
455
KVM_ARM_VCPU_SVE
456
}
457
};
458
all_features |= 1 << shift;
459
}
460
461
if check_extension(KVM_CAP_ARM_PTRAUTH_ADDRESS)
462
&& check_extension(KVM_CAP_ARM_PTRAUTH_GENERIC)
463
{
464
all_features |= 1 << KVM_ARM_VCPU_PTRAUTH_ADDRESS;
465
all_features |= 1 << KVM_ARM_VCPU_PTRAUTH_GENERIC;
466
}
467
468
Ok(all_features)
469
}
470
471
/// Finalize VCPU features setup. This does not affect features that do not make use of
472
/// finalize.
473
fn finalize(&self, features: u32) -> Result<()> {
474
if (features & 1 << KVM_ARM_VCPU_SVE) != 0 {
475
// SAFETY:
476
// Safe because we know that our file is a Vcpu fd and we verify the return result.
477
let ret = unsafe {
478
ioctl_with_ref(
479
self,
480
KVM_ARM_VCPU_FINALIZE,
481
&std::os::raw::c_int::try_from(KVM_ARM_VCPU_SVE)
482
.map_err(|_| Error::new(EINVAL))?,
483
)
484
};
485
if ret != 0 {
486
return errno_result();
487
}
488
}
489
490
Ok(())
491
}
492
}
493
494
/// KVM registers as used by the `GET_ONE_REG`/`SET_ONE_REG` ioctl API
495
///
496
/// These variants represent the registers as exposed by KVM which must be different from
497
/// `VcpuRegAArch64` to support registers which don't have an architectural definition such as
498
/// pseudo-registers (`Firmware`) and multiplexed registers (`Ccsidr`).
499
///
500
/// See https://docs.kernel.org/virt/kvm/api.html for more details.
501
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
502
pub enum KvmVcpuRegister {
503
/// General Purpose Registers X0-X30
504
X(u8),
505
/// Stack Pointer
506
Sp,
507
/// Program Counter
508
Pc,
509
/// Processor State
510
Pstate,
511
/// FP & SIMD Registers V0-V31
512
V(u8),
513
/// KVM Firmware Pseudo-Registers
514
Firmware(u16),
515
/// System Registers
516
System(AArch64SysRegId),
517
/// CCSIDR_EL1 Demultiplexed by CSSELR_EL1
518
Ccsidr(u8),
519
}
520
521
impl KvmVcpuRegister {
522
// Firmware pseudo-registers are part of the ARM KVM interface:
523
// https://docs.kernel.org/virt/kvm/arm/hypercalls.html
524
pub const PSCI_VERSION: Self = Self::Firmware(0);
525
pub const SMCCC_ARCH_WORKAROUND_1: Self = Self::Firmware(1);
526
pub const SMCCC_ARCH_WORKAROUND_2: Self = Self::Firmware(2);
527
pub const SMCCC_ARCH_WORKAROUND_3: Self = Self::Firmware(3);
528
529
/// Size of this register in bytes.
530
pub fn size(&self) -> usize {
531
let kvm_reg = u64::from(*self);
532
let size_field = kvm_reg & KVM_REG_SIZE_MASK;
533
const REG_SIZE_U8: u64 = KVM_REG_SIZE_U8 as u64; // cast from bindgen's u32 to u64
534
match size_field {
535
REG_SIZE_U8 => 1,
536
KVM_REG_SIZE_U16 => 2,
537
KVM_REG_SIZE_U32 => 4,
538
KVM_REG_SIZE_U64 => 8,
539
KVM_REG_SIZE_U128 => 16,
540
KVM_REG_SIZE_U256 => 32,
541
KVM_REG_SIZE_U512 => 64,
542
KVM_REG_SIZE_U1024 => 128,
543
KVM_REG_SIZE_U2048 => 256,
544
// `From<KvmVcpuRegister> for u64` should always include a valid size.
545
_ => panic!("invalid size field {size_field}"),
546
}
547
}
548
}
549
550
/// Gives the `u64` register ID expected by the `GET_ONE_REG`/`SET_ONE_REG` ioctl API.
551
///
552
/// See the KVM documentation of those ioctls for details about the format of the register ID.
553
impl From<KvmVcpuRegister> for u64 {
554
fn from(register: KvmVcpuRegister) -> Self {
555
const fn reg(size: u64, kind: u64, fields: u64) -> u64 {
556
KVM_REG_ARM64 | size | kind | fields
557
}
558
559
const fn kvm_regs_reg(size: u64, offset: usize) -> u64 {
560
let offset = offset / std::mem::size_of::<u32>();
561
562
reg(size, KVM_REG_ARM_CORE as u64, offset as u64)
563
}
564
565
const fn kvm_reg(offset: usize) -> u64 {
566
kvm_regs_reg(KVM_REG_SIZE_U64, offset)
567
}
568
569
fn spsr_reg(spsr_reg: u32) -> u64 {
570
let n = std::mem::size_of::<u64>() * (spsr_reg as usize);
571
kvm_reg(offset_of!(kvm_regs, spsr) + n)
572
}
573
574
fn user_pt_reg(offset: usize) -> u64 {
575
kvm_regs_reg(KVM_REG_SIZE_U64, offset_of!(kvm_regs, regs) + offset)
576
}
577
578
fn user_fpsimd_state_reg(size: u64, offset: usize) -> u64 {
579
kvm_regs_reg(size, offset_of!(kvm_regs, fp_regs) + offset)
580
}
581
582
const fn reg_u64(kind: u64, fields: u64) -> u64 {
583
reg(KVM_REG_SIZE_U64, kind, fields)
584
}
585
586
const fn demux_reg(size: u64, index: u64, value: u64) -> u64 {
587
let index = (index << KVM_REG_ARM_DEMUX_ID_SHIFT) & (KVM_REG_ARM_DEMUX_ID_MASK as u64);
588
let value =
589
(value << KVM_REG_ARM_DEMUX_VAL_SHIFT) & (KVM_REG_ARM_DEMUX_VAL_MASK as u64);
590
591
reg(size, KVM_REG_ARM_DEMUX as u64, index | value)
592
}
593
594
match register {
595
KvmVcpuRegister::X(n @ 0..=30) => {
596
let n = std::mem::size_of::<u64>() * (n as usize);
597
598
user_pt_reg(offset_of!(user_pt_regs, regs) + n)
599
}
600
KvmVcpuRegister::X(n) => unreachable!("invalid KvmVcpuRegister Xn index: {n}"),
601
KvmVcpuRegister::Sp => user_pt_reg(offset_of!(user_pt_regs, sp)),
602
KvmVcpuRegister::Pc => user_pt_reg(offset_of!(user_pt_regs, pc)),
603
KvmVcpuRegister::Pstate => user_pt_reg(offset_of!(user_pt_regs, pstate)),
604
KvmVcpuRegister::V(n @ 0..=31) => {
605
let n = std::mem::size_of::<u128>() * (n as usize);
606
607
user_fpsimd_state_reg(KVM_REG_SIZE_U128, offset_of!(user_fpsimd_state, vregs) + n)
608
}
609
KvmVcpuRegister::V(n) => unreachable!("invalid KvmVcpuRegister Vn index: {n}"),
610
KvmVcpuRegister::System(aarch64_sys_reg::FPSR) => {
611
user_fpsimd_state_reg(KVM_REG_SIZE_U32, offset_of!(user_fpsimd_state, fpsr))
612
}
613
KvmVcpuRegister::System(aarch64_sys_reg::FPCR) => {
614
user_fpsimd_state_reg(KVM_REG_SIZE_U32, offset_of!(user_fpsimd_state, fpcr))
615
}
616
KvmVcpuRegister::System(aarch64_sys_reg::SPSR_EL1) => spsr_reg(KVM_SPSR_EL1),
617
KvmVcpuRegister::System(aarch64_sys_reg::SPSR_abt) => spsr_reg(KVM_SPSR_ABT),
618
KvmVcpuRegister::System(aarch64_sys_reg::SPSR_und) => spsr_reg(KVM_SPSR_UND),
619
KvmVcpuRegister::System(aarch64_sys_reg::SPSR_irq) => spsr_reg(KVM_SPSR_IRQ),
620
KvmVcpuRegister::System(aarch64_sys_reg::SPSR_fiq) => spsr_reg(KVM_SPSR_FIQ),
621
KvmVcpuRegister::System(aarch64_sys_reg::SP_EL1) => {
622
kvm_reg(offset_of!(kvm_regs, sp_el1))
623
}
624
KvmVcpuRegister::System(aarch64_sys_reg::ELR_EL1) => {
625
kvm_reg(offset_of!(kvm_regs, elr_el1))
626
}
627
// The KVM API accidentally swapped CNTV_CVAL_EL0 and CNTVCT_EL0.
628
KvmVcpuRegister::System(aarch64_sys_reg::CNTV_CVAL_EL0) => reg_u64(
629
KVM_REG_ARM64_SYSREG.into(),
630
aarch64_sys_reg::CNTVCT_EL0.encoded().into(),
631
),
632
KvmVcpuRegister::System(aarch64_sys_reg::CNTVCT_EL0) => reg_u64(
633
KVM_REG_ARM64_SYSREG.into(),
634
aarch64_sys_reg::CNTV_CVAL_EL0.encoded().into(),
635
),
636
KvmVcpuRegister::System(sysreg) => {
637
reg_u64(KVM_REG_ARM64_SYSREG.into(), sysreg.encoded().into())
638
}
639
KvmVcpuRegister::Firmware(n) => reg_u64(KVM_REG_ARM_FW.into(), n.into()),
640
KvmVcpuRegister::Ccsidr(n) => demux_reg(KVM_REG_SIZE_U32, 0, n.into()),
641
}
642
}
643
}
644
645
impl VcpuAArch64 for KvmVcpu {
646
fn init(&self, features: &[VcpuFeature]) -> Result<()> {
647
let mut kvi = kvm_vcpu_init {
648
target: KVM_ARM_TARGET_GENERIC_V8,
649
features: [0; 7],
650
};
651
// SAFETY:
652
// Safe because we allocated the struct and we know the kernel will write exactly the size
653
// of the struct.
654
let ret = unsafe { ioctl_with_mut_ref(&self.vm, KVM_ARM_PREFERRED_TARGET, &mut kvi) };
655
if ret != 0 {
656
return errno_result();
657
}
658
659
kvi.features[0] = self.get_features_bitmap(features)?;
660
// SAFETY:
661
// Safe because we allocated the struct and we know the kernel will read exactly the size of
662
// the struct.
663
let ret = unsafe { ioctl_with_ref(self, KVM_ARM_VCPU_INIT, &kvi) };
664
if ret != 0 {
665
return errno_result();
666
}
667
668
self.finalize(kvi.features[0])?;
669
Ok(())
670
}
671
672
fn init_pmu(&self, irq: u64) -> Result<()> {
673
let irq_addr = &irq as *const u64;
674
675
// The in-kernel PMU virtualization is initialized by setting the irq
676
// with KVM_ARM_VCPU_PMU_V3_IRQ and then by KVM_ARM_VCPU_PMU_V3_INIT.
677
678
let irq_attr = kvm_device_attr {
679
group: KVM_ARM_VCPU_PMU_V3_CTRL,
680
attr: KVM_ARM_VCPU_PMU_V3_IRQ as u64,
681
addr: irq_addr as u64,
682
flags: 0,
683
};
684
// SAFETY:
685
// Safe because we allocated the struct and we know the kernel will read exactly the size of
686
// the struct.
687
let ret = unsafe { ioctl_with_ref(self, kvm_sys::KVM_HAS_DEVICE_ATTR, &irq_attr) };
688
if ret < 0 {
689
return errno_result();
690
}
691
692
// SAFETY:
693
// Safe because we allocated the struct and we know the kernel will read exactly the size of
694
// the struct.
695
let ret = unsafe { ioctl_with_ref(self, kvm_sys::KVM_SET_DEVICE_ATTR, &irq_attr) };
696
if ret < 0 {
697
return errno_result();
698
}
699
700
let init_attr = kvm_device_attr {
701
group: KVM_ARM_VCPU_PMU_V3_CTRL,
702
attr: KVM_ARM_VCPU_PMU_V3_INIT as u64,
703
addr: 0,
704
flags: 0,
705
};
706
// SAFETY:
707
// Safe because we allocated the struct and we know the kernel will read exactly the size of
708
// the struct.
709
let ret = unsafe { ioctl_with_ref(self, kvm_sys::KVM_SET_DEVICE_ATTR, &init_attr) };
710
if ret < 0 {
711
return errno_result();
712
}
713
714
Ok(())
715
}
716
717
fn has_pvtime_support(&self) -> bool {
718
// The in-kernel PV time structure is initialized by setting the base
719
// address with KVM_ARM_VCPU_PVTIME_IPA
720
let pvtime_attr = kvm_device_attr {
721
group: KVM_ARM_VCPU_PVTIME_CTRL,
722
attr: KVM_ARM_VCPU_PVTIME_IPA as u64,
723
addr: 0,
724
flags: 0,
725
};
726
// SAFETY:
727
// Safe because we allocated the struct and we know the kernel will read exactly the size of
728
// the struct.
729
let ret = unsafe { ioctl_with_ref(self, kvm_sys::KVM_HAS_DEVICE_ATTR, &pvtime_attr) };
730
ret >= 0
731
}
732
733
fn init_pvtime(&self, pvtime_ipa: u64) -> Result<()> {
734
let pvtime_ipa_addr = &pvtime_ipa as *const u64;
735
736
// The in-kernel PV time structure is initialized by setting the base
737
// address with KVM_ARM_VCPU_PVTIME_IPA
738
let pvtime_attr = kvm_device_attr {
739
group: KVM_ARM_VCPU_PVTIME_CTRL,
740
attr: KVM_ARM_VCPU_PVTIME_IPA as u64,
741
addr: pvtime_ipa_addr as u64,
742
flags: 0,
743
};
744
745
// SAFETY:
746
// Safe because we allocated the struct and we know the kernel will read exactly the size of
747
// the struct.
748
let ret = unsafe { ioctl_with_ref(self, kvm_sys::KVM_SET_DEVICE_ATTR, &pvtime_attr) };
749
if ret < 0 {
750
return errno_result();
751
}
752
753
Ok(())
754
}
755
756
fn set_one_reg(&self, reg_id: VcpuRegAArch64, data: u64) -> Result<()> {
757
let kvm_reg = self.kvm_reg_id(reg_id)?;
758
match kvm_reg.size() {
759
4 => self.set_one_kvm_reg_u32(kvm_reg, data as u32),
760
8 => self.set_one_kvm_reg_u64(kvm_reg, data),
761
size => panic!("bad reg size {size}"),
762
}
763
}
764
765
fn get_one_reg(&self, reg_id: VcpuRegAArch64) -> Result<u64> {
766
let kvm_reg = self.kvm_reg_id(reg_id)?;
767
match kvm_reg.size() {
768
4 => self.get_one_kvm_reg_u32(kvm_reg).map(u64::from),
769
8 => self.get_one_kvm_reg_u64(kvm_reg),
770
size => panic!("bad reg size {size}"),
771
}
772
}
773
774
fn set_vector_reg(&self, reg_num: u8, data: u128) -> Result<()> {
775
if reg_num > 31 {
776
return Err(Error::new(EINVAL));
777
}
778
self.set_one_kvm_reg_u128(KvmVcpuRegister::V(reg_num), data)
779
}
780
781
fn get_vector_reg(&self, reg_num: u8) -> Result<u128> {
782
if reg_num > 31 {
783
return Err(Error::new(EINVAL));
784
}
785
self.get_one_kvm_reg_u128(KvmVcpuRegister::V(reg_num))
786
}
787
788
fn get_mpidr(&self) -> Result<u64> {
789
self.get_one_reg(VcpuRegAArch64::System(aarch64_sys_reg::MPIDR_EL1))
790
}
791
792
fn get_psci_version(&self) -> Result<PsciVersion> {
793
let version = if let Ok(v) = self.get_one_kvm_reg_u64(KvmVcpuRegister::PSCI_VERSION) {
794
let v = u32::try_from(v).map_err(|_| Error::new(EINVAL))?;
795
PsciVersion::try_from(v)?
796
} else {
797
// When `KVM_REG_ARM_PSCI_VERSION` is not supported, we can return PSCI 0.2, as vCPU
798
// has been initialized with `KVM_ARM_VCPU_PSCI_0_2` successfully.
799
PSCI_0_2
800
};
801
802
if version < PSCI_0_2 {
803
// PSCI v0.1 isn't currently supported for guests
804
Err(Error::new(ENOTSUP))
805
} else {
806
Ok(version)
807
}
808
}
809
810
fn get_max_hw_bps(&self) -> Result<usize> {
811
// SAFETY:
812
// Safe because the kernel will only return the result of the ioctl.
813
let max_hw_bps = unsafe {
814
ioctl_with_val(
815
&self.vm,
816
KVM_CHECK_EXTENSION,
817
KVM_CAP_GUEST_DEBUG_HW_BPS.into(),
818
)
819
};
820
821
if max_hw_bps < 0 {
822
errno_result()
823
} else {
824
Ok(max_hw_bps.try_into().expect("can't represent u64 as usize"))
825
}
826
}
827
828
fn get_system_regs(&self) -> Result<BTreeMap<AArch64SysRegId, u64>> {
829
let reg_list = self.get_reg_list()?;
830
let cntvct_el0: u16 = aarch64_sys_reg::CNTVCT_EL0.encoded();
831
let cntv_cval_el0: u16 = aarch64_sys_reg::CNTV_CVAL_EL0.encoded();
832
let mut sys_regs = BTreeMap::new();
833
for reg in reg_list {
834
if (reg as u32) & KVM_REG_ARM_COPROC_MASK == KVM_REG_ARM64_SYSREG {
835
let r = if reg as u16 == cntvct_el0 {
836
aarch64_sys_reg::CNTV_CVAL_EL0
837
} else if reg as u16 == cntv_cval_el0 {
838
aarch64_sys_reg::CNTVCT_EL0
839
} else {
840
AArch64SysRegId::from_encoded((reg & 0xFFFF) as u16)
841
};
842
sys_regs.insert(r, self.get_one_reg(VcpuRegAArch64::System(r))?);
843
// The register representations are tricky. Double check they round trip correctly.
844
assert_eq!(
845
Ok(reg),
846
self.kvm_reg_id(VcpuRegAArch64::System(r)).map(u64::from),
847
);
848
}
849
}
850
851
// The list of system registers below do not follow the convention of system registers
852
// for bits 31-16.
853
// System registers bits 31-16 == 0x0013, but not for those registers. Add them
854
// explicitly
855
let extra_sys_regs = [
856
aarch64_sys_reg::ELR_EL1,
857
aarch64_sys_reg::FPCR,
858
aarch64_sys_reg::FPSR,
859
aarch64_sys_reg::SP_EL1,
860
aarch64_sys_reg::SPSR_EL1,
861
aarch64_sys_reg::SPSR_abt,
862
aarch64_sys_reg::SPSR_und,
863
aarch64_sys_reg::SPSR_irq,
864
aarch64_sys_reg::SPSR_fiq,
865
];
866
for reg in extra_sys_regs {
867
sys_regs.insert(reg, self.get_one_reg(VcpuRegAArch64::System(reg))?);
868
}
869
Ok(sys_regs)
870
}
871
872
fn get_cache_info(&self) -> Result<BTreeMap<u8, u64>> {
873
const KVM_REG_CCSIDR: u64 = KVM_REG_ARM64 | KVM_REG_SIZE_U32 | (KVM_REG_ARM_DEMUX as u64);
874
const CCSIDR_INDEX_MASK: u64 = 0xFF;
875
let reg_list = self.get_reg_list()?;
876
let mut cache_info = BTreeMap::new();
877
for reg in reg_list {
878
if (reg & !CCSIDR_INDEX_MASK) == KVM_REG_CCSIDR {
879
let idx = reg as u8;
880
cache_info.insert(
881
idx,
882
self.get_one_kvm_reg_u32(KvmVcpuRegister::Ccsidr(idx))?
883
.into(),
884
);
885
}
886
}
887
Ok(cache_info)
888
}
889
890
fn set_cache_info(&self, cache_info: BTreeMap<u8, u64>) -> Result<()> {
891
for (idx, val) in cache_info {
892
self.set_one_kvm_reg_u32(
893
KvmVcpuRegister::Ccsidr(idx),
894
val.try_into()
895
.expect("trying to set a u32 register with a u64 value"),
896
)?;
897
}
898
Ok(())
899
}
900
901
fn hypervisor_specific_snapshot(&self) -> anyhow::Result<AnySnapshot> {
902
let reg_list = self.get_reg_list()?;
903
let mut firmware_regs = BTreeMap::new();
904
for reg in reg_list {
905
if (reg as u32) & KVM_REG_ARM_COPROC_MASK == KVM_REG_ARM_FW {
906
firmware_regs.insert(
907
reg as u16,
908
self.get_one_kvm_reg_u64(KvmVcpuRegister::Firmware(reg as u16))?,
909
);
910
}
911
}
912
913
AnySnapshot::to_any(KvmSnapshot { firmware_regs })
914
.context("Failed to serialize KVM specific data")
915
}
916
917
fn hypervisor_specific_restore(&self, data: AnySnapshot) -> anyhow::Result<()> {
918
let deser: KvmSnapshot =
919
AnySnapshot::from_any(data).context("Failed to deserialize KVM specific data")?;
920
// TODO: need to set firmware registers before "create_fdt" is called, earlier in the
921
// stack.
922
for (id, val) in &deser.firmware_regs {
923
self.set_one_kvm_reg_u64(KvmVcpuRegister::Firmware(*id), *val)?;
924
}
925
Ok(())
926
}
927
928
#[allow(clippy::unusual_byte_groupings)]
929
fn set_guest_debug(&self, addrs: &[GuestAddress], enable_singlestep: bool) -> Result<()> {
930
let mut dbg = kvm_guest_debug {
931
control: KVM_GUESTDBG_ENABLE,
932
..Default::default()
933
};
934
935
if enable_singlestep {
936
dbg.control |= KVM_GUESTDBG_SINGLESTEP;
937
}
938
if !addrs.is_empty() {
939
dbg.control |= KVM_GUESTDBG_USE_HW;
940
}
941
942
for (i, guest_addr) in addrs.iter().enumerate() {
943
// From the ARMv8 Architecture Reference Manual (DDI0487H.a) D31.3.{2,3}:
944
// When DBGBCR<n>_EL1.BT == 0b000x:
945
// DBGBVR<n>_EL1, Bits [1:0]: Reserved, RES0
946
if guest_addr.0 & 0b11 != 0 {
947
return Err(Error::new(EINVAL));
948
}
949
let sign_ext = 15;
950
// DBGBVR<n>_EL1.RESS[14:0], bits [63:49]: Reserved, Sign extended
951
dbg.arch.dbg_bvr[i] = (((guest_addr.0 << sign_ext) as i64) >> sign_ext) as u64;
952
// DBGBCR<n>_EL1.BT, bits [23:20]: Breakpoint Type
953
// 0b0000: Unlinked instruction address match.
954
// DBGBVR<n>_EL1 is the address of an instruction.
955
// DBGBCR<n>_EL1.BAS, bits [8:5]: Byte address select
956
// 0b1111: Use for A64 and A32 instructions
957
// DBGBCR<n>_EL1.PMC, bits [2:1]: Privilege mode control
958
// 0b11: EL1 & EL0
959
// DBGBCR<n>_EL1.E, bit [0]: Enable breakpoint
960
// 0b1: Enabled
961
dbg.arch.dbg_bcr[i] = 0b1111_11_1;
962
}
963
964
// SAFETY:
965
// Safe because the kernel won't read past the end of the kvm_guest_debug struct.
966
let ret = unsafe { ioctl_with_ref(self, KVM_SET_GUEST_DEBUG, &dbg) };
967
if ret == 0 {
968
Ok(())
969
} else {
970
errno_result()
971
}
972
}
973
}
974
975
#[derive(Debug, Serialize, Deserialize)]
976
struct KvmSnapshot {
977
firmware_regs: BTreeMap<u16, u64>,
978
}
979
980
// This function translates an IrqSrouceChip to the kvm u32 equivalent. It has a different
981
// implementation between x86_64 and aarch64 because the irqchip KVM constants are not defined on
982
// all architectures.
983
pub(super) fn chip_to_kvm_chip(chip: IrqSourceChip) -> u32 {
984
match chip {
985
// ARM does not have a constant for this, but the default routing
986
// setup seems to set this to 0
987
IrqSourceChip::Gic => 0,
988
_ => {
989
error!("Invalid IrqChipSource for ARM {:?}", chip);
990
0
991
}
992
}
993
}
994
995
#[cfg(test)]
996
mod tests {
997
use super::*;
998
999
#[test]
1000
fn system_timer_register_mixup() {
1001
// Per https://docs.kernel.org/virt/kvm/api.html ARM64 system register encoding docs,
1002
// KVM_REG_ARM_TIMER_CVAL and KVM_REG_ARM_TIMER_CNT were accidentally defined backwards.
1003
// Ensure the AArch64SysRegId to KvmVcpuRegister encoding maps these to the expected
1004
// values.
1005
1006
const KVM_REG_ARM_TIMER_CVAL: u64 = 0x6030_0000_0013_DF02;
1007
let cntv_cval_el0_kvm = KvmVcpuRegister::System(aarch64_sys_reg::CNTV_CVAL_EL0);
1008
assert_eq!(u64::from(cntv_cval_el0_kvm), KVM_REG_ARM_TIMER_CVAL);
1009
1010
const KVM_REG_ARM_TIMER_CNT: u64 = 0x6030_0000_0013_DF1A;
1011
let cntvct_el0_kvm = KvmVcpuRegister::System(aarch64_sys_reg::CNTVCT_EL0);
1012
assert_eq!(u64::from(cntvct_el0_kvm), KVM_REG_ARM_TIMER_CNT);
1013
}
1014
}
1015
1016