1*a3cbbb47SArd Biesheuvel // SPDX-License-Identifier: GPL-2.0-only 2*a3cbbb47SArd Biesheuvel /* 3*a3cbbb47SArd Biesheuvel * AMD Memory Encryption Support 4*a3cbbb47SArd Biesheuvel * 5*a3cbbb47SArd Biesheuvel * Copyright (C) 2019 SUSE 6*a3cbbb47SArd Biesheuvel * 7*a3cbbb47SArd Biesheuvel * Author: Joerg Roedel <jroedel@suse.de> 8*a3cbbb47SArd Biesheuvel */ 9*a3cbbb47SArd Biesheuvel 10*a3cbbb47SArd Biesheuvel #define pr_fmt(fmt) "SEV: " fmt 11*a3cbbb47SArd Biesheuvel 12*a3cbbb47SArd Biesheuvel #include <linux/sched/debug.h> /* For show_regs() */ 13*a3cbbb47SArd Biesheuvel #include <linux/percpu-defs.h> 14*a3cbbb47SArd Biesheuvel #include <linux/cc_platform.h> 15*a3cbbb47SArd Biesheuvel #include <linux/printk.h> 16*a3cbbb47SArd Biesheuvel #include <linux/mm_types.h> 17*a3cbbb47SArd Biesheuvel #include <linux/set_memory.h> 18*a3cbbb47SArd Biesheuvel #include <linux/memblock.h> 19*a3cbbb47SArd Biesheuvel #include <linux/kernel.h> 20*a3cbbb47SArd Biesheuvel #include <linux/mm.h> 21*a3cbbb47SArd Biesheuvel #include <linux/cpumask.h> 22*a3cbbb47SArd Biesheuvel #include <linux/efi.h> 23*a3cbbb47SArd Biesheuvel #include <linux/io.h> 24*a3cbbb47SArd Biesheuvel #include <linux/psp-sev.h> 25*a3cbbb47SArd Biesheuvel #include <uapi/linux/sev-guest.h> 26*a3cbbb47SArd Biesheuvel 27*a3cbbb47SArd Biesheuvel #include <asm/init.h> 28*a3cbbb47SArd Biesheuvel #include <asm/cpu_entry_area.h> 29*a3cbbb47SArd Biesheuvel #include <asm/stacktrace.h> 30*a3cbbb47SArd Biesheuvel #include <asm/sev.h> 31*a3cbbb47SArd Biesheuvel #include <asm/sev-internal.h> 32*a3cbbb47SArd Biesheuvel #include <asm/insn-eval.h> 33*a3cbbb47SArd Biesheuvel #include <asm/fpu/xcr.h> 34*a3cbbb47SArd Biesheuvel #include <asm/processor.h> 35*a3cbbb47SArd Biesheuvel #include <asm/realmode.h> 36*a3cbbb47SArd Biesheuvel #include <asm/setup.h> 37*a3cbbb47SArd Biesheuvel #include <asm/traps.h> 38*a3cbbb47SArd Biesheuvel #include <asm/svm.h> 39*a3cbbb47SArd Biesheuvel #include <asm/smp.h> 40*a3cbbb47SArd Biesheuvel #include <asm/cpu.h> 41*a3cbbb47SArd Biesheuvel #include <asm/apic.h> 42*a3cbbb47SArd Biesheuvel #include <asm/cpuid.h> 43*a3cbbb47SArd Biesheuvel #include <asm/cmdline.h> 44*a3cbbb47SArd Biesheuvel 45*a3cbbb47SArd Biesheuvel /* For early boot hypervisor communication in SEV-ES enabled guests */ 46*a3cbbb47SArd Biesheuvel struct ghcb boot_ghcb_page __bss_decrypted __aligned(PAGE_SIZE); 47*a3cbbb47SArd Biesheuvel 48*a3cbbb47SArd Biesheuvel /* 49*a3cbbb47SArd Biesheuvel * Needs to be in the .data section because we need it NULL before bss is 50*a3cbbb47SArd Biesheuvel * cleared 51*a3cbbb47SArd Biesheuvel */ 52*a3cbbb47SArd Biesheuvel struct ghcb *boot_ghcb __section(".data"); 53*a3cbbb47SArd Biesheuvel 54*a3cbbb47SArd Biesheuvel /* Bitmap of SEV features supported by the hypervisor */ 55*a3cbbb47SArd Biesheuvel u64 sev_hv_features __ro_after_init; 56*a3cbbb47SArd Biesheuvel 57*a3cbbb47SArd Biesheuvel /* Secrets page physical address from the CC blob */ 58*a3cbbb47SArd Biesheuvel static u64 secrets_pa __ro_after_init; 59*a3cbbb47SArd Biesheuvel 60*a3cbbb47SArd Biesheuvel /* For early boot SVSM communication */ 61*a3cbbb47SArd Biesheuvel struct svsm_ca boot_svsm_ca_page __aligned(PAGE_SIZE); 62*a3cbbb47SArd Biesheuvel 63*a3cbbb47SArd Biesheuvel DEFINE_PER_CPU(struct svsm_ca *, svsm_caa); 64*a3cbbb47SArd Biesheuvel DEFINE_PER_CPU(u64, svsm_caa_pa); 65*a3cbbb47SArd Biesheuvel 66*a3cbbb47SArd Biesheuvel /* 67*a3cbbb47SArd Biesheuvel * Nothing shall interrupt this code path while holding the per-CPU 68*a3cbbb47SArd Biesheuvel * GHCB. The backup GHCB is only for NMIs interrupting this path. 69*a3cbbb47SArd Biesheuvel * 70*a3cbbb47SArd Biesheuvel * Callers must disable local interrupts around it. 71*a3cbbb47SArd Biesheuvel */ 72*a3cbbb47SArd Biesheuvel noinstr struct ghcb *__sev_get_ghcb(struct ghcb_state *state) 73*a3cbbb47SArd Biesheuvel { 74*a3cbbb47SArd Biesheuvel struct sev_es_runtime_data *data; 75*a3cbbb47SArd Biesheuvel struct ghcb *ghcb; 76*a3cbbb47SArd Biesheuvel 77*a3cbbb47SArd Biesheuvel WARN_ON(!irqs_disabled()); 78*a3cbbb47SArd Biesheuvel 79*a3cbbb47SArd Biesheuvel data = this_cpu_read(runtime_data); 80*a3cbbb47SArd Biesheuvel ghcb = &data->ghcb_page; 81*a3cbbb47SArd Biesheuvel 82*a3cbbb47SArd Biesheuvel if (unlikely(data->ghcb_active)) { 83*a3cbbb47SArd Biesheuvel /* GHCB is already in use - save its contents */ 84*a3cbbb47SArd Biesheuvel 85*a3cbbb47SArd Biesheuvel if (unlikely(data->backup_ghcb_active)) { 86*a3cbbb47SArd Biesheuvel /* 87*a3cbbb47SArd Biesheuvel * Backup-GHCB is also already in use. There is no way 88*a3cbbb47SArd Biesheuvel * to continue here so just kill the machine. To make 89*a3cbbb47SArd Biesheuvel * panic() work, mark GHCBs inactive so that messages 90*a3cbbb47SArd Biesheuvel * can be printed out. 91*a3cbbb47SArd Biesheuvel */ 92*a3cbbb47SArd Biesheuvel data->ghcb_active = false; 93*a3cbbb47SArd Biesheuvel data->backup_ghcb_active = false; 94*a3cbbb47SArd Biesheuvel 95*a3cbbb47SArd Biesheuvel instrumentation_begin(); 96*a3cbbb47SArd Biesheuvel panic("Unable to handle #VC exception! GHCB and Backup GHCB are already in use"); 97*a3cbbb47SArd Biesheuvel instrumentation_end(); 98*a3cbbb47SArd Biesheuvel } 99*a3cbbb47SArd Biesheuvel 100*a3cbbb47SArd Biesheuvel /* Mark backup_ghcb active before writing to it */ 101*a3cbbb47SArd Biesheuvel data->backup_ghcb_active = true; 102*a3cbbb47SArd Biesheuvel 103*a3cbbb47SArd Biesheuvel state->ghcb = &data->backup_ghcb; 104*a3cbbb47SArd Biesheuvel 105*a3cbbb47SArd Biesheuvel /* Backup GHCB content */ 106*a3cbbb47SArd Biesheuvel *state->ghcb = *ghcb; 107*a3cbbb47SArd Biesheuvel } else { 108*a3cbbb47SArd Biesheuvel state->ghcb = NULL; 109*a3cbbb47SArd Biesheuvel data->ghcb_active = true; 110*a3cbbb47SArd Biesheuvel } 111*a3cbbb47SArd Biesheuvel 112*a3cbbb47SArd Biesheuvel return ghcb; 113*a3cbbb47SArd Biesheuvel } 114*a3cbbb47SArd Biesheuvel 115*a3cbbb47SArd Biesheuvel static int vc_fetch_insn_kernel(struct es_em_ctxt *ctxt, 116*a3cbbb47SArd Biesheuvel unsigned char *buffer) 117*a3cbbb47SArd Biesheuvel { 118*a3cbbb47SArd Biesheuvel return copy_from_kernel_nofault(buffer, (unsigned char *)ctxt->regs->ip, MAX_INSN_SIZE); 119*a3cbbb47SArd Biesheuvel } 120*a3cbbb47SArd Biesheuvel 121*a3cbbb47SArd Biesheuvel static enum es_result __vc_decode_user_insn(struct es_em_ctxt *ctxt) 122*a3cbbb47SArd Biesheuvel { 123*a3cbbb47SArd Biesheuvel char buffer[MAX_INSN_SIZE]; 124*a3cbbb47SArd Biesheuvel int insn_bytes; 125*a3cbbb47SArd Biesheuvel 126*a3cbbb47SArd Biesheuvel insn_bytes = insn_fetch_from_user_inatomic(ctxt->regs, buffer); 127*a3cbbb47SArd Biesheuvel if (insn_bytes == 0) { 128*a3cbbb47SArd Biesheuvel /* Nothing could be copied */ 129*a3cbbb47SArd Biesheuvel ctxt->fi.vector = X86_TRAP_PF; 130*a3cbbb47SArd Biesheuvel ctxt->fi.error_code = X86_PF_INSTR | X86_PF_USER; 131*a3cbbb47SArd Biesheuvel ctxt->fi.cr2 = ctxt->regs->ip; 132*a3cbbb47SArd Biesheuvel return ES_EXCEPTION; 133*a3cbbb47SArd Biesheuvel } else if (insn_bytes == -EINVAL) { 134*a3cbbb47SArd Biesheuvel /* Effective RIP could not be calculated */ 135*a3cbbb47SArd Biesheuvel ctxt->fi.vector = X86_TRAP_GP; 136*a3cbbb47SArd Biesheuvel ctxt->fi.error_code = 0; 137*a3cbbb47SArd Biesheuvel ctxt->fi.cr2 = 0; 138*a3cbbb47SArd Biesheuvel return ES_EXCEPTION; 139*a3cbbb47SArd Biesheuvel } 140*a3cbbb47SArd Biesheuvel 141*a3cbbb47SArd Biesheuvel if (!insn_decode_from_regs(&ctxt->insn, ctxt->regs, buffer, insn_bytes)) 142*a3cbbb47SArd Biesheuvel return ES_DECODE_FAILED; 143*a3cbbb47SArd Biesheuvel 144*a3cbbb47SArd Biesheuvel if (ctxt->insn.immediate.got) 145*a3cbbb47SArd Biesheuvel return ES_OK; 146*a3cbbb47SArd Biesheuvel else 147*a3cbbb47SArd Biesheuvel return ES_DECODE_FAILED; 148*a3cbbb47SArd Biesheuvel } 149*a3cbbb47SArd Biesheuvel 150*a3cbbb47SArd Biesheuvel static enum es_result __vc_decode_kern_insn(struct es_em_ctxt *ctxt) 151*a3cbbb47SArd Biesheuvel { 152*a3cbbb47SArd Biesheuvel char buffer[MAX_INSN_SIZE]; 153*a3cbbb47SArd Biesheuvel int res, ret; 154*a3cbbb47SArd Biesheuvel 155*a3cbbb47SArd Biesheuvel res = vc_fetch_insn_kernel(ctxt, buffer); 156*a3cbbb47SArd Biesheuvel if (res) { 157*a3cbbb47SArd Biesheuvel ctxt->fi.vector = X86_TRAP_PF; 158*a3cbbb47SArd Biesheuvel ctxt->fi.error_code = X86_PF_INSTR; 159*a3cbbb47SArd Biesheuvel ctxt->fi.cr2 = ctxt->regs->ip; 160*a3cbbb47SArd Biesheuvel return ES_EXCEPTION; 161*a3cbbb47SArd Biesheuvel } 162*a3cbbb47SArd Biesheuvel 163*a3cbbb47SArd Biesheuvel ret = insn_decode(&ctxt->insn, buffer, MAX_INSN_SIZE, INSN_MODE_64); 164*a3cbbb47SArd Biesheuvel if (ret < 0) 165*a3cbbb47SArd Biesheuvel return ES_DECODE_FAILED; 166*a3cbbb47SArd Biesheuvel else 167*a3cbbb47SArd Biesheuvel return ES_OK; 168*a3cbbb47SArd Biesheuvel } 169*a3cbbb47SArd Biesheuvel 170*a3cbbb47SArd Biesheuvel static enum es_result vc_decode_insn(struct es_em_ctxt *ctxt) 171*a3cbbb47SArd Biesheuvel { 172*a3cbbb47SArd Biesheuvel if (user_mode(ctxt->regs)) 173*a3cbbb47SArd Biesheuvel return __vc_decode_user_insn(ctxt); 174*a3cbbb47SArd Biesheuvel else 175*a3cbbb47SArd Biesheuvel return __vc_decode_kern_insn(ctxt); 176*a3cbbb47SArd Biesheuvel } 177*a3cbbb47SArd Biesheuvel 178*a3cbbb47SArd Biesheuvel static enum es_result vc_write_mem(struct es_em_ctxt *ctxt, 179*a3cbbb47SArd Biesheuvel char *dst, char *buf, size_t size) 180*a3cbbb47SArd Biesheuvel { 181*a3cbbb47SArd Biesheuvel unsigned long error_code = X86_PF_PROT | X86_PF_WRITE; 182*a3cbbb47SArd Biesheuvel 183*a3cbbb47SArd Biesheuvel /* 184*a3cbbb47SArd Biesheuvel * This function uses __put_user() independent of whether kernel or user 185*a3cbbb47SArd Biesheuvel * memory is accessed. This works fine because __put_user() does no 186*a3cbbb47SArd Biesheuvel * sanity checks of the pointer being accessed. All that it does is 187*a3cbbb47SArd Biesheuvel * to report when the access failed. 188*a3cbbb47SArd Biesheuvel * 189*a3cbbb47SArd Biesheuvel * Also, this function runs in atomic context, so __put_user() is not 190*a3cbbb47SArd Biesheuvel * allowed to sleep. The page-fault handler detects that it is running 191*a3cbbb47SArd Biesheuvel * in atomic context and will not try to take mmap_sem and handle the 192*a3cbbb47SArd Biesheuvel * fault, so additional pagefault_enable()/disable() calls are not 193*a3cbbb47SArd Biesheuvel * needed. 194*a3cbbb47SArd Biesheuvel * 195*a3cbbb47SArd Biesheuvel * The access can't be done via copy_to_user() here because 196*a3cbbb47SArd Biesheuvel * vc_write_mem() must not use string instructions to access unsafe 197*a3cbbb47SArd Biesheuvel * memory. The reason is that MOVS is emulated by the #VC handler by 198*a3cbbb47SArd Biesheuvel * splitting the move up into a read and a write and taking a nested #VC 199*a3cbbb47SArd Biesheuvel * exception on whatever of them is the MMIO access. Using string 200*a3cbbb47SArd Biesheuvel * instructions here would cause infinite nesting. 201*a3cbbb47SArd Biesheuvel */ 202*a3cbbb47SArd Biesheuvel switch (size) { 203*a3cbbb47SArd Biesheuvel case 1: { 204*a3cbbb47SArd Biesheuvel u8 d1; 205*a3cbbb47SArd Biesheuvel u8 __user *target = (u8 __user *)dst; 206*a3cbbb47SArd Biesheuvel 207*a3cbbb47SArd Biesheuvel memcpy(&d1, buf, 1); 208*a3cbbb47SArd Biesheuvel if (__put_user(d1, target)) 209*a3cbbb47SArd Biesheuvel goto fault; 210*a3cbbb47SArd Biesheuvel break; 211*a3cbbb47SArd Biesheuvel } 212*a3cbbb47SArd Biesheuvel case 2: { 213*a3cbbb47SArd Biesheuvel u16 d2; 214*a3cbbb47SArd Biesheuvel u16 __user *target = (u16 __user *)dst; 215*a3cbbb47SArd Biesheuvel 216*a3cbbb47SArd Biesheuvel memcpy(&d2, buf, 2); 217*a3cbbb47SArd Biesheuvel if (__put_user(d2, target)) 218*a3cbbb47SArd Biesheuvel goto fault; 219*a3cbbb47SArd Biesheuvel break; 220*a3cbbb47SArd Biesheuvel } 221*a3cbbb47SArd Biesheuvel case 4: { 222*a3cbbb47SArd Biesheuvel u32 d4; 223*a3cbbb47SArd Biesheuvel u32 __user *target = (u32 __user *)dst; 224*a3cbbb47SArd Biesheuvel 225*a3cbbb47SArd Biesheuvel memcpy(&d4, buf, 4); 226*a3cbbb47SArd Biesheuvel if (__put_user(d4, target)) 227*a3cbbb47SArd Biesheuvel goto fault; 228*a3cbbb47SArd Biesheuvel break; 229*a3cbbb47SArd Biesheuvel } 230*a3cbbb47SArd Biesheuvel case 8: { 231*a3cbbb47SArd Biesheuvel u64 d8; 232*a3cbbb47SArd Biesheuvel u64 __user *target = (u64 __user *)dst; 233*a3cbbb47SArd Biesheuvel 234*a3cbbb47SArd Biesheuvel memcpy(&d8, buf, 8); 235*a3cbbb47SArd Biesheuvel if (__put_user(d8, target)) 236*a3cbbb47SArd Biesheuvel goto fault; 237*a3cbbb47SArd Biesheuvel break; 238*a3cbbb47SArd Biesheuvel } 239*a3cbbb47SArd Biesheuvel default: 240*a3cbbb47SArd Biesheuvel WARN_ONCE(1, "%s: Invalid size: %zu\n", __func__, size); 241*a3cbbb47SArd Biesheuvel return ES_UNSUPPORTED; 242*a3cbbb47SArd Biesheuvel } 243*a3cbbb47SArd Biesheuvel 244*a3cbbb47SArd Biesheuvel return ES_OK; 245*a3cbbb47SArd Biesheuvel 246*a3cbbb47SArd Biesheuvel fault: 247*a3cbbb47SArd Biesheuvel if (user_mode(ctxt->regs)) 248*a3cbbb47SArd Biesheuvel error_code |= X86_PF_USER; 249*a3cbbb47SArd Biesheuvel 250*a3cbbb47SArd Biesheuvel ctxt->fi.vector = X86_TRAP_PF; 251*a3cbbb47SArd Biesheuvel ctxt->fi.error_code = error_code; 252*a3cbbb47SArd Biesheuvel ctxt->fi.cr2 = (unsigned long)dst; 253*a3cbbb47SArd Biesheuvel 254*a3cbbb47SArd Biesheuvel return ES_EXCEPTION; 255*a3cbbb47SArd Biesheuvel } 256*a3cbbb47SArd Biesheuvel 257*a3cbbb47SArd Biesheuvel static enum es_result vc_read_mem(struct es_em_ctxt *ctxt, 258*a3cbbb47SArd Biesheuvel char *src, char *buf, size_t size) 259*a3cbbb47SArd Biesheuvel { 260*a3cbbb47SArd Biesheuvel unsigned long error_code = X86_PF_PROT; 261*a3cbbb47SArd Biesheuvel 262*a3cbbb47SArd Biesheuvel /* 263*a3cbbb47SArd Biesheuvel * This function uses __get_user() independent of whether kernel or user 264*a3cbbb47SArd Biesheuvel * memory is accessed. This works fine because __get_user() does no 265*a3cbbb47SArd Biesheuvel * sanity checks of the pointer being accessed. All that it does is 266*a3cbbb47SArd Biesheuvel * to report when the access failed. 267*a3cbbb47SArd Biesheuvel * 268*a3cbbb47SArd Biesheuvel * Also, this function runs in atomic context, so __get_user() is not 269*a3cbbb47SArd Biesheuvel * allowed to sleep. The page-fault handler detects that it is running 270*a3cbbb47SArd Biesheuvel * in atomic context and will not try to take mmap_sem and handle the 271*a3cbbb47SArd Biesheuvel * fault, so additional pagefault_enable()/disable() calls are not 272*a3cbbb47SArd Biesheuvel * needed. 273*a3cbbb47SArd Biesheuvel * 274*a3cbbb47SArd Biesheuvel * The access can't be done via copy_from_user() here because 275*a3cbbb47SArd Biesheuvel * vc_read_mem() must not use string instructions to access unsafe 276*a3cbbb47SArd Biesheuvel * memory. The reason is that MOVS is emulated by the #VC handler by 277*a3cbbb47SArd Biesheuvel * splitting the move up into a read and a write and taking a nested #VC 278*a3cbbb47SArd Biesheuvel * exception on whatever of them is the MMIO access. Using string 279*a3cbbb47SArd Biesheuvel * instructions here would cause infinite nesting. 280*a3cbbb47SArd Biesheuvel */ 281*a3cbbb47SArd Biesheuvel switch (size) { 282*a3cbbb47SArd Biesheuvel case 1: { 283*a3cbbb47SArd Biesheuvel u8 d1; 284*a3cbbb47SArd Biesheuvel u8 __user *s = (u8 __user *)src; 285*a3cbbb47SArd Biesheuvel 286*a3cbbb47SArd Biesheuvel if (__get_user(d1, s)) 287*a3cbbb47SArd Biesheuvel goto fault; 288*a3cbbb47SArd Biesheuvel memcpy(buf, &d1, 1); 289*a3cbbb47SArd Biesheuvel break; 290*a3cbbb47SArd Biesheuvel } 291*a3cbbb47SArd Biesheuvel case 2: { 292*a3cbbb47SArd Biesheuvel u16 d2; 293*a3cbbb47SArd Biesheuvel u16 __user *s = (u16 __user *)src; 294*a3cbbb47SArd Biesheuvel 295*a3cbbb47SArd Biesheuvel if (__get_user(d2, s)) 296*a3cbbb47SArd Biesheuvel goto fault; 297*a3cbbb47SArd Biesheuvel memcpy(buf, &d2, 2); 298*a3cbbb47SArd Biesheuvel break; 299*a3cbbb47SArd Biesheuvel } 300*a3cbbb47SArd Biesheuvel case 4: { 301*a3cbbb47SArd Biesheuvel u32 d4; 302*a3cbbb47SArd Biesheuvel u32 __user *s = (u32 __user *)src; 303*a3cbbb47SArd Biesheuvel 304*a3cbbb47SArd Biesheuvel if (__get_user(d4, s)) 305*a3cbbb47SArd Biesheuvel goto fault; 306*a3cbbb47SArd Biesheuvel memcpy(buf, &d4, 4); 307*a3cbbb47SArd Biesheuvel break; 308*a3cbbb47SArd Biesheuvel } 309*a3cbbb47SArd Biesheuvel case 8: { 310*a3cbbb47SArd Biesheuvel u64 d8; 311*a3cbbb47SArd Biesheuvel u64 __user *s = (u64 __user *)src; 312*a3cbbb47SArd Biesheuvel if (__get_user(d8, s)) 313*a3cbbb47SArd Biesheuvel goto fault; 314*a3cbbb47SArd Biesheuvel memcpy(buf, &d8, 8); 315*a3cbbb47SArd Biesheuvel break; 316*a3cbbb47SArd Biesheuvel } 317*a3cbbb47SArd Biesheuvel default: 318*a3cbbb47SArd Biesheuvel WARN_ONCE(1, "%s: Invalid size: %zu\n", __func__, size); 319*a3cbbb47SArd Biesheuvel return ES_UNSUPPORTED; 320*a3cbbb47SArd Biesheuvel } 321*a3cbbb47SArd Biesheuvel 322*a3cbbb47SArd Biesheuvel return ES_OK; 323*a3cbbb47SArd Biesheuvel 324*a3cbbb47SArd Biesheuvel fault: 325*a3cbbb47SArd Biesheuvel if (user_mode(ctxt->regs)) 326*a3cbbb47SArd Biesheuvel error_code |= X86_PF_USER; 327*a3cbbb47SArd Biesheuvel 328*a3cbbb47SArd Biesheuvel ctxt->fi.vector = X86_TRAP_PF; 329*a3cbbb47SArd Biesheuvel ctxt->fi.error_code = error_code; 330*a3cbbb47SArd Biesheuvel ctxt->fi.cr2 = (unsigned long)src; 331*a3cbbb47SArd Biesheuvel 332*a3cbbb47SArd Biesheuvel return ES_EXCEPTION; 333*a3cbbb47SArd Biesheuvel } 334*a3cbbb47SArd Biesheuvel 335*a3cbbb47SArd Biesheuvel static enum es_result vc_slow_virt_to_phys(struct ghcb *ghcb, struct es_em_ctxt *ctxt, 336*a3cbbb47SArd Biesheuvel unsigned long vaddr, phys_addr_t *paddr) 337*a3cbbb47SArd Biesheuvel { 338*a3cbbb47SArd Biesheuvel unsigned long va = (unsigned long)vaddr; 339*a3cbbb47SArd Biesheuvel unsigned int level; 340*a3cbbb47SArd Biesheuvel phys_addr_t pa; 341*a3cbbb47SArd Biesheuvel pgd_t *pgd; 342*a3cbbb47SArd Biesheuvel pte_t *pte; 343*a3cbbb47SArd Biesheuvel 344*a3cbbb47SArd Biesheuvel pgd = __va(read_cr3_pa()); 345*a3cbbb47SArd Biesheuvel pgd = &pgd[pgd_index(va)]; 346*a3cbbb47SArd Biesheuvel pte = lookup_address_in_pgd(pgd, va, &level); 347*a3cbbb47SArd Biesheuvel if (!pte) { 348*a3cbbb47SArd Biesheuvel ctxt->fi.vector = X86_TRAP_PF; 349*a3cbbb47SArd Biesheuvel ctxt->fi.cr2 = vaddr; 350*a3cbbb47SArd Biesheuvel ctxt->fi.error_code = 0; 351*a3cbbb47SArd Biesheuvel 352*a3cbbb47SArd Biesheuvel if (user_mode(ctxt->regs)) 353*a3cbbb47SArd Biesheuvel ctxt->fi.error_code |= X86_PF_USER; 354*a3cbbb47SArd Biesheuvel 355*a3cbbb47SArd Biesheuvel return ES_EXCEPTION; 356*a3cbbb47SArd Biesheuvel } 357*a3cbbb47SArd Biesheuvel 358*a3cbbb47SArd Biesheuvel if (WARN_ON_ONCE(pte_val(*pte) & _PAGE_ENC)) 359*a3cbbb47SArd Biesheuvel /* Emulated MMIO to/from encrypted memory not supported */ 360*a3cbbb47SArd Biesheuvel return ES_UNSUPPORTED; 361*a3cbbb47SArd Biesheuvel 362*a3cbbb47SArd Biesheuvel pa = (phys_addr_t)pte_pfn(*pte) << PAGE_SHIFT; 363*a3cbbb47SArd Biesheuvel pa |= va & ~page_level_mask(level); 364*a3cbbb47SArd Biesheuvel 365*a3cbbb47SArd Biesheuvel *paddr = pa; 366*a3cbbb47SArd Biesheuvel 367*a3cbbb47SArd Biesheuvel return ES_OK; 368*a3cbbb47SArd Biesheuvel } 369*a3cbbb47SArd Biesheuvel 370*a3cbbb47SArd Biesheuvel static enum es_result vc_ioio_check(struct es_em_ctxt *ctxt, u16 port, size_t size) 371*a3cbbb47SArd Biesheuvel { 372*a3cbbb47SArd Biesheuvel BUG_ON(size > 4); 373*a3cbbb47SArd Biesheuvel 374*a3cbbb47SArd Biesheuvel if (user_mode(ctxt->regs)) { 375*a3cbbb47SArd Biesheuvel struct thread_struct *t = ¤t->thread; 376*a3cbbb47SArd Biesheuvel struct io_bitmap *iobm = t->io_bitmap; 377*a3cbbb47SArd Biesheuvel size_t idx; 378*a3cbbb47SArd Biesheuvel 379*a3cbbb47SArd Biesheuvel if (!iobm) 380*a3cbbb47SArd Biesheuvel goto fault; 381*a3cbbb47SArd Biesheuvel 382*a3cbbb47SArd Biesheuvel for (idx = port; idx < port + size; ++idx) { 383*a3cbbb47SArd Biesheuvel if (test_bit(idx, iobm->bitmap)) 384*a3cbbb47SArd Biesheuvel goto fault; 385*a3cbbb47SArd Biesheuvel } 386*a3cbbb47SArd Biesheuvel } 387*a3cbbb47SArd Biesheuvel 388*a3cbbb47SArd Biesheuvel return ES_OK; 389*a3cbbb47SArd Biesheuvel 390*a3cbbb47SArd Biesheuvel fault: 391*a3cbbb47SArd Biesheuvel ctxt->fi.vector = X86_TRAP_GP; 392*a3cbbb47SArd Biesheuvel ctxt->fi.error_code = 0; 393*a3cbbb47SArd Biesheuvel 394*a3cbbb47SArd Biesheuvel return ES_EXCEPTION; 395*a3cbbb47SArd Biesheuvel } 396*a3cbbb47SArd Biesheuvel 397*a3cbbb47SArd Biesheuvel static __always_inline void vc_forward_exception(struct es_em_ctxt *ctxt) 398*a3cbbb47SArd Biesheuvel { 399*a3cbbb47SArd Biesheuvel long error_code = ctxt->fi.error_code; 400*a3cbbb47SArd Biesheuvel int trapnr = ctxt->fi.vector; 401*a3cbbb47SArd Biesheuvel 402*a3cbbb47SArd Biesheuvel ctxt->regs->orig_ax = ctxt->fi.error_code; 403*a3cbbb47SArd Biesheuvel 404*a3cbbb47SArd Biesheuvel switch (trapnr) { 405*a3cbbb47SArd Biesheuvel case X86_TRAP_GP: 406*a3cbbb47SArd Biesheuvel exc_general_protection(ctxt->regs, error_code); 407*a3cbbb47SArd Biesheuvel break; 408*a3cbbb47SArd Biesheuvel case X86_TRAP_UD: 409*a3cbbb47SArd Biesheuvel exc_invalid_op(ctxt->regs); 410*a3cbbb47SArd Biesheuvel break; 411*a3cbbb47SArd Biesheuvel case X86_TRAP_PF: 412*a3cbbb47SArd Biesheuvel write_cr2(ctxt->fi.cr2); 413*a3cbbb47SArd Biesheuvel exc_page_fault(ctxt->regs, error_code); 414*a3cbbb47SArd Biesheuvel break; 415*a3cbbb47SArd Biesheuvel case X86_TRAP_AC: 416*a3cbbb47SArd Biesheuvel exc_alignment_check(ctxt->regs, error_code); 417*a3cbbb47SArd Biesheuvel break; 418*a3cbbb47SArd Biesheuvel default: 419*a3cbbb47SArd Biesheuvel pr_emerg("Unsupported exception in #VC instruction emulation - can't continue\n"); 420*a3cbbb47SArd Biesheuvel BUG(); 421*a3cbbb47SArd Biesheuvel } 422*a3cbbb47SArd Biesheuvel } 423*a3cbbb47SArd Biesheuvel 424*a3cbbb47SArd Biesheuvel /* Include code shared with pre-decompression boot stage */ 425*a3cbbb47SArd Biesheuvel #include "sev-shared.c" 426*a3cbbb47SArd Biesheuvel 427*a3cbbb47SArd Biesheuvel noinstr void __sev_put_ghcb(struct ghcb_state *state) 428*a3cbbb47SArd Biesheuvel { 429*a3cbbb47SArd Biesheuvel struct sev_es_runtime_data *data; 430*a3cbbb47SArd Biesheuvel struct ghcb *ghcb; 431*a3cbbb47SArd Biesheuvel 432*a3cbbb47SArd Biesheuvel WARN_ON(!irqs_disabled()); 433*a3cbbb47SArd Biesheuvel 434*a3cbbb47SArd Biesheuvel data = this_cpu_read(runtime_data); 435*a3cbbb47SArd Biesheuvel ghcb = &data->ghcb_page; 436*a3cbbb47SArd Biesheuvel 437*a3cbbb47SArd Biesheuvel if (state->ghcb) { 438*a3cbbb47SArd Biesheuvel /* Restore GHCB from Backup */ 439*a3cbbb47SArd Biesheuvel *ghcb = *state->ghcb; 440*a3cbbb47SArd Biesheuvel data->backup_ghcb_active = false; 441*a3cbbb47SArd Biesheuvel state->ghcb = NULL; 442*a3cbbb47SArd Biesheuvel } else { 443*a3cbbb47SArd Biesheuvel /* 444*a3cbbb47SArd Biesheuvel * Invalidate the GHCB so a VMGEXIT instruction issued 445*a3cbbb47SArd Biesheuvel * from userspace won't appear to be valid. 446*a3cbbb47SArd Biesheuvel */ 447*a3cbbb47SArd Biesheuvel vc_ghcb_invalidate(ghcb); 448*a3cbbb47SArd Biesheuvel data->ghcb_active = false; 449*a3cbbb47SArd Biesheuvel } 450*a3cbbb47SArd Biesheuvel } 451*a3cbbb47SArd Biesheuvel 452*a3cbbb47SArd Biesheuvel int svsm_perform_call_protocol(struct svsm_call *call) 453*a3cbbb47SArd Biesheuvel { 454*a3cbbb47SArd Biesheuvel struct ghcb_state state; 455*a3cbbb47SArd Biesheuvel unsigned long flags; 456*a3cbbb47SArd Biesheuvel struct ghcb *ghcb; 457*a3cbbb47SArd Biesheuvel int ret; 458*a3cbbb47SArd Biesheuvel 459*a3cbbb47SArd Biesheuvel /* 460*a3cbbb47SArd Biesheuvel * This can be called very early in the boot, use native functions in 461*a3cbbb47SArd Biesheuvel * order to avoid paravirt issues. 462*a3cbbb47SArd Biesheuvel */ 463*a3cbbb47SArd Biesheuvel flags = native_local_irq_save(); 464*a3cbbb47SArd Biesheuvel 465*a3cbbb47SArd Biesheuvel /* 466*a3cbbb47SArd Biesheuvel * Use rip-relative references when called early in the boot. If 467*a3cbbb47SArd Biesheuvel * ghcbs_initialized is set, then it is late in the boot and no need 468*a3cbbb47SArd Biesheuvel * to worry about rip-relative references in called functions. 469*a3cbbb47SArd Biesheuvel */ 470*a3cbbb47SArd Biesheuvel if (RIP_REL_REF(sev_cfg).ghcbs_initialized) 471*a3cbbb47SArd Biesheuvel ghcb = __sev_get_ghcb(&state); 472*a3cbbb47SArd Biesheuvel else if (RIP_REL_REF(boot_ghcb)) 473*a3cbbb47SArd Biesheuvel ghcb = RIP_REL_REF(boot_ghcb); 474*a3cbbb47SArd Biesheuvel else 475*a3cbbb47SArd Biesheuvel ghcb = NULL; 476*a3cbbb47SArd Biesheuvel 477*a3cbbb47SArd Biesheuvel do { 478*a3cbbb47SArd Biesheuvel ret = ghcb ? svsm_perform_ghcb_protocol(ghcb, call) 479*a3cbbb47SArd Biesheuvel : svsm_perform_msr_protocol(call); 480*a3cbbb47SArd Biesheuvel } while (ret == -EAGAIN); 481*a3cbbb47SArd Biesheuvel 482*a3cbbb47SArd Biesheuvel if (RIP_REL_REF(sev_cfg).ghcbs_initialized) 483*a3cbbb47SArd Biesheuvel __sev_put_ghcb(&state); 484*a3cbbb47SArd Biesheuvel 485*a3cbbb47SArd Biesheuvel native_local_irq_restore(flags); 486*a3cbbb47SArd Biesheuvel 487*a3cbbb47SArd Biesheuvel return ret; 488*a3cbbb47SArd Biesheuvel } 489*a3cbbb47SArd Biesheuvel 490*a3cbbb47SArd Biesheuvel void __head 491*a3cbbb47SArd Biesheuvel early_set_pages_state(unsigned long vaddr, unsigned long paddr, 492*a3cbbb47SArd Biesheuvel unsigned long npages, enum psc_op op) 493*a3cbbb47SArd Biesheuvel { 494*a3cbbb47SArd Biesheuvel unsigned long paddr_end; 495*a3cbbb47SArd Biesheuvel u64 val; 496*a3cbbb47SArd Biesheuvel 497*a3cbbb47SArd Biesheuvel vaddr = vaddr & PAGE_MASK; 498*a3cbbb47SArd Biesheuvel 499*a3cbbb47SArd Biesheuvel paddr = paddr & PAGE_MASK; 500*a3cbbb47SArd Biesheuvel paddr_end = paddr + (npages << PAGE_SHIFT); 501*a3cbbb47SArd Biesheuvel 502*a3cbbb47SArd Biesheuvel while (paddr < paddr_end) { 503*a3cbbb47SArd Biesheuvel /* Page validation must be rescinded before changing to shared */ 504*a3cbbb47SArd Biesheuvel if (op == SNP_PAGE_STATE_SHARED) 505*a3cbbb47SArd Biesheuvel pvalidate_4k_page(vaddr, paddr, false); 506*a3cbbb47SArd Biesheuvel 507*a3cbbb47SArd Biesheuvel /* 508*a3cbbb47SArd Biesheuvel * Use the MSR protocol because this function can be called before 509*a3cbbb47SArd Biesheuvel * the GHCB is established. 510*a3cbbb47SArd Biesheuvel */ 511*a3cbbb47SArd Biesheuvel sev_es_wr_ghcb_msr(GHCB_MSR_PSC_REQ_GFN(paddr >> PAGE_SHIFT, op)); 512*a3cbbb47SArd Biesheuvel VMGEXIT(); 513*a3cbbb47SArd Biesheuvel 514*a3cbbb47SArd Biesheuvel val = sev_es_rd_ghcb_msr(); 515*a3cbbb47SArd Biesheuvel 516*a3cbbb47SArd Biesheuvel if (GHCB_RESP_CODE(val) != GHCB_MSR_PSC_RESP) 517*a3cbbb47SArd Biesheuvel goto e_term; 518*a3cbbb47SArd Biesheuvel 519*a3cbbb47SArd Biesheuvel if (GHCB_MSR_PSC_RESP_VAL(val)) 520*a3cbbb47SArd Biesheuvel goto e_term; 521*a3cbbb47SArd Biesheuvel 522*a3cbbb47SArd Biesheuvel /* Page validation must be performed after changing to private */ 523*a3cbbb47SArd Biesheuvel if (op == SNP_PAGE_STATE_PRIVATE) 524*a3cbbb47SArd Biesheuvel pvalidate_4k_page(vaddr, paddr, true); 525*a3cbbb47SArd Biesheuvel 526*a3cbbb47SArd Biesheuvel vaddr += PAGE_SIZE; 527*a3cbbb47SArd Biesheuvel paddr += PAGE_SIZE; 528*a3cbbb47SArd Biesheuvel } 529*a3cbbb47SArd Biesheuvel 530*a3cbbb47SArd Biesheuvel return; 531*a3cbbb47SArd Biesheuvel 532*a3cbbb47SArd Biesheuvel e_term: 533*a3cbbb47SArd Biesheuvel sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PSC); 534*a3cbbb47SArd Biesheuvel } 535*a3cbbb47SArd Biesheuvel 536*a3cbbb47SArd Biesheuvel void __head early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr, 537*a3cbbb47SArd Biesheuvel unsigned long npages) 538*a3cbbb47SArd Biesheuvel { 539*a3cbbb47SArd Biesheuvel /* 540*a3cbbb47SArd Biesheuvel * This can be invoked in early boot while running identity mapped, so 541*a3cbbb47SArd Biesheuvel * use an open coded check for SNP instead of using cc_platform_has(). 542*a3cbbb47SArd Biesheuvel * This eliminates worries about jump tables or checking boot_cpu_data 543*a3cbbb47SArd Biesheuvel * in the cc_platform_has() function. 544*a3cbbb47SArd Biesheuvel */ 545*a3cbbb47SArd Biesheuvel if (!(RIP_REL_REF(sev_status) & MSR_AMD64_SEV_SNP_ENABLED)) 546*a3cbbb47SArd Biesheuvel return; 547*a3cbbb47SArd Biesheuvel 548*a3cbbb47SArd Biesheuvel /* 549*a3cbbb47SArd Biesheuvel * Ask the hypervisor to mark the memory pages as private in the RMP 550*a3cbbb47SArd Biesheuvel * table. 551*a3cbbb47SArd Biesheuvel */ 552*a3cbbb47SArd Biesheuvel early_set_pages_state(vaddr, paddr, npages, SNP_PAGE_STATE_PRIVATE); 553*a3cbbb47SArd Biesheuvel } 554*a3cbbb47SArd Biesheuvel 555*a3cbbb47SArd Biesheuvel void __head early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr, 556*a3cbbb47SArd Biesheuvel unsigned long npages) 557*a3cbbb47SArd Biesheuvel { 558*a3cbbb47SArd Biesheuvel /* 559*a3cbbb47SArd Biesheuvel * This can be invoked in early boot while running identity mapped, so 560*a3cbbb47SArd Biesheuvel * use an open coded check for SNP instead of using cc_platform_has(). 561*a3cbbb47SArd Biesheuvel * This eliminates worries about jump tables or checking boot_cpu_data 562*a3cbbb47SArd Biesheuvel * in the cc_platform_has() function. 563*a3cbbb47SArd Biesheuvel */ 564*a3cbbb47SArd Biesheuvel if (!(RIP_REL_REF(sev_status) & MSR_AMD64_SEV_SNP_ENABLED)) 565*a3cbbb47SArd Biesheuvel return; 566*a3cbbb47SArd Biesheuvel 567*a3cbbb47SArd Biesheuvel /* Ask hypervisor to mark the memory pages shared in the RMP table. */ 568*a3cbbb47SArd Biesheuvel early_set_pages_state(vaddr, paddr, npages, SNP_PAGE_STATE_SHARED); 569*a3cbbb47SArd Biesheuvel } 570*a3cbbb47SArd Biesheuvel 571*a3cbbb47SArd Biesheuvel /* Writes to the SVSM CAA MSR are ignored */ 572*a3cbbb47SArd Biesheuvel static enum es_result __vc_handle_msr_caa(struct pt_regs *regs, bool write) 573*a3cbbb47SArd Biesheuvel { 574*a3cbbb47SArd Biesheuvel if (write) 575*a3cbbb47SArd Biesheuvel return ES_OK; 576*a3cbbb47SArd Biesheuvel 577*a3cbbb47SArd Biesheuvel regs->ax = lower_32_bits(this_cpu_read(svsm_caa_pa)); 578*a3cbbb47SArd Biesheuvel regs->dx = upper_32_bits(this_cpu_read(svsm_caa_pa)); 579*a3cbbb47SArd Biesheuvel 580*a3cbbb47SArd Biesheuvel return ES_OK; 581*a3cbbb47SArd Biesheuvel } 582*a3cbbb47SArd Biesheuvel 583*a3cbbb47SArd Biesheuvel /* 584*a3cbbb47SArd Biesheuvel * TSC related accesses should not exit to the hypervisor when a guest is 585*a3cbbb47SArd Biesheuvel * executing with Secure TSC enabled, so special handling is required for 586*a3cbbb47SArd Biesheuvel * accesses of MSR_IA32_TSC and MSR_AMD64_GUEST_TSC_FREQ. 587*a3cbbb47SArd Biesheuvel */ 588*a3cbbb47SArd Biesheuvel static enum es_result __vc_handle_secure_tsc_msrs(struct pt_regs *regs, bool write) 589*a3cbbb47SArd Biesheuvel { 590*a3cbbb47SArd Biesheuvel u64 tsc; 591*a3cbbb47SArd Biesheuvel 592*a3cbbb47SArd Biesheuvel /* 593*a3cbbb47SArd Biesheuvel * GUEST_TSC_FREQ should not be intercepted when Secure TSC is enabled. 594*a3cbbb47SArd Biesheuvel * Terminate the SNP guest when the interception is enabled. 595*a3cbbb47SArd Biesheuvel */ 596*a3cbbb47SArd Biesheuvel if (regs->cx == MSR_AMD64_GUEST_TSC_FREQ) 597*a3cbbb47SArd Biesheuvel return ES_VMM_ERROR; 598*a3cbbb47SArd Biesheuvel 599*a3cbbb47SArd Biesheuvel /* 600*a3cbbb47SArd Biesheuvel * Writes: Writing to MSR_IA32_TSC can cause subsequent reads of the TSC 601*a3cbbb47SArd Biesheuvel * to return undefined values, so ignore all writes. 602*a3cbbb47SArd Biesheuvel * 603*a3cbbb47SArd Biesheuvel * Reads: Reads of MSR_IA32_TSC should return the current TSC value, use 604*a3cbbb47SArd Biesheuvel * the value returned by rdtsc_ordered(). 605*a3cbbb47SArd Biesheuvel */ 606*a3cbbb47SArd Biesheuvel if (write) { 607*a3cbbb47SArd Biesheuvel WARN_ONCE(1, "TSC MSR writes are verboten!\n"); 608*a3cbbb47SArd Biesheuvel return ES_OK; 609*a3cbbb47SArd Biesheuvel } 610*a3cbbb47SArd Biesheuvel 611*a3cbbb47SArd Biesheuvel tsc = rdtsc_ordered(); 612*a3cbbb47SArd Biesheuvel regs->ax = lower_32_bits(tsc); 613*a3cbbb47SArd Biesheuvel regs->dx = upper_32_bits(tsc); 614*a3cbbb47SArd Biesheuvel 615*a3cbbb47SArd Biesheuvel return ES_OK; 616*a3cbbb47SArd Biesheuvel } 617*a3cbbb47SArd Biesheuvel 618*a3cbbb47SArd Biesheuvel static enum es_result vc_handle_msr(struct ghcb *ghcb, struct es_em_ctxt *ctxt) 619*a3cbbb47SArd Biesheuvel { 620*a3cbbb47SArd Biesheuvel struct pt_regs *regs = ctxt->regs; 621*a3cbbb47SArd Biesheuvel enum es_result ret; 622*a3cbbb47SArd Biesheuvel bool write; 623*a3cbbb47SArd Biesheuvel 624*a3cbbb47SArd Biesheuvel /* Is it a WRMSR? */ 625*a3cbbb47SArd Biesheuvel write = ctxt->insn.opcode.bytes[1] == 0x30; 626*a3cbbb47SArd Biesheuvel 627*a3cbbb47SArd Biesheuvel switch (regs->cx) { 628*a3cbbb47SArd Biesheuvel case MSR_SVSM_CAA: 629*a3cbbb47SArd Biesheuvel return __vc_handle_msr_caa(regs, write); 630*a3cbbb47SArd Biesheuvel case MSR_IA32_TSC: 631*a3cbbb47SArd Biesheuvel case MSR_AMD64_GUEST_TSC_FREQ: 632*a3cbbb47SArd Biesheuvel if (sev_status & MSR_AMD64_SNP_SECURE_TSC) 633*a3cbbb47SArd Biesheuvel return __vc_handle_secure_tsc_msrs(regs, write); 634*a3cbbb47SArd Biesheuvel break; 635*a3cbbb47SArd Biesheuvel default: 636*a3cbbb47SArd Biesheuvel break; 637*a3cbbb47SArd Biesheuvel } 638*a3cbbb47SArd Biesheuvel 639*a3cbbb47SArd Biesheuvel ghcb_set_rcx(ghcb, regs->cx); 640*a3cbbb47SArd Biesheuvel if (write) { 641*a3cbbb47SArd Biesheuvel ghcb_set_rax(ghcb, regs->ax); 642*a3cbbb47SArd Biesheuvel ghcb_set_rdx(ghcb, regs->dx); 643*a3cbbb47SArd Biesheuvel } 644*a3cbbb47SArd Biesheuvel 645*a3cbbb47SArd Biesheuvel ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_MSR, write, 0); 646*a3cbbb47SArd Biesheuvel 647*a3cbbb47SArd Biesheuvel if ((ret == ES_OK) && !write) { 648*a3cbbb47SArd Biesheuvel regs->ax = ghcb->save.rax; 649*a3cbbb47SArd Biesheuvel regs->dx = ghcb->save.rdx; 650*a3cbbb47SArd Biesheuvel } 651*a3cbbb47SArd Biesheuvel 652*a3cbbb47SArd Biesheuvel return ret; 653*a3cbbb47SArd Biesheuvel } 654*a3cbbb47SArd Biesheuvel 655*a3cbbb47SArd Biesheuvel static void __init vc_early_forward_exception(struct es_em_ctxt *ctxt) 656*a3cbbb47SArd Biesheuvel { 657*a3cbbb47SArd Biesheuvel int trapnr = ctxt->fi.vector; 658*a3cbbb47SArd Biesheuvel 659*a3cbbb47SArd Biesheuvel if (trapnr == X86_TRAP_PF) 660*a3cbbb47SArd Biesheuvel native_write_cr2(ctxt->fi.cr2); 661*a3cbbb47SArd Biesheuvel 662*a3cbbb47SArd Biesheuvel ctxt->regs->orig_ax = ctxt->fi.error_code; 663*a3cbbb47SArd Biesheuvel do_early_exception(ctxt->regs, trapnr); 664*a3cbbb47SArd Biesheuvel } 665*a3cbbb47SArd Biesheuvel 666*a3cbbb47SArd Biesheuvel static long *vc_insn_get_rm(struct es_em_ctxt *ctxt) 667*a3cbbb47SArd Biesheuvel { 668*a3cbbb47SArd Biesheuvel long *reg_array; 669*a3cbbb47SArd Biesheuvel int offset; 670*a3cbbb47SArd Biesheuvel 671*a3cbbb47SArd Biesheuvel reg_array = (long *)ctxt->regs; 672*a3cbbb47SArd Biesheuvel offset = insn_get_modrm_rm_off(&ctxt->insn, ctxt->regs); 673*a3cbbb47SArd Biesheuvel 674*a3cbbb47SArd Biesheuvel if (offset < 0) 675*a3cbbb47SArd Biesheuvel return NULL; 676*a3cbbb47SArd Biesheuvel 677*a3cbbb47SArd Biesheuvel offset /= sizeof(long); 678*a3cbbb47SArd Biesheuvel 679*a3cbbb47SArd Biesheuvel return reg_array + offset; 680*a3cbbb47SArd Biesheuvel } 681*a3cbbb47SArd Biesheuvel static enum es_result vc_do_mmio(struct ghcb *ghcb, struct es_em_ctxt *ctxt, 682*a3cbbb47SArd Biesheuvel unsigned int bytes, bool read) 683*a3cbbb47SArd Biesheuvel { 684*a3cbbb47SArd Biesheuvel u64 exit_code, exit_info_1, exit_info_2; 685*a3cbbb47SArd Biesheuvel unsigned long ghcb_pa = __pa(ghcb); 686*a3cbbb47SArd Biesheuvel enum es_result res; 687*a3cbbb47SArd Biesheuvel phys_addr_t paddr; 688*a3cbbb47SArd Biesheuvel void __user *ref; 689*a3cbbb47SArd Biesheuvel 690*a3cbbb47SArd Biesheuvel ref = insn_get_addr_ref(&ctxt->insn, ctxt->regs); 691*a3cbbb47SArd Biesheuvel if (ref == (void __user *)-1L) 692*a3cbbb47SArd Biesheuvel return ES_UNSUPPORTED; 693*a3cbbb47SArd Biesheuvel 694*a3cbbb47SArd Biesheuvel exit_code = read ? SVM_VMGEXIT_MMIO_READ : SVM_VMGEXIT_MMIO_WRITE; 695*a3cbbb47SArd Biesheuvel 696*a3cbbb47SArd Biesheuvel res = vc_slow_virt_to_phys(ghcb, ctxt, (unsigned long)ref, &paddr); 697*a3cbbb47SArd Biesheuvel if (res != ES_OK) { 698*a3cbbb47SArd Biesheuvel if (res == ES_EXCEPTION && !read) 699*a3cbbb47SArd Biesheuvel ctxt->fi.error_code |= X86_PF_WRITE; 700*a3cbbb47SArd Biesheuvel 701*a3cbbb47SArd Biesheuvel return res; 702*a3cbbb47SArd Biesheuvel } 703*a3cbbb47SArd Biesheuvel 704*a3cbbb47SArd Biesheuvel exit_info_1 = paddr; 705*a3cbbb47SArd Biesheuvel /* Can never be greater than 8 */ 706*a3cbbb47SArd Biesheuvel exit_info_2 = bytes; 707*a3cbbb47SArd Biesheuvel 708*a3cbbb47SArd Biesheuvel ghcb_set_sw_scratch(ghcb, ghcb_pa + offsetof(struct ghcb, shared_buffer)); 709*a3cbbb47SArd Biesheuvel 710*a3cbbb47SArd Biesheuvel return sev_es_ghcb_hv_call(ghcb, ctxt, exit_code, exit_info_1, exit_info_2); 711*a3cbbb47SArd Biesheuvel } 712*a3cbbb47SArd Biesheuvel 713*a3cbbb47SArd Biesheuvel /* 714*a3cbbb47SArd Biesheuvel * The MOVS instruction has two memory operands, which raises the 715*a3cbbb47SArd Biesheuvel * problem that it is not known whether the access to the source or the 716*a3cbbb47SArd Biesheuvel * destination caused the #VC exception (and hence whether an MMIO read 717*a3cbbb47SArd Biesheuvel * or write operation needs to be emulated). 718*a3cbbb47SArd Biesheuvel * 719*a3cbbb47SArd Biesheuvel * Instead of playing games with walking page-tables and trying to guess 720*a3cbbb47SArd Biesheuvel * whether the source or destination is an MMIO range, split the move 721*a3cbbb47SArd Biesheuvel * into two operations, a read and a write with only one memory operand. 722*a3cbbb47SArd Biesheuvel * This will cause a nested #VC exception on the MMIO address which can 723*a3cbbb47SArd Biesheuvel * then be handled. 724*a3cbbb47SArd Biesheuvel * 725*a3cbbb47SArd Biesheuvel * This implementation has the benefit that it also supports MOVS where 726*a3cbbb47SArd Biesheuvel * source _and_ destination are MMIO regions. 727*a3cbbb47SArd Biesheuvel * 728*a3cbbb47SArd Biesheuvel * It will slow MOVS on MMIO down a lot, but in SEV-ES guests it is a 729*a3cbbb47SArd Biesheuvel * rare operation. If it turns out to be a performance problem the split 730*a3cbbb47SArd Biesheuvel * operations can be moved to memcpy_fromio() and memcpy_toio(). 731*a3cbbb47SArd Biesheuvel */ 732*a3cbbb47SArd Biesheuvel static enum es_result vc_handle_mmio_movs(struct es_em_ctxt *ctxt, 733*a3cbbb47SArd Biesheuvel unsigned int bytes) 734*a3cbbb47SArd Biesheuvel { 735*a3cbbb47SArd Biesheuvel unsigned long ds_base, es_base; 736*a3cbbb47SArd Biesheuvel unsigned char *src, *dst; 737*a3cbbb47SArd Biesheuvel unsigned char buffer[8]; 738*a3cbbb47SArd Biesheuvel enum es_result ret; 739*a3cbbb47SArd Biesheuvel bool rep; 740*a3cbbb47SArd Biesheuvel int off; 741*a3cbbb47SArd Biesheuvel 742*a3cbbb47SArd Biesheuvel ds_base = insn_get_seg_base(ctxt->regs, INAT_SEG_REG_DS); 743*a3cbbb47SArd Biesheuvel es_base = insn_get_seg_base(ctxt->regs, INAT_SEG_REG_ES); 744*a3cbbb47SArd Biesheuvel 745*a3cbbb47SArd Biesheuvel if (ds_base == -1L || es_base == -1L) { 746*a3cbbb47SArd Biesheuvel ctxt->fi.vector = X86_TRAP_GP; 747*a3cbbb47SArd Biesheuvel ctxt->fi.error_code = 0; 748*a3cbbb47SArd Biesheuvel return ES_EXCEPTION; 749*a3cbbb47SArd Biesheuvel } 750*a3cbbb47SArd Biesheuvel 751*a3cbbb47SArd Biesheuvel src = ds_base + (unsigned char *)ctxt->regs->si; 752*a3cbbb47SArd Biesheuvel dst = es_base + (unsigned char *)ctxt->regs->di; 753*a3cbbb47SArd Biesheuvel 754*a3cbbb47SArd Biesheuvel ret = vc_read_mem(ctxt, src, buffer, bytes); 755*a3cbbb47SArd Biesheuvel if (ret != ES_OK) 756*a3cbbb47SArd Biesheuvel return ret; 757*a3cbbb47SArd Biesheuvel 758*a3cbbb47SArd Biesheuvel ret = vc_write_mem(ctxt, dst, buffer, bytes); 759*a3cbbb47SArd Biesheuvel if (ret != ES_OK) 760*a3cbbb47SArd Biesheuvel return ret; 761*a3cbbb47SArd Biesheuvel 762*a3cbbb47SArd Biesheuvel if (ctxt->regs->flags & X86_EFLAGS_DF) 763*a3cbbb47SArd Biesheuvel off = -bytes; 764*a3cbbb47SArd Biesheuvel else 765*a3cbbb47SArd Biesheuvel off = bytes; 766*a3cbbb47SArd Biesheuvel 767*a3cbbb47SArd Biesheuvel ctxt->regs->si += off; 768*a3cbbb47SArd Biesheuvel ctxt->regs->di += off; 769*a3cbbb47SArd Biesheuvel 770*a3cbbb47SArd Biesheuvel rep = insn_has_rep_prefix(&ctxt->insn); 771*a3cbbb47SArd Biesheuvel if (rep) 772*a3cbbb47SArd Biesheuvel ctxt->regs->cx -= 1; 773*a3cbbb47SArd Biesheuvel 774*a3cbbb47SArd Biesheuvel if (!rep || ctxt->regs->cx == 0) 775*a3cbbb47SArd Biesheuvel return ES_OK; 776*a3cbbb47SArd Biesheuvel else 777*a3cbbb47SArd Biesheuvel return ES_RETRY; 778*a3cbbb47SArd Biesheuvel } 779*a3cbbb47SArd Biesheuvel 780*a3cbbb47SArd Biesheuvel static enum es_result vc_handle_mmio(struct ghcb *ghcb, struct es_em_ctxt *ctxt) 781*a3cbbb47SArd Biesheuvel { 782*a3cbbb47SArd Biesheuvel struct insn *insn = &ctxt->insn; 783*a3cbbb47SArd Biesheuvel enum insn_mmio_type mmio; 784*a3cbbb47SArd Biesheuvel unsigned int bytes = 0; 785*a3cbbb47SArd Biesheuvel enum es_result ret; 786*a3cbbb47SArd Biesheuvel u8 sign_byte; 787*a3cbbb47SArd Biesheuvel long *reg_data; 788*a3cbbb47SArd Biesheuvel 789*a3cbbb47SArd Biesheuvel mmio = insn_decode_mmio(insn, &bytes); 790*a3cbbb47SArd Biesheuvel if (mmio == INSN_MMIO_DECODE_FAILED) 791*a3cbbb47SArd Biesheuvel return ES_DECODE_FAILED; 792*a3cbbb47SArd Biesheuvel 793*a3cbbb47SArd Biesheuvel if (mmio != INSN_MMIO_WRITE_IMM && mmio != INSN_MMIO_MOVS) { 794*a3cbbb47SArd Biesheuvel reg_data = insn_get_modrm_reg_ptr(insn, ctxt->regs); 795*a3cbbb47SArd Biesheuvel if (!reg_data) 796*a3cbbb47SArd Biesheuvel return ES_DECODE_FAILED; 797*a3cbbb47SArd Biesheuvel } 798*a3cbbb47SArd Biesheuvel 799*a3cbbb47SArd Biesheuvel if (user_mode(ctxt->regs)) 800*a3cbbb47SArd Biesheuvel return ES_UNSUPPORTED; 801*a3cbbb47SArd Biesheuvel 802*a3cbbb47SArd Biesheuvel switch (mmio) { 803*a3cbbb47SArd Biesheuvel case INSN_MMIO_WRITE: 804*a3cbbb47SArd Biesheuvel memcpy(ghcb->shared_buffer, reg_data, bytes); 805*a3cbbb47SArd Biesheuvel ret = vc_do_mmio(ghcb, ctxt, bytes, false); 806*a3cbbb47SArd Biesheuvel break; 807*a3cbbb47SArd Biesheuvel case INSN_MMIO_WRITE_IMM: 808*a3cbbb47SArd Biesheuvel memcpy(ghcb->shared_buffer, insn->immediate1.bytes, bytes); 809*a3cbbb47SArd Biesheuvel ret = vc_do_mmio(ghcb, ctxt, bytes, false); 810*a3cbbb47SArd Biesheuvel break; 811*a3cbbb47SArd Biesheuvel case INSN_MMIO_READ: 812*a3cbbb47SArd Biesheuvel ret = vc_do_mmio(ghcb, ctxt, bytes, true); 813*a3cbbb47SArd Biesheuvel if (ret) 814*a3cbbb47SArd Biesheuvel break; 815*a3cbbb47SArd Biesheuvel 816*a3cbbb47SArd Biesheuvel /* Zero-extend for 32-bit operation */ 817*a3cbbb47SArd Biesheuvel if (bytes == 4) 818*a3cbbb47SArd Biesheuvel *reg_data = 0; 819*a3cbbb47SArd Biesheuvel 820*a3cbbb47SArd Biesheuvel memcpy(reg_data, ghcb->shared_buffer, bytes); 821*a3cbbb47SArd Biesheuvel break; 822*a3cbbb47SArd Biesheuvel case INSN_MMIO_READ_ZERO_EXTEND: 823*a3cbbb47SArd Biesheuvel ret = vc_do_mmio(ghcb, ctxt, bytes, true); 824*a3cbbb47SArd Biesheuvel if (ret) 825*a3cbbb47SArd Biesheuvel break; 826*a3cbbb47SArd Biesheuvel 827*a3cbbb47SArd Biesheuvel /* Zero extend based on operand size */ 828*a3cbbb47SArd Biesheuvel memset(reg_data, 0, insn->opnd_bytes); 829*a3cbbb47SArd Biesheuvel memcpy(reg_data, ghcb->shared_buffer, bytes); 830*a3cbbb47SArd Biesheuvel break; 831*a3cbbb47SArd Biesheuvel case INSN_MMIO_READ_SIGN_EXTEND: 832*a3cbbb47SArd Biesheuvel ret = vc_do_mmio(ghcb, ctxt, bytes, true); 833*a3cbbb47SArd Biesheuvel if (ret) 834*a3cbbb47SArd Biesheuvel break; 835*a3cbbb47SArd Biesheuvel 836*a3cbbb47SArd Biesheuvel if (bytes == 1) { 837*a3cbbb47SArd Biesheuvel u8 *val = (u8 *)ghcb->shared_buffer; 838*a3cbbb47SArd Biesheuvel 839*a3cbbb47SArd Biesheuvel sign_byte = (*val & 0x80) ? 0xff : 0x00; 840*a3cbbb47SArd Biesheuvel } else { 841*a3cbbb47SArd Biesheuvel u16 *val = (u16 *)ghcb->shared_buffer; 842*a3cbbb47SArd Biesheuvel 843*a3cbbb47SArd Biesheuvel sign_byte = (*val & 0x8000) ? 0xff : 0x00; 844*a3cbbb47SArd Biesheuvel } 845*a3cbbb47SArd Biesheuvel 846*a3cbbb47SArd Biesheuvel /* Sign extend based on operand size */ 847*a3cbbb47SArd Biesheuvel memset(reg_data, sign_byte, insn->opnd_bytes); 848*a3cbbb47SArd Biesheuvel memcpy(reg_data, ghcb->shared_buffer, bytes); 849*a3cbbb47SArd Biesheuvel break; 850*a3cbbb47SArd Biesheuvel case INSN_MMIO_MOVS: 851*a3cbbb47SArd Biesheuvel ret = vc_handle_mmio_movs(ctxt, bytes); 852*a3cbbb47SArd Biesheuvel break; 853*a3cbbb47SArd Biesheuvel default: 854*a3cbbb47SArd Biesheuvel ret = ES_UNSUPPORTED; 855*a3cbbb47SArd Biesheuvel break; 856*a3cbbb47SArd Biesheuvel } 857*a3cbbb47SArd Biesheuvel 858*a3cbbb47SArd Biesheuvel return ret; 859*a3cbbb47SArd Biesheuvel } 860*a3cbbb47SArd Biesheuvel 861*a3cbbb47SArd Biesheuvel static enum es_result vc_handle_dr7_write(struct ghcb *ghcb, 862*a3cbbb47SArd Biesheuvel struct es_em_ctxt *ctxt) 863*a3cbbb47SArd Biesheuvel { 864*a3cbbb47SArd Biesheuvel struct sev_es_runtime_data *data = this_cpu_read(runtime_data); 865*a3cbbb47SArd Biesheuvel long val, *reg = vc_insn_get_rm(ctxt); 866*a3cbbb47SArd Biesheuvel enum es_result ret; 867*a3cbbb47SArd Biesheuvel 868*a3cbbb47SArd Biesheuvel if (sev_status & MSR_AMD64_SNP_DEBUG_SWAP) 869*a3cbbb47SArd Biesheuvel return ES_VMM_ERROR; 870*a3cbbb47SArd Biesheuvel 871*a3cbbb47SArd Biesheuvel if (!reg) 872*a3cbbb47SArd Biesheuvel return ES_DECODE_FAILED; 873*a3cbbb47SArd Biesheuvel 874*a3cbbb47SArd Biesheuvel val = *reg; 875*a3cbbb47SArd Biesheuvel 876*a3cbbb47SArd Biesheuvel /* Upper 32 bits must be written as zeroes */ 877*a3cbbb47SArd Biesheuvel if (val >> 32) { 878*a3cbbb47SArd Biesheuvel ctxt->fi.vector = X86_TRAP_GP; 879*a3cbbb47SArd Biesheuvel ctxt->fi.error_code = 0; 880*a3cbbb47SArd Biesheuvel return ES_EXCEPTION; 881*a3cbbb47SArd Biesheuvel } 882*a3cbbb47SArd Biesheuvel 883*a3cbbb47SArd Biesheuvel /* Clear out other reserved bits and set bit 10 */ 884*a3cbbb47SArd Biesheuvel val = (val & 0xffff23ffL) | BIT(10); 885*a3cbbb47SArd Biesheuvel 886*a3cbbb47SArd Biesheuvel /* Early non-zero writes to DR7 are not supported */ 887*a3cbbb47SArd Biesheuvel if (!data && (val & ~DR7_RESET_VALUE)) 888*a3cbbb47SArd Biesheuvel return ES_UNSUPPORTED; 889*a3cbbb47SArd Biesheuvel 890*a3cbbb47SArd Biesheuvel /* Using a value of 0 for ExitInfo1 means RAX holds the value */ 891*a3cbbb47SArd Biesheuvel ghcb_set_rax(ghcb, val); 892*a3cbbb47SArd Biesheuvel ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_WRITE_DR7, 0, 0); 893*a3cbbb47SArd Biesheuvel if (ret != ES_OK) 894*a3cbbb47SArd Biesheuvel return ret; 895*a3cbbb47SArd Biesheuvel 896*a3cbbb47SArd Biesheuvel if (data) 897*a3cbbb47SArd Biesheuvel data->dr7 = val; 898*a3cbbb47SArd Biesheuvel 899*a3cbbb47SArd Biesheuvel return ES_OK; 900*a3cbbb47SArd Biesheuvel } 901*a3cbbb47SArd Biesheuvel 902*a3cbbb47SArd Biesheuvel static enum es_result vc_handle_dr7_read(struct ghcb *ghcb, 903*a3cbbb47SArd Biesheuvel struct es_em_ctxt *ctxt) 904*a3cbbb47SArd Biesheuvel { 905*a3cbbb47SArd Biesheuvel struct sev_es_runtime_data *data = this_cpu_read(runtime_data); 906*a3cbbb47SArd Biesheuvel long *reg = vc_insn_get_rm(ctxt); 907*a3cbbb47SArd Biesheuvel 908*a3cbbb47SArd Biesheuvel if (sev_status & MSR_AMD64_SNP_DEBUG_SWAP) 909*a3cbbb47SArd Biesheuvel return ES_VMM_ERROR; 910*a3cbbb47SArd Biesheuvel 911*a3cbbb47SArd Biesheuvel if (!reg) 912*a3cbbb47SArd Biesheuvel return ES_DECODE_FAILED; 913*a3cbbb47SArd Biesheuvel 914*a3cbbb47SArd Biesheuvel if (data) 915*a3cbbb47SArd Biesheuvel *reg = data->dr7; 916*a3cbbb47SArd Biesheuvel else 917*a3cbbb47SArd Biesheuvel *reg = DR7_RESET_VALUE; 918*a3cbbb47SArd Biesheuvel 919*a3cbbb47SArd Biesheuvel return ES_OK; 920*a3cbbb47SArd Biesheuvel } 921*a3cbbb47SArd Biesheuvel 922*a3cbbb47SArd Biesheuvel static enum es_result vc_handle_wbinvd(struct ghcb *ghcb, 923*a3cbbb47SArd Biesheuvel struct es_em_ctxt *ctxt) 924*a3cbbb47SArd Biesheuvel { 925*a3cbbb47SArd Biesheuvel return sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_WBINVD, 0, 0); 926*a3cbbb47SArd Biesheuvel } 927*a3cbbb47SArd Biesheuvel 928*a3cbbb47SArd Biesheuvel static enum es_result vc_handle_rdpmc(struct ghcb *ghcb, struct es_em_ctxt *ctxt) 929*a3cbbb47SArd Biesheuvel { 930*a3cbbb47SArd Biesheuvel enum es_result ret; 931*a3cbbb47SArd Biesheuvel 932*a3cbbb47SArd Biesheuvel ghcb_set_rcx(ghcb, ctxt->regs->cx); 933*a3cbbb47SArd Biesheuvel 934*a3cbbb47SArd Biesheuvel ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_RDPMC, 0, 0); 935*a3cbbb47SArd Biesheuvel if (ret != ES_OK) 936*a3cbbb47SArd Biesheuvel return ret; 937*a3cbbb47SArd Biesheuvel 938*a3cbbb47SArd Biesheuvel if (!(ghcb_rax_is_valid(ghcb) && ghcb_rdx_is_valid(ghcb))) 939*a3cbbb47SArd Biesheuvel return ES_VMM_ERROR; 940*a3cbbb47SArd Biesheuvel 941*a3cbbb47SArd Biesheuvel ctxt->regs->ax = ghcb->save.rax; 942*a3cbbb47SArd Biesheuvel ctxt->regs->dx = ghcb->save.rdx; 943*a3cbbb47SArd Biesheuvel 944*a3cbbb47SArd Biesheuvel return ES_OK; 945*a3cbbb47SArd Biesheuvel } 946*a3cbbb47SArd Biesheuvel 947*a3cbbb47SArd Biesheuvel static enum es_result vc_handle_monitor(struct ghcb *ghcb, 948*a3cbbb47SArd Biesheuvel struct es_em_ctxt *ctxt) 949*a3cbbb47SArd Biesheuvel { 950*a3cbbb47SArd Biesheuvel /* 951*a3cbbb47SArd Biesheuvel * Treat it as a NOP and do not leak a physical address to the 952*a3cbbb47SArd Biesheuvel * hypervisor. 953*a3cbbb47SArd Biesheuvel */ 954*a3cbbb47SArd Biesheuvel return ES_OK; 955*a3cbbb47SArd Biesheuvel } 956*a3cbbb47SArd Biesheuvel 957*a3cbbb47SArd Biesheuvel static enum es_result vc_handle_mwait(struct ghcb *ghcb, 958*a3cbbb47SArd Biesheuvel struct es_em_ctxt *ctxt) 959*a3cbbb47SArd Biesheuvel { 960*a3cbbb47SArd Biesheuvel /* Treat the same as MONITOR/MONITORX */ 961*a3cbbb47SArd Biesheuvel return ES_OK; 962*a3cbbb47SArd Biesheuvel } 963*a3cbbb47SArd Biesheuvel 964*a3cbbb47SArd Biesheuvel static enum es_result vc_handle_vmmcall(struct ghcb *ghcb, 965*a3cbbb47SArd Biesheuvel struct es_em_ctxt *ctxt) 966*a3cbbb47SArd Biesheuvel { 967*a3cbbb47SArd Biesheuvel enum es_result ret; 968*a3cbbb47SArd Biesheuvel 969*a3cbbb47SArd Biesheuvel ghcb_set_rax(ghcb, ctxt->regs->ax); 970*a3cbbb47SArd Biesheuvel ghcb_set_cpl(ghcb, user_mode(ctxt->regs) ? 3 : 0); 971*a3cbbb47SArd Biesheuvel 972*a3cbbb47SArd Biesheuvel if (x86_platform.hyper.sev_es_hcall_prepare) 973*a3cbbb47SArd Biesheuvel x86_platform.hyper.sev_es_hcall_prepare(ghcb, ctxt->regs); 974*a3cbbb47SArd Biesheuvel 975*a3cbbb47SArd Biesheuvel ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_VMMCALL, 0, 0); 976*a3cbbb47SArd Biesheuvel if (ret != ES_OK) 977*a3cbbb47SArd Biesheuvel return ret; 978*a3cbbb47SArd Biesheuvel 979*a3cbbb47SArd Biesheuvel if (!ghcb_rax_is_valid(ghcb)) 980*a3cbbb47SArd Biesheuvel return ES_VMM_ERROR; 981*a3cbbb47SArd Biesheuvel 982*a3cbbb47SArd Biesheuvel ctxt->regs->ax = ghcb->save.rax; 983*a3cbbb47SArd Biesheuvel 984*a3cbbb47SArd Biesheuvel /* 985*a3cbbb47SArd Biesheuvel * Call sev_es_hcall_finish() after regs->ax is already set. 986*a3cbbb47SArd Biesheuvel * This allows the hypervisor handler to overwrite it again if 987*a3cbbb47SArd Biesheuvel * necessary. 988*a3cbbb47SArd Biesheuvel */ 989*a3cbbb47SArd Biesheuvel if (x86_platform.hyper.sev_es_hcall_finish && 990*a3cbbb47SArd Biesheuvel !x86_platform.hyper.sev_es_hcall_finish(ghcb, ctxt->regs)) 991*a3cbbb47SArd Biesheuvel return ES_VMM_ERROR; 992*a3cbbb47SArd Biesheuvel 993*a3cbbb47SArd Biesheuvel return ES_OK; 994*a3cbbb47SArd Biesheuvel } 995*a3cbbb47SArd Biesheuvel 996*a3cbbb47SArd Biesheuvel static enum es_result vc_handle_trap_ac(struct ghcb *ghcb, 997*a3cbbb47SArd Biesheuvel struct es_em_ctxt *ctxt) 998*a3cbbb47SArd Biesheuvel { 999*a3cbbb47SArd Biesheuvel /* 1000*a3cbbb47SArd Biesheuvel * Calling ecx_alignment_check() directly does not work, because it 1001*a3cbbb47SArd Biesheuvel * enables IRQs and the GHCB is active. Forward the exception and call 1002*a3cbbb47SArd Biesheuvel * it later from vc_forward_exception(). 1003*a3cbbb47SArd Biesheuvel */ 1004*a3cbbb47SArd Biesheuvel ctxt->fi.vector = X86_TRAP_AC; 1005*a3cbbb47SArd Biesheuvel ctxt->fi.error_code = 0; 1006*a3cbbb47SArd Biesheuvel return ES_EXCEPTION; 1007*a3cbbb47SArd Biesheuvel } 1008*a3cbbb47SArd Biesheuvel 1009*a3cbbb47SArd Biesheuvel static enum es_result vc_handle_exitcode(struct es_em_ctxt *ctxt, 1010*a3cbbb47SArd Biesheuvel struct ghcb *ghcb, 1011*a3cbbb47SArd Biesheuvel unsigned long exit_code) 1012*a3cbbb47SArd Biesheuvel { 1013*a3cbbb47SArd Biesheuvel enum es_result result = vc_check_opcode_bytes(ctxt, exit_code); 1014*a3cbbb47SArd Biesheuvel 1015*a3cbbb47SArd Biesheuvel if (result != ES_OK) 1016*a3cbbb47SArd Biesheuvel return result; 1017*a3cbbb47SArd Biesheuvel 1018*a3cbbb47SArd Biesheuvel switch (exit_code) { 1019*a3cbbb47SArd Biesheuvel case SVM_EXIT_READ_DR7: 1020*a3cbbb47SArd Biesheuvel result = vc_handle_dr7_read(ghcb, ctxt); 1021*a3cbbb47SArd Biesheuvel break; 1022*a3cbbb47SArd Biesheuvel case SVM_EXIT_WRITE_DR7: 1023*a3cbbb47SArd Biesheuvel result = vc_handle_dr7_write(ghcb, ctxt); 1024*a3cbbb47SArd Biesheuvel break; 1025*a3cbbb47SArd Biesheuvel case SVM_EXIT_EXCP_BASE + X86_TRAP_AC: 1026*a3cbbb47SArd Biesheuvel result = vc_handle_trap_ac(ghcb, ctxt); 1027*a3cbbb47SArd Biesheuvel break; 1028*a3cbbb47SArd Biesheuvel case SVM_EXIT_RDTSC: 1029*a3cbbb47SArd Biesheuvel case SVM_EXIT_RDTSCP: 1030*a3cbbb47SArd Biesheuvel result = vc_handle_rdtsc(ghcb, ctxt, exit_code); 1031*a3cbbb47SArd Biesheuvel break; 1032*a3cbbb47SArd Biesheuvel case SVM_EXIT_RDPMC: 1033*a3cbbb47SArd Biesheuvel result = vc_handle_rdpmc(ghcb, ctxt); 1034*a3cbbb47SArd Biesheuvel break; 1035*a3cbbb47SArd Biesheuvel case SVM_EXIT_INVD: 1036*a3cbbb47SArd Biesheuvel pr_err_ratelimited("#VC exception for INVD??? Seriously???\n"); 1037*a3cbbb47SArd Biesheuvel result = ES_UNSUPPORTED; 1038*a3cbbb47SArd Biesheuvel break; 1039*a3cbbb47SArd Biesheuvel case SVM_EXIT_CPUID: 1040*a3cbbb47SArd Biesheuvel result = vc_handle_cpuid(ghcb, ctxt); 1041*a3cbbb47SArd Biesheuvel break; 1042*a3cbbb47SArd Biesheuvel case SVM_EXIT_IOIO: 1043*a3cbbb47SArd Biesheuvel result = vc_handle_ioio(ghcb, ctxt); 1044*a3cbbb47SArd Biesheuvel break; 1045*a3cbbb47SArd Biesheuvel case SVM_EXIT_MSR: 1046*a3cbbb47SArd Biesheuvel result = vc_handle_msr(ghcb, ctxt); 1047*a3cbbb47SArd Biesheuvel break; 1048*a3cbbb47SArd Biesheuvel case SVM_EXIT_VMMCALL: 1049*a3cbbb47SArd Biesheuvel result = vc_handle_vmmcall(ghcb, ctxt); 1050*a3cbbb47SArd Biesheuvel break; 1051*a3cbbb47SArd Biesheuvel case SVM_EXIT_WBINVD: 1052*a3cbbb47SArd Biesheuvel result = vc_handle_wbinvd(ghcb, ctxt); 1053*a3cbbb47SArd Biesheuvel break; 1054*a3cbbb47SArd Biesheuvel case SVM_EXIT_MONITOR: 1055*a3cbbb47SArd Biesheuvel result = vc_handle_monitor(ghcb, ctxt); 1056*a3cbbb47SArd Biesheuvel break; 1057*a3cbbb47SArd Biesheuvel case SVM_EXIT_MWAIT: 1058*a3cbbb47SArd Biesheuvel result = vc_handle_mwait(ghcb, ctxt); 1059*a3cbbb47SArd Biesheuvel break; 1060*a3cbbb47SArd Biesheuvel case SVM_EXIT_NPF: 1061*a3cbbb47SArd Biesheuvel result = vc_handle_mmio(ghcb, ctxt); 1062*a3cbbb47SArd Biesheuvel break; 1063*a3cbbb47SArd Biesheuvel default: 1064*a3cbbb47SArd Biesheuvel /* 1065*a3cbbb47SArd Biesheuvel * Unexpected #VC exception 1066*a3cbbb47SArd Biesheuvel */ 1067*a3cbbb47SArd Biesheuvel result = ES_UNSUPPORTED; 1068*a3cbbb47SArd Biesheuvel } 1069*a3cbbb47SArd Biesheuvel 1070*a3cbbb47SArd Biesheuvel return result; 1071*a3cbbb47SArd Biesheuvel } 1072*a3cbbb47SArd Biesheuvel 1073*a3cbbb47SArd Biesheuvel static __always_inline bool is_vc2_stack(unsigned long sp) 1074*a3cbbb47SArd Biesheuvel { 1075*a3cbbb47SArd Biesheuvel return (sp >= __this_cpu_ist_bottom_va(VC2) && sp < __this_cpu_ist_top_va(VC2)); 1076*a3cbbb47SArd Biesheuvel } 1077*a3cbbb47SArd Biesheuvel 1078*a3cbbb47SArd Biesheuvel static __always_inline bool vc_from_invalid_context(struct pt_regs *regs) 1079*a3cbbb47SArd Biesheuvel { 1080*a3cbbb47SArd Biesheuvel unsigned long sp, prev_sp; 1081*a3cbbb47SArd Biesheuvel 1082*a3cbbb47SArd Biesheuvel sp = (unsigned long)regs; 1083*a3cbbb47SArd Biesheuvel prev_sp = regs->sp; 1084*a3cbbb47SArd Biesheuvel 1085*a3cbbb47SArd Biesheuvel /* 1086*a3cbbb47SArd Biesheuvel * If the code was already executing on the VC2 stack when the #VC 1087*a3cbbb47SArd Biesheuvel * happened, let it proceed to the normal handling routine. This way the 1088*a3cbbb47SArd Biesheuvel * code executing on the VC2 stack can cause #VC exceptions to get handled. 1089*a3cbbb47SArd Biesheuvel */ 1090*a3cbbb47SArd Biesheuvel return is_vc2_stack(sp) && !is_vc2_stack(prev_sp); 1091*a3cbbb47SArd Biesheuvel } 1092*a3cbbb47SArd Biesheuvel 1093*a3cbbb47SArd Biesheuvel static bool vc_raw_handle_exception(struct pt_regs *regs, unsigned long error_code) 1094*a3cbbb47SArd Biesheuvel { 1095*a3cbbb47SArd Biesheuvel struct ghcb_state state; 1096*a3cbbb47SArd Biesheuvel struct es_em_ctxt ctxt; 1097*a3cbbb47SArd Biesheuvel enum es_result result; 1098*a3cbbb47SArd Biesheuvel struct ghcb *ghcb; 1099*a3cbbb47SArd Biesheuvel bool ret = true; 1100*a3cbbb47SArd Biesheuvel 1101*a3cbbb47SArd Biesheuvel ghcb = __sev_get_ghcb(&state); 1102*a3cbbb47SArd Biesheuvel 1103*a3cbbb47SArd Biesheuvel vc_ghcb_invalidate(ghcb); 1104*a3cbbb47SArd Biesheuvel result = vc_init_em_ctxt(&ctxt, regs, error_code); 1105*a3cbbb47SArd Biesheuvel 1106*a3cbbb47SArd Biesheuvel if (result == ES_OK) 1107*a3cbbb47SArd Biesheuvel result = vc_handle_exitcode(&ctxt, ghcb, error_code); 1108*a3cbbb47SArd Biesheuvel 1109*a3cbbb47SArd Biesheuvel __sev_put_ghcb(&state); 1110*a3cbbb47SArd Biesheuvel 1111*a3cbbb47SArd Biesheuvel /* Done - now check the result */ 1112*a3cbbb47SArd Biesheuvel switch (result) { 1113*a3cbbb47SArd Biesheuvel case ES_OK: 1114*a3cbbb47SArd Biesheuvel vc_finish_insn(&ctxt); 1115*a3cbbb47SArd Biesheuvel break; 1116*a3cbbb47SArd Biesheuvel case ES_UNSUPPORTED: 1117*a3cbbb47SArd Biesheuvel pr_err_ratelimited("Unsupported exit-code 0x%02lx in #VC exception (IP: 0x%lx)\n", 1118*a3cbbb47SArd Biesheuvel error_code, regs->ip); 1119*a3cbbb47SArd Biesheuvel ret = false; 1120*a3cbbb47SArd Biesheuvel break; 1121*a3cbbb47SArd Biesheuvel case ES_VMM_ERROR: 1122*a3cbbb47SArd Biesheuvel pr_err_ratelimited("Failure in communication with VMM (exit-code 0x%02lx IP: 0x%lx)\n", 1123*a3cbbb47SArd Biesheuvel error_code, regs->ip); 1124*a3cbbb47SArd Biesheuvel ret = false; 1125*a3cbbb47SArd Biesheuvel break; 1126*a3cbbb47SArd Biesheuvel case ES_DECODE_FAILED: 1127*a3cbbb47SArd Biesheuvel pr_err_ratelimited("Failed to decode instruction (exit-code 0x%02lx IP: 0x%lx)\n", 1128*a3cbbb47SArd Biesheuvel error_code, regs->ip); 1129*a3cbbb47SArd Biesheuvel ret = false; 1130*a3cbbb47SArd Biesheuvel break; 1131*a3cbbb47SArd Biesheuvel case ES_EXCEPTION: 1132*a3cbbb47SArd Biesheuvel vc_forward_exception(&ctxt); 1133*a3cbbb47SArd Biesheuvel break; 1134*a3cbbb47SArd Biesheuvel case ES_RETRY: 1135*a3cbbb47SArd Biesheuvel /* Nothing to do */ 1136*a3cbbb47SArd Biesheuvel break; 1137*a3cbbb47SArd Biesheuvel default: 1138*a3cbbb47SArd Biesheuvel pr_emerg("Unknown result in %s():%d\n", __func__, result); 1139*a3cbbb47SArd Biesheuvel /* 1140*a3cbbb47SArd Biesheuvel * Emulating the instruction which caused the #VC exception 1141*a3cbbb47SArd Biesheuvel * failed - can't continue so print debug information 1142*a3cbbb47SArd Biesheuvel */ 1143*a3cbbb47SArd Biesheuvel BUG(); 1144*a3cbbb47SArd Biesheuvel } 1145*a3cbbb47SArd Biesheuvel 1146*a3cbbb47SArd Biesheuvel return ret; 1147*a3cbbb47SArd Biesheuvel } 1148*a3cbbb47SArd Biesheuvel 1149*a3cbbb47SArd Biesheuvel static __always_inline bool vc_is_db(unsigned long error_code) 1150*a3cbbb47SArd Biesheuvel { 1151*a3cbbb47SArd Biesheuvel return error_code == SVM_EXIT_EXCP_BASE + X86_TRAP_DB; 1152*a3cbbb47SArd Biesheuvel } 1153*a3cbbb47SArd Biesheuvel 1154*a3cbbb47SArd Biesheuvel /* 1155*a3cbbb47SArd Biesheuvel * Runtime #VC exception handler when raised from kernel mode. Runs in NMI mode 1156*a3cbbb47SArd Biesheuvel * and will panic when an error happens. 1157*a3cbbb47SArd Biesheuvel */ 1158*a3cbbb47SArd Biesheuvel DEFINE_IDTENTRY_VC_KERNEL(exc_vmm_communication) 1159*a3cbbb47SArd Biesheuvel { 1160*a3cbbb47SArd Biesheuvel irqentry_state_t irq_state; 1161*a3cbbb47SArd Biesheuvel 1162*a3cbbb47SArd Biesheuvel /* 1163*a3cbbb47SArd Biesheuvel * With the current implementation it is always possible to switch to a 1164*a3cbbb47SArd Biesheuvel * safe stack because #VC exceptions only happen at known places, like 1165*a3cbbb47SArd Biesheuvel * intercepted instructions or accesses to MMIO areas/IO ports. They can 1166*a3cbbb47SArd Biesheuvel * also happen with code instrumentation when the hypervisor intercepts 1167*a3cbbb47SArd Biesheuvel * #DB, but the critical paths are forbidden to be instrumented, so #DB 1168*a3cbbb47SArd Biesheuvel * exceptions currently also only happen in safe places. 1169*a3cbbb47SArd Biesheuvel * 1170*a3cbbb47SArd Biesheuvel * But keep this here in case the noinstr annotations are violated due 1171*a3cbbb47SArd Biesheuvel * to bug elsewhere. 1172*a3cbbb47SArd Biesheuvel */ 1173*a3cbbb47SArd Biesheuvel if (unlikely(vc_from_invalid_context(regs))) { 1174*a3cbbb47SArd Biesheuvel instrumentation_begin(); 1175*a3cbbb47SArd Biesheuvel panic("Can't handle #VC exception from unsupported context\n"); 1176*a3cbbb47SArd Biesheuvel instrumentation_end(); 1177*a3cbbb47SArd Biesheuvel } 1178*a3cbbb47SArd Biesheuvel 1179*a3cbbb47SArd Biesheuvel /* 1180*a3cbbb47SArd Biesheuvel * Handle #DB before calling into !noinstr code to avoid recursive #DB. 1181*a3cbbb47SArd Biesheuvel */ 1182*a3cbbb47SArd Biesheuvel if (vc_is_db(error_code)) { 1183*a3cbbb47SArd Biesheuvel exc_debug(regs); 1184*a3cbbb47SArd Biesheuvel return; 1185*a3cbbb47SArd Biesheuvel } 1186*a3cbbb47SArd Biesheuvel 1187*a3cbbb47SArd Biesheuvel irq_state = irqentry_nmi_enter(regs); 1188*a3cbbb47SArd Biesheuvel 1189*a3cbbb47SArd Biesheuvel instrumentation_begin(); 1190*a3cbbb47SArd Biesheuvel 1191*a3cbbb47SArd Biesheuvel if (!vc_raw_handle_exception(regs, error_code)) { 1192*a3cbbb47SArd Biesheuvel /* Show some debug info */ 1193*a3cbbb47SArd Biesheuvel show_regs(regs); 1194*a3cbbb47SArd Biesheuvel 1195*a3cbbb47SArd Biesheuvel /* Ask hypervisor to sev_es_terminate */ 1196*a3cbbb47SArd Biesheuvel sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ); 1197*a3cbbb47SArd Biesheuvel 1198*a3cbbb47SArd Biesheuvel /* If that fails and we get here - just panic */ 1199*a3cbbb47SArd Biesheuvel panic("Returned from Terminate-Request to Hypervisor\n"); 1200*a3cbbb47SArd Biesheuvel } 1201*a3cbbb47SArd Biesheuvel 1202*a3cbbb47SArd Biesheuvel instrumentation_end(); 1203*a3cbbb47SArd Biesheuvel irqentry_nmi_exit(regs, irq_state); 1204*a3cbbb47SArd Biesheuvel } 1205*a3cbbb47SArd Biesheuvel 1206*a3cbbb47SArd Biesheuvel /* 1207*a3cbbb47SArd Biesheuvel * Runtime #VC exception handler when raised from user mode. Runs in IRQ mode 1208*a3cbbb47SArd Biesheuvel * and will kill the current task with SIGBUS when an error happens. 1209*a3cbbb47SArd Biesheuvel */ 1210*a3cbbb47SArd Biesheuvel DEFINE_IDTENTRY_VC_USER(exc_vmm_communication) 1211*a3cbbb47SArd Biesheuvel { 1212*a3cbbb47SArd Biesheuvel /* 1213*a3cbbb47SArd Biesheuvel * Handle #DB before calling into !noinstr code to avoid recursive #DB. 1214*a3cbbb47SArd Biesheuvel */ 1215*a3cbbb47SArd Biesheuvel if (vc_is_db(error_code)) { 1216*a3cbbb47SArd Biesheuvel noist_exc_debug(regs); 1217*a3cbbb47SArd Biesheuvel return; 1218*a3cbbb47SArd Biesheuvel } 1219*a3cbbb47SArd Biesheuvel 1220*a3cbbb47SArd Biesheuvel irqentry_enter_from_user_mode(regs); 1221*a3cbbb47SArd Biesheuvel instrumentation_begin(); 1222*a3cbbb47SArd Biesheuvel 1223*a3cbbb47SArd Biesheuvel if (!vc_raw_handle_exception(regs, error_code)) { 1224*a3cbbb47SArd Biesheuvel /* 1225*a3cbbb47SArd Biesheuvel * Do not kill the machine if user-space triggered the 1226*a3cbbb47SArd Biesheuvel * exception. Send SIGBUS instead and let user-space deal with 1227*a3cbbb47SArd Biesheuvel * it. 1228*a3cbbb47SArd Biesheuvel */ 1229*a3cbbb47SArd Biesheuvel force_sig_fault(SIGBUS, BUS_OBJERR, (void __user *)0); 1230*a3cbbb47SArd Biesheuvel } 1231*a3cbbb47SArd Biesheuvel 1232*a3cbbb47SArd Biesheuvel instrumentation_end(); 1233*a3cbbb47SArd Biesheuvel irqentry_exit_to_user_mode(regs); 1234*a3cbbb47SArd Biesheuvel } 1235*a3cbbb47SArd Biesheuvel 1236*a3cbbb47SArd Biesheuvel bool __init handle_vc_boot_ghcb(struct pt_regs *regs) 1237*a3cbbb47SArd Biesheuvel { 1238*a3cbbb47SArd Biesheuvel unsigned long exit_code = regs->orig_ax; 1239*a3cbbb47SArd Biesheuvel struct es_em_ctxt ctxt; 1240*a3cbbb47SArd Biesheuvel enum es_result result; 1241*a3cbbb47SArd Biesheuvel 1242*a3cbbb47SArd Biesheuvel vc_ghcb_invalidate(boot_ghcb); 1243*a3cbbb47SArd Biesheuvel 1244*a3cbbb47SArd Biesheuvel result = vc_init_em_ctxt(&ctxt, regs, exit_code); 1245*a3cbbb47SArd Biesheuvel if (result == ES_OK) 1246*a3cbbb47SArd Biesheuvel result = vc_handle_exitcode(&ctxt, boot_ghcb, exit_code); 1247*a3cbbb47SArd Biesheuvel 1248*a3cbbb47SArd Biesheuvel /* Done - now check the result */ 1249*a3cbbb47SArd Biesheuvel switch (result) { 1250*a3cbbb47SArd Biesheuvel case ES_OK: 1251*a3cbbb47SArd Biesheuvel vc_finish_insn(&ctxt); 1252*a3cbbb47SArd Biesheuvel break; 1253*a3cbbb47SArd Biesheuvel case ES_UNSUPPORTED: 1254*a3cbbb47SArd Biesheuvel early_printk("PANIC: Unsupported exit-code 0x%02lx in early #VC exception (IP: 0x%lx)\n", 1255*a3cbbb47SArd Biesheuvel exit_code, regs->ip); 1256*a3cbbb47SArd Biesheuvel goto fail; 1257*a3cbbb47SArd Biesheuvel case ES_VMM_ERROR: 1258*a3cbbb47SArd Biesheuvel early_printk("PANIC: Failure in communication with VMM (exit-code 0x%02lx IP: 0x%lx)\n", 1259*a3cbbb47SArd Biesheuvel exit_code, regs->ip); 1260*a3cbbb47SArd Biesheuvel goto fail; 1261*a3cbbb47SArd Biesheuvel case ES_DECODE_FAILED: 1262*a3cbbb47SArd Biesheuvel early_printk("PANIC: Failed to decode instruction (exit-code 0x%02lx IP: 0x%lx)\n", 1263*a3cbbb47SArd Biesheuvel exit_code, regs->ip); 1264*a3cbbb47SArd Biesheuvel goto fail; 1265*a3cbbb47SArd Biesheuvel case ES_EXCEPTION: 1266*a3cbbb47SArd Biesheuvel vc_early_forward_exception(&ctxt); 1267*a3cbbb47SArd Biesheuvel break; 1268*a3cbbb47SArd Biesheuvel case ES_RETRY: 1269*a3cbbb47SArd Biesheuvel /* Nothing to do */ 1270*a3cbbb47SArd Biesheuvel break; 1271*a3cbbb47SArd Biesheuvel default: 1272*a3cbbb47SArd Biesheuvel BUG(); 1273*a3cbbb47SArd Biesheuvel } 1274*a3cbbb47SArd Biesheuvel 1275*a3cbbb47SArd Biesheuvel return true; 1276*a3cbbb47SArd Biesheuvel 1277*a3cbbb47SArd Biesheuvel fail: 1278*a3cbbb47SArd Biesheuvel show_regs(regs); 1279*a3cbbb47SArd Biesheuvel 1280*a3cbbb47SArd Biesheuvel sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ); 1281*a3cbbb47SArd Biesheuvel } 1282*a3cbbb47SArd Biesheuvel 1283*a3cbbb47SArd Biesheuvel /* 1284*a3cbbb47SArd Biesheuvel * Initial set up of SNP relies on information provided by the 1285*a3cbbb47SArd Biesheuvel * Confidential Computing blob, which can be passed to the kernel 1286*a3cbbb47SArd Biesheuvel * in the following ways, depending on how it is booted: 1287*a3cbbb47SArd Biesheuvel * 1288*a3cbbb47SArd Biesheuvel * - when booted via the boot/decompress kernel: 1289*a3cbbb47SArd Biesheuvel * - via boot_params 1290*a3cbbb47SArd Biesheuvel * 1291*a3cbbb47SArd Biesheuvel * - when booted directly by firmware/bootloader (e.g. CONFIG_PVH): 1292*a3cbbb47SArd Biesheuvel * - via a setup_data entry, as defined by the Linux Boot Protocol 1293*a3cbbb47SArd Biesheuvel * 1294*a3cbbb47SArd Biesheuvel * Scan for the blob in that order. 1295*a3cbbb47SArd Biesheuvel */ 1296*a3cbbb47SArd Biesheuvel static __head struct cc_blob_sev_info *find_cc_blob(struct boot_params *bp) 1297*a3cbbb47SArd Biesheuvel { 1298*a3cbbb47SArd Biesheuvel struct cc_blob_sev_info *cc_info; 1299*a3cbbb47SArd Biesheuvel 1300*a3cbbb47SArd Biesheuvel /* Boot kernel would have passed the CC blob via boot_params. */ 1301*a3cbbb47SArd Biesheuvel if (bp->cc_blob_address) { 1302*a3cbbb47SArd Biesheuvel cc_info = (struct cc_blob_sev_info *)(unsigned long)bp->cc_blob_address; 1303*a3cbbb47SArd Biesheuvel goto found_cc_info; 1304*a3cbbb47SArd Biesheuvel } 1305*a3cbbb47SArd Biesheuvel 1306*a3cbbb47SArd Biesheuvel /* 1307*a3cbbb47SArd Biesheuvel * If kernel was booted directly, without the use of the 1308*a3cbbb47SArd Biesheuvel * boot/decompression kernel, the CC blob may have been passed via 1309*a3cbbb47SArd Biesheuvel * setup_data instead. 1310*a3cbbb47SArd Biesheuvel */ 1311*a3cbbb47SArd Biesheuvel cc_info = find_cc_blob_setup_data(bp); 1312*a3cbbb47SArd Biesheuvel if (!cc_info) 1313*a3cbbb47SArd Biesheuvel return NULL; 1314*a3cbbb47SArd Biesheuvel 1315*a3cbbb47SArd Biesheuvel found_cc_info: 1316*a3cbbb47SArd Biesheuvel if (cc_info->magic != CC_BLOB_SEV_HDR_MAGIC) 1317*a3cbbb47SArd Biesheuvel snp_abort(); 1318*a3cbbb47SArd Biesheuvel 1319*a3cbbb47SArd Biesheuvel return cc_info; 1320*a3cbbb47SArd Biesheuvel } 1321*a3cbbb47SArd Biesheuvel 1322*a3cbbb47SArd Biesheuvel static __head void svsm_setup(struct cc_blob_sev_info *cc_info) 1323*a3cbbb47SArd Biesheuvel { 1324*a3cbbb47SArd Biesheuvel struct svsm_call call = {}; 1325*a3cbbb47SArd Biesheuvel int ret; 1326*a3cbbb47SArd Biesheuvel u64 pa; 1327*a3cbbb47SArd Biesheuvel 1328*a3cbbb47SArd Biesheuvel /* 1329*a3cbbb47SArd Biesheuvel * Record the SVSM Calling Area address (CAA) if the guest is not 1330*a3cbbb47SArd Biesheuvel * running at VMPL0. The CA will be used to communicate with the 1331*a3cbbb47SArd Biesheuvel * SVSM to perform the SVSM services. 1332*a3cbbb47SArd Biesheuvel */ 1333*a3cbbb47SArd Biesheuvel if (!svsm_setup_ca(cc_info)) 1334*a3cbbb47SArd Biesheuvel return; 1335*a3cbbb47SArd Biesheuvel 1336*a3cbbb47SArd Biesheuvel /* 1337*a3cbbb47SArd Biesheuvel * It is very early in the boot and the kernel is running identity 1338*a3cbbb47SArd Biesheuvel * mapped but without having adjusted the pagetables to where the 1339*a3cbbb47SArd Biesheuvel * kernel was loaded (physbase), so the get the CA address using 1340*a3cbbb47SArd Biesheuvel * RIP-relative addressing. 1341*a3cbbb47SArd Biesheuvel */ 1342*a3cbbb47SArd Biesheuvel pa = (u64)rip_rel_ptr(&boot_svsm_ca_page); 1343*a3cbbb47SArd Biesheuvel 1344*a3cbbb47SArd Biesheuvel /* 1345*a3cbbb47SArd Biesheuvel * Switch over to the boot SVSM CA while the current CA is still 1346*a3cbbb47SArd Biesheuvel * addressable. There is no GHCB at this point so use the MSR protocol. 1347*a3cbbb47SArd Biesheuvel * 1348*a3cbbb47SArd Biesheuvel * SVSM_CORE_REMAP_CA call: 1349*a3cbbb47SArd Biesheuvel * RAX = 0 (Protocol=0, CallID=0) 1350*a3cbbb47SArd Biesheuvel * RCX = New CA GPA 1351*a3cbbb47SArd Biesheuvel */ 1352*a3cbbb47SArd Biesheuvel call.caa = svsm_get_caa(); 1353*a3cbbb47SArd Biesheuvel call.rax = SVSM_CORE_CALL(SVSM_CORE_REMAP_CA); 1354*a3cbbb47SArd Biesheuvel call.rcx = pa; 1355*a3cbbb47SArd Biesheuvel ret = svsm_perform_call_protocol(&call); 1356*a3cbbb47SArd Biesheuvel if (ret) 1357*a3cbbb47SArd Biesheuvel sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_SVSM_CA_REMAP_FAIL); 1358*a3cbbb47SArd Biesheuvel 1359*a3cbbb47SArd Biesheuvel RIP_REL_REF(boot_svsm_caa) = (struct svsm_ca *)pa; 1360*a3cbbb47SArd Biesheuvel RIP_REL_REF(boot_svsm_caa_pa) = pa; 1361*a3cbbb47SArd Biesheuvel } 1362*a3cbbb47SArd Biesheuvel 1363*a3cbbb47SArd Biesheuvel bool __head snp_init(struct boot_params *bp) 1364*a3cbbb47SArd Biesheuvel { 1365*a3cbbb47SArd Biesheuvel struct cc_blob_sev_info *cc_info; 1366*a3cbbb47SArd Biesheuvel 1367*a3cbbb47SArd Biesheuvel if (!bp) 1368*a3cbbb47SArd Biesheuvel return false; 1369*a3cbbb47SArd Biesheuvel 1370*a3cbbb47SArd Biesheuvel cc_info = find_cc_blob(bp); 1371*a3cbbb47SArd Biesheuvel if (!cc_info) 1372*a3cbbb47SArd Biesheuvel return false; 1373*a3cbbb47SArd Biesheuvel 1374*a3cbbb47SArd Biesheuvel if (cc_info->secrets_phys && cc_info->secrets_len == PAGE_SIZE) 1375*a3cbbb47SArd Biesheuvel secrets_pa = cc_info->secrets_phys; 1376*a3cbbb47SArd Biesheuvel else 1377*a3cbbb47SArd Biesheuvel return false; 1378*a3cbbb47SArd Biesheuvel 1379*a3cbbb47SArd Biesheuvel setup_cpuid_table(cc_info); 1380*a3cbbb47SArd Biesheuvel 1381*a3cbbb47SArd Biesheuvel svsm_setup(cc_info); 1382*a3cbbb47SArd Biesheuvel 1383*a3cbbb47SArd Biesheuvel /* 1384*a3cbbb47SArd Biesheuvel * The CC blob will be used later to access the secrets page. Cache 1385*a3cbbb47SArd Biesheuvel * it here like the boot kernel does. 1386*a3cbbb47SArd Biesheuvel */ 1387*a3cbbb47SArd Biesheuvel bp->cc_blob_address = (u32)(unsigned long)cc_info; 1388*a3cbbb47SArd Biesheuvel 1389*a3cbbb47SArd Biesheuvel return true; 1390*a3cbbb47SArd Biesheuvel } 1391*a3cbbb47SArd Biesheuvel 1392*a3cbbb47SArd Biesheuvel void __head __noreturn snp_abort(void) 1393*a3cbbb47SArd Biesheuvel { 1394*a3cbbb47SArd Biesheuvel sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED); 1395*a3cbbb47SArd Biesheuvel } 1396