1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef __KVM_X86_VMX_TDX_H 3 #define __KVM_X86_VMX_TDX_H 4 5 #include "tdx_arch.h" 6 #include "tdx_errno.h" 7 8 #ifdef CONFIG_KVM_INTEL_TDX 9 #include "common.h" 10 11 int tdx_hardware_setup(void); 12 void tdx_hardware_unsetup(void); 13 14 extern bool enable_tdx; 15 16 /* TDX module hardware states. These follow the TDX module OP_STATEs. */ 17 enum kvm_tdx_state { 18 TD_STATE_UNINITIALIZED = 0, 19 TD_STATE_INITIALIZED, 20 TD_STATE_RUNNABLE, 21 }; 22 23 struct kvm_tdx { 24 struct kvm kvm; 25 26 struct misc_cg *misc_cg; 27 int hkid; 28 enum kvm_tdx_state state; 29 30 u64 attributes; 31 u64 xfam; 32 33 u64 tsc_offset; 34 u64 tsc_multiplier; 35 36 struct tdx_td td; 37 38 /* 39 * Scratch pointer used to pass the source page to tdx_mem_page_add(). 40 * Protected by slots_lock, and non-NULL only when mapping a private 41 * pfn via tdx_gmem_post_populate(). 42 */ 43 struct page *page_add_src; 44 45 /* 46 * Prevent vCPUs from TD entry to ensure SEPT zap related SEAMCALLs do 47 * not contend with tdh_vp_enter() and TDCALLs. 48 * Set/unset is protected with kvm->mmu_lock. 49 */ 50 bool wait_for_sept_zap; 51 }; 52 53 /* TDX module vCPU states */ 54 enum vcpu_tdx_state { 55 VCPU_TD_STATE_UNINITIALIZED = 0, 56 VCPU_TD_STATE_INITIALIZED, 57 }; 58 59 struct vcpu_tdx { 60 struct kvm_vcpu vcpu; 61 struct vcpu_vt vt; 62 u64 ext_exit_qualification; 63 gpa_t exit_gpa; 64 struct tdx_module_args vp_enter_args; 65 66 struct tdx_vp vp; 67 68 struct list_head cpu_list; 69 70 u64 vp_enter_ret; 71 72 enum vcpu_tdx_state state; 73 74 u64 map_gpa_next; 75 u64 map_gpa_end; 76 }; 77 78 void tdh_vp_rd_failed(struct vcpu_tdx *tdx, char *uclass, u32 field, u64 err); 79 void tdh_vp_wr_failed(struct vcpu_tdx *tdx, char *uclass, char *op, u32 field, 80 u64 val, u64 err); 81 82 static __always_inline u64 td_tdcs_exec_read64(struct kvm_tdx *kvm_tdx, u32 field) 83 { 84 u64 err, data; 85 86 err = tdh_mng_rd(&kvm_tdx->td, TDCS_EXEC(field), &data); 87 if (unlikely(err)) { 88 pr_err("TDH_MNG_RD[EXEC.0x%x] failed: 0x%llx\n", field, err); 89 return 0; 90 } 91 return data; 92 } 93 94 static __always_inline void tdvps_vmcs_check(u32 field, u8 bits) 95 { 96 #define VMCS_ENC_ACCESS_TYPE_MASK 0x1UL 97 #define VMCS_ENC_ACCESS_TYPE_FULL 0x0UL 98 #define VMCS_ENC_ACCESS_TYPE_HIGH 0x1UL 99 #define VMCS_ENC_ACCESS_TYPE(field) ((field) & VMCS_ENC_ACCESS_TYPE_MASK) 100 101 /* TDX is 64bit only. HIGH field isn't supported. */ 102 BUILD_BUG_ON_MSG(__builtin_constant_p(field) && 103 VMCS_ENC_ACCESS_TYPE(field) == VMCS_ENC_ACCESS_TYPE_HIGH, 104 "Read/Write to TD VMCS *_HIGH fields not supported"); 105 106 BUILD_BUG_ON(bits != 16 && bits != 32 && bits != 64); 107 108 #define VMCS_ENC_WIDTH_MASK GENMASK(14, 13) 109 #define VMCS_ENC_WIDTH_16BIT (0UL << 13) 110 #define VMCS_ENC_WIDTH_64BIT (1UL << 13) 111 #define VMCS_ENC_WIDTH_32BIT (2UL << 13) 112 #define VMCS_ENC_WIDTH_NATURAL (3UL << 13) 113 #define VMCS_ENC_WIDTH(field) ((field) & VMCS_ENC_WIDTH_MASK) 114 115 /* TDX is 64bit only. i.e. natural width = 64bit. */ 116 BUILD_BUG_ON_MSG(bits != 64 && __builtin_constant_p(field) && 117 (VMCS_ENC_WIDTH(field) == VMCS_ENC_WIDTH_64BIT || 118 VMCS_ENC_WIDTH(field) == VMCS_ENC_WIDTH_NATURAL), 119 "Invalid TD VMCS access for 64-bit field"); 120 BUILD_BUG_ON_MSG(bits != 32 && __builtin_constant_p(field) && 121 VMCS_ENC_WIDTH(field) == VMCS_ENC_WIDTH_32BIT, 122 "Invalid TD VMCS access for 32-bit field"); 123 BUILD_BUG_ON_MSG(bits != 16 && __builtin_constant_p(field) && 124 VMCS_ENC_WIDTH(field) == VMCS_ENC_WIDTH_16BIT, 125 "Invalid TD VMCS access for 16-bit field"); 126 } 127 128 static __always_inline void tdvps_management_check(u64 field, u8 bits) {} 129 static __always_inline void tdvps_state_non_arch_check(u64 field, u8 bits) {} 130 131 #define TDX_BUILD_TDVPS_ACCESSORS(bits, uclass, lclass) \ 132 static __always_inline u##bits td_##lclass##_read##bits(struct vcpu_tdx *tdx, \ 133 u32 field) \ 134 { \ 135 u64 err, data; \ 136 \ 137 tdvps_##lclass##_check(field, bits); \ 138 err = tdh_vp_rd(&tdx->vp, TDVPS_##uclass(field), &data); \ 139 if (unlikely(err)) { \ 140 tdh_vp_rd_failed(tdx, #uclass, field, err); \ 141 return 0; \ 142 } \ 143 return (u##bits)data; \ 144 } \ 145 static __always_inline void td_##lclass##_write##bits(struct vcpu_tdx *tdx, \ 146 u32 field, u##bits val) \ 147 { \ 148 u64 err; \ 149 \ 150 tdvps_##lclass##_check(field, bits); \ 151 err = tdh_vp_wr(&tdx->vp, TDVPS_##uclass(field), val, \ 152 GENMASK_ULL(bits - 1, 0)); \ 153 if (unlikely(err)) \ 154 tdh_vp_wr_failed(tdx, #uclass, " = ", field, (u64)val, err); \ 155 } \ 156 static __always_inline void td_##lclass##_setbit##bits(struct vcpu_tdx *tdx, \ 157 u32 field, u64 bit) \ 158 { \ 159 u64 err; \ 160 \ 161 tdvps_##lclass##_check(field, bits); \ 162 err = tdh_vp_wr(&tdx->vp, TDVPS_##uclass(field), bit, bit); \ 163 if (unlikely(err)) \ 164 tdh_vp_wr_failed(tdx, #uclass, " |= ", field, bit, err); \ 165 } \ 166 static __always_inline void td_##lclass##_clearbit##bits(struct vcpu_tdx *tdx, \ 167 u32 field, u64 bit) \ 168 { \ 169 u64 err; \ 170 \ 171 tdvps_##lclass##_check(field, bits); \ 172 err = tdh_vp_wr(&tdx->vp, TDVPS_##uclass(field), 0, bit); \ 173 if (unlikely(err)) \ 174 tdh_vp_wr_failed(tdx, #uclass, " &= ~", field, bit, err);\ 175 } 176 177 178 bool tdx_interrupt_allowed(struct kvm_vcpu *vcpu); 179 int tdx_complete_emulated_msr(struct kvm_vcpu *vcpu, int err); 180 181 TDX_BUILD_TDVPS_ACCESSORS(16, VMCS, vmcs); 182 TDX_BUILD_TDVPS_ACCESSORS(32, VMCS, vmcs); 183 TDX_BUILD_TDVPS_ACCESSORS(64, VMCS, vmcs); 184 185 TDX_BUILD_TDVPS_ACCESSORS(8, MANAGEMENT, management); 186 TDX_BUILD_TDVPS_ACCESSORS(64, STATE_NON_ARCH, state_non_arch); 187 188 #else 189 #define enable_tdx 0 190 191 struct kvm_tdx { 192 struct kvm kvm; 193 }; 194 195 struct vcpu_tdx { 196 struct kvm_vcpu vcpu; 197 }; 198 199 static inline bool tdx_interrupt_allowed(struct kvm_vcpu *vcpu) { return false; } 200 static inline int tdx_complete_emulated_msr(struct kvm_vcpu *vcpu, int err) { return 0; } 201 202 #endif 203 204 #endif 205