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