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 /// 12 /// Export generically-named wrappers of kvm-bindings for Unix-based platforms 13 /// 14 use crate::kvm::{KvmError, KvmResult}; 15 use kvm_bindings::{ 16 kvm_mp_state, kvm_one_reg, kvm_regs, KVM_REG_ARM64, KVM_REG_ARM64_SYSREG, 17 KVM_REG_ARM64_SYSREG_CRM_MASK, KVM_REG_ARM64_SYSREG_CRM_SHIFT, KVM_REG_ARM64_SYSREG_CRN_MASK, 18 KVM_REG_ARM64_SYSREG_CRN_SHIFT, KVM_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP0_SHIFT, 19 KVM_REG_ARM64_SYSREG_OP1_MASK, KVM_REG_ARM64_SYSREG_OP1_SHIFT, KVM_REG_ARM64_SYSREG_OP2_MASK, 20 KVM_REG_ARM64_SYSREG_OP2_SHIFT, KVM_REG_ARM_COPROC_MASK, KVM_REG_ARM_CORE, KVM_REG_SIZE_MASK, 21 KVM_REG_SIZE_U32, KVM_REG_SIZE_U64, 22 }; 23 pub use kvm_bindings::{ 24 kvm_one_reg as Register, kvm_regs as StandardRegisters, kvm_vcpu_init as VcpuInit, RegList, 25 }; 26 use serde_derive::{Deserialize, Serialize}; 27 pub use {kvm_ioctls::Cap, kvm_ioctls::Kvm}; 28 29 // This macro gets the offset of a structure (i.e `str`) member (i.e `field`) without having 30 // an instance of that structure. 31 #[macro_export] 32 macro_rules! offset__of { 33 ($str:ty, $($field:ident)+) => ({ 34 let tmp: std::mem::MaybeUninit<$str> = std::mem::MaybeUninit::uninit(); 35 let base = tmp.as_ptr(); 36 37 // Avoid warnings when nesting `unsafe` blocks. 38 #[allow(unused_unsafe)] 39 // SAFETY: The pointer is valid and aligned, just not initialised. Using `addr_of` ensures 40 // that we don't actually read from `base` (which would be UB) nor create an intermediate 41 // reference. 42 let member = unsafe { core::ptr::addr_of!((*base).$($field)*) } as *const u8; 43 44 // Avoid warnings when nesting `unsafe` blocks. 45 #[allow(unused_unsafe)] 46 // SAFETY: The two pointers are within the same allocated object `tmp`. All requirements 47 // from offset_from are upheld. 48 unsafe { member.offset_from(base as *const u8) as usize } 49 }); 50 } 51 52 // Following are macros that help with getting the ID of a aarch64 core register. 53 // The core register are represented by the user_pt_regs structure. Look for it in 54 // arch/arm64/include/uapi/asm/ptrace.h. 55 56 // Get the ID of a core register 57 #[macro_export] 58 macro_rules! arm64_core_reg_id { 59 ($size: tt, $offset: tt) => { 60 // The core registers of an arm64 machine are represented 61 // in kernel by the `kvm_regs` structure. This structure is a 62 // mix of 32, 64 and 128 bit fields: 63 // struct kvm_regs { 64 // struct user_pt_regs regs; 65 // 66 // __u64 sp_el1; 67 // __u64 elr_el1; 68 // 69 // __u64 spsr[KVM_NR_SPSR]; 70 // 71 // struct user_fpsimd_state fp_regs; 72 // }; 73 // struct user_pt_regs { 74 // __u64 regs[31]; 75 // __u64 sp; 76 // __u64 pc; 77 // __u64 pstate; 78 // }; 79 // The id of a core register can be obtained like this: 80 // offset = id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE). Thus, 81 // id = KVM_REG_ARM64 | KVM_REG_SIZE_U64/KVM_REG_SIZE_U32/KVM_REG_SIZE_U128 | KVM_REG_ARM_CORE | offset 82 KVM_REG_ARM64 as u64 83 | u64::from(KVM_REG_ARM_CORE) 84 | $size 85 | (($offset / mem::size_of::<u32>()) as u64) 86 }; 87 } 88 89 // This macro computes the ID of a specific ARM64 system register similar to how 90 // the kernel C macro does. 91 // https://elixir.bootlin.com/linux/v4.20.17/source/arch/arm64/include/uapi/asm/kvm.h#L203 92 #[macro_export] 93 macro_rules! arm64_sys_reg { 94 ($name: tt, $op0: tt, $op1: tt, $crn: tt, $crm: tt, $op2: tt) => { 95 pub const $name: u64 = KVM_REG_ARM64 as u64 96 | KVM_REG_SIZE_U64 as u64 97 | KVM_REG_ARM64_SYSREG as u64 98 | ((($op0 as u64) << KVM_REG_ARM64_SYSREG_OP0_SHIFT) 99 & KVM_REG_ARM64_SYSREG_OP0_MASK as u64) 100 | ((($op1 as u64) << KVM_REG_ARM64_SYSREG_OP1_SHIFT) 101 & KVM_REG_ARM64_SYSREG_OP1_MASK as u64) 102 | ((($crn as u64) << KVM_REG_ARM64_SYSREG_CRN_SHIFT) 103 & KVM_REG_ARM64_SYSREG_CRN_MASK as u64) 104 | ((($crm as u64) << KVM_REG_ARM64_SYSREG_CRM_SHIFT) 105 & KVM_REG_ARM64_SYSREG_CRM_MASK as u64) 106 | ((($op2 as u64) << KVM_REG_ARM64_SYSREG_OP2_SHIFT) 107 & KVM_REG_ARM64_SYSREG_OP2_MASK as u64); 108 }; 109 } 110 111 // Constant imported from the Linux kernel: 112 // https://elixir.bootlin.com/linux/v4.20.17/source/arch/arm64/include/asm/sysreg.h#L135 113 arm64_sys_reg!(MPIDR_EL1, 3, 0, 0, 0, 5); 114 115 /// Specifies whether a particular register is a system register or not. 116 /// The kernel splits the registers on aarch64 in core registers and system registers. 117 /// So, below we get the system registers by checking that they are not core registers. 118 /// 119 /// # Arguments 120 /// 121 /// * `regid` - The index of the register we are checking. 122 pub fn is_system_register(regid: u64) -> bool { 123 if (regid & KVM_REG_ARM_COPROC_MASK as u64) == KVM_REG_ARM_CORE as u64 { 124 return false; 125 } 126 127 let size = regid & KVM_REG_SIZE_MASK; 128 129 assert!( 130 !(size != KVM_REG_SIZE_U32 && size != KVM_REG_SIZE_U64), 131 "Unexpected register size for system register {}", 132 size 133 ); 134 135 true 136 } 137 138 pub fn check_required_kvm_extensions(kvm: &Kvm) -> KvmResult<()> { 139 if !kvm.check_extension(Cap::SignalMsi) { 140 return Err(KvmError::CapabilityMissing(Cap::SignalMsi)); 141 } 142 if !kvm.check_extension(Cap::OneReg) { 143 return Err(KvmError::CapabilityMissing(Cap::OneReg)); 144 } 145 Ok(()) 146 } 147 148 #[derive(Clone, Default, Serialize, Deserialize)] 149 pub struct VcpuKvmState { 150 pub mp_state: kvm_mp_state, 151 pub core_regs: kvm_regs, 152 pub sys_regs: Vec<kvm_one_reg>, 153 // We will be using the mpidr for passing it to the VmState. 154 // The VmState will give this away for saving restoring the icc and redistributor 155 // registers. 156 pub mpidr: u64, 157 } 158