172e39a34SMuminul Islam // Copyright © 2019 Intel Corporation
272e39a34SMuminul Islam //
372ae1577SMuminul Islam // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
472e39a34SMuminul Islam //
572e39a34SMuminul Islam // Copyright © 2020, Microsoft Corporation
672e39a34SMuminul Islam //
772ae1577SMuminul Islam // Copyright 2018-2019 CrowdStrike, Inc.
872ae1577SMuminul Islam //
972ae1577SMuminul Islam //
1072e39a34SMuminul Islam
11c2862b69SMichael Zhao pub mod gic;
12c2862b69SMichael Zhao
13e3d45be6SHenry Wang use kvm_bindings::{
147199119bSMichael Zhao kvm_mp_state, kvm_one_reg, kvm_regs, KVM_REG_ARM_COPROC_MASK, KVM_REG_ARM_CORE,
157199119bSMichael Zhao KVM_REG_SIZE_MASK, KVM_REG_SIZE_U32, KVM_REG_SIZE_U64,
16ffafeda4SHenry Wang };
17*61e57e1cSRuoqing He pub use kvm_ioctls::{Cap, Kvm};
183a0429c9SMaksym Pavlenko use serde::{Deserialize, Serialize};
1972e39a34SMuminul Islam
2088a9f799SRob Bradford use crate::kvm::{KvmError, KvmResult};
2188a9f799SRob Bradford
22e3d45be6SHenry Wang // This macro gets the offset of a structure (i.e `str`) member (i.e `field`) without having
23e3d45be6SHenry Wang // an instance of that structure.
24e3d45be6SHenry Wang #[macro_export]
25cd83d258SWei Liu macro_rules! offset_of {
263a232ef3SWei Liu ($str:ty, $field:ident) => {{
2728f383baSRob Bradford let tmp: std::mem::MaybeUninit<$str> = std::mem::MaybeUninit::uninit();
2857cc8bc6SWei Liu let base = tmp.as_ptr();
29e3d45be6SHenry Wang
3057cc8bc6SWei Liu // Avoid warnings when nesting `unsafe` blocks.
3157cc8bc6SWei Liu #[allow(unused_unsafe)]
3257cc8bc6SWei Liu // SAFETY: The pointer is valid and aligned, just not initialised. Using `addr_of` ensures
3357cc8bc6SWei Liu // that we don't actually read from `base` (which would be UB) nor create an intermediate
3457cc8bc6SWei Liu // reference.
353a232ef3SWei Liu let member = unsafe { core::ptr::addr_of!((*base).$field) } as *const u8;
3657cc8bc6SWei Liu
3757cc8bc6SWei Liu // Avoid warnings when nesting `unsafe` blocks.
3857cc8bc6SWei Liu #[allow(unused_unsafe)]
3957cc8bc6SWei Liu // SAFETY: The two pointers are within the same allocated object `tmp`. All requirements
4057cc8bc6SWei Liu // from offset_from are upheld.
413a232ef3SWei Liu unsafe {
423a232ef3SWei Liu member.offset_from(base as *const u8) as usize
433a232ef3SWei Liu }
443a232ef3SWei Liu }};
4528f383baSRob Bradford }
4657cc8bc6SWei Liu
476221b6f8SWei Liu // Following are macros that help with getting the ID of a aarch64 core register.
486221b6f8SWei Liu // The core register are represented by the user_pt_regs structure. Look for it in
496221b6f8SWei Liu // arch/arm64/include/uapi/asm/ptrace.h.
506221b6f8SWei Liu
51e3d45be6SHenry Wang // Get the ID of a core register
52e3d45be6SHenry Wang #[macro_export]
53e3d45be6SHenry Wang macro_rules! arm64_core_reg_id {
54e3d45be6SHenry Wang ($size: tt, $offset: tt) => {
55e3d45be6SHenry Wang // The core registers of an arm64 machine are represented
56e3d45be6SHenry Wang // in kernel by the `kvm_regs` structure. This structure is a
57e3d45be6SHenry Wang // mix of 32, 64 and 128 bit fields:
58e3d45be6SHenry Wang // struct kvm_regs {
59e3d45be6SHenry Wang // struct user_pt_regs regs;
60e3d45be6SHenry Wang //
61e3d45be6SHenry Wang // __u64 sp_el1;
62e3d45be6SHenry Wang // __u64 elr_el1;
63e3d45be6SHenry Wang //
64e3d45be6SHenry Wang // __u64 spsr[KVM_NR_SPSR];
65e3d45be6SHenry Wang //
66e3d45be6SHenry Wang // struct user_fpsimd_state fp_regs;
67e3d45be6SHenry Wang // };
68e3d45be6SHenry Wang // struct user_pt_regs {
69e3d45be6SHenry Wang // __u64 regs[31];
70e3d45be6SHenry Wang // __u64 sp;
71e3d45be6SHenry Wang // __u64 pc;
72e3d45be6SHenry Wang // __u64 pstate;
73e3d45be6SHenry Wang // };
74e3d45be6SHenry Wang // The id of a core register can be obtained like this:
75e3d45be6SHenry Wang // offset = id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE). Thus,
76e3d45be6SHenry Wang // id = KVM_REG_ARM64 | KVM_REG_SIZE_U64/KVM_REG_SIZE_U32/KVM_REG_SIZE_U128 | KVM_REG_ARM_CORE | offset
77e3d45be6SHenry Wang KVM_REG_ARM64 as u64
78e3d45be6SHenry Wang | u64::from(KVM_REG_ARM_CORE)
79e3d45be6SHenry Wang | $size
80e3d45be6SHenry Wang | (($offset / mem::size_of::<u32>()) as u64)
81e3d45be6SHenry Wang };
82e3d45be6SHenry Wang }
83e3d45be6SHenry Wang
84e3d45be6SHenry Wang /// Specifies whether a particular register is a system register or not.
8560c8a72eSBo Chen ///
86e3d45be6SHenry Wang /// The kernel splits the registers on aarch64 in core registers and system registers.
87e3d45be6SHenry Wang /// So, below we get the system registers by checking that they are not core registers.
88e3d45be6SHenry Wang ///
89e3d45be6SHenry Wang /// # Arguments
90e3d45be6SHenry Wang ///
91e3d45be6SHenry Wang /// * `regid` - The index of the register we are checking.
is_system_register(regid: u64) -> bool92e3d45be6SHenry Wang pub fn is_system_register(regid: u64) -> bool {
93e3d45be6SHenry Wang if (regid & KVM_REG_ARM_COPROC_MASK as u64) == KVM_REG_ARM_CORE as u64 {
94e3d45be6SHenry Wang return false;
95e3d45be6SHenry Wang }
96e3d45be6SHenry Wang
97e3d45be6SHenry Wang let size = regid & KVM_REG_SIZE_MASK;
9870f9fea1SRob Bradford
9970f9fea1SRob Bradford assert!(
10070f9fea1SRob Bradford !(size != KVM_REG_SIZE_U32 && size != KVM_REG_SIZE_U64),
1015e527294SRob Bradford "Unexpected register size for system register {size}"
10270f9fea1SRob Bradford );
10370f9fea1SRob Bradford
104e3d45be6SHenry Wang true
105e3d45be6SHenry Wang }
106e3d45be6SHenry Wang
check_required_kvm_extensions(kvm: &Kvm) -> KvmResult<()>10772e39a34SMuminul Islam pub fn check_required_kvm_extensions(kvm: &Kvm) -> KvmResult<()> {
108c07671edSWei Liu macro_rules! check_extension {
109c07671edSWei Liu ($cap:expr) => {
110c07671edSWei Liu if !kvm.check_extension($cap) {
111c07671edSWei Liu return Err(KvmError::CapabilityMissing($cap));
1129ad14e6bSWei Liu }
113c07671edSWei Liu };
114c07671edSWei Liu }
115c07671edSWei Liu
116241d1d5cSWei Liu // SetGuestDebug is required but some kernels have it implemented without the capability flag.
117241d1d5cSWei Liu check_extension!(Cap::ImmediateExit);
118241d1d5cSWei Liu check_extension!(Cap::Ioeventfd);
119241d1d5cSWei Liu check_extension!(Cap::Irqchip);
120241d1d5cSWei Liu check_extension!(Cap::Irqfd);
121241d1d5cSWei Liu check_extension!(Cap::IrqRouting);
122241d1d5cSWei Liu check_extension!(Cap::MpState);
123c07671edSWei Liu check_extension!(Cap::OneReg);
124241d1d5cSWei Liu check_extension!(Cap::UserMemory);
12572e39a34SMuminul Islam Ok(())
12672e39a34SMuminul Islam }
127c48d0c1aSMuminul Islam
128ffafeda4SHenry Wang #[derive(Clone, Default, Serialize, Deserialize)]
129ffafeda4SHenry Wang pub struct VcpuKvmState {
130ffafeda4SHenry Wang pub mp_state: kvm_mp_state,
131ffafeda4SHenry Wang pub core_regs: kvm_regs,
132ffafeda4SHenry Wang pub sys_regs: Vec<kvm_one_reg>,
133ffafeda4SHenry Wang }
134