1 // Copyright © 2019 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
4 //
5 // Copyright © 2020, Microsoft Corporation
6 //
7 // Copyright 2018-2019 CrowdStrike, Inc.
8 //
9 //
10
11 pub mod gic;
12
13 use kvm_bindings::{
14 kvm_mp_state, kvm_one_reg, kvm_regs, KVM_REG_ARM_COPROC_MASK, KVM_REG_ARM_CORE,
15 KVM_REG_SIZE_MASK, KVM_REG_SIZE_U32, KVM_REG_SIZE_U64,
16 };
17 pub use kvm_ioctls::{Cap, Kvm};
18 use serde::{Deserialize, Serialize};
19
20 use crate::kvm::{KvmError, KvmResult};
21
22 // This macro gets the offset of a structure (i.e `str`) member (i.e `field`) without having
23 // an instance of that structure.
24 #[macro_export]
25 macro_rules! offset_of {
26 ($str:ty, $field:ident) => {{
27 let tmp: std::mem::MaybeUninit<$str> = std::mem::MaybeUninit::uninit();
28 let base = tmp.as_ptr();
29
30 // Avoid warnings when nesting `unsafe` blocks.
31 #[allow(unused_unsafe)]
32 // SAFETY: The pointer is valid and aligned, just not initialised. Using `addr_of` ensures
33 // that we don't actually read from `base` (which would be UB) nor create an intermediate
34 // reference.
35 let member = unsafe { core::ptr::addr_of!((*base).$field) } as *const u8;
36
37 // Avoid warnings when nesting `unsafe` blocks.
38 #[allow(unused_unsafe)]
39 // SAFETY: The two pointers are within the same allocated object `tmp`. All requirements
40 // from offset_from are upheld.
41 unsafe {
42 member.offset_from(base as *const u8) as usize
43 }
44 }};
45 }
46
47 // Following are macros that help with getting the ID of a aarch64 core register.
48 // The core register are represented by the user_pt_regs structure. Look for it in
49 // arch/arm64/include/uapi/asm/ptrace.h.
50
51 // Get the ID of a core register
52 #[macro_export]
53 macro_rules! arm64_core_reg_id {
54 ($size: tt, $offset: tt) => {
55 // The core registers of an arm64 machine are represented
56 // in kernel by the `kvm_regs` structure. This structure is a
57 // mix of 32, 64 and 128 bit fields:
58 // struct kvm_regs {
59 // struct user_pt_regs regs;
60 //
61 // __u64 sp_el1;
62 // __u64 elr_el1;
63 //
64 // __u64 spsr[KVM_NR_SPSR];
65 //
66 // struct user_fpsimd_state fp_regs;
67 // };
68 // struct user_pt_regs {
69 // __u64 regs[31];
70 // __u64 sp;
71 // __u64 pc;
72 // __u64 pstate;
73 // };
74 // The id of a core register can be obtained like this:
75 // offset = id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE). Thus,
76 // id = KVM_REG_ARM64 | KVM_REG_SIZE_U64/KVM_REG_SIZE_U32/KVM_REG_SIZE_U128 | KVM_REG_ARM_CORE | offset
77 KVM_REG_ARM64 as u64
78 | u64::from(KVM_REG_ARM_CORE)
79 | $size
80 | (($offset / mem::size_of::<u32>()) as u64)
81 };
82 }
83
84 /// Specifies whether a particular register is a system register or not.
85 ///
86 /// The kernel splits the registers on aarch64 in core registers and system registers.
87 /// So, below we get the system registers by checking that they are not core registers.
88 ///
89 /// # Arguments
90 ///
91 /// * `regid` - The index of the register we are checking.
is_system_register(regid: u64) -> bool92 pub fn is_system_register(regid: u64) -> bool {
93 if (regid & KVM_REG_ARM_COPROC_MASK as u64) == KVM_REG_ARM_CORE as u64 {
94 return false;
95 }
96
97 let size = regid & KVM_REG_SIZE_MASK;
98
99 assert!(
100 !(size != KVM_REG_SIZE_U32 && size != KVM_REG_SIZE_U64),
101 "Unexpected register size for system register {size}"
102 );
103
104 true
105 }
106
check_required_kvm_extensions(kvm: &Kvm) -> KvmResult<()>107 pub fn check_required_kvm_extensions(kvm: &Kvm) -> KvmResult<()> {
108 macro_rules! check_extension {
109 ($cap:expr) => {
110 if !kvm.check_extension($cap) {
111 return Err(KvmError::CapabilityMissing($cap));
112 }
113 };
114 }
115
116 // SetGuestDebug is required but some kernels have it implemented without the capability flag.
117 check_extension!(Cap::ImmediateExit);
118 check_extension!(Cap::Ioeventfd);
119 check_extension!(Cap::Irqchip);
120 check_extension!(Cap::Irqfd);
121 check_extension!(Cap::IrqRouting);
122 check_extension!(Cap::MpState);
123 check_extension!(Cap::OneReg);
124 check_extension!(Cap::UserMemory);
125 Ok(())
126 }
127
128 #[derive(Clone, Default, Serialize, Deserialize)]
129 pub struct VcpuKvmState {
130 pub mp_state: kvm_mp_state,
131 pub core_regs: kvm_regs,
132 pub sys_regs: Vec<kvm_one_reg>,
133 }
134