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