162306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include <linux/kvm_host.h> 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include "irq.h" 662306a36Sopenharmony_ci#include "mmu.h" 762306a36Sopenharmony_ci#include "kvm_cache_regs.h" 862306a36Sopenharmony_ci#include "x86.h" 962306a36Sopenharmony_ci#include "smm.h" 1062306a36Sopenharmony_ci#include "cpuid.h" 1162306a36Sopenharmony_ci#include "pmu.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/vmalloc.h> 1762306a36Sopenharmony_ci#include <linux/highmem.h> 1862306a36Sopenharmony_ci#include <linux/amd-iommu.h> 1962306a36Sopenharmony_ci#include <linux/sched.h> 2062306a36Sopenharmony_ci#include <linux/trace_events.h> 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci#include <linux/hashtable.h> 2362306a36Sopenharmony_ci#include <linux/objtool.h> 2462306a36Sopenharmony_ci#include <linux/psp-sev.h> 2562306a36Sopenharmony_ci#include <linux/file.h> 2662306a36Sopenharmony_ci#include <linux/pagemap.h> 2762306a36Sopenharmony_ci#include <linux/swap.h> 2862306a36Sopenharmony_ci#include <linux/rwsem.h> 2962306a36Sopenharmony_ci#include <linux/cc_platform.h> 3062306a36Sopenharmony_ci#include <linux/smp.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include <asm/apic.h> 3362306a36Sopenharmony_ci#include <asm/perf_event.h> 3462306a36Sopenharmony_ci#include <asm/tlbflush.h> 3562306a36Sopenharmony_ci#include <asm/desc.h> 3662306a36Sopenharmony_ci#include <asm/debugreg.h> 3762306a36Sopenharmony_ci#include <asm/kvm_para.h> 3862306a36Sopenharmony_ci#include <asm/irq_remapping.h> 3962306a36Sopenharmony_ci#include <asm/spec-ctrl.h> 4062306a36Sopenharmony_ci#include <asm/cpu_device_id.h> 4162306a36Sopenharmony_ci#include <asm/traps.h> 4262306a36Sopenharmony_ci#include <asm/reboot.h> 4362306a36Sopenharmony_ci#include <asm/fpu/api.h> 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#include <trace/events/ipi.h> 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#include "trace.h" 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#include "svm.h" 5062306a36Sopenharmony_ci#include "svm_ops.h" 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#include "kvm_onhyperv.h" 5362306a36Sopenharmony_ci#include "svm_onhyperv.h" 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ciMODULE_AUTHOR("Qumranet"); 5662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#ifdef MODULE 5962306a36Sopenharmony_cistatic const struct x86_cpu_id svm_cpu_id[] = { 6062306a36Sopenharmony_ci X86_MATCH_FEATURE(X86_FEATURE_SVM, NULL), 6162306a36Sopenharmony_ci {} 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(x86cpu, svm_cpu_id); 6462306a36Sopenharmony_ci#endif 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define SEG_TYPE_LDT 2 6762306a36Sopenharmony_ci#define SEG_TYPE_BUSY_TSS16 3 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic bool erratum_383_found __read_mostly; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ciu32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* 7462306a36Sopenharmony_ci * Set osvw_len to higher value when updated Revision Guides 7562306a36Sopenharmony_ci * are published and we know what the new status bits are 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_cistatic uint64_t osvw_len = 4, osvw_status; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic DEFINE_PER_CPU(u64, current_tsc_ratio); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define X2APIC_MSR(x) (APIC_BASE_MSR + (x >> 4)) 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic const struct svm_direct_access_msrs { 8462306a36Sopenharmony_ci u32 index; /* Index of the MSR */ 8562306a36Sopenharmony_ci bool always; /* True if intercept is initially cleared */ 8662306a36Sopenharmony_ci} direct_access_msrs[MAX_DIRECT_ACCESS_MSRS] = { 8762306a36Sopenharmony_ci { .index = MSR_STAR, .always = true }, 8862306a36Sopenharmony_ci { .index = MSR_IA32_SYSENTER_CS, .always = true }, 8962306a36Sopenharmony_ci { .index = MSR_IA32_SYSENTER_EIP, .always = false }, 9062306a36Sopenharmony_ci { .index = MSR_IA32_SYSENTER_ESP, .always = false }, 9162306a36Sopenharmony_ci#ifdef CONFIG_X86_64 9262306a36Sopenharmony_ci { .index = MSR_GS_BASE, .always = true }, 9362306a36Sopenharmony_ci { .index = MSR_FS_BASE, .always = true }, 9462306a36Sopenharmony_ci { .index = MSR_KERNEL_GS_BASE, .always = true }, 9562306a36Sopenharmony_ci { .index = MSR_LSTAR, .always = true }, 9662306a36Sopenharmony_ci { .index = MSR_CSTAR, .always = true }, 9762306a36Sopenharmony_ci { .index = MSR_SYSCALL_MASK, .always = true }, 9862306a36Sopenharmony_ci#endif 9962306a36Sopenharmony_ci { .index = MSR_IA32_SPEC_CTRL, .always = false }, 10062306a36Sopenharmony_ci { .index = MSR_IA32_PRED_CMD, .always = false }, 10162306a36Sopenharmony_ci { .index = MSR_IA32_FLUSH_CMD, .always = false }, 10262306a36Sopenharmony_ci { .index = MSR_IA32_LASTBRANCHFROMIP, .always = false }, 10362306a36Sopenharmony_ci { .index = MSR_IA32_LASTBRANCHTOIP, .always = false }, 10462306a36Sopenharmony_ci { .index = MSR_IA32_LASTINTFROMIP, .always = false }, 10562306a36Sopenharmony_ci { .index = MSR_IA32_LASTINTTOIP, .always = false }, 10662306a36Sopenharmony_ci { .index = MSR_EFER, .always = false }, 10762306a36Sopenharmony_ci { .index = MSR_IA32_CR_PAT, .always = false }, 10862306a36Sopenharmony_ci { .index = MSR_AMD64_SEV_ES_GHCB, .always = true }, 10962306a36Sopenharmony_ci { .index = MSR_TSC_AUX, .always = false }, 11062306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_ID), .always = false }, 11162306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_LVR), .always = false }, 11262306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_TASKPRI), .always = false }, 11362306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_ARBPRI), .always = false }, 11462306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_PROCPRI), .always = false }, 11562306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_EOI), .always = false }, 11662306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_RRR), .always = false }, 11762306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_LDR), .always = false }, 11862306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_DFR), .always = false }, 11962306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_SPIV), .always = false }, 12062306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_ISR), .always = false }, 12162306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_TMR), .always = false }, 12262306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_IRR), .always = false }, 12362306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_ESR), .always = false }, 12462306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_ICR), .always = false }, 12562306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_ICR2), .always = false }, 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* 12862306a36Sopenharmony_ci * Note: 12962306a36Sopenharmony_ci * AMD does not virtualize APIC TSC-deadline timer mode, but it is 13062306a36Sopenharmony_ci * emulated by KVM. When setting APIC LVTT (0x832) register bit 18, 13162306a36Sopenharmony_ci * the AVIC hardware would generate GP fault. Therefore, always 13262306a36Sopenharmony_ci * intercept the MSR 0x832, and do not setup direct_access_msr. 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_LVTTHMR), .always = false }, 13562306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_LVTPC), .always = false }, 13662306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_LVT0), .always = false }, 13762306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_LVT1), .always = false }, 13862306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_LVTERR), .always = false }, 13962306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_TMICT), .always = false }, 14062306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_TMCCT), .always = false }, 14162306a36Sopenharmony_ci { .index = X2APIC_MSR(APIC_TDCR), .always = false }, 14262306a36Sopenharmony_ci { .index = MSR_INVALID, .always = false }, 14362306a36Sopenharmony_ci}; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/* 14662306a36Sopenharmony_ci * These 2 parameters are used to config the controls for Pause-Loop Exiting: 14762306a36Sopenharmony_ci * pause_filter_count: On processors that support Pause filtering(indicated 14862306a36Sopenharmony_ci * by CPUID Fn8000_000A_EDX), the VMCB provides a 16 bit pause filter 14962306a36Sopenharmony_ci * count value. On VMRUN this value is loaded into an internal counter. 15062306a36Sopenharmony_ci * Each time a pause instruction is executed, this counter is decremented 15162306a36Sopenharmony_ci * until it reaches zero at which time a #VMEXIT is generated if pause 15262306a36Sopenharmony_ci * intercept is enabled. Refer to AMD APM Vol 2 Section 15.14.4 Pause 15362306a36Sopenharmony_ci * Intercept Filtering for more details. 15462306a36Sopenharmony_ci * This also indicate if ple logic enabled. 15562306a36Sopenharmony_ci * 15662306a36Sopenharmony_ci * pause_filter_thresh: In addition, some processor families support advanced 15762306a36Sopenharmony_ci * pause filtering (indicated by CPUID Fn8000_000A_EDX) upper bound on 15862306a36Sopenharmony_ci * the amount of time a guest is allowed to execute in a pause loop. 15962306a36Sopenharmony_ci * In this mode, a 16-bit pause filter threshold field is added in the 16062306a36Sopenharmony_ci * VMCB. The threshold value is a cycle count that is used to reset the 16162306a36Sopenharmony_ci * pause counter. As with simple pause filtering, VMRUN loads the pause 16262306a36Sopenharmony_ci * count value from VMCB into an internal counter. Then, on each pause 16362306a36Sopenharmony_ci * instruction the hardware checks the elapsed number of cycles since 16462306a36Sopenharmony_ci * the most recent pause instruction against the pause filter threshold. 16562306a36Sopenharmony_ci * If the elapsed cycle count is greater than the pause filter threshold, 16662306a36Sopenharmony_ci * then the internal pause count is reloaded from the VMCB and execution 16762306a36Sopenharmony_ci * continues. If the elapsed cycle count is less than the pause filter 16862306a36Sopenharmony_ci * threshold, then the internal pause count is decremented. If the count 16962306a36Sopenharmony_ci * value is less than zero and PAUSE intercept is enabled, a #VMEXIT is 17062306a36Sopenharmony_ci * triggered. If advanced pause filtering is supported and pause filter 17162306a36Sopenharmony_ci * threshold field is set to zero, the filter will operate in the simpler, 17262306a36Sopenharmony_ci * count only mode. 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic unsigned short pause_filter_thresh = KVM_DEFAULT_PLE_GAP; 17662306a36Sopenharmony_cimodule_param(pause_filter_thresh, ushort, 0444); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic unsigned short pause_filter_count = KVM_SVM_DEFAULT_PLE_WINDOW; 17962306a36Sopenharmony_cimodule_param(pause_filter_count, ushort, 0444); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci/* Default doubles per-vcpu window every exit. */ 18262306a36Sopenharmony_cistatic unsigned short pause_filter_count_grow = KVM_DEFAULT_PLE_WINDOW_GROW; 18362306a36Sopenharmony_cimodule_param(pause_filter_count_grow, ushort, 0444); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci/* Default resets per-vcpu window every exit to pause_filter_count. */ 18662306a36Sopenharmony_cistatic unsigned short pause_filter_count_shrink = KVM_DEFAULT_PLE_WINDOW_SHRINK; 18762306a36Sopenharmony_cimodule_param(pause_filter_count_shrink, ushort, 0444); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci/* Default is to compute the maximum so we can never overflow. */ 19062306a36Sopenharmony_cistatic unsigned short pause_filter_count_max = KVM_SVM_DEFAULT_PLE_WINDOW_MAX; 19162306a36Sopenharmony_cimodule_param(pause_filter_count_max, ushort, 0444); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/* 19462306a36Sopenharmony_ci * Use nested page tables by default. Note, NPT may get forced off by 19562306a36Sopenharmony_ci * svm_hardware_setup() if it's unsupported by hardware or the host kernel. 19662306a36Sopenharmony_ci */ 19762306a36Sopenharmony_cibool npt_enabled = true; 19862306a36Sopenharmony_cimodule_param_named(npt, npt_enabled, bool, 0444); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci/* allow nested virtualization in KVM/SVM */ 20162306a36Sopenharmony_cistatic int nested = true; 20262306a36Sopenharmony_cimodule_param(nested, int, S_IRUGO); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci/* enable/disable Next RIP Save */ 20562306a36Sopenharmony_ciint nrips = true; 20662306a36Sopenharmony_cimodule_param(nrips, int, 0444); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci/* enable/disable Virtual VMLOAD VMSAVE */ 20962306a36Sopenharmony_cistatic int vls = true; 21062306a36Sopenharmony_cimodule_param(vls, int, 0444); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci/* enable/disable Virtual GIF */ 21362306a36Sopenharmony_ciint vgif = true; 21462306a36Sopenharmony_cimodule_param(vgif, int, 0444); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci/* enable/disable LBR virtualization */ 21762306a36Sopenharmony_cistatic int lbrv = true; 21862306a36Sopenharmony_cimodule_param(lbrv, int, 0444); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic int tsc_scaling = true; 22162306a36Sopenharmony_cimodule_param(tsc_scaling, int, 0444); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci/* 22462306a36Sopenharmony_ci * enable / disable AVIC. Because the defaults differ for APICv 22562306a36Sopenharmony_ci * support between VMX and SVM we cannot use module_param_named. 22662306a36Sopenharmony_ci */ 22762306a36Sopenharmony_cistatic bool avic; 22862306a36Sopenharmony_cimodule_param(avic, bool, 0444); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cibool __read_mostly dump_invalid_vmcb; 23162306a36Sopenharmony_cimodule_param(dump_invalid_vmcb, bool, 0644); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cibool intercept_smi = true; 23562306a36Sopenharmony_cimodule_param(intercept_smi, bool, 0444); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cibool vnmi = true; 23862306a36Sopenharmony_cimodule_param(vnmi, bool, 0444); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic bool svm_gp_erratum_intercept = true; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic u8 rsm_ins_bytes[] = "\x0f\xaa"; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic unsigned long iopm_base; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ciDEFINE_PER_CPU(struct svm_cpu_data, svm_data); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci/* 24962306a36Sopenharmony_ci * Only MSR_TSC_AUX is switched via the user return hook. EFER is switched via 25062306a36Sopenharmony_ci * the VMCB, and the SYSCALL/SYSENTER MSRs are handled by VMLOAD/VMSAVE. 25162306a36Sopenharmony_ci * 25262306a36Sopenharmony_ci * RDTSCP and RDPID are not used in the kernel, specifically to allow KVM to 25362306a36Sopenharmony_ci * defer the restoration of TSC_AUX until the CPU returns to userspace. 25462306a36Sopenharmony_ci */ 25562306a36Sopenharmony_cistatic int tsc_aux_uret_slot __read_mostly = -1; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic const u32 msrpm_ranges[] = {0, 0xc0000000, 0xc0010000}; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci#define NUM_MSR_MAPS ARRAY_SIZE(msrpm_ranges) 26062306a36Sopenharmony_ci#define MSRS_RANGE_SIZE 2048 26162306a36Sopenharmony_ci#define MSRS_IN_RANGE (MSRS_RANGE_SIZE * 8 / 2) 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ciu32 svm_msrpm_offset(u32 msr) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci u32 offset; 26662306a36Sopenharmony_ci int i; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci for (i = 0; i < NUM_MSR_MAPS; i++) { 26962306a36Sopenharmony_ci if (msr < msrpm_ranges[i] || 27062306a36Sopenharmony_ci msr >= msrpm_ranges[i] + MSRS_IN_RANGE) 27162306a36Sopenharmony_ci continue; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci offset = (msr - msrpm_ranges[i]) / 4; /* 4 msrs per u8 */ 27462306a36Sopenharmony_ci offset += (i * MSRS_RANGE_SIZE); /* add range offset */ 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* Now we have the u8 offset - but need the u32 offset */ 27762306a36Sopenharmony_ci return offset / 4; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci /* MSR not in any range */ 28162306a36Sopenharmony_ci return MSR_INVALID; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic void svm_flush_tlb_current(struct kvm_vcpu *vcpu); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic int get_npt_level(void) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci#ifdef CONFIG_X86_64 28962306a36Sopenharmony_ci return pgtable_l5_enabled() ? PT64_ROOT_5LEVEL : PT64_ROOT_4LEVEL; 29062306a36Sopenharmony_ci#else 29162306a36Sopenharmony_ci return PT32E_ROOT_LEVEL; 29262306a36Sopenharmony_ci#endif 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ciint svm_set_efer(struct kvm_vcpu *vcpu, u64 efer) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 29862306a36Sopenharmony_ci u64 old_efer = vcpu->arch.efer; 29962306a36Sopenharmony_ci vcpu->arch.efer = efer; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (!npt_enabled) { 30262306a36Sopenharmony_ci /* Shadow paging assumes NX to be available. */ 30362306a36Sopenharmony_ci efer |= EFER_NX; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (!(efer & EFER_LMA)) 30662306a36Sopenharmony_ci efer &= ~EFER_LME; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if ((old_efer & EFER_SVME) != (efer & EFER_SVME)) { 31062306a36Sopenharmony_ci if (!(efer & EFER_SVME)) { 31162306a36Sopenharmony_ci svm_leave_nested(vcpu); 31262306a36Sopenharmony_ci svm_set_gif(svm, true); 31362306a36Sopenharmony_ci /* #GP intercept is still needed for vmware backdoor */ 31462306a36Sopenharmony_ci if (!enable_vmware_backdoor) 31562306a36Sopenharmony_ci clr_exception_intercept(svm, GP_VECTOR); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* 31862306a36Sopenharmony_ci * Free the nested guest state, unless we are in SMM. 31962306a36Sopenharmony_ci * In this case we will return to the nested guest 32062306a36Sopenharmony_ci * as soon as we leave SMM. 32162306a36Sopenharmony_ci */ 32262306a36Sopenharmony_ci if (!is_smm(vcpu)) 32362306a36Sopenharmony_ci svm_free_nested(svm); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci } else { 32662306a36Sopenharmony_ci int ret = svm_allocate_nested(svm); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (ret) { 32962306a36Sopenharmony_ci vcpu->arch.efer = old_efer; 33062306a36Sopenharmony_ci return ret; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* 33462306a36Sopenharmony_ci * Never intercept #GP for SEV guests, KVM can't 33562306a36Sopenharmony_ci * decrypt guest memory to workaround the erratum. 33662306a36Sopenharmony_ci */ 33762306a36Sopenharmony_ci if (svm_gp_erratum_intercept && !sev_guest(vcpu->kvm)) 33862306a36Sopenharmony_ci set_exception_intercept(svm, GP_VECTOR); 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci svm->vmcb->save.efer = efer | EFER_SVME; 34362306a36Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_CR); 34462306a36Sopenharmony_ci return 0; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic u32 svm_get_interrupt_shadow(struct kvm_vcpu *vcpu) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 35062306a36Sopenharmony_ci u32 ret = 0; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (svm->vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) 35362306a36Sopenharmony_ci ret = KVM_X86_SHADOW_INT_STI | KVM_X86_SHADOW_INT_MOV_SS; 35462306a36Sopenharmony_ci return ret; 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic void svm_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (mask == 0) 36262306a36Sopenharmony_ci svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK; 36362306a36Sopenharmony_ci else 36462306a36Sopenharmony_ci svm->vmcb->control.int_state |= SVM_INTERRUPT_SHADOW_MASK; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_cistatic bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type, 36862306a36Sopenharmony_ci void *insn, int insn_len); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic int __svm_skip_emulated_instruction(struct kvm_vcpu *vcpu, 37162306a36Sopenharmony_ci bool commit_side_effects) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 37462306a36Sopenharmony_ci unsigned long old_rflags; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* 37762306a36Sopenharmony_ci * SEV-ES does not expose the next RIP. The RIP update is controlled by 37862306a36Sopenharmony_ci * the type of exit and the #VC handler in the guest. 37962306a36Sopenharmony_ci */ 38062306a36Sopenharmony_ci if (sev_es_guest(vcpu->kvm)) 38162306a36Sopenharmony_ci goto done; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (nrips && svm->vmcb->control.next_rip != 0) { 38462306a36Sopenharmony_ci WARN_ON_ONCE(!static_cpu_has(X86_FEATURE_NRIPS)); 38562306a36Sopenharmony_ci svm->next_rip = svm->vmcb->control.next_rip; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (!svm->next_rip) { 38962306a36Sopenharmony_ci /* 39062306a36Sopenharmony_ci * FIXME: Drop this when kvm_emulate_instruction() does the 39162306a36Sopenharmony_ci * right thing and treats "can't emulate" as outright failure 39262306a36Sopenharmony_ci * for EMULTYPE_SKIP. 39362306a36Sopenharmony_ci */ 39462306a36Sopenharmony_ci if (!svm_can_emulate_instruction(vcpu, EMULTYPE_SKIP, NULL, 0)) 39562306a36Sopenharmony_ci return 0; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (unlikely(!commit_side_effects)) 39862306a36Sopenharmony_ci old_rflags = svm->vmcb->save.rflags; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (!kvm_emulate_instruction(vcpu, EMULTYPE_SKIP)) 40162306a36Sopenharmony_ci return 0; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (unlikely(!commit_side_effects)) 40462306a36Sopenharmony_ci svm->vmcb->save.rflags = old_rflags; 40562306a36Sopenharmony_ci } else { 40662306a36Sopenharmony_ci kvm_rip_write(vcpu, svm->next_rip); 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cidone: 41062306a36Sopenharmony_ci if (likely(commit_side_effects)) 41162306a36Sopenharmony_ci svm_set_interrupt_shadow(vcpu, 0); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return 1; 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic int svm_skip_emulated_instruction(struct kvm_vcpu *vcpu) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci return __svm_skip_emulated_instruction(vcpu, true); 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic int svm_update_soft_interrupt_rip(struct kvm_vcpu *vcpu) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci unsigned long rip, old_rip = kvm_rip_read(vcpu); 42462306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* 42762306a36Sopenharmony_ci * Due to architectural shortcomings, the CPU doesn't always provide 42862306a36Sopenharmony_ci * NextRIP, e.g. if KVM intercepted an exception that occurred while 42962306a36Sopenharmony_ci * the CPU was vectoring an INTO/INT3 in the guest. Temporarily skip 43062306a36Sopenharmony_ci * the instruction even if NextRIP is supported to acquire the next 43162306a36Sopenharmony_ci * RIP so that it can be shoved into the NextRIP field, otherwise 43262306a36Sopenharmony_ci * hardware will fail to advance guest RIP during event injection. 43362306a36Sopenharmony_ci * Drop the exception/interrupt if emulation fails and effectively 43462306a36Sopenharmony_ci * retry the instruction, it's the least awful option. If NRIPS is 43562306a36Sopenharmony_ci * in use, the skip must not commit any side effects such as clearing 43662306a36Sopenharmony_ci * the interrupt shadow or RFLAGS.RF. 43762306a36Sopenharmony_ci */ 43862306a36Sopenharmony_ci if (!__svm_skip_emulated_instruction(vcpu, !nrips)) 43962306a36Sopenharmony_ci return -EIO; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci rip = kvm_rip_read(vcpu); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* 44462306a36Sopenharmony_ci * Save the injection information, even when using next_rip, as the 44562306a36Sopenharmony_ci * VMCB's next_rip will be lost (cleared on VM-Exit) if the injection 44662306a36Sopenharmony_ci * doesn't complete due to a VM-Exit occurring while the CPU is 44762306a36Sopenharmony_ci * vectoring the event. Decoding the instruction isn't guaranteed to 44862306a36Sopenharmony_ci * work as there may be no backing instruction, e.g. if the event is 44962306a36Sopenharmony_ci * being injected by L1 for L2, or if the guest is patching INT3 into 45062306a36Sopenharmony_ci * a different instruction. 45162306a36Sopenharmony_ci */ 45262306a36Sopenharmony_ci svm->soft_int_injected = true; 45362306a36Sopenharmony_ci svm->soft_int_csbase = svm->vmcb->save.cs.base; 45462306a36Sopenharmony_ci svm->soft_int_old_rip = old_rip; 45562306a36Sopenharmony_ci svm->soft_int_next_rip = rip; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (nrips) 45862306a36Sopenharmony_ci kvm_rip_write(vcpu, old_rip); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci if (static_cpu_has(X86_FEATURE_NRIPS)) 46162306a36Sopenharmony_ci svm->vmcb->control.next_rip = rip; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci return 0; 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic void svm_inject_exception(struct kvm_vcpu *vcpu) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci struct kvm_queued_exception *ex = &vcpu->arch.exception; 46962306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci kvm_deliver_exception_payload(vcpu, ex); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if (kvm_exception_is_soft(ex->vector) && 47462306a36Sopenharmony_ci svm_update_soft_interrupt_rip(vcpu)) 47562306a36Sopenharmony_ci return; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci svm->vmcb->control.event_inj = ex->vector 47862306a36Sopenharmony_ci | SVM_EVTINJ_VALID 47962306a36Sopenharmony_ci | (ex->has_error_code ? SVM_EVTINJ_VALID_ERR : 0) 48062306a36Sopenharmony_ci | SVM_EVTINJ_TYPE_EXEPT; 48162306a36Sopenharmony_ci svm->vmcb->control.event_inj_err = ex->error_code; 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic void svm_init_erratum_383(void) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci u32 low, high; 48762306a36Sopenharmony_ci int err; 48862306a36Sopenharmony_ci u64 val; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci if (!static_cpu_has_bug(X86_BUG_AMD_TLB_MMATCH)) 49162306a36Sopenharmony_ci return; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* Use _safe variants to not break nested virtualization */ 49462306a36Sopenharmony_ci val = native_read_msr_safe(MSR_AMD64_DC_CFG, &err); 49562306a36Sopenharmony_ci if (err) 49662306a36Sopenharmony_ci return; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci val |= (1ULL << 47); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci low = lower_32_bits(val); 50162306a36Sopenharmony_ci high = upper_32_bits(val); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci native_write_msr_safe(MSR_AMD64_DC_CFG, low, high); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci erratum_383_found = true; 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic void svm_init_osvw(struct kvm_vcpu *vcpu) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci /* 51162306a36Sopenharmony_ci * Guests should see errata 400 and 415 as fixed (assuming that 51262306a36Sopenharmony_ci * HLT and IO instructions are intercepted). 51362306a36Sopenharmony_ci */ 51462306a36Sopenharmony_ci vcpu->arch.osvw.length = (osvw_len >= 3) ? (osvw_len) : 3; 51562306a36Sopenharmony_ci vcpu->arch.osvw.status = osvw_status & ~(6ULL); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci /* 51862306a36Sopenharmony_ci * By increasing VCPU's osvw.length to 3 we are telling the guest that 51962306a36Sopenharmony_ci * all osvw.status bits inside that length, including bit 0 (which is 52062306a36Sopenharmony_ci * reserved for erratum 298), are valid. However, if host processor's 52162306a36Sopenharmony_ci * osvw_len is 0 then osvw_status[0] carries no information. We need to 52262306a36Sopenharmony_ci * be conservative here and therefore we tell the guest that erratum 298 52362306a36Sopenharmony_ci * is present (because we really don't know). 52462306a36Sopenharmony_ci */ 52562306a36Sopenharmony_ci if (osvw_len == 0 && boot_cpu_data.x86 == 0x10) 52662306a36Sopenharmony_ci vcpu->arch.osvw.status |= 1; 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic bool __kvm_is_svm_supported(void) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci int cpu = smp_processor_id(); 53262306a36Sopenharmony_ci struct cpuinfo_x86 *c = &cpu_data(cpu); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci u64 vm_cr; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (c->x86_vendor != X86_VENDOR_AMD && 53762306a36Sopenharmony_ci c->x86_vendor != X86_VENDOR_HYGON) { 53862306a36Sopenharmony_ci pr_err("CPU %d isn't AMD or Hygon\n", cpu); 53962306a36Sopenharmony_ci return false; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci if (!cpu_has(c, X86_FEATURE_SVM)) { 54362306a36Sopenharmony_ci pr_err("SVM not supported by CPU %d\n", cpu); 54462306a36Sopenharmony_ci return false; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) { 54862306a36Sopenharmony_ci pr_info("KVM is unsupported when running as an SEV guest\n"); 54962306a36Sopenharmony_ci return false; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci rdmsrl(MSR_VM_CR, vm_cr); 55362306a36Sopenharmony_ci if (vm_cr & (1 << SVM_VM_CR_SVM_DISABLE)) { 55462306a36Sopenharmony_ci pr_err("SVM disabled (by BIOS) in MSR_VM_CR on CPU %d\n", cpu); 55562306a36Sopenharmony_ci return false; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci return true; 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic bool kvm_is_svm_supported(void) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci bool supported; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci migrate_disable(); 56662306a36Sopenharmony_ci supported = __kvm_is_svm_supported(); 56762306a36Sopenharmony_ci migrate_enable(); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci return supported; 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_cistatic int svm_check_processor_compat(void) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci if (!__kvm_is_svm_supported()) 57562306a36Sopenharmony_ci return -EIO; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci return 0; 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic void __svm_write_tsc_multiplier(u64 multiplier) 58162306a36Sopenharmony_ci{ 58262306a36Sopenharmony_ci if (multiplier == __this_cpu_read(current_tsc_ratio)) 58362306a36Sopenharmony_ci return; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci wrmsrl(MSR_AMD64_TSC_RATIO, multiplier); 58662306a36Sopenharmony_ci __this_cpu_write(current_tsc_ratio, multiplier); 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_cistatic inline void kvm_cpu_svm_disable(void) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci uint64_t efer; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci wrmsrl(MSR_VM_HSAVE_PA, 0); 59462306a36Sopenharmony_ci rdmsrl(MSR_EFER, efer); 59562306a36Sopenharmony_ci if (efer & EFER_SVME) { 59662306a36Sopenharmony_ci /* 59762306a36Sopenharmony_ci * Force GIF=1 prior to disabling SVM, e.g. to ensure INIT and 59862306a36Sopenharmony_ci * NMI aren't blocked. 59962306a36Sopenharmony_ci */ 60062306a36Sopenharmony_ci stgi(); 60162306a36Sopenharmony_ci wrmsrl(MSR_EFER, efer & ~EFER_SVME); 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic void svm_emergency_disable(void) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci kvm_rebooting = true; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci kvm_cpu_svm_disable(); 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic void svm_hardware_disable(void) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci /* Make sure we clean up behind us */ 61562306a36Sopenharmony_ci if (tsc_scaling) 61662306a36Sopenharmony_ci __svm_write_tsc_multiplier(SVM_TSC_RATIO_DEFAULT); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci kvm_cpu_svm_disable(); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci amd_pmu_disable_virt(); 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistatic int svm_hardware_enable(void) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci struct svm_cpu_data *sd; 62762306a36Sopenharmony_ci uint64_t efer; 62862306a36Sopenharmony_ci int me = raw_smp_processor_id(); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci rdmsrl(MSR_EFER, efer); 63162306a36Sopenharmony_ci if (efer & EFER_SVME) 63262306a36Sopenharmony_ci return -EBUSY; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci sd = per_cpu_ptr(&svm_data, me); 63562306a36Sopenharmony_ci sd->asid_generation = 1; 63662306a36Sopenharmony_ci sd->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1; 63762306a36Sopenharmony_ci sd->next_asid = sd->max_asid + 1; 63862306a36Sopenharmony_ci sd->min_asid = max_sev_asid + 1; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci wrmsrl(MSR_EFER, efer | EFER_SVME); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci wrmsrl(MSR_VM_HSAVE_PA, sd->save_area_pa); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci if (static_cpu_has(X86_FEATURE_TSCRATEMSR)) { 64562306a36Sopenharmony_ci /* 64662306a36Sopenharmony_ci * Set the default value, even if we don't use TSC scaling 64762306a36Sopenharmony_ci * to avoid having stale value in the msr 64862306a36Sopenharmony_ci */ 64962306a36Sopenharmony_ci __svm_write_tsc_multiplier(SVM_TSC_RATIO_DEFAULT); 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci /* 65462306a36Sopenharmony_ci * Get OSVW bits. 65562306a36Sopenharmony_ci * 65662306a36Sopenharmony_ci * Note that it is possible to have a system with mixed processor 65762306a36Sopenharmony_ci * revisions and therefore different OSVW bits. If bits are not the same 65862306a36Sopenharmony_ci * on different processors then choose the worst case (i.e. if erratum 65962306a36Sopenharmony_ci * is present on one processor and not on another then assume that the 66062306a36Sopenharmony_ci * erratum is present everywhere). 66162306a36Sopenharmony_ci */ 66262306a36Sopenharmony_ci if (cpu_has(&boot_cpu_data, X86_FEATURE_OSVW)) { 66362306a36Sopenharmony_ci uint64_t len, status = 0; 66462306a36Sopenharmony_ci int err; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci len = native_read_msr_safe(MSR_AMD64_OSVW_ID_LENGTH, &err); 66762306a36Sopenharmony_ci if (!err) 66862306a36Sopenharmony_ci status = native_read_msr_safe(MSR_AMD64_OSVW_STATUS, 66962306a36Sopenharmony_ci &err); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci if (err) 67262306a36Sopenharmony_ci osvw_status = osvw_len = 0; 67362306a36Sopenharmony_ci else { 67462306a36Sopenharmony_ci if (len < osvw_len) 67562306a36Sopenharmony_ci osvw_len = len; 67662306a36Sopenharmony_ci osvw_status |= status; 67762306a36Sopenharmony_ci osvw_status &= (1ULL << osvw_len) - 1; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci } else 68062306a36Sopenharmony_ci osvw_status = osvw_len = 0; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci svm_init_erratum_383(); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci amd_pmu_enable_virt(); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* 68762306a36Sopenharmony_ci * If TSC_AUX virtualization is supported, TSC_AUX becomes a swap type 68862306a36Sopenharmony_ci * "B" field (see sev_es_prepare_switch_to_guest()) for SEV-ES guests. 68962306a36Sopenharmony_ci * Since Linux does not change the value of TSC_AUX once set, prime the 69062306a36Sopenharmony_ci * TSC_AUX field now to avoid a RDMSR on every vCPU run. 69162306a36Sopenharmony_ci */ 69262306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_V_TSC_AUX)) { 69362306a36Sopenharmony_ci struct sev_es_save_area *hostsa; 69462306a36Sopenharmony_ci u32 __maybe_unused msr_hi; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci hostsa = (struct sev_es_save_area *)(page_address(sd->save_area) + 0x400); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci rdmsr(MSR_TSC_AUX, hostsa->tsc_aux, msr_hi); 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci return 0; 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic void svm_cpu_uninit(int cpu) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci struct svm_cpu_data *sd = per_cpu_ptr(&svm_data, cpu); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci if (!sd->save_area) 70962306a36Sopenharmony_ci return; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci kfree(sd->sev_vmcbs); 71262306a36Sopenharmony_ci __free_page(sd->save_area); 71362306a36Sopenharmony_ci sd->save_area_pa = 0; 71462306a36Sopenharmony_ci sd->save_area = NULL; 71562306a36Sopenharmony_ci} 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_cistatic int svm_cpu_init(int cpu) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci struct svm_cpu_data *sd = per_cpu_ptr(&svm_data, cpu); 72062306a36Sopenharmony_ci int ret = -ENOMEM; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci memset(sd, 0, sizeof(struct svm_cpu_data)); 72362306a36Sopenharmony_ci sd->save_area = alloc_page(GFP_KERNEL | __GFP_ZERO); 72462306a36Sopenharmony_ci if (!sd->save_area) 72562306a36Sopenharmony_ci return ret; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci ret = sev_cpu_init(sd); 72862306a36Sopenharmony_ci if (ret) 72962306a36Sopenharmony_ci goto free_save_area; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci sd->save_area_pa = __sme_page_pa(sd->save_area); 73262306a36Sopenharmony_ci return 0; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_cifree_save_area: 73562306a36Sopenharmony_ci __free_page(sd->save_area); 73662306a36Sopenharmony_ci sd->save_area = NULL; 73762306a36Sopenharmony_ci return ret; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic void set_dr_intercepts(struct vcpu_svm *svm) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci struct vmcb *vmcb = svm->vmcb01.ptr; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci vmcb_set_intercept(&vmcb->control, INTERCEPT_DR0_READ); 74662306a36Sopenharmony_ci vmcb_set_intercept(&vmcb->control, INTERCEPT_DR1_READ); 74762306a36Sopenharmony_ci vmcb_set_intercept(&vmcb->control, INTERCEPT_DR2_READ); 74862306a36Sopenharmony_ci vmcb_set_intercept(&vmcb->control, INTERCEPT_DR3_READ); 74962306a36Sopenharmony_ci vmcb_set_intercept(&vmcb->control, INTERCEPT_DR4_READ); 75062306a36Sopenharmony_ci vmcb_set_intercept(&vmcb->control, INTERCEPT_DR5_READ); 75162306a36Sopenharmony_ci vmcb_set_intercept(&vmcb->control, INTERCEPT_DR6_READ); 75262306a36Sopenharmony_ci vmcb_set_intercept(&vmcb->control, INTERCEPT_DR0_WRITE); 75362306a36Sopenharmony_ci vmcb_set_intercept(&vmcb->control, INTERCEPT_DR1_WRITE); 75462306a36Sopenharmony_ci vmcb_set_intercept(&vmcb->control, INTERCEPT_DR2_WRITE); 75562306a36Sopenharmony_ci vmcb_set_intercept(&vmcb->control, INTERCEPT_DR3_WRITE); 75662306a36Sopenharmony_ci vmcb_set_intercept(&vmcb->control, INTERCEPT_DR4_WRITE); 75762306a36Sopenharmony_ci vmcb_set_intercept(&vmcb->control, INTERCEPT_DR5_WRITE); 75862306a36Sopenharmony_ci vmcb_set_intercept(&vmcb->control, INTERCEPT_DR6_WRITE); 75962306a36Sopenharmony_ci vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_READ); 76062306a36Sopenharmony_ci vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_WRITE); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci recalc_intercepts(svm); 76362306a36Sopenharmony_ci} 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_cistatic void clr_dr_intercepts(struct vcpu_svm *svm) 76662306a36Sopenharmony_ci{ 76762306a36Sopenharmony_ci struct vmcb *vmcb = svm->vmcb01.ptr; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci vmcb->control.intercepts[INTERCEPT_DR] = 0; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci recalc_intercepts(svm); 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic int direct_access_msr_slot(u32 msr) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci u32 i; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci for (i = 0; direct_access_msrs[i].index != MSR_INVALID; i++) 77962306a36Sopenharmony_ci if (direct_access_msrs[i].index == msr) 78062306a36Sopenharmony_ci return i; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci return -ENOENT; 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_cistatic void set_shadow_msr_intercept(struct kvm_vcpu *vcpu, u32 msr, int read, 78662306a36Sopenharmony_ci int write) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 78962306a36Sopenharmony_ci int slot = direct_access_msr_slot(msr); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci if (slot == -ENOENT) 79262306a36Sopenharmony_ci return; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci /* Set the shadow bitmaps to the desired intercept states */ 79562306a36Sopenharmony_ci if (read) 79662306a36Sopenharmony_ci set_bit(slot, svm->shadow_msr_intercept.read); 79762306a36Sopenharmony_ci else 79862306a36Sopenharmony_ci clear_bit(slot, svm->shadow_msr_intercept.read); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (write) 80162306a36Sopenharmony_ci set_bit(slot, svm->shadow_msr_intercept.write); 80262306a36Sopenharmony_ci else 80362306a36Sopenharmony_ci clear_bit(slot, svm->shadow_msr_intercept.write); 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_cistatic bool valid_msr_intercept(u32 index) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci return direct_access_msr_slot(index) != -ENOENT; 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_cistatic bool msr_write_intercepted(struct kvm_vcpu *vcpu, u32 msr) 81262306a36Sopenharmony_ci{ 81362306a36Sopenharmony_ci u8 bit_write; 81462306a36Sopenharmony_ci unsigned long tmp; 81562306a36Sopenharmony_ci u32 offset; 81662306a36Sopenharmony_ci u32 *msrpm; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci /* 81962306a36Sopenharmony_ci * For non-nested case: 82062306a36Sopenharmony_ci * If the L01 MSR bitmap does not intercept the MSR, then we need to 82162306a36Sopenharmony_ci * save it. 82262306a36Sopenharmony_ci * 82362306a36Sopenharmony_ci * For nested case: 82462306a36Sopenharmony_ci * If the L02 MSR bitmap does not intercept the MSR, then we need to 82562306a36Sopenharmony_ci * save it. 82662306a36Sopenharmony_ci */ 82762306a36Sopenharmony_ci msrpm = is_guest_mode(vcpu) ? to_svm(vcpu)->nested.msrpm: 82862306a36Sopenharmony_ci to_svm(vcpu)->msrpm; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci offset = svm_msrpm_offset(msr); 83162306a36Sopenharmony_ci bit_write = 2 * (msr & 0x0f) + 1; 83262306a36Sopenharmony_ci tmp = msrpm[offset]; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci BUG_ON(offset == MSR_INVALID); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci return test_bit(bit_write, &tmp); 83762306a36Sopenharmony_ci} 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_cistatic void set_msr_interception_bitmap(struct kvm_vcpu *vcpu, u32 *msrpm, 84062306a36Sopenharmony_ci u32 msr, int read, int write) 84162306a36Sopenharmony_ci{ 84262306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 84362306a36Sopenharmony_ci u8 bit_read, bit_write; 84462306a36Sopenharmony_ci unsigned long tmp; 84562306a36Sopenharmony_ci u32 offset; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci /* 84862306a36Sopenharmony_ci * If this warning triggers extend the direct_access_msrs list at the 84962306a36Sopenharmony_ci * beginning of the file 85062306a36Sopenharmony_ci */ 85162306a36Sopenharmony_ci WARN_ON(!valid_msr_intercept(msr)); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci /* Enforce non allowed MSRs to trap */ 85462306a36Sopenharmony_ci if (read && !kvm_msr_allowed(vcpu, msr, KVM_MSR_FILTER_READ)) 85562306a36Sopenharmony_ci read = 0; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci if (write && !kvm_msr_allowed(vcpu, msr, KVM_MSR_FILTER_WRITE)) 85862306a36Sopenharmony_ci write = 0; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci offset = svm_msrpm_offset(msr); 86162306a36Sopenharmony_ci bit_read = 2 * (msr & 0x0f); 86262306a36Sopenharmony_ci bit_write = 2 * (msr & 0x0f) + 1; 86362306a36Sopenharmony_ci tmp = msrpm[offset]; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci BUG_ON(offset == MSR_INVALID); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci read ? clear_bit(bit_read, &tmp) : set_bit(bit_read, &tmp); 86862306a36Sopenharmony_ci write ? clear_bit(bit_write, &tmp) : set_bit(bit_write, &tmp); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci msrpm[offset] = tmp; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci svm_hv_vmcb_dirty_nested_enlightenments(vcpu); 87362306a36Sopenharmony_ci svm->nested.force_msr_bitmap_recalc = true; 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_civoid set_msr_interception(struct kvm_vcpu *vcpu, u32 *msrpm, u32 msr, 87762306a36Sopenharmony_ci int read, int write) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci set_shadow_msr_intercept(vcpu, msr, read, write); 88062306a36Sopenharmony_ci set_msr_interception_bitmap(vcpu, msrpm, msr, read, write); 88162306a36Sopenharmony_ci} 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ciu32 *svm_vcpu_alloc_msrpm(void) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci unsigned int order = get_order(MSRPM_SIZE); 88662306a36Sopenharmony_ci struct page *pages = alloc_pages(GFP_KERNEL_ACCOUNT, order); 88762306a36Sopenharmony_ci u32 *msrpm; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci if (!pages) 89062306a36Sopenharmony_ci return NULL; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci msrpm = page_address(pages); 89362306a36Sopenharmony_ci memset(msrpm, 0xff, PAGE_SIZE * (1 << order)); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci return msrpm; 89662306a36Sopenharmony_ci} 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_civoid svm_vcpu_init_msrpm(struct kvm_vcpu *vcpu, u32 *msrpm) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci int i; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci for (i = 0; direct_access_msrs[i].index != MSR_INVALID; i++) { 90362306a36Sopenharmony_ci if (!direct_access_msrs[i].always) 90462306a36Sopenharmony_ci continue; 90562306a36Sopenharmony_ci set_msr_interception(vcpu, msrpm, direct_access_msrs[i].index, 1, 1); 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_civoid svm_set_x2apic_msr_interception(struct vcpu_svm *svm, bool intercept) 91062306a36Sopenharmony_ci{ 91162306a36Sopenharmony_ci int i; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci if (intercept == svm->x2avic_msrs_intercepted) 91462306a36Sopenharmony_ci return; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci if (!x2avic_enabled) 91762306a36Sopenharmony_ci return; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci for (i = 0; i < MAX_DIRECT_ACCESS_MSRS; i++) { 92062306a36Sopenharmony_ci int index = direct_access_msrs[i].index; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci if ((index < APIC_BASE_MSR) || 92362306a36Sopenharmony_ci (index > APIC_BASE_MSR + 0xff)) 92462306a36Sopenharmony_ci continue; 92562306a36Sopenharmony_ci set_msr_interception(&svm->vcpu, svm->msrpm, index, 92662306a36Sopenharmony_ci !intercept, !intercept); 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci svm->x2avic_msrs_intercepted = intercept; 93062306a36Sopenharmony_ci} 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_civoid svm_vcpu_free_msrpm(u32 *msrpm) 93362306a36Sopenharmony_ci{ 93462306a36Sopenharmony_ci __free_pages(virt_to_page(msrpm), get_order(MSRPM_SIZE)); 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_cistatic void svm_msr_filter_changed(struct kvm_vcpu *vcpu) 93862306a36Sopenharmony_ci{ 93962306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 94062306a36Sopenharmony_ci u32 i; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci /* 94362306a36Sopenharmony_ci * Set intercept permissions for all direct access MSRs again. They 94462306a36Sopenharmony_ci * will automatically get filtered through the MSR filter, so we are 94562306a36Sopenharmony_ci * back in sync after this. 94662306a36Sopenharmony_ci */ 94762306a36Sopenharmony_ci for (i = 0; direct_access_msrs[i].index != MSR_INVALID; i++) { 94862306a36Sopenharmony_ci u32 msr = direct_access_msrs[i].index; 94962306a36Sopenharmony_ci u32 read = test_bit(i, svm->shadow_msr_intercept.read); 95062306a36Sopenharmony_ci u32 write = test_bit(i, svm->shadow_msr_intercept.write); 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci set_msr_interception_bitmap(vcpu, svm->msrpm, msr, read, write); 95362306a36Sopenharmony_ci } 95462306a36Sopenharmony_ci} 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_cistatic void add_msr_offset(u32 offset) 95762306a36Sopenharmony_ci{ 95862306a36Sopenharmony_ci int i; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci for (i = 0; i < MSRPM_OFFSETS; ++i) { 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci /* Offset already in list? */ 96362306a36Sopenharmony_ci if (msrpm_offsets[i] == offset) 96462306a36Sopenharmony_ci return; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci /* Slot used by another offset? */ 96762306a36Sopenharmony_ci if (msrpm_offsets[i] != MSR_INVALID) 96862306a36Sopenharmony_ci continue; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci /* Add offset to list */ 97162306a36Sopenharmony_ci msrpm_offsets[i] = offset; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci return; 97462306a36Sopenharmony_ci } 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci /* 97762306a36Sopenharmony_ci * If this BUG triggers the msrpm_offsets table has an overflow. Just 97862306a36Sopenharmony_ci * increase MSRPM_OFFSETS in this case. 97962306a36Sopenharmony_ci */ 98062306a36Sopenharmony_ci BUG(); 98162306a36Sopenharmony_ci} 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_cistatic void init_msrpm_offsets(void) 98462306a36Sopenharmony_ci{ 98562306a36Sopenharmony_ci int i; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci memset(msrpm_offsets, 0xff, sizeof(msrpm_offsets)); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci for (i = 0; direct_access_msrs[i].index != MSR_INVALID; i++) { 99062306a36Sopenharmony_ci u32 offset; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci offset = svm_msrpm_offset(direct_access_msrs[i].index); 99362306a36Sopenharmony_ci BUG_ON(offset == MSR_INVALID); 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci add_msr_offset(offset); 99662306a36Sopenharmony_ci } 99762306a36Sopenharmony_ci} 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_civoid svm_copy_lbrs(struct vmcb *to_vmcb, struct vmcb *from_vmcb) 100062306a36Sopenharmony_ci{ 100162306a36Sopenharmony_ci to_vmcb->save.dbgctl = from_vmcb->save.dbgctl; 100262306a36Sopenharmony_ci to_vmcb->save.br_from = from_vmcb->save.br_from; 100362306a36Sopenharmony_ci to_vmcb->save.br_to = from_vmcb->save.br_to; 100462306a36Sopenharmony_ci to_vmcb->save.last_excp_from = from_vmcb->save.last_excp_from; 100562306a36Sopenharmony_ci to_vmcb->save.last_excp_to = from_vmcb->save.last_excp_to; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci vmcb_mark_dirty(to_vmcb, VMCB_LBR); 100862306a36Sopenharmony_ci} 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_cistatic void svm_enable_lbrv(struct kvm_vcpu *vcpu) 101162306a36Sopenharmony_ci{ 101262306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci svm->vmcb->control.virt_ext |= LBR_CTL_ENABLE_MASK; 101562306a36Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTBRANCHFROMIP, 1, 1); 101662306a36Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTBRANCHTOIP, 1, 1); 101762306a36Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTINTFROMIP, 1, 1); 101862306a36Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTINTTOIP, 1, 1); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci /* Move the LBR msrs to the vmcb02 so that the guest can see them. */ 102162306a36Sopenharmony_ci if (is_guest_mode(vcpu)) 102262306a36Sopenharmony_ci svm_copy_lbrs(svm->vmcb, svm->vmcb01.ptr); 102362306a36Sopenharmony_ci} 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_cistatic void svm_disable_lbrv(struct kvm_vcpu *vcpu) 102662306a36Sopenharmony_ci{ 102762306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci svm->vmcb->control.virt_ext &= ~LBR_CTL_ENABLE_MASK; 103062306a36Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTBRANCHFROMIP, 0, 0); 103162306a36Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTBRANCHTOIP, 0, 0); 103262306a36Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTINTFROMIP, 0, 0); 103362306a36Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTINTTOIP, 0, 0); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci /* 103662306a36Sopenharmony_ci * Move the LBR msrs back to the vmcb01 to avoid copying them 103762306a36Sopenharmony_ci * on nested guest entries. 103862306a36Sopenharmony_ci */ 103962306a36Sopenharmony_ci if (is_guest_mode(vcpu)) 104062306a36Sopenharmony_ci svm_copy_lbrs(svm->vmcb01.ptr, svm->vmcb); 104162306a36Sopenharmony_ci} 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_cistatic struct vmcb *svm_get_lbr_vmcb(struct vcpu_svm *svm) 104462306a36Sopenharmony_ci{ 104562306a36Sopenharmony_ci /* 104662306a36Sopenharmony_ci * If LBR virtualization is disabled, the LBR MSRs are always kept in 104762306a36Sopenharmony_ci * vmcb01. If LBR virtualization is enabled and L1 is running VMs of 104862306a36Sopenharmony_ci * its own, the MSRs are moved between vmcb01 and vmcb02 as needed. 104962306a36Sopenharmony_ci */ 105062306a36Sopenharmony_ci return svm->vmcb->control.virt_ext & LBR_CTL_ENABLE_MASK ? svm->vmcb : 105162306a36Sopenharmony_ci svm->vmcb01.ptr; 105262306a36Sopenharmony_ci} 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_civoid svm_update_lbrv(struct kvm_vcpu *vcpu) 105562306a36Sopenharmony_ci{ 105662306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 105762306a36Sopenharmony_ci bool current_enable_lbrv = svm->vmcb->control.virt_ext & LBR_CTL_ENABLE_MASK; 105862306a36Sopenharmony_ci bool enable_lbrv = (svm_get_lbr_vmcb(svm)->save.dbgctl & DEBUGCTLMSR_LBR) || 105962306a36Sopenharmony_ci (is_guest_mode(vcpu) && guest_can_use(vcpu, X86_FEATURE_LBRV) && 106062306a36Sopenharmony_ci (svm->nested.ctl.virt_ext & LBR_CTL_ENABLE_MASK)); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci if (enable_lbrv == current_enable_lbrv) 106362306a36Sopenharmony_ci return; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci if (enable_lbrv) 106662306a36Sopenharmony_ci svm_enable_lbrv(vcpu); 106762306a36Sopenharmony_ci else 106862306a36Sopenharmony_ci svm_disable_lbrv(vcpu); 106962306a36Sopenharmony_ci} 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_civoid disable_nmi_singlestep(struct vcpu_svm *svm) 107262306a36Sopenharmony_ci{ 107362306a36Sopenharmony_ci svm->nmi_singlestep = false; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci if (!(svm->vcpu.guest_debug & KVM_GUESTDBG_SINGLESTEP)) { 107662306a36Sopenharmony_ci /* Clear our flags if they were not set by the guest */ 107762306a36Sopenharmony_ci if (!(svm->nmi_singlestep_guest_rflags & X86_EFLAGS_TF)) 107862306a36Sopenharmony_ci svm->vmcb->save.rflags &= ~X86_EFLAGS_TF; 107962306a36Sopenharmony_ci if (!(svm->nmi_singlestep_guest_rflags & X86_EFLAGS_RF)) 108062306a36Sopenharmony_ci svm->vmcb->save.rflags &= ~X86_EFLAGS_RF; 108162306a36Sopenharmony_ci } 108262306a36Sopenharmony_ci} 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_cistatic void grow_ple_window(struct kvm_vcpu *vcpu) 108562306a36Sopenharmony_ci{ 108662306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 108762306a36Sopenharmony_ci struct vmcb_control_area *control = &svm->vmcb->control; 108862306a36Sopenharmony_ci int old = control->pause_filter_count; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci if (kvm_pause_in_guest(vcpu->kvm)) 109162306a36Sopenharmony_ci return; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci control->pause_filter_count = __grow_ple_window(old, 109462306a36Sopenharmony_ci pause_filter_count, 109562306a36Sopenharmony_ci pause_filter_count_grow, 109662306a36Sopenharmony_ci pause_filter_count_max); 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci if (control->pause_filter_count != old) { 109962306a36Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_INTERCEPTS); 110062306a36Sopenharmony_ci trace_kvm_ple_window_update(vcpu->vcpu_id, 110162306a36Sopenharmony_ci control->pause_filter_count, old); 110262306a36Sopenharmony_ci } 110362306a36Sopenharmony_ci} 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cistatic void shrink_ple_window(struct kvm_vcpu *vcpu) 110662306a36Sopenharmony_ci{ 110762306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 110862306a36Sopenharmony_ci struct vmcb_control_area *control = &svm->vmcb->control; 110962306a36Sopenharmony_ci int old = control->pause_filter_count; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci if (kvm_pause_in_guest(vcpu->kvm)) 111262306a36Sopenharmony_ci return; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci control->pause_filter_count = 111562306a36Sopenharmony_ci __shrink_ple_window(old, 111662306a36Sopenharmony_ci pause_filter_count, 111762306a36Sopenharmony_ci pause_filter_count_shrink, 111862306a36Sopenharmony_ci pause_filter_count); 111962306a36Sopenharmony_ci if (control->pause_filter_count != old) { 112062306a36Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_INTERCEPTS); 112162306a36Sopenharmony_ci trace_kvm_ple_window_update(vcpu->vcpu_id, 112262306a36Sopenharmony_ci control->pause_filter_count, old); 112362306a36Sopenharmony_ci } 112462306a36Sopenharmony_ci} 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_cistatic void svm_hardware_unsetup(void) 112762306a36Sopenharmony_ci{ 112862306a36Sopenharmony_ci int cpu; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci sev_hardware_unsetup(); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci for_each_possible_cpu(cpu) 113362306a36Sopenharmony_ci svm_cpu_uninit(cpu); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci __free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), 113662306a36Sopenharmony_ci get_order(IOPM_SIZE)); 113762306a36Sopenharmony_ci iopm_base = 0; 113862306a36Sopenharmony_ci} 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_cistatic void init_seg(struct vmcb_seg *seg) 114162306a36Sopenharmony_ci{ 114262306a36Sopenharmony_ci seg->selector = 0; 114362306a36Sopenharmony_ci seg->attrib = SVM_SELECTOR_P_MASK | SVM_SELECTOR_S_MASK | 114462306a36Sopenharmony_ci SVM_SELECTOR_WRITE_MASK; /* Read/Write Data Segment */ 114562306a36Sopenharmony_ci seg->limit = 0xffff; 114662306a36Sopenharmony_ci seg->base = 0; 114762306a36Sopenharmony_ci} 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_cistatic void init_sys_seg(struct vmcb_seg *seg, uint32_t type) 115062306a36Sopenharmony_ci{ 115162306a36Sopenharmony_ci seg->selector = 0; 115262306a36Sopenharmony_ci seg->attrib = SVM_SELECTOR_P_MASK | type; 115362306a36Sopenharmony_ci seg->limit = 0xffff; 115462306a36Sopenharmony_ci seg->base = 0; 115562306a36Sopenharmony_ci} 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_cistatic u64 svm_get_l2_tsc_offset(struct kvm_vcpu *vcpu) 115862306a36Sopenharmony_ci{ 115962306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci return svm->nested.ctl.tsc_offset; 116262306a36Sopenharmony_ci} 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_cistatic u64 svm_get_l2_tsc_multiplier(struct kvm_vcpu *vcpu) 116562306a36Sopenharmony_ci{ 116662306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci return svm->tsc_ratio_msr; 116962306a36Sopenharmony_ci} 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_cistatic void svm_write_tsc_offset(struct kvm_vcpu *vcpu) 117262306a36Sopenharmony_ci{ 117362306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci svm->vmcb01.ptr->control.tsc_offset = vcpu->arch.l1_tsc_offset; 117662306a36Sopenharmony_ci svm->vmcb->control.tsc_offset = vcpu->arch.tsc_offset; 117762306a36Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_INTERCEPTS); 117862306a36Sopenharmony_ci} 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_civoid svm_write_tsc_multiplier(struct kvm_vcpu *vcpu) 118162306a36Sopenharmony_ci{ 118262306a36Sopenharmony_ci preempt_disable(); 118362306a36Sopenharmony_ci if (to_svm(vcpu)->guest_state_loaded) 118462306a36Sopenharmony_ci __svm_write_tsc_multiplier(vcpu->arch.tsc_scaling_ratio); 118562306a36Sopenharmony_ci preempt_enable(); 118662306a36Sopenharmony_ci} 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci/* Evaluate instruction intercepts that depend on guest CPUID features. */ 118962306a36Sopenharmony_cistatic void svm_recalc_instruction_intercepts(struct kvm_vcpu *vcpu, 119062306a36Sopenharmony_ci struct vcpu_svm *svm) 119162306a36Sopenharmony_ci{ 119262306a36Sopenharmony_ci /* 119362306a36Sopenharmony_ci * Intercept INVPCID if shadow paging is enabled to sync/free shadow 119462306a36Sopenharmony_ci * roots, or if INVPCID is disabled in the guest to inject #UD. 119562306a36Sopenharmony_ci */ 119662306a36Sopenharmony_ci if (kvm_cpu_cap_has(X86_FEATURE_INVPCID)) { 119762306a36Sopenharmony_ci if (!npt_enabled || 119862306a36Sopenharmony_ci !guest_cpuid_has(&svm->vcpu, X86_FEATURE_INVPCID)) 119962306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_INVPCID); 120062306a36Sopenharmony_ci else 120162306a36Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_INVPCID); 120262306a36Sopenharmony_ci } 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci if (kvm_cpu_cap_has(X86_FEATURE_RDTSCP)) { 120562306a36Sopenharmony_ci if (guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP)) 120662306a36Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_RDTSCP); 120762306a36Sopenharmony_ci else 120862306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_RDTSCP); 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_ci} 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_cistatic inline void init_vmcb_after_set_cpuid(struct kvm_vcpu *vcpu) 121362306a36Sopenharmony_ci{ 121462306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci if (guest_cpuid_is_intel(vcpu)) { 121762306a36Sopenharmony_ci /* 121862306a36Sopenharmony_ci * We must intercept SYSENTER_EIP and SYSENTER_ESP 121962306a36Sopenharmony_ci * accesses because the processor only stores 32 bits. 122062306a36Sopenharmony_ci * For the same reason we cannot use virtual VMLOAD/VMSAVE. 122162306a36Sopenharmony_ci */ 122262306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_VMLOAD); 122362306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_VMSAVE); 122462306a36Sopenharmony_ci svm->vmcb->control.virt_ext &= ~VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_SYSENTER_EIP, 0, 0); 122762306a36Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_SYSENTER_ESP, 0, 0); 122862306a36Sopenharmony_ci } else { 122962306a36Sopenharmony_ci /* 123062306a36Sopenharmony_ci * If hardware supports Virtual VMLOAD VMSAVE then enable it 123162306a36Sopenharmony_ci * in VMCB and clear intercepts to avoid #VMEXIT. 123262306a36Sopenharmony_ci */ 123362306a36Sopenharmony_ci if (vls) { 123462306a36Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_VMLOAD); 123562306a36Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_VMSAVE); 123662306a36Sopenharmony_ci svm->vmcb->control.virt_ext |= VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK; 123762306a36Sopenharmony_ci } 123862306a36Sopenharmony_ci /* No need to intercept these MSRs */ 123962306a36Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_SYSENTER_EIP, 1, 1); 124062306a36Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_SYSENTER_ESP, 1, 1); 124162306a36Sopenharmony_ci } 124262306a36Sopenharmony_ci} 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_cistatic void init_vmcb(struct kvm_vcpu *vcpu) 124562306a36Sopenharmony_ci{ 124662306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 124762306a36Sopenharmony_ci struct vmcb *vmcb = svm->vmcb01.ptr; 124862306a36Sopenharmony_ci struct vmcb_control_area *control = &vmcb->control; 124962306a36Sopenharmony_ci struct vmcb_save_area *save = &vmcb->save; 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CR0_READ); 125262306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CR3_READ); 125362306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CR4_READ); 125462306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CR0_WRITE); 125562306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CR3_WRITE); 125662306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CR4_WRITE); 125762306a36Sopenharmony_ci if (!kvm_vcpu_apicv_active(vcpu)) 125862306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CR8_WRITE); 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci set_dr_intercepts(svm); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci set_exception_intercept(svm, PF_VECTOR); 126362306a36Sopenharmony_ci set_exception_intercept(svm, UD_VECTOR); 126462306a36Sopenharmony_ci set_exception_intercept(svm, MC_VECTOR); 126562306a36Sopenharmony_ci set_exception_intercept(svm, AC_VECTOR); 126662306a36Sopenharmony_ci set_exception_intercept(svm, DB_VECTOR); 126762306a36Sopenharmony_ci /* 126862306a36Sopenharmony_ci * Guest access to VMware backdoor ports could legitimately 126962306a36Sopenharmony_ci * trigger #GP because of TSS I/O permission bitmap. 127062306a36Sopenharmony_ci * We intercept those #GP and allow access to them anyway 127162306a36Sopenharmony_ci * as VMware does. 127262306a36Sopenharmony_ci */ 127362306a36Sopenharmony_ci if (enable_vmware_backdoor) 127462306a36Sopenharmony_ci set_exception_intercept(svm, GP_VECTOR); 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_INTR); 127762306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_NMI); 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci if (intercept_smi) 128062306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_SMI); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_SELECTIVE_CR0); 128362306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_RDPMC); 128462306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CPUID); 128562306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_INVD); 128662306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_INVLPG); 128762306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_INVLPGA); 128862306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_IOIO_PROT); 128962306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_MSR_PROT); 129062306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_TASK_SWITCH); 129162306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_SHUTDOWN); 129262306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_VMRUN); 129362306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_VMMCALL); 129462306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_VMLOAD); 129562306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_VMSAVE); 129662306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_STGI); 129762306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CLGI); 129862306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_SKINIT); 129962306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_WBINVD); 130062306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_XSETBV); 130162306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_RDPRU); 130262306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_RSM); 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci if (!kvm_mwait_in_guest(vcpu->kvm)) { 130562306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_MONITOR); 130662306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_MWAIT); 130762306a36Sopenharmony_ci } 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci if (!kvm_hlt_in_guest(vcpu->kvm)) 131062306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_HLT); 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci control->iopm_base_pa = __sme_set(iopm_base); 131362306a36Sopenharmony_ci control->msrpm_base_pa = __sme_set(__pa(svm->msrpm)); 131462306a36Sopenharmony_ci control->int_ctl = V_INTR_MASKING_MASK; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci init_seg(&save->es); 131762306a36Sopenharmony_ci init_seg(&save->ss); 131862306a36Sopenharmony_ci init_seg(&save->ds); 131962306a36Sopenharmony_ci init_seg(&save->fs); 132062306a36Sopenharmony_ci init_seg(&save->gs); 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci save->cs.selector = 0xf000; 132362306a36Sopenharmony_ci save->cs.base = 0xffff0000; 132462306a36Sopenharmony_ci /* Executable/Readable Code Segment */ 132562306a36Sopenharmony_ci save->cs.attrib = SVM_SELECTOR_READ_MASK | SVM_SELECTOR_P_MASK | 132662306a36Sopenharmony_ci SVM_SELECTOR_S_MASK | SVM_SELECTOR_CODE_MASK; 132762306a36Sopenharmony_ci save->cs.limit = 0xffff; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci save->gdtr.base = 0; 133062306a36Sopenharmony_ci save->gdtr.limit = 0xffff; 133162306a36Sopenharmony_ci save->idtr.base = 0; 133262306a36Sopenharmony_ci save->idtr.limit = 0xffff; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci init_sys_seg(&save->ldtr, SEG_TYPE_LDT); 133562306a36Sopenharmony_ci init_sys_seg(&save->tr, SEG_TYPE_BUSY_TSS16); 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci if (npt_enabled) { 133862306a36Sopenharmony_ci /* Setup VMCB for Nested Paging */ 133962306a36Sopenharmony_ci control->nested_ctl |= SVM_NESTED_CTL_NP_ENABLE; 134062306a36Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_INVLPG); 134162306a36Sopenharmony_ci clr_exception_intercept(svm, PF_VECTOR); 134262306a36Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_CR3_READ); 134362306a36Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_CR3_WRITE); 134462306a36Sopenharmony_ci save->g_pat = vcpu->arch.pat; 134562306a36Sopenharmony_ci save->cr3 = 0; 134662306a36Sopenharmony_ci } 134762306a36Sopenharmony_ci svm->current_vmcb->asid_generation = 0; 134862306a36Sopenharmony_ci svm->asid = 0; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci svm->nested.vmcb12_gpa = INVALID_GPA; 135162306a36Sopenharmony_ci svm->nested.last_vmcb12_gpa = INVALID_GPA; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci if (!kvm_pause_in_guest(vcpu->kvm)) { 135462306a36Sopenharmony_ci control->pause_filter_count = pause_filter_count; 135562306a36Sopenharmony_ci if (pause_filter_thresh) 135662306a36Sopenharmony_ci control->pause_filter_thresh = pause_filter_thresh; 135762306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_PAUSE); 135862306a36Sopenharmony_ci } else { 135962306a36Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_PAUSE); 136062306a36Sopenharmony_ci } 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci svm_recalc_instruction_intercepts(vcpu, svm); 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci /* 136562306a36Sopenharmony_ci * If the host supports V_SPEC_CTRL then disable the interception 136662306a36Sopenharmony_ci * of MSR_IA32_SPEC_CTRL. 136762306a36Sopenharmony_ci */ 136862306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_V_SPEC_CTRL)) 136962306a36Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_SPEC_CTRL, 1, 1); 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci if (kvm_vcpu_apicv_active(vcpu)) 137262306a36Sopenharmony_ci avic_init_vmcb(svm, vmcb); 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci if (vnmi) 137562306a36Sopenharmony_ci svm->vmcb->control.int_ctl |= V_NMI_ENABLE_MASK; 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci if (vgif) { 137862306a36Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_STGI); 137962306a36Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_CLGI); 138062306a36Sopenharmony_ci svm->vmcb->control.int_ctl |= V_GIF_ENABLE_MASK; 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci if (sev_guest(vcpu->kvm)) 138462306a36Sopenharmony_ci sev_init_vmcb(svm); 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci svm_hv_init_vmcb(vmcb); 138762306a36Sopenharmony_ci init_vmcb_after_set_cpuid(vcpu); 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci vmcb_mark_all_dirty(vmcb); 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci enable_gif(svm); 139262306a36Sopenharmony_ci} 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_cistatic void __svm_vcpu_reset(struct kvm_vcpu *vcpu) 139562306a36Sopenharmony_ci{ 139662306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci svm_vcpu_init_msrpm(vcpu, svm->msrpm); 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci svm_init_osvw(vcpu); 140162306a36Sopenharmony_ci vcpu->arch.microcode_version = 0x01000065; 140262306a36Sopenharmony_ci svm->tsc_ratio_msr = kvm_caps.default_tsc_scaling_ratio; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci svm->nmi_masked = false; 140562306a36Sopenharmony_ci svm->awaiting_iret_completion = false; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci if (sev_es_guest(vcpu->kvm)) 140862306a36Sopenharmony_ci sev_es_vcpu_reset(svm); 140962306a36Sopenharmony_ci} 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_cistatic void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) 141262306a36Sopenharmony_ci{ 141362306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci svm->spec_ctrl = 0; 141662306a36Sopenharmony_ci svm->virt_spec_ctrl = 0; 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci init_vmcb(vcpu); 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci if (!init_event) 142162306a36Sopenharmony_ci __svm_vcpu_reset(vcpu); 142262306a36Sopenharmony_ci} 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_civoid svm_switch_vmcb(struct vcpu_svm *svm, struct kvm_vmcb_info *target_vmcb) 142562306a36Sopenharmony_ci{ 142662306a36Sopenharmony_ci svm->current_vmcb = target_vmcb; 142762306a36Sopenharmony_ci svm->vmcb = target_vmcb->ptr; 142862306a36Sopenharmony_ci} 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_cistatic int svm_vcpu_create(struct kvm_vcpu *vcpu) 143162306a36Sopenharmony_ci{ 143262306a36Sopenharmony_ci struct vcpu_svm *svm; 143362306a36Sopenharmony_ci struct page *vmcb01_page; 143462306a36Sopenharmony_ci struct page *vmsa_page = NULL; 143562306a36Sopenharmony_ci int err; 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci BUILD_BUG_ON(offsetof(struct vcpu_svm, vcpu) != 0); 143862306a36Sopenharmony_ci svm = to_svm(vcpu); 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci err = -ENOMEM; 144162306a36Sopenharmony_ci vmcb01_page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO); 144262306a36Sopenharmony_ci if (!vmcb01_page) 144362306a36Sopenharmony_ci goto out; 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci if (sev_es_guest(vcpu->kvm)) { 144662306a36Sopenharmony_ci /* 144762306a36Sopenharmony_ci * SEV-ES guests require a separate VMSA page used to contain 144862306a36Sopenharmony_ci * the encrypted register state of the guest. 144962306a36Sopenharmony_ci */ 145062306a36Sopenharmony_ci vmsa_page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO); 145162306a36Sopenharmony_ci if (!vmsa_page) 145262306a36Sopenharmony_ci goto error_free_vmcb_page; 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci /* 145562306a36Sopenharmony_ci * SEV-ES guests maintain an encrypted version of their FPU 145662306a36Sopenharmony_ci * state which is restored and saved on VMRUN and VMEXIT. 145762306a36Sopenharmony_ci * Mark vcpu->arch.guest_fpu->fpstate as scratch so it won't 145862306a36Sopenharmony_ci * do xsave/xrstor on it. 145962306a36Sopenharmony_ci */ 146062306a36Sopenharmony_ci fpstate_set_confidential(&vcpu->arch.guest_fpu); 146162306a36Sopenharmony_ci } 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci err = avic_init_vcpu(svm); 146462306a36Sopenharmony_ci if (err) 146562306a36Sopenharmony_ci goto error_free_vmsa_page; 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci svm->msrpm = svm_vcpu_alloc_msrpm(); 146862306a36Sopenharmony_ci if (!svm->msrpm) { 146962306a36Sopenharmony_ci err = -ENOMEM; 147062306a36Sopenharmony_ci goto error_free_vmsa_page; 147162306a36Sopenharmony_ci } 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci svm->x2avic_msrs_intercepted = true; 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci svm->vmcb01.ptr = page_address(vmcb01_page); 147662306a36Sopenharmony_ci svm->vmcb01.pa = __sme_set(page_to_pfn(vmcb01_page) << PAGE_SHIFT); 147762306a36Sopenharmony_ci svm_switch_vmcb(svm, &svm->vmcb01); 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci if (vmsa_page) 148062306a36Sopenharmony_ci svm->sev_es.vmsa = page_address(vmsa_page); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci svm->guest_state_loaded = false; 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci return 0; 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_cierror_free_vmsa_page: 148762306a36Sopenharmony_ci if (vmsa_page) 148862306a36Sopenharmony_ci __free_page(vmsa_page); 148962306a36Sopenharmony_cierror_free_vmcb_page: 149062306a36Sopenharmony_ci __free_page(vmcb01_page); 149162306a36Sopenharmony_ciout: 149262306a36Sopenharmony_ci return err; 149362306a36Sopenharmony_ci} 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_cistatic void svm_clear_current_vmcb(struct vmcb *vmcb) 149662306a36Sopenharmony_ci{ 149762306a36Sopenharmony_ci int i; 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci for_each_online_cpu(i) 150062306a36Sopenharmony_ci cmpxchg(per_cpu_ptr(&svm_data.current_vmcb, i), vmcb, NULL); 150162306a36Sopenharmony_ci} 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_cistatic void svm_vcpu_free(struct kvm_vcpu *vcpu) 150462306a36Sopenharmony_ci{ 150562306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci /* 150862306a36Sopenharmony_ci * The vmcb page can be recycled, causing a false negative in 150962306a36Sopenharmony_ci * svm_vcpu_load(). So, ensure that no logical CPU has this 151062306a36Sopenharmony_ci * vmcb page recorded as its current vmcb. 151162306a36Sopenharmony_ci */ 151262306a36Sopenharmony_ci svm_clear_current_vmcb(svm->vmcb); 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci svm_leave_nested(vcpu); 151562306a36Sopenharmony_ci svm_free_nested(svm); 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci sev_free_vcpu(vcpu); 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci __free_page(pfn_to_page(__sme_clr(svm->vmcb01.pa) >> PAGE_SHIFT)); 152062306a36Sopenharmony_ci __free_pages(virt_to_page(svm->msrpm), get_order(MSRPM_SIZE)); 152162306a36Sopenharmony_ci} 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_cistatic void svm_prepare_switch_to_guest(struct kvm_vcpu *vcpu) 152462306a36Sopenharmony_ci{ 152562306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 152662306a36Sopenharmony_ci struct svm_cpu_data *sd = per_cpu_ptr(&svm_data, vcpu->cpu); 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci if (sev_es_guest(vcpu->kvm)) 152962306a36Sopenharmony_ci sev_es_unmap_ghcb(svm); 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci if (svm->guest_state_loaded) 153262306a36Sopenharmony_ci return; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci /* 153562306a36Sopenharmony_ci * Save additional host state that will be restored on VMEXIT (sev-es) 153662306a36Sopenharmony_ci * or subsequent vmload of host save area. 153762306a36Sopenharmony_ci */ 153862306a36Sopenharmony_ci vmsave(sd->save_area_pa); 153962306a36Sopenharmony_ci if (sev_es_guest(vcpu->kvm)) { 154062306a36Sopenharmony_ci struct sev_es_save_area *hostsa; 154162306a36Sopenharmony_ci hostsa = (struct sev_es_save_area *)(page_address(sd->save_area) + 0x400); 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci sev_es_prepare_switch_to_guest(hostsa); 154462306a36Sopenharmony_ci } 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci if (tsc_scaling) 154762306a36Sopenharmony_ci __svm_write_tsc_multiplier(vcpu->arch.tsc_scaling_ratio); 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci /* 155062306a36Sopenharmony_ci * TSC_AUX is always virtualized for SEV-ES guests when the feature is 155162306a36Sopenharmony_ci * available. The user return MSR support is not required in this case 155262306a36Sopenharmony_ci * because TSC_AUX is restored on #VMEXIT from the host save area 155362306a36Sopenharmony_ci * (which has been initialized in svm_hardware_enable()). 155462306a36Sopenharmony_ci */ 155562306a36Sopenharmony_ci if (likely(tsc_aux_uret_slot >= 0) && 155662306a36Sopenharmony_ci (!boot_cpu_has(X86_FEATURE_V_TSC_AUX) || !sev_es_guest(vcpu->kvm))) 155762306a36Sopenharmony_ci kvm_set_user_return_msr(tsc_aux_uret_slot, svm->tsc_aux, -1ull); 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci svm->guest_state_loaded = true; 156062306a36Sopenharmony_ci} 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_cistatic void svm_prepare_host_switch(struct kvm_vcpu *vcpu) 156362306a36Sopenharmony_ci{ 156462306a36Sopenharmony_ci to_svm(vcpu)->guest_state_loaded = false; 156562306a36Sopenharmony_ci} 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_cistatic void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu) 156862306a36Sopenharmony_ci{ 156962306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 157062306a36Sopenharmony_ci struct svm_cpu_data *sd = per_cpu_ptr(&svm_data, cpu); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci if (sd->current_vmcb != svm->vmcb) { 157362306a36Sopenharmony_ci sd->current_vmcb = svm->vmcb; 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci if (!cpu_feature_enabled(X86_FEATURE_IBPB_ON_VMEXIT)) 157662306a36Sopenharmony_ci indirect_branch_prediction_barrier(); 157762306a36Sopenharmony_ci } 157862306a36Sopenharmony_ci if (kvm_vcpu_apicv_active(vcpu)) 157962306a36Sopenharmony_ci avic_vcpu_load(vcpu, cpu); 158062306a36Sopenharmony_ci} 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_cistatic void svm_vcpu_put(struct kvm_vcpu *vcpu) 158362306a36Sopenharmony_ci{ 158462306a36Sopenharmony_ci if (kvm_vcpu_apicv_active(vcpu)) 158562306a36Sopenharmony_ci avic_vcpu_put(vcpu); 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci svm_prepare_host_switch(vcpu); 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci ++vcpu->stat.host_state_reload; 159062306a36Sopenharmony_ci} 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_cistatic unsigned long svm_get_rflags(struct kvm_vcpu *vcpu) 159362306a36Sopenharmony_ci{ 159462306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 159562306a36Sopenharmony_ci unsigned long rflags = svm->vmcb->save.rflags; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci if (svm->nmi_singlestep) { 159862306a36Sopenharmony_ci /* Hide our flags if they were not set by the guest */ 159962306a36Sopenharmony_ci if (!(svm->nmi_singlestep_guest_rflags & X86_EFLAGS_TF)) 160062306a36Sopenharmony_ci rflags &= ~X86_EFLAGS_TF; 160162306a36Sopenharmony_ci if (!(svm->nmi_singlestep_guest_rflags & X86_EFLAGS_RF)) 160262306a36Sopenharmony_ci rflags &= ~X86_EFLAGS_RF; 160362306a36Sopenharmony_ci } 160462306a36Sopenharmony_ci return rflags; 160562306a36Sopenharmony_ci} 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_cistatic void svm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) 160862306a36Sopenharmony_ci{ 160962306a36Sopenharmony_ci if (to_svm(vcpu)->nmi_singlestep) 161062306a36Sopenharmony_ci rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF); 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci /* 161362306a36Sopenharmony_ci * Any change of EFLAGS.VM is accompanied by a reload of SS 161462306a36Sopenharmony_ci * (caused by either a task switch or an inter-privilege IRET), 161562306a36Sopenharmony_ci * so we do not need to update the CPL here. 161662306a36Sopenharmony_ci */ 161762306a36Sopenharmony_ci to_svm(vcpu)->vmcb->save.rflags = rflags; 161862306a36Sopenharmony_ci} 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_cistatic bool svm_get_if_flag(struct kvm_vcpu *vcpu) 162162306a36Sopenharmony_ci{ 162262306a36Sopenharmony_ci struct vmcb *vmcb = to_svm(vcpu)->vmcb; 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci return sev_es_guest(vcpu->kvm) 162562306a36Sopenharmony_ci ? vmcb->control.int_state & SVM_GUEST_INTERRUPT_MASK 162662306a36Sopenharmony_ci : kvm_get_rflags(vcpu) & X86_EFLAGS_IF; 162762306a36Sopenharmony_ci} 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_cistatic void svm_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg) 163062306a36Sopenharmony_ci{ 163162306a36Sopenharmony_ci kvm_register_mark_available(vcpu, reg); 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci switch (reg) { 163462306a36Sopenharmony_ci case VCPU_EXREG_PDPTR: 163562306a36Sopenharmony_ci /* 163662306a36Sopenharmony_ci * When !npt_enabled, mmu->pdptrs[] is already available since 163762306a36Sopenharmony_ci * it is always updated per SDM when moving to CRs. 163862306a36Sopenharmony_ci */ 163962306a36Sopenharmony_ci if (npt_enabled) 164062306a36Sopenharmony_ci load_pdptrs(vcpu, kvm_read_cr3(vcpu)); 164162306a36Sopenharmony_ci break; 164262306a36Sopenharmony_ci default: 164362306a36Sopenharmony_ci KVM_BUG_ON(1, vcpu->kvm); 164462306a36Sopenharmony_ci } 164562306a36Sopenharmony_ci} 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_cistatic void svm_set_vintr(struct vcpu_svm *svm) 164862306a36Sopenharmony_ci{ 164962306a36Sopenharmony_ci struct vmcb_control_area *control; 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci /* 165262306a36Sopenharmony_ci * The following fields are ignored when AVIC is enabled 165362306a36Sopenharmony_ci */ 165462306a36Sopenharmony_ci WARN_ON(kvm_vcpu_apicv_activated(&svm->vcpu)); 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_VINTR); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci /* 165962306a36Sopenharmony_ci * Recalculating intercepts may have cleared the VINTR intercept. If 166062306a36Sopenharmony_ci * V_INTR_MASKING is enabled in vmcb12, then the effective RFLAGS.IF 166162306a36Sopenharmony_ci * for L1 physical interrupts is L1's RFLAGS.IF at the time of VMRUN. 166262306a36Sopenharmony_ci * Requesting an interrupt window if save.RFLAGS.IF=0 is pointless as 166362306a36Sopenharmony_ci * interrupts will never be unblocked while L2 is running. 166462306a36Sopenharmony_ci */ 166562306a36Sopenharmony_ci if (!svm_is_intercept(svm, INTERCEPT_VINTR)) 166662306a36Sopenharmony_ci return; 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci /* 166962306a36Sopenharmony_ci * This is just a dummy VINTR to actually cause a vmexit to happen. 167062306a36Sopenharmony_ci * Actual injection of virtual interrupts happens through EVENTINJ. 167162306a36Sopenharmony_ci */ 167262306a36Sopenharmony_ci control = &svm->vmcb->control; 167362306a36Sopenharmony_ci control->int_vector = 0x0; 167462306a36Sopenharmony_ci control->int_ctl &= ~V_INTR_PRIO_MASK; 167562306a36Sopenharmony_ci control->int_ctl |= V_IRQ_MASK | 167662306a36Sopenharmony_ci ((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT); 167762306a36Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_INTR); 167862306a36Sopenharmony_ci} 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_cistatic void svm_clear_vintr(struct vcpu_svm *svm) 168162306a36Sopenharmony_ci{ 168262306a36Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_VINTR); 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci /* Drop int_ctl fields related to VINTR injection. */ 168562306a36Sopenharmony_ci svm->vmcb->control.int_ctl &= ~V_IRQ_INJECTION_BITS_MASK; 168662306a36Sopenharmony_ci if (is_guest_mode(&svm->vcpu)) { 168762306a36Sopenharmony_ci svm->vmcb01.ptr->control.int_ctl &= ~V_IRQ_INJECTION_BITS_MASK; 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci WARN_ON((svm->vmcb->control.int_ctl & V_TPR_MASK) != 169062306a36Sopenharmony_ci (svm->nested.ctl.int_ctl & V_TPR_MASK)); 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci svm->vmcb->control.int_ctl |= svm->nested.ctl.int_ctl & 169362306a36Sopenharmony_ci V_IRQ_INJECTION_BITS_MASK; 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci svm->vmcb->control.int_vector = svm->nested.ctl.int_vector; 169662306a36Sopenharmony_ci } 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_INTR); 169962306a36Sopenharmony_ci} 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_cistatic struct vmcb_seg *svm_seg(struct kvm_vcpu *vcpu, int seg) 170262306a36Sopenharmony_ci{ 170362306a36Sopenharmony_ci struct vmcb_save_area *save = &to_svm(vcpu)->vmcb->save; 170462306a36Sopenharmony_ci struct vmcb_save_area *save01 = &to_svm(vcpu)->vmcb01.ptr->save; 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci switch (seg) { 170762306a36Sopenharmony_ci case VCPU_SREG_CS: return &save->cs; 170862306a36Sopenharmony_ci case VCPU_SREG_DS: return &save->ds; 170962306a36Sopenharmony_ci case VCPU_SREG_ES: return &save->es; 171062306a36Sopenharmony_ci case VCPU_SREG_FS: return &save01->fs; 171162306a36Sopenharmony_ci case VCPU_SREG_GS: return &save01->gs; 171262306a36Sopenharmony_ci case VCPU_SREG_SS: return &save->ss; 171362306a36Sopenharmony_ci case VCPU_SREG_TR: return &save01->tr; 171462306a36Sopenharmony_ci case VCPU_SREG_LDTR: return &save01->ldtr; 171562306a36Sopenharmony_ci } 171662306a36Sopenharmony_ci BUG(); 171762306a36Sopenharmony_ci return NULL; 171862306a36Sopenharmony_ci} 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_cistatic u64 svm_get_segment_base(struct kvm_vcpu *vcpu, int seg) 172162306a36Sopenharmony_ci{ 172262306a36Sopenharmony_ci struct vmcb_seg *s = svm_seg(vcpu, seg); 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci return s->base; 172562306a36Sopenharmony_ci} 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_cistatic void svm_get_segment(struct kvm_vcpu *vcpu, 172862306a36Sopenharmony_ci struct kvm_segment *var, int seg) 172962306a36Sopenharmony_ci{ 173062306a36Sopenharmony_ci struct vmcb_seg *s = svm_seg(vcpu, seg); 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci var->base = s->base; 173362306a36Sopenharmony_ci var->limit = s->limit; 173462306a36Sopenharmony_ci var->selector = s->selector; 173562306a36Sopenharmony_ci var->type = s->attrib & SVM_SELECTOR_TYPE_MASK; 173662306a36Sopenharmony_ci var->s = (s->attrib >> SVM_SELECTOR_S_SHIFT) & 1; 173762306a36Sopenharmony_ci var->dpl = (s->attrib >> SVM_SELECTOR_DPL_SHIFT) & 3; 173862306a36Sopenharmony_ci var->present = (s->attrib >> SVM_SELECTOR_P_SHIFT) & 1; 173962306a36Sopenharmony_ci var->avl = (s->attrib >> SVM_SELECTOR_AVL_SHIFT) & 1; 174062306a36Sopenharmony_ci var->l = (s->attrib >> SVM_SELECTOR_L_SHIFT) & 1; 174162306a36Sopenharmony_ci var->db = (s->attrib >> SVM_SELECTOR_DB_SHIFT) & 1; 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci /* 174462306a36Sopenharmony_ci * AMD CPUs circa 2014 track the G bit for all segments except CS. 174562306a36Sopenharmony_ci * However, the SVM spec states that the G bit is not observed by the 174662306a36Sopenharmony_ci * CPU, and some VMware virtual CPUs drop the G bit for all segments. 174762306a36Sopenharmony_ci * So let's synthesize a legal G bit for all segments, this helps 174862306a36Sopenharmony_ci * running KVM nested. It also helps cross-vendor migration, because 174962306a36Sopenharmony_ci * Intel's vmentry has a check on the 'G' bit. 175062306a36Sopenharmony_ci */ 175162306a36Sopenharmony_ci var->g = s->limit > 0xfffff; 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci /* 175462306a36Sopenharmony_ci * AMD's VMCB does not have an explicit unusable field, so emulate it 175562306a36Sopenharmony_ci * for cross vendor migration purposes by "not present" 175662306a36Sopenharmony_ci */ 175762306a36Sopenharmony_ci var->unusable = !var->present; 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci switch (seg) { 176062306a36Sopenharmony_ci case VCPU_SREG_TR: 176162306a36Sopenharmony_ci /* 176262306a36Sopenharmony_ci * Work around a bug where the busy flag in the tr selector 176362306a36Sopenharmony_ci * isn't exposed 176462306a36Sopenharmony_ci */ 176562306a36Sopenharmony_ci var->type |= 0x2; 176662306a36Sopenharmony_ci break; 176762306a36Sopenharmony_ci case VCPU_SREG_DS: 176862306a36Sopenharmony_ci case VCPU_SREG_ES: 176962306a36Sopenharmony_ci case VCPU_SREG_FS: 177062306a36Sopenharmony_ci case VCPU_SREG_GS: 177162306a36Sopenharmony_ci /* 177262306a36Sopenharmony_ci * The accessed bit must always be set in the segment 177362306a36Sopenharmony_ci * descriptor cache, although it can be cleared in the 177462306a36Sopenharmony_ci * descriptor, the cached bit always remains at 1. Since 177562306a36Sopenharmony_ci * Intel has a check on this, set it here to support 177662306a36Sopenharmony_ci * cross-vendor migration. 177762306a36Sopenharmony_ci */ 177862306a36Sopenharmony_ci if (!var->unusable) 177962306a36Sopenharmony_ci var->type |= 0x1; 178062306a36Sopenharmony_ci break; 178162306a36Sopenharmony_ci case VCPU_SREG_SS: 178262306a36Sopenharmony_ci /* 178362306a36Sopenharmony_ci * On AMD CPUs sometimes the DB bit in the segment 178462306a36Sopenharmony_ci * descriptor is left as 1, although the whole segment has 178562306a36Sopenharmony_ci * been made unusable. Clear it here to pass an Intel VMX 178662306a36Sopenharmony_ci * entry check when cross vendor migrating. 178762306a36Sopenharmony_ci */ 178862306a36Sopenharmony_ci if (var->unusable) 178962306a36Sopenharmony_ci var->db = 0; 179062306a36Sopenharmony_ci /* This is symmetric with svm_set_segment() */ 179162306a36Sopenharmony_ci var->dpl = to_svm(vcpu)->vmcb->save.cpl; 179262306a36Sopenharmony_ci break; 179362306a36Sopenharmony_ci } 179462306a36Sopenharmony_ci} 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_cistatic int svm_get_cpl(struct kvm_vcpu *vcpu) 179762306a36Sopenharmony_ci{ 179862306a36Sopenharmony_ci struct vmcb_save_area *save = &to_svm(vcpu)->vmcb->save; 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci return save->cpl; 180162306a36Sopenharmony_ci} 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_cistatic void svm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) 180462306a36Sopenharmony_ci{ 180562306a36Sopenharmony_ci struct kvm_segment cs; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci svm_get_segment(vcpu, &cs, VCPU_SREG_CS); 180862306a36Sopenharmony_ci *db = cs.db; 180962306a36Sopenharmony_ci *l = cs.l; 181062306a36Sopenharmony_ci} 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_cistatic void svm_get_idt(struct kvm_vcpu *vcpu, struct desc_ptr *dt) 181362306a36Sopenharmony_ci{ 181462306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci dt->size = svm->vmcb->save.idtr.limit; 181762306a36Sopenharmony_ci dt->address = svm->vmcb->save.idtr.base; 181862306a36Sopenharmony_ci} 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_cistatic void svm_set_idt(struct kvm_vcpu *vcpu, struct desc_ptr *dt) 182162306a36Sopenharmony_ci{ 182262306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci svm->vmcb->save.idtr.limit = dt->size; 182562306a36Sopenharmony_ci svm->vmcb->save.idtr.base = dt->address ; 182662306a36Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_DT); 182762306a36Sopenharmony_ci} 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_cistatic void svm_get_gdt(struct kvm_vcpu *vcpu, struct desc_ptr *dt) 183062306a36Sopenharmony_ci{ 183162306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci dt->size = svm->vmcb->save.gdtr.limit; 183462306a36Sopenharmony_ci dt->address = svm->vmcb->save.gdtr.base; 183562306a36Sopenharmony_ci} 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_cistatic void svm_set_gdt(struct kvm_vcpu *vcpu, struct desc_ptr *dt) 183862306a36Sopenharmony_ci{ 183962306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci svm->vmcb->save.gdtr.limit = dt->size; 184262306a36Sopenharmony_ci svm->vmcb->save.gdtr.base = dt->address ; 184362306a36Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_DT); 184462306a36Sopenharmony_ci} 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_cistatic void sev_post_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) 184762306a36Sopenharmony_ci{ 184862306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci /* 185162306a36Sopenharmony_ci * For guests that don't set guest_state_protected, the cr3 update is 185262306a36Sopenharmony_ci * handled via kvm_mmu_load() while entering the guest. For guests 185362306a36Sopenharmony_ci * that do (SEV-ES/SEV-SNP), the cr3 update needs to be written to 185462306a36Sopenharmony_ci * VMCB save area now, since the save area will become the initial 185562306a36Sopenharmony_ci * contents of the VMSA, and future VMCB save area updates won't be 185662306a36Sopenharmony_ci * seen. 185762306a36Sopenharmony_ci */ 185862306a36Sopenharmony_ci if (sev_es_guest(vcpu->kvm)) { 185962306a36Sopenharmony_ci svm->vmcb->save.cr3 = cr3; 186062306a36Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_CR); 186162306a36Sopenharmony_ci } 186262306a36Sopenharmony_ci} 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_cistatic bool svm_is_valid_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) 186562306a36Sopenharmony_ci{ 186662306a36Sopenharmony_ci return true; 186762306a36Sopenharmony_ci} 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_civoid svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) 187062306a36Sopenharmony_ci{ 187162306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 187262306a36Sopenharmony_ci u64 hcr0 = cr0; 187362306a36Sopenharmony_ci bool old_paging = is_paging(vcpu); 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci#ifdef CONFIG_X86_64 187662306a36Sopenharmony_ci if (vcpu->arch.efer & EFER_LME) { 187762306a36Sopenharmony_ci if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) { 187862306a36Sopenharmony_ci vcpu->arch.efer |= EFER_LMA; 187962306a36Sopenharmony_ci if (!vcpu->arch.guest_state_protected) 188062306a36Sopenharmony_ci svm->vmcb->save.efer |= EFER_LMA | EFER_LME; 188162306a36Sopenharmony_ci } 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci if (is_paging(vcpu) && !(cr0 & X86_CR0_PG)) { 188462306a36Sopenharmony_ci vcpu->arch.efer &= ~EFER_LMA; 188562306a36Sopenharmony_ci if (!vcpu->arch.guest_state_protected) 188662306a36Sopenharmony_ci svm->vmcb->save.efer &= ~(EFER_LMA | EFER_LME); 188762306a36Sopenharmony_ci } 188862306a36Sopenharmony_ci } 188962306a36Sopenharmony_ci#endif 189062306a36Sopenharmony_ci vcpu->arch.cr0 = cr0; 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci if (!npt_enabled) { 189362306a36Sopenharmony_ci hcr0 |= X86_CR0_PG | X86_CR0_WP; 189462306a36Sopenharmony_ci if (old_paging != is_paging(vcpu)) 189562306a36Sopenharmony_ci svm_set_cr4(vcpu, kvm_read_cr4(vcpu)); 189662306a36Sopenharmony_ci } 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci /* 189962306a36Sopenharmony_ci * re-enable caching here because the QEMU bios 190062306a36Sopenharmony_ci * does not do it - this results in some delay at 190162306a36Sopenharmony_ci * reboot 190262306a36Sopenharmony_ci */ 190362306a36Sopenharmony_ci if (kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_CD_NW_CLEARED)) 190462306a36Sopenharmony_ci hcr0 &= ~(X86_CR0_CD | X86_CR0_NW); 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci svm->vmcb->save.cr0 = hcr0; 190762306a36Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_CR); 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci /* 191062306a36Sopenharmony_ci * SEV-ES guests must always keep the CR intercepts cleared. CR 191162306a36Sopenharmony_ci * tracking is done using the CR write traps. 191262306a36Sopenharmony_ci */ 191362306a36Sopenharmony_ci if (sev_es_guest(vcpu->kvm)) 191462306a36Sopenharmony_ci return; 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci if (hcr0 == cr0) { 191762306a36Sopenharmony_ci /* Selective CR0 write remains on. */ 191862306a36Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_CR0_READ); 191962306a36Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_CR0_WRITE); 192062306a36Sopenharmony_ci } else { 192162306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CR0_READ); 192262306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CR0_WRITE); 192362306a36Sopenharmony_ci } 192462306a36Sopenharmony_ci} 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_cistatic bool svm_is_valid_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) 192762306a36Sopenharmony_ci{ 192862306a36Sopenharmony_ci return true; 192962306a36Sopenharmony_ci} 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_civoid svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) 193262306a36Sopenharmony_ci{ 193362306a36Sopenharmony_ci unsigned long host_cr4_mce = cr4_read_shadow() & X86_CR4_MCE; 193462306a36Sopenharmony_ci unsigned long old_cr4 = vcpu->arch.cr4; 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci if (npt_enabled && ((old_cr4 ^ cr4) & X86_CR4_PGE)) 193762306a36Sopenharmony_ci svm_flush_tlb_current(vcpu); 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci vcpu->arch.cr4 = cr4; 194062306a36Sopenharmony_ci if (!npt_enabled) { 194162306a36Sopenharmony_ci cr4 |= X86_CR4_PAE; 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci if (!is_paging(vcpu)) 194462306a36Sopenharmony_ci cr4 &= ~(X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_PKE); 194562306a36Sopenharmony_ci } 194662306a36Sopenharmony_ci cr4 |= host_cr4_mce; 194762306a36Sopenharmony_ci to_svm(vcpu)->vmcb->save.cr4 = cr4; 194862306a36Sopenharmony_ci vmcb_mark_dirty(to_svm(vcpu)->vmcb, VMCB_CR); 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci if ((cr4 ^ old_cr4) & (X86_CR4_OSXSAVE | X86_CR4_PKE)) 195162306a36Sopenharmony_ci kvm_update_cpuid_runtime(vcpu); 195262306a36Sopenharmony_ci} 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_cistatic void svm_set_segment(struct kvm_vcpu *vcpu, 195562306a36Sopenharmony_ci struct kvm_segment *var, int seg) 195662306a36Sopenharmony_ci{ 195762306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 195862306a36Sopenharmony_ci struct vmcb_seg *s = svm_seg(vcpu, seg); 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci s->base = var->base; 196162306a36Sopenharmony_ci s->limit = var->limit; 196262306a36Sopenharmony_ci s->selector = var->selector; 196362306a36Sopenharmony_ci s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK); 196462306a36Sopenharmony_ci s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT; 196562306a36Sopenharmony_ci s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT; 196662306a36Sopenharmony_ci s->attrib |= ((var->present & 1) && !var->unusable) << SVM_SELECTOR_P_SHIFT; 196762306a36Sopenharmony_ci s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT; 196862306a36Sopenharmony_ci s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT; 196962306a36Sopenharmony_ci s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT; 197062306a36Sopenharmony_ci s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT; 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci /* 197362306a36Sopenharmony_ci * This is always accurate, except if SYSRET returned to a segment 197462306a36Sopenharmony_ci * with SS.DPL != 3. Intel does not have this quirk, and always 197562306a36Sopenharmony_ci * forces SS.DPL to 3 on sysret, so we ignore that case; fixing it 197662306a36Sopenharmony_ci * would entail passing the CPL to userspace and back. 197762306a36Sopenharmony_ci */ 197862306a36Sopenharmony_ci if (seg == VCPU_SREG_SS) 197962306a36Sopenharmony_ci /* This is symmetric with svm_get_segment() */ 198062306a36Sopenharmony_ci svm->vmcb->save.cpl = (var->dpl & 3); 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_SEG); 198362306a36Sopenharmony_ci} 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_cistatic void svm_update_exception_bitmap(struct kvm_vcpu *vcpu) 198662306a36Sopenharmony_ci{ 198762306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci clr_exception_intercept(svm, BP_VECTOR); 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci if (vcpu->guest_debug & KVM_GUESTDBG_ENABLE) { 199262306a36Sopenharmony_ci if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) 199362306a36Sopenharmony_ci set_exception_intercept(svm, BP_VECTOR); 199462306a36Sopenharmony_ci } 199562306a36Sopenharmony_ci} 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_cistatic void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *sd) 199862306a36Sopenharmony_ci{ 199962306a36Sopenharmony_ci if (sd->next_asid > sd->max_asid) { 200062306a36Sopenharmony_ci ++sd->asid_generation; 200162306a36Sopenharmony_ci sd->next_asid = sd->min_asid; 200262306a36Sopenharmony_ci svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID; 200362306a36Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_ASID); 200462306a36Sopenharmony_ci } 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci svm->current_vmcb->asid_generation = sd->asid_generation; 200762306a36Sopenharmony_ci svm->asid = sd->next_asid++; 200862306a36Sopenharmony_ci} 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_cistatic void svm_set_dr6(struct vcpu_svm *svm, unsigned long value) 201162306a36Sopenharmony_ci{ 201262306a36Sopenharmony_ci struct vmcb *vmcb = svm->vmcb; 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci if (svm->vcpu.arch.guest_state_protected) 201562306a36Sopenharmony_ci return; 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci if (unlikely(value != vmcb->save.dr6)) { 201862306a36Sopenharmony_ci vmcb->save.dr6 = value; 201962306a36Sopenharmony_ci vmcb_mark_dirty(vmcb, VMCB_DR); 202062306a36Sopenharmony_ci } 202162306a36Sopenharmony_ci} 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_cistatic void svm_sync_dirty_debug_regs(struct kvm_vcpu *vcpu) 202462306a36Sopenharmony_ci{ 202562306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci if (WARN_ON_ONCE(sev_es_guest(vcpu->kvm))) 202862306a36Sopenharmony_ci return; 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci get_debugreg(vcpu->arch.db[0], 0); 203162306a36Sopenharmony_ci get_debugreg(vcpu->arch.db[1], 1); 203262306a36Sopenharmony_ci get_debugreg(vcpu->arch.db[2], 2); 203362306a36Sopenharmony_ci get_debugreg(vcpu->arch.db[3], 3); 203462306a36Sopenharmony_ci /* 203562306a36Sopenharmony_ci * We cannot reset svm->vmcb->save.dr6 to DR6_ACTIVE_LOW here, 203662306a36Sopenharmony_ci * because db_interception might need it. We can do it before vmentry. 203762306a36Sopenharmony_ci */ 203862306a36Sopenharmony_ci vcpu->arch.dr6 = svm->vmcb->save.dr6; 203962306a36Sopenharmony_ci vcpu->arch.dr7 = svm->vmcb->save.dr7; 204062306a36Sopenharmony_ci vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_WONT_EXIT; 204162306a36Sopenharmony_ci set_dr_intercepts(svm); 204262306a36Sopenharmony_ci} 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_cistatic void svm_set_dr7(struct kvm_vcpu *vcpu, unsigned long value) 204562306a36Sopenharmony_ci{ 204662306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci if (vcpu->arch.guest_state_protected) 204962306a36Sopenharmony_ci return; 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci svm->vmcb->save.dr7 = value; 205262306a36Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_DR); 205362306a36Sopenharmony_ci} 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_cistatic int pf_interception(struct kvm_vcpu *vcpu) 205662306a36Sopenharmony_ci{ 205762306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci u64 fault_address = svm->vmcb->control.exit_info_2; 206062306a36Sopenharmony_ci u64 error_code = svm->vmcb->control.exit_info_1; 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ci return kvm_handle_page_fault(vcpu, error_code, fault_address, 206362306a36Sopenharmony_ci static_cpu_has(X86_FEATURE_DECODEASSISTS) ? 206462306a36Sopenharmony_ci svm->vmcb->control.insn_bytes : NULL, 206562306a36Sopenharmony_ci svm->vmcb->control.insn_len); 206662306a36Sopenharmony_ci} 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_cistatic int npf_interception(struct kvm_vcpu *vcpu) 206962306a36Sopenharmony_ci{ 207062306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci u64 fault_address = svm->vmcb->control.exit_info_2; 207362306a36Sopenharmony_ci u64 error_code = svm->vmcb->control.exit_info_1; 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci trace_kvm_page_fault(vcpu, fault_address, error_code); 207662306a36Sopenharmony_ci return kvm_mmu_page_fault(vcpu, fault_address, error_code, 207762306a36Sopenharmony_ci static_cpu_has(X86_FEATURE_DECODEASSISTS) ? 207862306a36Sopenharmony_ci svm->vmcb->control.insn_bytes : NULL, 207962306a36Sopenharmony_ci svm->vmcb->control.insn_len); 208062306a36Sopenharmony_ci} 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_cistatic int db_interception(struct kvm_vcpu *vcpu) 208362306a36Sopenharmony_ci{ 208462306a36Sopenharmony_ci struct kvm_run *kvm_run = vcpu->run; 208562306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci if (!(vcpu->guest_debug & 208862306a36Sopenharmony_ci (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)) && 208962306a36Sopenharmony_ci !svm->nmi_singlestep) { 209062306a36Sopenharmony_ci u32 payload = svm->vmcb->save.dr6 ^ DR6_ACTIVE_LOW; 209162306a36Sopenharmony_ci kvm_queue_exception_p(vcpu, DB_VECTOR, payload); 209262306a36Sopenharmony_ci return 1; 209362306a36Sopenharmony_ci } 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_ci if (svm->nmi_singlestep) { 209662306a36Sopenharmony_ci disable_nmi_singlestep(svm); 209762306a36Sopenharmony_ci /* Make sure we check for pending NMIs upon entry */ 209862306a36Sopenharmony_ci kvm_make_request(KVM_REQ_EVENT, vcpu); 209962306a36Sopenharmony_ci } 210062306a36Sopenharmony_ci 210162306a36Sopenharmony_ci if (vcpu->guest_debug & 210262306a36Sopenharmony_ci (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)) { 210362306a36Sopenharmony_ci kvm_run->exit_reason = KVM_EXIT_DEBUG; 210462306a36Sopenharmony_ci kvm_run->debug.arch.dr6 = svm->vmcb->save.dr6; 210562306a36Sopenharmony_ci kvm_run->debug.arch.dr7 = svm->vmcb->save.dr7; 210662306a36Sopenharmony_ci kvm_run->debug.arch.pc = 210762306a36Sopenharmony_ci svm->vmcb->save.cs.base + svm->vmcb->save.rip; 210862306a36Sopenharmony_ci kvm_run->debug.arch.exception = DB_VECTOR; 210962306a36Sopenharmony_ci return 0; 211062306a36Sopenharmony_ci } 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci return 1; 211362306a36Sopenharmony_ci} 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_cistatic int bp_interception(struct kvm_vcpu *vcpu) 211662306a36Sopenharmony_ci{ 211762306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 211862306a36Sopenharmony_ci struct kvm_run *kvm_run = vcpu->run; 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci kvm_run->exit_reason = KVM_EXIT_DEBUG; 212162306a36Sopenharmony_ci kvm_run->debug.arch.pc = svm->vmcb->save.cs.base + svm->vmcb->save.rip; 212262306a36Sopenharmony_ci kvm_run->debug.arch.exception = BP_VECTOR; 212362306a36Sopenharmony_ci return 0; 212462306a36Sopenharmony_ci} 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_cistatic int ud_interception(struct kvm_vcpu *vcpu) 212762306a36Sopenharmony_ci{ 212862306a36Sopenharmony_ci return handle_ud(vcpu); 212962306a36Sopenharmony_ci} 213062306a36Sopenharmony_ci 213162306a36Sopenharmony_cistatic int ac_interception(struct kvm_vcpu *vcpu) 213262306a36Sopenharmony_ci{ 213362306a36Sopenharmony_ci kvm_queue_exception_e(vcpu, AC_VECTOR, 0); 213462306a36Sopenharmony_ci return 1; 213562306a36Sopenharmony_ci} 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_cistatic bool is_erratum_383(void) 213862306a36Sopenharmony_ci{ 213962306a36Sopenharmony_ci int err, i; 214062306a36Sopenharmony_ci u64 value; 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci if (!erratum_383_found) 214362306a36Sopenharmony_ci return false; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci value = native_read_msr_safe(MSR_IA32_MC0_STATUS, &err); 214662306a36Sopenharmony_ci if (err) 214762306a36Sopenharmony_ci return false; 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci /* Bit 62 may or may not be set for this mce */ 215062306a36Sopenharmony_ci value &= ~(1ULL << 62); 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci if (value != 0xb600000000010015ULL) 215362306a36Sopenharmony_ci return false; 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci /* Clear MCi_STATUS registers */ 215662306a36Sopenharmony_ci for (i = 0; i < 6; ++i) 215762306a36Sopenharmony_ci native_write_msr_safe(MSR_IA32_MCx_STATUS(i), 0, 0); 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_ci value = native_read_msr_safe(MSR_IA32_MCG_STATUS, &err); 216062306a36Sopenharmony_ci if (!err) { 216162306a36Sopenharmony_ci u32 low, high; 216262306a36Sopenharmony_ci 216362306a36Sopenharmony_ci value &= ~(1ULL << 2); 216462306a36Sopenharmony_ci low = lower_32_bits(value); 216562306a36Sopenharmony_ci high = upper_32_bits(value); 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_ci native_write_msr_safe(MSR_IA32_MCG_STATUS, low, high); 216862306a36Sopenharmony_ci } 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci /* Flush tlb to evict multi-match entries */ 217162306a36Sopenharmony_ci __flush_tlb_all(); 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci return true; 217462306a36Sopenharmony_ci} 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_cistatic void svm_handle_mce(struct kvm_vcpu *vcpu) 217762306a36Sopenharmony_ci{ 217862306a36Sopenharmony_ci if (is_erratum_383()) { 217962306a36Sopenharmony_ci /* 218062306a36Sopenharmony_ci * Erratum 383 triggered. Guest state is corrupt so kill the 218162306a36Sopenharmony_ci * guest. 218262306a36Sopenharmony_ci */ 218362306a36Sopenharmony_ci pr_err("Guest triggered AMD Erratum 383\n"); 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu); 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci return; 218862306a36Sopenharmony_ci } 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci /* 219162306a36Sopenharmony_ci * On an #MC intercept the MCE handler is not called automatically in 219262306a36Sopenharmony_ci * the host. So do it by hand here. 219362306a36Sopenharmony_ci */ 219462306a36Sopenharmony_ci kvm_machine_check(); 219562306a36Sopenharmony_ci} 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_cistatic int mc_interception(struct kvm_vcpu *vcpu) 219862306a36Sopenharmony_ci{ 219962306a36Sopenharmony_ci return 1; 220062306a36Sopenharmony_ci} 220162306a36Sopenharmony_ci 220262306a36Sopenharmony_cistatic int shutdown_interception(struct kvm_vcpu *vcpu) 220362306a36Sopenharmony_ci{ 220462306a36Sopenharmony_ci struct kvm_run *kvm_run = vcpu->run; 220562306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci /* 220862306a36Sopenharmony_ci * The VM save area has already been encrypted so it 220962306a36Sopenharmony_ci * cannot be reinitialized - just terminate. 221062306a36Sopenharmony_ci */ 221162306a36Sopenharmony_ci if (sev_es_guest(vcpu->kvm)) 221262306a36Sopenharmony_ci return -EINVAL; 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci /* 221562306a36Sopenharmony_ci * VMCB is undefined after a SHUTDOWN intercept. INIT the vCPU to put 221662306a36Sopenharmony_ci * the VMCB in a known good state. Unfortuately, KVM doesn't have 221762306a36Sopenharmony_ci * KVM_MP_STATE_SHUTDOWN and can't add it without potentially breaking 221862306a36Sopenharmony_ci * userspace. At a platform view, INIT is acceptable behavior as 221962306a36Sopenharmony_ci * there exist bare metal platforms that automatically INIT the CPU 222062306a36Sopenharmony_ci * in response to shutdown. 222162306a36Sopenharmony_ci */ 222262306a36Sopenharmony_ci clear_page(svm->vmcb); 222362306a36Sopenharmony_ci kvm_vcpu_reset(vcpu, true); 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci kvm_run->exit_reason = KVM_EXIT_SHUTDOWN; 222662306a36Sopenharmony_ci return 0; 222762306a36Sopenharmony_ci} 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_cistatic int io_interception(struct kvm_vcpu *vcpu) 223062306a36Sopenharmony_ci{ 223162306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 223262306a36Sopenharmony_ci u32 io_info = svm->vmcb->control.exit_info_1; /* address size bug? */ 223362306a36Sopenharmony_ci int size, in, string; 223462306a36Sopenharmony_ci unsigned port; 223562306a36Sopenharmony_ci 223662306a36Sopenharmony_ci ++vcpu->stat.io_exits; 223762306a36Sopenharmony_ci string = (io_info & SVM_IOIO_STR_MASK) != 0; 223862306a36Sopenharmony_ci in = (io_info & SVM_IOIO_TYPE_MASK) != 0; 223962306a36Sopenharmony_ci port = io_info >> 16; 224062306a36Sopenharmony_ci size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT; 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci if (string) { 224362306a36Sopenharmony_ci if (sev_es_guest(vcpu->kvm)) 224462306a36Sopenharmony_ci return sev_es_string_io(svm, size, port, in); 224562306a36Sopenharmony_ci else 224662306a36Sopenharmony_ci return kvm_emulate_instruction(vcpu, 0); 224762306a36Sopenharmony_ci } 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci svm->next_rip = svm->vmcb->control.exit_info_2; 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci return kvm_fast_pio(vcpu, size, port, in); 225262306a36Sopenharmony_ci} 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_cistatic int nmi_interception(struct kvm_vcpu *vcpu) 225562306a36Sopenharmony_ci{ 225662306a36Sopenharmony_ci return 1; 225762306a36Sopenharmony_ci} 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_cistatic int smi_interception(struct kvm_vcpu *vcpu) 226062306a36Sopenharmony_ci{ 226162306a36Sopenharmony_ci return 1; 226262306a36Sopenharmony_ci} 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_cistatic int intr_interception(struct kvm_vcpu *vcpu) 226562306a36Sopenharmony_ci{ 226662306a36Sopenharmony_ci ++vcpu->stat.irq_exits; 226762306a36Sopenharmony_ci return 1; 226862306a36Sopenharmony_ci} 226962306a36Sopenharmony_ci 227062306a36Sopenharmony_cistatic int vmload_vmsave_interception(struct kvm_vcpu *vcpu, bool vmload) 227162306a36Sopenharmony_ci{ 227262306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 227362306a36Sopenharmony_ci struct vmcb *vmcb12; 227462306a36Sopenharmony_ci struct kvm_host_map map; 227562306a36Sopenharmony_ci int ret; 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci if (nested_svm_check_permissions(vcpu)) 227862306a36Sopenharmony_ci return 1; 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_ci ret = kvm_vcpu_map(vcpu, gpa_to_gfn(svm->vmcb->save.rax), &map); 228162306a36Sopenharmony_ci if (ret) { 228262306a36Sopenharmony_ci if (ret == -EINVAL) 228362306a36Sopenharmony_ci kvm_inject_gp(vcpu, 0); 228462306a36Sopenharmony_ci return 1; 228562306a36Sopenharmony_ci } 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci vmcb12 = map.hva; 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_ci ret = kvm_skip_emulated_instruction(vcpu); 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci if (vmload) { 229262306a36Sopenharmony_ci svm_copy_vmloadsave_state(svm->vmcb, vmcb12); 229362306a36Sopenharmony_ci svm->sysenter_eip_hi = 0; 229462306a36Sopenharmony_ci svm->sysenter_esp_hi = 0; 229562306a36Sopenharmony_ci } else { 229662306a36Sopenharmony_ci svm_copy_vmloadsave_state(vmcb12, svm->vmcb); 229762306a36Sopenharmony_ci } 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci kvm_vcpu_unmap(vcpu, &map, true); 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci return ret; 230262306a36Sopenharmony_ci} 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_cistatic int vmload_interception(struct kvm_vcpu *vcpu) 230562306a36Sopenharmony_ci{ 230662306a36Sopenharmony_ci return vmload_vmsave_interception(vcpu, true); 230762306a36Sopenharmony_ci} 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_cistatic int vmsave_interception(struct kvm_vcpu *vcpu) 231062306a36Sopenharmony_ci{ 231162306a36Sopenharmony_ci return vmload_vmsave_interception(vcpu, false); 231262306a36Sopenharmony_ci} 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_cistatic int vmrun_interception(struct kvm_vcpu *vcpu) 231562306a36Sopenharmony_ci{ 231662306a36Sopenharmony_ci if (nested_svm_check_permissions(vcpu)) 231762306a36Sopenharmony_ci return 1; 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci return nested_svm_vmrun(vcpu); 232062306a36Sopenharmony_ci} 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_cienum { 232362306a36Sopenharmony_ci NONE_SVM_INSTR, 232462306a36Sopenharmony_ci SVM_INSTR_VMRUN, 232562306a36Sopenharmony_ci SVM_INSTR_VMLOAD, 232662306a36Sopenharmony_ci SVM_INSTR_VMSAVE, 232762306a36Sopenharmony_ci}; 232862306a36Sopenharmony_ci 232962306a36Sopenharmony_ci/* Return NONE_SVM_INSTR if not SVM instrs, otherwise return decode result */ 233062306a36Sopenharmony_cistatic int svm_instr_opcode(struct kvm_vcpu *vcpu) 233162306a36Sopenharmony_ci{ 233262306a36Sopenharmony_ci struct x86_emulate_ctxt *ctxt = vcpu->arch.emulate_ctxt; 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci if (ctxt->b != 0x1 || ctxt->opcode_len != 2) 233562306a36Sopenharmony_ci return NONE_SVM_INSTR; 233662306a36Sopenharmony_ci 233762306a36Sopenharmony_ci switch (ctxt->modrm) { 233862306a36Sopenharmony_ci case 0xd8: /* VMRUN */ 233962306a36Sopenharmony_ci return SVM_INSTR_VMRUN; 234062306a36Sopenharmony_ci case 0xda: /* VMLOAD */ 234162306a36Sopenharmony_ci return SVM_INSTR_VMLOAD; 234262306a36Sopenharmony_ci case 0xdb: /* VMSAVE */ 234362306a36Sopenharmony_ci return SVM_INSTR_VMSAVE; 234462306a36Sopenharmony_ci default: 234562306a36Sopenharmony_ci break; 234662306a36Sopenharmony_ci } 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci return NONE_SVM_INSTR; 234962306a36Sopenharmony_ci} 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_cistatic int emulate_svm_instr(struct kvm_vcpu *vcpu, int opcode) 235262306a36Sopenharmony_ci{ 235362306a36Sopenharmony_ci const int guest_mode_exit_codes[] = { 235462306a36Sopenharmony_ci [SVM_INSTR_VMRUN] = SVM_EXIT_VMRUN, 235562306a36Sopenharmony_ci [SVM_INSTR_VMLOAD] = SVM_EXIT_VMLOAD, 235662306a36Sopenharmony_ci [SVM_INSTR_VMSAVE] = SVM_EXIT_VMSAVE, 235762306a36Sopenharmony_ci }; 235862306a36Sopenharmony_ci int (*const svm_instr_handlers[])(struct kvm_vcpu *vcpu) = { 235962306a36Sopenharmony_ci [SVM_INSTR_VMRUN] = vmrun_interception, 236062306a36Sopenharmony_ci [SVM_INSTR_VMLOAD] = vmload_interception, 236162306a36Sopenharmony_ci [SVM_INSTR_VMSAVE] = vmsave_interception, 236262306a36Sopenharmony_ci }; 236362306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 236462306a36Sopenharmony_ci int ret; 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci if (is_guest_mode(vcpu)) { 236762306a36Sopenharmony_ci /* Returns '1' or -errno on failure, '0' on success. */ 236862306a36Sopenharmony_ci ret = nested_svm_simple_vmexit(svm, guest_mode_exit_codes[opcode]); 236962306a36Sopenharmony_ci if (ret) 237062306a36Sopenharmony_ci return ret; 237162306a36Sopenharmony_ci return 1; 237262306a36Sopenharmony_ci } 237362306a36Sopenharmony_ci return svm_instr_handlers[opcode](vcpu); 237462306a36Sopenharmony_ci} 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci/* 237762306a36Sopenharmony_ci * #GP handling code. Note that #GP can be triggered under the following two 237862306a36Sopenharmony_ci * cases: 237962306a36Sopenharmony_ci * 1) SVM VM-related instructions (VMRUN/VMSAVE/VMLOAD) that trigger #GP on 238062306a36Sopenharmony_ci * some AMD CPUs when EAX of these instructions are in the reserved memory 238162306a36Sopenharmony_ci * regions (e.g. SMM memory on host). 238262306a36Sopenharmony_ci * 2) VMware backdoor 238362306a36Sopenharmony_ci */ 238462306a36Sopenharmony_cistatic int gp_interception(struct kvm_vcpu *vcpu) 238562306a36Sopenharmony_ci{ 238662306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 238762306a36Sopenharmony_ci u32 error_code = svm->vmcb->control.exit_info_1; 238862306a36Sopenharmony_ci int opcode; 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci /* Both #GP cases have zero error_code */ 239162306a36Sopenharmony_ci if (error_code) 239262306a36Sopenharmony_ci goto reinject; 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_ci /* Decode the instruction for usage later */ 239562306a36Sopenharmony_ci if (x86_decode_emulated_instruction(vcpu, 0, NULL, 0) != EMULATION_OK) 239662306a36Sopenharmony_ci goto reinject; 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_ci opcode = svm_instr_opcode(vcpu); 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci if (opcode == NONE_SVM_INSTR) { 240162306a36Sopenharmony_ci if (!enable_vmware_backdoor) 240262306a36Sopenharmony_ci goto reinject; 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_ci /* 240562306a36Sopenharmony_ci * VMware backdoor emulation on #GP interception only handles 240662306a36Sopenharmony_ci * IN{S}, OUT{S}, and RDPMC. 240762306a36Sopenharmony_ci */ 240862306a36Sopenharmony_ci if (!is_guest_mode(vcpu)) 240962306a36Sopenharmony_ci return kvm_emulate_instruction(vcpu, 241062306a36Sopenharmony_ci EMULTYPE_VMWARE_GP | EMULTYPE_NO_DECODE); 241162306a36Sopenharmony_ci } else { 241262306a36Sopenharmony_ci /* All SVM instructions expect page aligned RAX */ 241362306a36Sopenharmony_ci if (svm->vmcb->save.rax & ~PAGE_MASK) 241462306a36Sopenharmony_ci goto reinject; 241562306a36Sopenharmony_ci 241662306a36Sopenharmony_ci return emulate_svm_instr(vcpu, opcode); 241762306a36Sopenharmony_ci } 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_cireinject: 242062306a36Sopenharmony_ci kvm_queue_exception_e(vcpu, GP_VECTOR, error_code); 242162306a36Sopenharmony_ci return 1; 242262306a36Sopenharmony_ci} 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_civoid svm_set_gif(struct vcpu_svm *svm, bool value) 242562306a36Sopenharmony_ci{ 242662306a36Sopenharmony_ci if (value) { 242762306a36Sopenharmony_ci /* 242862306a36Sopenharmony_ci * If VGIF is enabled, the STGI intercept is only added to 242962306a36Sopenharmony_ci * detect the opening of the SMI/NMI window; remove it now. 243062306a36Sopenharmony_ci * Likewise, clear the VINTR intercept, we will set it 243162306a36Sopenharmony_ci * again while processing KVM_REQ_EVENT if needed. 243262306a36Sopenharmony_ci */ 243362306a36Sopenharmony_ci if (vgif) 243462306a36Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_STGI); 243562306a36Sopenharmony_ci if (svm_is_intercept(svm, INTERCEPT_VINTR)) 243662306a36Sopenharmony_ci svm_clear_vintr(svm); 243762306a36Sopenharmony_ci 243862306a36Sopenharmony_ci enable_gif(svm); 243962306a36Sopenharmony_ci if (svm->vcpu.arch.smi_pending || 244062306a36Sopenharmony_ci svm->vcpu.arch.nmi_pending || 244162306a36Sopenharmony_ci kvm_cpu_has_injectable_intr(&svm->vcpu) || 244262306a36Sopenharmony_ci kvm_apic_has_pending_init_or_sipi(&svm->vcpu)) 244362306a36Sopenharmony_ci kvm_make_request(KVM_REQ_EVENT, &svm->vcpu); 244462306a36Sopenharmony_ci } else { 244562306a36Sopenharmony_ci disable_gif(svm); 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_ci /* 244862306a36Sopenharmony_ci * After a CLGI no interrupts should come. But if vGIF is 244962306a36Sopenharmony_ci * in use, we still rely on the VINTR intercept (rather than 245062306a36Sopenharmony_ci * STGI) to detect an open interrupt window. 245162306a36Sopenharmony_ci */ 245262306a36Sopenharmony_ci if (!vgif) 245362306a36Sopenharmony_ci svm_clear_vintr(svm); 245462306a36Sopenharmony_ci } 245562306a36Sopenharmony_ci} 245662306a36Sopenharmony_ci 245762306a36Sopenharmony_cistatic int stgi_interception(struct kvm_vcpu *vcpu) 245862306a36Sopenharmony_ci{ 245962306a36Sopenharmony_ci int ret; 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_ci if (nested_svm_check_permissions(vcpu)) 246262306a36Sopenharmony_ci return 1; 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_ci ret = kvm_skip_emulated_instruction(vcpu); 246562306a36Sopenharmony_ci svm_set_gif(to_svm(vcpu), true); 246662306a36Sopenharmony_ci return ret; 246762306a36Sopenharmony_ci} 246862306a36Sopenharmony_ci 246962306a36Sopenharmony_cistatic int clgi_interception(struct kvm_vcpu *vcpu) 247062306a36Sopenharmony_ci{ 247162306a36Sopenharmony_ci int ret; 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_ci if (nested_svm_check_permissions(vcpu)) 247462306a36Sopenharmony_ci return 1; 247562306a36Sopenharmony_ci 247662306a36Sopenharmony_ci ret = kvm_skip_emulated_instruction(vcpu); 247762306a36Sopenharmony_ci svm_set_gif(to_svm(vcpu), false); 247862306a36Sopenharmony_ci return ret; 247962306a36Sopenharmony_ci} 248062306a36Sopenharmony_ci 248162306a36Sopenharmony_cistatic int invlpga_interception(struct kvm_vcpu *vcpu) 248262306a36Sopenharmony_ci{ 248362306a36Sopenharmony_ci gva_t gva = kvm_rax_read(vcpu); 248462306a36Sopenharmony_ci u32 asid = kvm_rcx_read(vcpu); 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci /* FIXME: Handle an address size prefix. */ 248762306a36Sopenharmony_ci if (!is_long_mode(vcpu)) 248862306a36Sopenharmony_ci gva = (u32)gva; 248962306a36Sopenharmony_ci 249062306a36Sopenharmony_ci trace_kvm_invlpga(to_svm(vcpu)->vmcb->save.rip, asid, gva); 249162306a36Sopenharmony_ci 249262306a36Sopenharmony_ci /* Let's treat INVLPGA the same as INVLPG (can be optimized!) */ 249362306a36Sopenharmony_ci kvm_mmu_invlpg(vcpu, gva); 249462306a36Sopenharmony_ci 249562306a36Sopenharmony_ci return kvm_skip_emulated_instruction(vcpu); 249662306a36Sopenharmony_ci} 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_cistatic int skinit_interception(struct kvm_vcpu *vcpu) 249962306a36Sopenharmony_ci{ 250062306a36Sopenharmony_ci trace_kvm_skinit(to_svm(vcpu)->vmcb->save.rip, kvm_rax_read(vcpu)); 250162306a36Sopenharmony_ci 250262306a36Sopenharmony_ci kvm_queue_exception(vcpu, UD_VECTOR); 250362306a36Sopenharmony_ci return 1; 250462306a36Sopenharmony_ci} 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_cistatic int task_switch_interception(struct kvm_vcpu *vcpu) 250762306a36Sopenharmony_ci{ 250862306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 250962306a36Sopenharmony_ci u16 tss_selector; 251062306a36Sopenharmony_ci int reason; 251162306a36Sopenharmony_ci int int_type = svm->vmcb->control.exit_int_info & 251262306a36Sopenharmony_ci SVM_EXITINTINFO_TYPE_MASK; 251362306a36Sopenharmony_ci int int_vec = svm->vmcb->control.exit_int_info & SVM_EVTINJ_VEC_MASK; 251462306a36Sopenharmony_ci uint32_t type = 251562306a36Sopenharmony_ci svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_TYPE_MASK; 251662306a36Sopenharmony_ci uint32_t idt_v = 251762306a36Sopenharmony_ci svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_VALID; 251862306a36Sopenharmony_ci bool has_error_code = false; 251962306a36Sopenharmony_ci u32 error_code = 0; 252062306a36Sopenharmony_ci 252162306a36Sopenharmony_ci tss_selector = (u16)svm->vmcb->control.exit_info_1; 252262306a36Sopenharmony_ci 252362306a36Sopenharmony_ci if (svm->vmcb->control.exit_info_2 & 252462306a36Sopenharmony_ci (1ULL << SVM_EXITINFOSHIFT_TS_REASON_IRET)) 252562306a36Sopenharmony_ci reason = TASK_SWITCH_IRET; 252662306a36Sopenharmony_ci else if (svm->vmcb->control.exit_info_2 & 252762306a36Sopenharmony_ci (1ULL << SVM_EXITINFOSHIFT_TS_REASON_JMP)) 252862306a36Sopenharmony_ci reason = TASK_SWITCH_JMP; 252962306a36Sopenharmony_ci else if (idt_v) 253062306a36Sopenharmony_ci reason = TASK_SWITCH_GATE; 253162306a36Sopenharmony_ci else 253262306a36Sopenharmony_ci reason = TASK_SWITCH_CALL; 253362306a36Sopenharmony_ci 253462306a36Sopenharmony_ci if (reason == TASK_SWITCH_GATE) { 253562306a36Sopenharmony_ci switch (type) { 253662306a36Sopenharmony_ci case SVM_EXITINTINFO_TYPE_NMI: 253762306a36Sopenharmony_ci vcpu->arch.nmi_injected = false; 253862306a36Sopenharmony_ci break; 253962306a36Sopenharmony_ci case SVM_EXITINTINFO_TYPE_EXEPT: 254062306a36Sopenharmony_ci if (svm->vmcb->control.exit_info_2 & 254162306a36Sopenharmony_ci (1ULL << SVM_EXITINFOSHIFT_TS_HAS_ERROR_CODE)) { 254262306a36Sopenharmony_ci has_error_code = true; 254362306a36Sopenharmony_ci error_code = 254462306a36Sopenharmony_ci (u32)svm->vmcb->control.exit_info_2; 254562306a36Sopenharmony_ci } 254662306a36Sopenharmony_ci kvm_clear_exception_queue(vcpu); 254762306a36Sopenharmony_ci break; 254862306a36Sopenharmony_ci case SVM_EXITINTINFO_TYPE_INTR: 254962306a36Sopenharmony_ci case SVM_EXITINTINFO_TYPE_SOFT: 255062306a36Sopenharmony_ci kvm_clear_interrupt_queue(vcpu); 255162306a36Sopenharmony_ci break; 255262306a36Sopenharmony_ci default: 255362306a36Sopenharmony_ci break; 255462306a36Sopenharmony_ci } 255562306a36Sopenharmony_ci } 255662306a36Sopenharmony_ci 255762306a36Sopenharmony_ci if (reason != TASK_SWITCH_GATE || 255862306a36Sopenharmony_ci int_type == SVM_EXITINTINFO_TYPE_SOFT || 255962306a36Sopenharmony_ci (int_type == SVM_EXITINTINFO_TYPE_EXEPT && 256062306a36Sopenharmony_ci (int_vec == OF_VECTOR || int_vec == BP_VECTOR))) { 256162306a36Sopenharmony_ci if (!svm_skip_emulated_instruction(vcpu)) 256262306a36Sopenharmony_ci return 0; 256362306a36Sopenharmony_ci } 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci if (int_type != SVM_EXITINTINFO_TYPE_SOFT) 256662306a36Sopenharmony_ci int_vec = -1; 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ci return kvm_task_switch(vcpu, tss_selector, int_vec, reason, 256962306a36Sopenharmony_ci has_error_code, error_code); 257062306a36Sopenharmony_ci} 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_cistatic void svm_clr_iret_intercept(struct vcpu_svm *svm) 257362306a36Sopenharmony_ci{ 257462306a36Sopenharmony_ci if (!sev_es_guest(svm->vcpu.kvm)) 257562306a36Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_IRET); 257662306a36Sopenharmony_ci} 257762306a36Sopenharmony_ci 257862306a36Sopenharmony_cistatic void svm_set_iret_intercept(struct vcpu_svm *svm) 257962306a36Sopenharmony_ci{ 258062306a36Sopenharmony_ci if (!sev_es_guest(svm->vcpu.kvm)) 258162306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_IRET); 258262306a36Sopenharmony_ci} 258362306a36Sopenharmony_ci 258462306a36Sopenharmony_cistatic int iret_interception(struct kvm_vcpu *vcpu) 258562306a36Sopenharmony_ci{ 258662306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci WARN_ON_ONCE(sev_es_guest(vcpu->kvm)); 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_ci ++vcpu->stat.nmi_window_exits; 259162306a36Sopenharmony_ci svm->awaiting_iret_completion = true; 259262306a36Sopenharmony_ci 259362306a36Sopenharmony_ci svm_clr_iret_intercept(svm); 259462306a36Sopenharmony_ci svm->nmi_iret_rip = kvm_rip_read(vcpu); 259562306a36Sopenharmony_ci 259662306a36Sopenharmony_ci kvm_make_request(KVM_REQ_EVENT, vcpu); 259762306a36Sopenharmony_ci return 1; 259862306a36Sopenharmony_ci} 259962306a36Sopenharmony_ci 260062306a36Sopenharmony_cistatic int invlpg_interception(struct kvm_vcpu *vcpu) 260162306a36Sopenharmony_ci{ 260262306a36Sopenharmony_ci if (!static_cpu_has(X86_FEATURE_DECODEASSISTS)) 260362306a36Sopenharmony_ci return kvm_emulate_instruction(vcpu, 0); 260462306a36Sopenharmony_ci 260562306a36Sopenharmony_ci kvm_mmu_invlpg(vcpu, to_svm(vcpu)->vmcb->control.exit_info_1); 260662306a36Sopenharmony_ci return kvm_skip_emulated_instruction(vcpu); 260762306a36Sopenharmony_ci} 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_cistatic int emulate_on_interception(struct kvm_vcpu *vcpu) 261062306a36Sopenharmony_ci{ 261162306a36Sopenharmony_ci return kvm_emulate_instruction(vcpu, 0); 261262306a36Sopenharmony_ci} 261362306a36Sopenharmony_ci 261462306a36Sopenharmony_cistatic int rsm_interception(struct kvm_vcpu *vcpu) 261562306a36Sopenharmony_ci{ 261662306a36Sopenharmony_ci return kvm_emulate_instruction_from_buffer(vcpu, rsm_ins_bytes, 2); 261762306a36Sopenharmony_ci} 261862306a36Sopenharmony_ci 261962306a36Sopenharmony_cistatic bool check_selective_cr0_intercepted(struct kvm_vcpu *vcpu, 262062306a36Sopenharmony_ci unsigned long val) 262162306a36Sopenharmony_ci{ 262262306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 262362306a36Sopenharmony_ci unsigned long cr0 = vcpu->arch.cr0; 262462306a36Sopenharmony_ci bool ret = false; 262562306a36Sopenharmony_ci 262662306a36Sopenharmony_ci if (!is_guest_mode(vcpu) || 262762306a36Sopenharmony_ci (!(vmcb12_is_intercept(&svm->nested.ctl, INTERCEPT_SELECTIVE_CR0)))) 262862306a36Sopenharmony_ci return false; 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_ci cr0 &= ~SVM_CR0_SELECTIVE_MASK; 263162306a36Sopenharmony_ci val &= ~SVM_CR0_SELECTIVE_MASK; 263262306a36Sopenharmony_ci 263362306a36Sopenharmony_ci if (cr0 ^ val) { 263462306a36Sopenharmony_ci svm->vmcb->control.exit_code = SVM_EXIT_CR0_SEL_WRITE; 263562306a36Sopenharmony_ci ret = (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE); 263662306a36Sopenharmony_ci } 263762306a36Sopenharmony_ci 263862306a36Sopenharmony_ci return ret; 263962306a36Sopenharmony_ci} 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci#define CR_VALID (1ULL << 63) 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_cistatic int cr_interception(struct kvm_vcpu *vcpu) 264462306a36Sopenharmony_ci{ 264562306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 264662306a36Sopenharmony_ci int reg, cr; 264762306a36Sopenharmony_ci unsigned long val; 264862306a36Sopenharmony_ci int err; 264962306a36Sopenharmony_ci 265062306a36Sopenharmony_ci if (!static_cpu_has(X86_FEATURE_DECODEASSISTS)) 265162306a36Sopenharmony_ci return emulate_on_interception(vcpu); 265262306a36Sopenharmony_ci 265362306a36Sopenharmony_ci if (unlikely((svm->vmcb->control.exit_info_1 & CR_VALID) == 0)) 265462306a36Sopenharmony_ci return emulate_on_interception(vcpu); 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_ci reg = svm->vmcb->control.exit_info_1 & SVM_EXITINFO_REG_MASK; 265762306a36Sopenharmony_ci if (svm->vmcb->control.exit_code == SVM_EXIT_CR0_SEL_WRITE) 265862306a36Sopenharmony_ci cr = SVM_EXIT_WRITE_CR0 - SVM_EXIT_READ_CR0; 265962306a36Sopenharmony_ci else 266062306a36Sopenharmony_ci cr = svm->vmcb->control.exit_code - SVM_EXIT_READ_CR0; 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_ci err = 0; 266362306a36Sopenharmony_ci if (cr >= 16) { /* mov to cr */ 266462306a36Sopenharmony_ci cr -= 16; 266562306a36Sopenharmony_ci val = kvm_register_read(vcpu, reg); 266662306a36Sopenharmony_ci trace_kvm_cr_write(cr, val); 266762306a36Sopenharmony_ci switch (cr) { 266862306a36Sopenharmony_ci case 0: 266962306a36Sopenharmony_ci if (!check_selective_cr0_intercepted(vcpu, val)) 267062306a36Sopenharmony_ci err = kvm_set_cr0(vcpu, val); 267162306a36Sopenharmony_ci else 267262306a36Sopenharmony_ci return 1; 267362306a36Sopenharmony_ci 267462306a36Sopenharmony_ci break; 267562306a36Sopenharmony_ci case 3: 267662306a36Sopenharmony_ci err = kvm_set_cr3(vcpu, val); 267762306a36Sopenharmony_ci break; 267862306a36Sopenharmony_ci case 4: 267962306a36Sopenharmony_ci err = kvm_set_cr4(vcpu, val); 268062306a36Sopenharmony_ci break; 268162306a36Sopenharmony_ci case 8: 268262306a36Sopenharmony_ci err = kvm_set_cr8(vcpu, val); 268362306a36Sopenharmony_ci break; 268462306a36Sopenharmony_ci default: 268562306a36Sopenharmony_ci WARN(1, "unhandled write to CR%d", cr); 268662306a36Sopenharmony_ci kvm_queue_exception(vcpu, UD_VECTOR); 268762306a36Sopenharmony_ci return 1; 268862306a36Sopenharmony_ci } 268962306a36Sopenharmony_ci } else { /* mov from cr */ 269062306a36Sopenharmony_ci switch (cr) { 269162306a36Sopenharmony_ci case 0: 269262306a36Sopenharmony_ci val = kvm_read_cr0(vcpu); 269362306a36Sopenharmony_ci break; 269462306a36Sopenharmony_ci case 2: 269562306a36Sopenharmony_ci val = vcpu->arch.cr2; 269662306a36Sopenharmony_ci break; 269762306a36Sopenharmony_ci case 3: 269862306a36Sopenharmony_ci val = kvm_read_cr3(vcpu); 269962306a36Sopenharmony_ci break; 270062306a36Sopenharmony_ci case 4: 270162306a36Sopenharmony_ci val = kvm_read_cr4(vcpu); 270262306a36Sopenharmony_ci break; 270362306a36Sopenharmony_ci case 8: 270462306a36Sopenharmony_ci val = kvm_get_cr8(vcpu); 270562306a36Sopenharmony_ci break; 270662306a36Sopenharmony_ci default: 270762306a36Sopenharmony_ci WARN(1, "unhandled read from CR%d", cr); 270862306a36Sopenharmony_ci kvm_queue_exception(vcpu, UD_VECTOR); 270962306a36Sopenharmony_ci return 1; 271062306a36Sopenharmony_ci } 271162306a36Sopenharmony_ci kvm_register_write(vcpu, reg, val); 271262306a36Sopenharmony_ci trace_kvm_cr_read(cr, val); 271362306a36Sopenharmony_ci } 271462306a36Sopenharmony_ci return kvm_complete_insn_gp(vcpu, err); 271562306a36Sopenharmony_ci} 271662306a36Sopenharmony_ci 271762306a36Sopenharmony_cistatic int cr_trap(struct kvm_vcpu *vcpu) 271862306a36Sopenharmony_ci{ 271962306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 272062306a36Sopenharmony_ci unsigned long old_value, new_value; 272162306a36Sopenharmony_ci unsigned int cr; 272262306a36Sopenharmony_ci int ret = 0; 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ci new_value = (unsigned long)svm->vmcb->control.exit_info_1; 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_ci cr = svm->vmcb->control.exit_code - SVM_EXIT_CR0_WRITE_TRAP; 272762306a36Sopenharmony_ci switch (cr) { 272862306a36Sopenharmony_ci case 0: 272962306a36Sopenharmony_ci old_value = kvm_read_cr0(vcpu); 273062306a36Sopenharmony_ci svm_set_cr0(vcpu, new_value); 273162306a36Sopenharmony_ci 273262306a36Sopenharmony_ci kvm_post_set_cr0(vcpu, old_value, new_value); 273362306a36Sopenharmony_ci break; 273462306a36Sopenharmony_ci case 4: 273562306a36Sopenharmony_ci old_value = kvm_read_cr4(vcpu); 273662306a36Sopenharmony_ci svm_set_cr4(vcpu, new_value); 273762306a36Sopenharmony_ci 273862306a36Sopenharmony_ci kvm_post_set_cr4(vcpu, old_value, new_value); 273962306a36Sopenharmony_ci break; 274062306a36Sopenharmony_ci case 8: 274162306a36Sopenharmony_ci ret = kvm_set_cr8(vcpu, new_value); 274262306a36Sopenharmony_ci break; 274362306a36Sopenharmony_ci default: 274462306a36Sopenharmony_ci WARN(1, "unhandled CR%d write trap", cr); 274562306a36Sopenharmony_ci kvm_queue_exception(vcpu, UD_VECTOR); 274662306a36Sopenharmony_ci return 1; 274762306a36Sopenharmony_ci } 274862306a36Sopenharmony_ci 274962306a36Sopenharmony_ci return kvm_complete_insn_gp(vcpu, ret); 275062306a36Sopenharmony_ci} 275162306a36Sopenharmony_ci 275262306a36Sopenharmony_cistatic int dr_interception(struct kvm_vcpu *vcpu) 275362306a36Sopenharmony_ci{ 275462306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 275562306a36Sopenharmony_ci int reg, dr; 275662306a36Sopenharmony_ci unsigned long val; 275762306a36Sopenharmony_ci int err = 0; 275862306a36Sopenharmony_ci 275962306a36Sopenharmony_ci /* 276062306a36Sopenharmony_ci * SEV-ES intercepts DR7 only to disable guest debugging and the guest issues a VMGEXIT 276162306a36Sopenharmony_ci * for DR7 write only. KVM cannot change DR7 (always swapped as type 'A') so return early. 276262306a36Sopenharmony_ci */ 276362306a36Sopenharmony_ci if (sev_es_guest(vcpu->kvm)) 276462306a36Sopenharmony_ci return 1; 276562306a36Sopenharmony_ci 276662306a36Sopenharmony_ci if (vcpu->guest_debug == 0) { 276762306a36Sopenharmony_ci /* 276862306a36Sopenharmony_ci * No more DR vmexits; force a reload of the debug registers 276962306a36Sopenharmony_ci * and reenter on this instruction. The next vmexit will 277062306a36Sopenharmony_ci * retrieve the full state of the debug registers. 277162306a36Sopenharmony_ci */ 277262306a36Sopenharmony_ci clr_dr_intercepts(svm); 277362306a36Sopenharmony_ci vcpu->arch.switch_db_regs |= KVM_DEBUGREG_WONT_EXIT; 277462306a36Sopenharmony_ci return 1; 277562306a36Sopenharmony_ci } 277662306a36Sopenharmony_ci 277762306a36Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_DECODEASSISTS)) 277862306a36Sopenharmony_ci return emulate_on_interception(vcpu); 277962306a36Sopenharmony_ci 278062306a36Sopenharmony_ci reg = svm->vmcb->control.exit_info_1 & SVM_EXITINFO_REG_MASK; 278162306a36Sopenharmony_ci dr = svm->vmcb->control.exit_code - SVM_EXIT_READ_DR0; 278262306a36Sopenharmony_ci if (dr >= 16) { /* mov to DRn */ 278362306a36Sopenharmony_ci dr -= 16; 278462306a36Sopenharmony_ci val = kvm_register_read(vcpu, reg); 278562306a36Sopenharmony_ci err = kvm_set_dr(vcpu, dr, val); 278662306a36Sopenharmony_ci } else { 278762306a36Sopenharmony_ci kvm_get_dr(vcpu, dr, &val); 278862306a36Sopenharmony_ci kvm_register_write(vcpu, reg, val); 278962306a36Sopenharmony_ci } 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_ci return kvm_complete_insn_gp(vcpu, err); 279262306a36Sopenharmony_ci} 279362306a36Sopenharmony_ci 279462306a36Sopenharmony_cistatic int cr8_write_interception(struct kvm_vcpu *vcpu) 279562306a36Sopenharmony_ci{ 279662306a36Sopenharmony_ci int r; 279762306a36Sopenharmony_ci 279862306a36Sopenharmony_ci u8 cr8_prev = kvm_get_cr8(vcpu); 279962306a36Sopenharmony_ci /* instruction emulation calls kvm_set_cr8() */ 280062306a36Sopenharmony_ci r = cr_interception(vcpu); 280162306a36Sopenharmony_ci if (lapic_in_kernel(vcpu)) 280262306a36Sopenharmony_ci return r; 280362306a36Sopenharmony_ci if (cr8_prev <= kvm_get_cr8(vcpu)) 280462306a36Sopenharmony_ci return r; 280562306a36Sopenharmony_ci vcpu->run->exit_reason = KVM_EXIT_SET_TPR; 280662306a36Sopenharmony_ci return 0; 280762306a36Sopenharmony_ci} 280862306a36Sopenharmony_ci 280962306a36Sopenharmony_cistatic int efer_trap(struct kvm_vcpu *vcpu) 281062306a36Sopenharmony_ci{ 281162306a36Sopenharmony_ci struct msr_data msr_info; 281262306a36Sopenharmony_ci int ret; 281362306a36Sopenharmony_ci 281462306a36Sopenharmony_ci /* 281562306a36Sopenharmony_ci * Clear the EFER_SVME bit from EFER. The SVM code always sets this 281662306a36Sopenharmony_ci * bit in svm_set_efer(), but __kvm_valid_efer() checks it against 281762306a36Sopenharmony_ci * whether the guest has X86_FEATURE_SVM - this avoids a failure if 281862306a36Sopenharmony_ci * the guest doesn't have X86_FEATURE_SVM. 281962306a36Sopenharmony_ci */ 282062306a36Sopenharmony_ci msr_info.host_initiated = false; 282162306a36Sopenharmony_ci msr_info.index = MSR_EFER; 282262306a36Sopenharmony_ci msr_info.data = to_svm(vcpu)->vmcb->control.exit_info_1 & ~EFER_SVME; 282362306a36Sopenharmony_ci ret = kvm_set_msr_common(vcpu, &msr_info); 282462306a36Sopenharmony_ci 282562306a36Sopenharmony_ci return kvm_complete_insn_gp(vcpu, ret); 282662306a36Sopenharmony_ci} 282762306a36Sopenharmony_ci 282862306a36Sopenharmony_cistatic int svm_get_msr_feature(struct kvm_msr_entry *msr) 282962306a36Sopenharmony_ci{ 283062306a36Sopenharmony_ci msr->data = 0; 283162306a36Sopenharmony_ci 283262306a36Sopenharmony_ci switch (msr->index) { 283362306a36Sopenharmony_ci case MSR_AMD64_DE_CFG: 283462306a36Sopenharmony_ci if (cpu_feature_enabled(X86_FEATURE_LFENCE_RDTSC)) 283562306a36Sopenharmony_ci msr->data |= MSR_AMD64_DE_CFG_LFENCE_SERIALIZE; 283662306a36Sopenharmony_ci break; 283762306a36Sopenharmony_ci default: 283862306a36Sopenharmony_ci return KVM_MSR_RET_INVALID; 283962306a36Sopenharmony_ci } 284062306a36Sopenharmony_ci 284162306a36Sopenharmony_ci return 0; 284262306a36Sopenharmony_ci} 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_cistatic int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) 284562306a36Sopenharmony_ci{ 284662306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 284762306a36Sopenharmony_ci 284862306a36Sopenharmony_ci switch (msr_info->index) { 284962306a36Sopenharmony_ci case MSR_AMD64_TSC_RATIO: 285062306a36Sopenharmony_ci if (!msr_info->host_initiated && 285162306a36Sopenharmony_ci !guest_can_use(vcpu, X86_FEATURE_TSCRATEMSR)) 285262306a36Sopenharmony_ci return 1; 285362306a36Sopenharmony_ci msr_info->data = svm->tsc_ratio_msr; 285462306a36Sopenharmony_ci break; 285562306a36Sopenharmony_ci case MSR_STAR: 285662306a36Sopenharmony_ci msr_info->data = svm->vmcb01.ptr->save.star; 285762306a36Sopenharmony_ci break; 285862306a36Sopenharmony_ci#ifdef CONFIG_X86_64 285962306a36Sopenharmony_ci case MSR_LSTAR: 286062306a36Sopenharmony_ci msr_info->data = svm->vmcb01.ptr->save.lstar; 286162306a36Sopenharmony_ci break; 286262306a36Sopenharmony_ci case MSR_CSTAR: 286362306a36Sopenharmony_ci msr_info->data = svm->vmcb01.ptr->save.cstar; 286462306a36Sopenharmony_ci break; 286562306a36Sopenharmony_ci case MSR_KERNEL_GS_BASE: 286662306a36Sopenharmony_ci msr_info->data = svm->vmcb01.ptr->save.kernel_gs_base; 286762306a36Sopenharmony_ci break; 286862306a36Sopenharmony_ci case MSR_SYSCALL_MASK: 286962306a36Sopenharmony_ci msr_info->data = svm->vmcb01.ptr->save.sfmask; 287062306a36Sopenharmony_ci break; 287162306a36Sopenharmony_ci#endif 287262306a36Sopenharmony_ci case MSR_IA32_SYSENTER_CS: 287362306a36Sopenharmony_ci msr_info->data = svm->vmcb01.ptr->save.sysenter_cs; 287462306a36Sopenharmony_ci break; 287562306a36Sopenharmony_ci case MSR_IA32_SYSENTER_EIP: 287662306a36Sopenharmony_ci msr_info->data = (u32)svm->vmcb01.ptr->save.sysenter_eip; 287762306a36Sopenharmony_ci if (guest_cpuid_is_intel(vcpu)) 287862306a36Sopenharmony_ci msr_info->data |= (u64)svm->sysenter_eip_hi << 32; 287962306a36Sopenharmony_ci break; 288062306a36Sopenharmony_ci case MSR_IA32_SYSENTER_ESP: 288162306a36Sopenharmony_ci msr_info->data = svm->vmcb01.ptr->save.sysenter_esp; 288262306a36Sopenharmony_ci if (guest_cpuid_is_intel(vcpu)) 288362306a36Sopenharmony_ci msr_info->data |= (u64)svm->sysenter_esp_hi << 32; 288462306a36Sopenharmony_ci break; 288562306a36Sopenharmony_ci case MSR_TSC_AUX: 288662306a36Sopenharmony_ci msr_info->data = svm->tsc_aux; 288762306a36Sopenharmony_ci break; 288862306a36Sopenharmony_ci case MSR_IA32_DEBUGCTLMSR: 288962306a36Sopenharmony_ci msr_info->data = svm_get_lbr_vmcb(svm)->save.dbgctl; 289062306a36Sopenharmony_ci break; 289162306a36Sopenharmony_ci case MSR_IA32_LASTBRANCHFROMIP: 289262306a36Sopenharmony_ci msr_info->data = svm_get_lbr_vmcb(svm)->save.br_from; 289362306a36Sopenharmony_ci break; 289462306a36Sopenharmony_ci case MSR_IA32_LASTBRANCHTOIP: 289562306a36Sopenharmony_ci msr_info->data = svm_get_lbr_vmcb(svm)->save.br_to; 289662306a36Sopenharmony_ci break; 289762306a36Sopenharmony_ci case MSR_IA32_LASTINTFROMIP: 289862306a36Sopenharmony_ci msr_info->data = svm_get_lbr_vmcb(svm)->save.last_excp_from; 289962306a36Sopenharmony_ci break; 290062306a36Sopenharmony_ci case MSR_IA32_LASTINTTOIP: 290162306a36Sopenharmony_ci msr_info->data = svm_get_lbr_vmcb(svm)->save.last_excp_to; 290262306a36Sopenharmony_ci break; 290362306a36Sopenharmony_ci case MSR_VM_HSAVE_PA: 290462306a36Sopenharmony_ci msr_info->data = svm->nested.hsave_msr; 290562306a36Sopenharmony_ci break; 290662306a36Sopenharmony_ci case MSR_VM_CR: 290762306a36Sopenharmony_ci msr_info->data = svm->nested.vm_cr_msr; 290862306a36Sopenharmony_ci break; 290962306a36Sopenharmony_ci case MSR_IA32_SPEC_CTRL: 291062306a36Sopenharmony_ci if (!msr_info->host_initiated && 291162306a36Sopenharmony_ci !guest_has_spec_ctrl_msr(vcpu)) 291262306a36Sopenharmony_ci return 1; 291362306a36Sopenharmony_ci 291462306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_V_SPEC_CTRL)) 291562306a36Sopenharmony_ci msr_info->data = svm->vmcb->save.spec_ctrl; 291662306a36Sopenharmony_ci else 291762306a36Sopenharmony_ci msr_info->data = svm->spec_ctrl; 291862306a36Sopenharmony_ci break; 291962306a36Sopenharmony_ci case MSR_AMD64_VIRT_SPEC_CTRL: 292062306a36Sopenharmony_ci if (!msr_info->host_initiated && 292162306a36Sopenharmony_ci !guest_cpuid_has(vcpu, X86_FEATURE_VIRT_SSBD)) 292262306a36Sopenharmony_ci return 1; 292362306a36Sopenharmony_ci 292462306a36Sopenharmony_ci msr_info->data = svm->virt_spec_ctrl; 292562306a36Sopenharmony_ci break; 292662306a36Sopenharmony_ci case MSR_F15H_IC_CFG: { 292762306a36Sopenharmony_ci 292862306a36Sopenharmony_ci int family, model; 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_ci family = guest_cpuid_family(vcpu); 293162306a36Sopenharmony_ci model = guest_cpuid_model(vcpu); 293262306a36Sopenharmony_ci 293362306a36Sopenharmony_ci if (family < 0 || model < 0) 293462306a36Sopenharmony_ci return kvm_get_msr_common(vcpu, msr_info); 293562306a36Sopenharmony_ci 293662306a36Sopenharmony_ci msr_info->data = 0; 293762306a36Sopenharmony_ci 293862306a36Sopenharmony_ci if (family == 0x15 && 293962306a36Sopenharmony_ci (model >= 0x2 && model < 0x20)) 294062306a36Sopenharmony_ci msr_info->data = 0x1E; 294162306a36Sopenharmony_ci } 294262306a36Sopenharmony_ci break; 294362306a36Sopenharmony_ci case MSR_AMD64_DE_CFG: 294462306a36Sopenharmony_ci msr_info->data = svm->msr_decfg; 294562306a36Sopenharmony_ci break; 294662306a36Sopenharmony_ci default: 294762306a36Sopenharmony_ci return kvm_get_msr_common(vcpu, msr_info); 294862306a36Sopenharmony_ci } 294962306a36Sopenharmony_ci return 0; 295062306a36Sopenharmony_ci} 295162306a36Sopenharmony_ci 295262306a36Sopenharmony_cistatic int svm_complete_emulated_msr(struct kvm_vcpu *vcpu, int err) 295362306a36Sopenharmony_ci{ 295462306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 295562306a36Sopenharmony_ci if (!err || !sev_es_guest(vcpu->kvm) || WARN_ON_ONCE(!svm->sev_es.ghcb)) 295662306a36Sopenharmony_ci return kvm_complete_insn_gp(vcpu, err); 295762306a36Sopenharmony_ci 295862306a36Sopenharmony_ci ghcb_set_sw_exit_info_1(svm->sev_es.ghcb, 1); 295962306a36Sopenharmony_ci ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, 296062306a36Sopenharmony_ci X86_TRAP_GP | 296162306a36Sopenharmony_ci SVM_EVTINJ_TYPE_EXEPT | 296262306a36Sopenharmony_ci SVM_EVTINJ_VALID); 296362306a36Sopenharmony_ci return 1; 296462306a36Sopenharmony_ci} 296562306a36Sopenharmony_ci 296662306a36Sopenharmony_cistatic int svm_set_vm_cr(struct kvm_vcpu *vcpu, u64 data) 296762306a36Sopenharmony_ci{ 296862306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 296962306a36Sopenharmony_ci int svm_dis, chg_mask; 297062306a36Sopenharmony_ci 297162306a36Sopenharmony_ci if (data & ~SVM_VM_CR_VALID_MASK) 297262306a36Sopenharmony_ci return 1; 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_ci chg_mask = SVM_VM_CR_VALID_MASK; 297562306a36Sopenharmony_ci 297662306a36Sopenharmony_ci if (svm->nested.vm_cr_msr & SVM_VM_CR_SVM_DIS_MASK) 297762306a36Sopenharmony_ci chg_mask &= ~(SVM_VM_CR_SVM_LOCK_MASK | SVM_VM_CR_SVM_DIS_MASK); 297862306a36Sopenharmony_ci 297962306a36Sopenharmony_ci svm->nested.vm_cr_msr &= ~chg_mask; 298062306a36Sopenharmony_ci svm->nested.vm_cr_msr |= (data & chg_mask); 298162306a36Sopenharmony_ci 298262306a36Sopenharmony_ci svm_dis = svm->nested.vm_cr_msr & SVM_VM_CR_SVM_DIS_MASK; 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_ci /* check for svm_disable while efer.svme is set */ 298562306a36Sopenharmony_ci if (svm_dis && (vcpu->arch.efer & EFER_SVME)) 298662306a36Sopenharmony_ci return 1; 298762306a36Sopenharmony_ci 298862306a36Sopenharmony_ci return 0; 298962306a36Sopenharmony_ci} 299062306a36Sopenharmony_ci 299162306a36Sopenharmony_cistatic int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) 299262306a36Sopenharmony_ci{ 299362306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 299462306a36Sopenharmony_ci int ret = 0; 299562306a36Sopenharmony_ci 299662306a36Sopenharmony_ci u32 ecx = msr->index; 299762306a36Sopenharmony_ci u64 data = msr->data; 299862306a36Sopenharmony_ci switch (ecx) { 299962306a36Sopenharmony_ci case MSR_AMD64_TSC_RATIO: 300062306a36Sopenharmony_ci 300162306a36Sopenharmony_ci if (!guest_can_use(vcpu, X86_FEATURE_TSCRATEMSR)) { 300262306a36Sopenharmony_ci 300362306a36Sopenharmony_ci if (!msr->host_initiated) 300462306a36Sopenharmony_ci return 1; 300562306a36Sopenharmony_ci /* 300662306a36Sopenharmony_ci * In case TSC scaling is not enabled, always 300762306a36Sopenharmony_ci * leave this MSR at the default value. 300862306a36Sopenharmony_ci * 300962306a36Sopenharmony_ci * Due to bug in qemu 6.2.0, it would try to set 301062306a36Sopenharmony_ci * this msr to 0 if tsc scaling is not enabled. 301162306a36Sopenharmony_ci * Ignore this value as well. 301262306a36Sopenharmony_ci */ 301362306a36Sopenharmony_ci if (data != 0 && data != svm->tsc_ratio_msr) 301462306a36Sopenharmony_ci return 1; 301562306a36Sopenharmony_ci break; 301662306a36Sopenharmony_ci } 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_ci if (data & SVM_TSC_RATIO_RSVD) 301962306a36Sopenharmony_ci return 1; 302062306a36Sopenharmony_ci 302162306a36Sopenharmony_ci svm->tsc_ratio_msr = data; 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_ci if (guest_can_use(vcpu, X86_FEATURE_TSCRATEMSR) && 302462306a36Sopenharmony_ci is_guest_mode(vcpu)) 302562306a36Sopenharmony_ci nested_svm_update_tsc_ratio_msr(vcpu); 302662306a36Sopenharmony_ci 302762306a36Sopenharmony_ci break; 302862306a36Sopenharmony_ci case MSR_IA32_CR_PAT: 302962306a36Sopenharmony_ci ret = kvm_set_msr_common(vcpu, msr); 303062306a36Sopenharmony_ci if (ret) 303162306a36Sopenharmony_ci break; 303262306a36Sopenharmony_ci 303362306a36Sopenharmony_ci svm->vmcb01.ptr->save.g_pat = data; 303462306a36Sopenharmony_ci if (is_guest_mode(vcpu)) 303562306a36Sopenharmony_ci nested_vmcb02_compute_g_pat(svm); 303662306a36Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_NPT); 303762306a36Sopenharmony_ci break; 303862306a36Sopenharmony_ci case MSR_IA32_SPEC_CTRL: 303962306a36Sopenharmony_ci if (!msr->host_initiated && 304062306a36Sopenharmony_ci !guest_has_spec_ctrl_msr(vcpu)) 304162306a36Sopenharmony_ci return 1; 304262306a36Sopenharmony_ci 304362306a36Sopenharmony_ci if (kvm_spec_ctrl_test_value(data)) 304462306a36Sopenharmony_ci return 1; 304562306a36Sopenharmony_ci 304662306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_V_SPEC_CTRL)) 304762306a36Sopenharmony_ci svm->vmcb->save.spec_ctrl = data; 304862306a36Sopenharmony_ci else 304962306a36Sopenharmony_ci svm->spec_ctrl = data; 305062306a36Sopenharmony_ci if (!data) 305162306a36Sopenharmony_ci break; 305262306a36Sopenharmony_ci 305362306a36Sopenharmony_ci /* 305462306a36Sopenharmony_ci * For non-nested: 305562306a36Sopenharmony_ci * When it's written (to non-zero) for the first time, pass 305662306a36Sopenharmony_ci * it through. 305762306a36Sopenharmony_ci * 305862306a36Sopenharmony_ci * For nested: 305962306a36Sopenharmony_ci * The handling of the MSR bitmap for L2 guests is done in 306062306a36Sopenharmony_ci * nested_svm_vmrun_msrpm. 306162306a36Sopenharmony_ci * We update the L1 MSR bit as well since it will end up 306262306a36Sopenharmony_ci * touching the MSR anyway now. 306362306a36Sopenharmony_ci */ 306462306a36Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_SPEC_CTRL, 1, 1); 306562306a36Sopenharmony_ci break; 306662306a36Sopenharmony_ci case MSR_AMD64_VIRT_SPEC_CTRL: 306762306a36Sopenharmony_ci if (!msr->host_initiated && 306862306a36Sopenharmony_ci !guest_cpuid_has(vcpu, X86_FEATURE_VIRT_SSBD)) 306962306a36Sopenharmony_ci return 1; 307062306a36Sopenharmony_ci 307162306a36Sopenharmony_ci if (data & ~SPEC_CTRL_SSBD) 307262306a36Sopenharmony_ci return 1; 307362306a36Sopenharmony_ci 307462306a36Sopenharmony_ci svm->virt_spec_ctrl = data; 307562306a36Sopenharmony_ci break; 307662306a36Sopenharmony_ci case MSR_STAR: 307762306a36Sopenharmony_ci svm->vmcb01.ptr->save.star = data; 307862306a36Sopenharmony_ci break; 307962306a36Sopenharmony_ci#ifdef CONFIG_X86_64 308062306a36Sopenharmony_ci case MSR_LSTAR: 308162306a36Sopenharmony_ci svm->vmcb01.ptr->save.lstar = data; 308262306a36Sopenharmony_ci break; 308362306a36Sopenharmony_ci case MSR_CSTAR: 308462306a36Sopenharmony_ci svm->vmcb01.ptr->save.cstar = data; 308562306a36Sopenharmony_ci break; 308662306a36Sopenharmony_ci case MSR_KERNEL_GS_BASE: 308762306a36Sopenharmony_ci svm->vmcb01.ptr->save.kernel_gs_base = data; 308862306a36Sopenharmony_ci break; 308962306a36Sopenharmony_ci case MSR_SYSCALL_MASK: 309062306a36Sopenharmony_ci svm->vmcb01.ptr->save.sfmask = data; 309162306a36Sopenharmony_ci break; 309262306a36Sopenharmony_ci#endif 309362306a36Sopenharmony_ci case MSR_IA32_SYSENTER_CS: 309462306a36Sopenharmony_ci svm->vmcb01.ptr->save.sysenter_cs = data; 309562306a36Sopenharmony_ci break; 309662306a36Sopenharmony_ci case MSR_IA32_SYSENTER_EIP: 309762306a36Sopenharmony_ci svm->vmcb01.ptr->save.sysenter_eip = (u32)data; 309862306a36Sopenharmony_ci /* 309962306a36Sopenharmony_ci * We only intercept the MSR_IA32_SYSENTER_{EIP|ESP} msrs 310062306a36Sopenharmony_ci * when we spoof an Intel vendor ID (for cross vendor migration). 310162306a36Sopenharmony_ci * In this case we use this intercept to track the high 310262306a36Sopenharmony_ci * 32 bit part of these msrs to support Intel's 310362306a36Sopenharmony_ci * implementation of SYSENTER/SYSEXIT. 310462306a36Sopenharmony_ci */ 310562306a36Sopenharmony_ci svm->sysenter_eip_hi = guest_cpuid_is_intel(vcpu) ? (data >> 32) : 0; 310662306a36Sopenharmony_ci break; 310762306a36Sopenharmony_ci case MSR_IA32_SYSENTER_ESP: 310862306a36Sopenharmony_ci svm->vmcb01.ptr->save.sysenter_esp = (u32)data; 310962306a36Sopenharmony_ci svm->sysenter_esp_hi = guest_cpuid_is_intel(vcpu) ? (data >> 32) : 0; 311062306a36Sopenharmony_ci break; 311162306a36Sopenharmony_ci case MSR_TSC_AUX: 311262306a36Sopenharmony_ci /* 311362306a36Sopenharmony_ci * TSC_AUX is always virtualized for SEV-ES guests when the 311462306a36Sopenharmony_ci * feature is available. The user return MSR support is not 311562306a36Sopenharmony_ci * required in this case because TSC_AUX is restored on #VMEXIT 311662306a36Sopenharmony_ci * from the host save area (which has been initialized in 311762306a36Sopenharmony_ci * svm_hardware_enable()). 311862306a36Sopenharmony_ci */ 311962306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_V_TSC_AUX) && sev_es_guest(vcpu->kvm)) 312062306a36Sopenharmony_ci break; 312162306a36Sopenharmony_ci 312262306a36Sopenharmony_ci /* 312362306a36Sopenharmony_ci * TSC_AUX is usually changed only during boot and never read 312462306a36Sopenharmony_ci * directly. Intercept TSC_AUX instead of exposing it to the 312562306a36Sopenharmony_ci * guest via direct_access_msrs, and switch it via user return. 312662306a36Sopenharmony_ci */ 312762306a36Sopenharmony_ci preempt_disable(); 312862306a36Sopenharmony_ci ret = kvm_set_user_return_msr(tsc_aux_uret_slot, data, -1ull); 312962306a36Sopenharmony_ci preempt_enable(); 313062306a36Sopenharmony_ci if (ret) 313162306a36Sopenharmony_ci break; 313262306a36Sopenharmony_ci 313362306a36Sopenharmony_ci svm->tsc_aux = data; 313462306a36Sopenharmony_ci break; 313562306a36Sopenharmony_ci case MSR_IA32_DEBUGCTLMSR: 313662306a36Sopenharmony_ci if (!lbrv) { 313762306a36Sopenharmony_ci kvm_pr_unimpl_wrmsr(vcpu, ecx, data); 313862306a36Sopenharmony_ci break; 313962306a36Sopenharmony_ci } 314062306a36Sopenharmony_ci if (data & DEBUGCTL_RESERVED_BITS) 314162306a36Sopenharmony_ci return 1; 314262306a36Sopenharmony_ci 314362306a36Sopenharmony_ci svm_get_lbr_vmcb(svm)->save.dbgctl = data; 314462306a36Sopenharmony_ci svm_update_lbrv(vcpu); 314562306a36Sopenharmony_ci break; 314662306a36Sopenharmony_ci case MSR_VM_HSAVE_PA: 314762306a36Sopenharmony_ci /* 314862306a36Sopenharmony_ci * Old kernels did not validate the value written to 314962306a36Sopenharmony_ci * MSR_VM_HSAVE_PA. Allow KVM_SET_MSR to set an invalid 315062306a36Sopenharmony_ci * value to allow live migrating buggy or malicious guests 315162306a36Sopenharmony_ci * originating from those kernels. 315262306a36Sopenharmony_ci */ 315362306a36Sopenharmony_ci if (!msr->host_initiated && !page_address_valid(vcpu, data)) 315462306a36Sopenharmony_ci return 1; 315562306a36Sopenharmony_ci 315662306a36Sopenharmony_ci svm->nested.hsave_msr = data & PAGE_MASK; 315762306a36Sopenharmony_ci break; 315862306a36Sopenharmony_ci case MSR_VM_CR: 315962306a36Sopenharmony_ci return svm_set_vm_cr(vcpu, data); 316062306a36Sopenharmony_ci case MSR_VM_IGNNE: 316162306a36Sopenharmony_ci kvm_pr_unimpl_wrmsr(vcpu, ecx, data); 316262306a36Sopenharmony_ci break; 316362306a36Sopenharmony_ci case MSR_AMD64_DE_CFG: { 316462306a36Sopenharmony_ci struct kvm_msr_entry msr_entry; 316562306a36Sopenharmony_ci 316662306a36Sopenharmony_ci msr_entry.index = msr->index; 316762306a36Sopenharmony_ci if (svm_get_msr_feature(&msr_entry)) 316862306a36Sopenharmony_ci return 1; 316962306a36Sopenharmony_ci 317062306a36Sopenharmony_ci /* Check the supported bits */ 317162306a36Sopenharmony_ci if (data & ~msr_entry.data) 317262306a36Sopenharmony_ci return 1; 317362306a36Sopenharmony_ci 317462306a36Sopenharmony_ci /* Don't allow the guest to change a bit, #GP */ 317562306a36Sopenharmony_ci if (!msr->host_initiated && (data ^ msr_entry.data)) 317662306a36Sopenharmony_ci return 1; 317762306a36Sopenharmony_ci 317862306a36Sopenharmony_ci svm->msr_decfg = data; 317962306a36Sopenharmony_ci break; 318062306a36Sopenharmony_ci } 318162306a36Sopenharmony_ci default: 318262306a36Sopenharmony_ci return kvm_set_msr_common(vcpu, msr); 318362306a36Sopenharmony_ci } 318462306a36Sopenharmony_ci return ret; 318562306a36Sopenharmony_ci} 318662306a36Sopenharmony_ci 318762306a36Sopenharmony_cistatic int msr_interception(struct kvm_vcpu *vcpu) 318862306a36Sopenharmony_ci{ 318962306a36Sopenharmony_ci if (to_svm(vcpu)->vmcb->control.exit_info_1) 319062306a36Sopenharmony_ci return kvm_emulate_wrmsr(vcpu); 319162306a36Sopenharmony_ci else 319262306a36Sopenharmony_ci return kvm_emulate_rdmsr(vcpu); 319362306a36Sopenharmony_ci} 319462306a36Sopenharmony_ci 319562306a36Sopenharmony_cistatic int interrupt_window_interception(struct kvm_vcpu *vcpu) 319662306a36Sopenharmony_ci{ 319762306a36Sopenharmony_ci kvm_make_request(KVM_REQ_EVENT, vcpu); 319862306a36Sopenharmony_ci svm_clear_vintr(to_svm(vcpu)); 319962306a36Sopenharmony_ci 320062306a36Sopenharmony_ci /* 320162306a36Sopenharmony_ci * If not running nested, for AVIC, the only reason to end up here is ExtINTs. 320262306a36Sopenharmony_ci * In this case AVIC was temporarily disabled for 320362306a36Sopenharmony_ci * requesting the IRQ window and we have to re-enable it. 320462306a36Sopenharmony_ci * 320562306a36Sopenharmony_ci * If running nested, still remove the VM wide AVIC inhibit to 320662306a36Sopenharmony_ci * support case in which the interrupt window was requested when the 320762306a36Sopenharmony_ci * vCPU was not running nested. 320862306a36Sopenharmony_ci 320962306a36Sopenharmony_ci * All vCPUs which run still run nested, will remain to have their 321062306a36Sopenharmony_ci * AVIC still inhibited due to per-cpu AVIC inhibition. 321162306a36Sopenharmony_ci */ 321262306a36Sopenharmony_ci kvm_clear_apicv_inhibit(vcpu->kvm, APICV_INHIBIT_REASON_IRQWIN); 321362306a36Sopenharmony_ci 321462306a36Sopenharmony_ci ++vcpu->stat.irq_window_exits; 321562306a36Sopenharmony_ci return 1; 321662306a36Sopenharmony_ci} 321762306a36Sopenharmony_ci 321862306a36Sopenharmony_cistatic int pause_interception(struct kvm_vcpu *vcpu) 321962306a36Sopenharmony_ci{ 322062306a36Sopenharmony_ci bool in_kernel; 322162306a36Sopenharmony_ci /* 322262306a36Sopenharmony_ci * CPL is not made available for an SEV-ES guest, therefore 322362306a36Sopenharmony_ci * vcpu->arch.preempted_in_kernel can never be true. Just 322462306a36Sopenharmony_ci * set in_kernel to false as well. 322562306a36Sopenharmony_ci */ 322662306a36Sopenharmony_ci in_kernel = !sev_es_guest(vcpu->kvm) && svm_get_cpl(vcpu) == 0; 322762306a36Sopenharmony_ci 322862306a36Sopenharmony_ci grow_ple_window(vcpu); 322962306a36Sopenharmony_ci 323062306a36Sopenharmony_ci kvm_vcpu_on_spin(vcpu, in_kernel); 323162306a36Sopenharmony_ci return kvm_skip_emulated_instruction(vcpu); 323262306a36Sopenharmony_ci} 323362306a36Sopenharmony_ci 323462306a36Sopenharmony_cistatic int invpcid_interception(struct kvm_vcpu *vcpu) 323562306a36Sopenharmony_ci{ 323662306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 323762306a36Sopenharmony_ci unsigned long type; 323862306a36Sopenharmony_ci gva_t gva; 323962306a36Sopenharmony_ci 324062306a36Sopenharmony_ci if (!guest_cpuid_has(vcpu, X86_FEATURE_INVPCID)) { 324162306a36Sopenharmony_ci kvm_queue_exception(vcpu, UD_VECTOR); 324262306a36Sopenharmony_ci return 1; 324362306a36Sopenharmony_ci } 324462306a36Sopenharmony_ci 324562306a36Sopenharmony_ci /* 324662306a36Sopenharmony_ci * For an INVPCID intercept: 324762306a36Sopenharmony_ci * EXITINFO1 provides the linear address of the memory operand. 324862306a36Sopenharmony_ci * EXITINFO2 provides the contents of the register operand. 324962306a36Sopenharmony_ci */ 325062306a36Sopenharmony_ci type = svm->vmcb->control.exit_info_2; 325162306a36Sopenharmony_ci gva = svm->vmcb->control.exit_info_1; 325262306a36Sopenharmony_ci 325362306a36Sopenharmony_ci return kvm_handle_invpcid(vcpu, type, gva); 325462306a36Sopenharmony_ci} 325562306a36Sopenharmony_ci 325662306a36Sopenharmony_cistatic int (*const svm_exit_handlers[])(struct kvm_vcpu *vcpu) = { 325762306a36Sopenharmony_ci [SVM_EXIT_READ_CR0] = cr_interception, 325862306a36Sopenharmony_ci [SVM_EXIT_READ_CR3] = cr_interception, 325962306a36Sopenharmony_ci [SVM_EXIT_READ_CR4] = cr_interception, 326062306a36Sopenharmony_ci [SVM_EXIT_READ_CR8] = cr_interception, 326162306a36Sopenharmony_ci [SVM_EXIT_CR0_SEL_WRITE] = cr_interception, 326262306a36Sopenharmony_ci [SVM_EXIT_WRITE_CR0] = cr_interception, 326362306a36Sopenharmony_ci [SVM_EXIT_WRITE_CR3] = cr_interception, 326462306a36Sopenharmony_ci [SVM_EXIT_WRITE_CR4] = cr_interception, 326562306a36Sopenharmony_ci [SVM_EXIT_WRITE_CR8] = cr8_write_interception, 326662306a36Sopenharmony_ci [SVM_EXIT_READ_DR0] = dr_interception, 326762306a36Sopenharmony_ci [SVM_EXIT_READ_DR1] = dr_interception, 326862306a36Sopenharmony_ci [SVM_EXIT_READ_DR2] = dr_interception, 326962306a36Sopenharmony_ci [SVM_EXIT_READ_DR3] = dr_interception, 327062306a36Sopenharmony_ci [SVM_EXIT_READ_DR4] = dr_interception, 327162306a36Sopenharmony_ci [SVM_EXIT_READ_DR5] = dr_interception, 327262306a36Sopenharmony_ci [SVM_EXIT_READ_DR6] = dr_interception, 327362306a36Sopenharmony_ci [SVM_EXIT_READ_DR7] = dr_interception, 327462306a36Sopenharmony_ci [SVM_EXIT_WRITE_DR0] = dr_interception, 327562306a36Sopenharmony_ci [SVM_EXIT_WRITE_DR1] = dr_interception, 327662306a36Sopenharmony_ci [SVM_EXIT_WRITE_DR2] = dr_interception, 327762306a36Sopenharmony_ci [SVM_EXIT_WRITE_DR3] = dr_interception, 327862306a36Sopenharmony_ci [SVM_EXIT_WRITE_DR4] = dr_interception, 327962306a36Sopenharmony_ci [SVM_EXIT_WRITE_DR5] = dr_interception, 328062306a36Sopenharmony_ci [SVM_EXIT_WRITE_DR6] = dr_interception, 328162306a36Sopenharmony_ci [SVM_EXIT_WRITE_DR7] = dr_interception, 328262306a36Sopenharmony_ci [SVM_EXIT_EXCP_BASE + DB_VECTOR] = db_interception, 328362306a36Sopenharmony_ci [SVM_EXIT_EXCP_BASE + BP_VECTOR] = bp_interception, 328462306a36Sopenharmony_ci [SVM_EXIT_EXCP_BASE + UD_VECTOR] = ud_interception, 328562306a36Sopenharmony_ci [SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception, 328662306a36Sopenharmony_ci [SVM_EXIT_EXCP_BASE + MC_VECTOR] = mc_interception, 328762306a36Sopenharmony_ci [SVM_EXIT_EXCP_BASE + AC_VECTOR] = ac_interception, 328862306a36Sopenharmony_ci [SVM_EXIT_EXCP_BASE + GP_VECTOR] = gp_interception, 328962306a36Sopenharmony_ci [SVM_EXIT_INTR] = intr_interception, 329062306a36Sopenharmony_ci [SVM_EXIT_NMI] = nmi_interception, 329162306a36Sopenharmony_ci [SVM_EXIT_SMI] = smi_interception, 329262306a36Sopenharmony_ci [SVM_EXIT_VINTR] = interrupt_window_interception, 329362306a36Sopenharmony_ci [SVM_EXIT_RDPMC] = kvm_emulate_rdpmc, 329462306a36Sopenharmony_ci [SVM_EXIT_CPUID] = kvm_emulate_cpuid, 329562306a36Sopenharmony_ci [SVM_EXIT_IRET] = iret_interception, 329662306a36Sopenharmony_ci [SVM_EXIT_INVD] = kvm_emulate_invd, 329762306a36Sopenharmony_ci [SVM_EXIT_PAUSE] = pause_interception, 329862306a36Sopenharmony_ci [SVM_EXIT_HLT] = kvm_emulate_halt, 329962306a36Sopenharmony_ci [SVM_EXIT_INVLPG] = invlpg_interception, 330062306a36Sopenharmony_ci [SVM_EXIT_INVLPGA] = invlpga_interception, 330162306a36Sopenharmony_ci [SVM_EXIT_IOIO] = io_interception, 330262306a36Sopenharmony_ci [SVM_EXIT_MSR] = msr_interception, 330362306a36Sopenharmony_ci [SVM_EXIT_TASK_SWITCH] = task_switch_interception, 330462306a36Sopenharmony_ci [SVM_EXIT_SHUTDOWN] = shutdown_interception, 330562306a36Sopenharmony_ci [SVM_EXIT_VMRUN] = vmrun_interception, 330662306a36Sopenharmony_ci [SVM_EXIT_VMMCALL] = kvm_emulate_hypercall, 330762306a36Sopenharmony_ci [SVM_EXIT_VMLOAD] = vmload_interception, 330862306a36Sopenharmony_ci [SVM_EXIT_VMSAVE] = vmsave_interception, 330962306a36Sopenharmony_ci [SVM_EXIT_STGI] = stgi_interception, 331062306a36Sopenharmony_ci [SVM_EXIT_CLGI] = clgi_interception, 331162306a36Sopenharmony_ci [SVM_EXIT_SKINIT] = skinit_interception, 331262306a36Sopenharmony_ci [SVM_EXIT_RDTSCP] = kvm_handle_invalid_op, 331362306a36Sopenharmony_ci [SVM_EXIT_WBINVD] = kvm_emulate_wbinvd, 331462306a36Sopenharmony_ci [SVM_EXIT_MONITOR] = kvm_emulate_monitor, 331562306a36Sopenharmony_ci [SVM_EXIT_MWAIT] = kvm_emulate_mwait, 331662306a36Sopenharmony_ci [SVM_EXIT_XSETBV] = kvm_emulate_xsetbv, 331762306a36Sopenharmony_ci [SVM_EXIT_RDPRU] = kvm_handle_invalid_op, 331862306a36Sopenharmony_ci [SVM_EXIT_EFER_WRITE_TRAP] = efer_trap, 331962306a36Sopenharmony_ci [SVM_EXIT_CR0_WRITE_TRAP] = cr_trap, 332062306a36Sopenharmony_ci [SVM_EXIT_CR4_WRITE_TRAP] = cr_trap, 332162306a36Sopenharmony_ci [SVM_EXIT_CR8_WRITE_TRAP] = cr_trap, 332262306a36Sopenharmony_ci [SVM_EXIT_INVPCID] = invpcid_interception, 332362306a36Sopenharmony_ci [SVM_EXIT_NPF] = npf_interception, 332462306a36Sopenharmony_ci [SVM_EXIT_RSM] = rsm_interception, 332562306a36Sopenharmony_ci [SVM_EXIT_AVIC_INCOMPLETE_IPI] = avic_incomplete_ipi_interception, 332662306a36Sopenharmony_ci [SVM_EXIT_AVIC_UNACCELERATED_ACCESS] = avic_unaccelerated_access_interception, 332762306a36Sopenharmony_ci [SVM_EXIT_VMGEXIT] = sev_handle_vmgexit, 332862306a36Sopenharmony_ci}; 332962306a36Sopenharmony_ci 333062306a36Sopenharmony_cistatic void dump_vmcb(struct kvm_vcpu *vcpu) 333162306a36Sopenharmony_ci{ 333262306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 333362306a36Sopenharmony_ci struct vmcb_control_area *control = &svm->vmcb->control; 333462306a36Sopenharmony_ci struct vmcb_save_area *save = &svm->vmcb->save; 333562306a36Sopenharmony_ci struct vmcb_save_area *save01 = &svm->vmcb01.ptr->save; 333662306a36Sopenharmony_ci 333762306a36Sopenharmony_ci if (!dump_invalid_vmcb) { 333862306a36Sopenharmony_ci pr_warn_ratelimited("set kvm_amd.dump_invalid_vmcb=1 to dump internal KVM state.\n"); 333962306a36Sopenharmony_ci return; 334062306a36Sopenharmony_ci } 334162306a36Sopenharmony_ci 334262306a36Sopenharmony_ci pr_err("VMCB %p, last attempted VMRUN on CPU %d\n", 334362306a36Sopenharmony_ci svm->current_vmcb->ptr, vcpu->arch.last_vmentry_cpu); 334462306a36Sopenharmony_ci pr_err("VMCB Control Area:\n"); 334562306a36Sopenharmony_ci pr_err("%-20s%04x\n", "cr_read:", control->intercepts[INTERCEPT_CR] & 0xffff); 334662306a36Sopenharmony_ci pr_err("%-20s%04x\n", "cr_write:", control->intercepts[INTERCEPT_CR] >> 16); 334762306a36Sopenharmony_ci pr_err("%-20s%04x\n", "dr_read:", control->intercepts[INTERCEPT_DR] & 0xffff); 334862306a36Sopenharmony_ci pr_err("%-20s%04x\n", "dr_write:", control->intercepts[INTERCEPT_DR] >> 16); 334962306a36Sopenharmony_ci pr_err("%-20s%08x\n", "exceptions:", control->intercepts[INTERCEPT_EXCEPTION]); 335062306a36Sopenharmony_ci pr_err("%-20s%08x %08x\n", "intercepts:", 335162306a36Sopenharmony_ci control->intercepts[INTERCEPT_WORD3], 335262306a36Sopenharmony_ci control->intercepts[INTERCEPT_WORD4]); 335362306a36Sopenharmony_ci pr_err("%-20s%d\n", "pause filter count:", control->pause_filter_count); 335462306a36Sopenharmony_ci pr_err("%-20s%d\n", "pause filter threshold:", 335562306a36Sopenharmony_ci control->pause_filter_thresh); 335662306a36Sopenharmony_ci pr_err("%-20s%016llx\n", "iopm_base_pa:", control->iopm_base_pa); 335762306a36Sopenharmony_ci pr_err("%-20s%016llx\n", "msrpm_base_pa:", control->msrpm_base_pa); 335862306a36Sopenharmony_ci pr_err("%-20s%016llx\n", "tsc_offset:", control->tsc_offset); 335962306a36Sopenharmony_ci pr_err("%-20s%d\n", "asid:", control->asid); 336062306a36Sopenharmony_ci pr_err("%-20s%d\n", "tlb_ctl:", control->tlb_ctl); 336162306a36Sopenharmony_ci pr_err("%-20s%08x\n", "int_ctl:", control->int_ctl); 336262306a36Sopenharmony_ci pr_err("%-20s%08x\n", "int_vector:", control->int_vector); 336362306a36Sopenharmony_ci pr_err("%-20s%08x\n", "int_state:", control->int_state); 336462306a36Sopenharmony_ci pr_err("%-20s%08x\n", "exit_code:", control->exit_code); 336562306a36Sopenharmony_ci pr_err("%-20s%016llx\n", "exit_info1:", control->exit_info_1); 336662306a36Sopenharmony_ci pr_err("%-20s%016llx\n", "exit_info2:", control->exit_info_2); 336762306a36Sopenharmony_ci pr_err("%-20s%08x\n", "exit_int_info:", control->exit_int_info); 336862306a36Sopenharmony_ci pr_err("%-20s%08x\n", "exit_int_info_err:", control->exit_int_info_err); 336962306a36Sopenharmony_ci pr_err("%-20s%lld\n", "nested_ctl:", control->nested_ctl); 337062306a36Sopenharmony_ci pr_err("%-20s%016llx\n", "nested_cr3:", control->nested_cr3); 337162306a36Sopenharmony_ci pr_err("%-20s%016llx\n", "avic_vapic_bar:", control->avic_vapic_bar); 337262306a36Sopenharmony_ci pr_err("%-20s%016llx\n", "ghcb:", control->ghcb_gpa); 337362306a36Sopenharmony_ci pr_err("%-20s%08x\n", "event_inj:", control->event_inj); 337462306a36Sopenharmony_ci pr_err("%-20s%08x\n", "event_inj_err:", control->event_inj_err); 337562306a36Sopenharmony_ci pr_err("%-20s%lld\n", "virt_ext:", control->virt_ext); 337662306a36Sopenharmony_ci pr_err("%-20s%016llx\n", "next_rip:", control->next_rip); 337762306a36Sopenharmony_ci pr_err("%-20s%016llx\n", "avic_backing_page:", control->avic_backing_page); 337862306a36Sopenharmony_ci pr_err("%-20s%016llx\n", "avic_logical_id:", control->avic_logical_id); 337962306a36Sopenharmony_ci pr_err("%-20s%016llx\n", "avic_physical_id:", control->avic_physical_id); 338062306a36Sopenharmony_ci pr_err("%-20s%016llx\n", "vmsa_pa:", control->vmsa_pa); 338162306a36Sopenharmony_ci pr_err("VMCB State Save Area:\n"); 338262306a36Sopenharmony_ci pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", 338362306a36Sopenharmony_ci "es:", 338462306a36Sopenharmony_ci save->es.selector, save->es.attrib, 338562306a36Sopenharmony_ci save->es.limit, save->es.base); 338662306a36Sopenharmony_ci pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", 338762306a36Sopenharmony_ci "cs:", 338862306a36Sopenharmony_ci save->cs.selector, save->cs.attrib, 338962306a36Sopenharmony_ci save->cs.limit, save->cs.base); 339062306a36Sopenharmony_ci pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", 339162306a36Sopenharmony_ci "ss:", 339262306a36Sopenharmony_ci save->ss.selector, save->ss.attrib, 339362306a36Sopenharmony_ci save->ss.limit, save->ss.base); 339462306a36Sopenharmony_ci pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", 339562306a36Sopenharmony_ci "ds:", 339662306a36Sopenharmony_ci save->ds.selector, save->ds.attrib, 339762306a36Sopenharmony_ci save->ds.limit, save->ds.base); 339862306a36Sopenharmony_ci pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", 339962306a36Sopenharmony_ci "fs:", 340062306a36Sopenharmony_ci save01->fs.selector, save01->fs.attrib, 340162306a36Sopenharmony_ci save01->fs.limit, save01->fs.base); 340262306a36Sopenharmony_ci pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", 340362306a36Sopenharmony_ci "gs:", 340462306a36Sopenharmony_ci save01->gs.selector, save01->gs.attrib, 340562306a36Sopenharmony_ci save01->gs.limit, save01->gs.base); 340662306a36Sopenharmony_ci pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", 340762306a36Sopenharmony_ci "gdtr:", 340862306a36Sopenharmony_ci save->gdtr.selector, save->gdtr.attrib, 340962306a36Sopenharmony_ci save->gdtr.limit, save->gdtr.base); 341062306a36Sopenharmony_ci pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", 341162306a36Sopenharmony_ci "ldtr:", 341262306a36Sopenharmony_ci save01->ldtr.selector, save01->ldtr.attrib, 341362306a36Sopenharmony_ci save01->ldtr.limit, save01->ldtr.base); 341462306a36Sopenharmony_ci pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", 341562306a36Sopenharmony_ci "idtr:", 341662306a36Sopenharmony_ci save->idtr.selector, save->idtr.attrib, 341762306a36Sopenharmony_ci save->idtr.limit, save->idtr.base); 341862306a36Sopenharmony_ci pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", 341962306a36Sopenharmony_ci "tr:", 342062306a36Sopenharmony_ci save01->tr.selector, save01->tr.attrib, 342162306a36Sopenharmony_ci save01->tr.limit, save01->tr.base); 342262306a36Sopenharmony_ci pr_err("vmpl: %d cpl: %d efer: %016llx\n", 342362306a36Sopenharmony_ci save->vmpl, save->cpl, save->efer); 342462306a36Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 342562306a36Sopenharmony_ci "cr0:", save->cr0, "cr2:", save->cr2); 342662306a36Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 342762306a36Sopenharmony_ci "cr3:", save->cr3, "cr4:", save->cr4); 342862306a36Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 342962306a36Sopenharmony_ci "dr6:", save->dr6, "dr7:", save->dr7); 343062306a36Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 343162306a36Sopenharmony_ci "rip:", save->rip, "rflags:", save->rflags); 343262306a36Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 343362306a36Sopenharmony_ci "rsp:", save->rsp, "rax:", save->rax); 343462306a36Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 343562306a36Sopenharmony_ci "star:", save01->star, "lstar:", save01->lstar); 343662306a36Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 343762306a36Sopenharmony_ci "cstar:", save01->cstar, "sfmask:", save01->sfmask); 343862306a36Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 343962306a36Sopenharmony_ci "kernel_gs_base:", save01->kernel_gs_base, 344062306a36Sopenharmony_ci "sysenter_cs:", save01->sysenter_cs); 344162306a36Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 344262306a36Sopenharmony_ci "sysenter_esp:", save01->sysenter_esp, 344362306a36Sopenharmony_ci "sysenter_eip:", save01->sysenter_eip); 344462306a36Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 344562306a36Sopenharmony_ci "gpat:", save->g_pat, "dbgctl:", save->dbgctl); 344662306a36Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 344762306a36Sopenharmony_ci "br_from:", save->br_from, "br_to:", save->br_to); 344862306a36Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 344962306a36Sopenharmony_ci "excp_from:", save->last_excp_from, 345062306a36Sopenharmony_ci "excp_to:", save->last_excp_to); 345162306a36Sopenharmony_ci} 345262306a36Sopenharmony_ci 345362306a36Sopenharmony_cistatic bool svm_check_exit_valid(u64 exit_code) 345462306a36Sopenharmony_ci{ 345562306a36Sopenharmony_ci return (exit_code < ARRAY_SIZE(svm_exit_handlers) && 345662306a36Sopenharmony_ci svm_exit_handlers[exit_code]); 345762306a36Sopenharmony_ci} 345862306a36Sopenharmony_ci 345962306a36Sopenharmony_cistatic int svm_handle_invalid_exit(struct kvm_vcpu *vcpu, u64 exit_code) 346062306a36Sopenharmony_ci{ 346162306a36Sopenharmony_ci vcpu_unimpl(vcpu, "svm: unexpected exit reason 0x%llx\n", exit_code); 346262306a36Sopenharmony_ci dump_vmcb(vcpu); 346362306a36Sopenharmony_ci vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 346462306a36Sopenharmony_ci vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON; 346562306a36Sopenharmony_ci vcpu->run->internal.ndata = 2; 346662306a36Sopenharmony_ci vcpu->run->internal.data[0] = exit_code; 346762306a36Sopenharmony_ci vcpu->run->internal.data[1] = vcpu->arch.last_vmentry_cpu; 346862306a36Sopenharmony_ci return 0; 346962306a36Sopenharmony_ci} 347062306a36Sopenharmony_ci 347162306a36Sopenharmony_ciint svm_invoke_exit_handler(struct kvm_vcpu *vcpu, u64 exit_code) 347262306a36Sopenharmony_ci{ 347362306a36Sopenharmony_ci if (!svm_check_exit_valid(exit_code)) 347462306a36Sopenharmony_ci return svm_handle_invalid_exit(vcpu, exit_code); 347562306a36Sopenharmony_ci 347662306a36Sopenharmony_ci#ifdef CONFIG_RETPOLINE 347762306a36Sopenharmony_ci if (exit_code == SVM_EXIT_MSR) 347862306a36Sopenharmony_ci return msr_interception(vcpu); 347962306a36Sopenharmony_ci else if (exit_code == SVM_EXIT_VINTR) 348062306a36Sopenharmony_ci return interrupt_window_interception(vcpu); 348162306a36Sopenharmony_ci else if (exit_code == SVM_EXIT_INTR) 348262306a36Sopenharmony_ci return intr_interception(vcpu); 348362306a36Sopenharmony_ci else if (exit_code == SVM_EXIT_HLT) 348462306a36Sopenharmony_ci return kvm_emulate_halt(vcpu); 348562306a36Sopenharmony_ci else if (exit_code == SVM_EXIT_NPF) 348662306a36Sopenharmony_ci return npf_interception(vcpu); 348762306a36Sopenharmony_ci#endif 348862306a36Sopenharmony_ci return svm_exit_handlers[exit_code](vcpu); 348962306a36Sopenharmony_ci} 349062306a36Sopenharmony_ci 349162306a36Sopenharmony_cistatic void svm_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason, 349262306a36Sopenharmony_ci u64 *info1, u64 *info2, 349362306a36Sopenharmony_ci u32 *intr_info, u32 *error_code) 349462306a36Sopenharmony_ci{ 349562306a36Sopenharmony_ci struct vmcb_control_area *control = &to_svm(vcpu)->vmcb->control; 349662306a36Sopenharmony_ci 349762306a36Sopenharmony_ci *reason = control->exit_code; 349862306a36Sopenharmony_ci *info1 = control->exit_info_1; 349962306a36Sopenharmony_ci *info2 = control->exit_info_2; 350062306a36Sopenharmony_ci *intr_info = control->exit_int_info; 350162306a36Sopenharmony_ci if ((*intr_info & SVM_EXITINTINFO_VALID) && 350262306a36Sopenharmony_ci (*intr_info & SVM_EXITINTINFO_VALID_ERR)) 350362306a36Sopenharmony_ci *error_code = control->exit_int_info_err; 350462306a36Sopenharmony_ci else 350562306a36Sopenharmony_ci *error_code = 0; 350662306a36Sopenharmony_ci} 350762306a36Sopenharmony_ci 350862306a36Sopenharmony_cistatic int svm_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath) 350962306a36Sopenharmony_ci{ 351062306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 351162306a36Sopenharmony_ci struct kvm_run *kvm_run = vcpu->run; 351262306a36Sopenharmony_ci u32 exit_code = svm->vmcb->control.exit_code; 351362306a36Sopenharmony_ci 351462306a36Sopenharmony_ci /* SEV-ES guests must use the CR write traps to track CR registers. */ 351562306a36Sopenharmony_ci if (!sev_es_guest(vcpu->kvm)) { 351662306a36Sopenharmony_ci if (!svm_is_intercept(svm, INTERCEPT_CR0_WRITE)) 351762306a36Sopenharmony_ci vcpu->arch.cr0 = svm->vmcb->save.cr0; 351862306a36Sopenharmony_ci if (npt_enabled) 351962306a36Sopenharmony_ci vcpu->arch.cr3 = svm->vmcb->save.cr3; 352062306a36Sopenharmony_ci } 352162306a36Sopenharmony_ci 352262306a36Sopenharmony_ci if (is_guest_mode(vcpu)) { 352362306a36Sopenharmony_ci int vmexit; 352462306a36Sopenharmony_ci 352562306a36Sopenharmony_ci trace_kvm_nested_vmexit(vcpu, KVM_ISA_SVM); 352662306a36Sopenharmony_ci 352762306a36Sopenharmony_ci vmexit = nested_svm_exit_special(svm); 352862306a36Sopenharmony_ci 352962306a36Sopenharmony_ci if (vmexit == NESTED_EXIT_CONTINUE) 353062306a36Sopenharmony_ci vmexit = nested_svm_exit_handled(svm); 353162306a36Sopenharmony_ci 353262306a36Sopenharmony_ci if (vmexit == NESTED_EXIT_DONE) 353362306a36Sopenharmony_ci return 1; 353462306a36Sopenharmony_ci } 353562306a36Sopenharmony_ci 353662306a36Sopenharmony_ci if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) { 353762306a36Sopenharmony_ci kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; 353862306a36Sopenharmony_ci kvm_run->fail_entry.hardware_entry_failure_reason 353962306a36Sopenharmony_ci = svm->vmcb->control.exit_code; 354062306a36Sopenharmony_ci kvm_run->fail_entry.cpu = vcpu->arch.last_vmentry_cpu; 354162306a36Sopenharmony_ci dump_vmcb(vcpu); 354262306a36Sopenharmony_ci return 0; 354362306a36Sopenharmony_ci } 354462306a36Sopenharmony_ci 354562306a36Sopenharmony_ci if (exit_fastpath != EXIT_FASTPATH_NONE) 354662306a36Sopenharmony_ci return 1; 354762306a36Sopenharmony_ci 354862306a36Sopenharmony_ci return svm_invoke_exit_handler(vcpu, exit_code); 354962306a36Sopenharmony_ci} 355062306a36Sopenharmony_ci 355162306a36Sopenharmony_cistatic void pre_svm_run(struct kvm_vcpu *vcpu) 355262306a36Sopenharmony_ci{ 355362306a36Sopenharmony_ci struct svm_cpu_data *sd = per_cpu_ptr(&svm_data, vcpu->cpu); 355462306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 355562306a36Sopenharmony_ci 355662306a36Sopenharmony_ci /* 355762306a36Sopenharmony_ci * If the previous vmrun of the vmcb occurred on a different physical 355862306a36Sopenharmony_ci * cpu, then mark the vmcb dirty and assign a new asid. Hardware's 355962306a36Sopenharmony_ci * vmcb clean bits are per logical CPU, as are KVM's asid assignments. 356062306a36Sopenharmony_ci */ 356162306a36Sopenharmony_ci if (unlikely(svm->current_vmcb->cpu != vcpu->cpu)) { 356262306a36Sopenharmony_ci svm->current_vmcb->asid_generation = 0; 356362306a36Sopenharmony_ci vmcb_mark_all_dirty(svm->vmcb); 356462306a36Sopenharmony_ci svm->current_vmcb->cpu = vcpu->cpu; 356562306a36Sopenharmony_ci } 356662306a36Sopenharmony_ci 356762306a36Sopenharmony_ci if (sev_guest(vcpu->kvm)) 356862306a36Sopenharmony_ci return pre_sev_run(svm, vcpu->cpu); 356962306a36Sopenharmony_ci 357062306a36Sopenharmony_ci /* FIXME: handle wraparound of asid_generation */ 357162306a36Sopenharmony_ci if (svm->current_vmcb->asid_generation != sd->asid_generation) 357262306a36Sopenharmony_ci new_asid(svm, sd); 357362306a36Sopenharmony_ci} 357462306a36Sopenharmony_ci 357562306a36Sopenharmony_cistatic void svm_inject_nmi(struct kvm_vcpu *vcpu) 357662306a36Sopenharmony_ci{ 357762306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 357862306a36Sopenharmony_ci 357962306a36Sopenharmony_ci svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_NMI; 358062306a36Sopenharmony_ci 358162306a36Sopenharmony_ci if (svm->nmi_l1_to_l2) 358262306a36Sopenharmony_ci return; 358362306a36Sopenharmony_ci 358462306a36Sopenharmony_ci svm->nmi_masked = true; 358562306a36Sopenharmony_ci svm_set_iret_intercept(svm); 358662306a36Sopenharmony_ci ++vcpu->stat.nmi_injections; 358762306a36Sopenharmony_ci} 358862306a36Sopenharmony_ci 358962306a36Sopenharmony_cistatic bool svm_is_vnmi_pending(struct kvm_vcpu *vcpu) 359062306a36Sopenharmony_ci{ 359162306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 359262306a36Sopenharmony_ci 359362306a36Sopenharmony_ci if (!is_vnmi_enabled(svm)) 359462306a36Sopenharmony_ci return false; 359562306a36Sopenharmony_ci 359662306a36Sopenharmony_ci return !!(svm->vmcb->control.int_ctl & V_NMI_PENDING_MASK); 359762306a36Sopenharmony_ci} 359862306a36Sopenharmony_ci 359962306a36Sopenharmony_cistatic bool svm_set_vnmi_pending(struct kvm_vcpu *vcpu) 360062306a36Sopenharmony_ci{ 360162306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 360262306a36Sopenharmony_ci 360362306a36Sopenharmony_ci if (!is_vnmi_enabled(svm)) 360462306a36Sopenharmony_ci return false; 360562306a36Sopenharmony_ci 360662306a36Sopenharmony_ci if (svm->vmcb->control.int_ctl & V_NMI_PENDING_MASK) 360762306a36Sopenharmony_ci return false; 360862306a36Sopenharmony_ci 360962306a36Sopenharmony_ci svm->vmcb->control.int_ctl |= V_NMI_PENDING_MASK; 361062306a36Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_INTR); 361162306a36Sopenharmony_ci 361262306a36Sopenharmony_ci /* 361362306a36Sopenharmony_ci * Because the pending NMI is serviced by hardware, KVM can't know when 361462306a36Sopenharmony_ci * the NMI is "injected", but for all intents and purposes, passing the 361562306a36Sopenharmony_ci * NMI off to hardware counts as injection. 361662306a36Sopenharmony_ci */ 361762306a36Sopenharmony_ci ++vcpu->stat.nmi_injections; 361862306a36Sopenharmony_ci 361962306a36Sopenharmony_ci return true; 362062306a36Sopenharmony_ci} 362162306a36Sopenharmony_ci 362262306a36Sopenharmony_cistatic void svm_inject_irq(struct kvm_vcpu *vcpu, bool reinjected) 362362306a36Sopenharmony_ci{ 362462306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 362562306a36Sopenharmony_ci u32 type; 362662306a36Sopenharmony_ci 362762306a36Sopenharmony_ci if (vcpu->arch.interrupt.soft) { 362862306a36Sopenharmony_ci if (svm_update_soft_interrupt_rip(vcpu)) 362962306a36Sopenharmony_ci return; 363062306a36Sopenharmony_ci 363162306a36Sopenharmony_ci type = SVM_EVTINJ_TYPE_SOFT; 363262306a36Sopenharmony_ci } else { 363362306a36Sopenharmony_ci type = SVM_EVTINJ_TYPE_INTR; 363462306a36Sopenharmony_ci } 363562306a36Sopenharmony_ci 363662306a36Sopenharmony_ci trace_kvm_inj_virq(vcpu->arch.interrupt.nr, 363762306a36Sopenharmony_ci vcpu->arch.interrupt.soft, reinjected); 363862306a36Sopenharmony_ci ++vcpu->stat.irq_injections; 363962306a36Sopenharmony_ci 364062306a36Sopenharmony_ci svm->vmcb->control.event_inj = vcpu->arch.interrupt.nr | 364162306a36Sopenharmony_ci SVM_EVTINJ_VALID | type; 364262306a36Sopenharmony_ci} 364362306a36Sopenharmony_ci 364462306a36Sopenharmony_civoid svm_complete_interrupt_delivery(struct kvm_vcpu *vcpu, int delivery_mode, 364562306a36Sopenharmony_ci int trig_mode, int vector) 364662306a36Sopenharmony_ci{ 364762306a36Sopenharmony_ci /* 364862306a36Sopenharmony_ci * apic->apicv_active must be read after vcpu->mode. 364962306a36Sopenharmony_ci * Pairs with smp_store_release in vcpu_enter_guest. 365062306a36Sopenharmony_ci */ 365162306a36Sopenharmony_ci bool in_guest_mode = (smp_load_acquire(&vcpu->mode) == IN_GUEST_MODE); 365262306a36Sopenharmony_ci 365362306a36Sopenharmony_ci /* Note, this is called iff the local APIC is in-kernel. */ 365462306a36Sopenharmony_ci if (!READ_ONCE(vcpu->arch.apic->apicv_active)) { 365562306a36Sopenharmony_ci /* Process the interrupt via kvm_check_and_inject_events(). */ 365662306a36Sopenharmony_ci kvm_make_request(KVM_REQ_EVENT, vcpu); 365762306a36Sopenharmony_ci kvm_vcpu_kick(vcpu); 365862306a36Sopenharmony_ci return; 365962306a36Sopenharmony_ci } 366062306a36Sopenharmony_ci 366162306a36Sopenharmony_ci trace_kvm_apicv_accept_irq(vcpu->vcpu_id, delivery_mode, trig_mode, vector); 366262306a36Sopenharmony_ci if (in_guest_mode) { 366362306a36Sopenharmony_ci /* 366462306a36Sopenharmony_ci * Signal the doorbell to tell hardware to inject the IRQ. If 366562306a36Sopenharmony_ci * the vCPU exits the guest before the doorbell chimes, hardware 366662306a36Sopenharmony_ci * will automatically process AVIC interrupts at the next VMRUN. 366762306a36Sopenharmony_ci */ 366862306a36Sopenharmony_ci avic_ring_doorbell(vcpu); 366962306a36Sopenharmony_ci } else { 367062306a36Sopenharmony_ci /* 367162306a36Sopenharmony_ci * Wake the vCPU if it was blocking. KVM will then detect the 367262306a36Sopenharmony_ci * pending IRQ when checking if the vCPU has a wake event. 367362306a36Sopenharmony_ci */ 367462306a36Sopenharmony_ci kvm_vcpu_wake_up(vcpu); 367562306a36Sopenharmony_ci } 367662306a36Sopenharmony_ci} 367762306a36Sopenharmony_ci 367862306a36Sopenharmony_cistatic void svm_deliver_interrupt(struct kvm_lapic *apic, int delivery_mode, 367962306a36Sopenharmony_ci int trig_mode, int vector) 368062306a36Sopenharmony_ci{ 368162306a36Sopenharmony_ci kvm_lapic_set_irr(vector, apic); 368262306a36Sopenharmony_ci 368362306a36Sopenharmony_ci /* 368462306a36Sopenharmony_ci * Pairs with the smp_mb_*() after setting vcpu->guest_mode in 368562306a36Sopenharmony_ci * vcpu_enter_guest() to ensure the write to the vIRR is ordered before 368662306a36Sopenharmony_ci * the read of guest_mode. This guarantees that either VMRUN will see 368762306a36Sopenharmony_ci * and process the new vIRR entry, or that svm_complete_interrupt_delivery 368862306a36Sopenharmony_ci * will signal the doorbell if the CPU has already entered the guest. 368962306a36Sopenharmony_ci */ 369062306a36Sopenharmony_ci smp_mb__after_atomic(); 369162306a36Sopenharmony_ci svm_complete_interrupt_delivery(apic->vcpu, delivery_mode, trig_mode, vector); 369262306a36Sopenharmony_ci} 369362306a36Sopenharmony_ci 369462306a36Sopenharmony_cistatic void svm_update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) 369562306a36Sopenharmony_ci{ 369662306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 369762306a36Sopenharmony_ci 369862306a36Sopenharmony_ci /* 369962306a36Sopenharmony_ci * SEV-ES guests must always keep the CR intercepts cleared. CR 370062306a36Sopenharmony_ci * tracking is done using the CR write traps. 370162306a36Sopenharmony_ci */ 370262306a36Sopenharmony_ci if (sev_es_guest(vcpu->kvm)) 370362306a36Sopenharmony_ci return; 370462306a36Sopenharmony_ci 370562306a36Sopenharmony_ci if (nested_svm_virtualize_tpr(vcpu)) 370662306a36Sopenharmony_ci return; 370762306a36Sopenharmony_ci 370862306a36Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_CR8_WRITE); 370962306a36Sopenharmony_ci 371062306a36Sopenharmony_ci if (irr == -1) 371162306a36Sopenharmony_ci return; 371262306a36Sopenharmony_ci 371362306a36Sopenharmony_ci if (tpr >= irr) 371462306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CR8_WRITE); 371562306a36Sopenharmony_ci} 371662306a36Sopenharmony_ci 371762306a36Sopenharmony_cistatic bool svm_get_nmi_mask(struct kvm_vcpu *vcpu) 371862306a36Sopenharmony_ci{ 371962306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 372062306a36Sopenharmony_ci 372162306a36Sopenharmony_ci if (is_vnmi_enabled(svm)) 372262306a36Sopenharmony_ci return svm->vmcb->control.int_ctl & V_NMI_BLOCKING_MASK; 372362306a36Sopenharmony_ci else 372462306a36Sopenharmony_ci return svm->nmi_masked; 372562306a36Sopenharmony_ci} 372662306a36Sopenharmony_ci 372762306a36Sopenharmony_cistatic void svm_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked) 372862306a36Sopenharmony_ci{ 372962306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 373062306a36Sopenharmony_ci 373162306a36Sopenharmony_ci if (is_vnmi_enabled(svm)) { 373262306a36Sopenharmony_ci if (masked) 373362306a36Sopenharmony_ci svm->vmcb->control.int_ctl |= V_NMI_BLOCKING_MASK; 373462306a36Sopenharmony_ci else 373562306a36Sopenharmony_ci svm->vmcb->control.int_ctl &= ~V_NMI_BLOCKING_MASK; 373662306a36Sopenharmony_ci 373762306a36Sopenharmony_ci } else { 373862306a36Sopenharmony_ci svm->nmi_masked = masked; 373962306a36Sopenharmony_ci if (masked) 374062306a36Sopenharmony_ci svm_set_iret_intercept(svm); 374162306a36Sopenharmony_ci else 374262306a36Sopenharmony_ci svm_clr_iret_intercept(svm); 374362306a36Sopenharmony_ci } 374462306a36Sopenharmony_ci} 374562306a36Sopenharmony_ci 374662306a36Sopenharmony_cibool svm_nmi_blocked(struct kvm_vcpu *vcpu) 374762306a36Sopenharmony_ci{ 374862306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 374962306a36Sopenharmony_ci struct vmcb *vmcb = svm->vmcb; 375062306a36Sopenharmony_ci 375162306a36Sopenharmony_ci if (!gif_set(svm)) 375262306a36Sopenharmony_ci return true; 375362306a36Sopenharmony_ci 375462306a36Sopenharmony_ci if (is_guest_mode(vcpu) && nested_exit_on_nmi(svm)) 375562306a36Sopenharmony_ci return false; 375662306a36Sopenharmony_ci 375762306a36Sopenharmony_ci if (svm_get_nmi_mask(vcpu)) 375862306a36Sopenharmony_ci return true; 375962306a36Sopenharmony_ci 376062306a36Sopenharmony_ci return vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK; 376162306a36Sopenharmony_ci} 376262306a36Sopenharmony_ci 376362306a36Sopenharmony_cistatic int svm_nmi_allowed(struct kvm_vcpu *vcpu, bool for_injection) 376462306a36Sopenharmony_ci{ 376562306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 376662306a36Sopenharmony_ci if (svm->nested.nested_run_pending) 376762306a36Sopenharmony_ci return -EBUSY; 376862306a36Sopenharmony_ci 376962306a36Sopenharmony_ci if (svm_nmi_blocked(vcpu)) 377062306a36Sopenharmony_ci return 0; 377162306a36Sopenharmony_ci 377262306a36Sopenharmony_ci /* An NMI must not be injected into L2 if it's supposed to VM-Exit. */ 377362306a36Sopenharmony_ci if (for_injection && is_guest_mode(vcpu) && nested_exit_on_nmi(svm)) 377462306a36Sopenharmony_ci return -EBUSY; 377562306a36Sopenharmony_ci return 1; 377662306a36Sopenharmony_ci} 377762306a36Sopenharmony_ci 377862306a36Sopenharmony_cibool svm_interrupt_blocked(struct kvm_vcpu *vcpu) 377962306a36Sopenharmony_ci{ 378062306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 378162306a36Sopenharmony_ci struct vmcb *vmcb = svm->vmcb; 378262306a36Sopenharmony_ci 378362306a36Sopenharmony_ci if (!gif_set(svm)) 378462306a36Sopenharmony_ci return true; 378562306a36Sopenharmony_ci 378662306a36Sopenharmony_ci if (is_guest_mode(vcpu)) { 378762306a36Sopenharmony_ci /* As long as interrupts are being delivered... */ 378862306a36Sopenharmony_ci if ((svm->nested.ctl.int_ctl & V_INTR_MASKING_MASK) 378962306a36Sopenharmony_ci ? !(svm->vmcb01.ptr->save.rflags & X86_EFLAGS_IF) 379062306a36Sopenharmony_ci : !(kvm_get_rflags(vcpu) & X86_EFLAGS_IF)) 379162306a36Sopenharmony_ci return true; 379262306a36Sopenharmony_ci 379362306a36Sopenharmony_ci /* ... vmexits aren't blocked by the interrupt shadow */ 379462306a36Sopenharmony_ci if (nested_exit_on_intr(svm)) 379562306a36Sopenharmony_ci return false; 379662306a36Sopenharmony_ci } else { 379762306a36Sopenharmony_ci if (!svm_get_if_flag(vcpu)) 379862306a36Sopenharmony_ci return true; 379962306a36Sopenharmony_ci } 380062306a36Sopenharmony_ci 380162306a36Sopenharmony_ci return (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK); 380262306a36Sopenharmony_ci} 380362306a36Sopenharmony_ci 380462306a36Sopenharmony_cistatic int svm_interrupt_allowed(struct kvm_vcpu *vcpu, bool for_injection) 380562306a36Sopenharmony_ci{ 380662306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 380762306a36Sopenharmony_ci 380862306a36Sopenharmony_ci if (svm->nested.nested_run_pending) 380962306a36Sopenharmony_ci return -EBUSY; 381062306a36Sopenharmony_ci 381162306a36Sopenharmony_ci if (svm_interrupt_blocked(vcpu)) 381262306a36Sopenharmony_ci return 0; 381362306a36Sopenharmony_ci 381462306a36Sopenharmony_ci /* 381562306a36Sopenharmony_ci * An IRQ must not be injected into L2 if it's supposed to VM-Exit, 381662306a36Sopenharmony_ci * e.g. if the IRQ arrived asynchronously after checking nested events. 381762306a36Sopenharmony_ci */ 381862306a36Sopenharmony_ci if (for_injection && is_guest_mode(vcpu) && nested_exit_on_intr(svm)) 381962306a36Sopenharmony_ci return -EBUSY; 382062306a36Sopenharmony_ci 382162306a36Sopenharmony_ci return 1; 382262306a36Sopenharmony_ci} 382362306a36Sopenharmony_ci 382462306a36Sopenharmony_cistatic void svm_enable_irq_window(struct kvm_vcpu *vcpu) 382562306a36Sopenharmony_ci{ 382662306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 382762306a36Sopenharmony_ci 382862306a36Sopenharmony_ci /* 382962306a36Sopenharmony_ci * In case GIF=0 we can't rely on the CPU to tell us when GIF becomes 383062306a36Sopenharmony_ci * 1, because that's a separate STGI/VMRUN intercept. The next time we 383162306a36Sopenharmony_ci * get that intercept, this function will be called again though and 383262306a36Sopenharmony_ci * we'll get the vintr intercept. However, if the vGIF feature is 383362306a36Sopenharmony_ci * enabled, the STGI interception will not occur. Enable the irq 383462306a36Sopenharmony_ci * window under the assumption that the hardware will set the GIF. 383562306a36Sopenharmony_ci */ 383662306a36Sopenharmony_ci if (vgif || gif_set(svm)) { 383762306a36Sopenharmony_ci /* 383862306a36Sopenharmony_ci * IRQ window is not needed when AVIC is enabled, 383962306a36Sopenharmony_ci * unless we have pending ExtINT since it cannot be injected 384062306a36Sopenharmony_ci * via AVIC. In such case, KVM needs to temporarily disable AVIC, 384162306a36Sopenharmony_ci * and fallback to injecting IRQ via V_IRQ. 384262306a36Sopenharmony_ci * 384362306a36Sopenharmony_ci * If running nested, AVIC is already locally inhibited 384462306a36Sopenharmony_ci * on this vCPU, therefore there is no need to request 384562306a36Sopenharmony_ci * the VM wide AVIC inhibition. 384662306a36Sopenharmony_ci */ 384762306a36Sopenharmony_ci if (!is_guest_mode(vcpu)) 384862306a36Sopenharmony_ci kvm_set_apicv_inhibit(vcpu->kvm, APICV_INHIBIT_REASON_IRQWIN); 384962306a36Sopenharmony_ci 385062306a36Sopenharmony_ci svm_set_vintr(svm); 385162306a36Sopenharmony_ci } 385262306a36Sopenharmony_ci} 385362306a36Sopenharmony_ci 385462306a36Sopenharmony_cistatic void svm_enable_nmi_window(struct kvm_vcpu *vcpu) 385562306a36Sopenharmony_ci{ 385662306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 385762306a36Sopenharmony_ci 385862306a36Sopenharmony_ci /* 385962306a36Sopenharmony_ci * KVM should never request an NMI window when vNMI is enabled, as KVM 386062306a36Sopenharmony_ci * allows at most one to-be-injected NMI and one pending NMI, i.e. if 386162306a36Sopenharmony_ci * two NMIs arrive simultaneously, KVM will inject one and set 386262306a36Sopenharmony_ci * V_NMI_PENDING for the other. WARN, but continue with the standard 386362306a36Sopenharmony_ci * single-step approach to try and salvage the pending NMI. 386462306a36Sopenharmony_ci */ 386562306a36Sopenharmony_ci WARN_ON_ONCE(is_vnmi_enabled(svm)); 386662306a36Sopenharmony_ci 386762306a36Sopenharmony_ci if (svm_get_nmi_mask(vcpu) && !svm->awaiting_iret_completion) 386862306a36Sopenharmony_ci return; /* IRET will cause a vm exit */ 386962306a36Sopenharmony_ci 387062306a36Sopenharmony_ci /* 387162306a36Sopenharmony_ci * SEV-ES guests are responsible for signaling when a vCPU is ready to 387262306a36Sopenharmony_ci * receive a new NMI, as SEV-ES guests can't be single-stepped, i.e. 387362306a36Sopenharmony_ci * KVM can't intercept and single-step IRET to detect when NMIs are 387462306a36Sopenharmony_ci * unblocked (architecturally speaking). See SVM_VMGEXIT_NMI_COMPLETE. 387562306a36Sopenharmony_ci * 387662306a36Sopenharmony_ci * Note, GIF is guaranteed to be '1' for SEV-ES guests as hardware 387762306a36Sopenharmony_ci * ignores SEV-ES guest writes to EFER.SVME *and* CLGI/STGI are not 387862306a36Sopenharmony_ci * supported NAEs in the GHCB protocol. 387962306a36Sopenharmony_ci */ 388062306a36Sopenharmony_ci if (sev_es_guest(vcpu->kvm)) 388162306a36Sopenharmony_ci return; 388262306a36Sopenharmony_ci 388362306a36Sopenharmony_ci if (!gif_set(svm)) { 388462306a36Sopenharmony_ci if (vgif) 388562306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_STGI); 388662306a36Sopenharmony_ci return; /* STGI will cause a vm exit */ 388762306a36Sopenharmony_ci } 388862306a36Sopenharmony_ci 388962306a36Sopenharmony_ci /* 389062306a36Sopenharmony_ci * Something prevents NMI from been injected. Single step over possible 389162306a36Sopenharmony_ci * problem (IRET or exception injection or interrupt shadow) 389262306a36Sopenharmony_ci */ 389362306a36Sopenharmony_ci svm->nmi_singlestep_guest_rflags = svm_get_rflags(vcpu); 389462306a36Sopenharmony_ci svm->nmi_singlestep = true; 389562306a36Sopenharmony_ci svm->vmcb->save.rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF); 389662306a36Sopenharmony_ci} 389762306a36Sopenharmony_ci 389862306a36Sopenharmony_cistatic void svm_flush_tlb_asid(struct kvm_vcpu *vcpu) 389962306a36Sopenharmony_ci{ 390062306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 390162306a36Sopenharmony_ci 390262306a36Sopenharmony_ci /* 390362306a36Sopenharmony_ci * Unlike VMX, SVM doesn't provide a way to flush only NPT TLB entries. 390462306a36Sopenharmony_ci * A TLB flush for the current ASID flushes both "host" and "guest" TLB 390562306a36Sopenharmony_ci * entries, and thus is a superset of Hyper-V's fine grained flushing. 390662306a36Sopenharmony_ci */ 390762306a36Sopenharmony_ci kvm_hv_vcpu_purge_flush_tlb(vcpu); 390862306a36Sopenharmony_ci 390962306a36Sopenharmony_ci /* 391062306a36Sopenharmony_ci * Flush only the current ASID even if the TLB flush was invoked via 391162306a36Sopenharmony_ci * kvm_flush_remote_tlbs(). Although flushing remote TLBs requires all 391262306a36Sopenharmony_ci * ASIDs to be flushed, KVM uses a single ASID for L1 and L2, and 391362306a36Sopenharmony_ci * unconditionally does a TLB flush on both nested VM-Enter and nested 391462306a36Sopenharmony_ci * VM-Exit (via kvm_mmu_reset_context()). 391562306a36Sopenharmony_ci */ 391662306a36Sopenharmony_ci if (static_cpu_has(X86_FEATURE_FLUSHBYASID)) 391762306a36Sopenharmony_ci svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ASID; 391862306a36Sopenharmony_ci else 391962306a36Sopenharmony_ci svm->current_vmcb->asid_generation--; 392062306a36Sopenharmony_ci} 392162306a36Sopenharmony_ci 392262306a36Sopenharmony_cistatic void svm_flush_tlb_current(struct kvm_vcpu *vcpu) 392362306a36Sopenharmony_ci{ 392462306a36Sopenharmony_ci hpa_t root_tdp = vcpu->arch.mmu->root.hpa; 392562306a36Sopenharmony_ci 392662306a36Sopenharmony_ci /* 392762306a36Sopenharmony_ci * When running on Hyper-V with EnlightenedNptTlb enabled, explicitly 392862306a36Sopenharmony_ci * flush the NPT mappings via hypercall as flushing the ASID only 392962306a36Sopenharmony_ci * affects virtual to physical mappings, it does not invalidate guest 393062306a36Sopenharmony_ci * physical to host physical mappings. 393162306a36Sopenharmony_ci */ 393262306a36Sopenharmony_ci if (svm_hv_is_enlightened_tlb_enabled(vcpu) && VALID_PAGE(root_tdp)) 393362306a36Sopenharmony_ci hyperv_flush_guest_mapping(root_tdp); 393462306a36Sopenharmony_ci 393562306a36Sopenharmony_ci svm_flush_tlb_asid(vcpu); 393662306a36Sopenharmony_ci} 393762306a36Sopenharmony_ci 393862306a36Sopenharmony_cistatic void svm_flush_tlb_all(struct kvm_vcpu *vcpu) 393962306a36Sopenharmony_ci{ 394062306a36Sopenharmony_ci /* 394162306a36Sopenharmony_ci * When running on Hyper-V with EnlightenedNptTlb enabled, remote TLB 394262306a36Sopenharmony_ci * flushes should be routed to hv_flush_remote_tlbs() without requesting 394362306a36Sopenharmony_ci * a "regular" remote flush. Reaching this point means either there's 394462306a36Sopenharmony_ci * a KVM bug or a prior hv_flush_remote_tlbs() call failed, both of 394562306a36Sopenharmony_ci * which might be fatal to the guest. Yell, but try to recover. 394662306a36Sopenharmony_ci */ 394762306a36Sopenharmony_ci if (WARN_ON_ONCE(svm_hv_is_enlightened_tlb_enabled(vcpu))) 394862306a36Sopenharmony_ci hv_flush_remote_tlbs(vcpu->kvm); 394962306a36Sopenharmony_ci 395062306a36Sopenharmony_ci svm_flush_tlb_asid(vcpu); 395162306a36Sopenharmony_ci} 395262306a36Sopenharmony_ci 395362306a36Sopenharmony_cistatic void svm_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t gva) 395462306a36Sopenharmony_ci{ 395562306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 395662306a36Sopenharmony_ci 395762306a36Sopenharmony_ci invlpga(gva, svm->vmcb->control.asid); 395862306a36Sopenharmony_ci} 395962306a36Sopenharmony_ci 396062306a36Sopenharmony_cistatic inline void sync_cr8_to_lapic(struct kvm_vcpu *vcpu) 396162306a36Sopenharmony_ci{ 396262306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 396362306a36Sopenharmony_ci 396462306a36Sopenharmony_ci if (nested_svm_virtualize_tpr(vcpu)) 396562306a36Sopenharmony_ci return; 396662306a36Sopenharmony_ci 396762306a36Sopenharmony_ci if (!svm_is_intercept(svm, INTERCEPT_CR8_WRITE)) { 396862306a36Sopenharmony_ci int cr8 = svm->vmcb->control.int_ctl & V_TPR_MASK; 396962306a36Sopenharmony_ci kvm_set_cr8(vcpu, cr8); 397062306a36Sopenharmony_ci } 397162306a36Sopenharmony_ci} 397262306a36Sopenharmony_ci 397362306a36Sopenharmony_cistatic inline void sync_lapic_to_cr8(struct kvm_vcpu *vcpu) 397462306a36Sopenharmony_ci{ 397562306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 397662306a36Sopenharmony_ci u64 cr8; 397762306a36Sopenharmony_ci 397862306a36Sopenharmony_ci if (nested_svm_virtualize_tpr(vcpu) || 397962306a36Sopenharmony_ci kvm_vcpu_apicv_active(vcpu)) 398062306a36Sopenharmony_ci return; 398162306a36Sopenharmony_ci 398262306a36Sopenharmony_ci cr8 = kvm_get_cr8(vcpu); 398362306a36Sopenharmony_ci svm->vmcb->control.int_ctl &= ~V_TPR_MASK; 398462306a36Sopenharmony_ci svm->vmcb->control.int_ctl |= cr8 & V_TPR_MASK; 398562306a36Sopenharmony_ci} 398662306a36Sopenharmony_ci 398762306a36Sopenharmony_cistatic void svm_complete_soft_interrupt(struct kvm_vcpu *vcpu, u8 vector, 398862306a36Sopenharmony_ci int type) 398962306a36Sopenharmony_ci{ 399062306a36Sopenharmony_ci bool is_exception = (type == SVM_EXITINTINFO_TYPE_EXEPT); 399162306a36Sopenharmony_ci bool is_soft = (type == SVM_EXITINTINFO_TYPE_SOFT); 399262306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 399362306a36Sopenharmony_ci 399462306a36Sopenharmony_ci /* 399562306a36Sopenharmony_ci * If NRIPS is enabled, KVM must snapshot the pre-VMRUN next_rip that's 399662306a36Sopenharmony_ci * associated with the original soft exception/interrupt. next_rip is 399762306a36Sopenharmony_ci * cleared on all exits that can occur while vectoring an event, so KVM 399862306a36Sopenharmony_ci * needs to manually set next_rip for re-injection. Unlike the !nrips 399962306a36Sopenharmony_ci * case below, this needs to be done if and only if KVM is re-injecting 400062306a36Sopenharmony_ci * the same event, i.e. if the event is a soft exception/interrupt, 400162306a36Sopenharmony_ci * otherwise next_rip is unused on VMRUN. 400262306a36Sopenharmony_ci */ 400362306a36Sopenharmony_ci if (nrips && (is_soft || (is_exception && kvm_exception_is_soft(vector))) && 400462306a36Sopenharmony_ci kvm_is_linear_rip(vcpu, svm->soft_int_old_rip + svm->soft_int_csbase)) 400562306a36Sopenharmony_ci svm->vmcb->control.next_rip = svm->soft_int_next_rip; 400662306a36Sopenharmony_ci /* 400762306a36Sopenharmony_ci * If NRIPS isn't enabled, KVM must manually advance RIP prior to 400862306a36Sopenharmony_ci * injecting the soft exception/interrupt. That advancement needs to 400962306a36Sopenharmony_ci * be unwound if vectoring didn't complete. Note, the new event may 401062306a36Sopenharmony_ci * not be the injected event, e.g. if KVM injected an INTn, the INTn 401162306a36Sopenharmony_ci * hit a #NP in the guest, and the #NP encountered a #PF, the #NP will 401262306a36Sopenharmony_ci * be the reported vectored event, but RIP still needs to be unwound. 401362306a36Sopenharmony_ci */ 401462306a36Sopenharmony_ci else if (!nrips && (is_soft || is_exception) && 401562306a36Sopenharmony_ci kvm_is_linear_rip(vcpu, svm->soft_int_next_rip + svm->soft_int_csbase)) 401662306a36Sopenharmony_ci kvm_rip_write(vcpu, svm->soft_int_old_rip); 401762306a36Sopenharmony_ci} 401862306a36Sopenharmony_ci 401962306a36Sopenharmony_cistatic void svm_complete_interrupts(struct kvm_vcpu *vcpu) 402062306a36Sopenharmony_ci{ 402162306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 402262306a36Sopenharmony_ci u8 vector; 402362306a36Sopenharmony_ci int type; 402462306a36Sopenharmony_ci u32 exitintinfo = svm->vmcb->control.exit_int_info; 402562306a36Sopenharmony_ci bool nmi_l1_to_l2 = svm->nmi_l1_to_l2; 402662306a36Sopenharmony_ci bool soft_int_injected = svm->soft_int_injected; 402762306a36Sopenharmony_ci 402862306a36Sopenharmony_ci svm->nmi_l1_to_l2 = false; 402962306a36Sopenharmony_ci svm->soft_int_injected = false; 403062306a36Sopenharmony_ci 403162306a36Sopenharmony_ci /* 403262306a36Sopenharmony_ci * If we've made progress since setting awaiting_iret_completion, we've 403362306a36Sopenharmony_ci * executed an IRET and can allow NMI injection. 403462306a36Sopenharmony_ci */ 403562306a36Sopenharmony_ci if (svm->awaiting_iret_completion && 403662306a36Sopenharmony_ci kvm_rip_read(vcpu) != svm->nmi_iret_rip) { 403762306a36Sopenharmony_ci svm->awaiting_iret_completion = false; 403862306a36Sopenharmony_ci svm->nmi_masked = false; 403962306a36Sopenharmony_ci kvm_make_request(KVM_REQ_EVENT, vcpu); 404062306a36Sopenharmony_ci } 404162306a36Sopenharmony_ci 404262306a36Sopenharmony_ci vcpu->arch.nmi_injected = false; 404362306a36Sopenharmony_ci kvm_clear_exception_queue(vcpu); 404462306a36Sopenharmony_ci kvm_clear_interrupt_queue(vcpu); 404562306a36Sopenharmony_ci 404662306a36Sopenharmony_ci if (!(exitintinfo & SVM_EXITINTINFO_VALID)) 404762306a36Sopenharmony_ci return; 404862306a36Sopenharmony_ci 404962306a36Sopenharmony_ci kvm_make_request(KVM_REQ_EVENT, vcpu); 405062306a36Sopenharmony_ci 405162306a36Sopenharmony_ci vector = exitintinfo & SVM_EXITINTINFO_VEC_MASK; 405262306a36Sopenharmony_ci type = exitintinfo & SVM_EXITINTINFO_TYPE_MASK; 405362306a36Sopenharmony_ci 405462306a36Sopenharmony_ci if (soft_int_injected) 405562306a36Sopenharmony_ci svm_complete_soft_interrupt(vcpu, vector, type); 405662306a36Sopenharmony_ci 405762306a36Sopenharmony_ci switch (type) { 405862306a36Sopenharmony_ci case SVM_EXITINTINFO_TYPE_NMI: 405962306a36Sopenharmony_ci vcpu->arch.nmi_injected = true; 406062306a36Sopenharmony_ci svm->nmi_l1_to_l2 = nmi_l1_to_l2; 406162306a36Sopenharmony_ci break; 406262306a36Sopenharmony_ci case SVM_EXITINTINFO_TYPE_EXEPT: 406362306a36Sopenharmony_ci /* 406462306a36Sopenharmony_ci * Never re-inject a #VC exception. 406562306a36Sopenharmony_ci */ 406662306a36Sopenharmony_ci if (vector == X86_TRAP_VC) 406762306a36Sopenharmony_ci break; 406862306a36Sopenharmony_ci 406962306a36Sopenharmony_ci if (exitintinfo & SVM_EXITINTINFO_VALID_ERR) { 407062306a36Sopenharmony_ci u32 err = svm->vmcb->control.exit_int_info_err; 407162306a36Sopenharmony_ci kvm_requeue_exception_e(vcpu, vector, err); 407262306a36Sopenharmony_ci 407362306a36Sopenharmony_ci } else 407462306a36Sopenharmony_ci kvm_requeue_exception(vcpu, vector); 407562306a36Sopenharmony_ci break; 407662306a36Sopenharmony_ci case SVM_EXITINTINFO_TYPE_INTR: 407762306a36Sopenharmony_ci kvm_queue_interrupt(vcpu, vector, false); 407862306a36Sopenharmony_ci break; 407962306a36Sopenharmony_ci case SVM_EXITINTINFO_TYPE_SOFT: 408062306a36Sopenharmony_ci kvm_queue_interrupt(vcpu, vector, true); 408162306a36Sopenharmony_ci break; 408262306a36Sopenharmony_ci default: 408362306a36Sopenharmony_ci break; 408462306a36Sopenharmony_ci } 408562306a36Sopenharmony_ci 408662306a36Sopenharmony_ci} 408762306a36Sopenharmony_ci 408862306a36Sopenharmony_cistatic void svm_cancel_injection(struct kvm_vcpu *vcpu) 408962306a36Sopenharmony_ci{ 409062306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 409162306a36Sopenharmony_ci struct vmcb_control_area *control = &svm->vmcb->control; 409262306a36Sopenharmony_ci 409362306a36Sopenharmony_ci control->exit_int_info = control->event_inj; 409462306a36Sopenharmony_ci control->exit_int_info_err = control->event_inj_err; 409562306a36Sopenharmony_ci control->event_inj = 0; 409662306a36Sopenharmony_ci svm_complete_interrupts(vcpu); 409762306a36Sopenharmony_ci} 409862306a36Sopenharmony_ci 409962306a36Sopenharmony_cistatic int svm_vcpu_pre_run(struct kvm_vcpu *vcpu) 410062306a36Sopenharmony_ci{ 410162306a36Sopenharmony_ci return 1; 410262306a36Sopenharmony_ci} 410362306a36Sopenharmony_ci 410462306a36Sopenharmony_cistatic fastpath_t svm_exit_handlers_fastpath(struct kvm_vcpu *vcpu) 410562306a36Sopenharmony_ci{ 410662306a36Sopenharmony_ci if (to_svm(vcpu)->vmcb->control.exit_code == SVM_EXIT_MSR && 410762306a36Sopenharmony_ci to_svm(vcpu)->vmcb->control.exit_info_1) 410862306a36Sopenharmony_ci return handle_fastpath_set_msr_irqoff(vcpu); 410962306a36Sopenharmony_ci 411062306a36Sopenharmony_ci return EXIT_FASTPATH_NONE; 411162306a36Sopenharmony_ci} 411262306a36Sopenharmony_ci 411362306a36Sopenharmony_cistatic noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu, bool spec_ctrl_intercepted) 411462306a36Sopenharmony_ci{ 411562306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 411662306a36Sopenharmony_ci 411762306a36Sopenharmony_ci guest_state_enter_irqoff(); 411862306a36Sopenharmony_ci 411962306a36Sopenharmony_ci amd_clear_divider(); 412062306a36Sopenharmony_ci 412162306a36Sopenharmony_ci if (sev_es_guest(vcpu->kvm)) 412262306a36Sopenharmony_ci __svm_sev_es_vcpu_run(svm, spec_ctrl_intercepted); 412362306a36Sopenharmony_ci else 412462306a36Sopenharmony_ci __svm_vcpu_run(svm, spec_ctrl_intercepted); 412562306a36Sopenharmony_ci 412662306a36Sopenharmony_ci guest_state_exit_irqoff(); 412762306a36Sopenharmony_ci} 412862306a36Sopenharmony_ci 412962306a36Sopenharmony_cistatic __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu) 413062306a36Sopenharmony_ci{ 413162306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 413262306a36Sopenharmony_ci bool spec_ctrl_intercepted = msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL); 413362306a36Sopenharmony_ci 413462306a36Sopenharmony_ci trace_kvm_entry(vcpu); 413562306a36Sopenharmony_ci 413662306a36Sopenharmony_ci svm->vmcb->save.rax = vcpu->arch.regs[VCPU_REGS_RAX]; 413762306a36Sopenharmony_ci svm->vmcb->save.rsp = vcpu->arch.regs[VCPU_REGS_RSP]; 413862306a36Sopenharmony_ci svm->vmcb->save.rip = vcpu->arch.regs[VCPU_REGS_RIP]; 413962306a36Sopenharmony_ci 414062306a36Sopenharmony_ci /* 414162306a36Sopenharmony_ci * Disable singlestep if we're injecting an interrupt/exception. 414262306a36Sopenharmony_ci * We don't want our modified rflags to be pushed on the stack where 414362306a36Sopenharmony_ci * we might not be able to easily reset them if we disabled NMI 414462306a36Sopenharmony_ci * singlestep later. 414562306a36Sopenharmony_ci */ 414662306a36Sopenharmony_ci if (svm->nmi_singlestep && svm->vmcb->control.event_inj) { 414762306a36Sopenharmony_ci /* 414862306a36Sopenharmony_ci * Event injection happens before external interrupts cause a 414962306a36Sopenharmony_ci * vmexit and interrupts are disabled here, so smp_send_reschedule 415062306a36Sopenharmony_ci * is enough to force an immediate vmexit. 415162306a36Sopenharmony_ci */ 415262306a36Sopenharmony_ci disable_nmi_singlestep(svm); 415362306a36Sopenharmony_ci smp_send_reschedule(vcpu->cpu); 415462306a36Sopenharmony_ci } 415562306a36Sopenharmony_ci 415662306a36Sopenharmony_ci pre_svm_run(vcpu); 415762306a36Sopenharmony_ci 415862306a36Sopenharmony_ci sync_lapic_to_cr8(vcpu); 415962306a36Sopenharmony_ci 416062306a36Sopenharmony_ci if (unlikely(svm->asid != svm->vmcb->control.asid)) { 416162306a36Sopenharmony_ci svm->vmcb->control.asid = svm->asid; 416262306a36Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_ASID); 416362306a36Sopenharmony_ci } 416462306a36Sopenharmony_ci svm->vmcb->save.cr2 = vcpu->arch.cr2; 416562306a36Sopenharmony_ci 416662306a36Sopenharmony_ci svm_hv_update_vp_id(svm->vmcb, vcpu); 416762306a36Sopenharmony_ci 416862306a36Sopenharmony_ci /* 416962306a36Sopenharmony_ci * Run with all-zero DR6 unless needed, so that we can get the exact cause 417062306a36Sopenharmony_ci * of a #DB. 417162306a36Sopenharmony_ci */ 417262306a36Sopenharmony_ci if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)) 417362306a36Sopenharmony_ci svm_set_dr6(svm, vcpu->arch.dr6); 417462306a36Sopenharmony_ci else 417562306a36Sopenharmony_ci svm_set_dr6(svm, DR6_ACTIVE_LOW); 417662306a36Sopenharmony_ci 417762306a36Sopenharmony_ci clgi(); 417862306a36Sopenharmony_ci kvm_load_guest_xsave_state(vcpu); 417962306a36Sopenharmony_ci 418062306a36Sopenharmony_ci kvm_wait_lapic_expire(vcpu); 418162306a36Sopenharmony_ci 418262306a36Sopenharmony_ci /* 418362306a36Sopenharmony_ci * If this vCPU has touched SPEC_CTRL, restore the guest's value if 418462306a36Sopenharmony_ci * it's non-zero. Since vmentry is serialising on affected CPUs, there 418562306a36Sopenharmony_ci * is no need to worry about the conditional branch over the wrmsr 418662306a36Sopenharmony_ci * being speculatively taken. 418762306a36Sopenharmony_ci */ 418862306a36Sopenharmony_ci if (!static_cpu_has(X86_FEATURE_V_SPEC_CTRL)) 418962306a36Sopenharmony_ci x86_spec_ctrl_set_guest(svm->virt_spec_ctrl); 419062306a36Sopenharmony_ci 419162306a36Sopenharmony_ci svm_vcpu_enter_exit(vcpu, spec_ctrl_intercepted); 419262306a36Sopenharmony_ci 419362306a36Sopenharmony_ci if (!static_cpu_has(X86_FEATURE_V_SPEC_CTRL)) 419462306a36Sopenharmony_ci x86_spec_ctrl_restore_host(svm->virt_spec_ctrl); 419562306a36Sopenharmony_ci 419662306a36Sopenharmony_ci if (!sev_es_guest(vcpu->kvm)) { 419762306a36Sopenharmony_ci vcpu->arch.cr2 = svm->vmcb->save.cr2; 419862306a36Sopenharmony_ci vcpu->arch.regs[VCPU_REGS_RAX] = svm->vmcb->save.rax; 419962306a36Sopenharmony_ci vcpu->arch.regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp; 420062306a36Sopenharmony_ci vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip; 420162306a36Sopenharmony_ci } 420262306a36Sopenharmony_ci vcpu->arch.regs_dirty = 0; 420362306a36Sopenharmony_ci 420462306a36Sopenharmony_ci if (unlikely(svm->vmcb->control.exit_code == SVM_EXIT_NMI)) 420562306a36Sopenharmony_ci kvm_before_interrupt(vcpu, KVM_HANDLING_NMI); 420662306a36Sopenharmony_ci 420762306a36Sopenharmony_ci kvm_load_host_xsave_state(vcpu); 420862306a36Sopenharmony_ci stgi(); 420962306a36Sopenharmony_ci 421062306a36Sopenharmony_ci /* Any pending NMI will happen here */ 421162306a36Sopenharmony_ci 421262306a36Sopenharmony_ci if (unlikely(svm->vmcb->control.exit_code == SVM_EXIT_NMI)) 421362306a36Sopenharmony_ci kvm_after_interrupt(vcpu); 421462306a36Sopenharmony_ci 421562306a36Sopenharmony_ci sync_cr8_to_lapic(vcpu); 421662306a36Sopenharmony_ci 421762306a36Sopenharmony_ci svm->next_rip = 0; 421862306a36Sopenharmony_ci if (is_guest_mode(vcpu)) { 421962306a36Sopenharmony_ci nested_sync_control_from_vmcb02(svm); 422062306a36Sopenharmony_ci 422162306a36Sopenharmony_ci /* Track VMRUNs that have made past consistency checking */ 422262306a36Sopenharmony_ci if (svm->nested.nested_run_pending && 422362306a36Sopenharmony_ci svm->vmcb->control.exit_code != SVM_EXIT_ERR) 422462306a36Sopenharmony_ci ++vcpu->stat.nested_run; 422562306a36Sopenharmony_ci 422662306a36Sopenharmony_ci svm->nested.nested_run_pending = 0; 422762306a36Sopenharmony_ci } 422862306a36Sopenharmony_ci 422962306a36Sopenharmony_ci svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING; 423062306a36Sopenharmony_ci vmcb_mark_all_clean(svm->vmcb); 423162306a36Sopenharmony_ci 423262306a36Sopenharmony_ci /* if exit due to PF check for async PF */ 423362306a36Sopenharmony_ci if (svm->vmcb->control.exit_code == SVM_EXIT_EXCP_BASE + PF_VECTOR) 423462306a36Sopenharmony_ci vcpu->arch.apf.host_apf_flags = 423562306a36Sopenharmony_ci kvm_read_and_reset_apf_flags(); 423662306a36Sopenharmony_ci 423762306a36Sopenharmony_ci vcpu->arch.regs_avail &= ~SVM_REGS_LAZY_LOAD_SET; 423862306a36Sopenharmony_ci 423962306a36Sopenharmony_ci /* 424062306a36Sopenharmony_ci * We need to handle MC intercepts here before the vcpu has a chance to 424162306a36Sopenharmony_ci * change the physical cpu 424262306a36Sopenharmony_ci */ 424362306a36Sopenharmony_ci if (unlikely(svm->vmcb->control.exit_code == 424462306a36Sopenharmony_ci SVM_EXIT_EXCP_BASE + MC_VECTOR)) 424562306a36Sopenharmony_ci svm_handle_mce(vcpu); 424662306a36Sopenharmony_ci 424762306a36Sopenharmony_ci trace_kvm_exit(vcpu, KVM_ISA_SVM); 424862306a36Sopenharmony_ci 424962306a36Sopenharmony_ci svm_complete_interrupts(vcpu); 425062306a36Sopenharmony_ci 425162306a36Sopenharmony_ci if (is_guest_mode(vcpu)) 425262306a36Sopenharmony_ci return EXIT_FASTPATH_NONE; 425362306a36Sopenharmony_ci 425462306a36Sopenharmony_ci return svm_exit_handlers_fastpath(vcpu); 425562306a36Sopenharmony_ci} 425662306a36Sopenharmony_ci 425762306a36Sopenharmony_cistatic void svm_load_mmu_pgd(struct kvm_vcpu *vcpu, hpa_t root_hpa, 425862306a36Sopenharmony_ci int root_level) 425962306a36Sopenharmony_ci{ 426062306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 426162306a36Sopenharmony_ci unsigned long cr3; 426262306a36Sopenharmony_ci 426362306a36Sopenharmony_ci if (npt_enabled) { 426462306a36Sopenharmony_ci svm->vmcb->control.nested_cr3 = __sme_set(root_hpa); 426562306a36Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_NPT); 426662306a36Sopenharmony_ci 426762306a36Sopenharmony_ci hv_track_root_tdp(vcpu, root_hpa); 426862306a36Sopenharmony_ci 426962306a36Sopenharmony_ci cr3 = vcpu->arch.cr3; 427062306a36Sopenharmony_ci } else if (root_level >= PT64_ROOT_4LEVEL) { 427162306a36Sopenharmony_ci cr3 = __sme_set(root_hpa) | kvm_get_active_pcid(vcpu); 427262306a36Sopenharmony_ci } else { 427362306a36Sopenharmony_ci /* PCID in the guest should be impossible with a 32-bit MMU. */ 427462306a36Sopenharmony_ci WARN_ON_ONCE(kvm_get_active_pcid(vcpu)); 427562306a36Sopenharmony_ci cr3 = root_hpa; 427662306a36Sopenharmony_ci } 427762306a36Sopenharmony_ci 427862306a36Sopenharmony_ci svm->vmcb->save.cr3 = cr3; 427962306a36Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_CR); 428062306a36Sopenharmony_ci} 428162306a36Sopenharmony_ci 428262306a36Sopenharmony_cistatic void 428362306a36Sopenharmony_cisvm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) 428462306a36Sopenharmony_ci{ 428562306a36Sopenharmony_ci /* 428662306a36Sopenharmony_ci * Patch in the VMMCALL instruction: 428762306a36Sopenharmony_ci */ 428862306a36Sopenharmony_ci hypercall[0] = 0x0f; 428962306a36Sopenharmony_ci hypercall[1] = 0x01; 429062306a36Sopenharmony_ci hypercall[2] = 0xd9; 429162306a36Sopenharmony_ci} 429262306a36Sopenharmony_ci 429362306a36Sopenharmony_ci/* 429462306a36Sopenharmony_ci * The kvm parameter can be NULL (module initialization, or invocation before 429562306a36Sopenharmony_ci * VM creation). Be sure to check the kvm parameter before using it. 429662306a36Sopenharmony_ci */ 429762306a36Sopenharmony_cistatic bool svm_has_emulated_msr(struct kvm *kvm, u32 index) 429862306a36Sopenharmony_ci{ 429962306a36Sopenharmony_ci switch (index) { 430062306a36Sopenharmony_ci case MSR_IA32_MCG_EXT_CTL: 430162306a36Sopenharmony_ci case KVM_FIRST_EMULATED_VMX_MSR ... KVM_LAST_EMULATED_VMX_MSR: 430262306a36Sopenharmony_ci return false; 430362306a36Sopenharmony_ci case MSR_IA32_SMBASE: 430462306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_KVM_SMM)) 430562306a36Sopenharmony_ci return false; 430662306a36Sopenharmony_ci /* SEV-ES guests do not support SMM, so report false */ 430762306a36Sopenharmony_ci if (kvm && sev_es_guest(kvm)) 430862306a36Sopenharmony_ci return false; 430962306a36Sopenharmony_ci break; 431062306a36Sopenharmony_ci default: 431162306a36Sopenharmony_ci break; 431262306a36Sopenharmony_ci } 431362306a36Sopenharmony_ci 431462306a36Sopenharmony_ci return true; 431562306a36Sopenharmony_ci} 431662306a36Sopenharmony_ci 431762306a36Sopenharmony_cistatic void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) 431862306a36Sopenharmony_ci{ 431962306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 432062306a36Sopenharmony_ci 432162306a36Sopenharmony_ci /* 432262306a36Sopenharmony_ci * SVM doesn't provide a way to disable just XSAVES in the guest, KVM 432362306a36Sopenharmony_ci * can only disable all variants of by disallowing CR4.OSXSAVE from 432462306a36Sopenharmony_ci * being set. As a result, if the host has XSAVE and XSAVES, and the 432562306a36Sopenharmony_ci * guest has XSAVE enabled, the guest can execute XSAVES without 432662306a36Sopenharmony_ci * faulting. Treat XSAVES as enabled in this case regardless of 432762306a36Sopenharmony_ci * whether it's advertised to the guest so that KVM context switches 432862306a36Sopenharmony_ci * XSS on VM-Enter/VM-Exit. Failure to do so would effectively give 432962306a36Sopenharmony_ci * the guest read/write access to the host's XSS. 433062306a36Sopenharmony_ci */ 433162306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_XSAVE) && 433262306a36Sopenharmony_ci boot_cpu_has(X86_FEATURE_XSAVES) && 433362306a36Sopenharmony_ci guest_cpuid_has(vcpu, X86_FEATURE_XSAVE)) 433462306a36Sopenharmony_ci kvm_governed_feature_set(vcpu, X86_FEATURE_XSAVES); 433562306a36Sopenharmony_ci 433662306a36Sopenharmony_ci kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_NRIPS); 433762306a36Sopenharmony_ci kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_TSCRATEMSR); 433862306a36Sopenharmony_ci kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_LBRV); 433962306a36Sopenharmony_ci 434062306a36Sopenharmony_ci /* 434162306a36Sopenharmony_ci * Intercept VMLOAD if the vCPU mode is Intel in order to emulate that 434262306a36Sopenharmony_ci * VMLOAD drops bits 63:32 of SYSENTER (ignoring the fact that exposing 434362306a36Sopenharmony_ci * SVM on Intel is bonkers and extremely unlikely to work). 434462306a36Sopenharmony_ci */ 434562306a36Sopenharmony_ci if (!guest_cpuid_is_intel(vcpu)) 434662306a36Sopenharmony_ci kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_V_VMSAVE_VMLOAD); 434762306a36Sopenharmony_ci 434862306a36Sopenharmony_ci kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_PAUSEFILTER); 434962306a36Sopenharmony_ci kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_PFTHRESHOLD); 435062306a36Sopenharmony_ci kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_VGIF); 435162306a36Sopenharmony_ci kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_VNMI); 435262306a36Sopenharmony_ci 435362306a36Sopenharmony_ci svm_recalc_instruction_intercepts(vcpu, svm); 435462306a36Sopenharmony_ci 435562306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_IBPB)) 435662306a36Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_PRED_CMD, 0, 435762306a36Sopenharmony_ci !!guest_has_pred_cmd_msr(vcpu)); 435862306a36Sopenharmony_ci 435962306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_FLUSH_L1D)) 436062306a36Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_FLUSH_CMD, 0, 436162306a36Sopenharmony_ci !!guest_cpuid_has(vcpu, X86_FEATURE_FLUSH_L1D)); 436262306a36Sopenharmony_ci 436362306a36Sopenharmony_ci if (sev_guest(vcpu->kvm)) 436462306a36Sopenharmony_ci sev_vcpu_after_set_cpuid(svm); 436562306a36Sopenharmony_ci 436662306a36Sopenharmony_ci init_vmcb_after_set_cpuid(vcpu); 436762306a36Sopenharmony_ci} 436862306a36Sopenharmony_ci 436962306a36Sopenharmony_cistatic bool svm_has_wbinvd_exit(void) 437062306a36Sopenharmony_ci{ 437162306a36Sopenharmony_ci return true; 437262306a36Sopenharmony_ci} 437362306a36Sopenharmony_ci 437462306a36Sopenharmony_ci#define PRE_EX(exit) { .exit_code = (exit), \ 437562306a36Sopenharmony_ci .stage = X86_ICPT_PRE_EXCEPT, } 437662306a36Sopenharmony_ci#define POST_EX(exit) { .exit_code = (exit), \ 437762306a36Sopenharmony_ci .stage = X86_ICPT_POST_EXCEPT, } 437862306a36Sopenharmony_ci#define POST_MEM(exit) { .exit_code = (exit), \ 437962306a36Sopenharmony_ci .stage = X86_ICPT_POST_MEMACCESS, } 438062306a36Sopenharmony_ci 438162306a36Sopenharmony_cistatic const struct __x86_intercept { 438262306a36Sopenharmony_ci u32 exit_code; 438362306a36Sopenharmony_ci enum x86_intercept_stage stage; 438462306a36Sopenharmony_ci} x86_intercept_map[] = { 438562306a36Sopenharmony_ci [x86_intercept_cr_read] = POST_EX(SVM_EXIT_READ_CR0), 438662306a36Sopenharmony_ci [x86_intercept_cr_write] = POST_EX(SVM_EXIT_WRITE_CR0), 438762306a36Sopenharmony_ci [x86_intercept_clts] = POST_EX(SVM_EXIT_WRITE_CR0), 438862306a36Sopenharmony_ci [x86_intercept_lmsw] = POST_EX(SVM_EXIT_WRITE_CR0), 438962306a36Sopenharmony_ci [x86_intercept_smsw] = POST_EX(SVM_EXIT_READ_CR0), 439062306a36Sopenharmony_ci [x86_intercept_dr_read] = POST_EX(SVM_EXIT_READ_DR0), 439162306a36Sopenharmony_ci [x86_intercept_dr_write] = POST_EX(SVM_EXIT_WRITE_DR0), 439262306a36Sopenharmony_ci [x86_intercept_sldt] = POST_EX(SVM_EXIT_LDTR_READ), 439362306a36Sopenharmony_ci [x86_intercept_str] = POST_EX(SVM_EXIT_TR_READ), 439462306a36Sopenharmony_ci [x86_intercept_lldt] = POST_EX(SVM_EXIT_LDTR_WRITE), 439562306a36Sopenharmony_ci [x86_intercept_ltr] = POST_EX(SVM_EXIT_TR_WRITE), 439662306a36Sopenharmony_ci [x86_intercept_sgdt] = POST_EX(SVM_EXIT_GDTR_READ), 439762306a36Sopenharmony_ci [x86_intercept_sidt] = POST_EX(SVM_EXIT_IDTR_READ), 439862306a36Sopenharmony_ci [x86_intercept_lgdt] = POST_EX(SVM_EXIT_GDTR_WRITE), 439962306a36Sopenharmony_ci [x86_intercept_lidt] = POST_EX(SVM_EXIT_IDTR_WRITE), 440062306a36Sopenharmony_ci [x86_intercept_vmrun] = POST_EX(SVM_EXIT_VMRUN), 440162306a36Sopenharmony_ci [x86_intercept_vmmcall] = POST_EX(SVM_EXIT_VMMCALL), 440262306a36Sopenharmony_ci [x86_intercept_vmload] = POST_EX(SVM_EXIT_VMLOAD), 440362306a36Sopenharmony_ci [x86_intercept_vmsave] = POST_EX(SVM_EXIT_VMSAVE), 440462306a36Sopenharmony_ci [x86_intercept_stgi] = POST_EX(SVM_EXIT_STGI), 440562306a36Sopenharmony_ci [x86_intercept_clgi] = POST_EX(SVM_EXIT_CLGI), 440662306a36Sopenharmony_ci [x86_intercept_skinit] = POST_EX(SVM_EXIT_SKINIT), 440762306a36Sopenharmony_ci [x86_intercept_invlpga] = POST_EX(SVM_EXIT_INVLPGA), 440862306a36Sopenharmony_ci [x86_intercept_rdtscp] = POST_EX(SVM_EXIT_RDTSCP), 440962306a36Sopenharmony_ci [x86_intercept_monitor] = POST_MEM(SVM_EXIT_MONITOR), 441062306a36Sopenharmony_ci [x86_intercept_mwait] = POST_EX(SVM_EXIT_MWAIT), 441162306a36Sopenharmony_ci [x86_intercept_invlpg] = POST_EX(SVM_EXIT_INVLPG), 441262306a36Sopenharmony_ci [x86_intercept_invd] = POST_EX(SVM_EXIT_INVD), 441362306a36Sopenharmony_ci [x86_intercept_wbinvd] = POST_EX(SVM_EXIT_WBINVD), 441462306a36Sopenharmony_ci [x86_intercept_wrmsr] = POST_EX(SVM_EXIT_MSR), 441562306a36Sopenharmony_ci [x86_intercept_rdtsc] = POST_EX(SVM_EXIT_RDTSC), 441662306a36Sopenharmony_ci [x86_intercept_rdmsr] = POST_EX(SVM_EXIT_MSR), 441762306a36Sopenharmony_ci [x86_intercept_rdpmc] = POST_EX(SVM_EXIT_RDPMC), 441862306a36Sopenharmony_ci [x86_intercept_cpuid] = PRE_EX(SVM_EXIT_CPUID), 441962306a36Sopenharmony_ci [x86_intercept_rsm] = PRE_EX(SVM_EXIT_RSM), 442062306a36Sopenharmony_ci [x86_intercept_pause] = PRE_EX(SVM_EXIT_PAUSE), 442162306a36Sopenharmony_ci [x86_intercept_pushf] = PRE_EX(SVM_EXIT_PUSHF), 442262306a36Sopenharmony_ci [x86_intercept_popf] = PRE_EX(SVM_EXIT_POPF), 442362306a36Sopenharmony_ci [x86_intercept_intn] = PRE_EX(SVM_EXIT_SWINT), 442462306a36Sopenharmony_ci [x86_intercept_iret] = PRE_EX(SVM_EXIT_IRET), 442562306a36Sopenharmony_ci [x86_intercept_icebp] = PRE_EX(SVM_EXIT_ICEBP), 442662306a36Sopenharmony_ci [x86_intercept_hlt] = POST_EX(SVM_EXIT_HLT), 442762306a36Sopenharmony_ci [x86_intercept_in] = POST_EX(SVM_EXIT_IOIO), 442862306a36Sopenharmony_ci [x86_intercept_ins] = POST_EX(SVM_EXIT_IOIO), 442962306a36Sopenharmony_ci [x86_intercept_out] = POST_EX(SVM_EXIT_IOIO), 443062306a36Sopenharmony_ci [x86_intercept_outs] = POST_EX(SVM_EXIT_IOIO), 443162306a36Sopenharmony_ci [x86_intercept_xsetbv] = PRE_EX(SVM_EXIT_XSETBV), 443262306a36Sopenharmony_ci}; 443362306a36Sopenharmony_ci 443462306a36Sopenharmony_ci#undef PRE_EX 443562306a36Sopenharmony_ci#undef POST_EX 443662306a36Sopenharmony_ci#undef POST_MEM 443762306a36Sopenharmony_ci 443862306a36Sopenharmony_cistatic int svm_check_intercept(struct kvm_vcpu *vcpu, 443962306a36Sopenharmony_ci struct x86_instruction_info *info, 444062306a36Sopenharmony_ci enum x86_intercept_stage stage, 444162306a36Sopenharmony_ci struct x86_exception *exception) 444262306a36Sopenharmony_ci{ 444362306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 444462306a36Sopenharmony_ci int vmexit, ret = X86EMUL_CONTINUE; 444562306a36Sopenharmony_ci struct __x86_intercept icpt_info; 444662306a36Sopenharmony_ci struct vmcb *vmcb = svm->vmcb; 444762306a36Sopenharmony_ci 444862306a36Sopenharmony_ci if (info->intercept >= ARRAY_SIZE(x86_intercept_map)) 444962306a36Sopenharmony_ci goto out; 445062306a36Sopenharmony_ci 445162306a36Sopenharmony_ci icpt_info = x86_intercept_map[info->intercept]; 445262306a36Sopenharmony_ci 445362306a36Sopenharmony_ci if (stage != icpt_info.stage) 445462306a36Sopenharmony_ci goto out; 445562306a36Sopenharmony_ci 445662306a36Sopenharmony_ci switch (icpt_info.exit_code) { 445762306a36Sopenharmony_ci case SVM_EXIT_READ_CR0: 445862306a36Sopenharmony_ci if (info->intercept == x86_intercept_cr_read) 445962306a36Sopenharmony_ci icpt_info.exit_code += info->modrm_reg; 446062306a36Sopenharmony_ci break; 446162306a36Sopenharmony_ci case SVM_EXIT_WRITE_CR0: { 446262306a36Sopenharmony_ci unsigned long cr0, val; 446362306a36Sopenharmony_ci 446462306a36Sopenharmony_ci if (info->intercept == x86_intercept_cr_write) 446562306a36Sopenharmony_ci icpt_info.exit_code += info->modrm_reg; 446662306a36Sopenharmony_ci 446762306a36Sopenharmony_ci if (icpt_info.exit_code != SVM_EXIT_WRITE_CR0 || 446862306a36Sopenharmony_ci info->intercept == x86_intercept_clts) 446962306a36Sopenharmony_ci break; 447062306a36Sopenharmony_ci 447162306a36Sopenharmony_ci if (!(vmcb12_is_intercept(&svm->nested.ctl, 447262306a36Sopenharmony_ci INTERCEPT_SELECTIVE_CR0))) 447362306a36Sopenharmony_ci break; 447462306a36Sopenharmony_ci 447562306a36Sopenharmony_ci cr0 = vcpu->arch.cr0 & ~SVM_CR0_SELECTIVE_MASK; 447662306a36Sopenharmony_ci val = info->src_val & ~SVM_CR0_SELECTIVE_MASK; 447762306a36Sopenharmony_ci 447862306a36Sopenharmony_ci if (info->intercept == x86_intercept_lmsw) { 447962306a36Sopenharmony_ci cr0 &= 0xfUL; 448062306a36Sopenharmony_ci val &= 0xfUL; 448162306a36Sopenharmony_ci /* lmsw can't clear PE - catch this here */ 448262306a36Sopenharmony_ci if (cr0 & X86_CR0_PE) 448362306a36Sopenharmony_ci val |= X86_CR0_PE; 448462306a36Sopenharmony_ci } 448562306a36Sopenharmony_ci 448662306a36Sopenharmony_ci if (cr0 ^ val) 448762306a36Sopenharmony_ci icpt_info.exit_code = SVM_EXIT_CR0_SEL_WRITE; 448862306a36Sopenharmony_ci 448962306a36Sopenharmony_ci break; 449062306a36Sopenharmony_ci } 449162306a36Sopenharmony_ci case SVM_EXIT_READ_DR0: 449262306a36Sopenharmony_ci case SVM_EXIT_WRITE_DR0: 449362306a36Sopenharmony_ci icpt_info.exit_code += info->modrm_reg; 449462306a36Sopenharmony_ci break; 449562306a36Sopenharmony_ci case SVM_EXIT_MSR: 449662306a36Sopenharmony_ci if (info->intercept == x86_intercept_wrmsr) 449762306a36Sopenharmony_ci vmcb->control.exit_info_1 = 1; 449862306a36Sopenharmony_ci else 449962306a36Sopenharmony_ci vmcb->control.exit_info_1 = 0; 450062306a36Sopenharmony_ci break; 450162306a36Sopenharmony_ci case SVM_EXIT_PAUSE: 450262306a36Sopenharmony_ci /* 450362306a36Sopenharmony_ci * We get this for NOP only, but pause 450462306a36Sopenharmony_ci * is rep not, check this here 450562306a36Sopenharmony_ci */ 450662306a36Sopenharmony_ci if (info->rep_prefix != REPE_PREFIX) 450762306a36Sopenharmony_ci goto out; 450862306a36Sopenharmony_ci break; 450962306a36Sopenharmony_ci case SVM_EXIT_IOIO: { 451062306a36Sopenharmony_ci u64 exit_info; 451162306a36Sopenharmony_ci u32 bytes; 451262306a36Sopenharmony_ci 451362306a36Sopenharmony_ci if (info->intercept == x86_intercept_in || 451462306a36Sopenharmony_ci info->intercept == x86_intercept_ins) { 451562306a36Sopenharmony_ci exit_info = ((info->src_val & 0xffff) << 16) | 451662306a36Sopenharmony_ci SVM_IOIO_TYPE_MASK; 451762306a36Sopenharmony_ci bytes = info->dst_bytes; 451862306a36Sopenharmony_ci } else { 451962306a36Sopenharmony_ci exit_info = (info->dst_val & 0xffff) << 16; 452062306a36Sopenharmony_ci bytes = info->src_bytes; 452162306a36Sopenharmony_ci } 452262306a36Sopenharmony_ci 452362306a36Sopenharmony_ci if (info->intercept == x86_intercept_outs || 452462306a36Sopenharmony_ci info->intercept == x86_intercept_ins) 452562306a36Sopenharmony_ci exit_info |= SVM_IOIO_STR_MASK; 452662306a36Sopenharmony_ci 452762306a36Sopenharmony_ci if (info->rep_prefix) 452862306a36Sopenharmony_ci exit_info |= SVM_IOIO_REP_MASK; 452962306a36Sopenharmony_ci 453062306a36Sopenharmony_ci bytes = min(bytes, 4u); 453162306a36Sopenharmony_ci 453262306a36Sopenharmony_ci exit_info |= bytes << SVM_IOIO_SIZE_SHIFT; 453362306a36Sopenharmony_ci 453462306a36Sopenharmony_ci exit_info |= (u32)info->ad_bytes << (SVM_IOIO_ASIZE_SHIFT - 1); 453562306a36Sopenharmony_ci 453662306a36Sopenharmony_ci vmcb->control.exit_info_1 = exit_info; 453762306a36Sopenharmony_ci vmcb->control.exit_info_2 = info->next_rip; 453862306a36Sopenharmony_ci 453962306a36Sopenharmony_ci break; 454062306a36Sopenharmony_ci } 454162306a36Sopenharmony_ci default: 454262306a36Sopenharmony_ci break; 454362306a36Sopenharmony_ci } 454462306a36Sopenharmony_ci 454562306a36Sopenharmony_ci /* TODO: Advertise NRIPS to guest hypervisor unconditionally */ 454662306a36Sopenharmony_ci if (static_cpu_has(X86_FEATURE_NRIPS)) 454762306a36Sopenharmony_ci vmcb->control.next_rip = info->next_rip; 454862306a36Sopenharmony_ci vmcb->control.exit_code = icpt_info.exit_code; 454962306a36Sopenharmony_ci vmexit = nested_svm_exit_handled(svm); 455062306a36Sopenharmony_ci 455162306a36Sopenharmony_ci ret = (vmexit == NESTED_EXIT_DONE) ? X86EMUL_INTERCEPTED 455262306a36Sopenharmony_ci : X86EMUL_CONTINUE; 455362306a36Sopenharmony_ci 455462306a36Sopenharmony_ciout: 455562306a36Sopenharmony_ci return ret; 455662306a36Sopenharmony_ci} 455762306a36Sopenharmony_ci 455862306a36Sopenharmony_cistatic void svm_handle_exit_irqoff(struct kvm_vcpu *vcpu) 455962306a36Sopenharmony_ci{ 456062306a36Sopenharmony_ci if (to_svm(vcpu)->vmcb->control.exit_code == SVM_EXIT_INTR) 456162306a36Sopenharmony_ci vcpu->arch.at_instruction_boundary = true; 456262306a36Sopenharmony_ci} 456362306a36Sopenharmony_ci 456462306a36Sopenharmony_cistatic void svm_sched_in(struct kvm_vcpu *vcpu, int cpu) 456562306a36Sopenharmony_ci{ 456662306a36Sopenharmony_ci if (!kvm_pause_in_guest(vcpu->kvm)) 456762306a36Sopenharmony_ci shrink_ple_window(vcpu); 456862306a36Sopenharmony_ci} 456962306a36Sopenharmony_ci 457062306a36Sopenharmony_cistatic void svm_setup_mce(struct kvm_vcpu *vcpu) 457162306a36Sopenharmony_ci{ 457262306a36Sopenharmony_ci /* [63:9] are reserved. */ 457362306a36Sopenharmony_ci vcpu->arch.mcg_cap &= 0x1ff; 457462306a36Sopenharmony_ci} 457562306a36Sopenharmony_ci 457662306a36Sopenharmony_ci#ifdef CONFIG_KVM_SMM 457762306a36Sopenharmony_cibool svm_smi_blocked(struct kvm_vcpu *vcpu) 457862306a36Sopenharmony_ci{ 457962306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 458062306a36Sopenharmony_ci 458162306a36Sopenharmony_ci /* Per APM Vol.2 15.22.2 "Response to SMI" */ 458262306a36Sopenharmony_ci if (!gif_set(svm)) 458362306a36Sopenharmony_ci return true; 458462306a36Sopenharmony_ci 458562306a36Sopenharmony_ci return is_smm(vcpu); 458662306a36Sopenharmony_ci} 458762306a36Sopenharmony_ci 458862306a36Sopenharmony_cistatic int svm_smi_allowed(struct kvm_vcpu *vcpu, bool for_injection) 458962306a36Sopenharmony_ci{ 459062306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 459162306a36Sopenharmony_ci if (svm->nested.nested_run_pending) 459262306a36Sopenharmony_ci return -EBUSY; 459362306a36Sopenharmony_ci 459462306a36Sopenharmony_ci if (svm_smi_blocked(vcpu)) 459562306a36Sopenharmony_ci return 0; 459662306a36Sopenharmony_ci 459762306a36Sopenharmony_ci /* An SMI must not be injected into L2 if it's supposed to VM-Exit. */ 459862306a36Sopenharmony_ci if (for_injection && is_guest_mode(vcpu) && nested_exit_on_smi(svm)) 459962306a36Sopenharmony_ci return -EBUSY; 460062306a36Sopenharmony_ci 460162306a36Sopenharmony_ci return 1; 460262306a36Sopenharmony_ci} 460362306a36Sopenharmony_ci 460462306a36Sopenharmony_cistatic int svm_enter_smm(struct kvm_vcpu *vcpu, union kvm_smram *smram) 460562306a36Sopenharmony_ci{ 460662306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 460762306a36Sopenharmony_ci struct kvm_host_map map_save; 460862306a36Sopenharmony_ci int ret; 460962306a36Sopenharmony_ci 461062306a36Sopenharmony_ci if (!is_guest_mode(vcpu)) 461162306a36Sopenharmony_ci return 0; 461262306a36Sopenharmony_ci 461362306a36Sopenharmony_ci /* 461462306a36Sopenharmony_ci * 32-bit SMRAM format doesn't preserve EFER and SVM state. Userspace is 461562306a36Sopenharmony_ci * responsible for ensuring nested SVM and SMIs are mutually exclusive. 461662306a36Sopenharmony_ci */ 461762306a36Sopenharmony_ci 461862306a36Sopenharmony_ci if (!guest_cpuid_has(vcpu, X86_FEATURE_LM)) 461962306a36Sopenharmony_ci return 1; 462062306a36Sopenharmony_ci 462162306a36Sopenharmony_ci smram->smram64.svm_guest_flag = 1; 462262306a36Sopenharmony_ci smram->smram64.svm_guest_vmcb_gpa = svm->nested.vmcb12_gpa; 462362306a36Sopenharmony_ci 462462306a36Sopenharmony_ci svm->vmcb->save.rax = vcpu->arch.regs[VCPU_REGS_RAX]; 462562306a36Sopenharmony_ci svm->vmcb->save.rsp = vcpu->arch.regs[VCPU_REGS_RSP]; 462662306a36Sopenharmony_ci svm->vmcb->save.rip = vcpu->arch.regs[VCPU_REGS_RIP]; 462762306a36Sopenharmony_ci 462862306a36Sopenharmony_ci ret = nested_svm_simple_vmexit(svm, SVM_EXIT_SW); 462962306a36Sopenharmony_ci if (ret) 463062306a36Sopenharmony_ci return ret; 463162306a36Sopenharmony_ci 463262306a36Sopenharmony_ci /* 463362306a36Sopenharmony_ci * KVM uses VMCB01 to store L1 host state while L2 runs but 463462306a36Sopenharmony_ci * VMCB01 is going to be used during SMM and thus the state will 463562306a36Sopenharmony_ci * be lost. Temporary save non-VMLOAD/VMSAVE state to the host save 463662306a36Sopenharmony_ci * area pointed to by MSR_VM_HSAVE_PA. APM guarantees that the 463762306a36Sopenharmony_ci * format of the area is identical to guest save area offsetted 463862306a36Sopenharmony_ci * by 0x400 (matches the offset of 'struct vmcb_save_area' 463962306a36Sopenharmony_ci * within 'struct vmcb'). Note: HSAVE area may also be used by 464062306a36Sopenharmony_ci * L1 hypervisor to save additional host context (e.g. KVM does 464162306a36Sopenharmony_ci * that, see svm_prepare_switch_to_guest()) which must be 464262306a36Sopenharmony_ci * preserved. 464362306a36Sopenharmony_ci */ 464462306a36Sopenharmony_ci if (kvm_vcpu_map(vcpu, gpa_to_gfn(svm->nested.hsave_msr), &map_save)) 464562306a36Sopenharmony_ci return 1; 464662306a36Sopenharmony_ci 464762306a36Sopenharmony_ci BUILD_BUG_ON(offsetof(struct vmcb, save) != 0x400); 464862306a36Sopenharmony_ci 464962306a36Sopenharmony_ci svm_copy_vmrun_state(map_save.hva + 0x400, 465062306a36Sopenharmony_ci &svm->vmcb01.ptr->save); 465162306a36Sopenharmony_ci 465262306a36Sopenharmony_ci kvm_vcpu_unmap(vcpu, &map_save, true); 465362306a36Sopenharmony_ci return 0; 465462306a36Sopenharmony_ci} 465562306a36Sopenharmony_ci 465662306a36Sopenharmony_cistatic int svm_leave_smm(struct kvm_vcpu *vcpu, const union kvm_smram *smram) 465762306a36Sopenharmony_ci{ 465862306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 465962306a36Sopenharmony_ci struct kvm_host_map map, map_save; 466062306a36Sopenharmony_ci struct vmcb *vmcb12; 466162306a36Sopenharmony_ci int ret; 466262306a36Sopenharmony_ci 466362306a36Sopenharmony_ci const struct kvm_smram_state_64 *smram64 = &smram->smram64; 466462306a36Sopenharmony_ci 466562306a36Sopenharmony_ci if (!guest_cpuid_has(vcpu, X86_FEATURE_LM)) 466662306a36Sopenharmony_ci return 0; 466762306a36Sopenharmony_ci 466862306a36Sopenharmony_ci /* Non-zero if SMI arrived while vCPU was in guest mode. */ 466962306a36Sopenharmony_ci if (!smram64->svm_guest_flag) 467062306a36Sopenharmony_ci return 0; 467162306a36Sopenharmony_ci 467262306a36Sopenharmony_ci if (!guest_cpuid_has(vcpu, X86_FEATURE_SVM)) 467362306a36Sopenharmony_ci return 1; 467462306a36Sopenharmony_ci 467562306a36Sopenharmony_ci if (!(smram64->efer & EFER_SVME)) 467662306a36Sopenharmony_ci return 1; 467762306a36Sopenharmony_ci 467862306a36Sopenharmony_ci if (kvm_vcpu_map(vcpu, gpa_to_gfn(smram64->svm_guest_vmcb_gpa), &map)) 467962306a36Sopenharmony_ci return 1; 468062306a36Sopenharmony_ci 468162306a36Sopenharmony_ci ret = 1; 468262306a36Sopenharmony_ci if (kvm_vcpu_map(vcpu, gpa_to_gfn(svm->nested.hsave_msr), &map_save)) 468362306a36Sopenharmony_ci goto unmap_map; 468462306a36Sopenharmony_ci 468562306a36Sopenharmony_ci if (svm_allocate_nested(svm)) 468662306a36Sopenharmony_ci goto unmap_save; 468762306a36Sopenharmony_ci 468862306a36Sopenharmony_ci /* 468962306a36Sopenharmony_ci * Restore L1 host state from L1 HSAVE area as VMCB01 was 469062306a36Sopenharmony_ci * used during SMM (see svm_enter_smm()) 469162306a36Sopenharmony_ci */ 469262306a36Sopenharmony_ci 469362306a36Sopenharmony_ci svm_copy_vmrun_state(&svm->vmcb01.ptr->save, map_save.hva + 0x400); 469462306a36Sopenharmony_ci 469562306a36Sopenharmony_ci /* 469662306a36Sopenharmony_ci * Enter the nested guest now 469762306a36Sopenharmony_ci */ 469862306a36Sopenharmony_ci 469962306a36Sopenharmony_ci vmcb_mark_all_dirty(svm->vmcb01.ptr); 470062306a36Sopenharmony_ci 470162306a36Sopenharmony_ci vmcb12 = map.hva; 470262306a36Sopenharmony_ci nested_copy_vmcb_control_to_cache(svm, &vmcb12->control); 470362306a36Sopenharmony_ci nested_copy_vmcb_save_to_cache(svm, &vmcb12->save); 470462306a36Sopenharmony_ci ret = enter_svm_guest_mode(vcpu, smram64->svm_guest_vmcb_gpa, vmcb12, false); 470562306a36Sopenharmony_ci 470662306a36Sopenharmony_ci if (ret) 470762306a36Sopenharmony_ci goto unmap_save; 470862306a36Sopenharmony_ci 470962306a36Sopenharmony_ci svm->nested.nested_run_pending = 1; 471062306a36Sopenharmony_ci 471162306a36Sopenharmony_ciunmap_save: 471262306a36Sopenharmony_ci kvm_vcpu_unmap(vcpu, &map_save, true); 471362306a36Sopenharmony_ciunmap_map: 471462306a36Sopenharmony_ci kvm_vcpu_unmap(vcpu, &map, true); 471562306a36Sopenharmony_ci return ret; 471662306a36Sopenharmony_ci} 471762306a36Sopenharmony_ci 471862306a36Sopenharmony_cistatic void svm_enable_smi_window(struct kvm_vcpu *vcpu) 471962306a36Sopenharmony_ci{ 472062306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 472162306a36Sopenharmony_ci 472262306a36Sopenharmony_ci if (!gif_set(svm)) { 472362306a36Sopenharmony_ci if (vgif) 472462306a36Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_STGI); 472562306a36Sopenharmony_ci /* STGI will cause a vm exit */ 472662306a36Sopenharmony_ci } else { 472762306a36Sopenharmony_ci /* We must be in SMM; RSM will cause a vmexit anyway. */ 472862306a36Sopenharmony_ci } 472962306a36Sopenharmony_ci} 473062306a36Sopenharmony_ci#endif 473162306a36Sopenharmony_ci 473262306a36Sopenharmony_cistatic bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type, 473362306a36Sopenharmony_ci void *insn, int insn_len) 473462306a36Sopenharmony_ci{ 473562306a36Sopenharmony_ci bool smep, smap, is_user; 473662306a36Sopenharmony_ci u64 error_code; 473762306a36Sopenharmony_ci 473862306a36Sopenharmony_ci /* Emulation is always possible when KVM has access to all guest state. */ 473962306a36Sopenharmony_ci if (!sev_guest(vcpu->kvm)) 474062306a36Sopenharmony_ci return true; 474162306a36Sopenharmony_ci 474262306a36Sopenharmony_ci /* #UD and #GP should never be intercepted for SEV guests. */ 474362306a36Sopenharmony_ci WARN_ON_ONCE(emul_type & (EMULTYPE_TRAP_UD | 474462306a36Sopenharmony_ci EMULTYPE_TRAP_UD_FORCED | 474562306a36Sopenharmony_ci EMULTYPE_VMWARE_GP)); 474662306a36Sopenharmony_ci 474762306a36Sopenharmony_ci /* 474862306a36Sopenharmony_ci * Emulation is impossible for SEV-ES guests as KVM doesn't have access 474962306a36Sopenharmony_ci * to guest register state. 475062306a36Sopenharmony_ci */ 475162306a36Sopenharmony_ci if (sev_es_guest(vcpu->kvm)) 475262306a36Sopenharmony_ci return false; 475362306a36Sopenharmony_ci 475462306a36Sopenharmony_ci /* 475562306a36Sopenharmony_ci * Emulation is possible if the instruction is already decoded, e.g. 475662306a36Sopenharmony_ci * when completing I/O after returning from userspace. 475762306a36Sopenharmony_ci */ 475862306a36Sopenharmony_ci if (emul_type & EMULTYPE_NO_DECODE) 475962306a36Sopenharmony_ci return true; 476062306a36Sopenharmony_ci 476162306a36Sopenharmony_ci /* 476262306a36Sopenharmony_ci * Emulation is possible for SEV guests if and only if a prefilled 476362306a36Sopenharmony_ci * buffer containing the bytes of the intercepted instruction is 476462306a36Sopenharmony_ci * available. SEV guest memory is encrypted with a guest specific key 476562306a36Sopenharmony_ci * and cannot be decrypted by KVM, i.e. KVM would read cyphertext and 476662306a36Sopenharmony_ci * decode garbage. 476762306a36Sopenharmony_ci * 476862306a36Sopenharmony_ci * If KVM is NOT trying to simply skip an instruction, inject #UD if 476962306a36Sopenharmony_ci * KVM reached this point without an instruction buffer. In practice, 477062306a36Sopenharmony_ci * this path should never be hit by a well-behaved guest, e.g. KVM 477162306a36Sopenharmony_ci * doesn't intercept #UD or #GP for SEV guests, but this path is still 477262306a36Sopenharmony_ci * theoretically reachable, e.g. via unaccelerated fault-like AVIC 477362306a36Sopenharmony_ci * access, and needs to be handled by KVM to avoid putting the guest 477462306a36Sopenharmony_ci * into an infinite loop. Injecting #UD is somewhat arbitrary, but 477562306a36Sopenharmony_ci * its the least awful option given lack of insight into the guest. 477662306a36Sopenharmony_ci * 477762306a36Sopenharmony_ci * If KVM is trying to skip an instruction, simply resume the guest. 477862306a36Sopenharmony_ci * If a #NPF occurs while the guest is vectoring an INT3/INTO, then KVM 477962306a36Sopenharmony_ci * will attempt to re-inject the INT3/INTO and skip the instruction. 478062306a36Sopenharmony_ci * In that scenario, retrying the INT3/INTO and hoping the guest will 478162306a36Sopenharmony_ci * make forward progress is the only option that has a chance of 478262306a36Sopenharmony_ci * success (and in practice it will work the vast majority of the time). 478362306a36Sopenharmony_ci */ 478462306a36Sopenharmony_ci if (unlikely(!insn)) { 478562306a36Sopenharmony_ci if (!(emul_type & EMULTYPE_SKIP)) 478662306a36Sopenharmony_ci kvm_queue_exception(vcpu, UD_VECTOR); 478762306a36Sopenharmony_ci return false; 478862306a36Sopenharmony_ci } 478962306a36Sopenharmony_ci 479062306a36Sopenharmony_ci /* 479162306a36Sopenharmony_ci * Emulate for SEV guests if the insn buffer is not empty. The buffer 479262306a36Sopenharmony_ci * will be empty if the DecodeAssist microcode cannot fetch bytes for 479362306a36Sopenharmony_ci * the faulting instruction because the code fetch itself faulted, e.g. 479462306a36Sopenharmony_ci * the guest attempted to fetch from emulated MMIO or a guest page 479562306a36Sopenharmony_ci * table used to translate CS:RIP resides in emulated MMIO. 479662306a36Sopenharmony_ci */ 479762306a36Sopenharmony_ci if (likely(insn_len)) 479862306a36Sopenharmony_ci return true; 479962306a36Sopenharmony_ci 480062306a36Sopenharmony_ci /* 480162306a36Sopenharmony_ci * Detect and workaround Errata 1096 Fam_17h_00_0Fh. 480262306a36Sopenharmony_ci * 480362306a36Sopenharmony_ci * Errata: 480462306a36Sopenharmony_ci * When CPU raises #NPF on guest data access and vCPU CR4.SMAP=1, it is 480562306a36Sopenharmony_ci * possible that CPU microcode implementing DecodeAssist will fail to 480662306a36Sopenharmony_ci * read guest memory at CS:RIP and vmcb.GuestIntrBytes will incorrectly 480762306a36Sopenharmony_ci * be '0'. This happens because microcode reads CS:RIP using a _data_ 480862306a36Sopenharmony_ci * loap uop with CPL=0 privileges. If the load hits a SMAP #PF, ucode 480962306a36Sopenharmony_ci * gives up and does not fill the instruction bytes buffer. 481062306a36Sopenharmony_ci * 481162306a36Sopenharmony_ci * As above, KVM reaches this point iff the VM is an SEV guest, the CPU 481262306a36Sopenharmony_ci * supports DecodeAssist, a #NPF was raised, KVM's page fault handler 481362306a36Sopenharmony_ci * triggered emulation (e.g. for MMIO), and the CPU returned 0 in the 481462306a36Sopenharmony_ci * GuestIntrBytes field of the VMCB. 481562306a36Sopenharmony_ci * 481662306a36Sopenharmony_ci * This does _not_ mean that the erratum has been encountered, as the 481762306a36Sopenharmony_ci * DecodeAssist will also fail if the load for CS:RIP hits a legitimate 481862306a36Sopenharmony_ci * #PF, e.g. if the guest attempt to execute from emulated MMIO and 481962306a36Sopenharmony_ci * encountered a reserved/not-present #PF. 482062306a36Sopenharmony_ci * 482162306a36Sopenharmony_ci * To hit the erratum, the following conditions must be true: 482262306a36Sopenharmony_ci * 1. CR4.SMAP=1 (obviously). 482362306a36Sopenharmony_ci * 2. CR4.SMEP=0 || CPL=3. If SMEP=1 and CPL<3, the erratum cannot 482462306a36Sopenharmony_ci * have been hit as the guest would have encountered a SMEP 482562306a36Sopenharmony_ci * violation #PF, not a #NPF. 482662306a36Sopenharmony_ci * 3. The #NPF is not due to a code fetch, in which case failure to 482762306a36Sopenharmony_ci * retrieve the instruction bytes is legitimate (see abvoe). 482862306a36Sopenharmony_ci * 482962306a36Sopenharmony_ci * In addition, don't apply the erratum workaround if the #NPF occurred 483062306a36Sopenharmony_ci * while translating guest page tables (see below). 483162306a36Sopenharmony_ci */ 483262306a36Sopenharmony_ci error_code = to_svm(vcpu)->vmcb->control.exit_info_1; 483362306a36Sopenharmony_ci if (error_code & (PFERR_GUEST_PAGE_MASK | PFERR_FETCH_MASK)) 483462306a36Sopenharmony_ci goto resume_guest; 483562306a36Sopenharmony_ci 483662306a36Sopenharmony_ci smep = kvm_is_cr4_bit_set(vcpu, X86_CR4_SMEP); 483762306a36Sopenharmony_ci smap = kvm_is_cr4_bit_set(vcpu, X86_CR4_SMAP); 483862306a36Sopenharmony_ci is_user = svm_get_cpl(vcpu) == 3; 483962306a36Sopenharmony_ci if (smap && (!smep || is_user)) { 484062306a36Sopenharmony_ci pr_err_ratelimited("SEV Guest triggered AMD Erratum 1096\n"); 484162306a36Sopenharmony_ci 484262306a36Sopenharmony_ci /* 484362306a36Sopenharmony_ci * If the fault occurred in userspace, arbitrarily inject #GP 484462306a36Sopenharmony_ci * to avoid killing the guest and to hopefully avoid confusing 484562306a36Sopenharmony_ci * the guest kernel too much, e.g. injecting #PF would not be 484662306a36Sopenharmony_ci * coherent with respect to the guest's page tables. Request 484762306a36Sopenharmony_ci * triple fault if the fault occurred in the kernel as there's 484862306a36Sopenharmony_ci * no fault that KVM can inject without confusing the guest. 484962306a36Sopenharmony_ci * In practice, the triple fault is moot as no sane SEV kernel 485062306a36Sopenharmony_ci * will execute from user memory while also running with SMAP=1. 485162306a36Sopenharmony_ci */ 485262306a36Sopenharmony_ci if (is_user) 485362306a36Sopenharmony_ci kvm_inject_gp(vcpu, 0); 485462306a36Sopenharmony_ci else 485562306a36Sopenharmony_ci kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu); 485662306a36Sopenharmony_ci } 485762306a36Sopenharmony_ci 485862306a36Sopenharmony_ciresume_guest: 485962306a36Sopenharmony_ci /* 486062306a36Sopenharmony_ci * If the erratum was not hit, simply resume the guest and let it fault 486162306a36Sopenharmony_ci * again. While awful, e.g. the vCPU may get stuck in an infinite loop 486262306a36Sopenharmony_ci * if the fault is at CPL=0, it's the lesser of all evils. Exiting to 486362306a36Sopenharmony_ci * userspace will kill the guest, and letting the emulator read garbage 486462306a36Sopenharmony_ci * will yield random behavior and potentially corrupt the guest. 486562306a36Sopenharmony_ci * 486662306a36Sopenharmony_ci * Simply resuming the guest is technically not a violation of the SEV 486762306a36Sopenharmony_ci * architecture. AMD's APM states that all code fetches and page table 486862306a36Sopenharmony_ci * accesses for SEV guest are encrypted, regardless of the C-Bit. The 486962306a36Sopenharmony_ci * APM also states that encrypted accesses to MMIO are "ignored", but 487062306a36Sopenharmony_ci * doesn't explicitly define "ignored", i.e. doing nothing and letting 487162306a36Sopenharmony_ci * the guest spin is technically "ignoring" the access. 487262306a36Sopenharmony_ci */ 487362306a36Sopenharmony_ci return false; 487462306a36Sopenharmony_ci} 487562306a36Sopenharmony_ci 487662306a36Sopenharmony_cistatic bool svm_apic_init_signal_blocked(struct kvm_vcpu *vcpu) 487762306a36Sopenharmony_ci{ 487862306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 487962306a36Sopenharmony_ci 488062306a36Sopenharmony_ci return !gif_set(svm); 488162306a36Sopenharmony_ci} 488262306a36Sopenharmony_ci 488362306a36Sopenharmony_cistatic void svm_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector) 488462306a36Sopenharmony_ci{ 488562306a36Sopenharmony_ci if (!sev_es_guest(vcpu->kvm)) 488662306a36Sopenharmony_ci return kvm_vcpu_deliver_sipi_vector(vcpu, vector); 488762306a36Sopenharmony_ci 488862306a36Sopenharmony_ci sev_vcpu_deliver_sipi_vector(vcpu, vector); 488962306a36Sopenharmony_ci} 489062306a36Sopenharmony_ci 489162306a36Sopenharmony_cistatic void svm_vm_destroy(struct kvm *kvm) 489262306a36Sopenharmony_ci{ 489362306a36Sopenharmony_ci avic_vm_destroy(kvm); 489462306a36Sopenharmony_ci sev_vm_destroy(kvm); 489562306a36Sopenharmony_ci} 489662306a36Sopenharmony_ci 489762306a36Sopenharmony_cistatic int svm_vm_init(struct kvm *kvm) 489862306a36Sopenharmony_ci{ 489962306a36Sopenharmony_ci if (!pause_filter_count || !pause_filter_thresh) 490062306a36Sopenharmony_ci kvm->arch.pause_in_guest = true; 490162306a36Sopenharmony_ci 490262306a36Sopenharmony_ci if (enable_apicv) { 490362306a36Sopenharmony_ci int ret = avic_vm_init(kvm); 490462306a36Sopenharmony_ci if (ret) 490562306a36Sopenharmony_ci return ret; 490662306a36Sopenharmony_ci } 490762306a36Sopenharmony_ci 490862306a36Sopenharmony_ci return 0; 490962306a36Sopenharmony_ci} 491062306a36Sopenharmony_ci 491162306a36Sopenharmony_cistatic struct kvm_x86_ops svm_x86_ops __initdata = { 491262306a36Sopenharmony_ci .name = KBUILD_MODNAME, 491362306a36Sopenharmony_ci 491462306a36Sopenharmony_ci .check_processor_compatibility = svm_check_processor_compat, 491562306a36Sopenharmony_ci 491662306a36Sopenharmony_ci .hardware_unsetup = svm_hardware_unsetup, 491762306a36Sopenharmony_ci .hardware_enable = svm_hardware_enable, 491862306a36Sopenharmony_ci .hardware_disable = svm_hardware_disable, 491962306a36Sopenharmony_ci .has_emulated_msr = svm_has_emulated_msr, 492062306a36Sopenharmony_ci 492162306a36Sopenharmony_ci .vcpu_create = svm_vcpu_create, 492262306a36Sopenharmony_ci .vcpu_free = svm_vcpu_free, 492362306a36Sopenharmony_ci .vcpu_reset = svm_vcpu_reset, 492462306a36Sopenharmony_ci 492562306a36Sopenharmony_ci .vm_size = sizeof(struct kvm_svm), 492662306a36Sopenharmony_ci .vm_init = svm_vm_init, 492762306a36Sopenharmony_ci .vm_destroy = svm_vm_destroy, 492862306a36Sopenharmony_ci 492962306a36Sopenharmony_ci .prepare_switch_to_guest = svm_prepare_switch_to_guest, 493062306a36Sopenharmony_ci .vcpu_load = svm_vcpu_load, 493162306a36Sopenharmony_ci .vcpu_put = svm_vcpu_put, 493262306a36Sopenharmony_ci .vcpu_blocking = avic_vcpu_blocking, 493362306a36Sopenharmony_ci .vcpu_unblocking = avic_vcpu_unblocking, 493462306a36Sopenharmony_ci 493562306a36Sopenharmony_ci .update_exception_bitmap = svm_update_exception_bitmap, 493662306a36Sopenharmony_ci .get_msr_feature = svm_get_msr_feature, 493762306a36Sopenharmony_ci .get_msr = svm_get_msr, 493862306a36Sopenharmony_ci .set_msr = svm_set_msr, 493962306a36Sopenharmony_ci .get_segment_base = svm_get_segment_base, 494062306a36Sopenharmony_ci .get_segment = svm_get_segment, 494162306a36Sopenharmony_ci .set_segment = svm_set_segment, 494262306a36Sopenharmony_ci .get_cpl = svm_get_cpl, 494362306a36Sopenharmony_ci .get_cs_db_l_bits = svm_get_cs_db_l_bits, 494462306a36Sopenharmony_ci .is_valid_cr0 = svm_is_valid_cr0, 494562306a36Sopenharmony_ci .set_cr0 = svm_set_cr0, 494662306a36Sopenharmony_ci .post_set_cr3 = sev_post_set_cr3, 494762306a36Sopenharmony_ci .is_valid_cr4 = svm_is_valid_cr4, 494862306a36Sopenharmony_ci .set_cr4 = svm_set_cr4, 494962306a36Sopenharmony_ci .set_efer = svm_set_efer, 495062306a36Sopenharmony_ci .get_idt = svm_get_idt, 495162306a36Sopenharmony_ci .set_idt = svm_set_idt, 495262306a36Sopenharmony_ci .get_gdt = svm_get_gdt, 495362306a36Sopenharmony_ci .set_gdt = svm_set_gdt, 495462306a36Sopenharmony_ci .set_dr7 = svm_set_dr7, 495562306a36Sopenharmony_ci .sync_dirty_debug_regs = svm_sync_dirty_debug_regs, 495662306a36Sopenharmony_ci .cache_reg = svm_cache_reg, 495762306a36Sopenharmony_ci .get_rflags = svm_get_rflags, 495862306a36Sopenharmony_ci .set_rflags = svm_set_rflags, 495962306a36Sopenharmony_ci .get_if_flag = svm_get_if_flag, 496062306a36Sopenharmony_ci 496162306a36Sopenharmony_ci .flush_tlb_all = svm_flush_tlb_all, 496262306a36Sopenharmony_ci .flush_tlb_current = svm_flush_tlb_current, 496362306a36Sopenharmony_ci .flush_tlb_gva = svm_flush_tlb_gva, 496462306a36Sopenharmony_ci .flush_tlb_guest = svm_flush_tlb_asid, 496562306a36Sopenharmony_ci 496662306a36Sopenharmony_ci .vcpu_pre_run = svm_vcpu_pre_run, 496762306a36Sopenharmony_ci .vcpu_run = svm_vcpu_run, 496862306a36Sopenharmony_ci .handle_exit = svm_handle_exit, 496962306a36Sopenharmony_ci .skip_emulated_instruction = svm_skip_emulated_instruction, 497062306a36Sopenharmony_ci .update_emulated_instruction = NULL, 497162306a36Sopenharmony_ci .set_interrupt_shadow = svm_set_interrupt_shadow, 497262306a36Sopenharmony_ci .get_interrupt_shadow = svm_get_interrupt_shadow, 497362306a36Sopenharmony_ci .patch_hypercall = svm_patch_hypercall, 497462306a36Sopenharmony_ci .inject_irq = svm_inject_irq, 497562306a36Sopenharmony_ci .inject_nmi = svm_inject_nmi, 497662306a36Sopenharmony_ci .is_vnmi_pending = svm_is_vnmi_pending, 497762306a36Sopenharmony_ci .set_vnmi_pending = svm_set_vnmi_pending, 497862306a36Sopenharmony_ci .inject_exception = svm_inject_exception, 497962306a36Sopenharmony_ci .cancel_injection = svm_cancel_injection, 498062306a36Sopenharmony_ci .interrupt_allowed = svm_interrupt_allowed, 498162306a36Sopenharmony_ci .nmi_allowed = svm_nmi_allowed, 498262306a36Sopenharmony_ci .get_nmi_mask = svm_get_nmi_mask, 498362306a36Sopenharmony_ci .set_nmi_mask = svm_set_nmi_mask, 498462306a36Sopenharmony_ci .enable_nmi_window = svm_enable_nmi_window, 498562306a36Sopenharmony_ci .enable_irq_window = svm_enable_irq_window, 498662306a36Sopenharmony_ci .update_cr8_intercept = svm_update_cr8_intercept, 498762306a36Sopenharmony_ci .set_virtual_apic_mode = avic_refresh_virtual_apic_mode, 498862306a36Sopenharmony_ci .refresh_apicv_exec_ctrl = avic_refresh_apicv_exec_ctrl, 498962306a36Sopenharmony_ci .apicv_post_state_restore = avic_apicv_post_state_restore, 499062306a36Sopenharmony_ci .required_apicv_inhibits = AVIC_REQUIRED_APICV_INHIBITS, 499162306a36Sopenharmony_ci 499262306a36Sopenharmony_ci .get_exit_info = svm_get_exit_info, 499362306a36Sopenharmony_ci 499462306a36Sopenharmony_ci .vcpu_after_set_cpuid = svm_vcpu_after_set_cpuid, 499562306a36Sopenharmony_ci 499662306a36Sopenharmony_ci .has_wbinvd_exit = svm_has_wbinvd_exit, 499762306a36Sopenharmony_ci 499862306a36Sopenharmony_ci .get_l2_tsc_offset = svm_get_l2_tsc_offset, 499962306a36Sopenharmony_ci .get_l2_tsc_multiplier = svm_get_l2_tsc_multiplier, 500062306a36Sopenharmony_ci .write_tsc_offset = svm_write_tsc_offset, 500162306a36Sopenharmony_ci .write_tsc_multiplier = svm_write_tsc_multiplier, 500262306a36Sopenharmony_ci 500362306a36Sopenharmony_ci .load_mmu_pgd = svm_load_mmu_pgd, 500462306a36Sopenharmony_ci 500562306a36Sopenharmony_ci .check_intercept = svm_check_intercept, 500662306a36Sopenharmony_ci .handle_exit_irqoff = svm_handle_exit_irqoff, 500762306a36Sopenharmony_ci 500862306a36Sopenharmony_ci .request_immediate_exit = __kvm_request_immediate_exit, 500962306a36Sopenharmony_ci 501062306a36Sopenharmony_ci .sched_in = svm_sched_in, 501162306a36Sopenharmony_ci 501262306a36Sopenharmony_ci .nested_ops = &svm_nested_ops, 501362306a36Sopenharmony_ci 501462306a36Sopenharmony_ci .deliver_interrupt = svm_deliver_interrupt, 501562306a36Sopenharmony_ci .pi_update_irte = avic_pi_update_irte, 501662306a36Sopenharmony_ci .setup_mce = svm_setup_mce, 501762306a36Sopenharmony_ci 501862306a36Sopenharmony_ci#ifdef CONFIG_KVM_SMM 501962306a36Sopenharmony_ci .smi_allowed = svm_smi_allowed, 502062306a36Sopenharmony_ci .enter_smm = svm_enter_smm, 502162306a36Sopenharmony_ci .leave_smm = svm_leave_smm, 502262306a36Sopenharmony_ci .enable_smi_window = svm_enable_smi_window, 502362306a36Sopenharmony_ci#endif 502462306a36Sopenharmony_ci 502562306a36Sopenharmony_ci .mem_enc_ioctl = sev_mem_enc_ioctl, 502662306a36Sopenharmony_ci .mem_enc_register_region = sev_mem_enc_register_region, 502762306a36Sopenharmony_ci .mem_enc_unregister_region = sev_mem_enc_unregister_region, 502862306a36Sopenharmony_ci .guest_memory_reclaimed = sev_guest_memory_reclaimed, 502962306a36Sopenharmony_ci 503062306a36Sopenharmony_ci .vm_copy_enc_context_from = sev_vm_copy_enc_context_from, 503162306a36Sopenharmony_ci .vm_move_enc_context_from = sev_vm_move_enc_context_from, 503262306a36Sopenharmony_ci 503362306a36Sopenharmony_ci .can_emulate_instruction = svm_can_emulate_instruction, 503462306a36Sopenharmony_ci 503562306a36Sopenharmony_ci .apic_init_signal_blocked = svm_apic_init_signal_blocked, 503662306a36Sopenharmony_ci 503762306a36Sopenharmony_ci .msr_filter_changed = svm_msr_filter_changed, 503862306a36Sopenharmony_ci .complete_emulated_msr = svm_complete_emulated_msr, 503962306a36Sopenharmony_ci 504062306a36Sopenharmony_ci .vcpu_deliver_sipi_vector = svm_vcpu_deliver_sipi_vector, 504162306a36Sopenharmony_ci .vcpu_get_apicv_inhibit_reasons = avic_vcpu_get_apicv_inhibit_reasons, 504262306a36Sopenharmony_ci}; 504362306a36Sopenharmony_ci 504462306a36Sopenharmony_ci/* 504562306a36Sopenharmony_ci * The default MMIO mask is a single bit (excluding the present bit), 504662306a36Sopenharmony_ci * which could conflict with the memory encryption bit. Check for 504762306a36Sopenharmony_ci * memory encryption support and override the default MMIO mask if 504862306a36Sopenharmony_ci * memory encryption is enabled. 504962306a36Sopenharmony_ci */ 505062306a36Sopenharmony_cistatic __init void svm_adjust_mmio_mask(void) 505162306a36Sopenharmony_ci{ 505262306a36Sopenharmony_ci unsigned int enc_bit, mask_bit; 505362306a36Sopenharmony_ci u64 msr, mask; 505462306a36Sopenharmony_ci 505562306a36Sopenharmony_ci /* If there is no memory encryption support, use existing mask */ 505662306a36Sopenharmony_ci if (cpuid_eax(0x80000000) < 0x8000001f) 505762306a36Sopenharmony_ci return; 505862306a36Sopenharmony_ci 505962306a36Sopenharmony_ci /* If memory encryption is not enabled, use existing mask */ 506062306a36Sopenharmony_ci rdmsrl(MSR_AMD64_SYSCFG, msr); 506162306a36Sopenharmony_ci if (!(msr & MSR_AMD64_SYSCFG_MEM_ENCRYPT)) 506262306a36Sopenharmony_ci return; 506362306a36Sopenharmony_ci 506462306a36Sopenharmony_ci enc_bit = cpuid_ebx(0x8000001f) & 0x3f; 506562306a36Sopenharmony_ci mask_bit = boot_cpu_data.x86_phys_bits; 506662306a36Sopenharmony_ci 506762306a36Sopenharmony_ci /* Increment the mask bit if it is the same as the encryption bit */ 506862306a36Sopenharmony_ci if (enc_bit == mask_bit) 506962306a36Sopenharmony_ci mask_bit++; 507062306a36Sopenharmony_ci 507162306a36Sopenharmony_ci /* 507262306a36Sopenharmony_ci * If the mask bit location is below 52, then some bits above the 507362306a36Sopenharmony_ci * physical addressing limit will always be reserved, so use the 507462306a36Sopenharmony_ci * rsvd_bits() function to generate the mask. This mask, along with 507562306a36Sopenharmony_ci * the present bit, will be used to generate a page fault with 507662306a36Sopenharmony_ci * PFER.RSV = 1. 507762306a36Sopenharmony_ci * 507862306a36Sopenharmony_ci * If the mask bit location is 52 (or above), then clear the mask. 507962306a36Sopenharmony_ci */ 508062306a36Sopenharmony_ci mask = (mask_bit < 52) ? rsvd_bits(mask_bit, 51) | PT_PRESENT_MASK : 0; 508162306a36Sopenharmony_ci 508262306a36Sopenharmony_ci kvm_mmu_set_mmio_spte_mask(mask, mask, PT_WRITABLE_MASK | PT_USER_MASK); 508362306a36Sopenharmony_ci} 508462306a36Sopenharmony_ci 508562306a36Sopenharmony_cistatic __init void svm_set_cpu_caps(void) 508662306a36Sopenharmony_ci{ 508762306a36Sopenharmony_ci kvm_set_cpu_caps(); 508862306a36Sopenharmony_ci 508962306a36Sopenharmony_ci kvm_caps.supported_perf_cap = 0; 509062306a36Sopenharmony_ci kvm_caps.supported_xss = 0; 509162306a36Sopenharmony_ci 509262306a36Sopenharmony_ci /* CPUID 0x80000001 and 0x8000000A (SVM features) */ 509362306a36Sopenharmony_ci if (nested) { 509462306a36Sopenharmony_ci kvm_cpu_cap_set(X86_FEATURE_SVM); 509562306a36Sopenharmony_ci kvm_cpu_cap_set(X86_FEATURE_VMCBCLEAN); 509662306a36Sopenharmony_ci 509762306a36Sopenharmony_ci if (nrips) 509862306a36Sopenharmony_ci kvm_cpu_cap_set(X86_FEATURE_NRIPS); 509962306a36Sopenharmony_ci 510062306a36Sopenharmony_ci if (npt_enabled) 510162306a36Sopenharmony_ci kvm_cpu_cap_set(X86_FEATURE_NPT); 510262306a36Sopenharmony_ci 510362306a36Sopenharmony_ci if (tsc_scaling) 510462306a36Sopenharmony_ci kvm_cpu_cap_set(X86_FEATURE_TSCRATEMSR); 510562306a36Sopenharmony_ci 510662306a36Sopenharmony_ci if (vls) 510762306a36Sopenharmony_ci kvm_cpu_cap_set(X86_FEATURE_V_VMSAVE_VMLOAD); 510862306a36Sopenharmony_ci if (lbrv) 510962306a36Sopenharmony_ci kvm_cpu_cap_set(X86_FEATURE_LBRV); 511062306a36Sopenharmony_ci 511162306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_PAUSEFILTER)) 511262306a36Sopenharmony_ci kvm_cpu_cap_set(X86_FEATURE_PAUSEFILTER); 511362306a36Sopenharmony_ci 511462306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_PFTHRESHOLD)) 511562306a36Sopenharmony_ci kvm_cpu_cap_set(X86_FEATURE_PFTHRESHOLD); 511662306a36Sopenharmony_ci 511762306a36Sopenharmony_ci if (vgif) 511862306a36Sopenharmony_ci kvm_cpu_cap_set(X86_FEATURE_VGIF); 511962306a36Sopenharmony_ci 512062306a36Sopenharmony_ci if (vnmi) 512162306a36Sopenharmony_ci kvm_cpu_cap_set(X86_FEATURE_VNMI); 512262306a36Sopenharmony_ci 512362306a36Sopenharmony_ci /* Nested VM can receive #VMEXIT instead of triggering #GP */ 512462306a36Sopenharmony_ci kvm_cpu_cap_set(X86_FEATURE_SVME_ADDR_CHK); 512562306a36Sopenharmony_ci } 512662306a36Sopenharmony_ci 512762306a36Sopenharmony_ci /* CPUID 0x80000008 */ 512862306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_LS_CFG_SSBD) || 512962306a36Sopenharmony_ci boot_cpu_has(X86_FEATURE_AMD_SSBD)) 513062306a36Sopenharmony_ci kvm_cpu_cap_set(X86_FEATURE_VIRT_SSBD); 513162306a36Sopenharmony_ci 513262306a36Sopenharmony_ci if (enable_pmu) { 513362306a36Sopenharmony_ci /* 513462306a36Sopenharmony_ci * Enumerate support for PERFCTR_CORE if and only if KVM has 513562306a36Sopenharmony_ci * access to enough counters to virtualize "core" support, 513662306a36Sopenharmony_ci * otherwise limit vPMU support to the legacy number of counters. 513762306a36Sopenharmony_ci */ 513862306a36Sopenharmony_ci if (kvm_pmu_cap.num_counters_gp < AMD64_NUM_COUNTERS_CORE) 513962306a36Sopenharmony_ci kvm_pmu_cap.num_counters_gp = min(AMD64_NUM_COUNTERS, 514062306a36Sopenharmony_ci kvm_pmu_cap.num_counters_gp); 514162306a36Sopenharmony_ci else 514262306a36Sopenharmony_ci kvm_cpu_cap_check_and_set(X86_FEATURE_PERFCTR_CORE); 514362306a36Sopenharmony_ci 514462306a36Sopenharmony_ci if (kvm_pmu_cap.version != 2 || 514562306a36Sopenharmony_ci !kvm_cpu_cap_has(X86_FEATURE_PERFCTR_CORE)) 514662306a36Sopenharmony_ci kvm_cpu_cap_clear(X86_FEATURE_PERFMON_V2); 514762306a36Sopenharmony_ci } 514862306a36Sopenharmony_ci 514962306a36Sopenharmony_ci /* CPUID 0x8000001F (SME/SEV features) */ 515062306a36Sopenharmony_ci sev_set_cpu_caps(); 515162306a36Sopenharmony_ci} 515262306a36Sopenharmony_ci 515362306a36Sopenharmony_cistatic __init int svm_hardware_setup(void) 515462306a36Sopenharmony_ci{ 515562306a36Sopenharmony_ci int cpu; 515662306a36Sopenharmony_ci struct page *iopm_pages; 515762306a36Sopenharmony_ci void *iopm_va; 515862306a36Sopenharmony_ci int r; 515962306a36Sopenharmony_ci unsigned int order = get_order(IOPM_SIZE); 516062306a36Sopenharmony_ci 516162306a36Sopenharmony_ci /* 516262306a36Sopenharmony_ci * NX is required for shadow paging and for NPT if the NX huge pages 516362306a36Sopenharmony_ci * mitigation is enabled. 516462306a36Sopenharmony_ci */ 516562306a36Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_NX)) { 516662306a36Sopenharmony_ci pr_err_ratelimited("NX (Execute Disable) not supported\n"); 516762306a36Sopenharmony_ci return -EOPNOTSUPP; 516862306a36Sopenharmony_ci } 516962306a36Sopenharmony_ci kvm_enable_efer_bits(EFER_NX); 517062306a36Sopenharmony_ci 517162306a36Sopenharmony_ci iopm_pages = alloc_pages(GFP_KERNEL, order); 517262306a36Sopenharmony_ci 517362306a36Sopenharmony_ci if (!iopm_pages) 517462306a36Sopenharmony_ci return -ENOMEM; 517562306a36Sopenharmony_ci 517662306a36Sopenharmony_ci iopm_va = page_address(iopm_pages); 517762306a36Sopenharmony_ci memset(iopm_va, 0xff, PAGE_SIZE * (1 << order)); 517862306a36Sopenharmony_ci iopm_base = page_to_pfn(iopm_pages) << PAGE_SHIFT; 517962306a36Sopenharmony_ci 518062306a36Sopenharmony_ci init_msrpm_offsets(); 518162306a36Sopenharmony_ci 518262306a36Sopenharmony_ci kvm_caps.supported_xcr0 &= ~(XFEATURE_MASK_BNDREGS | 518362306a36Sopenharmony_ci XFEATURE_MASK_BNDCSR); 518462306a36Sopenharmony_ci 518562306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_FXSR_OPT)) 518662306a36Sopenharmony_ci kvm_enable_efer_bits(EFER_FFXSR); 518762306a36Sopenharmony_ci 518862306a36Sopenharmony_ci if (tsc_scaling) { 518962306a36Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_TSCRATEMSR)) { 519062306a36Sopenharmony_ci tsc_scaling = false; 519162306a36Sopenharmony_ci } else { 519262306a36Sopenharmony_ci pr_info("TSC scaling supported\n"); 519362306a36Sopenharmony_ci kvm_caps.has_tsc_control = true; 519462306a36Sopenharmony_ci } 519562306a36Sopenharmony_ci } 519662306a36Sopenharmony_ci kvm_caps.max_tsc_scaling_ratio = SVM_TSC_RATIO_MAX; 519762306a36Sopenharmony_ci kvm_caps.tsc_scaling_ratio_frac_bits = 32; 519862306a36Sopenharmony_ci 519962306a36Sopenharmony_ci tsc_aux_uret_slot = kvm_add_user_return_msr(MSR_TSC_AUX); 520062306a36Sopenharmony_ci 520162306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_AUTOIBRS)) 520262306a36Sopenharmony_ci kvm_enable_efer_bits(EFER_AUTOIBRS); 520362306a36Sopenharmony_ci 520462306a36Sopenharmony_ci /* Check for pause filtering support */ 520562306a36Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_PAUSEFILTER)) { 520662306a36Sopenharmony_ci pause_filter_count = 0; 520762306a36Sopenharmony_ci pause_filter_thresh = 0; 520862306a36Sopenharmony_ci } else if (!boot_cpu_has(X86_FEATURE_PFTHRESHOLD)) { 520962306a36Sopenharmony_ci pause_filter_thresh = 0; 521062306a36Sopenharmony_ci } 521162306a36Sopenharmony_ci 521262306a36Sopenharmony_ci if (nested) { 521362306a36Sopenharmony_ci pr_info("Nested Virtualization enabled\n"); 521462306a36Sopenharmony_ci kvm_enable_efer_bits(EFER_SVME | EFER_LMSLE); 521562306a36Sopenharmony_ci } 521662306a36Sopenharmony_ci 521762306a36Sopenharmony_ci /* 521862306a36Sopenharmony_ci * KVM's MMU doesn't support using 2-level paging for itself, and thus 521962306a36Sopenharmony_ci * NPT isn't supported if the host is using 2-level paging since host 522062306a36Sopenharmony_ci * CR4 is unchanged on VMRUN. 522162306a36Sopenharmony_ci */ 522262306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_X86_64) && !IS_ENABLED(CONFIG_X86_PAE)) 522362306a36Sopenharmony_ci npt_enabled = false; 522462306a36Sopenharmony_ci 522562306a36Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_NPT)) 522662306a36Sopenharmony_ci npt_enabled = false; 522762306a36Sopenharmony_ci 522862306a36Sopenharmony_ci /* Force VM NPT level equal to the host's paging level */ 522962306a36Sopenharmony_ci kvm_configure_mmu(npt_enabled, get_npt_level(), 523062306a36Sopenharmony_ci get_npt_level(), PG_LEVEL_1G); 523162306a36Sopenharmony_ci pr_info("Nested Paging %sabled\n", npt_enabled ? "en" : "dis"); 523262306a36Sopenharmony_ci 523362306a36Sopenharmony_ci /* Setup shadow_me_value and shadow_me_mask */ 523462306a36Sopenharmony_ci kvm_mmu_set_me_spte_mask(sme_me_mask, sme_me_mask); 523562306a36Sopenharmony_ci 523662306a36Sopenharmony_ci svm_adjust_mmio_mask(); 523762306a36Sopenharmony_ci 523862306a36Sopenharmony_ci nrips = nrips && boot_cpu_has(X86_FEATURE_NRIPS); 523962306a36Sopenharmony_ci 524062306a36Sopenharmony_ci /* 524162306a36Sopenharmony_ci * Note, SEV setup consumes npt_enabled and enable_mmio_caching (which 524262306a36Sopenharmony_ci * may be modified by svm_adjust_mmio_mask()), as well as nrips. 524362306a36Sopenharmony_ci */ 524462306a36Sopenharmony_ci sev_hardware_setup(); 524562306a36Sopenharmony_ci 524662306a36Sopenharmony_ci svm_hv_hardware_setup(); 524762306a36Sopenharmony_ci 524862306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 524962306a36Sopenharmony_ci r = svm_cpu_init(cpu); 525062306a36Sopenharmony_ci if (r) 525162306a36Sopenharmony_ci goto err; 525262306a36Sopenharmony_ci } 525362306a36Sopenharmony_ci 525462306a36Sopenharmony_ci enable_apicv = avic = avic && avic_hardware_setup(); 525562306a36Sopenharmony_ci 525662306a36Sopenharmony_ci if (!enable_apicv) { 525762306a36Sopenharmony_ci svm_x86_ops.vcpu_blocking = NULL; 525862306a36Sopenharmony_ci svm_x86_ops.vcpu_unblocking = NULL; 525962306a36Sopenharmony_ci svm_x86_ops.vcpu_get_apicv_inhibit_reasons = NULL; 526062306a36Sopenharmony_ci } else if (!x2avic_enabled) { 526162306a36Sopenharmony_ci svm_x86_ops.allow_apicv_in_x2apic_without_x2apic_virtualization = true; 526262306a36Sopenharmony_ci } 526362306a36Sopenharmony_ci 526462306a36Sopenharmony_ci if (vls) { 526562306a36Sopenharmony_ci if (!npt_enabled || 526662306a36Sopenharmony_ci !boot_cpu_has(X86_FEATURE_V_VMSAVE_VMLOAD) || 526762306a36Sopenharmony_ci !IS_ENABLED(CONFIG_X86_64)) { 526862306a36Sopenharmony_ci vls = false; 526962306a36Sopenharmony_ci } else { 527062306a36Sopenharmony_ci pr_info("Virtual VMLOAD VMSAVE supported\n"); 527162306a36Sopenharmony_ci } 527262306a36Sopenharmony_ci } 527362306a36Sopenharmony_ci 527462306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_SVME_ADDR_CHK)) 527562306a36Sopenharmony_ci svm_gp_erratum_intercept = false; 527662306a36Sopenharmony_ci 527762306a36Sopenharmony_ci if (vgif) { 527862306a36Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_VGIF)) 527962306a36Sopenharmony_ci vgif = false; 528062306a36Sopenharmony_ci else 528162306a36Sopenharmony_ci pr_info("Virtual GIF supported\n"); 528262306a36Sopenharmony_ci } 528362306a36Sopenharmony_ci 528462306a36Sopenharmony_ci vnmi = vgif && vnmi && boot_cpu_has(X86_FEATURE_VNMI); 528562306a36Sopenharmony_ci if (vnmi) 528662306a36Sopenharmony_ci pr_info("Virtual NMI enabled\n"); 528762306a36Sopenharmony_ci 528862306a36Sopenharmony_ci if (!vnmi) { 528962306a36Sopenharmony_ci svm_x86_ops.is_vnmi_pending = NULL; 529062306a36Sopenharmony_ci svm_x86_ops.set_vnmi_pending = NULL; 529162306a36Sopenharmony_ci } 529262306a36Sopenharmony_ci 529362306a36Sopenharmony_ci 529462306a36Sopenharmony_ci if (lbrv) { 529562306a36Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_LBRV)) 529662306a36Sopenharmony_ci lbrv = false; 529762306a36Sopenharmony_ci else 529862306a36Sopenharmony_ci pr_info("LBR virtualization supported\n"); 529962306a36Sopenharmony_ci } 530062306a36Sopenharmony_ci 530162306a36Sopenharmony_ci if (!enable_pmu) 530262306a36Sopenharmony_ci pr_info("PMU virtualization is disabled\n"); 530362306a36Sopenharmony_ci 530462306a36Sopenharmony_ci svm_set_cpu_caps(); 530562306a36Sopenharmony_ci 530662306a36Sopenharmony_ci /* 530762306a36Sopenharmony_ci * It seems that on AMD processors PTE's accessed bit is 530862306a36Sopenharmony_ci * being set by the CPU hardware before the NPF vmexit. 530962306a36Sopenharmony_ci * This is not expected behaviour and our tests fail because 531062306a36Sopenharmony_ci * of it. 531162306a36Sopenharmony_ci * A workaround here is to disable support for 531262306a36Sopenharmony_ci * GUEST_MAXPHYADDR < HOST_MAXPHYADDR if NPT is enabled. 531362306a36Sopenharmony_ci * In this case userspace can know if there is support using 531462306a36Sopenharmony_ci * KVM_CAP_SMALLER_MAXPHYADDR extension and decide how to handle 531562306a36Sopenharmony_ci * it 531662306a36Sopenharmony_ci * If future AMD CPU models change the behaviour described above, 531762306a36Sopenharmony_ci * this variable can be changed accordingly 531862306a36Sopenharmony_ci */ 531962306a36Sopenharmony_ci allow_smaller_maxphyaddr = !npt_enabled; 532062306a36Sopenharmony_ci 532162306a36Sopenharmony_ci return 0; 532262306a36Sopenharmony_ci 532362306a36Sopenharmony_cierr: 532462306a36Sopenharmony_ci svm_hardware_unsetup(); 532562306a36Sopenharmony_ci return r; 532662306a36Sopenharmony_ci} 532762306a36Sopenharmony_ci 532862306a36Sopenharmony_ci 532962306a36Sopenharmony_cistatic struct kvm_x86_init_ops svm_init_ops __initdata = { 533062306a36Sopenharmony_ci .hardware_setup = svm_hardware_setup, 533162306a36Sopenharmony_ci 533262306a36Sopenharmony_ci .runtime_ops = &svm_x86_ops, 533362306a36Sopenharmony_ci .pmu_ops = &amd_pmu_ops, 533462306a36Sopenharmony_ci}; 533562306a36Sopenharmony_ci 533662306a36Sopenharmony_cistatic void __svm_exit(void) 533762306a36Sopenharmony_ci{ 533862306a36Sopenharmony_ci kvm_x86_vendor_exit(); 533962306a36Sopenharmony_ci 534062306a36Sopenharmony_ci cpu_emergency_unregister_virt_callback(svm_emergency_disable); 534162306a36Sopenharmony_ci} 534262306a36Sopenharmony_ci 534362306a36Sopenharmony_cistatic int __init svm_init(void) 534462306a36Sopenharmony_ci{ 534562306a36Sopenharmony_ci int r; 534662306a36Sopenharmony_ci 534762306a36Sopenharmony_ci __unused_size_checks(); 534862306a36Sopenharmony_ci 534962306a36Sopenharmony_ci if (!kvm_is_svm_supported()) 535062306a36Sopenharmony_ci return -EOPNOTSUPP; 535162306a36Sopenharmony_ci 535262306a36Sopenharmony_ci r = kvm_x86_vendor_init(&svm_init_ops); 535362306a36Sopenharmony_ci if (r) 535462306a36Sopenharmony_ci return r; 535562306a36Sopenharmony_ci 535662306a36Sopenharmony_ci cpu_emergency_register_virt_callback(svm_emergency_disable); 535762306a36Sopenharmony_ci 535862306a36Sopenharmony_ci /* 535962306a36Sopenharmony_ci * Common KVM initialization _must_ come last, after this, /dev/kvm is 536062306a36Sopenharmony_ci * exposed to userspace! 536162306a36Sopenharmony_ci */ 536262306a36Sopenharmony_ci r = kvm_init(sizeof(struct vcpu_svm), __alignof__(struct vcpu_svm), 536362306a36Sopenharmony_ci THIS_MODULE); 536462306a36Sopenharmony_ci if (r) 536562306a36Sopenharmony_ci goto err_kvm_init; 536662306a36Sopenharmony_ci 536762306a36Sopenharmony_ci return 0; 536862306a36Sopenharmony_ci 536962306a36Sopenharmony_cierr_kvm_init: 537062306a36Sopenharmony_ci __svm_exit(); 537162306a36Sopenharmony_ci return r; 537262306a36Sopenharmony_ci} 537362306a36Sopenharmony_ci 537462306a36Sopenharmony_cistatic void __exit svm_exit(void) 537562306a36Sopenharmony_ci{ 537662306a36Sopenharmony_ci kvm_exit(); 537762306a36Sopenharmony_ci __svm_exit(); 537862306a36Sopenharmony_ci} 537962306a36Sopenharmony_ci 538062306a36Sopenharmony_cimodule_init(svm_init) 538162306a36Sopenharmony_cimodule_exit(svm_exit) 5382