1*e759959fSBrijesh Singh // SPDX-License-Identifier: GPL-2.0 2*e759959fSBrijesh Singh /* 3*e759959fSBrijesh Singh * AMD Encrypted Register State Support 4*e759959fSBrijesh Singh * 5*e759959fSBrijesh Singh * Author: Joerg Roedel <jroedel@suse.de> 6*e759959fSBrijesh Singh */ 7*e759959fSBrijesh Singh 8*e759959fSBrijesh Singh /* 9*e759959fSBrijesh Singh * misc.h needs to be first because it knows how to include the other kernel 10*e759959fSBrijesh Singh * headers in the pre-decompression code in a way that does not break 11*e759959fSBrijesh Singh * compilation. 12*e759959fSBrijesh Singh */ 13*e759959fSBrijesh Singh #include "misc.h" 14*e759959fSBrijesh Singh 15*e759959fSBrijesh Singh #include <asm/pgtable_types.h> 16*e759959fSBrijesh Singh #include <asm/sev.h> 17*e759959fSBrijesh Singh #include <asm/trapnr.h> 18*e759959fSBrijesh Singh #include <asm/trap_pf.h> 19*e759959fSBrijesh Singh #include <asm/msr-index.h> 20*e759959fSBrijesh Singh #include <asm/fpu/xcr.h> 21*e759959fSBrijesh Singh #include <asm/ptrace.h> 22*e759959fSBrijesh Singh #include <asm/svm.h> 23*e759959fSBrijesh Singh 24*e759959fSBrijesh Singh #include "error.h" 25*e759959fSBrijesh Singh 26*e759959fSBrijesh Singh struct ghcb boot_ghcb_page __aligned(PAGE_SIZE); 27*e759959fSBrijesh Singh struct ghcb *boot_ghcb; 28*e759959fSBrijesh Singh 29*e759959fSBrijesh Singh /* 30*e759959fSBrijesh Singh * Copy a version of this function here - insn-eval.c can't be used in 31*e759959fSBrijesh Singh * pre-decompression code. 32*e759959fSBrijesh Singh */ 33*e759959fSBrijesh Singh static bool insn_has_rep_prefix(struct insn *insn) 34*e759959fSBrijesh Singh { 35*e759959fSBrijesh Singh insn_byte_t p; 36*e759959fSBrijesh Singh int i; 37*e759959fSBrijesh Singh 38*e759959fSBrijesh Singh insn_get_prefixes(insn); 39*e759959fSBrijesh Singh 40*e759959fSBrijesh Singh for_each_insn_prefix(insn, i, p) { 41*e759959fSBrijesh Singh if (p == 0xf2 || p == 0xf3) 42*e759959fSBrijesh Singh return true; 43*e759959fSBrijesh Singh } 44*e759959fSBrijesh Singh 45*e759959fSBrijesh Singh return false; 46*e759959fSBrijesh Singh } 47*e759959fSBrijesh Singh 48*e759959fSBrijesh Singh /* 49*e759959fSBrijesh Singh * Only a dummy for insn_get_seg_base() - Early boot-code is 64bit only and 50*e759959fSBrijesh Singh * doesn't use segments. 51*e759959fSBrijesh Singh */ 52*e759959fSBrijesh Singh static unsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx) 53*e759959fSBrijesh Singh { 54*e759959fSBrijesh Singh return 0UL; 55*e759959fSBrijesh Singh } 56*e759959fSBrijesh Singh 57*e759959fSBrijesh Singh static inline u64 sev_es_rd_ghcb_msr(void) 58*e759959fSBrijesh Singh { 59*e759959fSBrijesh Singh unsigned long low, high; 60*e759959fSBrijesh Singh 61*e759959fSBrijesh Singh asm volatile("rdmsr" : "=a" (low), "=d" (high) : 62*e759959fSBrijesh Singh "c" (MSR_AMD64_SEV_ES_GHCB)); 63*e759959fSBrijesh Singh 64*e759959fSBrijesh Singh return ((high << 32) | low); 65*e759959fSBrijesh Singh } 66*e759959fSBrijesh Singh 67*e759959fSBrijesh Singh static inline void sev_es_wr_ghcb_msr(u64 val) 68*e759959fSBrijesh Singh { 69*e759959fSBrijesh Singh u32 low, high; 70*e759959fSBrijesh Singh 71*e759959fSBrijesh Singh low = val & 0xffffffffUL; 72*e759959fSBrijesh Singh high = val >> 32; 73*e759959fSBrijesh Singh 74*e759959fSBrijesh Singh asm volatile("wrmsr" : : "c" (MSR_AMD64_SEV_ES_GHCB), 75*e759959fSBrijesh Singh "a"(low), "d" (high) : "memory"); 76*e759959fSBrijesh Singh } 77*e759959fSBrijesh Singh 78*e759959fSBrijesh Singh static enum es_result vc_decode_insn(struct es_em_ctxt *ctxt) 79*e759959fSBrijesh Singh { 80*e759959fSBrijesh Singh char buffer[MAX_INSN_SIZE]; 81*e759959fSBrijesh Singh int ret; 82*e759959fSBrijesh Singh 83*e759959fSBrijesh Singh memcpy(buffer, (unsigned char *)ctxt->regs->ip, MAX_INSN_SIZE); 84*e759959fSBrijesh Singh 85*e759959fSBrijesh Singh ret = insn_decode(&ctxt->insn, buffer, MAX_INSN_SIZE, INSN_MODE_64); 86*e759959fSBrijesh Singh if (ret < 0) 87*e759959fSBrijesh Singh return ES_DECODE_FAILED; 88*e759959fSBrijesh Singh 89*e759959fSBrijesh Singh return ES_OK; 90*e759959fSBrijesh Singh } 91*e759959fSBrijesh Singh 92*e759959fSBrijesh Singh static enum es_result vc_write_mem(struct es_em_ctxt *ctxt, 93*e759959fSBrijesh Singh void *dst, char *buf, size_t size) 94*e759959fSBrijesh Singh { 95*e759959fSBrijesh Singh memcpy(dst, buf, size); 96*e759959fSBrijesh Singh 97*e759959fSBrijesh Singh return ES_OK; 98*e759959fSBrijesh Singh } 99*e759959fSBrijesh Singh 100*e759959fSBrijesh Singh static enum es_result vc_read_mem(struct es_em_ctxt *ctxt, 101*e759959fSBrijesh Singh void *src, char *buf, size_t size) 102*e759959fSBrijesh Singh { 103*e759959fSBrijesh Singh memcpy(buf, src, size); 104*e759959fSBrijesh Singh 105*e759959fSBrijesh Singh return ES_OK; 106*e759959fSBrijesh Singh } 107*e759959fSBrijesh Singh 108*e759959fSBrijesh Singh #undef __init 109*e759959fSBrijesh Singh #undef __pa 110*e759959fSBrijesh Singh #define __init 111*e759959fSBrijesh Singh #define __pa(x) ((unsigned long)(x)) 112*e759959fSBrijesh Singh 113*e759959fSBrijesh Singh #define __BOOT_COMPRESSED 114*e759959fSBrijesh Singh 115*e759959fSBrijesh Singh /* Basic instruction decoding support needed */ 116*e759959fSBrijesh Singh #include "../../lib/inat.c" 117*e759959fSBrijesh Singh #include "../../lib/insn.c" 118*e759959fSBrijesh Singh 119*e759959fSBrijesh Singh /* Include code for early handlers */ 120*e759959fSBrijesh Singh #include "../../kernel/sev-shared.c" 121*e759959fSBrijesh Singh 122*e759959fSBrijesh Singh static bool early_setup_sev_es(void) 123*e759959fSBrijesh Singh { 124*e759959fSBrijesh Singh if (!sev_es_negotiate_protocol()) 125*e759959fSBrijesh Singh sev_es_terminate(GHCB_SEV_ES_REASON_PROTOCOL_UNSUPPORTED); 126*e759959fSBrijesh Singh 127*e759959fSBrijesh Singh if (set_page_decrypted((unsigned long)&boot_ghcb_page)) 128*e759959fSBrijesh Singh return false; 129*e759959fSBrijesh Singh 130*e759959fSBrijesh Singh /* Page is now mapped decrypted, clear it */ 131*e759959fSBrijesh Singh memset(&boot_ghcb_page, 0, sizeof(boot_ghcb_page)); 132*e759959fSBrijesh Singh 133*e759959fSBrijesh Singh boot_ghcb = &boot_ghcb_page; 134*e759959fSBrijesh Singh 135*e759959fSBrijesh Singh /* Initialize lookup tables for the instruction decoder */ 136*e759959fSBrijesh Singh inat_init_tables(); 137*e759959fSBrijesh Singh 138*e759959fSBrijesh Singh return true; 139*e759959fSBrijesh Singh } 140*e759959fSBrijesh Singh 141*e759959fSBrijesh Singh void sev_es_shutdown_ghcb(void) 142*e759959fSBrijesh Singh { 143*e759959fSBrijesh Singh if (!boot_ghcb) 144*e759959fSBrijesh Singh return; 145*e759959fSBrijesh Singh 146*e759959fSBrijesh Singh if (!sev_es_check_cpu_features()) 147*e759959fSBrijesh Singh error("SEV-ES CPU Features missing."); 148*e759959fSBrijesh Singh 149*e759959fSBrijesh Singh /* 150*e759959fSBrijesh Singh * GHCB Page must be flushed from the cache and mapped encrypted again. 151*e759959fSBrijesh Singh * Otherwise the running kernel will see strange cache effects when 152*e759959fSBrijesh Singh * trying to use that page. 153*e759959fSBrijesh Singh */ 154*e759959fSBrijesh Singh if (set_page_encrypted((unsigned long)&boot_ghcb_page)) 155*e759959fSBrijesh Singh error("Can't map GHCB page encrypted"); 156*e759959fSBrijesh Singh 157*e759959fSBrijesh Singh /* 158*e759959fSBrijesh Singh * GHCB page is mapped encrypted again and flushed from the cache. 159*e759959fSBrijesh Singh * Mark it non-present now to catch bugs when #VC exceptions trigger 160*e759959fSBrijesh Singh * after this point. 161*e759959fSBrijesh Singh */ 162*e759959fSBrijesh Singh if (set_page_non_present((unsigned long)&boot_ghcb_page)) 163*e759959fSBrijesh Singh error("Can't unmap GHCB page"); 164*e759959fSBrijesh Singh } 165*e759959fSBrijesh Singh 166*e759959fSBrijesh Singh bool sev_es_check_ghcb_fault(unsigned long address) 167*e759959fSBrijesh Singh { 168*e759959fSBrijesh Singh /* Check whether the fault was on the GHCB page */ 169*e759959fSBrijesh Singh return ((address & PAGE_MASK) == (unsigned long)&boot_ghcb_page); 170*e759959fSBrijesh Singh } 171*e759959fSBrijesh Singh 172*e759959fSBrijesh Singh void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code) 173*e759959fSBrijesh Singh { 174*e759959fSBrijesh Singh struct es_em_ctxt ctxt; 175*e759959fSBrijesh Singh enum es_result result; 176*e759959fSBrijesh Singh 177*e759959fSBrijesh Singh if (!boot_ghcb && !early_setup_sev_es()) 178*e759959fSBrijesh Singh sev_es_terminate(GHCB_SEV_ES_REASON_GENERAL_REQUEST); 179*e759959fSBrijesh Singh 180*e759959fSBrijesh Singh vc_ghcb_invalidate(boot_ghcb); 181*e759959fSBrijesh Singh result = vc_init_em_ctxt(&ctxt, regs, exit_code); 182*e759959fSBrijesh Singh if (result != ES_OK) 183*e759959fSBrijesh Singh goto finish; 184*e759959fSBrijesh Singh 185*e759959fSBrijesh Singh switch (exit_code) { 186*e759959fSBrijesh Singh case SVM_EXIT_RDTSC: 187*e759959fSBrijesh Singh case SVM_EXIT_RDTSCP: 188*e759959fSBrijesh Singh result = vc_handle_rdtsc(boot_ghcb, &ctxt, exit_code); 189*e759959fSBrijesh Singh break; 190*e759959fSBrijesh Singh case SVM_EXIT_IOIO: 191*e759959fSBrijesh Singh result = vc_handle_ioio(boot_ghcb, &ctxt); 192*e759959fSBrijesh Singh break; 193*e759959fSBrijesh Singh case SVM_EXIT_CPUID: 194*e759959fSBrijesh Singh result = vc_handle_cpuid(boot_ghcb, &ctxt); 195*e759959fSBrijesh Singh break; 196*e759959fSBrijesh Singh default: 197*e759959fSBrijesh Singh result = ES_UNSUPPORTED; 198*e759959fSBrijesh Singh break; 199*e759959fSBrijesh Singh } 200*e759959fSBrijesh Singh 201*e759959fSBrijesh Singh finish: 202*e759959fSBrijesh Singh if (result == ES_OK) 203*e759959fSBrijesh Singh vc_finish_insn(&ctxt); 204*e759959fSBrijesh Singh else if (result != ES_RETRY) 205*e759959fSBrijesh Singh sev_es_terminate(GHCB_SEV_ES_REASON_GENERAL_REQUEST); 206*e759959fSBrijesh Singh } 207