1*a3cbbb47SArd Biesheuvel // SPDX-License-Identifier: GPL-2.0 2*a3cbbb47SArd Biesheuvel /* 3*a3cbbb47SArd Biesheuvel * AMD Encrypted Register State Support 4*a3cbbb47SArd Biesheuvel * 5*a3cbbb47SArd Biesheuvel * Author: Joerg Roedel <jroedel@suse.de> 6*a3cbbb47SArd Biesheuvel * 7*a3cbbb47SArd Biesheuvel * This file is not compiled stand-alone. It contains code shared 8*a3cbbb47SArd Biesheuvel * between the pre-decompression boot code and the running Linux kernel 9*a3cbbb47SArd Biesheuvel * and is included directly into both code-bases. 10*a3cbbb47SArd Biesheuvel */ 11*a3cbbb47SArd Biesheuvel 12*a3cbbb47SArd Biesheuvel #include <asm/setup_data.h> 13*a3cbbb47SArd Biesheuvel 14*a3cbbb47SArd Biesheuvel #ifndef __BOOT_COMPRESSED 15*a3cbbb47SArd Biesheuvel #define error(v) pr_err(v) 16*a3cbbb47SArd Biesheuvel #define has_cpuflag(f) boot_cpu_has(f) 17*a3cbbb47SArd Biesheuvel #define sev_printk(fmt, ...) printk(fmt, ##__VA_ARGS__) 18*a3cbbb47SArd Biesheuvel #define sev_printk_rtl(fmt, ...) printk_ratelimited(fmt, ##__VA_ARGS__) 19*a3cbbb47SArd Biesheuvel #else 20*a3cbbb47SArd Biesheuvel #undef WARN 21*a3cbbb47SArd Biesheuvel #define WARN(condition, format...) (!!(condition)) 22*a3cbbb47SArd Biesheuvel #define sev_printk(fmt, ...) 23*a3cbbb47SArd Biesheuvel #define sev_printk_rtl(fmt, ...) 24*a3cbbb47SArd Biesheuvel #undef vc_forward_exception 25*a3cbbb47SArd Biesheuvel #define vc_forward_exception(c) panic("SNP: Hypervisor requested exception\n") 26*a3cbbb47SArd Biesheuvel #endif 27*a3cbbb47SArd Biesheuvel 28*a3cbbb47SArd Biesheuvel /* 29*a3cbbb47SArd Biesheuvel * SVSM related information: 30*a3cbbb47SArd Biesheuvel * During boot, the page tables are set up as identity mapped and later 31*a3cbbb47SArd Biesheuvel * changed to use kernel virtual addresses. Maintain separate virtual and 32*a3cbbb47SArd Biesheuvel * physical addresses for the CAA to allow SVSM functions to be used during 33*a3cbbb47SArd Biesheuvel * early boot, both with identity mapped virtual addresses and proper kernel 34*a3cbbb47SArd Biesheuvel * virtual addresses. 35*a3cbbb47SArd Biesheuvel */ 36*a3cbbb47SArd Biesheuvel struct svsm_ca *boot_svsm_caa __ro_after_init; 37*a3cbbb47SArd Biesheuvel u64 boot_svsm_caa_pa __ro_after_init; 38*a3cbbb47SArd Biesheuvel 39*a3cbbb47SArd Biesheuvel /* I/O parameters for CPUID-related helpers */ 40*a3cbbb47SArd Biesheuvel struct cpuid_leaf { 41*a3cbbb47SArd Biesheuvel u32 fn; 42*a3cbbb47SArd Biesheuvel u32 subfn; 43*a3cbbb47SArd Biesheuvel u32 eax; 44*a3cbbb47SArd Biesheuvel u32 ebx; 45*a3cbbb47SArd Biesheuvel u32 ecx; 46*a3cbbb47SArd Biesheuvel u32 edx; 47*a3cbbb47SArd Biesheuvel }; 48*a3cbbb47SArd Biesheuvel 49*a3cbbb47SArd Biesheuvel /* 50*a3cbbb47SArd Biesheuvel * Since feature negotiation related variables are set early in the boot 51*a3cbbb47SArd Biesheuvel * process they must reside in the .data section so as not to be zeroed 52*a3cbbb47SArd Biesheuvel * out when the .bss section is later cleared. 53*a3cbbb47SArd Biesheuvel * 54*a3cbbb47SArd Biesheuvel * GHCB protocol version negotiated with the hypervisor. 55*a3cbbb47SArd Biesheuvel */ 56*a3cbbb47SArd Biesheuvel static u16 ghcb_version __ro_after_init; 57*a3cbbb47SArd Biesheuvel 58*a3cbbb47SArd Biesheuvel /* Copy of the SNP firmware's CPUID page. */ 59*a3cbbb47SArd Biesheuvel static struct snp_cpuid_table cpuid_table_copy __ro_after_init; 60*a3cbbb47SArd Biesheuvel 61*a3cbbb47SArd Biesheuvel /* 62*a3cbbb47SArd Biesheuvel * These will be initialized based on CPUID table so that non-present 63*a3cbbb47SArd Biesheuvel * all-zero leaves (for sparse tables) can be differentiated from 64*a3cbbb47SArd Biesheuvel * invalid/out-of-range leaves. This is needed since all-zero leaves 65*a3cbbb47SArd Biesheuvel * still need to be post-processed. 66*a3cbbb47SArd Biesheuvel */ 67*a3cbbb47SArd Biesheuvel static u32 cpuid_std_range_max __ro_after_init; 68*a3cbbb47SArd Biesheuvel static u32 cpuid_hyp_range_max __ro_after_init; 69*a3cbbb47SArd Biesheuvel static u32 cpuid_ext_range_max __ro_after_init; 70*a3cbbb47SArd Biesheuvel 71*a3cbbb47SArd Biesheuvel bool __init sev_es_check_cpu_features(void) 72*a3cbbb47SArd Biesheuvel { 73*a3cbbb47SArd Biesheuvel if (!has_cpuflag(X86_FEATURE_RDRAND)) { 74*a3cbbb47SArd Biesheuvel error("RDRAND instruction not supported - no trusted source of randomness available\n"); 75*a3cbbb47SArd Biesheuvel return false; 76*a3cbbb47SArd Biesheuvel } 77*a3cbbb47SArd Biesheuvel 78*a3cbbb47SArd Biesheuvel return true; 79*a3cbbb47SArd Biesheuvel } 80*a3cbbb47SArd Biesheuvel 81*a3cbbb47SArd Biesheuvel void __head __noreturn 82*a3cbbb47SArd Biesheuvel sev_es_terminate(unsigned int set, unsigned int reason) 83*a3cbbb47SArd Biesheuvel { 84*a3cbbb47SArd Biesheuvel u64 val = GHCB_MSR_TERM_REQ; 85*a3cbbb47SArd Biesheuvel 86*a3cbbb47SArd Biesheuvel /* Tell the hypervisor what went wrong. */ 87*a3cbbb47SArd Biesheuvel val |= GHCB_SEV_TERM_REASON(set, reason); 88*a3cbbb47SArd Biesheuvel 89*a3cbbb47SArd Biesheuvel /* Request Guest Termination from Hypervisor */ 90*a3cbbb47SArd Biesheuvel sev_es_wr_ghcb_msr(val); 91*a3cbbb47SArd Biesheuvel VMGEXIT(); 92*a3cbbb47SArd Biesheuvel 93*a3cbbb47SArd Biesheuvel while (true) 94*a3cbbb47SArd Biesheuvel asm volatile("hlt\n" : : : "memory"); 95*a3cbbb47SArd Biesheuvel } 96*a3cbbb47SArd Biesheuvel 97*a3cbbb47SArd Biesheuvel /* 98*a3cbbb47SArd Biesheuvel * The hypervisor features are available from GHCB version 2 onward. 99*a3cbbb47SArd Biesheuvel */ 100*a3cbbb47SArd Biesheuvel u64 get_hv_features(void) 101*a3cbbb47SArd Biesheuvel { 102*a3cbbb47SArd Biesheuvel u64 val; 103*a3cbbb47SArd Biesheuvel 104*a3cbbb47SArd Biesheuvel if (ghcb_version < 2) 105*a3cbbb47SArd Biesheuvel return 0; 106*a3cbbb47SArd Biesheuvel 107*a3cbbb47SArd Biesheuvel sev_es_wr_ghcb_msr(GHCB_MSR_HV_FT_REQ); 108*a3cbbb47SArd Biesheuvel VMGEXIT(); 109*a3cbbb47SArd Biesheuvel 110*a3cbbb47SArd Biesheuvel val = sev_es_rd_ghcb_msr(); 111*a3cbbb47SArd Biesheuvel if (GHCB_RESP_CODE(val) != GHCB_MSR_HV_FT_RESP) 112*a3cbbb47SArd Biesheuvel return 0; 113*a3cbbb47SArd Biesheuvel 114*a3cbbb47SArd Biesheuvel return GHCB_MSR_HV_FT_RESP_VAL(val); 115*a3cbbb47SArd Biesheuvel } 116*a3cbbb47SArd Biesheuvel 117*a3cbbb47SArd Biesheuvel void snp_register_ghcb_early(unsigned long paddr) 118*a3cbbb47SArd Biesheuvel { 119*a3cbbb47SArd Biesheuvel unsigned long pfn = paddr >> PAGE_SHIFT; 120*a3cbbb47SArd Biesheuvel u64 val; 121*a3cbbb47SArd Biesheuvel 122*a3cbbb47SArd Biesheuvel sev_es_wr_ghcb_msr(GHCB_MSR_REG_GPA_REQ_VAL(pfn)); 123*a3cbbb47SArd Biesheuvel VMGEXIT(); 124*a3cbbb47SArd Biesheuvel 125*a3cbbb47SArd Biesheuvel val = sev_es_rd_ghcb_msr(); 126*a3cbbb47SArd Biesheuvel 127*a3cbbb47SArd Biesheuvel /* If the response GPA is not ours then abort the guest */ 128*a3cbbb47SArd Biesheuvel if ((GHCB_RESP_CODE(val) != GHCB_MSR_REG_GPA_RESP) || 129*a3cbbb47SArd Biesheuvel (GHCB_MSR_REG_GPA_RESP_VAL(val) != pfn)) 130*a3cbbb47SArd Biesheuvel sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_REGISTER); 131*a3cbbb47SArd Biesheuvel } 132*a3cbbb47SArd Biesheuvel 133*a3cbbb47SArd Biesheuvel bool sev_es_negotiate_protocol(void) 134*a3cbbb47SArd Biesheuvel { 135*a3cbbb47SArd Biesheuvel u64 val; 136*a3cbbb47SArd Biesheuvel 137*a3cbbb47SArd Biesheuvel /* Do the GHCB protocol version negotiation */ 138*a3cbbb47SArd Biesheuvel sev_es_wr_ghcb_msr(GHCB_MSR_SEV_INFO_REQ); 139*a3cbbb47SArd Biesheuvel VMGEXIT(); 140*a3cbbb47SArd Biesheuvel val = sev_es_rd_ghcb_msr(); 141*a3cbbb47SArd Biesheuvel 142*a3cbbb47SArd Biesheuvel if (GHCB_MSR_INFO(val) != GHCB_MSR_SEV_INFO_RESP) 143*a3cbbb47SArd Biesheuvel return false; 144*a3cbbb47SArd Biesheuvel 145*a3cbbb47SArd Biesheuvel if (GHCB_MSR_PROTO_MAX(val) < GHCB_PROTOCOL_MIN || 146*a3cbbb47SArd Biesheuvel GHCB_MSR_PROTO_MIN(val) > GHCB_PROTOCOL_MAX) 147*a3cbbb47SArd Biesheuvel return false; 148*a3cbbb47SArd Biesheuvel 149*a3cbbb47SArd Biesheuvel ghcb_version = min_t(size_t, GHCB_MSR_PROTO_MAX(val), GHCB_PROTOCOL_MAX); 150*a3cbbb47SArd Biesheuvel 151*a3cbbb47SArd Biesheuvel return true; 152*a3cbbb47SArd Biesheuvel } 153*a3cbbb47SArd Biesheuvel 154*a3cbbb47SArd Biesheuvel static bool vc_decoding_needed(unsigned long exit_code) 155*a3cbbb47SArd Biesheuvel { 156*a3cbbb47SArd Biesheuvel /* Exceptions don't require to decode the instruction */ 157*a3cbbb47SArd Biesheuvel return !(exit_code >= SVM_EXIT_EXCP_BASE && 158*a3cbbb47SArd Biesheuvel exit_code <= SVM_EXIT_LAST_EXCP); 159*a3cbbb47SArd Biesheuvel } 160*a3cbbb47SArd Biesheuvel 161*a3cbbb47SArd Biesheuvel static enum es_result vc_init_em_ctxt(struct es_em_ctxt *ctxt, 162*a3cbbb47SArd Biesheuvel struct pt_regs *regs, 163*a3cbbb47SArd Biesheuvel unsigned long exit_code) 164*a3cbbb47SArd Biesheuvel { 165*a3cbbb47SArd Biesheuvel enum es_result ret = ES_OK; 166*a3cbbb47SArd Biesheuvel 167*a3cbbb47SArd Biesheuvel memset(ctxt, 0, sizeof(*ctxt)); 168*a3cbbb47SArd Biesheuvel ctxt->regs = regs; 169*a3cbbb47SArd Biesheuvel 170*a3cbbb47SArd Biesheuvel if (vc_decoding_needed(exit_code)) 171*a3cbbb47SArd Biesheuvel ret = vc_decode_insn(ctxt); 172*a3cbbb47SArd Biesheuvel 173*a3cbbb47SArd Biesheuvel return ret; 174*a3cbbb47SArd Biesheuvel } 175*a3cbbb47SArd Biesheuvel 176*a3cbbb47SArd Biesheuvel static void vc_finish_insn(struct es_em_ctxt *ctxt) 177*a3cbbb47SArd Biesheuvel { 178*a3cbbb47SArd Biesheuvel ctxt->regs->ip += ctxt->insn.length; 179*a3cbbb47SArd Biesheuvel } 180*a3cbbb47SArd Biesheuvel 181*a3cbbb47SArd Biesheuvel static enum es_result verify_exception_info(struct ghcb *ghcb, struct es_em_ctxt *ctxt) 182*a3cbbb47SArd Biesheuvel { 183*a3cbbb47SArd Biesheuvel u32 ret; 184*a3cbbb47SArd Biesheuvel 185*a3cbbb47SArd Biesheuvel ret = ghcb->save.sw_exit_info_1 & GENMASK_ULL(31, 0); 186*a3cbbb47SArd Biesheuvel if (!ret) 187*a3cbbb47SArd Biesheuvel return ES_OK; 188*a3cbbb47SArd Biesheuvel 189*a3cbbb47SArd Biesheuvel if (ret == 1) { 190*a3cbbb47SArd Biesheuvel u64 info = ghcb->save.sw_exit_info_2; 191*a3cbbb47SArd Biesheuvel unsigned long v = info & SVM_EVTINJ_VEC_MASK; 192*a3cbbb47SArd Biesheuvel 193*a3cbbb47SArd Biesheuvel /* Check if exception information from hypervisor is sane. */ 194*a3cbbb47SArd Biesheuvel if ((info & SVM_EVTINJ_VALID) && 195*a3cbbb47SArd Biesheuvel ((v == X86_TRAP_GP) || (v == X86_TRAP_UD)) && 196*a3cbbb47SArd Biesheuvel ((info & SVM_EVTINJ_TYPE_MASK) == SVM_EVTINJ_TYPE_EXEPT)) { 197*a3cbbb47SArd Biesheuvel ctxt->fi.vector = v; 198*a3cbbb47SArd Biesheuvel 199*a3cbbb47SArd Biesheuvel if (info & SVM_EVTINJ_VALID_ERR) 200*a3cbbb47SArd Biesheuvel ctxt->fi.error_code = info >> 32; 201*a3cbbb47SArd Biesheuvel 202*a3cbbb47SArd Biesheuvel return ES_EXCEPTION; 203*a3cbbb47SArd Biesheuvel } 204*a3cbbb47SArd Biesheuvel } 205*a3cbbb47SArd Biesheuvel 206*a3cbbb47SArd Biesheuvel return ES_VMM_ERROR; 207*a3cbbb47SArd Biesheuvel } 208*a3cbbb47SArd Biesheuvel 209*a3cbbb47SArd Biesheuvel static inline int svsm_process_result_codes(struct svsm_call *call) 210*a3cbbb47SArd Biesheuvel { 211*a3cbbb47SArd Biesheuvel switch (call->rax_out) { 212*a3cbbb47SArd Biesheuvel case SVSM_SUCCESS: 213*a3cbbb47SArd Biesheuvel return 0; 214*a3cbbb47SArd Biesheuvel case SVSM_ERR_INCOMPLETE: 215*a3cbbb47SArd Biesheuvel case SVSM_ERR_BUSY: 216*a3cbbb47SArd Biesheuvel return -EAGAIN; 217*a3cbbb47SArd Biesheuvel default: 218*a3cbbb47SArd Biesheuvel return -EINVAL; 219*a3cbbb47SArd Biesheuvel } 220*a3cbbb47SArd Biesheuvel } 221*a3cbbb47SArd Biesheuvel 222*a3cbbb47SArd Biesheuvel /* 223*a3cbbb47SArd Biesheuvel * Issue a VMGEXIT to call the SVSM: 224*a3cbbb47SArd Biesheuvel * - Load the SVSM register state (RAX, RCX, RDX, R8 and R9) 225*a3cbbb47SArd Biesheuvel * - Set the CA call pending field to 1 226*a3cbbb47SArd Biesheuvel * - Issue VMGEXIT 227*a3cbbb47SArd Biesheuvel * - Save the SVSM return register state (RAX, RCX, RDX, R8 and R9) 228*a3cbbb47SArd Biesheuvel * - Perform atomic exchange of the CA call pending field 229*a3cbbb47SArd Biesheuvel * 230*a3cbbb47SArd Biesheuvel * - See the "Secure VM Service Module for SEV-SNP Guests" specification for 231*a3cbbb47SArd Biesheuvel * details on the calling convention. 232*a3cbbb47SArd Biesheuvel * - The calling convention loosely follows the Microsoft X64 calling 233*a3cbbb47SArd Biesheuvel * convention by putting arguments in RCX, RDX, R8 and R9. 234*a3cbbb47SArd Biesheuvel * - RAX specifies the SVSM protocol/callid as input and the return code 235*a3cbbb47SArd Biesheuvel * as output. 236*a3cbbb47SArd Biesheuvel */ 237*a3cbbb47SArd Biesheuvel static __always_inline void svsm_issue_call(struct svsm_call *call, u8 *pending) 238*a3cbbb47SArd Biesheuvel { 239*a3cbbb47SArd Biesheuvel register unsigned long rax asm("rax") = call->rax; 240*a3cbbb47SArd Biesheuvel register unsigned long rcx asm("rcx") = call->rcx; 241*a3cbbb47SArd Biesheuvel register unsigned long rdx asm("rdx") = call->rdx; 242*a3cbbb47SArd Biesheuvel register unsigned long r8 asm("r8") = call->r8; 243*a3cbbb47SArd Biesheuvel register unsigned long r9 asm("r9") = call->r9; 244*a3cbbb47SArd Biesheuvel 245*a3cbbb47SArd Biesheuvel call->caa->call_pending = 1; 246*a3cbbb47SArd Biesheuvel 247*a3cbbb47SArd Biesheuvel asm volatile("rep; vmmcall\n\t" 248*a3cbbb47SArd Biesheuvel : "+r" (rax), "+r" (rcx), "+r" (rdx), "+r" (r8), "+r" (r9) 249*a3cbbb47SArd Biesheuvel : : "memory"); 250*a3cbbb47SArd Biesheuvel 251*a3cbbb47SArd Biesheuvel *pending = xchg(&call->caa->call_pending, *pending); 252*a3cbbb47SArd Biesheuvel 253*a3cbbb47SArd Biesheuvel call->rax_out = rax; 254*a3cbbb47SArd Biesheuvel call->rcx_out = rcx; 255*a3cbbb47SArd Biesheuvel call->rdx_out = rdx; 256*a3cbbb47SArd Biesheuvel call->r8_out = r8; 257*a3cbbb47SArd Biesheuvel call->r9_out = r9; 258*a3cbbb47SArd Biesheuvel } 259*a3cbbb47SArd Biesheuvel 260*a3cbbb47SArd Biesheuvel static int svsm_perform_msr_protocol(struct svsm_call *call) 261*a3cbbb47SArd Biesheuvel { 262*a3cbbb47SArd Biesheuvel u8 pending = 0; 263*a3cbbb47SArd Biesheuvel u64 val, resp; 264*a3cbbb47SArd Biesheuvel 265*a3cbbb47SArd Biesheuvel /* 266*a3cbbb47SArd Biesheuvel * When using the MSR protocol, be sure to save and restore 267*a3cbbb47SArd Biesheuvel * the current MSR value. 268*a3cbbb47SArd Biesheuvel */ 269*a3cbbb47SArd Biesheuvel val = sev_es_rd_ghcb_msr(); 270*a3cbbb47SArd Biesheuvel 271*a3cbbb47SArd Biesheuvel sev_es_wr_ghcb_msr(GHCB_MSR_VMPL_REQ_LEVEL(0)); 272*a3cbbb47SArd Biesheuvel 273*a3cbbb47SArd Biesheuvel svsm_issue_call(call, &pending); 274*a3cbbb47SArd Biesheuvel 275*a3cbbb47SArd Biesheuvel resp = sev_es_rd_ghcb_msr(); 276*a3cbbb47SArd Biesheuvel 277*a3cbbb47SArd Biesheuvel sev_es_wr_ghcb_msr(val); 278*a3cbbb47SArd Biesheuvel 279*a3cbbb47SArd Biesheuvel if (pending) 280*a3cbbb47SArd Biesheuvel return -EINVAL; 281*a3cbbb47SArd Biesheuvel 282*a3cbbb47SArd Biesheuvel if (GHCB_RESP_CODE(resp) != GHCB_MSR_VMPL_RESP) 283*a3cbbb47SArd Biesheuvel return -EINVAL; 284*a3cbbb47SArd Biesheuvel 285*a3cbbb47SArd Biesheuvel if (GHCB_MSR_VMPL_RESP_VAL(resp)) 286*a3cbbb47SArd Biesheuvel return -EINVAL; 287*a3cbbb47SArd Biesheuvel 288*a3cbbb47SArd Biesheuvel return svsm_process_result_codes(call); 289*a3cbbb47SArd Biesheuvel } 290*a3cbbb47SArd Biesheuvel 291*a3cbbb47SArd Biesheuvel static int svsm_perform_ghcb_protocol(struct ghcb *ghcb, struct svsm_call *call) 292*a3cbbb47SArd Biesheuvel { 293*a3cbbb47SArd Biesheuvel struct es_em_ctxt ctxt; 294*a3cbbb47SArd Biesheuvel u8 pending = 0; 295*a3cbbb47SArd Biesheuvel 296*a3cbbb47SArd Biesheuvel vc_ghcb_invalidate(ghcb); 297*a3cbbb47SArd Biesheuvel 298*a3cbbb47SArd Biesheuvel /* 299*a3cbbb47SArd Biesheuvel * Fill in protocol and format specifiers. This can be called very early 300*a3cbbb47SArd Biesheuvel * in the boot, so use rip-relative references as needed. 301*a3cbbb47SArd Biesheuvel */ 302*a3cbbb47SArd Biesheuvel ghcb->protocol_version = RIP_REL_REF(ghcb_version); 303*a3cbbb47SArd Biesheuvel ghcb->ghcb_usage = GHCB_DEFAULT_USAGE; 304*a3cbbb47SArd Biesheuvel 305*a3cbbb47SArd Biesheuvel ghcb_set_sw_exit_code(ghcb, SVM_VMGEXIT_SNP_RUN_VMPL); 306*a3cbbb47SArd Biesheuvel ghcb_set_sw_exit_info_1(ghcb, 0); 307*a3cbbb47SArd Biesheuvel ghcb_set_sw_exit_info_2(ghcb, 0); 308*a3cbbb47SArd Biesheuvel 309*a3cbbb47SArd Biesheuvel sev_es_wr_ghcb_msr(__pa(ghcb)); 310*a3cbbb47SArd Biesheuvel 311*a3cbbb47SArd Biesheuvel svsm_issue_call(call, &pending); 312*a3cbbb47SArd Biesheuvel 313*a3cbbb47SArd Biesheuvel if (pending) 314*a3cbbb47SArd Biesheuvel return -EINVAL; 315*a3cbbb47SArd Biesheuvel 316*a3cbbb47SArd Biesheuvel switch (verify_exception_info(ghcb, &ctxt)) { 317*a3cbbb47SArd Biesheuvel case ES_OK: 318*a3cbbb47SArd Biesheuvel break; 319*a3cbbb47SArd Biesheuvel case ES_EXCEPTION: 320*a3cbbb47SArd Biesheuvel vc_forward_exception(&ctxt); 321*a3cbbb47SArd Biesheuvel fallthrough; 322*a3cbbb47SArd Biesheuvel default: 323*a3cbbb47SArd Biesheuvel return -EINVAL; 324*a3cbbb47SArd Biesheuvel } 325*a3cbbb47SArd Biesheuvel 326*a3cbbb47SArd Biesheuvel return svsm_process_result_codes(call); 327*a3cbbb47SArd Biesheuvel } 328*a3cbbb47SArd Biesheuvel 329*a3cbbb47SArd Biesheuvel enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb, 330*a3cbbb47SArd Biesheuvel struct es_em_ctxt *ctxt, 331*a3cbbb47SArd Biesheuvel u64 exit_code, u64 exit_info_1, 332*a3cbbb47SArd Biesheuvel u64 exit_info_2) 333*a3cbbb47SArd Biesheuvel { 334*a3cbbb47SArd Biesheuvel /* Fill in protocol and format specifiers */ 335*a3cbbb47SArd Biesheuvel ghcb->protocol_version = ghcb_version; 336*a3cbbb47SArd Biesheuvel ghcb->ghcb_usage = GHCB_DEFAULT_USAGE; 337*a3cbbb47SArd Biesheuvel 338*a3cbbb47SArd Biesheuvel ghcb_set_sw_exit_code(ghcb, exit_code); 339*a3cbbb47SArd Biesheuvel ghcb_set_sw_exit_info_1(ghcb, exit_info_1); 340*a3cbbb47SArd Biesheuvel ghcb_set_sw_exit_info_2(ghcb, exit_info_2); 341*a3cbbb47SArd Biesheuvel 342*a3cbbb47SArd Biesheuvel sev_es_wr_ghcb_msr(__pa(ghcb)); 343*a3cbbb47SArd Biesheuvel VMGEXIT(); 344*a3cbbb47SArd Biesheuvel 345*a3cbbb47SArd Biesheuvel return verify_exception_info(ghcb, ctxt); 346*a3cbbb47SArd Biesheuvel } 347*a3cbbb47SArd Biesheuvel 348*a3cbbb47SArd Biesheuvel static int __sev_cpuid_hv(u32 fn, int reg_idx, u32 *reg) 349*a3cbbb47SArd Biesheuvel { 350*a3cbbb47SArd Biesheuvel u64 val; 351*a3cbbb47SArd Biesheuvel 352*a3cbbb47SArd Biesheuvel sev_es_wr_ghcb_msr(GHCB_CPUID_REQ(fn, reg_idx)); 353*a3cbbb47SArd Biesheuvel VMGEXIT(); 354*a3cbbb47SArd Biesheuvel val = sev_es_rd_ghcb_msr(); 355*a3cbbb47SArd Biesheuvel if (GHCB_RESP_CODE(val) != GHCB_MSR_CPUID_RESP) 356*a3cbbb47SArd Biesheuvel return -EIO; 357*a3cbbb47SArd Biesheuvel 358*a3cbbb47SArd Biesheuvel *reg = (val >> 32); 359*a3cbbb47SArd Biesheuvel 360*a3cbbb47SArd Biesheuvel return 0; 361*a3cbbb47SArd Biesheuvel } 362*a3cbbb47SArd Biesheuvel 363*a3cbbb47SArd Biesheuvel static int __sev_cpuid_hv_msr(struct cpuid_leaf *leaf) 364*a3cbbb47SArd Biesheuvel { 365*a3cbbb47SArd Biesheuvel int ret; 366*a3cbbb47SArd Biesheuvel 367*a3cbbb47SArd Biesheuvel /* 368*a3cbbb47SArd Biesheuvel * MSR protocol does not support fetching non-zero subfunctions, but is 369*a3cbbb47SArd Biesheuvel * sufficient to handle current early-boot cases. Should that change, 370*a3cbbb47SArd Biesheuvel * make sure to report an error rather than ignoring the index and 371*a3cbbb47SArd Biesheuvel * grabbing random values. If this issue arises in the future, handling 372*a3cbbb47SArd Biesheuvel * can be added here to use GHCB-page protocol for cases that occur late 373*a3cbbb47SArd Biesheuvel * enough in boot that GHCB page is available. 374*a3cbbb47SArd Biesheuvel */ 375*a3cbbb47SArd Biesheuvel if (cpuid_function_is_indexed(leaf->fn) && leaf->subfn) 376*a3cbbb47SArd Biesheuvel return -EINVAL; 377*a3cbbb47SArd Biesheuvel 378*a3cbbb47SArd Biesheuvel ret = __sev_cpuid_hv(leaf->fn, GHCB_CPUID_REQ_EAX, &leaf->eax); 379*a3cbbb47SArd Biesheuvel ret = ret ? : __sev_cpuid_hv(leaf->fn, GHCB_CPUID_REQ_EBX, &leaf->ebx); 380*a3cbbb47SArd Biesheuvel ret = ret ? : __sev_cpuid_hv(leaf->fn, GHCB_CPUID_REQ_ECX, &leaf->ecx); 381*a3cbbb47SArd Biesheuvel ret = ret ? : __sev_cpuid_hv(leaf->fn, GHCB_CPUID_REQ_EDX, &leaf->edx); 382*a3cbbb47SArd Biesheuvel 383*a3cbbb47SArd Biesheuvel return ret; 384*a3cbbb47SArd Biesheuvel } 385*a3cbbb47SArd Biesheuvel 386*a3cbbb47SArd Biesheuvel static int __sev_cpuid_hv_ghcb(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf) 387*a3cbbb47SArd Biesheuvel { 388*a3cbbb47SArd Biesheuvel u32 cr4 = native_read_cr4(); 389*a3cbbb47SArd Biesheuvel int ret; 390*a3cbbb47SArd Biesheuvel 391*a3cbbb47SArd Biesheuvel ghcb_set_rax(ghcb, leaf->fn); 392*a3cbbb47SArd Biesheuvel ghcb_set_rcx(ghcb, leaf->subfn); 393*a3cbbb47SArd Biesheuvel 394*a3cbbb47SArd Biesheuvel if (cr4 & X86_CR4_OSXSAVE) 395*a3cbbb47SArd Biesheuvel /* Safe to read xcr0 */ 396*a3cbbb47SArd Biesheuvel ghcb_set_xcr0(ghcb, xgetbv(XCR_XFEATURE_ENABLED_MASK)); 397*a3cbbb47SArd Biesheuvel else 398*a3cbbb47SArd Biesheuvel /* xgetbv will cause #UD - use reset value for xcr0 */ 399*a3cbbb47SArd Biesheuvel ghcb_set_xcr0(ghcb, 1); 400*a3cbbb47SArd Biesheuvel 401*a3cbbb47SArd Biesheuvel ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_CPUID, 0, 0); 402*a3cbbb47SArd Biesheuvel if (ret != ES_OK) 403*a3cbbb47SArd Biesheuvel return ret; 404*a3cbbb47SArd Biesheuvel 405*a3cbbb47SArd Biesheuvel if (!(ghcb_rax_is_valid(ghcb) && 406*a3cbbb47SArd Biesheuvel ghcb_rbx_is_valid(ghcb) && 407*a3cbbb47SArd Biesheuvel ghcb_rcx_is_valid(ghcb) && 408*a3cbbb47SArd Biesheuvel ghcb_rdx_is_valid(ghcb))) 409*a3cbbb47SArd Biesheuvel return ES_VMM_ERROR; 410*a3cbbb47SArd Biesheuvel 411*a3cbbb47SArd Biesheuvel leaf->eax = ghcb->save.rax; 412*a3cbbb47SArd Biesheuvel leaf->ebx = ghcb->save.rbx; 413*a3cbbb47SArd Biesheuvel leaf->ecx = ghcb->save.rcx; 414*a3cbbb47SArd Biesheuvel leaf->edx = ghcb->save.rdx; 415*a3cbbb47SArd Biesheuvel 416*a3cbbb47SArd Biesheuvel return ES_OK; 417*a3cbbb47SArd Biesheuvel } 418*a3cbbb47SArd Biesheuvel 419*a3cbbb47SArd Biesheuvel static int sev_cpuid_hv(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf) 420*a3cbbb47SArd Biesheuvel { 421*a3cbbb47SArd Biesheuvel return ghcb ? __sev_cpuid_hv_ghcb(ghcb, ctxt, leaf) 422*a3cbbb47SArd Biesheuvel : __sev_cpuid_hv_msr(leaf); 423*a3cbbb47SArd Biesheuvel } 424*a3cbbb47SArd Biesheuvel 425*a3cbbb47SArd Biesheuvel /* 426*a3cbbb47SArd Biesheuvel * This may be called early while still running on the initial identity 427*a3cbbb47SArd Biesheuvel * mapping. Use RIP-relative addressing to obtain the correct address 428*a3cbbb47SArd Biesheuvel * while running with the initial identity mapping as well as the 429*a3cbbb47SArd Biesheuvel * switch-over to kernel virtual addresses later. 430*a3cbbb47SArd Biesheuvel */ 431*a3cbbb47SArd Biesheuvel const struct snp_cpuid_table *snp_cpuid_get_table(void) 432*a3cbbb47SArd Biesheuvel { 433*a3cbbb47SArd Biesheuvel return rip_rel_ptr(&cpuid_table_copy); 434*a3cbbb47SArd Biesheuvel } 435*a3cbbb47SArd Biesheuvel 436*a3cbbb47SArd Biesheuvel /* 437*a3cbbb47SArd Biesheuvel * The SNP Firmware ABI, Revision 0.9, Section 7.1, details the use of 438*a3cbbb47SArd Biesheuvel * XCR0_IN and XSS_IN to encode multiple versions of 0xD subfunctions 0 439*a3cbbb47SArd Biesheuvel * and 1 based on the corresponding features enabled by a particular 440*a3cbbb47SArd Biesheuvel * combination of XCR0 and XSS registers so that a guest can look up the 441*a3cbbb47SArd Biesheuvel * version corresponding to the features currently enabled in its XCR0/XSS 442*a3cbbb47SArd Biesheuvel * registers. The only values that differ between these versions/table 443*a3cbbb47SArd Biesheuvel * entries is the enabled XSAVE area size advertised via EBX. 444*a3cbbb47SArd Biesheuvel * 445*a3cbbb47SArd Biesheuvel * While hypervisors may choose to make use of this support, it is more 446*a3cbbb47SArd Biesheuvel * robust/secure for a guest to simply find the entry corresponding to the 447*a3cbbb47SArd Biesheuvel * base/legacy XSAVE area size (XCR0=1 or XCR0=3), and then calculate the 448*a3cbbb47SArd Biesheuvel * XSAVE area size using subfunctions 2 through 64, as documented in APM 449*a3cbbb47SArd Biesheuvel * Volume 3, Rev 3.31, Appendix E.3.8, which is what is done here. 450*a3cbbb47SArd Biesheuvel * 451*a3cbbb47SArd Biesheuvel * Since base/legacy XSAVE area size is documented as 0x240, use that value 452*a3cbbb47SArd Biesheuvel * directly rather than relying on the base size in the CPUID table. 453*a3cbbb47SArd Biesheuvel * 454*a3cbbb47SArd Biesheuvel * Return: XSAVE area size on success, 0 otherwise. 455*a3cbbb47SArd Biesheuvel */ 456*a3cbbb47SArd Biesheuvel static u32 __head snp_cpuid_calc_xsave_size(u64 xfeatures_en, bool compacted) 457*a3cbbb47SArd Biesheuvel { 458*a3cbbb47SArd Biesheuvel const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table(); 459*a3cbbb47SArd Biesheuvel u64 xfeatures_found = 0; 460*a3cbbb47SArd Biesheuvel u32 xsave_size = 0x240; 461*a3cbbb47SArd Biesheuvel int i; 462*a3cbbb47SArd Biesheuvel 463*a3cbbb47SArd Biesheuvel for (i = 0; i < cpuid_table->count; i++) { 464*a3cbbb47SArd Biesheuvel const struct snp_cpuid_fn *e = &cpuid_table->fn[i]; 465*a3cbbb47SArd Biesheuvel 466*a3cbbb47SArd Biesheuvel if (!(e->eax_in == 0xD && e->ecx_in > 1 && e->ecx_in < 64)) 467*a3cbbb47SArd Biesheuvel continue; 468*a3cbbb47SArd Biesheuvel if (!(xfeatures_en & (BIT_ULL(e->ecx_in)))) 469*a3cbbb47SArd Biesheuvel continue; 470*a3cbbb47SArd Biesheuvel if (xfeatures_found & (BIT_ULL(e->ecx_in))) 471*a3cbbb47SArd Biesheuvel continue; 472*a3cbbb47SArd Biesheuvel 473*a3cbbb47SArd Biesheuvel xfeatures_found |= (BIT_ULL(e->ecx_in)); 474*a3cbbb47SArd Biesheuvel 475*a3cbbb47SArd Biesheuvel if (compacted) 476*a3cbbb47SArd Biesheuvel xsave_size += e->eax; 477*a3cbbb47SArd Biesheuvel else 478*a3cbbb47SArd Biesheuvel xsave_size = max(xsave_size, e->eax + e->ebx); 479*a3cbbb47SArd Biesheuvel } 480*a3cbbb47SArd Biesheuvel 481*a3cbbb47SArd Biesheuvel /* 482*a3cbbb47SArd Biesheuvel * Either the guest set unsupported XCR0/XSS bits, or the corresponding 483*a3cbbb47SArd Biesheuvel * entries in the CPUID table were not present. This is not a valid 484*a3cbbb47SArd Biesheuvel * state to be in. 485*a3cbbb47SArd Biesheuvel */ 486*a3cbbb47SArd Biesheuvel if (xfeatures_found != (xfeatures_en & GENMASK_ULL(63, 2))) 487*a3cbbb47SArd Biesheuvel return 0; 488*a3cbbb47SArd Biesheuvel 489*a3cbbb47SArd Biesheuvel return xsave_size; 490*a3cbbb47SArd Biesheuvel } 491*a3cbbb47SArd Biesheuvel 492*a3cbbb47SArd Biesheuvel static bool __head 493*a3cbbb47SArd Biesheuvel snp_cpuid_get_validated_func(struct cpuid_leaf *leaf) 494*a3cbbb47SArd Biesheuvel { 495*a3cbbb47SArd Biesheuvel const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table(); 496*a3cbbb47SArd Biesheuvel int i; 497*a3cbbb47SArd Biesheuvel 498*a3cbbb47SArd Biesheuvel for (i = 0; i < cpuid_table->count; i++) { 499*a3cbbb47SArd Biesheuvel const struct snp_cpuid_fn *e = &cpuid_table->fn[i]; 500*a3cbbb47SArd Biesheuvel 501*a3cbbb47SArd Biesheuvel if (e->eax_in != leaf->fn) 502*a3cbbb47SArd Biesheuvel continue; 503*a3cbbb47SArd Biesheuvel 504*a3cbbb47SArd Biesheuvel if (cpuid_function_is_indexed(leaf->fn) && e->ecx_in != leaf->subfn) 505*a3cbbb47SArd Biesheuvel continue; 506*a3cbbb47SArd Biesheuvel 507*a3cbbb47SArd Biesheuvel /* 508*a3cbbb47SArd Biesheuvel * For 0xD subfunctions 0 and 1, only use the entry corresponding 509*a3cbbb47SArd Biesheuvel * to the base/legacy XSAVE area size (XCR0=1 or XCR0=3, XSS=0). 510*a3cbbb47SArd Biesheuvel * See the comments above snp_cpuid_calc_xsave_size() for more 511*a3cbbb47SArd Biesheuvel * details. 512*a3cbbb47SArd Biesheuvel */ 513*a3cbbb47SArd Biesheuvel if (e->eax_in == 0xD && (e->ecx_in == 0 || e->ecx_in == 1)) 514*a3cbbb47SArd Biesheuvel if (!(e->xcr0_in == 1 || e->xcr0_in == 3) || e->xss_in) 515*a3cbbb47SArd Biesheuvel continue; 516*a3cbbb47SArd Biesheuvel 517*a3cbbb47SArd Biesheuvel leaf->eax = e->eax; 518*a3cbbb47SArd Biesheuvel leaf->ebx = e->ebx; 519*a3cbbb47SArd Biesheuvel leaf->ecx = e->ecx; 520*a3cbbb47SArd Biesheuvel leaf->edx = e->edx; 521*a3cbbb47SArd Biesheuvel 522*a3cbbb47SArd Biesheuvel return true; 523*a3cbbb47SArd Biesheuvel } 524*a3cbbb47SArd Biesheuvel 525*a3cbbb47SArd Biesheuvel return false; 526*a3cbbb47SArd Biesheuvel } 527*a3cbbb47SArd Biesheuvel 528*a3cbbb47SArd Biesheuvel static void snp_cpuid_hv(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf) 529*a3cbbb47SArd Biesheuvel { 530*a3cbbb47SArd Biesheuvel if (sev_cpuid_hv(ghcb, ctxt, leaf)) 531*a3cbbb47SArd Biesheuvel sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_CPUID_HV); 532*a3cbbb47SArd Biesheuvel } 533*a3cbbb47SArd Biesheuvel 534*a3cbbb47SArd Biesheuvel static int __head 535*a3cbbb47SArd Biesheuvel snp_cpuid_postprocess(struct ghcb *ghcb, struct es_em_ctxt *ctxt, 536*a3cbbb47SArd Biesheuvel struct cpuid_leaf *leaf) 537*a3cbbb47SArd Biesheuvel { 538*a3cbbb47SArd Biesheuvel struct cpuid_leaf leaf_hv = *leaf; 539*a3cbbb47SArd Biesheuvel 540*a3cbbb47SArd Biesheuvel switch (leaf->fn) { 541*a3cbbb47SArd Biesheuvel case 0x1: 542*a3cbbb47SArd Biesheuvel snp_cpuid_hv(ghcb, ctxt, &leaf_hv); 543*a3cbbb47SArd Biesheuvel 544*a3cbbb47SArd Biesheuvel /* initial APIC ID */ 545*a3cbbb47SArd Biesheuvel leaf->ebx = (leaf_hv.ebx & GENMASK(31, 24)) | (leaf->ebx & GENMASK(23, 0)); 546*a3cbbb47SArd Biesheuvel /* APIC enabled bit */ 547*a3cbbb47SArd Biesheuvel leaf->edx = (leaf_hv.edx & BIT(9)) | (leaf->edx & ~BIT(9)); 548*a3cbbb47SArd Biesheuvel 549*a3cbbb47SArd Biesheuvel /* OSXSAVE enabled bit */ 550*a3cbbb47SArd Biesheuvel if (native_read_cr4() & X86_CR4_OSXSAVE) 551*a3cbbb47SArd Biesheuvel leaf->ecx |= BIT(27); 552*a3cbbb47SArd Biesheuvel break; 553*a3cbbb47SArd Biesheuvel case 0x7: 554*a3cbbb47SArd Biesheuvel /* OSPKE enabled bit */ 555*a3cbbb47SArd Biesheuvel leaf->ecx &= ~BIT(4); 556*a3cbbb47SArd Biesheuvel if (native_read_cr4() & X86_CR4_PKE) 557*a3cbbb47SArd Biesheuvel leaf->ecx |= BIT(4); 558*a3cbbb47SArd Biesheuvel break; 559*a3cbbb47SArd Biesheuvel case 0xB: 560*a3cbbb47SArd Biesheuvel leaf_hv.subfn = 0; 561*a3cbbb47SArd Biesheuvel snp_cpuid_hv(ghcb, ctxt, &leaf_hv); 562*a3cbbb47SArd Biesheuvel 563*a3cbbb47SArd Biesheuvel /* extended APIC ID */ 564*a3cbbb47SArd Biesheuvel leaf->edx = leaf_hv.edx; 565*a3cbbb47SArd Biesheuvel break; 566*a3cbbb47SArd Biesheuvel case 0xD: { 567*a3cbbb47SArd Biesheuvel bool compacted = false; 568*a3cbbb47SArd Biesheuvel u64 xcr0 = 1, xss = 0; 569*a3cbbb47SArd Biesheuvel u32 xsave_size; 570*a3cbbb47SArd Biesheuvel 571*a3cbbb47SArd Biesheuvel if (leaf->subfn != 0 && leaf->subfn != 1) 572*a3cbbb47SArd Biesheuvel return 0; 573*a3cbbb47SArd Biesheuvel 574*a3cbbb47SArd Biesheuvel if (native_read_cr4() & X86_CR4_OSXSAVE) 575*a3cbbb47SArd Biesheuvel xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK); 576*a3cbbb47SArd Biesheuvel if (leaf->subfn == 1) { 577*a3cbbb47SArd Biesheuvel /* Get XSS value if XSAVES is enabled. */ 578*a3cbbb47SArd Biesheuvel if (leaf->eax & BIT(3)) { 579*a3cbbb47SArd Biesheuvel unsigned long lo, hi; 580*a3cbbb47SArd Biesheuvel 581*a3cbbb47SArd Biesheuvel asm volatile("rdmsr" : "=a" (lo), "=d" (hi) 582*a3cbbb47SArd Biesheuvel : "c" (MSR_IA32_XSS)); 583*a3cbbb47SArd Biesheuvel xss = (hi << 32) | lo; 584*a3cbbb47SArd Biesheuvel } 585*a3cbbb47SArd Biesheuvel 586*a3cbbb47SArd Biesheuvel /* 587*a3cbbb47SArd Biesheuvel * The PPR and APM aren't clear on what size should be 588*a3cbbb47SArd Biesheuvel * encoded in 0xD:0x1:EBX when compaction is not enabled 589*a3cbbb47SArd Biesheuvel * by either XSAVEC (feature bit 1) or XSAVES (feature 590*a3cbbb47SArd Biesheuvel * bit 3) since SNP-capable hardware has these feature 591*a3cbbb47SArd Biesheuvel * bits fixed as 1. KVM sets it to 0 in this case, but 592*a3cbbb47SArd Biesheuvel * to avoid this becoming an issue it's safer to simply 593*a3cbbb47SArd Biesheuvel * treat this as unsupported for SNP guests. 594*a3cbbb47SArd Biesheuvel */ 595*a3cbbb47SArd Biesheuvel if (!(leaf->eax & (BIT(1) | BIT(3)))) 596*a3cbbb47SArd Biesheuvel return -EINVAL; 597*a3cbbb47SArd Biesheuvel 598*a3cbbb47SArd Biesheuvel compacted = true; 599*a3cbbb47SArd Biesheuvel } 600*a3cbbb47SArd Biesheuvel 601*a3cbbb47SArd Biesheuvel xsave_size = snp_cpuid_calc_xsave_size(xcr0 | xss, compacted); 602*a3cbbb47SArd Biesheuvel if (!xsave_size) 603*a3cbbb47SArd Biesheuvel return -EINVAL; 604*a3cbbb47SArd Biesheuvel 605*a3cbbb47SArd Biesheuvel leaf->ebx = xsave_size; 606*a3cbbb47SArd Biesheuvel } 607*a3cbbb47SArd Biesheuvel break; 608*a3cbbb47SArd Biesheuvel case 0x8000001E: 609*a3cbbb47SArd Biesheuvel snp_cpuid_hv(ghcb, ctxt, &leaf_hv); 610*a3cbbb47SArd Biesheuvel 611*a3cbbb47SArd Biesheuvel /* extended APIC ID */ 612*a3cbbb47SArd Biesheuvel leaf->eax = leaf_hv.eax; 613*a3cbbb47SArd Biesheuvel /* compute ID */ 614*a3cbbb47SArd Biesheuvel leaf->ebx = (leaf->ebx & GENMASK(31, 8)) | (leaf_hv.ebx & GENMASK(7, 0)); 615*a3cbbb47SArd Biesheuvel /* node ID */ 616*a3cbbb47SArd Biesheuvel leaf->ecx = (leaf->ecx & GENMASK(31, 8)) | (leaf_hv.ecx & GENMASK(7, 0)); 617*a3cbbb47SArd Biesheuvel break; 618*a3cbbb47SArd Biesheuvel default: 619*a3cbbb47SArd Biesheuvel /* No fix-ups needed, use values as-is. */ 620*a3cbbb47SArd Biesheuvel break; 621*a3cbbb47SArd Biesheuvel } 622*a3cbbb47SArd Biesheuvel 623*a3cbbb47SArd Biesheuvel return 0; 624*a3cbbb47SArd Biesheuvel } 625*a3cbbb47SArd Biesheuvel 626*a3cbbb47SArd Biesheuvel /* 627*a3cbbb47SArd Biesheuvel * Returns -EOPNOTSUPP if feature not enabled. Any other non-zero return value 628*a3cbbb47SArd Biesheuvel * should be treated as fatal by caller. 629*a3cbbb47SArd Biesheuvel */ 630*a3cbbb47SArd Biesheuvel static int __head 631*a3cbbb47SArd Biesheuvel snp_cpuid(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf) 632*a3cbbb47SArd Biesheuvel { 633*a3cbbb47SArd Biesheuvel const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table(); 634*a3cbbb47SArd Biesheuvel 635*a3cbbb47SArd Biesheuvel if (!cpuid_table->count) 636*a3cbbb47SArd Biesheuvel return -EOPNOTSUPP; 637*a3cbbb47SArd Biesheuvel 638*a3cbbb47SArd Biesheuvel if (!snp_cpuid_get_validated_func(leaf)) { 639*a3cbbb47SArd Biesheuvel /* 640*a3cbbb47SArd Biesheuvel * Some hypervisors will avoid keeping track of CPUID entries 641*a3cbbb47SArd Biesheuvel * where all values are zero, since they can be handled the 642*a3cbbb47SArd Biesheuvel * same as out-of-range values (all-zero). This is useful here 643*a3cbbb47SArd Biesheuvel * as well as it allows virtually all guest configurations to 644*a3cbbb47SArd Biesheuvel * work using a single SNP CPUID table. 645*a3cbbb47SArd Biesheuvel * 646*a3cbbb47SArd Biesheuvel * To allow for this, there is a need to distinguish between 647*a3cbbb47SArd Biesheuvel * out-of-range entries and in-range zero entries, since the 648*a3cbbb47SArd Biesheuvel * CPUID table entries are only a template that may need to be 649*a3cbbb47SArd Biesheuvel * augmented with additional values for things like 650*a3cbbb47SArd Biesheuvel * CPU-specific information during post-processing. So if it's 651*a3cbbb47SArd Biesheuvel * not in the table, set the values to zero. Then, if they are 652*a3cbbb47SArd Biesheuvel * within a valid CPUID range, proceed with post-processing 653*a3cbbb47SArd Biesheuvel * using zeros as the initial values. Otherwise, skip 654*a3cbbb47SArd Biesheuvel * post-processing and just return zeros immediately. 655*a3cbbb47SArd Biesheuvel */ 656*a3cbbb47SArd Biesheuvel leaf->eax = leaf->ebx = leaf->ecx = leaf->edx = 0; 657*a3cbbb47SArd Biesheuvel 658*a3cbbb47SArd Biesheuvel /* Skip post-processing for out-of-range zero leafs. */ 659*a3cbbb47SArd Biesheuvel if (!(leaf->fn <= RIP_REL_REF(cpuid_std_range_max) || 660*a3cbbb47SArd Biesheuvel (leaf->fn >= 0x40000000 && leaf->fn <= RIP_REL_REF(cpuid_hyp_range_max)) || 661*a3cbbb47SArd Biesheuvel (leaf->fn >= 0x80000000 && leaf->fn <= RIP_REL_REF(cpuid_ext_range_max)))) 662*a3cbbb47SArd Biesheuvel return 0; 663*a3cbbb47SArd Biesheuvel } 664*a3cbbb47SArd Biesheuvel 665*a3cbbb47SArd Biesheuvel return snp_cpuid_postprocess(ghcb, ctxt, leaf); 666*a3cbbb47SArd Biesheuvel } 667*a3cbbb47SArd Biesheuvel 668*a3cbbb47SArd Biesheuvel /* 669*a3cbbb47SArd Biesheuvel * Boot VC Handler - This is the first VC handler during boot, there is no GHCB 670*a3cbbb47SArd Biesheuvel * page yet, so it only supports the MSR based communication with the 671*a3cbbb47SArd Biesheuvel * hypervisor and only the CPUID exit-code. 672*a3cbbb47SArd Biesheuvel */ 673*a3cbbb47SArd Biesheuvel void __head do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code) 674*a3cbbb47SArd Biesheuvel { 675*a3cbbb47SArd Biesheuvel unsigned int subfn = lower_bits(regs->cx, 32); 676*a3cbbb47SArd Biesheuvel unsigned int fn = lower_bits(regs->ax, 32); 677*a3cbbb47SArd Biesheuvel u16 opcode = *(unsigned short *)regs->ip; 678*a3cbbb47SArd Biesheuvel struct cpuid_leaf leaf; 679*a3cbbb47SArd Biesheuvel int ret; 680*a3cbbb47SArd Biesheuvel 681*a3cbbb47SArd Biesheuvel /* Only CPUID is supported via MSR protocol */ 682*a3cbbb47SArd Biesheuvel if (exit_code != SVM_EXIT_CPUID) 683*a3cbbb47SArd Biesheuvel goto fail; 684*a3cbbb47SArd Biesheuvel 685*a3cbbb47SArd Biesheuvel /* Is it really a CPUID insn? */ 686*a3cbbb47SArd Biesheuvel if (opcode != 0xa20f) 687*a3cbbb47SArd Biesheuvel goto fail; 688*a3cbbb47SArd Biesheuvel 689*a3cbbb47SArd Biesheuvel leaf.fn = fn; 690*a3cbbb47SArd Biesheuvel leaf.subfn = subfn; 691*a3cbbb47SArd Biesheuvel 692*a3cbbb47SArd Biesheuvel ret = snp_cpuid(NULL, NULL, &leaf); 693*a3cbbb47SArd Biesheuvel if (!ret) 694*a3cbbb47SArd Biesheuvel goto cpuid_done; 695*a3cbbb47SArd Biesheuvel 696*a3cbbb47SArd Biesheuvel if (ret != -EOPNOTSUPP) 697*a3cbbb47SArd Biesheuvel goto fail; 698*a3cbbb47SArd Biesheuvel 699*a3cbbb47SArd Biesheuvel if (__sev_cpuid_hv_msr(&leaf)) 700*a3cbbb47SArd Biesheuvel goto fail; 701*a3cbbb47SArd Biesheuvel 702*a3cbbb47SArd Biesheuvel cpuid_done: 703*a3cbbb47SArd Biesheuvel regs->ax = leaf.eax; 704*a3cbbb47SArd Biesheuvel regs->bx = leaf.ebx; 705*a3cbbb47SArd Biesheuvel regs->cx = leaf.ecx; 706*a3cbbb47SArd Biesheuvel regs->dx = leaf.edx; 707*a3cbbb47SArd Biesheuvel 708*a3cbbb47SArd Biesheuvel /* 709*a3cbbb47SArd Biesheuvel * This is a VC handler and the #VC is only raised when SEV-ES is 710*a3cbbb47SArd Biesheuvel * active, which means SEV must be active too. Do sanity checks on the 711*a3cbbb47SArd Biesheuvel * CPUID results to make sure the hypervisor does not trick the kernel 712*a3cbbb47SArd Biesheuvel * into the no-sev path. This could map sensitive data unencrypted and 713*a3cbbb47SArd Biesheuvel * make it accessible to the hypervisor. 714*a3cbbb47SArd Biesheuvel * 715*a3cbbb47SArd Biesheuvel * In particular, check for: 716*a3cbbb47SArd Biesheuvel * - Availability of CPUID leaf 0x8000001f 717*a3cbbb47SArd Biesheuvel * - SEV CPUID bit. 718*a3cbbb47SArd Biesheuvel * 719*a3cbbb47SArd Biesheuvel * The hypervisor might still report the wrong C-bit position, but this 720*a3cbbb47SArd Biesheuvel * can't be checked here. 721*a3cbbb47SArd Biesheuvel */ 722*a3cbbb47SArd Biesheuvel 723*a3cbbb47SArd Biesheuvel if (fn == 0x80000000 && (regs->ax < 0x8000001f)) 724*a3cbbb47SArd Biesheuvel /* SEV leaf check */ 725*a3cbbb47SArd Biesheuvel goto fail; 726*a3cbbb47SArd Biesheuvel else if ((fn == 0x8000001f && !(regs->ax & BIT(1)))) 727*a3cbbb47SArd Biesheuvel /* SEV bit */ 728*a3cbbb47SArd Biesheuvel goto fail; 729*a3cbbb47SArd Biesheuvel 730*a3cbbb47SArd Biesheuvel /* Skip over the CPUID two-byte opcode */ 731*a3cbbb47SArd Biesheuvel regs->ip += 2; 732*a3cbbb47SArd Biesheuvel 733*a3cbbb47SArd Biesheuvel return; 734*a3cbbb47SArd Biesheuvel 735*a3cbbb47SArd Biesheuvel fail: 736*a3cbbb47SArd Biesheuvel /* Terminate the guest */ 737*a3cbbb47SArd Biesheuvel sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ); 738*a3cbbb47SArd Biesheuvel } 739*a3cbbb47SArd Biesheuvel 740*a3cbbb47SArd Biesheuvel static enum es_result vc_insn_string_check(struct es_em_ctxt *ctxt, 741*a3cbbb47SArd Biesheuvel unsigned long address, 742*a3cbbb47SArd Biesheuvel bool write) 743*a3cbbb47SArd Biesheuvel { 744*a3cbbb47SArd Biesheuvel if (user_mode(ctxt->regs) && fault_in_kernel_space(address)) { 745*a3cbbb47SArd Biesheuvel ctxt->fi.vector = X86_TRAP_PF; 746*a3cbbb47SArd Biesheuvel ctxt->fi.error_code = X86_PF_USER; 747*a3cbbb47SArd Biesheuvel ctxt->fi.cr2 = address; 748*a3cbbb47SArd Biesheuvel if (write) 749*a3cbbb47SArd Biesheuvel ctxt->fi.error_code |= X86_PF_WRITE; 750*a3cbbb47SArd Biesheuvel 751*a3cbbb47SArd Biesheuvel return ES_EXCEPTION; 752*a3cbbb47SArd Biesheuvel } 753*a3cbbb47SArd Biesheuvel 754*a3cbbb47SArd Biesheuvel return ES_OK; 755*a3cbbb47SArd Biesheuvel } 756*a3cbbb47SArd Biesheuvel 757*a3cbbb47SArd Biesheuvel static enum es_result vc_insn_string_read(struct es_em_ctxt *ctxt, 758*a3cbbb47SArd Biesheuvel void *src, char *buf, 759*a3cbbb47SArd Biesheuvel unsigned int data_size, 760*a3cbbb47SArd Biesheuvel unsigned int count, 761*a3cbbb47SArd Biesheuvel bool backwards) 762*a3cbbb47SArd Biesheuvel { 763*a3cbbb47SArd Biesheuvel int i, b = backwards ? -1 : 1; 764*a3cbbb47SArd Biesheuvel unsigned long address = (unsigned long)src; 765*a3cbbb47SArd Biesheuvel enum es_result ret; 766*a3cbbb47SArd Biesheuvel 767*a3cbbb47SArd Biesheuvel ret = vc_insn_string_check(ctxt, address, false); 768*a3cbbb47SArd Biesheuvel if (ret != ES_OK) 769*a3cbbb47SArd Biesheuvel return ret; 770*a3cbbb47SArd Biesheuvel 771*a3cbbb47SArd Biesheuvel for (i = 0; i < count; i++) { 772*a3cbbb47SArd Biesheuvel void *s = src + (i * data_size * b); 773*a3cbbb47SArd Biesheuvel char *d = buf + (i * data_size); 774*a3cbbb47SArd Biesheuvel 775*a3cbbb47SArd Biesheuvel ret = vc_read_mem(ctxt, s, d, data_size); 776*a3cbbb47SArd Biesheuvel if (ret != ES_OK) 777*a3cbbb47SArd Biesheuvel break; 778*a3cbbb47SArd Biesheuvel } 779*a3cbbb47SArd Biesheuvel 780*a3cbbb47SArd Biesheuvel return ret; 781*a3cbbb47SArd Biesheuvel } 782*a3cbbb47SArd Biesheuvel 783*a3cbbb47SArd Biesheuvel static enum es_result vc_insn_string_write(struct es_em_ctxt *ctxt, 784*a3cbbb47SArd Biesheuvel void *dst, char *buf, 785*a3cbbb47SArd Biesheuvel unsigned int data_size, 786*a3cbbb47SArd Biesheuvel unsigned int count, 787*a3cbbb47SArd Biesheuvel bool backwards) 788*a3cbbb47SArd Biesheuvel { 789*a3cbbb47SArd Biesheuvel int i, s = backwards ? -1 : 1; 790*a3cbbb47SArd Biesheuvel unsigned long address = (unsigned long)dst; 791*a3cbbb47SArd Biesheuvel enum es_result ret; 792*a3cbbb47SArd Biesheuvel 793*a3cbbb47SArd Biesheuvel ret = vc_insn_string_check(ctxt, address, true); 794*a3cbbb47SArd Biesheuvel if (ret != ES_OK) 795*a3cbbb47SArd Biesheuvel return ret; 796*a3cbbb47SArd Biesheuvel 797*a3cbbb47SArd Biesheuvel for (i = 0; i < count; i++) { 798*a3cbbb47SArd Biesheuvel void *d = dst + (i * data_size * s); 799*a3cbbb47SArd Biesheuvel char *b = buf + (i * data_size); 800*a3cbbb47SArd Biesheuvel 801*a3cbbb47SArd Biesheuvel ret = vc_write_mem(ctxt, d, b, data_size); 802*a3cbbb47SArd Biesheuvel if (ret != ES_OK) 803*a3cbbb47SArd Biesheuvel break; 804*a3cbbb47SArd Biesheuvel } 805*a3cbbb47SArd Biesheuvel 806*a3cbbb47SArd Biesheuvel return ret; 807*a3cbbb47SArd Biesheuvel } 808*a3cbbb47SArd Biesheuvel 809*a3cbbb47SArd Biesheuvel #define IOIO_TYPE_STR BIT(2) 810*a3cbbb47SArd Biesheuvel #define IOIO_TYPE_IN 1 811*a3cbbb47SArd Biesheuvel #define IOIO_TYPE_INS (IOIO_TYPE_IN | IOIO_TYPE_STR) 812*a3cbbb47SArd Biesheuvel #define IOIO_TYPE_OUT 0 813*a3cbbb47SArd Biesheuvel #define IOIO_TYPE_OUTS (IOIO_TYPE_OUT | IOIO_TYPE_STR) 814*a3cbbb47SArd Biesheuvel 815*a3cbbb47SArd Biesheuvel #define IOIO_REP BIT(3) 816*a3cbbb47SArd Biesheuvel 817*a3cbbb47SArd Biesheuvel #define IOIO_ADDR_64 BIT(9) 818*a3cbbb47SArd Biesheuvel #define IOIO_ADDR_32 BIT(8) 819*a3cbbb47SArd Biesheuvel #define IOIO_ADDR_16 BIT(7) 820*a3cbbb47SArd Biesheuvel 821*a3cbbb47SArd Biesheuvel #define IOIO_DATA_32 BIT(6) 822*a3cbbb47SArd Biesheuvel #define IOIO_DATA_16 BIT(5) 823*a3cbbb47SArd Biesheuvel #define IOIO_DATA_8 BIT(4) 824*a3cbbb47SArd Biesheuvel 825*a3cbbb47SArd Biesheuvel #define IOIO_SEG_ES (0 << 10) 826*a3cbbb47SArd Biesheuvel #define IOIO_SEG_DS (3 << 10) 827*a3cbbb47SArd Biesheuvel 828*a3cbbb47SArd Biesheuvel static enum es_result vc_ioio_exitinfo(struct es_em_ctxt *ctxt, u64 *exitinfo) 829*a3cbbb47SArd Biesheuvel { 830*a3cbbb47SArd Biesheuvel struct insn *insn = &ctxt->insn; 831*a3cbbb47SArd Biesheuvel size_t size; 832*a3cbbb47SArd Biesheuvel u64 port; 833*a3cbbb47SArd Biesheuvel 834*a3cbbb47SArd Biesheuvel *exitinfo = 0; 835*a3cbbb47SArd Biesheuvel 836*a3cbbb47SArd Biesheuvel switch (insn->opcode.bytes[0]) { 837*a3cbbb47SArd Biesheuvel /* INS opcodes */ 838*a3cbbb47SArd Biesheuvel case 0x6c: 839*a3cbbb47SArd Biesheuvel case 0x6d: 840*a3cbbb47SArd Biesheuvel *exitinfo |= IOIO_TYPE_INS; 841*a3cbbb47SArd Biesheuvel *exitinfo |= IOIO_SEG_ES; 842*a3cbbb47SArd Biesheuvel port = ctxt->regs->dx & 0xffff; 843*a3cbbb47SArd Biesheuvel break; 844*a3cbbb47SArd Biesheuvel 845*a3cbbb47SArd Biesheuvel /* OUTS opcodes */ 846*a3cbbb47SArd Biesheuvel case 0x6e: 847*a3cbbb47SArd Biesheuvel case 0x6f: 848*a3cbbb47SArd Biesheuvel *exitinfo |= IOIO_TYPE_OUTS; 849*a3cbbb47SArd Biesheuvel *exitinfo |= IOIO_SEG_DS; 850*a3cbbb47SArd Biesheuvel port = ctxt->regs->dx & 0xffff; 851*a3cbbb47SArd Biesheuvel break; 852*a3cbbb47SArd Biesheuvel 853*a3cbbb47SArd Biesheuvel /* IN immediate opcodes */ 854*a3cbbb47SArd Biesheuvel case 0xe4: 855*a3cbbb47SArd Biesheuvel case 0xe5: 856*a3cbbb47SArd Biesheuvel *exitinfo |= IOIO_TYPE_IN; 857*a3cbbb47SArd Biesheuvel port = (u8)insn->immediate.value & 0xffff; 858*a3cbbb47SArd Biesheuvel break; 859*a3cbbb47SArd Biesheuvel 860*a3cbbb47SArd Biesheuvel /* OUT immediate opcodes */ 861*a3cbbb47SArd Biesheuvel case 0xe6: 862*a3cbbb47SArd Biesheuvel case 0xe7: 863*a3cbbb47SArd Biesheuvel *exitinfo |= IOIO_TYPE_OUT; 864*a3cbbb47SArd Biesheuvel port = (u8)insn->immediate.value & 0xffff; 865*a3cbbb47SArd Biesheuvel break; 866*a3cbbb47SArd Biesheuvel 867*a3cbbb47SArd Biesheuvel /* IN register opcodes */ 868*a3cbbb47SArd Biesheuvel case 0xec: 869*a3cbbb47SArd Biesheuvel case 0xed: 870*a3cbbb47SArd Biesheuvel *exitinfo |= IOIO_TYPE_IN; 871*a3cbbb47SArd Biesheuvel port = ctxt->regs->dx & 0xffff; 872*a3cbbb47SArd Biesheuvel break; 873*a3cbbb47SArd Biesheuvel 874*a3cbbb47SArd Biesheuvel /* OUT register opcodes */ 875*a3cbbb47SArd Biesheuvel case 0xee: 876*a3cbbb47SArd Biesheuvel case 0xef: 877*a3cbbb47SArd Biesheuvel *exitinfo |= IOIO_TYPE_OUT; 878*a3cbbb47SArd Biesheuvel port = ctxt->regs->dx & 0xffff; 879*a3cbbb47SArd Biesheuvel break; 880*a3cbbb47SArd Biesheuvel 881*a3cbbb47SArd Biesheuvel default: 882*a3cbbb47SArd Biesheuvel return ES_DECODE_FAILED; 883*a3cbbb47SArd Biesheuvel } 884*a3cbbb47SArd Biesheuvel 885*a3cbbb47SArd Biesheuvel *exitinfo |= port << 16; 886*a3cbbb47SArd Biesheuvel 887*a3cbbb47SArd Biesheuvel switch (insn->opcode.bytes[0]) { 888*a3cbbb47SArd Biesheuvel case 0x6c: 889*a3cbbb47SArd Biesheuvel case 0x6e: 890*a3cbbb47SArd Biesheuvel case 0xe4: 891*a3cbbb47SArd Biesheuvel case 0xe6: 892*a3cbbb47SArd Biesheuvel case 0xec: 893*a3cbbb47SArd Biesheuvel case 0xee: 894*a3cbbb47SArd Biesheuvel /* Single byte opcodes */ 895*a3cbbb47SArd Biesheuvel *exitinfo |= IOIO_DATA_8; 896*a3cbbb47SArd Biesheuvel size = 1; 897*a3cbbb47SArd Biesheuvel break; 898*a3cbbb47SArd Biesheuvel default: 899*a3cbbb47SArd Biesheuvel /* Length determined by instruction parsing */ 900*a3cbbb47SArd Biesheuvel *exitinfo |= (insn->opnd_bytes == 2) ? IOIO_DATA_16 901*a3cbbb47SArd Biesheuvel : IOIO_DATA_32; 902*a3cbbb47SArd Biesheuvel size = (insn->opnd_bytes == 2) ? 2 : 4; 903*a3cbbb47SArd Biesheuvel } 904*a3cbbb47SArd Biesheuvel 905*a3cbbb47SArd Biesheuvel switch (insn->addr_bytes) { 906*a3cbbb47SArd Biesheuvel case 2: 907*a3cbbb47SArd Biesheuvel *exitinfo |= IOIO_ADDR_16; 908*a3cbbb47SArd Biesheuvel break; 909*a3cbbb47SArd Biesheuvel case 4: 910*a3cbbb47SArd Biesheuvel *exitinfo |= IOIO_ADDR_32; 911*a3cbbb47SArd Biesheuvel break; 912*a3cbbb47SArd Biesheuvel case 8: 913*a3cbbb47SArd Biesheuvel *exitinfo |= IOIO_ADDR_64; 914*a3cbbb47SArd Biesheuvel break; 915*a3cbbb47SArd Biesheuvel } 916*a3cbbb47SArd Biesheuvel 917*a3cbbb47SArd Biesheuvel if (insn_has_rep_prefix(insn)) 918*a3cbbb47SArd Biesheuvel *exitinfo |= IOIO_REP; 919*a3cbbb47SArd Biesheuvel 920*a3cbbb47SArd Biesheuvel return vc_ioio_check(ctxt, (u16)port, size); 921*a3cbbb47SArd Biesheuvel } 922*a3cbbb47SArd Biesheuvel 923*a3cbbb47SArd Biesheuvel static enum es_result vc_handle_ioio(struct ghcb *ghcb, struct es_em_ctxt *ctxt) 924*a3cbbb47SArd Biesheuvel { 925*a3cbbb47SArd Biesheuvel struct pt_regs *regs = ctxt->regs; 926*a3cbbb47SArd Biesheuvel u64 exit_info_1, exit_info_2; 927*a3cbbb47SArd Biesheuvel enum es_result ret; 928*a3cbbb47SArd Biesheuvel 929*a3cbbb47SArd Biesheuvel ret = vc_ioio_exitinfo(ctxt, &exit_info_1); 930*a3cbbb47SArd Biesheuvel if (ret != ES_OK) 931*a3cbbb47SArd Biesheuvel return ret; 932*a3cbbb47SArd Biesheuvel 933*a3cbbb47SArd Biesheuvel if (exit_info_1 & IOIO_TYPE_STR) { 934*a3cbbb47SArd Biesheuvel 935*a3cbbb47SArd Biesheuvel /* (REP) INS/OUTS */ 936*a3cbbb47SArd Biesheuvel 937*a3cbbb47SArd Biesheuvel bool df = ((regs->flags & X86_EFLAGS_DF) == X86_EFLAGS_DF); 938*a3cbbb47SArd Biesheuvel unsigned int io_bytes, exit_bytes; 939*a3cbbb47SArd Biesheuvel unsigned int ghcb_count, op_count; 940*a3cbbb47SArd Biesheuvel unsigned long es_base; 941*a3cbbb47SArd Biesheuvel u64 sw_scratch; 942*a3cbbb47SArd Biesheuvel 943*a3cbbb47SArd Biesheuvel /* 944*a3cbbb47SArd Biesheuvel * For the string variants with rep prefix the amount of in/out 945*a3cbbb47SArd Biesheuvel * operations per #VC exception is limited so that the kernel 946*a3cbbb47SArd Biesheuvel * has a chance to take interrupts and re-schedule while the 947*a3cbbb47SArd Biesheuvel * instruction is emulated. 948*a3cbbb47SArd Biesheuvel */ 949*a3cbbb47SArd Biesheuvel io_bytes = (exit_info_1 >> 4) & 0x7; 950*a3cbbb47SArd Biesheuvel ghcb_count = sizeof(ghcb->shared_buffer) / io_bytes; 951*a3cbbb47SArd Biesheuvel 952*a3cbbb47SArd Biesheuvel op_count = (exit_info_1 & IOIO_REP) ? regs->cx : 1; 953*a3cbbb47SArd Biesheuvel exit_info_2 = min(op_count, ghcb_count); 954*a3cbbb47SArd Biesheuvel exit_bytes = exit_info_2 * io_bytes; 955*a3cbbb47SArd Biesheuvel 956*a3cbbb47SArd Biesheuvel es_base = insn_get_seg_base(ctxt->regs, INAT_SEG_REG_ES); 957*a3cbbb47SArd Biesheuvel 958*a3cbbb47SArd Biesheuvel /* Read bytes of OUTS into the shared buffer */ 959*a3cbbb47SArd Biesheuvel if (!(exit_info_1 & IOIO_TYPE_IN)) { 960*a3cbbb47SArd Biesheuvel ret = vc_insn_string_read(ctxt, 961*a3cbbb47SArd Biesheuvel (void *)(es_base + regs->si), 962*a3cbbb47SArd Biesheuvel ghcb->shared_buffer, io_bytes, 963*a3cbbb47SArd Biesheuvel exit_info_2, df); 964*a3cbbb47SArd Biesheuvel if (ret) 965*a3cbbb47SArd Biesheuvel return ret; 966*a3cbbb47SArd Biesheuvel } 967*a3cbbb47SArd Biesheuvel 968*a3cbbb47SArd Biesheuvel /* 969*a3cbbb47SArd Biesheuvel * Issue an VMGEXIT to the HV to consume the bytes from the 970*a3cbbb47SArd Biesheuvel * shared buffer or to have it write them into the shared buffer 971*a3cbbb47SArd Biesheuvel * depending on the instruction: OUTS or INS. 972*a3cbbb47SArd Biesheuvel */ 973*a3cbbb47SArd Biesheuvel sw_scratch = __pa(ghcb) + offsetof(struct ghcb, shared_buffer); 974*a3cbbb47SArd Biesheuvel ghcb_set_sw_scratch(ghcb, sw_scratch); 975*a3cbbb47SArd Biesheuvel ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_IOIO, 976*a3cbbb47SArd Biesheuvel exit_info_1, exit_info_2); 977*a3cbbb47SArd Biesheuvel if (ret != ES_OK) 978*a3cbbb47SArd Biesheuvel return ret; 979*a3cbbb47SArd Biesheuvel 980*a3cbbb47SArd Biesheuvel /* Read bytes from shared buffer into the guest's destination. */ 981*a3cbbb47SArd Biesheuvel if (exit_info_1 & IOIO_TYPE_IN) { 982*a3cbbb47SArd Biesheuvel ret = vc_insn_string_write(ctxt, 983*a3cbbb47SArd Biesheuvel (void *)(es_base + regs->di), 984*a3cbbb47SArd Biesheuvel ghcb->shared_buffer, io_bytes, 985*a3cbbb47SArd Biesheuvel exit_info_2, df); 986*a3cbbb47SArd Biesheuvel if (ret) 987*a3cbbb47SArd Biesheuvel return ret; 988*a3cbbb47SArd Biesheuvel 989*a3cbbb47SArd Biesheuvel if (df) 990*a3cbbb47SArd Biesheuvel regs->di -= exit_bytes; 991*a3cbbb47SArd Biesheuvel else 992*a3cbbb47SArd Biesheuvel regs->di += exit_bytes; 993*a3cbbb47SArd Biesheuvel } else { 994*a3cbbb47SArd Biesheuvel if (df) 995*a3cbbb47SArd Biesheuvel regs->si -= exit_bytes; 996*a3cbbb47SArd Biesheuvel else 997*a3cbbb47SArd Biesheuvel regs->si += exit_bytes; 998*a3cbbb47SArd Biesheuvel } 999*a3cbbb47SArd Biesheuvel 1000*a3cbbb47SArd Biesheuvel if (exit_info_1 & IOIO_REP) 1001*a3cbbb47SArd Biesheuvel regs->cx -= exit_info_2; 1002*a3cbbb47SArd Biesheuvel 1003*a3cbbb47SArd Biesheuvel ret = regs->cx ? ES_RETRY : ES_OK; 1004*a3cbbb47SArd Biesheuvel 1005*a3cbbb47SArd Biesheuvel } else { 1006*a3cbbb47SArd Biesheuvel 1007*a3cbbb47SArd Biesheuvel /* IN/OUT into/from rAX */ 1008*a3cbbb47SArd Biesheuvel 1009*a3cbbb47SArd Biesheuvel int bits = (exit_info_1 & 0x70) >> 1; 1010*a3cbbb47SArd Biesheuvel u64 rax = 0; 1011*a3cbbb47SArd Biesheuvel 1012*a3cbbb47SArd Biesheuvel if (!(exit_info_1 & IOIO_TYPE_IN)) 1013*a3cbbb47SArd Biesheuvel rax = lower_bits(regs->ax, bits); 1014*a3cbbb47SArd Biesheuvel 1015*a3cbbb47SArd Biesheuvel ghcb_set_rax(ghcb, rax); 1016*a3cbbb47SArd Biesheuvel 1017*a3cbbb47SArd Biesheuvel ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_IOIO, exit_info_1, 0); 1018*a3cbbb47SArd Biesheuvel if (ret != ES_OK) 1019*a3cbbb47SArd Biesheuvel return ret; 1020*a3cbbb47SArd Biesheuvel 1021*a3cbbb47SArd Biesheuvel if (exit_info_1 & IOIO_TYPE_IN) { 1022*a3cbbb47SArd Biesheuvel if (!ghcb_rax_is_valid(ghcb)) 1023*a3cbbb47SArd Biesheuvel return ES_VMM_ERROR; 1024*a3cbbb47SArd Biesheuvel regs->ax = lower_bits(ghcb->save.rax, bits); 1025*a3cbbb47SArd Biesheuvel } 1026*a3cbbb47SArd Biesheuvel } 1027*a3cbbb47SArd Biesheuvel 1028*a3cbbb47SArd Biesheuvel return ret; 1029*a3cbbb47SArd Biesheuvel } 1030*a3cbbb47SArd Biesheuvel 1031*a3cbbb47SArd Biesheuvel static int vc_handle_cpuid_snp(struct ghcb *ghcb, struct es_em_ctxt *ctxt) 1032*a3cbbb47SArd Biesheuvel { 1033*a3cbbb47SArd Biesheuvel struct pt_regs *regs = ctxt->regs; 1034*a3cbbb47SArd Biesheuvel struct cpuid_leaf leaf; 1035*a3cbbb47SArd Biesheuvel int ret; 1036*a3cbbb47SArd Biesheuvel 1037*a3cbbb47SArd Biesheuvel leaf.fn = regs->ax; 1038*a3cbbb47SArd Biesheuvel leaf.subfn = regs->cx; 1039*a3cbbb47SArd Biesheuvel ret = snp_cpuid(ghcb, ctxt, &leaf); 1040*a3cbbb47SArd Biesheuvel if (!ret) { 1041*a3cbbb47SArd Biesheuvel regs->ax = leaf.eax; 1042*a3cbbb47SArd Biesheuvel regs->bx = leaf.ebx; 1043*a3cbbb47SArd Biesheuvel regs->cx = leaf.ecx; 1044*a3cbbb47SArd Biesheuvel regs->dx = leaf.edx; 1045*a3cbbb47SArd Biesheuvel } 1046*a3cbbb47SArd Biesheuvel 1047*a3cbbb47SArd Biesheuvel return ret; 1048*a3cbbb47SArd Biesheuvel } 1049*a3cbbb47SArd Biesheuvel 1050*a3cbbb47SArd Biesheuvel static enum es_result vc_handle_cpuid(struct ghcb *ghcb, 1051*a3cbbb47SArd Biesheuvel struct es_em_ctxt *ctxt) 1052*a3cbbb47SArd Biesheuvel { 1053*a3cbbb47SArd Biesheuvel struct pt_regs *regs = ctxt->regs; 1054*a3cbbb47SArd Biesheuvel u32 cr4 = native_read_cr4(); 1055*a3cbbb47SArd Biesheuvel enum es_result ret; 1056*a3cbbb47SArd Biesheuvel int snp_cpuid_ret; 1057*a3cbbb47SArd Biesheuvel 1058*a3cbbb47SArd Biesheuvel snp_cpuid_ret = vc_handle_cpuid_snp(ghcb, ctxt); 1059*a3cbbb47SArd Biesheuvel if (!snp_cpuid_ret) 1060*a3cbbb47SArd Biesheuvel return ES_OK; 1061*a3cbbb47SArd Biesheuvel if (snp_cpuid_ret != -EOPNOTSUPP) 1062*a3cbbb47SArd Biesheuvel return ES_VMM_ERROR; 1063*a3cbbb47SArd Biesheuvel 1064*a3cbbb47SArd Biesheuvel ghcb_set_rax(ghcb, regs->ax); 1065*a3cbbb47SArd Biesheuvel ghcb_set_rcx(ghcb, regs->cx); 1066*a3cbbb47SArd Biesheuvel 1067*a3cbbb47SArd Biesheuvel if (cr4 & X86_CR4_OSXSAVE) 1068*a3cbbb47SArd Biesheuvel /* Safe to read xcr0 */ 1069*a3cbbb47SArd Biesheuvel ghcb_set_xcr0(ghcb, xgetbv(XCR_XFEATURE_ENABLED_MASK)); 1070*a3cbbb47SArd Biesheuvel else 1071*a3cbbb47SArd Biesheuvel /* xgetbv will cause #GP - use reset value for xcr0 */ 1072*a3cbbb47SArd Biesheuvel ghcb_set_xcr0(ghcb, 1); 1073*a3cbbb47SArd Biesheuvel 1074*a3cbbb47SArd Biesheuvel ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_CPUID, 0, 0); 1075*a3cbbb47SArd Biesheuvel if (ret != ES_OK) 1076*a3cbbb47SArd Biesheuvel return ret; 1077*a3cbbb47SArd Biesheuvel 1078*a3cbbb47SArd Biesheuvel if (!(ghcb_rax_is_valid(ghcb) && 1079*a3cbbb47SArd Biesheuvel ghcb_rbx_is_valid(ghcb) && 1080*a3cbbb47SArd Biesheuvel ghcb_rcx_is_valid(ghcb) && 1081*a3cbbb47SArd Biesheuvel ghcb_rdx_is_valid(ghcb))) 1082*a3cbbb47SArd Biesheuvel return ES_VMM_ERROR; 1083*a3cbbb47SArd Biesheuvel 1084*a3cbbb47SArd Biesheuvel regs->ax = ghcb->save.rax; 1085*a3cbbb47SArd Biesheuvel regs->bx = ghcb->save.rbx; 1086*a3cbbb47SArd Biesheuvel regs->cx = ghcb->save.rcx; 1087*a3cbbb47SArd Biesheuvel regs->dx = ghcb->save.rdx; 1088*a3cbbb47SArd Biesheuvel 1089*a3cbbb47SArd Biesheuvel return ES_OK; 1090*a3cbbb47SArd Biesheuvel } 1091*a3cbbb47SArd Biesheuvel 1092*a3cbbb47SArd Biesheuvel static enum es_result vc_handle_rdtsc(struct ghcb *ghcb, 1093*a3cbbb47SArd Biesheuvel struct es_em_ctxt *ctxt, 1094*a3cbbb47SArd Biesheuvel unsigned long exit_code) 1095*a3cbbb47SArd Biesheuvel { 1096*a3cbbb47SArd Biesheuvel bool rdtscp = (exit_code == SVM_EXIT_RDTSCP); 1097*a3cbbb47SArd Biesheuvel enum es_result ret; 1098*a3cbbb47SArd Biesheuvel 1099*a3cbbb47SArd Biesheuvel /* 1100*a3cbbb47SArd Biesheuvel * The hypervisor should not be intercepting RDTSC/RDTSCP when Secure 1101*a3cbbb47SArd Biesheuvel * TSC is enabled. A #VC exception will be generated if the RDTSC/RDTSCP 1102*a3cbbb47SArd Biesheuvel * instructions are being intercepted. If this should occur and Secure 1103*a3cbbb47SArd Biesheuvel * TSC is enabled, guest execution should be terminated as the guest 1104*a3cbbb47SArd Biesheuvel * cannot rely on the TSC value provided by the hypervisor. 1105*a3cbbb47SArd Biesheuvel */ 1106*a3cbbb47SArd Biesheuvel if (sev_status & MSR_AMD64_SNP_SECURE_TSC) 1107*a3cbbb47SArd Biesheuvel return ES_VMM_ERROR; 1108*a3cbbb47SArd Biesheuvel 1109*a3cbbb47SArd Biesheuvel ret = sev_es_ghcb_hv_call(ghcb, ctxt, exit_code, 0, 0); 1110*a3cbbb47SArd Biesheuvel if (ret != ES_OK) 1111*a3cbbb47SArd Biesheuvel return ret; 1112*a3cbbb47SArd Biesheuvel 1113*a3cbbb47SArd Biesheuvel if (!(ghcb_rax_is_valid(ghcb) && ghcb_rdx_is_valid(ghcb) && 1114*a3cbbb47SArd Biesheuvel (!rdtscp || ghcb_rcx_is_valid(ghcb)))) 1115*a3cbbb47SArd Biesheuvel return ES_VMM_ERROR; 1116*a3cbbb47SArd Biesheuvel 1117*a3cbbb47SArd Biesheuvel ctxt->regs->ax = ghcb->save.rax; 1118*a3cbbb47SArd Biesheuvel ctxt->regs->dx = ghcb->save.rdx; 1119*a3cbbb47SArd Biesheuvel if (rdtscp) 1120*a3cbbb47SArd Biesheuvel ctxt->regs->cx = ghcb->save.rcx; 1121*a3cbbb47SArd Biesheuvel 1122*a3cbbb47SArd Biesheuvel return ES_OK; 1123*a3cbbb47SArd Biesheuvel } 1124*a3cbbb47SArd Biesheuvel 1125*a3cbbb47SArd Biesheuvel struct cc_setup_data { 1126*a3cbbb47SArd Biesheuvel struct setup_data header; 1127*a3cbbb47SArd Biesheuvel u32 cc_blob_address; 1128*a3cbbb47SArd Biesheuvel }; 1129*a3cbbb47SArd Biesheuvel 1130*a3cbbb47SArd Biesheuvel /* 1131*a3cbbb47SArd Biesheuvel * Search for a Confidential Computing blob passed in as a setup_data entry 1132*a3cbbb47SArd Biesheuvel * via the Linux Boot Protocol. 1133*a3cbbb47SArd Biesheuvel */ 1134*a3cbbb47SArd Biesheuvel static __head 1135*a3cbbb47SArd Biesheuvel struct cc_blob_sev_info *find_cc_blob_setup_data(struct boot_params *bp) 1136*a3cbbb47SArd Biesheuvel { 1137*a3cbbb47SArd Biesheuvel struct cc_setup_data *sd = NULL; 1138*a3cbbb47SArd Biesheuvel struct setup_data *hdr; 1139*a3cbbb47SArd Biesheuvel 1140*a3cbbb47SArd Biesheuvel hdr = (struct setup_data *)bp->hdr.setup_data; 1141*a3cbbb47SArd Biesheuvel 1142*a3cbbb47SArd Biesheuvel while (hdr) { 1143*a3cbbb47SArd Biesheuvel if (hdr->type == SETUP_CC_BLOB) { 1144*a3cbbb47SArd Biesheuvel sd = (struct cc_setup_data *)hdr; 1145*a3cbbb47SArd Biesheuvel return (struct cc_blob_sev_info *)(unsigned long)sd->cc_blob_address; 1146*a3cbbb47SArd Biesheuvel } 1147*a3cbbb47SArd Biesheuvel hdr = (struct setup_data *)hdr->next; 1148*a3cbbb47SArd Biesheuvel } 1149*a3cbbb47SArd Biesheuvel 1150*a3cbbb47SArd Biesheuvel return NULL; 1151*a3cbbb47SArd Biesheuvel } 1152*a3cbbb47SArd Biesheuvel 1153*a3cbbb47SArd Biesheuvel /* 1154*a3cbbb47SArd Biesheuvel * Initialize the kernel's copy of the SNP CPUID table, and set up the 1155*a3cbbb47SArd Biesheuvel * pointer that will be used to access it. 1156*a3cbbb47SArd Biesheuvel * 1157*a3cbbb47SArd Biesheuvel * Maintaining a direct mapping of the SNP CPUID table used by firmware would 1158*a3cbbb47SArd Biesheuvel * be possible as an alternative, but the approach is brittle since the 1159*a3cbbb47SArd Biesheuvel * mapping needs to be updated in sync with all the changes to virtual memory 1160*a3cbbb47SArd Biesheuvel * layout and related mapping facilities throughout the boot process. 1161*a3cbbb47SArd Biesheuvel */ 1162*a3cbbb47SArd Biesheuvel static void __head setup_cpuid_table(const struct cc_blob_sev_info *cc_info) 1163*a3cbbb47SArd Biesheuvel { 1164*a3cbbb47SArd Biesheuvel const struct snp_cpuid_table *cpuid_table_fw, *cpuid_table; 1165*a3cbbb47SArd Biesheuvel int i; 1166*a3cbbb47SArd Biesheuvel 1167*a3cbbb47SArd Biesheuvel if (!cc_info || !cc_info->cpuid_phys || cc_info->cpuid_len < PAGE_SIZE) 1168*a3cbbb47SArd Biesheuvel sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_CPUID); 1169*a3cbbb47SArd Biesheuvel 1170*a3cbbb47SArd Biesheuvel cpuid_table_fw = (const struct snp_cpuid_table *)cc_info->cpuid_phys; 1171*a3cbbb47SArd Biesheuvel if (!cpuid_table_fw->count || cpuid_table_fw->count > SNP_CPUID_COUNT_MAX) 1172*a3cbbb47SArd Biesheuvel sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_CPUID); 1173*a3cbbb47SArd Biesheuvel 1174*a3cbbb47SArd Biesheuvel cpuid_table = snp_cpuid_get_table(); 1175*a3cbbb47SArd Biesheuvel memcpy((void *)cpuid_table, cpuid_table_fw, sizeof(*cpuid_table)); 1176*a3cbbb47SArd Biesheuvel 1177*a3cbbb47SArd Biesheuvel /* Initialize CPUID ranges for range-checking. */ 1178*a3cbbb47SArd Biesheuvel for (i = 0; i < cpuid_table->count; i++) { 1179*a3cbbb47SArd Biesheuvel const struct snp_cpuid_fn *fn = &cpuid_table->fn[i]; 1180*a3cbbb47SArd Biesheuvel 1181*a3cbbb47SArd Biesheuvel if (fn->eax_in == 0x0) 1182*a3cbbb47SArd Biesheuvel RIP_REL_REF(cpuid_std_range_max) = fn->eax; 1183*a3cbbb47SArd Biesheuvel else if (fn->eax_in == 0x40000000) 1184*a3cbbb47SArd Biesheuvel RIP_REL_REF(cpuid_hyp_range_max) = fn->eax; 1185*a3cbbb47SArd Biesheuvel else if (fn->eax_in == 0x80000000) 1186*a3cbbb47SArd Biesheuvel RIP_REL_REF(cpuid_ext_range_max) = fn->eax; 1187*a3cbbb47SArd Biesheuvel } 1188*a3cbbb47SArd Biesheuvel } 1189*a3cbbb47SArd Biesheuvel 1190*a3cbbb47SArd Biesheuvel static void __head svsm_pval_4k_page(unsigned long paddr, bool validate) 1191*a3cbbb47SArd Biesheuvel { 1192*a3cbbb47SArd Biesheuvel struct svsm_pvalidate_call *pc; 1193*a3cbbb47SArd Biesheuvel struct svsm_call call = {}; 1194*a3cbbb47SArd Biesheuvel unsigned long flags; 1195*a3cbbb47SArd Biesheuvel u64 pc_pa; 1196*a3cbbb47SArd Biesheuvel int ret; 1197*a3cbbb47SArd Biesheuvel 1198*a3cbbb47SArd Biesheuvel /* 1199*a3cbbb47SArd Biesheuvel * This can be called very early in the boot, use native functions in 1200*a3cbbb47SArd Biesheuvel * order to avoid paravirt issues. 1201*a3cbbb47SArd Biesheuvel */ 1202*a3cbbb47SArd Biesheuvel flags = native_local_irq_save(); 1203*a3cbbb47SArd Biesheuvel 1204*a3cbbb47SArd Biesheuvel call.caa = svsm_get_caa(); 1205*a3cbbb47SArd Biesheuvel 1206*a3cbbb47SArd Biesheuvel pc = (struct svsm_pvalidate_call *)call.caa->svsm_buffer; 1207*a3cbbb47SArd Biesheuvel pc_pa = svsm_get_caa_pa() + offsetof(struct svsm_ca, svsm_buffer); 1208*a3cbbb47SArd Biesheuvel 1209*a3cbbb47SArd Biesheuvel pc->num_entries = 1; 1210*a3cbbb47SArd Biesheuvel pc->cur_index = 0; 1211*a3cbbb47SArd Biesheuvel pc->entry[0].page_size = RMP_PG_SIZE_4K; 1212*a3cbbb47SArd Biesheuvel pc->entry[0].action = validate; 1213*a3cbbb47SArd Biesheuvel pc->entry[0].ignore_cf = 0; 1214*a3cbbb47SArd Biesheuvel pc->entry[0].pfn = paddr >> PAGE_SHIFT; 1215*a3cbbb47SArd Biesheuvel 1216*a3cbbb47SArd Biesheuvel /* Protocol 0, Call ID 1 */ 1217*a3cbbb47SArd Biesheuvel call.rax = SVSM_CORE_CALL(SVSM_CORE_PVALIDATE); 1218*a3cbbb47SArd Biesheuvel call.rcx = pc_pa; 1219*a3cbbb47SArd Biesheuvel 1220*a3cbbb47SArd Biesheuvel ret = svsm_perform_call_protocol(&call); 1221*a3cbbb47SArd Biesheuvel if (ret) 1222*a3cbbb47SArd Biesheuvel sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PVALIDATE); 1223*a3cbbb47SArd Biesheuvel 1224*a3cbbb47SArd Biesheuvel native_local_irq_restore(flags); 1225*a3cbbb47SArd Biesheuvel } 1226*a3cbbb47SArd Biesheuvel 1227*a3cbbb47SArd Biesheuvel static void __head pvalidate_4k_page(unsigned long vaddr, unsigned long paddr, 1228*a3cbbb47SArd Biesheuvel bool validate) 1229*a3cbbb47SArd Biesheuvel { 1230*a3cbbb47SArd Biesheuvel int ret; 1231*a3cbbb47SArd Biesheuvel 1232*a3cbbb47SArd Biesheuvel /* 1233*a3cbbb47SArd Biesheuvel * This can be called very early during boot, so use rIP-relative 1234*a3cbbb47SArd Biesheuvel * references as needed. 1235*a3cbbb47SArd Biesheuvel */ 1236*a3cbbb47SArd Biesheuvel if (RIP_REL_REF(snp_vmpl)) { 1237*a3cbbb47SArd Biesheuvel svsm_pval_4k_page(paddr, validate); 1238*a3cbbb47SArd Biesheuvel } else { 1239*a3cbbb47SArd Biesheuvel ret = pvalidate(vaddr, RMP_PG_SIZE_4K, validate); 1240*a3cbbb47SArd Biesheuvel if (ret) 1241*a3cbbb47SArd Biesheuvel sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PVALIDATE); 1242*a3cbbb47SArd Biesheuvel } 1243*a3cbbb47SArd Biesheuvel } 1244*a3cbbb47SArd Biesheuvel 1245*a3cbbb47SArd Biesheuvel static enum es_result vc_check_opcode_bytes(struct es_em_ctxt *ctxt, 1246*a3cbbb47SArd Biesheuvel unsigned long exit_code) 1247*a3cbbb47SArd Biesheuvel { 1248*a3cbbb47SArd Biesheuvel unsigned int opcode = (unsigned int)ctxt->insn.opcode.value; 1249*a3cbbb47SArd Biesheuvel u8 modrm = ctxt->insn.modrm.value; 1250*a3cbbb47SArd Biesheuvel 1251*a3cbbb47SArd Biesheuvel switch (exit_code) { 1252*a3cbbb47SArd Biesheuvel 1253*a3cbbb47SArd Biesheuvel case SVM_EXIT_IOIO: 1254*a3cbbb47SArd Biesheuvel case SVM_EXIT_NPF: 1255*a3cbbb47SArd Biesheuvel /* handled separately */ 1256*a3cbbb47SArd Biesheuvel return ES_OK; 1257*a3cbbb47SArd Biesheuvel 1258*a3cbbb47SArd Biesheuvel case SVM_EXIT_CPUID: 1259*a3cbbb47SArd Biesheuvel if (opcode == 0xa20f) 1260*a3cbbb47SArd Biesheuvel return ES_OK; 1261*a3cbbb47SArd Biesheuvel break; 1262*a3cbbb47SArd Biesheuvel 1263*a3cbbb47SArd Biesheuvel case SVM_EXIT_INVD: 1264*a3cbbb47SArd Biesheuvel if (opcode == 0x080f) 1265*a3cbbb47SArd Biesheuvel return ES_OK; 1266*a3cbbb47SArd Biesheuvel break; 1267*a3cbbb47SArd Biesheuvel 1268*a3cbbb47SArd Biesheuvel case SVM_EXIT_MONITOR: 1269*a3cbbb47SArd Biesheuvel /* MONITOR and MONITORX instructions generate the same error code */ 1270*a3cbbb47SArd Biesheuvel if (opcode == 0x010f && (modrm == 0xc8 || modrm == 0xfa)) 1271*a3cbbb47SArd Biesheuvel return ES_OK; 1272*a3cbbb47SArd Biesheuvel break; 1273*a3cbbb47SArd Biesheuvel 1274*a3cbbb47SArd Biesheuvel case SVM_EXIT_MWAIT: 1275*a3cbbb47SArd Biesheuvel /* MWAIT and MWAITX instructions generate the same error code */ 1276*a3cbbb47SArd Biesheuvel if (opcode == 0x010f && (modrm == 0xc9 || modrm == 0xfb)) 1277*a3cbbb47SArd Biesheuvel return ES_OK; 1278*a3cbbb47SArd Biesheuvel break; 1279*a3cbbb47SArd Biesheuvel 1280*a3cbbb47SArd Biesheuvel case SVM_EXIT_MSR: 1281*a3cbbb47SArd Biesheuvel /* RDMSR */ 1282*a3cbbb47SArd Biesheuvel if (opcode == 0x320f || 1283*a3cbbb47SArd Biesheuvel /* WRMSR */ 1284*a3cbbb47SArd Biesheuvel opcode == 0x300f) 1285*a3cbbb47SArd Biesheuvel return ES_OK; 1286*a3cbbb47SArd Biesheuvel break; 1287*a3cbbb47SArd Biesheuvel 1288*a3cbbb47SArd Biesheuvel case SVM_EXIT_RDPMC: 1289*a3cbbb47SArd Biesheuvel if (opcode == 0x330f) 1290*a3cbbb47SArd Biesheuvel return ES_OK; 1291*a3cbbb47SArd Biesheuvel break; 1292*a3cbbb47SArd Biesheuvel 1293*a3cbbb47SArd Biesheuvel case SVM_EXIT_RDTSC: 1294*a3cbbb47SArd Biesheuvel if (opcode == 0x310f) 1295*a3cbbb47SArd Biesheuvel return ES_OK; 1296*a3cbbb47SArd Biesheuvel break; 1297*a3cbbb47SArd Biesheuvel 1298*a3cbbb47SArd Biesheuvel case SVM_EXIT_RDTSCP: 1299*a3cbbb47SArd Biesheuvel if (opcode == 0x010f && modrm == 0xf9) 1300*a3cbbb47SArd Biesheuvel return ES_OK; 1301*a3cbbb47SArd Biesheuvel break; 1302*a3cbbb47SArd Biesheuvel 1303*a3cbbb47SArd Biesheuvel case SVM_EXIT_READ_DR7: 1304*a3cbbb47SArd Biesheuvel if (opcode == 0x210f && 1305*a3cbbb47SArd Biesheuvel X86_MODRM_REG(ctxt->insn.modrm.value) == 7) 1306*a3cbbb47SArd Biesheuvel return ES_OK; 1307*a3cbbb47SArd Biesheuvel break; 1308*a3cbbb47SArd Biesheuvel 1309*a3cbbb47SArd Biesheuvel case SVM_EXIT_VMMCALL: 1310*a3cbbb47SArd Biesheuvel if (opcode == 0x010f && modrm == 0xd9) 1311*a3cbbb47SArd Biesheuvel return ES_OK; 1312*a3cbbb47SArd Biesheuvel 1313*a3cbbb47SArd Biesheuvel break; 1314*a3cbbb47SArd Biesheuvel 1315*a3cbbb47SArd Biesheuvel case SVM_EXIT_WRITE_DR7: 1316*a3cbbb47SArd Biesheuvel if (opcode == 0x230f && 1317*a3cbbb47SArd Biesheuvel X86_MODRM_REG(ctxt->insn.modrm.value) == 7) 1318*a3cbbb47SArd Biesheuvel return ES_OK; 1319*a3cbbb47SArd Biesheuvel break; 1320*a3cbbb47SArd Biesheuvel 1321*a3cbbb47SArd Biesheuvel case SVM_EXIT_WBINVD: 1322*a3cbbb47SArd Biesheuvel if (opcode == 0x90f) 1323*a3cbbb47SArd Biesheuvel return ES_OK; 1324*a3cbbb47SArd Biesheuvel break; 1325*a3cbbb47SArd Biesheuvel 1326*a3cbbb47SArd Biesheuvel default: 1327*a3cbbb47SArd Biesheuvel break; 1328*a3cbbb47SArd Biesheuvel } 1329*a3cbbb47SArd Biesheuvel 1330*a3cbbb47SArd Biesheuvel sev_printk(KERN_ERR "Wrong/unhandled opcode bytes: 0x%x, exit_code: 0x%lx, rIP: 0x%lx\n", 1331*a3cbbb47SArd Biesheuvel opcode, exit_code, ctxt->regs->ip); 1332*a3cbbb47SArd Biesheuvel 1333*a3cbbb47SArd Biesheuvel return ES_UNSUPPORTED; 1334*a3cbbb47SArd Biesheuvel } 1335*a3cbbb47SArd Biesheuvel 1336*a3cbbb47SArd Biesheuvel /* 1337*a3cbbb47SArd Biesheuvel * Maintain the GPA of the SVSM Calling Area (CA) in order to utilize the SVSM 1338*a3cbbb47SArd Biesheuvel * services needed when not running in VMPL0. 1339*a3cbbb47SArd Biesheuvel */ 1340*a3cbbb47SArd Biesheuvel static bool __head svsm_setup_ca(const struct cc_blob_sev_info *cc_info) 1341*a3cbbb47SArd Biesheuvel { 1342*a3cbbb47SArd Biesheuvel struct snp_secrets_page *secrets_page; 1343*a3cbbb47SArd Biesheuvel struct snp_cpuid_table *cpuid_table; 1344*a3cbbb47SArd Biesheuvel unsigned int i; 1345*a3cbbb47SArd Biesheuvel u64 caa; 1346*a3cbbb47SArd Biesheuvel 1347*a3cbbb47SArd Biesheuvel BUILD_BUG_ON(sizeof(*secrets_page) != PAGE_SIZE); 1348*a3cbbb47SArd Biesheuvel 1349*a3cbbb47SArd Biesheuvel /* 1350*a3cbbb47SArd Biesheuvel * Check if running at VMPL0. 1351*a3cbbb47SArd Biesheuvel * 1352*a3cbbb47SArd Biesheuvel * Use RMPADJUST (see the rmpadjust() function for a description of what 1353*a3cbbb47SArd Biesheuvel * the instruction does) to update the VMPL1 permissions of a page. If 1354*a3cbbb47SArd Biesheuvel * the guest is running at VMPL0, this will succeed and implies there is 1355*a3cbbb47SArd Biesheuvel * no SVSM. If the guest is running at any other VMPL, this will fail. 1356*a3cbbb47SArd Biesheuvel * Linux SNP guests only ever run at a single VMPL level so permission mask 1357*a3cbbb47SArd Biesheuvel * changes of a lesser-privileged VMPL are a don't-care. 1358*a3cbbb47SArd Biesheuvel * 1359*a3cbbb47SArd Biesheuvel * Use a rip-relative reference to obtain the proper address, since this 1360*a3cbbb47SArd Biesheuvel * routine is running identity mapped when called, both by the decompressor 1361*a3cbbb47SArd Biesheuvel * code and the early kernel code. 1362*a3cbbb47SArd Biesheuvel */ 1363*a3cbbb47SArd Biesheuvel if (!rmpadjust((unsigned long)rip_rel_ptr(&boot_ghcb_page), RMP_PG_SIZE_4K, 1)) 1364*a3cbbb47SArd Biesheuvel return false; 1365*a3cbbb47SArd Biesheuvel 1366*a3cbbb47SArd Biesheuvel /* 1367*a3cbbb47SArd Biesheuvel * Not running at VMPL0, ensure everything has been properly supplied 1368*a3cbbb47SArd Biesheuvel * for running under an SVSM. 1369*a3cbbb47SArd Biesheuvel */ 1370*a3cbbb47SArd Biesheuvel if (!cc_info || !cc_info->secrets_phys || cc_info->secrets_len != PAGE_SIZE) 1371*a3cbbb47SArd Biesheuvel sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_SECRETS_PAGE); 1372*a3cbbb47SArd Biesheuvel 1373*a3cbbb47SArd Biesheuvel secrets_page = (struct snp_secrets_page *)cc_info->secrets_phys; 1374*a3cbbb47SArd Biesheuvel if (!secrets_page->svsm_size) 1375*a3cbbb47SArd Biesheuvel sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_NO_SVSM); 1376*a3cbbb47SArd Biesheuvel 1377*a3cbbb47SArd Biesheuvel if (!secrets_page->svsm_guest_vmpl) 1378*a3cbbb47SArd Biesheuvel sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_SVSM_VMPL0); 1379*a3cbbb47SArd Biesheuvel 1380*a3cbbb47SArd Biesheuvel RIP_REL_REF(snp_vmpl) = secrets_page->svsm_guest_vmpl; 1381*a3cbbb47SArd Biesheuvel 1382*a3cbbb47SArd Biesheuvel caa = secrets_page->svsm_caa; 1383*a3cbbb47SArd Biesheuvel 1384*a3cbbb47SArd Biesheuvel /* 1385*a3cbbb47SArd Biesheuvel * An open-coded PAGE_ALIGNED() in order to avoid including 1386*a3cbbb47SArd Biesheuvel * kernel-proper headers into the decompressor. 1387*a3cbbb47SArd Biesheuvel */ 1388*a3cbbb47SArd Biesheuvel if (caa & (PAGE_SIZE - 1)) 1389*a3cbbb47SArd Biesheuvel sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_SVSM_CAA); 1390*a3cbbb47SArd Biesheuvel 1391*a3cbbb47SArd Biesheuvel /* 1392*a3cbbb47SArd Biesheuvel * The CA is identity mapped when this routine is called, both by the 1393*a3cbbb47SArd Biesheuvel * decompressor code and the early kernel code. 1394*a3cbbb47SArd Biesheuvel */ 1395*a3cbbb47SArd Biesheuvel RIP_REL_REF(boot_svsm_caa) = (struct svsm_ca *)caa; 1396*a3cbbb47SArd Biesheuvel RIP_REL_REF(boot_svsm_caa_pa) = caa; 1397*a3cbbb47SArd Biesheuvel 1398*a3cbbb47SArd Biesheuvel /* Advertise the SVSM presence via CPUID. */ 1399*a3cbbb47SArd Biesheuvel cpuid_table = (struct snp_cpuid_table *)snp_cpuid_get_table(); 1400*a3cbbb47SArd Biesheuvel for (i = 0; i < cpuid_table->count; i++) { 1401*a3cbbb47SArd Biesheuvel struct snp_cpuid_fn *fn = &cpuid_table->fn[i]; 1402*a3cbbb47SArd Biesheuvel 1403*a3cbbb47SArd Biesheuvel if (fn->eax_in == 0x8000001f) 1404*a3cbbb47SArd Biesheuvel fn->eax |= BIT(28); 1405*a3cbbb47SArd Biesheuvel } 1406*a3cbbb47SArd Biesheuvel 1407*a3cbbb47SArd Biesheuvel return true; 1408*a3cbbb47SArd Biesheuvel } 1409