18c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "SVM: " fmt 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci#include <linux/kvm_host.h> 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include "irq.h" 68c2ecf20Sopenharmony_ci#include "mmu.h" 78c2ecf20Sopenharmony_ci#include "kvm_cache_regs.h" 88c2ecf20Sopenharmony_ci#include "x86.h" 98c2ecf20Sopenharmony_ci#include "cpuid.h" 108c2ecf20Sopenharmony_ci#include "pmu.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 168c2ecf20Sopenharmony_ci#include <linux/highmem.h> 178c2ecf20Sopenharmony_ci#include <linux/amd-iommu.h> 188c2ecf20Sopenharmony_ci#include <linux/sched.h> 198c2ecf20Sopenharmony_ci#include <linux/trace_events.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci#include <linux/hashtable.h> 228c2ecf20Sopenharmony_ci#include <linux/objtool.h> 238c2ecf20Sopenharmony_ci#include <linux/psp-sev.h> 248c2ecf20Sopenharmony_ci#include <linux/file.h> 258c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 268c2ecf20Sopenharmony_ci#include <linux/swap.h> 278c2ecf20Sopenharmony_ci#include <linux/rwsem.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <asm/apic.h> 308c2ecf20Sopenharmony_ci#include <asm/perf_event.h> 318c2ecf20Sopenharmony_ci#include <asm/tlbflush.h> 328c2ecf20Sopenharmony_ci#include <asm/desc.h> 338c2ecf20Sopenharmony_ci#include <asm/debugreg.h> 348c2ecf20Sopenharmony_ci#include <asm/kvm_para.h> 358c2ecf20Sopenharmony_ci#include <asm/irq_remapping.h> 368c2ecf20Sopenharmony_ci#include <asm/mce.h> 378c2ecf20Sopenharmony_ci#include <asm/spec-ctrl.h> 388c2ecf20Sopenharmony_ci#include <asm/cpu_device_id.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include <asm/virtext.h> 418c2ecf20Sopenharmony_ci#include "trace.h" 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#include "svm.h" 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define __ex(x) __kvm_handle_fault_on_reboot(x) 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ciMODULE_AUTHOR("Qumranet"); 488c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#ifdef MODULE 518c2ecf20Sopenharmony_cistatic const struct x86_cpu_id svm_cpu_id[] = { 528c2ecf20Sopenharmony_ci X86_MATCH_FEATURE(X86_FEATURE_SVM, NULL), 538c2ecf20Sopenharmony_ci {} 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(x86cpu, svm_cpu_id); 568c2ecf20Sopenharmony_ci#endif 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define IOPM_ALLOC_ORDER 2 598c2ecf20Sopenharmony_ci#define MSRPM_ALLOC_ORDER 1 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define SEG_TYPE_LDT 2 628c2ecf20Sopenharmony_ci#define SEG_TYPE_BUSY_TSS16 3 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define SVM_FEATURE_LBRV (1 << 1) 658c2ecf20Sopenharmony_ci#define SVM_FEATURE_SVML (1 << 2) 668c2ecf20Sopenharmony_ci#define SVM_FEATURE_TSC_RATE (1 << 4) 678c2ecf20Sopenharmony_ci#define SVM_FEATURE_VMCB_CLEAN (1 << 5) 688c2ecf20Sopenharmony_ci#define SVM_FEATURE_FLUSH_ASID (1 << 6) 698c2ecf20Sopenharmony_ci#define SVM_FEATURE_DECODE_ASSIST (1 << 7) 708c2ecf20Sopenharmony_ci#define SVM_FEATURE_PAUSE_FILTER (1 << 10) 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define DEBUGCTL_RESERVED_BITS (~(0x3fULL)) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define TSC_RATIO_RSVD 0xffffff0000000000ULL 758c2ecf20Sopenharmony_ci#define TSC_RATIO_MIN 0x0000000000000001ULL 768c2ecf20Sopenharmony_ci#define TSC_RATIO_MAX 0x000000ffffffffffULL 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic bool erratum_383_found __read_mostly; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ciu32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* 838c2ecf20Sopenharmony_ci * Set osvw_len to higher value when updated Revision Guides 848c2ecf20Sopenharmony_ci * are published and we know what the new status bits are 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_cistatic uint64_t osvw_len = 4, osvw_status; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(u64, current_tsc_ratio); 898c2ecf20Sopenharmony_ci#define TSC_RATIO_DEFAULT 0x0100000000ULL 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic const struct svm_direct_access_msrs { 928c2ecf20Sopenharmony_ci u32 index; /* Index of the MSR */ 938c2ecf20Sopenharmony_ci bool always; /* True if intercept is always on */ 948c2ecf20Sopenharmony_ci} direct_access_msrs[MAX_DIRECT_ACCESS_MSRS] = { 958c2ecf20Sopenharmony_ci { .index = MSR_STAR, .always = true }, 968c2ecf20Sopenharmony_ci { .index = MSR_IA32_SYSENTER_CS, .always = true }, 978c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 988c2ecf20Sopenharmony_ci { .index = MSR_GS_BASE, .always = true }, 998c2ecf20Sopenharmony_ci { .index = MSR_FS_BASE, .always = true }, 1008c2ecf20Sopenharmony_ci { .index = MSR_KERNEL_GS_BASE, .always = true }, 1018c2ecf20Sopenharmony_ci { .index = MSR_LSTAR, .always = true }, 1028c2ecf20Sopenharmony_ci { .index = MSR_CSTAR, .always = true }, 1038c2ecf20Sopenharmony_ci { .index = MSR_SYSCALL_MASK, .always = true }, 1048c2ecf20Sopenharmony_ci#endif 1058c2ecf20Sopenharmony_ci { .index = MSR_IA32_SPEC_CTRL, .always = false }, 1068c2ecf20Sopenharmony_ci { .index = MSR_IA32_PRED_CMD, .always = false }, 1078c2ecf20Sopenharmony_ci { .index = MSR_IA32_LASTBRANCHFROMIP, .always = false }, 1088c2ecf20Sopenharmony_ci { .index = MSR_IA32_LASTBRANCHTOIP, .always = false }, 1098c2ecf20Sopenharmony_ci { .index = MSR_IA32_LASTINTFROMIP, .always = false }, 1108c2ecf20Sopenharmony_ci { .index = MSR_IA32_LASTINTTOIP, .always = false }, 1118c2ecf20Sopenharmony_ci { .index = MSR_INVALID, .always = false }, 1128c2ecf20Sopenharmony_ci}; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* enable NPT for AMD64 and X86 with PAE */ 1158c2ecf20Sopenharmony_ci#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE) 1168c2ecf20Sopenharmony_cibool npt_enabled = true; 1178c2ecf20Sopenharmony_ci#else 1188c2ecf20Sopenharmony_cibool npt_enabled; 1198c2ecf20Sopenharmony_ci#endif 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/* 1228c2ecf20Sopenharmony_ci * These 2 parameters are used to config the controls for Pause-Loop Exiting: 1238c2ecf20Sopenharmony_ci * pause_filter_count: On processors that support Pause filtering(indicated 1248c2ecf20Sopenharmony_ci * by CPUID Fn8000_000A_EDX), the VMCB provides a 16 bit pause filter 1258c2ecf20Sopenharmony_ci * count value. On VMRUN this value is loaded into an internal counter. 1268c2ecf20Sopenharmony_ci * Each time a pause instruction is executed, this counter is decremented 1278c2ecf20Sopenharmony_ci * until it reaches zero at which time a #VMEXIT is generated if pause 1288c2ecf20Sopenharmony_ci * intercept is enabled. Refer to AMD APM Vol 2 Section 15.14.4 Pause 1298c2ecf20Sopenharmony_ci * Intercept Filtering for more details. 1308c2ecf20Sopenharmony_ci * This also indicate if ple logic enabled. 1318c2ecf20Sopenharmony_ci * 1328c2ecf20Sopenharmony_ci * pause_filter_thresh: In addition, some processor families support advanced 1338c2ecf20Sopenharmony_ci * pause filtering (indicated by CPUID Fn8000_000A_EDX) upper bound on 1348c2ecf20Sopenharmony_ci * the amount of time a guest is allowed to execute in a pause loop. 1358c2ecf20Sopenharmony_ci * In this mode, a 16-bit pause filter threshold field is added in the 1368c2ecf20Sopenharmony_ci * VMCB. The threshold value is a cycle count that is used to reset the 1378c2ecf20Sopenharmony_ci * pause counter. As with simple pause filtering, VMRUN loads the pause 1388c2ecf20Sopenharmony_ci * count value from VMCB into an internal counter. Then, on each pause 1398c2ecf20Sopenharmony_ci * instruction the hardware checks the elapsed number of cycles since 1408c2ecf20Sopenharmony_ci * the most recent pause instruction against the pause filter threshold. 1418c2ecf20Sopenharmony_ci * If the elapsed cycle count is greater than the pause filter threshold, 1428c2ecf20Sopenharmony_ci * then the internal pause count is reloaded from the VMCB and execution 1438c2ecf20Sopenharmony_ci * continues. If the elapsed cycle count is less than the pause filter 1448c2ecf20Sopenharmony_ci * threshold, then the internal pause count is decremented. If the count 1458c2ecf20Sopenharmony_ci * value is less than zero and PAUSE intercept is enabled, a #VMEXIT is 1468c2ecf20Sopenharmony_ci * triggered. If advanced pause filtering is supported and pause filter 1478c2ecf20Sopenharmony_ci * threshold field is set to zero, the filter will operate in the simpler, 1488c2ecf20Sopenharmony_ci * count only mode. 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic unsigned short pause_filter_thresh = KVM_DEFAULT_PLE_GAP; 1528c2ecf20Sopenharmony_cimodule_param(pause_filter_thresh, ushort, 0444); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic unsigned short pause_filter_count = KVM_SVM_DEFAULT_PLE_WINDOW; 1558c2ecf20Sopenharmony_cimodule_param(pause_filter_count, ushort, 0444); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci/* Default doubles per-vcpu window every exit. */ 1588c2ecf20Sopenharmony_cistatic unsigned short pause_filter_count_grow = KVM_DEFAULT_PLE_WINDOW_GROW; 1598c2ecf20Sopenharmony_cimodule_param(pause_filter_count_grow, ushort, 0444); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/* Default resets per-vcpu window every exit to pause_filter_count. */ 1628c2ecf20Sopenharmony_cistatic unsigned short pause_filter_count_shrink = KVM_DEFAULT_PLE_WINDOW_SHRINK; 1638c2ecf20Sopenharmony_cimodule_param(pause_filter_count_shrink, ushort, 0444); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* Default is to compute the maximum so we can never overflow. */ 1668c2ecf20Sopenharmony_cistatic unsigned short pause_filter_count_max = KVM_SVM_DEFAULT_PLE_WINDOW_MAX; 1678c2ecf20Sopenharmony_cimodule_param(pause_filter_count_max, ushort, 0444); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/* allow nested paging (virtualized MMU) for all guests */ 1708c2ecf20Sopenharmony_cistatic int npt = true; 1718c2ecf20Sopenharmony_cimodule_param(npt, int, S_IRUGO); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/* allow nested virtualization in KVM/SVM */ 1748c2ecf20Sopenharmony_cistatic int nested = true; 1758c2ecf20Sopenharmony_cimodule_param(nested, int, S_IRUGO); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci/* enable/disable Next RIP Save */ 1788c2ecf20Sopenharmony_cistatic int nrips = true; 1798c2ecf20Sopenharmony_cimodule_param(nrips, int, 0444); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci/* enable/disable Virtual VMLOAD VMSAVE */ 1828c2ecf20Sopenharmony_cistatic int vls = true; 1838c2ecf20Sopenharmony_cimodule_param(vls, int, 0444); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci/* enable/disable Virtual GIF */ 1868c2ecf20Sopenharmony_cistatic int vgif = true; 1878c2ecf20Sopenharmony_cimodule_param(vgif, int, 0444); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci/* enable/disable SEV support */ 1908c2ecf20Sopenharmony_cistatic int sev = IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT); 1918c2ecf20Sopenharmony_cimodule_param(sev, int, 0444); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic bool __read_mostly dump_invalid_vmcb = 0; 1948c2ecf20Sopenharmony_cimodule_param(dump_invalid_vmcb, bool, 0644); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic u8 rsm_ins_bytes[] = "\x0f\xaa"; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic void svm_complete_interrupts(struct vcpu_svm *svm); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic unsigned long iopm_base; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistruct kvm_ldttss_desc { 2038c2ecf20Sopenharmony_ci u16 limit0; 2048c2ecf20Sopenharmony_ci u16 base0; 2058c2ecf20Sopenharmony_ci unsigned base1:8, type:5, dpl:2, p:1; 2068c2ecf20Sopenharmony_ci unsigned limit1:4, zero0:3, g:1, base2:8; 2078c2ecf20Sopenharmony_ci u32 base3; 2088c2ecf20Sopenharmony_ci u32 zero1; 2098c2ecf20Sopenharmony_ci} __attribute__((packed)); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ciDEFINE_PER_CPU(struct svm_cpu_data *, svm_data); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic const u32 msrpm_ranges[] = {0, 0xc0000000, 0xc0010000}; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci#define NUM_MSR_MAPS ARRAY_SIZE(msrpm_ranges) 2168c2ecf20Sopenharmony_ci#define MSRS_RANGE_SIZE 2048 2178c2ecf20Sopenharmony_ci#define MSRS_IN_RANGE (MSRS_RANGE_SIZE * 8 / 2) 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ciu32 svm_msrpm_offset(u32 msr) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci u32 offset; 2228c2ecf20Sopenharmony_ci int i; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci for (i = 0; i < NUM_MSR_MAPS; i++) { 2258c2ecf20Sopenharmony_ci if (msr < msrpm_ranges[i] || 2268c2ecf20Sopenharmony_ci msr >= msrpm_ranges[i] + MSRS_IN_RANGE) 2278c2ecf20Sopenharmony_ci continue; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci offset = (msr - msrpm_ranges[i]) / 4; /* 4 msrs per u8 */ 2308c2ecf20Sopenharmony_ci offset += (i * MSRS_RANGE_SIZE); /* add range offset */ 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* Now we have the u8 offset - but need the u32 offset */ 2338c2ecf20Sopenharmony_ci return offset / 4; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* MSR not in any range */ 2378c2ecf20Sopenharmony_ci return MSR_INVALID; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci#define MAX_INST_SIZE 15 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic inline void clgi(void) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci asm volatile (__ex("clgi")); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic inline void stgi(void) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci asm volatile (__ex("stgi")); 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic inline void invlpga(unsigned long addr, u32 asid) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci asm volatile (__ex("invlpga %1, %0") : : "c"(asid), "a"(addr)); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic int get_max_npt_level(void) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 2608c2ecf20Sopenharmony_ci return PT64_ROOT_4LEVEL; 2618c2ecf20Sopenharmony_ci#else 2628c2ecf20Sopenharmony_ci return PT32E_ROOT_LEVEL; 2638c2ecf20Sopenharmony_ci#endif 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ciint svm_set_efer(struct kvm_vcpu *vcpu, u64 efer) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 2698c2ecf20Sopenharmony_ci u64 old_efer = vcpu->arch.efer; 2708c2ecf20Sopenharmony_ci vcpu->arch.efer = efer; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (!npt_enabled) { 2738c2ecf20Sopenharmony_ci /* Shadow paging assumes NX to be available. */ 2748c2ecf20Sopenharmony_ci efer |= EFER_NX; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (!(efer & EFER_LMA)) 2778c2ecf20Sopenharmony_ci efer &= ~EFER_LME; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if ((old_efer & EFER_SVME) != (efer & EFER_SVME)) { 2818c2ecf20Sopenharmony_ci if (!(efer & EFER_SVME)) { 2828c2ecf20Sopenharmony_ci svm_leave_nested(vcpu); 2838c2ecf20Sopenharmony_ci svm_set_gif(svm, true); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* 2868c2ecf20Sopenharmony_ci * Free the nested guest state, unless we are in SMM. 2878c2ecf20Sopenharmony_ci * In this case we will return to the nested guest 2888c2ecf20Sopenharmony_ci * as soon as we leave SMM. 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_ci if (!is_smm(&svm->vcpu)) 2918c2ecf20Sopenharmony_ci svm_free_nested(svm); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci } else { 2948c2ecf20Sopenharmony_ci int ret = svm_allocate_nested(svm); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (ret) { 2978c2ecf20Sopenharmony_ci vcpu->arch.efer = old_efer; 2988c2ecf20Sopenharmony_ci return ret; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci svm->vmcb->save.efer = efer | EFER_SVME; 3048c2ecf20Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_CR); 3058c2ecf20Sopenharmony_ci return 0; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic u32 svm_get_interrupt_shadow(struct kvm_vcpu *vcpu) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 3118c2ecf20Sopenharmony_ci u32 ret = 0; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (svm->vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) 3148c2ecf20Sopenharmony_ci ret = KVM_X86_SHADOW_INT_STI | KVM_X86_SHADOW_INT_MOV_SS; 3158c2ecf20Sopenharmony_ci return ret; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic void svm_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (mask == 0) 3238c2ecf20Sopenharmony_ci svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK; 3248c2ecf20Sopenharmony_ci else 3258c2ecf20Sopenharmony_ci svm->vmcb->control.int_state |= SVM_INTERRUPT_SHADOW_MASK; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic int skip_emulated_instruction(struct kvm_vcpu *vcpu) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (nrips && svm->vmcb->control.next_rip != 0) { 3348c2ecf20Sopenharmony_ci WARN_ON_ONCE(!static_cpu_has(X86_FEATURE_NRIPS)); 3358c2ecf20Sopenharmony_ci svm->next_rip = svm->vmcb->control.next_rip; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (!svm->next_rip) { 3398c2ecf20Sopenharmony_ci if (!kvm_emulate_instruction(vcpu, EMULTYPE_SKIP)) 3408c2ecf20Sopenharmony_ci return 0; 3418c2ecf20Sopenharmony_ci } else { 3428c2ecf20Sopenharmony_ci kvm_rip_write(vcpu, svm->next_rip); 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci svm_set_interrupt_shadow(vcpu, 0); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci return 1; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic void svm_queue_exception(struct kvm_vcpu *vcpu) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 3528c2ecf20Sopenharmony_ci unsigned nr = vcpu->arch.exception.nr; 3538c2ecf20Sopenharmony_ci bool has_error_code = vcpu->arch.exception.has_error_code; 3548c2ecf20Sopenharmony_ci u32 error_code = vcpu->arch.exception.error_code; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci kvm_deliver_exception_payload(&svm->vcpu); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (nr == BP_VECTOR && !nrips) { 3598c2ecf20Sopenharmony_ci unsigned long rip, old_rip = kvm_rip_read(&svm->vcpu); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* 3628c2ecf20Sopenharmony_ci * For guest debugging where we have to reinject #BP if some 3638c2ecf20Sopenharmony_ci * INT3 is guest-owned: 3648c2ecf20Sopenharmony_ci * Emulate nRIP by moving RIP forward. Will fail if injection 3658c2ecf20Sopenharmony_ci * raises a fault that is not intercepted. Still better than 3668c2ecf20Sopenharmony_ci * failing in all cases. 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_ci (void)skip_emulated_instruction(&svm->vcpu); 3698c2ecf20Sopenharmony_ci rip = kvm_rip_read(&svm->vcpu); 3708c2ecf20Sopenharmony_ci svm->int3_rip = rip + svm->vmcb->save.cs.base; 3718c2ecf20Sopenharmony_ci svm->int3_injected = rip - old_rip; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci svm->vmcb->control.event_inj = nr 3758c2ecf20Sopenharmony_ci | SVM_EVTINJ_VALID 3768c2ecf20Sopenharmony_ci | (has_error_code ? SVM_EVTINJ_VALID_ERR : 0) 3778c2ecf20Sopenharmony_ci | SVM_EVTINJ_TYPE_EXEPT; 3788c2ecf20Sopenharmony_ci svm->vmcb->control.event_inj_err = error_code; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic void svm_init_erratum_383(void) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci u32 low, high; 3848c2ecf20Sopenharmony_ci int err; 3858c2ecf20Sopenharmony_ci u64 val; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (!static_cpu_has_bug(X86_BUG_AMD_TLB_MMATCH)) 3888c2ecf20Sopenharmony_ci return; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* Use _safe variants to not break nested virtualization */ 3918c2ecf20Sopenharmony_ci val = native_read_msr_safe(MSR_AMD64_DC_CFG, &err); 3928c2ecf20Sopenharmony_ci if (err) 3938c2ecf20Sopenharmony_ci return; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci val |= (1ULL << 47); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci low = lower_32_bits(val); 3988c2ecf20Sopenharmony_ci high = upper_32_bits(val); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci native_write_msr_safe(MSR_AMD64_DC_CFG, low, high); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci erratum_383_found = true; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic void svm_init_osvw(struct kvm_vcpu *vcpu) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci /* 4088c2ecf20Sopenharmony_ci * Guests should see errata 400 and 415 as fixed (assuming that 4098c2ecf20Sopenharmony_ci * HLT and IO instructions are intercepted). 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_ci vcpu->arch.osvw.length = (osvw_len >= 3) ? (osvw_len) : 3; 4128c2ecf20Sopenharmony_ci vcpu->arch.osvw.status = osvw_status & ~(6ULL); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci /* 4158c2ecf20Sopenharmony_ci * By increasing VCPU's osvw.length to 3 we are telling the guest that 4168c2ecf20Sopenharmony_ci * all osvw.status bits inside that length, including bit 0 (which is 4178c2ecf20Sopenharmony_ci * reserved for erratum 298), are valid. However, if host processor's 4188c2ecf20Sopenharmony_ci * osvw_len is 0 then osvw_status[0] carries no information. We need to 4198c2ecf20Sopenharmony_ci * be conservative here and therefore we tell the guest that erratum 298 4208c2ecf20Sopenharmony_ci * is present (because we really don't know). 4218c2ecf20Sopenharmony_ci */ 4228c2ecf20Sopenharmony_ci if (osvw_len == 0 && boot_cpu_data.x86 == 0x10) 4238c2ecf20Sopenharmony_ci vcpu->arch.osvw.status |= 1; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic int has_svm(void) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci const char *msg; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (!cpu_has_svm(&msg)) { 4318c2ecf20Sopenharmony_ci printk(KERN_INFO "has_svm: %s\n", msg); 4328c2ecf20Sopenharmony_ci return 0; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (sev_active()) { 4368c2ecf20Sopenharmony_ci pr_info("KVM is unsupported when running as an SEV guest\n"); 4378c2ecf20Sopenharmony_ci return 0; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci return 1; 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic void svm_hardware_disable(void) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci /* Make sure we clean up behind us */ 4468c2ecf20Sopenharmony_ci if (static_cpu_has(X86_FEATURE_TSCRATEMSR)) 4478c2ecf20Sopenharmony_ci wrmsrl(MSR_AMD64_TSC_RATIO, TSC_RATIO_DEFAULT); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci cpu_svm_disable(); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci amd_pmu_disable_virt(); 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic int svm_hardware_enable(void) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci struct svm_cpu_data *sd; 4588c2ecf20Sopenharmony_ci uint64_t efer; 4598c2ecf20Sopenharmony_ci struct desc_struct *gdt; 4608c2ecf20Sopenharmony_ci int me = raw_smp_processor_id(); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci rdmsrl(MSR_EFER, efer); 4638c2ecf20Sopenharmony_ci if (efer & EFER_SVME) 4648c2ecf20Sopenharmony_ci return -EBUSY; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (!has_svm()) { 4678c2ecf20Sopenharmony_ci pr_err("%s: err EOPNOTSUPP on %d\n", __func__, me); 4688c2ecf20Sopenharmony_ci return -EINVAL; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci sd = per_cpu(svm_data, me); 4718c2ecf20Sopenharmony_ci if (!sd) { 4728c2ecf20Sopenharmony_ci pr_err("%s: svm_data is NULL on %d\n", __func__, me); 4738c2ecf20Sopenharmony_ci return -EINVAL; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci sd->asid_generation = 1; 4778c2ecf20Sopenharmony_ci sd->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1; 4788c2ecf20Sopenharmony_ci sd->next_asid = sd->max_asid + 1; 4798c2ecf20Sopenharmony_ci sd->min_asid = max_sev_asid + 1; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci gdt = get_current_gdt_rw(); 4828c2ecf20Sopenharmony_ci sd->tss_desc = (struct kvm_ldttss_desc *)(gdt + GDT_ENTRY_TSS); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci wrmsrl(MSR_EFER, efer | EFER_SVME); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci wrmsrl(MSR_VM_HSAVE_PA, page_to_pfn(sd->save_area) << PAGE_SHIFT); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (static_cpu_has(X86_FEATURE_TSCRATEMSR)) { 4898c2ecf20Sopenharmony_ci wrmsrl(MSR_AMD64_TSC_RATIO, TSC_RATIO_DEFAULT); 4908c2ecf20Sopenharmony_ci __this_cpu_write(current_tsc_ratio, TSC_RATIO_DEFAULT); 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci /* 4958c2ecf20Sopenharmony_ci * Get OSVW bits. 4968c2ecf20Sopenharmony_ci * 4978c2ecf20Sopenharmony_ci * Note that it is possible to have a system with mixed processor 4988c2ecf20Sopenharmony_ci * revisions and therefore different OSVW bits. If bits are not the same 4998c2ecf20Sopenharmony_ci * on different processors then choose the worst case (i.e. if erratum 5008c2ecf20Sopenharmony_ci * is present on one processor and not on another then assume that the 5018c2ecf20Sopenharmony_ci * erratum is present everywhere). 5028c2ecf20Sopenharmony_ci */ 5038c2ecf20Sopenharmony_ci if (cpu_has(&boot_cpu_data, X86_FEATURE_OSVW)) { 5048c2ecf20Sopenharmony_ci uint64_t len, status = 0; 5058c2ecf20Sopenharmony_ci int err; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci len = native_read_msr_safe(MSR_AMD64_OSVW_ID_LENGTH, &err); 5088c2ecf20Sopenharmony_ci if (!err) 5098c2ecf20Sopenharmony_ci status = native_read_msr_safe(MSR_AMD64_OSVW_STATUS, 5108c2ecf20Sopenharmony_ci &err); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci if (err) 5138c2ecf20Sopenharmony_ci osvw_status = osvw_len = 0; 5148c2ecf20Sopenharmony_ci else { 5158c2ecf20Sopenharmony_ci if (len < osvw_len) 5168c2ecf20Sopenharmony_ci osvw_len = len; 5178c2ecf20Sopenharmony_ci osvw_status |= status; 5188c2ecf20Sopenharmony_ci osvw_status &= (1ULL << osvw_len) - 1; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci } else 5218c2ecf20Sopenharmony_ci osvw_status = osvw_len = 0; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci svm_init_erratum_383(); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci amd_pmu_enable_virt(); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci return 0; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic void svm_cpu_uninit(int cpu) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci struct svm_cpu_data *sd = per_cpu(svm_data, cpu); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if (!sd) 5358c2ecf20Sopenharmony_ci return; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci per_cpu(svm_data, cpu) = NULL; 5388c2ecf20Sopenharmony_ci kfree(sd->sev_vmcbs); 5398c2ecf20Sopenharmony_ci __free_page(sd->save_area); 5408c2ecf20Sopenharmony_ci kfree(sd); 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic int svm_cpu_init(int cpu) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci struct svm_cpu_data *sd; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci sd = kzalloc(sizeof(struct svm_cpu_data), GFP_KERNEL); 5488c2ecf20Sopenharmony_ci if (!sd) 5498c2ecf20Sopenharmony_ci return -ENOMEM; 5508c2ecf20Sopenharmony_ci sd->cpu = cpu; 5518c2ecf20Sopenharmony_ci sd->save_area = alloc_page(GFP_KERNEL); 5528c2ecf20Sopenharmony_ci if (!sd->save_area) 5538c2ecf20Sopenharmony_ci goto free_cpu_data; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (svm_sev_enabled()) { 5568c2ecf20Sopenharmony_ci sd->sev_vmcbs = kmalloc_array(max_sev_asid + 1, 5578c2ecf20Sopenharmony_ci sizeof(void *), 5588c2ecf20Sopenharmony_ci GFP_KERNEL); 5598c2ecf20Sopenharmony_ci if (!sd->sev_vmcbs) 5608c2ecf20Sopenharmony_ci goto free_save_area; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci per_cpu(svm_data, cpu) = sd; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci return 0; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cifree_save_area: 5688c2ecf20Sopenharmony_ci __free_page(sd->save_area); 5698c2ecf20Sopenharmony_cifree_cpu_data: 5708c2ecf20Sopenharmony_ci kfree(sd); 5718c2ecf20Sopenharmony_ci return -ENOMEM; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic int direct_access_msr_slot(u32 msr) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci u32 i; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci for (i = 0; direct_access_msrs[i].index != MSR_INVALID; i++) 5808c2ecf20Sopenharmony_ci if (direct_access_msrs[i].index == msr) 5818c2ecf20Sopenharmony_ci return i; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci return -ENOENT; 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic void set_shadow_msr_intercept(struct kvm_vcpu *vcpu, u32 msr, int read, 5878c2ecf20Sopenharmony_ci int write) 5888c2ecf20Sopenharmony_ci{ 5898c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 5908c2ecf20Sopenharmony_ci int slot = direct_access_msr_slot(msr); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci if (slot == -ENOENT) 5938c2ecf20Sopenharmony_ci return; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci /* Set the shadow bitmaps to the desired intercept states */ 5968c2ecf20Sopenharmony_ci if (read) 5978c2ecf20Sopenharmony_ci set_bit(slot, svm->shadow_msr_intercept.read); 5988c2ecf20Sopenharmony_ci else 5998c2ecf20Sopenharmony_ci clear_bit(slot, svm->shadow_msr_intercept.read); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (write) 6028c2ecf20Sopenharmony_ci set_bit(slot, svm->shadow_msr_intercept.write); 6038c2ecf20Sopenharmony_ci else 6048c2ecf20Sopenharmony_ci clear_bit(slot, svm->shadow_msr_intercept.write); 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic bool valid_msr_intercept(u32 index) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci return direct_access_msr_slot(index) != -ENOENT; 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cistatic bool msr_write_intercepted(struct kvm_vcpu *vcpu, u32 msr) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci u8 bit_write; 6158c2ecf20Sopenharmony_ci unsigned long tmp; 6168c2ecf20Sopenharmony_ci u32 offset; 6178c2ecf20Sopenharmony_ci u32 *msrpm; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci msrpm = is_guest_mode(vcpu) ? to_svm(vcpu)->nested.msrpm: 6208c2ecf20Sopenharmony_ci to_svm(vcpu)->msrpm; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci offset = svm_msrpm_offset(msr); 6238c2ecf20Sopenharmony_ci bit_write = 2 * (msr & 0x0f) + 1; 6248c2ecf20Sopenharmony_ci tmp = msrpm[offset]; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci BUG_ON(offset == MSR_INVALID); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci return !!test_bit(bit_write, &tmp); 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_cistatic void set_msr_interception_bitmap(struct kvm_vcpu *vcpu, u32 *msrpm, 6328c2ecf20Sopenharmony_ci u32 msr, int read, int write) 6338c2ecf20Sopenharmony_ci{ 6348c2ecf20Sopenharmony_ci u8 bit_read, bit_write; 6358c2ecf20Sopenharmony_ci unsigned long tmp; 6368c2ecf20Sopenharmony_ci u32 offset; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci /* 6398c2ecf20Sopenharmony_ci * If this warning triggers extend the direct_access_msrs list at the 6408c2ecf20Sopenharmony_ci * beginning of the file 6418c2ecf20Sopenharmony_ci */ 6428c2ecf20Sopenharmony_ci WARN_ON(!valid_msr_intercept(msr)); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci /* Enforce non allowed MSRs to trap */ 6458c2ecf20Sopenharmony_ci if (read && !kvm_msr_allowed(vcpu, msr, KVM_MSR_FILTER_READ)) 6468c2ecf20Sopenharmony_ci read = 0; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if (write && !kvm_msr_allowed(vcpu, msr, KVM_MSR_FILTER_WRITE)) 6498c2ecf20Sopenharmony_ci write = 0; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci offset = svm_msrpm_offset(msr); 6528c2ecf20Sopenharmony_ci bit_read = 2 * (msr & 0x0f); 6538c2ecf20Sopenharmony_ci bit_write = 2 * (msr & 0x0f) + 1; 6548c2ecf20Sopenharmony_ci tmp = msrpm[offset]; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci BUG_ON(offset == MSR_INVALID); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci read ? clear_bit(bit_read, &tmp) : set_bit(bit_read, &tmp); 6598c2ecf20Sopenharmony_ci write ? clear_bit(bit_write, &tmp) : set_bit(bit_write, &tmp); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci msrpm[offset] = tmp; 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic void set_msr_interception(struct kvm_vcpu *vcpu, u32 *msrpm, u32 msr, 6658c2ecf20Sopenharmony_ci int read, int write) 6668c2ecf20Sopenharmony_ci{ 6678c2ecf20Sopenharmony_ci set_shadow_msr_intercept(vcpu, msr, read, write); 6688c2ecf20Sopenharmony_ci set_msr_interception_bitmap(vcpu, msrpm, msr, read, write); 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ciu32 *svm_vcpu_alloc_msrpm(void) 6728c2ecf20Sopenharmony_ci{ 6738c2ecf20Sopenharmony_ci struct page *pages = alloc_pages(GFP_KERNEL_ACCOUNT, MSRPM_ALLOC_ORDER); 6748c2ecf20Sopenharmony_ci u32 *msrpm; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci if (!pages) 6778c2ecf20Sopenharmony_ci return NULL; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci msrpm = page_address(pages); 6808c2ecf20Sopenharmony_ci memset(msrpm, 0xff, PAGE_SIZE * (1 << MSRPM_ALLOC_ORDER)); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci return msrpm; 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_civoid svm_vcpu_init_msrpm(struct kvm_vcpu *vcpu, u32 *msrpm) 6868c2ecf20Sopenharmony_ci{ 6878c2ecf20Sopenharmony_ci int i; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci for (i = 0; direct_access_msrs[i].index != MSR_INVALID; i++) { 6908c2ecf20Sopenharmony_ci if (!direct_access_msrs[i].always) 6918c2ecf20Sopenharmony_ci continue; 6928c2ecf20Sopenharmony_ci set_msr_interception(vcpu, msrpm, direct_access_msrs[i].index, 1, 1); 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_civoid svm_vcpu_free_msrpm(u32 *msrpm) 6988c2ecf20Sopenharmony_ci{ 6998c2ecf20Sopenharmony_ci __free_pages(virt_to_page(msrpm), MSRPM_ALLOC_ORDER); 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic void svm_msr_filter_changed(struct kvm_vcpu *vcpu) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 7058c2ecf20Sopenharmony_ci u32 i; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci /* 7088c2ecf20Sopenharmony_ci * Set intercept permissions for all direct access MSRs again. They 7098c2ecf20Sopenharmony_ci * will automatically get filtered through the MSR filter, so we are 7108c2ecf20Sopenharmony_ci * back in sync after this. 7118c2ecf20Sopenharmony_ci */ 7128c2ecf20Sopenharmony_ci for (i = 0; direct_access_msrs[i].index != MSR_INVALID; i++) { 7138c2ecf20Sopenharmony_ci u32 msr = direct_access_msrs[i].index; 7148c2ecf20Sopenharmony_ci u32 read = test_bit(i, svm->shadow_msr_intercept.read); 7158c2ecf20Sopenharmony_ci u32 write = test_bit(i, svm->shadow_msr_intercept.write); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci set_msr_interception_bitmap(vcpu, svm->msrpm, msr, read, write); 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci} 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_cistatic void add_msr_offset(u32 offset) 7228c2ecf20Sopenharmony_ci{ 7238c2ecf20Sopenharmony_ci int i; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci for (i = 0; i < MSRPM_OFFSETS; ++i) { 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* Offset already in list? */ 7288c2ecf20Sopenharmony_ci if (msrpm_offsets[i] == offset) 7298c2ecf20Sopenharmony_ci return; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci /* Slot used by another offset? */ 7328c2ecf20Sopenharmony_ci if (msrpm_offsets[i] != MSR_INVALID) 7338c2ecf20Sopenharmony_ci continue; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci /* Add offset to list */ 7368c2ecf20Sopenharmony_ci msrpm_offsets[i] = offset; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci return; 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci /* 7428c2ecf20Sopenharmony_ci * If this BUG triggers the msrpm_offsets table has an overflow. Just 7438c2ecf20Sopenharmony_ci * increase MSRPM_OFFSETS in this case. 7448c2ecf20Sopenharmony_ci */ 7458c2ecf20Sopenharmony_ci BUG(); 7468c2ecf20Sopenharmony_ci} 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_cistatic void init_msrpm_offsets(void) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci int i; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci memset(msrpm_offsets, 0xff, sizeof(msrpm_offsets)); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci for (i = 0; direct_access_msrs[i].index != MSR_INVALID; i++) { 7558c2ecf20Sopenharmony_ci u32 offset; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci offset = svm_msrpm_offset(direct_access_msrs[i].index); 7588c2ecf20Sopenharmony_ci BUG_ON(offset == MSR_INVALID); 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci add_msr_offset(offset); 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic void svm_enable_lbrv(struct kvm_vcpu *vcpu) 7658c2ecf20Sopenharmony_ci{ 7668c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci svm->vmcb->control.virt_ext |= LBR_CTL_ENABLE_MASK; 7698c2ecf20Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTBRANCHFROMIP, 1, 1); 7708c2ecf20Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTBRANCHTOIP, 1, 1); 7718c2ecf20Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTINTFROMIP, 1, 1); 7728c2ecf20Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTINTTOIP, 1, 1); 7738c2ecf20Sopenharmony_ci} 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_cistatic void svm_disable_lbrv(struct kvm_vcpu *vcpu) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci svm->vmcb->control.virt_ext &= ~LBR_CTL_ENABLE_MASK; 7808c2ecf20Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTBRANCHFROMIP, 0, 0); 7818c2ecf20Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTBRANCHTOIP, 0, 0); 7828c2ecf20Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTINTFROMIP, 0, 0); 7838c2ecf20Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTINTTOIP, 0, 0); 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_civoid disable_nmi_singlestep(struct vcpu_svm *svm) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci svm->nmi_singlestep = false; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci if (!(svm->vcpu.guest_debug & KVM_GUESTDBG_SINGLESTEP)) { 7918c2ecf20Sopenharmony_ci /* Clear our flags if they were not set by the guest */ 7928c2ecf20Sopenharmony_ci if (!(svm->nmi_singlestep_guest_rflags & X86_EFLAGS_TF)) 7938c2ecf20Sopenharmony_ci svm->vmcb->save.rflags &= ~X86_EFLAGS_TF; 7948c2ecf20Sopenharmony_ci if (!(svm->nmi_singlestep_guest_rflags & X86_EFLAGS_RF)) 7958c2ecf20Sopenharmony_ci svm->vmcb->save.rflags &= ~X86_EFLAGS_RF; 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic void grow_ple_window(struct kvm_vcpu *vcpu) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 8028c2ecf20Sopenharmony_ci struct vmcb_control_area *control = &svm->vmcb->control; 8038c2ecf20Sopenharmony_ci int old = control->pause_filter_count; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci control->pause_filter_count = __grow_ple_window(old, 8068c2ecf20Sopenharmony_ci pause_filter_count, 8078c2ecf20Sopenharmony_ci pause_filter_count_grow, 8088c2ecf20Sopenharmony_ci pause_filter_count_max); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci if (control->pause_filter_count != old) { 8118c2ecf20Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_INTERCEPTS); 8128c2ecf20Sopenharmony_ci trace_kvm_ple_window_update(vcpu->vcpu_id, 8138c2ecf20Sopenharmony_ci control->pause_filter_count, old); 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_cistatic void shrink_ple_window(struct kvm_vcpu *vcpu) 8188c2ecf20Sopenharmony_ci{ 8198c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 8208c2ecf20Sopenharmony_ci struct vmcb_control_area *control = &svm->vmcb->control; 8218c2ecf20Sopenharmony_ci int old = control->pause_filter_count; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci control->pause_filter_count = 8248c2ecf20Sopenharmony_ci __shrink_ple_window(old, 8258c2ecf20Sopenharmony_ci pause_filter_count, 8268c2ecf20Sopenharmony_ci pause_filter_count_shrink, 8278c2ecf20Sopenharmony_ci pause_filter_count); 8288c2ecf20Sopenharmony_ci if (control->pause_filter_count != old) { 8298c2ecf20Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_INTERCEPTS); 8308c2ecf20Sopenharmony_ci trace_kvm_ple_window_update(vcpu->vcpu_id, 8318c2ecf20Sopenharmony_ci control->pause_filter_count, old); 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci/* 8368c2ecf20Sopenharmony_ci * The default MMIO mask is a single bit (excluding the present bit), 8378c2ecf20Sopenharmony_ci * which could conflict with the memory encryption bit. Check for 8388c2ecf20Sopenharmony_ci * memory encryption support and override the default MMIO mask if 8398c2ecf20Sopenharmony_ci * memory encryption is enabled. 8408c2ecf20Sopenharmony_ci */ 8418c2ecf20Sopenharmony_cistatic __init void svm_adjust_mmio_mask(void) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci unsigned int enc_bit, mask_bit; 8448c2ecf20Sopenharmony_ci u64 msr, mask; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci /* If there is no memory encryption support, use existing mask */ 8478c2ecf20Sopenharmony_ci if (cpuid_eax(0x80000000) < 0x8000001f) 8488c2ecf20Sopenharmony_ci return; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci /* If memory encryption is not enabled, use existing mask */ 8518c2ecf20Sopenharmony_ci rdmsrl(MSR_K8_SYSCFG, msr); 8528c2ecf20Sopenharmony_ci if (!(msr & MSR_K8_SYSCFG_MEM_ENCRYPT)) 8538c2ecf20Sopenharmony_ci return; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci enc_bit = cpuid_ebx(0x8000001f) & 0x3f; 8568c2ecf20Sopenharmony_ci mask_bit = boot_cpu_data.x86_phys_bits; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci /* Increment the mask bit if it is the same as the encryption bit */ 8598c2ecf20Sopenharmony_ci if (enc_bit == mask_bit) 8608c2ecf20Sopenharmony_ci mask_bit++; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci /* 8638c2ecf20Sopenharmony_ci * If the mask bit location is below 52, then some bits above the 8648c2ecf20Sopenharmony_ci * physical addressing limit will always be reserved, so use the 8658c2ecf20Sopenharmony_ci * rsvd_bits() function to generate the mask. This mask, along with 8668c2ecf20Sopenharmony_ci * the present bit, will be used to generate a page fault with 8678c2ecf20Sopenharmony_ci * PFER.RSV = 1. 8688c2ecf20Sopenharmony_ci * 8698c2ecf20Sopenharmony_ci * If the mask bit location is 52 (or above), then clear the mask. 8708c2ecf20Sopenharmony_ci */ 8718c2ecf20Sopenharmony_ci mask = (mask_bit < 52) ? rsvd_bits(mask_bit, 51) | PT_PRESENT_MASK : 0; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci kvm_mmu_set_mmio_spte_mask(mask, PT_WRITABLE_MASK | PT_USER_MASK); 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_cistatic void svm_hardware_teardown(void) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci int cpu; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci if (svm_sev_enabled()) 8818c2ecf20Sopenharmony_ci sev_hardware_teardown(); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) 8848c2ecf20Sopenharmony_ci svm_cpu_uninit(cpu); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci __free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER); 8878c2ecf20Sopenharmony_ci iopm_base = 0; 8888c2ecf20Sopenharmony_ci} 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_cistatic __init void svm_set_cpu_caps(void) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci kvm_set_cpu_caps(); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci supported_xss = 0; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci /* CPUID 0x80000001 and 0x8000000A (SVM features) */ 8978c2ecf20Sopenharmony_ci if (nested) { 8988c2ecf20Sopenharmony_ci kvm_cpu_cap_set(X86_FEATURE_SVM); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci if (nrips) 9018c2ecf20Sopenharmony_ci kvm_cpu_cap_set(X86_FEATURE_NRIPS); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci if (npt_enabled) 9048c2ecf20Sopenharmony_ci kvm_cpu_cap_set(X86_FEATURE_NPT); 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci /* CPUID 0x80000008 */ 9088c2ecf20Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_LS_CFG_SSBD) || 9098c2ecf20Sopenharmony_ci boot_cpu_has(X86_FEATURE_AMD_SSBD)) 9108c2ecf20Sopenharmony_ci kvm_cpu_cap_set(X86_FEATURE_VIRT_SSBD); 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci /* Enable INVPCID feature */ 9138c2ecf20Sopenharmony_ci kvm_cpu_cap_check_and_set(X86_FEATURE_INVPCID); 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cistatic __init int svm_hardware_setup(void) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci int cpu; 9198c2ecf20Sopenharmony_ci struct page *iopm_pages; 9208c2ecf20Sopenharmony_ci void *iopm_va; 9218c2ecf20Sopenharmony_ci int r; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci iopm_pages = alloc_pages(GFP_KERNEL, IOPM_ALLOC_ORDER); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci if (!iopm_pages) 9268c2ecf20Sopenharmony_ci return -ENOMEM; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci iopm_va = page_address(iopm_pages); 9298c2ecf20Sopenharmony_ci memset(iopm_va, 0xff, PAGE_SIZE * (1 << IOPM_ALLOC_ORDER)); 9308c2ecf20Sopenharmony_ci iopm_base = page_to_pfn(iopm_pages) << PAGE_SHIFT; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci init_msrpm_offsets(); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci supported_xcr0 &= ~(XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_NX)) 9378c2ecf20Sopenharmony_ci kvm_enable_efer_bits(EFER_NX); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_FXSR_OPT)) 9408c2ecf20Sopenharmony_ci kvm_enable_efer_bits(EFER_FFXSR); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_TSCRATEMSR)) { 9438c2ecf20Sopenharmony_ci kvm_has_tsc_control = true; 9448c2ecf20Sopenharmony_ci kvm_max_tsc_scaling_ratio = TSC_RATIO_MAX; 9458c2ecf20Sopenharmony_ci kvm_tsc_scaling_ratio_frac_bits = 32; 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci /* Check for pause filtering support */ 9498c2ecf20Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_PAUSEFILTER)) { 9508c2ecf20Sopenharmony_ci pause_filter_count = 0; 9518c2ecf20Sopenharmony_ci pause_filter_thresh = 0; 9528c2ecf20Sopenharmony_ci } else if (!boot_cpu_has(X86_FEATURE_PFTHRESHOLD)) { 9538c2ecf20Sopenharmony_ci pause_filter_thresh = 0; 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (nested) { 9578c2ecf20Sopenharmony_ci printk(KERN_INFO "kvm: Nested Virtualization enabled\n"); 9588c2ecf20Sopenharmony_ci kvm_enable_efer_bits(EFER_SVME | EFER_LMSLE); 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (sev) { 9628c2ecf20Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_SEV) && 9638c2ecf20Sopenharmony_ci IS_ENABLED(CONFIG_KVM_AMD_SEV)) { 9648c2ecf20Sopenharmony_ci r = sev_hardware_setup(); 9658c2ecf20Sopenharmony_ci if (r) 9668c2ecf20Sopenharmony_ci sev = false; 9678c2ecf20Sopenharmony_ci } else { 9688c2ecf20Sopenharmony_ci sev = false; 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci svm_adjust_mmio_mask(); 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 9758c2ecf20Sopenharmony_ci r = svm_cpu_init(cpu); 9768c2ecf20Sopenharmony_ci if (r) 9778c2ecf20Sopenharmony_ci goto err; 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_NPT)) 9818c2ecf20Sopenharmony_ci npt_enabled = false; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci if (npt_enabled && !npt) 9848c2ecf20Sopenharmony_ci npt_enabled = false; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci kvm_configure_mmu(npt_enabled, get_max_npt_level(), PG_LEVEL_1G); 9878c2ecf20Sopenharmony_ci pr_info("kvm: Nested Paging %sabled\n", npt_enabled ? "en" : "dis"); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (nrips) { 9908c2ecf20Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_NRIPS)) 9918c2ecf20Sopenharmony_ci nrips = false; 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci if (avic) { 9958c2ecf20Sopenharmony_ci if (!npt_enabled || 9968c2ecf20Sopenharmony_ci !boot_cpu_has(X86_FEATURE_AVIC) || 9978c2ecf20Sopenharmony_ci !IS_ENABLED(CONFIG_X86_LOCAL_APIC)) { 9988c2ecf20Sopenharmony_ci avic = false; 9998c2ecf20Sopenharmony_ci } else { 10008c2ecf20Sopenharmony_ci pr_info("AVIC enabled\n"); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci amd_iommu_register_ga_log_notifier(&avic_ga_log_notifier); 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci if (vls) { 10078c2ecf20Sopenharmony_ci if (!npt_enabled || 10088c2ecf20Sopenharmony_ci !boot_cpu_has(X86_FEATURE_V_VMSAVE_VMLOAD) || 10098c2ecf20Sopenharmony_ci !IS_ENABLED(CONFIG_X86_64)) { 10108c2ecf20Sopenharmony_ci vls = false; 10118c2ecf20Sopenharmony_ci } else { 10128c2ecf20Sopenharmony_ci pr_info("Virtual VMLOAD VMSAVE supported\n"); 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci if (vgif) { 10178c2ecf20Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_VGIF)) 10188c2ecf20Sopenharmony_ci vgif = false; 10198c2ecf20Sopenharmony_ci else 10208c2ecf20Sopenharmony_ci pr_info("Virtual GIF supported\n"); 10218c2ecf20Sopenharmony_ci } 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci svm_set_cpu_caps(); 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci /* 10268c2ecf20Sopenharmony_ci * It seems that on AMD processors PTE's accessed bit is 10278c2ecf20Sopenharmony_ci * being set by the CPU hardware before the NPF vmexit. 10288c2ecf20Sopenharmony_ci * This is not expected behaviour and our tests fail because 10298c2ecf20Sopenharmony_ci * of it. 10308c2ecf20Sopenharmony_ci * A workaround here is to disable support for 10318c2ecf20Sopenharmony_ci * GUEST_MAXPHYADDR < HOST_MAXPHYADDR if NPT is enabled. 10328c2ecf20Sopenharmony_ci * In this case userspace can know if there is support using 10338c2ecf20Sopenharmony_ci * KVM_CAP_SMALLER_MAXPHYADDR extension and decide how to handle 10348c2ecf20Sopenharmony_ci * it 10358c2ecf20Sopenharmony_ci * If future AMD CPU models change the behaviour described above, 10368c2ecf20Sopenharmony_ci * this variable can be changed accordingly 10378c2ecf20Sopenharmony_ci */ 10388c2ecf20Sopenharmony_ci allow_smaller_maxphyaddr = !npt_enabled; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci return 0; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_cierr: 10438c2ecf20Sopenharmony_ci svm_hardware_teardown(); 10448c2ecf20Sopenharmony_ci return r; 10458c2ecf20Sopenharmony_ci} 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_cistatic void init_seg(struct vmcb_seg *seg) 10488c2ecf20Sopenharmony_ci{ 10498c2ecf20Sopenharmony_ci seg->selector = 0; 10508c2ecf20Sopenharmony_ci seg->attrib = SVM_SELECTOR_P_MASK | SVM_SELECTOR_S_MASK | 10518c2ecf20Sopenharmony_ci SVM_SELECTOR_WRITE_MASK; /* Read/Write Data Segment */ 10528c2ecf20Sopenharmony_ci seg->limit = 0xffff; 10538c2ecf20Sopenharmony_ci seg->base = 0; 10548c2ecf20Sopenharmony_ci} 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_cistatic void init_sys_seg(struct vmcb_seg *seg, uint32_t type) 10578c2ecf20Sopenharmony_ci{ 10588c2ecf20Sopenharmony_ci seg->selector = 0; 10598c2ecf20Sopenharmony_ci seg->attrib = SVM_SELECTOR_P_MASK | type; 10608c2ecf20Sopenharmony_ci seg->limit = 0xffff; 10618c2ecf20Sopenharmony_ci seg->base = 0; 10628c2ecf20Sopenharmony_ci} 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_cistatic u64 svm_write_l1_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) 10658c2ecf20Sopenharmony_ci{ 10668c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 10678c2ecf20Sopenharmony_ci u64 g_tsc_offset = 0; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci if (is_guest_mode(vcpu)) { 10708c2ecf20Sopenharmony_ci /* Write L1's TSC offset. */ 10718c2ecf20Sopenharmony_ci g_tsc_offset = svm->vmcb->control.tsc_offset - 10728c2ecf20Sopenharmony_ci svm->nested.hsave->control.tsc_offset; 10738c2ecf20Sopenharmony_ci svm->nested.hsave->control.tsc_offset = offset; 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci trace_kvm_write_tsc_offset(vcpu->vcpu_id, 10778c2ecf20Sopenharmony_ci svm->vmcb->control.tsc_offset - g_tsc_offset, 10788c2ecf20Sopenharmony_ci offset); 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci svm->vmcb->control.tsc_offset = offset + g_tsc_offset; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_INTERCEPTS); 10838c2ecf20Sopenharmony_ci return svm->vmcb->control.tsc_offset; 10848c2ecf20Sopenharmony_ci} 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_cistatic void svm_check_invpcid(struct vcpu_svm *svm) 10878c2ecf20Sopenharmony_ci{ 10888c2ecf20Sopenharmony_ci /* 10898c2ecf20Sopenharmony_ci * Intercept INVPCID if shadow paging is enabled to sync/free shadow 10908c2ecf20Sopenharmony_ci * roots, or if INVPCID is disabled in the guest to inject #UD. 10918c2ecf20Sopenharmony_ci */ 10928c2ecf20Sopenharmony_ci if (kvm_cpu_cap_has(X86_FEATURE_INVPCID)) { 10938c2ecf20Sopenharmony_ci if (!npt_enabled || 10948c2ecf20Sopenharmony_ci !guest_cpuid_has(&svm->vcpu, X86_FEATURE_INVPCID)) 10958c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_INVPCID); 10968c2ecf20Sopenharmony_ci else 10978c2ecf20Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_INVPCID); 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci} 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_cistatic void init_vmcb(struct vcpu_svm *svm) 11028c2ecf20Sopenharmony_ci{ 11038c2ecf20Sopenharmony_ci struct vmcb_control_area *control = &svm->vmcb->control; 11048c2ecf20Sopenharmony_ci struct vmcb_save_area *save = &svm->vmcb->save; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci svm->vcpu.arch.hflags = 0; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CR0_READ); 11098c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CR3_READ); 11108c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CR4_READ); 11118c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CR0_WRITE); 11128c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CR3_WRITE); 11138c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CR4_WRITE); 11148c2ecf20Sopenharmony_ci if (!kvm_vcpu_apicv_active(&svm->vcpu)) 11158c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CR8_WRITE); 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci set_dr_intercepts(svm); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci set_exception_intercept(svm, PF_VECTOR); 11208c2ecf20Sopenharmony_ci set_exception_intercept(svm, UD_VECTOR); 11218c2ecf20Sopenharmony_ci set_exception_intercept(svm, MC_VECTOR); 11228c2ecf20Sopenharmony_ci set_exception_intercept(svm, AC_VECTOR); 11238c2ecf20Sopenharmony_ci set_exception_intercept(svm, DB_VECTOR); 11248c2ecf20Sopenharmony_ci /* 11258c2ecf20Sopenharmony_ci * Guest access to VMware backdoor ports could legitimately 11268c2ecf20Sopenharmony_ci * trigger #GP because of TSS I/O permission bitmap. 11278c2ecf20Sopenharmony_ci * We intercept those #GP and allow access to them anyway 11288c2ecf20Sopenharmony_ci * as VMware does. 11298c2ecf20Sopenharmony_ci */ 11308c2ecf20Sopenharmony_ci if (enable_vmware_backdoor) 11318c2ecf20Sopenharmony_ci set_exception_intercept(svm, GP_VECTOR); 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_INTR); 11348c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_NMI); 11358c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_SMI); 11368c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_SELECTIVE_CR0); 11378c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_RDPMC); 11388c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CPUID); 11398c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_INVD); 11408c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_INVLPG); 11418c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_INVLPGA); 11428c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_IOIO_PROT); 11438c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_MSR_PROT); 11448c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_TASK_SWITCH); 11458c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_SHUTDOWN); 11468c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_VMRUN); 11478c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_VMMCALL); 11488c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_VMLOAD); 11498c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_VMSAVE); 11508c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_STGI); 11518c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CLGI); 11528c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_SKINIT); 11538c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_WBINVD); 11548c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_XSETBV); 11558c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_RDPRU); 11568c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_RSM); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci if (!kvm_mwait_in_guest(svm->vcpu.kvm)) { 11598c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_MONITOR); 11608c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_MWAIT); 11618c2ecf20Sopenharmony_ci } 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci if (!kvm_hlt_in_guest(svm->vcpu.kvm)) 11648c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_HLT); 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci control->iopm_base_pa = __sme_set(iopm_base); 11678c2ecf20Sopenharmony_ci control->msrpm_base_pa = __sme_set(__pa(svm->msrpm)); 11688c2ecf20Sopenharmony_ci control->int_ctl = V_INTR_MASKING_MASK; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci init_seg(&save->es); 11718c2ecf20Sopenharmony_ci init_seg(&save->ss); 11728c2ecf20Sopenharmony_ci init_seg(&save->ds); 11738c2ecf20Sopenharmony_ci init_seg(&save->fs); 11748c2ecf20Sopenharmony_ci init_seg(&save->gs); 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci save->cs.selector = 0xf000; 11778c2ecf20Sopenharmony_ci save->cs.base = 0xffff0000; 11788c2ecf20Sopenharmony_ci /* Executable/Readable Code Segment */ 11798c2ecf20Sopenharmony_ci save->cs.attrib = SVM_SELECTOR_READ_MASK | SVM_SELECTOR_P_MASK | 11808c2ecf20Sopenharmony_ci SVM_SELECTOR_S_MASK | SVM_SELECTOR_CODE_MASK; 11818c2ecf20Sopenharmony_ci save->cs.limit = 0xffff; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci save->gdtr.limit = 0xffff; 11848c2ecf20Sopenharmony_ci save->idtr.limit = 0xffff; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci init_sys_seg(&save->ldtr, SEG_TYPE_LDT); 11878c2ecf20Sopenharmony_ci init_sys_seg(&save->tr, SEG_TYPE_BUSY_TSS16); 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci svm_set_cr4(&svm->vcpu, 0); 11908c2ecf20Sopenharmony_ci svm_set_efer(&svm->vcpu, 0); 11918c2ecf20Sopenharmony_ci save->dr6 = 0xffff0ff0; 11928c2ecf20Sopenharmony_ci kvm_set_rflags(&svm->vcpu, 2); 11938c2ecf20Sopenharmony_ci save->rip = 0x0000fff0; 11948c2ecf20Sopenharmony_ci svm->vcpu.arch.regs[VCPU_REGS_RIP] = save->rip; 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci /* 11978c2ecf20Sopenharmony_ci * svm_set_cr0() sets PG and WP and clears NW and CD on save->cr0. 11988c2ecf20Sopenharmony_ci * It also updates the guest-visible cr0 value. 11998c2ecf20Sopenharmony_ci */ 12008c2ecf20Sopenharmony_ci svm_set_cr0(&svm->vcpu, X86_CR0_NW | X86_CR0_CD | X86_CR0_ET); 12018c2ecf20Sopenharmony_ci kvm_mmu_reset_context(&svm->vcpu); 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci save->cr4 = X86_CR4_PAE; 12048c2ecf20Sopenharmony_ci /* rdx = ?? */ 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci if (npt_enabled) { 12078c2ecf20Sopenharmony_ci /* Setup VMCB for Nested Paging */ 12088c2ecf20Sopenharmony_ci control->nested_ctl |= SVM_NESTED_CTL_NP_ENABLE; 12098c2ecf20Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_INVLPG); 12108c2ecf20Sopenharmony_ci clr_exception_intercept(svm, PF_VECTOR); 12118c2ecf20Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_CR3_READ); 12128c2ecf20Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_CR3_WRITE); 12138c2ecf20Sopenharmony_ci save->g_pat = svm->vcpu.arch.pat; 12148c2ecf20Sopenharmony_ci save->cr3 = 0; 12158c2ecf20Sopenharmony_ci save->cr4 = 0; 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci svm->asid_generation = 0; 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci svm->nested.vmcb12_gpa = 0; 12208c2ecf20Sopenharmony_ci svm->vcpu.arch.hflags = 0; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci if (!kvm_pause_in_guest(svm->vcpu.kvm)) { 12238c2ecf20Sopenharmony_ci control->pause_filter_count = pause_filter_count; 12248c2ecf20Sopenharmony_ci if (pause_filter_thresh) 12258c2ecf20Sopenharmony_ci control->pause_filter_thresh = pause_filter_thresh; 12268c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_PAUSE); 12278c2ecf20Sopenharmony_ci } else { 12288c2ecf20Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_PAUSE); 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci svm_check_invpcid(svm); 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci if (kvm_vcpu_apicv_active(&svm->vcpu)) 12348c2ecf20Sopenharmony_ci avic_init_vmcb(svm); 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci /* 12378c2ecf20Sopenharmony_ci * If hardware supports Virtual VMLOAD VMSAVE then enable it 12388c2ecf20Sopenharmony_ci * in VMCB and clear intercepts to avoid #VMEXIT. 12398c2ecf20Sopenharmony_ci */ 12408c2ecf20Sopenharmony_ci if (vls) { 12418c2ecf20Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_VMLOAD); 12428c2ecf20Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_VMSAVE); 12438c2ecf20Sopenharmony_ci svm->vmcb->control.virt_ext |= VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK; 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci if (vgif) { 12478c2ecf20Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_STGI); 12488c2ecf20Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_CLGI); 12498c2ecf20Sopenharmony_ci svm->vmcb->control.int_ctl |= V_GIF_ENABLE_MASK; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci if (sev_guest(svm->vcpu.kvm)) { 12538c2ecf20Sopenharmony_ci svm->vmcb->control.nested_ctl |= SVM_NESTED_CTL_SEV_ENABLE; 12548c2ecf20Sopenharmony_ci clr_exception_intercept(svm, UD_VECTOR); 12558c2ecf20Sopenharmony_ci } 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci vmcb_mark_all_dirty(svm->vmcb); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci enable_gif(svm); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci} 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_cistatic void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) 12648c2ecf20Sopenharmony_ci{ 12658c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 12668c2ecf20Sopenharmony_ci u32 dummy; 12678c2ecf20Sopenharmony_ci u32 eax = 1; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci svm->spec_ctrl = 0; 12708c2ecf20Sopenharmony_ci svm->virt_spec_ctrl = 0; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci if (!init_event) { 12738c2ecf20Sopenharmony_ci svm->vcpu.arch.apic_base = APIC_DEFAULT_PHYS_BASE | 12748c2ecf20Sopenharmony_ci MSR_IA32_APICBASE_ENABLE; 12758c2ecf20Sopenharmony_ci if (kvm_vcpu_is_reset_bsp(&svm->vcpu)) 12768c2ecf20Sopenharmony_ci svm->vcpu.arch.apic_base |= MSR_IA32_APICBASE_BSP; 12778c2ecf20Sopenharmony_ci } 12788c2ecf20Sopenharmony_ci init_vmcb(svm); 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci kvm_cpuid(vcpu, &eax, &dummy, &dummy, &dummy, false); 12818c2ecf20Sopenharmony_ci kvm_rdx_write(vcpu, eax); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci if (kvm_vcpu_apicv_active(vcpu) && !init_event) 12848c2ecf20Sopenharmony_ci avic_update_vapic_bar(svm, APIC_DEFAULT_PHYS_BASE); 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_cistatic int svm_create_vcpu(struct kvm_vcpu *vcpu) 12888c2ecf20Sopenharmony_ci{ 12898c2ecf20Sopenharmony_ci struct vcpu_svm *svm; 12908c2ecf20Sopenharmony_ci struct page *vmcb_page; 12918c2ecf20Sopenharmony_ci int err; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(struct vcpu_svm, vcpu) != 0); 12948c2ecf20Sopenharmony_ci svm = to_svm(vcpu); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci err = -ENOMEM; 12978c2ecf20Sopenharmony_ci vmcb_page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO); 12988c2ecf20Sopenharmony_ci if (!vmcb_page) 12998c2ecf20Sopenharmony_ci goto out; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci err = avic_init_vcpu(svm); 13028c2ecf20Sopenharmony_ci if (err) 13038c2ecf20Sopenharmony_ci goto error_free_vmcb_page; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci /* We initialize this flag to true to make sure that the is_running 13068c2ecf20Sopenharmony_ci * bit would be set the first time the vcpu is loaded. 13078c2ecf20Sopenharmony_ci */ 13088c2ecf20Sopenharmony_ci if (irqchip_in_kernel(vcpu->kvm) && kvm_apicv_activated(vcpu->kvm)) 13098c2ecf20Sopenharmony_ci svm->avic_is_running = true; 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci svm->msrpm = svm_vcpu_alloc_msrpm(); 13128c2ecf20Sopenharmony_ci if (!svm->msrpm) { 13138c2ecf20Sopenharmony_ci err = -ENOMEM; 13148c2ecf20Sopenharmony_ci goto error_free_vmcb_page; 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci svm_vcpu_init_msrpm(vcpu, svm->msrpm); 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci svm->vmcb = page_address(vmcb_page); 13208c2ecf20Sopenharmony_ci svm->vmcb_pa = __sme_set(page_to_pfn(vmcb_page) << PAGE_SHIFT); 13218c2ecf20Sopenharmony_ci svm->asid_generation = 0; 13228c2ecf20Sopenharmony_ci init_vmcb(svm); 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci svm_init_osvw(vcpu); 13258c2ecf20Sopenharmony_ci vcpu->arch.microcode_version = 0x01000065; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci return 0; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_cierror_free_vmcb_page: 13308c2ecf20Sopenharmony_ci __free_page(vmcb_page); 13318c2ecf20Sopenharmony_ciout: 13328c2ecf20Sopenharmony_ci return err; 13338c2ecf20Sopenharmony_ci} 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_cistatic void svm_clear_current_vmcb(struct vmcb *vmcb) 13368c2ecf20Sopenharmony_ci{ 13378c2ecf20Sopenharmony_ci int i; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci for_each_online_cpu(i) 13408c2ecf20Sopenharmony_ci cmpxchg(&per_cpu(svm_data, i)->current_vmcb, vmcb, NULL); 13418c2ecf20Sopenharmony_ci} 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_cistatic void svm_free_vcpu(struct kvm_vcpu *vcpu) 13448c2ecf20Sopenharmony_ci{ 13458c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci /* 13488c2ecf20Sopenharmony_ci * The vmcb page can be recycled, causing a false negative in 13498c2ecf20Sopenharmony_ci * svm_vcpu_load(). So, ensure that no logical CPU has this 13508c2ecf20Sopenharmony_ci * vmcb page recorded as its current vmcb. 13518c2ecf20Sopenharmony_ci */ 13528c2ecf20Sopenharmony_ci svm_clear_current_vmcb(svm->vmcb); 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci svm_leave_nested(vcpu); 13558c2ecf20Sopenharmony_ci svm_free_nested(svm); 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci __free_page(pfn_to_page(__sme_clr(svm->vmcb_pa) >> PAGE_SHIFT)); 13588c2ecf20Sopenharmony_ci __free_pages(virt_to_page(svm->msrpm), MSRPM_ALLOC_ORDER); 13598c2ecf20Sopenharmony_ci} 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_cistatic void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu) 13628c2ecf20Sopenharmony_ci{ 13638c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 13648c2ecf20Sopenharmony_ci struct svm_cpu_data *sd = per_cpu(svm_data, cpu); 13658c2ecf20Sopenharmony_ci int i; 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci if (unlikely(cpu != vcpu->cpu)) { 13688c2ecf20Sopenharmony_ci svm->asid_generation = 0; 13698c2ecf20Sopenharmony_ci vmcb_mark_all_dirty(svm->vmcb); 13708c2ecf20Sopenharmony_ci } 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 13738c2ecf20Sopenharmony_ci rdmsrl(MSR_GS_BASE, to_svm(vcpu)->host.gs_base); 13748c2ecf20Sopenharmony_ci#endif 13758c2ecf20Sopenharmony_ci savesegment(fs, svm->host.fs); 13768c2ecf20Sopenharmony_ci savesegment(gs, svm->host.gs); 13778c2ecf20Sopenharmony_ci svm->host.ldt = kvm_read_ldt(); 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++) 13808c2ecf20Sopenharmony_ci rdmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]); 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci if (static_cpu_has(X86_FEATURE_TSCRATEMSR)) { 13838c2ecf20Sopenharmony_ci u64 tsc_ratio = vcpu->arch.tsc_scaling_ratio; 13848c2ecf20Sopenharmony_ci if (tsc_ratio != __this_cpu_read(current_tsc_ratio)) { 13858c2ecf20Sopenharmony_ci __this_cpu_write(current_tsc_ratio, tsc_ratio); 13868c2ecf20Sopenharmony_ci wrmsrl(MSR_AMD64_TSC_RATIO, tsc_ratio); 13878c2ecf20Sopenharmony_ci } 13888c2ecf20Sopenharmony_ci } 13898c2ecf20Sopenharmony_ci /* This assumes that the kernel never uses MSR_TSC_AUX */ 13908c2ecf20Sopenharmony_ci if (static_cpu_has(X86_FEATURE_RDTSCP)) 13918c2ecf20Sopenharmony_ci wrmsrl(MSR_TSC_AUX, svm->tsc_aux); 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci if (sd->current_vmcb != svm->vmcb) { 13948c2ecf20Sopenharmony_ci sd->current_vmcb = svm->vmcb; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci if (!cpu_feature_enabled(X86_FEATURE_IBPB_ON_VMEXIT)) 13978c2ecf20Sopenharmony_ci indirect_branch_prediction_barrier(); 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci avic_vcpu_load(vcpu, cpu); 14008c2ecf20Sopenharmony_ci} 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_cistatic void svm_vcpu_put(struct kvm_vcpu *vcpu) 14038c2ecf20Sopenharmony_ci{ 14048c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 14058c2ecf20Sopenharmony_ci int i; 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci avic_vcpu_put(vcpu); 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci ++vcpu->stat.host_state_reload; 14108c2ecf20Sopenharmony_ci kvm_load_ldt(svm->host.ldt); 14118c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 14128c2ecf20Sopenharmony_ci loadsegment(fs, svm->host.fs); 14138c2ecf20Sopenharmony_ci wrmsrl(MSR_KERNEL_GS_BASE, current->thread.gsbase); 14148c2ecf20Sopenharmony_ci load_gs_index(svm->host.gs); 14158c2ecf20Sopenharmony_ci#else 14168c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32_LAZY_GS 14178c2ecf20Sopenharmony_ci loadsegment(gs, svm->host.gs); 14188c2ecf20Sopenharmony_ci#endif 14198c2ecf20Sopenharmony_ci#endif 14208c2ecf20Sopenharmony_ci for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++) 14218c2ecf20Sopenharmony_ci wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]); 14228c2ecf20Sopenharmony_ci} 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_cistatic unsigned long svm_get_rflags(struct kvm_vcpu *vcpu) 14258c2ecf20Sopenharmony_ci{ 14268c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 14278c2ecf20Sopenharmony_ci unsigned long rflags = svm->vmcb->save.rflags; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci if (svm->nmi_singlestep) { 14308c2ecf20Sopenharmony_ci /* Hide our flags if they were not set by the guest */ 14318c2ecf20Sopenharmony_ci if (!(svm->nmi_singlestep_guest_rflags & X86_EFLAGS_TF)) 14328c2ecf20Sopenharmony_ci rflags &= ~X86_EFLAGS_TF; 14338c2ecf20Sopenharmony_ci if (!(svm->nmi_singlestep_guest_rflags & X86_EFLAGS_RF)) 14348c2ecf20Sopenharmony_ci rflags &= ~X86_EFLAGS_RF; 14358c2ecf20Sopenharmony_ci } 14368c2ecf20Sopenharmony_ci return rflags; 14378c2ecf20Sopenharmony_ci} 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_cistatic void svm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) 14408c2ecf20Sopenharmony_ci{ 14418c2ecf20Sopenharmony_ci if (to_svm(vcpu)->nmi_singlestep) 14428c2ecf20Sopenharmony_ci rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF); 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci /* 14458c2ecf20Sopenharmony_ci * Any change of EFLAGS.VM is accompanied by a reload of SS 14468c2ecf20Sopenharmony_ci * (caused by either a task switch or an inter-privilege IRET), 14478c2ecf20Sopenharmony_ci * so we do not need to update the CPL here. 14488c2ecf20Sopenharmony_ci */ 14498c2ecf20Sopenharmony_ci to_svm(vcpu)->vmcb->save.rflags = rflags; 14508c2ecf20Sopenharmony_ci} 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_cistatic void svm_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg) 14538c2ecf20Sopenharmony_ci{ 14548c2ecf20Sopenharmony_ci switch (reg) { 14558c2ecf20Sopenharmony_ci case VCPU_EXREG_PDPTR: 14568c2ecf20Sopenharmony_ci BUG_ON(!npt_enabled); 14578c2ecf20Sopenharmony_ci load_pdptrs(vcpu, vcpu->arch.walk_mmu, kvm_read_cr3(vcpu)); 14588c2ecf20Sopenharmony_ci break; 14598c2ecf20Sopenharmony_ci default: 14608c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 14618c2ecf20Sopenharmony_ci } 14628c2ecf20Sopenharmony_ci} 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_cistatic void svm_set_vintr(struct vcpu_svm *svm) 14658c2ecf20Sopenharmony_ci{ 14668c2ecf20Sopenharmony_ci struct vmcb_control_area *control; 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci /* The following fields are ignored when AVIC is enabled */ 14698c2ecf20Sopenharmony_ci WARN_ON(kvm_vcpu_apicv_active(&svm->vcpu)); 14708c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_VINTR); 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci /* 14738c2ecf20Sopenharmony_ci * This is just a dummy VINTR to actually cause a vmexit to happen. 14748c2ecf20Sopenharmony_ci * Actual injection of virtual interrupts happens through EVENTINJ. 14758c2ecf20Sopenharmony_ci */ 14768c2ecf20Sopenharmony_ci control = &svm->vmcb->control; 14778c2ecf20Sopenharmony_ci control->int_vector = 0x0; 14788c2ecf20Sopenharmony_ci control->int_ctl &= ~V_INTR_PRIO_MASK; 14798c2ecf20Sopenharmony_ci control->int_ctl |= V_IRQ_MASK | 14808c2ecf20Sopenharmony_ci ((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT); 14818c2ecf20Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_INTR); 14828c2ecf20Sopenharmony_ci} 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_cistatic void svm_clear_vintr(struct vcpu_svm *svm) 14858c2ecf20Sopenharmony_ci{ 14868c2ecf20Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_VINTR); 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci /* Drop int_ctl fields related to VINTR injection. */ 14898c2ecf20Sopenharmony_ci svm->vmcb->control.int_ctl &= ~V_IRQ_INJECTION_BITS_MASK; 14908c2ecf20Sopenharmony_ci if (is_guest_mode(&svm->vcpu)) { 14918c2ecf20Sopenharmony_ci svm->nested.hsave->control.int_ctl &= ~V_IRQ_INJECTION_BITS_MASK; 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci WARN_ON((svm->vmcb->control.int_ctl & V_TPR_MASK) != 14948c2ecf20Sopenharmony_ci (svm->nested.ctl.int_ctl & V_TPR_MASK)); 14958c2ecf20Sopenharmony_ci svm->vmcb->control.int_ctl |= svm->nested.ctl.int_ctl & 14968c2ecf20Sopenharmony_ci V_IRQ_INJECTION_BITS_MASK; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci svm->vmcb->control.int_vector = svm->nested.ctl.int_vector; 14998c2ecf20Sopenharmony_ci } 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_INTR); 15028c2ecf20Sopenharmony_ci} 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_cistatic struct vmcb_seg *svm_seg(struct kvm_vcpu *vcpu, int seg) 15058c2ecf20Sopenharmony_ci{ 15068c2ecf20Sopenharmony_ci struct vmcb_save_area *save = &to_svm(vcpu)->vmcb->save; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci switch (seg) { 15098c2ecf20Sopenharmony_ci case VCPU_SREG_CS: return &save->cs; 15108c2ecf20Sopenharmony_ci case VCPU_SREG_DS: return &save->ds; 15118c2ecf20Sopenharmony_ci case VCPU_SREG_ES: return &save->es; 15128c2ecf20Sopenharmony_ci case VCPU_SREG_FS: return &save->fs; 15138c2ecf20Sopenharmony_ci case VCPU_SREG_GS: return &save->gs; 15148c2ecf20Sopenharmony_ci case VCPU_SREG_SS: return &save->ss; 15158c2ecf20Sopenharmony_ci case VCPU_SREG_TR: return &save->tr; 15168c2ecf20Sopenharmony_ci case VCPU_SREG_LDTR: return &save->ldtr; 15178c2ecf20Sopenharmony_ci } 15188c2ecf20Sopenharmony_ci BUG(); 15198c2ecf20Sopenharmony_ci return NULL; 15208c2ecf20Sopenharmony_ci} 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_cistatic u64 svm_get_segment_base(struct kvm_vcpu *vcpu, int seg) 15238c2ecf20Sopenharmony_ci{ 15248c2ecf20Sopenharmony_ci struct vmcb_seg *s = svm_seg(vcpu, seg); 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci return s->base; 15278c2ecf20Sopenharmony_ci} 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_cistatic void svm_get_segment(struct kvm_vcpu *vcpu, 15308c2ecf20Sopenharmony_ci struct kvm_segment *var, int seg) 15318c2ecf20Sopenharmony_ci{ 15328c2ecf20Sopenharmony_ci struct vmcb_seg *s = svm_seg(vcpu, seg); 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci var->base = s->base; 15358c2ecf20Sopenharmony_ci var->limit = s->limit; 15368c2ecf20Sopenharmony_ci var->selector = s->selector; 15378c2ecf20Sopenharmony_ci var->type = s->attrib & SVM_SELECTOR_TYPE_MASK; 15388c2ecf20Sopenharmony_ci var->s = (s->attrib >> SVM_SELECTOR_S_SHIFT) & 1; 15398c2ecf20Sopenharmony_ci var->dpl = (s->attrib >> SVM_SELECTOR_DPL_SHIFT) & 3; 15408c2ecf20Sopenharmony_ci var->present = (s->attrib >> SVM_SELECTOR_P_SHIFT) & 1; 15418c2ecf20Sopenharmony_ci var->avl = (s->attrib >> SVM_SELECTOR_AVL_SHIFT) & 1; 15428c2ecf20Sopenharmony_ci var->l = (s->attrib >> SVM_SELECTOR_L_SHIFT) & 1; 15438c2ecf20Sopenharmony_ci var->db = (s->attrib >> SVM_SELECTOR_DB_SHIFT) & 1; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci /* 15468c2ecf20Sopenharmony_ci * AMD CPUs circa 2014 track the G bit for all segments except CS. 15478c2ecf20Sopenharmony_ci * However, the SVM spec states that the G bit is not observed by the 15488c2ecf20Sopenharmony_ci * CPU, and some VMware virtual CPUs drop the G bit for all segments. 15498c2ecf20Sopenharmony_ci * So let's synthesize a legal G bit for all segments, this helps 15508c2ecf20Sopenharmony_ci * running KVM nested. It also helps cross-vendor migration, because 15518c2ecf20Sopenharmony_ci * Intel's vmentry has a check on the 'G' bit. 15528c2ecf20Sopenharmony_ci */ 15538c2ecf20Sopenharmony_ci var->g = s->limit > 0xfffff; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci /* 15568c2ecf20Sopenharmony_ci * AMD's VMCB does not have an explicit unusable field, so emulate it 15578c2ecf20Sopenharmony_ci * for cross vendor migration purposes by "not present" 15588c2ecf20Sopenharmony_ci */ 15598c2ecf20Sopenharmony_ci var->unusable = !var->present; 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci switch (seg) { 15628c2ecf20Sopenharmony_ci case VCPU_SREG_TR: 15638c2ecf20Sopenharmony_ci /* 15648c2ecf20Sopenharmony_ci * Work around a bug where the busy flag in the tr selector 15658c2ecf20Sopenharmony_ci * isn't exposed 15668c2ecf20Sopenharmony_ci */ 15678c2ecf20Sopenharmony_ci var->type |= 0x2; 15688c2ecf20Sopenharmony_ci break; 15698c2ecf20Sopenharmony_ci case VCPU_SREG_DS: 15708c2ecf20Sopenharmony_ci case VCPU_SREG_ES: 15718c2ecf20Sopenharmony_ci case VCPU_SREG_FS: 15728c2ecf20Sopenharmony_ci case VCPU_SREG_GS: 15738c2ecf20Sopenharmony_ci /* 15748c2ecf20Sopenharmony_ci * The accessed bit must always be set in the segment 15758c2ecf20Sopenharmony_ci * descriptor cache, although it can be cleared in the 15768c2ecf20Sopenharmony_ci * descriptor, the cached bit always remains at 1. Since 15778c2ecf20Sopenharmony_ci * Intel has a check on this, set it here to support 15788c2ecf20Sopenharmony_ci * cross-vendor migration. 15798c2ecf20Sopenharmony_ci */ 15808c2ecf20Sopenharmony_ci if (!var->unusable) 15818c2ecf20Sopenharmony_ci var->type |= 0x1; 15828c2ecf20Sopenharmony_ci break; 15838c2ecf20Sopenharmony_ci case VCPU_SREG_SS: 15848c2ecf20Sopenharmony_ci /* 15858c2ecf20Sopenharmony_ci * On AMD CPUs sometimes the DB bit in the segment 15868c2ecf20Sopenharmony_ci * descriptor is left as 1, although the whole segment has 15878c2ecf20Sopenharmony_ci * been made unusable. Clear it here to pass an Intel VMX 15888c2ecf20Sopenharmony_ci * entry check when cross vendor migrating. 15898c2ecf20Sopenharmony_ci */ 15908c2ecf20Sopenharmony_ci if (var->unusable) 15918c2ecf20Sopenharmony_ci var->db = 0; 15928c2ecf20Sopenharmony_ci /* This is symmetric with svm_set_segment() */ 15938c2ecf20Sopenharmony_ci var->dpl = to_svm(vcpu)->vmcb->save.cpl; 15948c2ecf20Sopenharmony_ci break; 15958c2ecf20Sopenharmony_ci } 15968c2ecf20Sopenharmony_ci} 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_cistatic int svm_get_cpl(struct kvm_vcpu *vcpu) 15998c2ecf20Sopenharmony_ci{ 16008c2ecf20Sopenharmony_ci struct vmcb_save_area *save = &to_svm(vcpu)->vmcb->save; 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci return save->cpl; 16038c2ecf20Sopenharmony_ci} 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_cistatic void svm_get_idt(struct kvm_vcpu *vcpu, struct desc_ptr *dt) 16068c2ecf20Sopenharmony_ci{ 16078c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci dt->size = svm->vmcb->save.idtr.limit; 16108c2ecf20Sopenharmony_ci dt->address = svm->vmcb->save.idtr.base; 16118c2ecf20Sopenharmony_ci} 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_cistatic void svm_set_idt(struct kvm_vcpu *vcpu, struct desc_ptr *dt) 16148c2ecf20Sopenharmony_ci{ 16158c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci svm->vmcb->save.idtr.limit = dt->size; 16188c2ecf20Sopenharmony_ci svm->vmcb->save.idtr.base = dt->address ; 16198c2ecf20Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_DT); 16208c2ecf20Sopenharmony_ci} 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_cistatic void svm_get_gdt(struct kvm_vcpu *vcpu, struct desc_ptr *dt) 16238c2ecf20Sopenharmony_ci{ 16248c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci dt->size = svm->vmcb->save.gdtr.limit; 16278c2ecf20Sopenharmony_ci dt->address = svm->vmcb->save.gdtr.base; 16288c2ecf20Sopenharmony_ci} 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_cistatic void svm_set_gdt(struct kvm_vcpu *vcpu, struct desc_ptr *dt) 16318c2ecf20Sopenharmony_ci{ 16328c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci svm->vmcb->save.gdtr.limit = dt->size; 16358c2ecf20Sopenharmony_ci svm->vmcb->save.gdtr.base = dt->address ; 16368c2ecf20Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_DT); 16378c2ecf20Sopenharmony_ci} 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_cistatic void update_cr0_intercept(struct vcpu_svm *svm) 16408c2ecf20Sopenharmony_ci{ 16418c2ecf20Sopenharmony_ci ulong gcr0 = svm->vcpu.arch.cr0; 16428c2ecf20Sopenharmony_ci u64 *hcr0 = &svm->vmcb->save.cr0; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci *hcr0 = (*hcr0 & ~SVM_CR0_SELECTIVE_MASK) 16458c2ecf20Sopenharmony_ci | (gcr0 & SVM_CR0_SELECTIVE_MASK); 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_CR); 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci if (gcr0 == *hcr0) { 16508c2ecf20Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_CR0_READ); 16518c2ecf20Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_CR0_WRITE); 16528c2ecf20Sopenharmony_ci } else { 16538c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CR0_READ); 16548c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CR0_WRITE); 16558c2ecf20Sopenharmony_ci } 16568c2ecf20Sopenharmony_ci} 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_civoid svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) 16598c2ecf20Sopenharmony_ci{ 16608c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 16638c2ecf20Sopenharmony_ci if (vcpu->arch.efer & EFER_LME) { 16648c2ecf20Sopenharmony_ci if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) { 16658c2ecf20Sopenharmony_ci vcpu->arch.efer |= EFER_LMA; 16668c2ecf20Sopenharmony_ci svm->vmcb->save.efer |= EFER_LMA | EFER_LME; 16678c2ecf20Sopenharmony_ci } 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci if (is_paging(vcpu) && !(cr0 & X86_CR0_PG)) { 16708c2ecf20Sopenharmony_ci vcpu->arch.efer &= ~EFER_LMA; 16718c2ecf20Sopenharmony_ci svm->vmcb->save.efer &= ~(EFER_LMA | EFER_LME); 16728c2ecf20Sopenharmony_ci } 16738c2ecf20Sopenharmony_ci } 16748c2ecf20Sopenharmony_ci#endif 16758c2ecf20Sopenharmony_ci vcpu->arch.cr0 = cr0; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci if (!npt_enabled) 16788c2ecf20Sopenharmony_ci cr0 |= X86_CR0_PG | X86_CR0_WP; 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci /* 16818c2ecf20Sopenharmony_ci * re-enable caching here because the QEMU bios 16828c2ecf20Sopenharmony_ci * does not do it - this results in some delay at 16838c2ecf20Sopenharmony_ci * reboot 16848c2ecf20Sopenharmony_ci */ 16858c2ecf20Sopenharmony_ci if (kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_CD_NW_CLEARED)) 16868c2ecf20Sopenharmony_ci cr0 &= ~(X86_CR0_CD | X86_CR0_NW); 16878c2ecf20Sopenharmony_ci svm->vmcb->save.cr0 = cr0; 16888c2ecf20Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_CR); 16898c2ecf20Sopenharmony_ci update_cr0_intercept(svm); 16908c2ecf20Sopenharmony_ci} 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_cistatic bool svm_is_valid_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) 16938c2ecf20Sopenharmony_ci{ 16948c2ecf20Sopenharmony_ci return true; 16958c2ecf20Sopenharmony_ci} 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_civoid svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) 16988c2ecf20Sopenharmony_ci{ 16998c2ecf20Sopenharmony_ci unsigned long host_cr4_mce = cr4_read_shadow() & X86_CR4_MCE; 17008c2ecf20Sopenharmony_ci unsigned long old_cr4 = to_svm(vcpu)->vmcb->save.cr4; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci if (npt_enabled && ((old_cr4 ^ cr4) & X86_CR4_PGE)) 17038c2ecf20Sopenharmony_ci svm_flush_tlb(vcpu); 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci vcpu->arch.cr4 = cr4; 17068c2ecf20Sopenharmony_ci if (!npt_enabled) 17078c2ecf20Sopenharmony_ci cr4 |= X86_CR4_PAE; 17088c2ecf20Sopenharmony_ci cr4 |= host_cr4_mce; 17098c2ecf20Sopenharmony_ci to_svm(vcpu)->vmcb->save.cr4 = cr4; 17108c2ecf20Sopenharmony_ci vmcb_mark_dirty(to_svm(vcpu)->vmcb, VMCB_CR); 17118c2ecf20Sopenharmony_ci} 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_cistatic void svm_set_segment(struct kvm_vcpu *vcpu, 17148c2ecf20Sopenharmony_ci struct kvm_segment *var, int seg) 17158c2ecf20Sopenharmony_ci{ 17168c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 17178c2ecf20Sopenharmony_ci struct vmcb_seg *s = svm_seg(vcpu, seg); 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci s->base = var->base; 17208c2ecf20Sopenharmony_ci s->limit = var->limit; 17218c2ecf20Sopenharmony_ci s->selector = var->selector; 17228c2ecf20Sopenharmony_ci s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK); 17238c2ecf20Sopenharmony_ci s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT; 17248c2ecf20Sopenharmony_ci s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT; 17258c2ecf20Sopenharmony_ci s->attrib |= ((var->present & 1) && !var->unusable) << SVM_SELECTOR_P_SHIFT; 17268c2ecf20Sopenharmony_ci s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT; 17278c2ecf20Sopenharmony_ci s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT; 17288c2ecf20Sopenharmony_ci s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT; 17298c2ecf20Sopenharmony_ci s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT; 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci /* 17328c2ecf20Sopenharmony_ci * This is always accurate, except if SYSRET returned to a segment 17338c2ecf20Sopenharmony_ci * with SS.DPL != 3. Intel does not have this quirk, and always 17348c2ecf20Sopenharmony_ci * forces SS.DPL to 3 on sysret, so we ignore that case; fixing it 17358c2ecf20Sopenharmony_ci * would entail passing the CPL to userspace and back. 17368c2ecf20Sopenharmony_ci */ 17378c2ecf20Sopenharmony_ci if (seg == VCPU_SREG_SS) 17388c2ecf20Sopenharmony_ci /* This is symmetric with svm_get_segment() */ 17398c2ecf20Sopenharmony_ci svm->vmcb->save.cpl = (var->dpl & 3); 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_SEG); 17428c2ecf20Sopenharmony_ci} 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_cistatic void update_exception_bitmap(struct kvm_vcpu *vcpu) 17458c2ecf20Sopenharmony_ci{ 17468c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci clr_exception_intercept(svm, BP_VECTOR); 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci if (vcpu->guest_debug & KVM_GUESTDBG_ENABLE) { 17518c2ecf20Sopenharmony_ci if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) 17528c2ecf20Sopenharmony_ci set_exception_intercept(svm, BP_VECTOR); 17538c2ecf20Sopenharmony_ci } 17548c2ecf20Sopenharmony_ci} 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_cistatic void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *sd) 17578c2ecf20Sopenharmony_ci{ 17588c2ecf20Sopenharmony_ci if (sd->next_asid > sd->max_asid) { 17598c2ecf20Sopenharmony_ci ++sd->asid_generation; 17608c2ecf20Sopenharmony_ci sd->next_asid = sd->min_asid; 17618c2ecf20Sopenharmony_ci svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID; 17628c2ecf20Sopenharmony_ci } 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci svm->asid_generation = sd->asid_generation; 17658c2ecf20Sopenharmony_ci svm->vmcb->control.asid = sd->next_asid++; 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_ASID); 17688c2ecf20Sopenharmony_ci} 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_cistatic void svm_set_dr6(struct vcpu_svm *svm, unsigned long value) 17718c2ecf20Sopenharmony_ci{ 17728c2ecf20Sopenharmony_ci struct vmcb *vmcb = svm->vmcb; 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci if (unlikely(value != vmcb->save.dr6)) { 17758c2ecf20Sopenharmony_ci vmcb->save.dr6 = value; 17768c2ecf20Sopenharmony_ci vmcb_mark_dirty(vmcb, VMCB_DR); 17778c2ecf20Sopenharmony_ci } 17788c2ecf20Sopenharmony_ci} 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_cistatic void svm_sync_dirty_debug_regs(struct kvm_vcpu *vcpu) 17818c2ecf20Sopenharmony_ci{ 17828c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci get_debugreg(vcpu->arch.db[0], 0); 17858c2ecf20Sopenharmony_ci get_debugreg(vcpu->arch.db[1], 1); 17868c2ecf20Sopenharmony_ci get_debugreg(vcpu->arch.db[2], 2); 17878c2ecf20Sopenharmony_ci get_debugreg(vcpu->arch.db[3], 3); 17888c2ecf20Sopenharmony_ci /* 17898c2ecf20Sopenharmony_ci * We cannot reset svm->vmcb->save.dr6 to DR6_FIXED_1|DR6_RTM here, 17908c2ecf20Sopenharmony_ci * because db_interception might need it. We can do it before vmentry. 17918c2ecf20Sopenharmony_ci */ 17928c2ecf20Sopenharmony_ci vcpu->arch.dr6 = svm->vmcb->save.dr6; 17938c2ecf20Sopenharmony_ci vcpu->arch.dr7 = svm->vmcb->save.dr7; 17948c2ecf20Sopenharmony_ci vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_WONT_EXIT; 17958c2ecf20Sopenharmony_ci set_dr_intercepts(svm); 17968c2ecf20Sopenharmony_ci} 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_cistatic void svm_set_dr7(struct kvm_vcpu *vcpu, unsigned long value) 17998c2ecf20Sopenharmony_ci{ 18008c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci svm->vmcb->save.dr7 = value; 18038c2ecf20Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_DR); 18048c2ecf20Sopenharmony_ci} 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_cistatic int pf_interception(struct vcpu_svm *svm) 18078c2ecf20Sopenharmony_ci{ 18088c2ecf20Sopenharmony_ci u64 fault_address = svm->vmcb->control.exit_info_2; 18098c2ecf20Sopenharmony_ci u64 error_code = svm->vmcb->control.exit_info_1; 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci return kvm_handle_page_fault(&svm->vcpu, error_code, fault_address, 18128c2ecf20Sopenharmony_ci static_cpu_has(X86_FEATURE_DECODEASSISTS) ? 18138c2ecf20Sopenharmony_ci svm->vmcb->control.insn_bytes : NULL, 18148c2ecf20Sopenharmony_ci svm->vmcb->control.insn_len); 18158c2ecf20Sopenharmony_ci} 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_cistatic int npf_interception(struct vcpu_svm *svm) 18188c2ecf20Sopenharmony_ci{ 18198c2ecf20Sopenharmony_ci u64 fault_address = __sme_clr(svm->vmcb->control.exit_info_2); 18208c2ecf20Sopenharmony_ci u64 error_code = svm->vmcb->control.exit_info_1; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci trace_kvm_page_fault(fault_address, error_code); 18238c2ecf20Sopenharmony_ci return kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code, 18248c2ecf20Sopenharmony_ci static_cpu_has(X86_FEATURE_DECODEASSISTS) ? 18258c2ecf20Sopenharmony_ci svm->vmcb->control.insn_bytes : NULL, 18268c2ecf20Sopenharmony_ci svm->vmcb->control.insn_len); 18278c2ecf20Sopenharmony_ci} 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_cistatic int db_interception(struct vcpu_svm *svm) 18308c2ecf20Sopenharmony_ci{ 18318c2ecf20Sopenharmony_ci struct kvm_run *kvm_run = svm->vcpu.run; 18328c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = &svm->vcpu; 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci if (!(svm->vcpu.guest_debug & 18358c2ecf20Sopenharmony_ci (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)) && 18368c2ecf20Sopenharmony_ci !svm->nmi_singlestep) { 18378c2ecf20Sopenharmony_ci u32 payload = (svm->vmcb->save.dr6 ^ DR6_RTM) & ~DR6_FIXED_1; 18388c2ecf20Sopenharmony_ci kvm_queue_exception_p(&svm->vcpu, DB_VECTOR, payload); 18398c2ecf20Sopenharmony_ci return 1; 18408c2ecf20Sopenharmony_ci } 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci if (svm->nmi_singlestep) { 18438c2ecf20Sopenharmony_ci disable_nmi_singlestep(svm); 18448c2ecf20Sopenharmony_ci /* Make sure we check for pending NMIs upon entry */ 18458c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_EVENT, vcpu); 18468c2ecf20Sopenharmony_ci } 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci if (svm->vcpu.guest_debug & 18498c2ecf20Sopenharmony_ci (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)) { 18508c2ecf20Sopenharmony_ci kvm_run->exit_reason = KVM_EXIT_DEBUG; 18518c2ecf20Sopenharmony_ci kvm_run->debug.arch.dr6 = svm->vmcb->save.dr6; 18528c2ecf20Sopenharmony_ci kvm_run->debug.arch.dr7 = svm->vmcb->save.dr7; 18538c2ecf20Sopenharmony_ci kvm_run->debug.arch.pc = 18548c2ecf20Sopenharmony_ci svm->vmcb->save.cs.base + svm->vmcb->save.rip; 18558c2ecf20Sopenharmony_ci kvm_run->debug.arch.exception = DB_VECTOR; 18568c2ecf20Sopenharmony_ci return 0; 18578c2ecf20Sopenharmony_ci } 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci return 1; 18608c2ecf20Sopenharmony_ci} 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_cistatic int bp_interception(struct vcpu_svm *svm) 18638c2ecf20Sopenharmony_ci{ 18648c2ecf20Sopenharmony_ci struct kvm_run *kvm_run = svm->vcpu.run; 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci kvm_run->exit_reason = KVM_EXIT_DEBUG; 18678c2ecf20Sopenharmony_ci kvm_run->debug.arch.pc = svm->vmcb->save.cs.base + svm->vmcb->save.rip; 18688c2ecf20Sopenharmony_ci kvm_run->debug.arch.exception = BP_VECTOR; 18698c2ecf20Sopenharmony_ci return 0; 18708c2ecf20Sopenharmony_ci} 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_cistatic int ud_interception(struct vcpu_svm *svm) 18738c2ecf20Sopenharmony_ci{ 18748c2ecf20Sopenharmony_ci return handle_ud(&svm->vcpu); 18758c2ecf20Sopenharmony_ci} 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_cistatic int ac_interception(struct vcpu_svm *svm) 18788c2ecf20Sopenharmony_ci{ 18798c2ecf20Sopenharmony_ci kvm_queue_exception_e(&svm->vcpu, AC_VECTOR, 0); 18808c2ecf20Sopenharmony_ci return 1; 18818c2ecf20Sopenharmony_ci} 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_cistatic int gp_interception(struct vcpu_svm *svm) 18848c2ecf20Sopenharmony_ci{ 18858c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = &svm->vcpu; 18868c2ecf20Sopenharmony_ci u32 error_code = svm->vmcb->control.exit_info_1; 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci WARN_ON_ONCE(!enable_vmware_backdoor); 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci /* 18918c2ecf20Sopenharmony_ci * VMware backdoor emulation on #GP interception only handles IN{S}, 18928c2ecf20Sopenharmony_ci * OUT{S}, and RDPMC, none of which generate a non-zero error code. 18938c2ecf20Sopenharmony_ci */ 18948c2ecf20Sopenharmony_ci if (error_code) { 18958c2ecf20Sopenharmony_ci kvm_queue_exception_e(vcpu, GP_VECTOR, error_code); 18968c2ecf20Sopenharmony_ci return 1; 18978c2ecf20Sopenharmony_ci } 18988c2ecf20Sopenharmony_ci return kvm_emulate_instruction(vcpu, EMULTYPE_VMWARE_GP); 18998c2ecf20Sopenharmony_ci} 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_cistatic bool is_erratum_383(void) 19028c2ecf20Sopenharmony_ci{ 19038c2ecf20Sopenharmony_ci int err, i; 19048c2ecf20Sopenharmony_ci u64 value; 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci if (!erratum_383_found) 19078c2ecf20Sopenharmony_ci return false; 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci value = native_read_msr_safe(MSR_IA32_MC0_STATUS, &err); 19108c2ecf20Sopenharmony_ci if (err) 19118c2ecf20Sopenharmony_ci return false; 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci /* Bit 62 may or may not be set for this mce */ 19148c2ecf20Sopenharmony_ci value &= ~(1ULL << 62); 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci if (value != 0xb600000000010015ULL) 19178c2ecf20Sopenharmony_ci return false; 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci /* Clear MCi_STATUS registers */ 19208c2ecf20Sopenharmony_ci for (i = 0; i < 6; ++i) 19218c2ecf20Sopenharmony_ci native_write_msr_safe(MSR_IA32_MCx_STATUS(i), 0, 0); 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci value = native_read_msr_safe(MSR_IA32_MCG_STATUS, &err); 19248c2ecf20Sopenharmony_ci if (!err) { 19258c2ecf20Sopenharmony_ci u32 low, high; 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci value &= ~(1ULL << 2); 19288c2ecf20Sopenharmony_ci low = lower_32_bits(value); 19298c2ecf20Sopenharmony_ci high = upper_32_bits(value); 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci native_write_msr_safe(MSR_IA32_MCG_STATUS, low, high); 19328c2ecf20Sopenharmony_ci } 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci /* Flush tlb to evict multi-match entries */ 19358c2ecf20Sopenharmony_ci __flush_tlb_all(); 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci return true; 19388c2ecf20Sopenharmony_ci} 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci/* 19418c2ecf20Sopenharmony_ci * Trigger machine check on the host. We assume all the MSRs are already set up 19428c2ecf20Sopenharmony_ci * by the CPU and that we still run on the same CPU as the MCE occurred on. 19438c2ecf20Sopenharmony_ci * We pass a fake environment to the machine check handler because we want 19448c2ecf20Sopenharmony_ci * the guest to be always treated like user space, no matter what context 19458c2ecf20Sopenharmony_ci * it used internally. 19468c2ecf20Sopenharmony_ci */ 19478c2ecf20Sopenharmony_cistatic void kvm_machine_check(void) 19488c2ecf20Sopenharmony_ci{ 19498c2ecf20Sopenharmony_ci#if defined(CONFIG_X86_MCE) 19508c2ecf20Sopenharmony_ci struct pt_regs regs = { 19518c2ecf20Sopenharmony_ci .cs = 3, /* Fake ring 3 no matter what the guest ran on */ 19528c2ecf20Sopenharmony_ci .flags = X86_EFLAGS_IF, 19538c2ecf20Sopenharmony_ci }; 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci do_machine_check(®s); 19568c2ecf20Sopenharmony_ci#endif 19578c2ecf20Sopenharmony_ci} 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_cistatic void svm_handle_mce(struct vcpu_svm *svm) 19608c2ecf20Sopenharmony_ci{ 19618c2ecf20Sopenharmony_ci if (is_erratum_383()) { 19628c2ecf20Sopenharmony_ci /* 19638c2ecf20Sopenharmony_ci * Erratum 383 triggered. Guest state is corrupt so kill the 19648c2ecf20Sopenharmony_ci * guest. 19658c2ecf20Sopenharmony_ci */ 19668c2ecf20Sopenharmony_ci pr_err("KVM: Guest triggered AMD Erratum 383\n"); 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_TRIPLE_FAULT, &svm->vcpu); 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci return; 19718c2ecf20Sopenharmony_ci } 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ci /* 19748c2ecf20Sopenharmony_ci * On an #MC intercept the MCE handler is not called automatically in 19758c2ecf20Sopenharmony_ci * the host. So do it by hand here. 19768c2ecf20Sopenharmony_ci */ 19778c2ecf20Sopenharmony_ci kvm_machine_check(); 19788c2ecf20Sopenharmony_ci} 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_cistatic int mc_interception(struct vcpu_svm *svm) 19818c2ecf20Sopenharmony_ci{ 19828c2ecf20Sopenharmony_ci return 1; 19838c2ecf20Sopenharmony_ci} 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_cistatic int shutdown_interception(struct vcpu_svm *svm) 19868c2ecf20Sopenharmony_ci{ 19878c2ecf20Sopenharmony_ci struct kvm_run *kvm_run = svm->vcpu.run; 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci /* 19908c2ecf20Sopenharmony_ci * VMCB is undefined after a SHUTDOWN intercept 19918c2ecf20Sopenharmony_ci * so reinitialize it. 19928c2ecf20Sopenharmony_ci */ 19938c2ecf20Sopenharmony_ci clear_page(svm->vmcb); 19948c2ecf20Sopenharmony_ci init_vmcb(svm); 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci kvm_run->exit_reason = KVM_EXIT_SHUTDOWN; 19978c2ecf20Sopenharmony_ci return 0; 19988c2ecf20Sopenharmony_ci} 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_cistatic int io_interception(struct vcpu_svm *svm) 20018c2ecf20Sopenharmony_ci{ 20028c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = &svm->vcpu; 20038c2ecf20Sopenharmony_ci u32 io_info = svm->vmcb->control.exit_info_1; /* address size bug? */ 20048c2ecf20Sopenharmony_ci int size, in, string; 20058c2ecf20Sopenharmony_ci unsigned port; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci ++svm->vcpu.stat.io_exits; 20088c2ecf20Sopenharmony_ci string = (io_info & SVM_IOIO_STR_MASK) != 0; 20098c2ecf20Sopenharmony_ci in = (io_info & SVM_IOIO_TYPE_MASK) != 0; 20108c2ecf20Sopenharmony_ci if (string) 20118c2ecf20Sopenharmony_ci return kvm_emulate_instruction(vcpu, 0); 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci port = io_info >> 16; 20148c2ecf20Sopenharmony_ci size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT; 20158c2ecf20Sopenharmony_ci svm->next_rip = svm->vmcb->control.exit_info_2; 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci return kvm_fast_pio(&svm->vcpu, size, port, in); 20188c2ecf20Sopenharmony_ci} 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_cistatic int nmi_interception(struct vcpu_svm *svm) 20218c2ecf20Sopenharmony_ci{ 20228c2ecf20Sopenharmony_ci return 1; 20238c2ecf20Sopenharmony_ci} 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_cistatic int intr_interception(struct vcpu_svm *svm) 20268c2ecf20Sopenharmony_ci{ 20278c2ecf20Sopenharmony_ci ++svm->vcpu.stat.irq_exits; 20288c2ecf20Sopenharmony_ci return 1; 20298c2ecf20Sopenharmony_ci} 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_cistatic int nop_on_interception(struct vcpu_svm *svm) 20328c2ecf20Sopenharmony_ci{ 20338c2ecf20Sopenharmony_ci return 1; 20348c2ecf20Sopenharmony_ci} 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_cistatic int halt_interception(struct vcpu_svm *svm) 20378c2ecf20Sopenharmony_ci{ 20388c2ecf20Sopenharmony_ci return kvm_emulate_halt(&svm->vcpu); 20398c2ecf20Sopenharmony_ci} 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_cistatic int vmmcall_interception(struct vcpu_svm *svm) 20428c2ecf20Sopenharmony_ci{ 20438c2ecf20Sopenharmony_ci return kvm_emulate_hypercall(&svm->vcpu); 20448c2ecf20Sopenharmony_ci} 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_cistatic int vmload_interception(struct vcpu_svm *svm) 20478c2ecf20Sopenharmony_ci{ 20488c2ecf20Sopenharmony_ci struct vmcb *nested_vmcb; 20498c2ecf20Sopenharmony_ci struct kvm_host_map map; 20508c2ecf20Sopenharmony_ci int ret; 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci if (nested_svm_check_permissions(svm)) 20538c2ecf20Sopenharmony_ci return 1; 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci ret = kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(svm->vmcb->save.rax), &map); 20568c2ecf20Sopenharmony_ci if (ret) { 20578c2ecf20Sopenharmony_ci if (ret == -EINVAL) 20588c2ecf20Sopenharmony_ci kvm_inject_gp(&svm->vcpu, 0); 20598c2ecf20Sopenharmony_ci return 1; 20608c2ecf20Sopenharmony_ci } 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci nested_vmcb = map.hva; 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci ret = kvm_skip_emulated_instruction(&svm->vcpu); 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci nested_svm_vmloadsave(nested_vmcb, svm->vmcb); 20678c2ecf20Sopenharmony_ci kvm_vcpu_unmap(&svm->vcpu, &map, true); 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci return ret; 20708c2ecf20Sopenharmony_ci} 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_cistatic int vmsave_interception(struct vcpu_svm *svm) 20738c2ecf20Sopenharmony_ci{ 20748c2ecf20Sopenharmony_ci struct vmcb *nested_vmcb; 20758c2ecf20Sopenharmony_ci struct kvm_host_map map; 20768c2ecf20Sopenharmony_ci int ret; 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci if (nested_svm_check_permissions(svm)) 20798c2ecf20Sopenharmony_ci return 1; 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci ret = kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(svm->vmcb->save.rax), &map); 20828c2ecf20Sopenharmony_ci if (ret) { 20838c2ecf20Sopenharmony_ci if (ret == -EINVAL) 20848c2ecf20Sopenharmony_ci kvm_inject_gp(&svm->vcpu, 0); 20858c2ecf20Sopenharmony_ci return 1; 20868c2ecf20Sopenharmony_ci } 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci nested_vmcb = map.hva; 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci ret = kvm_skip_emulated_instruction(&svm->vcpu); 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci nested_svm_vmloadsave(svm->vmcb, nested_vmcb); 20938c2ecf20Sopenharmony_ci kvm_vcpu_unmap(&svm->vcpu, &map, true); 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci return ret; 20968c2ecf20Sopenharmony_ci} 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_cistatic int vmrun_interception(struct vcpu_svm *svm) 20998c2ecf20Sopenharmony_ci{ 21008c2ecf20Sopenharmony_ci if (nested_svm_check_permissions(svm)) 21018c2ecf20Sopenharmony_ci return 1; 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci return nested_svm_vmrun(svm); 21048c2ecf20Sopenharmony_ci} 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_civoid svm_set_gif(struct vcpu_svm *svm, bool value) 21078c2ecf20Sopenharmony_ci{ 21088c2ecf20Sopenharmony_ci if (value) { 21098c2ecf20Sopenharmony_ci /* 21108c2ecf20Sopenharmony_ci * If VGIF is enabled, the STGI intercept is only added to 21118c2ecf20Sopenharmony_ci * detect the opening of the SMI/NMI window; remove it now. 21128c2ecf20Sopenharmony_ci * Likewise, clear the VINTR intercept, we will set it 21138c2ecf20Sopenharmony_ci * again while processing KVM_REQ_EVENT if needed. 21148c2ecf20Sopenharmony_ci */ 21158c2ecf20Sopenharmony_ci if (vgif_enabled(svm)) 21168c2ecf20Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_STGI); 21178c2ecf20Sopenharmony_ci if (svm_is_intercept(svm, INTERCEPT_VINTR)) 21188c2ecf20Sopenharmony_ci svm_clear_vintr(svm); 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci enable_gif(svm); 21218c2ecf20Sopenharmony_ci if (svm->vcpu.arch.smi_pending || 21228c2ecf20Sopenharmony_ci svm->vcpu.arch.nmi_pending || 21238c2ecf20Sopenharmony_ci kvm_cpu_has_injectable_intr(&svm->vcpu)) 21248c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_EVENT, &svm->vcpu); 21258c2ecf20Sopenharmony_ci } else { 21268c2ecf20Sopenharmony_ci disable_gif(svm); 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci /* 21298c2ecf20Sopenharmony_ci * After a CLGI no interrupts should come. But if vGIF is 21308c2ecf20Sopenharmony_ci * in use, we still rely on the VINTR intercept (rather than 21318c2ecf20Sopenharmony_ci * STGI) to detect an open interrupt window. 21328c2ecf20Sopenharmony_ci */ 21338c2ecf20Sopenharmony_ci if (!vgif_enabled(svm)) 21348c2ecf20Sopenharmony_ci svm_clear_vintr(svm); 21358c2ecf20Sopenharmony_ci } 21368c2ecf20Sopenharmony_ci} 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_cistatic int stgi_interception(struct vcpu_svm *svm) 21398c2ecf20Sopenharmony_ci{ 21408c2ecf20Sopenharmony_ci int ret; 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci if (nested_svm_check_permissions(svm)) 21438c2ecf20Sopenharmony_ci return 1; 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci ret = kvm_skip_emulated_instruction(&svm->vcpu); 21468c2ecf20Sopenharmony_ci svm_set_gif(svm, true); 21478c2ecf20Sopenharmony_ci return ret; 21488c2ecf20Sopenharmony_ci} 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_cistatic int clgi_interception(struct vcpu_svm *svm) 21518c2ecf20Sopenharmony_ci{ 21528c2ecf20Sopenharmony_ci int ret; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci if (nested_svm_check_permissions(svm)) 21558c2ecf20Sopenharmony_ci return 1; 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci ret = kvm_skip_emulated_instruction(&svm->vcpu); 21588c2ecf20Sopenharmony_ci svm_set_gif(svm, false); 21598c2ecf20Sopenharmony_ci return ret; 21608c2ecf20Sopenharmony_ci} 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_cistatic int invlpga_interception(struct vcpu_svm *svm) 21638c2ecf20Sopenharmony_ci{ 21648c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = &svm->vcpu; 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci trace_kvm_invlpga(svm->vmcb->save.rip, kvm_rcx_read(&svm->vcpu), 21678c2ecf20Sopenharmony_ci kvm_rax_read(&svm->vcpu)); 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci /* Let's treat INVLPGA the same as INVLPG (can be optimized!) */ 21708c2ecf20Sopenharmony_ci kvm_mmu_invlpg(vcpu, kvm_rax_read(&svm->vcpu)); 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci return kvm_skip_emulated_instruction(&svm->vcpu); 21738c2ecf20Sopenharmony_ci} 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_cistatic int skinit_interception(struct vcpu_svm *svm) 21768c2ecf20Sopenharmony_ci{ 21778c2ecf20Sopenharmony_ci trace_kvm_skinit(svm->vmcb->save.rip, kvm_rax_read(&svm->vcpu)); 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci kvm_queue_exception(&svm->vcpu, UD_VECTOR); 21808c2ecf20Sopenharmony_ci return 1; 21818c2ecf20Sopenharmony_ci} 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_cistatic int wbinvd_interception(struct vcpu_svm *svm) 21848c2ecf20Sopenharmony_ci{ 21858c2ecf20Sopenharmony_ci return kvm_emulate_wbinvd(&svm->vcpu); 21868c2ecf20Sopenharmony_ci} 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_cistatic int xsetbv_interception(struct vcpu_svm *svm) 21898c2ecf20Sopenharmony_ci{ 21908c2ecf20Sopenharmony_ci u64 new_bv = kvm_read_edx_eax(&svm->vcpu); 21918c2ecf20Sopenharmony_ci u32 index = kvm_rcx_read(&svm->vcpu); 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci if (kvm_set_xcr(&svm->vcpu, index, new_bv) == 0) { 21948c2ecf20Sopenharmony_ci return kvm_skip_emulated_instruction(&svm->vcpu); 21958c2ecf20Sopenharmony_ci } 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci return 1; 21988c2ecf20Sopenharmony_ci} 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_cistatic int rdpru_interception(struct vcpu_svm *svm) 22018c2ecf20Sopenharmony_ci{ 22028c2ecf20Sopenharmony_ci kvm_queue_exception(&svm->vcpu, UD_VECTOR); 22038c2ecf20Sopenharmony_ci return 1; 22048c2ecf20Sopenharmony_ci} 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_cistatic int task_switch_interception(struct vcpu_svm *svm) 22078c2ecf20Sopenharmony_ci{ 22088c2ecf20Sopenharmony_ci u16 tss_selector; 22098c2ecf20Sopenharmony_ci int reason; 22108c2ecf20Sopenharmony_ci int int_type = svm->vmcb->control.exit_int_info & 22118c2ecf20Sopenharmony_ci SVM_EXITINTINFO_TYPE_MASK; 22128c2ecf20Sopenharmony_ci int int_vec = svm->vmcb->control.exit_int_info & SVM_EVTINJ_VEC_MASK; 22138c2ecf20Sopenharmony_ci uint32_t type = 22148c2ecf20Sopenharmony_ci svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_TYPE_MASK; 22158c2ecf20Sopenharmony_ci uint32_t idt_v = 22168c2ecf20Sopenharmony_ci svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_VALID; 22178c2ecf20Sopenharmony_ci bool has_error_code = false; 22188c2ecf20Sopenharmony_ci u32 error_code = 0; 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci tss_selector = (u16)svm->vmcb->control.exit_info_1; 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci if (svm->vmcb->control.exit_info_2 & 22238c2ecf20Sopenharmony_ci (1ULL << SVM_EXITINFOSHIFT_TS_REASON_IRET)) 22248c2ecf20Sopenharmony_ci reason = TASK_SWITCH_IRET; 22258c2ecf20Sopenharmony_ci else if (svm->vmcb->control.exit_info_2 & 22268c2ecf20Sopenharmony_ci (1ULL << SVM_EXITINFOSHIFT_TS_REASON_JMP)) 22278c2ecf20Sopenharmony_ci reason = TASK_SWITCH_JMP; 22288c2ecf20Sopenharmony_ci else if (idt_v) 22298c2ecf20Sopenharmony_ci reason = TASK_SWITCH_GATE; 22308c2ecf20Sopenharmony_ci else 22318c2ecf20Sopenharmony_ci reason = TASK_SWITCH_CALL; 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ci if (reason == TASK_SWITCH_GATE) { 22348c2ecf20Sopenharmony_ci switch (type) { 22358c2ecf20Sopenharmony_ci case SVM_EXITINTINFO_TYPE_NMI: 22368c2ecf20Sopenharmony_ci svm->vcpu.arch.nmi_injected = false; 22378c2ecf20Sopenharmony_ci break; 22388c2ecf20Sopenharmony_ci case SVM_EXITINTINFO_TYPE_EXEPT: 22398c2ecf20Sopenharmony_ci if (svm->vmcb->control.exit_info_2 & 22408c2ecf20Sopenharmony_ci (1ULL << SVM_EXITINFOSHIFT_TS_HAS_ERROR_CODE)) { 22418c2ecf20Sopenharmony_ci has_error_code = true; 22428c2ecf20Sopenharmony_ci error_code = 22438c2ecf20Sopenharmony_ci (u32)svm->vmcb->control.exit_info_2; 22448c2ecf20Sopenharmony_ci } 22458c2ecf20Sopenharmony_ci kvm_clear_exception_queue(&svm->vcpu); 22468c2ecf20Sopenharmony_ci break; 22478c2ecf20Sopenharmony_ci case SVM_EXITINTINFO_TYPE_INTR: 22488c2ecf20Sopenharmony_ci kvm_clear_interrupt_queue(&svm->vcpu); 22498c2ecf20Sopenharmony_ci break; 22508c2ecf20Sopenharmony_ci default: 22518c2ecf20Sopenharmony_ci break; 22528c2ecf20Sopenharmony_ci } 22538c2ecf20Sopenharmony_ci } 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_ci if (reason != TASK_SWITCH_GATE || 22568c2ecf20Sopenharmony_ci int_type == SVM_EXITINTINFO_TYPE_SOFT || 22578c2ecf20Sopenharmony_ci (int_type == SVM_EXITINTINFO_TYPE_EXEPT && 22588c2ecf20Sopenharmony_ci (int_vec == OF_VECTOR || int_vec == BP_VECTOR))) { 22598c2ecf20Sopenharmony_ci if (!skip_emulated_instruction(&svm->vcpu)) 22608c2ecf20Sopenharmony_ci return 0; 22618c2ecf20Sopenharmony_ci } 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci if (int_type != SVM_EXITINTINFO_TYPE_SOFT) 22648c2ecf20Sopenharmony_ci int_vec = -1; 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci return kvm_task_switch(&svm->vcpu, tss_selector, int_vec, reason, 22678c2ecf20Sopenharmony_ci has_error_code, error_code); 22688c2ecf20Sopenharmony_ci} 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_cistatic int cpuid_interception(struct vcpu_svm *svm) 22718c2ecf20Sopenharmony_ci{ 22728c2ecf20Sopenharmony_ci return kvm_emulate_cpuid(&svm->vcpu); 22738c2ecf20Sopenharmony_ci} 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_cistatic int iret_interception(struct vcpu_svm *svm) 22768c2ecf20Sopenharmony_ci{ 22778c2ecf20Sopenharmony_ci ++svm->vcpu.stat.nmi_window_exits; 22788c2ecf20Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_IRET); 22798c2ecf20Sopenharmony_ci svm->vcpu.arch.hflags |= HF_IRET_MASK; 22808c2ecf20Sopenharmony_ci svm->nmi_iret_rip = kvm_rip_read(&svm->vcpu); 22818c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_EVENT, &svm->vcpu); 22828c2ecf20Sopenharmony_ci return 1; 22838c2ecf20Sopenharmony_ci} 22848c2ecf20Sopenharmony_ci 22858c2ecf20Sopenharmony_cistatic int invd_interception(struct vcpu_svm *svm) 22868c2ecf20Sopenharmony_ci{ 22878c2ecf20Sopenharmony_ci /* Treat an INVD instruction as a NOP and just skip it. */ 22888c2ecf20Sopenharmony_ci return kvm_skip_emulated_instruction(&svm->vcpu); 22898c2ecf20Sopenharmony_ci} 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_cistatic int invlpg_interception(struct vcpu_svm *svm) 22928c2ecf20Sopenharmony_ci{ 22938c2ecf20Sopenharmony_ci if (!static_cpu_has(X86_FEATURE_DECODEASSISTS)) 22948c2ecf20Sopenharmony_ci return kvm_emulate_instruction(&svm->vcpu, 0); 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_ci kvm_mmu_invlpg(&svm->vcpu, svm->vmcb->control.exit_info_1); 22978c2ecf20Sopenharmony_ci return kvm_skip_emulated_instruction(&svm->vcpu); 22988c2ecf20Sopenharmony_ci} 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_cistatic int emulate_on_interception(struct vcpu_svm *svm) 23018c2ecf20Sopenharmony_ci{ 23028c2ecf20Sopenharmony_ci return kvm_emulate_instruction(&svm->vcpu, 0); 23038c2ecf20Sopenharmony_ci} 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_cistatic int rsm_interception(struct vcpu_svm *svm) 23068c2ecf20Sopenharmony_ci{ 23078c2ecf20Sopenharmony_ci return kvm_emulate_instruction_from_buffer(&svm->vcpu, rsm_ins_bytes, 2); 23088c2ecf20Sopenharmony_ci} 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_cistatic int rdpmc_interception(struct vcpu_svm *svm) 23118c2ecf20Sopenharmony_ci{ 23128c2ecf20Sopenharmony_ci int err; 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_ci if (!nrips) 23158c2ecf20Sopenharmony_ci return emulate_on_interception(svm); 23168c2ecf20Sopenharmony_ci 23178c2ecf20Sopenharmony_ci err = kvm_rdpmc(&svm->vcpu); 23188c2ecf20Sopenharmony_ci return kvm_complete_insn_gp(&svm->vcpu, err); 23198c2ecf20Sopenharmony_ci} 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_cistatic bool check_selective_cr0_intercepted(struct vcpu_svm *svm, 23228c2ecf20Sopenharmony_ci unsigned long val) 23238c2ecf20Sopenharmony_ci{ 23248c2ecf20Sopenharmony_ci unsigned long cr0 = svm->vcpu.arch.cr0; 23258c2ecf20Sopenharmony_ci bool ret = false; 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci if (!is_guest_mode(&svm->vcpu) || 23288c2ecf20Sopenharmony_ci (!(vmcb_is_intercept(&svm->nested.ctl, INTERCEPT_SELECTIVE_CR0)))) 23298c2ecf20Sopenharmony_ci return false; 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_ci cr0 &= ~SVM_CR0_SELECTIVE_MASK; 23328c2ecf20Sopenharmony_ci val &= ~SVM_CR0_SELECTIVE_MASK; 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci if (cr0 ^ val) { 23358c2ecf20Sopenharmony_ci svm->vmcb->control.exit_code = SVM_EXIT_CR0_SEL_WRITE; 23368c2ecf20Sopenharmony_ci ret = (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE); 23378c2ecf20Sopenharmony_ci } 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci return ret; 23408c2ecf20Sopenharmony_ci} 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci#define CR_VALID (1ULL << 63) 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_cistatic int cr_interception(struct vcpu_svm *svm) 23458c2ecf20Sopenharmony_ci{ 23468c2ecf20Sopenharmony_ci int reg, cr; 23478c2ecf20Sopenharmony_ci unsigned long val; 23488c2ecf20Sopenharmony_ci int err; 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci if (!static_cpu_has(X86_FEATURE_DECODEASSISTS)) 23518c2ecf20Sopenharmony_ci return emulate_on_interception(svm); 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_ci if (unlikely((svm->vmcb->control.exit_info_1 & CR_VALID) == 0)) 23548c2ecf20Sopenharmony_ci return emulate_on_interception(svm); 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci reg = svm->vmcb->control.exit_info_1 & SVM_EXITINFO_REG_MASK; 23578c2ecf20Sopenharmony_ci if (svm->vmcb->control.exit_code == SVM_EXIT_CR0_SEL_WRITE) 23588c2ecf20Sopenharmony_ci cr = SVM_EXIT_WRITE_CR0 - SVM_EXIT_READ_CR0; 23598c2ecf20Sopenharmony_ci else 23608c2ecf20Sopenharmony_ci cr = svm->vmcb->control.exit_code - SVM_EXIT_READ_CR0; 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ci err = 0; 23638c2ecf20Sopenharmony_ci if (cr >= 16) { /* mov to cr */ 23648c2ecf20Sopenharmony_ci cr -= 16; 23658c2ecf20Sopenharmony_ci val = kvm_register_readl(&svm->vcpu, reg); 23668c2ecf20Sopenharmony_ci trace_kvm_cr_write(cr, val); 23678c2ecf20Sopenharmony_ci switch (cr) { 23688c2ecf20Sopenharmony_ci case 0: 23698c2ecf20Sopenharmony_ci if (!check_selective_cr0_intercepted(svm, val)) 23708c2ecf20Sopenharmony_ci err = kvm_set_cr0(&svm->vcpu, val); 23718c2ecf20Sopenharmony_ci else 23728c2ecf20Sopenharmony_ci return 1; 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ci break; 23758c2ecf20Sopenharmony_ci case 3: 23768c2ecf20Sopenharmony_ci err = kvm_set_cr3(&svm->vcpu, val); 23778c2ecf20Sopenharmony_ci break; 23788c2ecf20Sopenharmony_ci case 4: 23798c2ecf20Sopenharmony_ci err = kvm_set_cr4(&svm->vcpu, val); 23808c2ecf20Sopenharmony_ci break; 23818c2ecf20Sopenharmony_ci case 8: 23828c2ecf20Sopenharmony_ci err = kvm_set_cr8(&svm->vcpu, val); 23838c2ecf20Sopenharmony_ci break; 23848c2ecf20Sopenharmony_ci default: 23858c2ecf20Sopenharmony_ci WARN(1, "unhandled write to CR%d", cr); 23868c2ecf20Sopenharmony_ci kvm_queue_exception(&svm->vcpu, UD_VECTOR); 23878c2ecf20Sopenharmony_ci return 1; 23888c2ecf20Sopenharmony_ci } 23898c2ecf20Sopenharmony_ci } else { /* mov from cr */ 23908c2ecf20Sopenharmony_ci switch (cr) { 23918c2ecf20Sopenharmony_ci case 0: 23928c2ecf20Sopenharmony_ci val = kvm_read_cr0(&svm->vcpu); 23938c2ecf20Sopenharmony_ci break; 23948c2ecf20Sopenharmony_ci case 2: 23958c2ecf20Sopenharmony_ci val = svm->vcpu.arch.cr2; 23968c2ecf20Sopenharmony_ci break; 23978c2ecf20Sopenharmony_ci case 3: 23988c2ecf20Sopenharmony_ci val = kvm_read_cr3(&svm->vcpu); 23998c2ecf20Sopenharmony_ci break; 24008c2ecf20Sopenharmony_ci case 4: 24018c2ecf20Sopenharmony_ci val = kvm_read_cr4(&svm->vcpu); 24028c2ecf20Sopenharmony_ci break; 24038c2ecf20Sopenharmony_ci case 8: 24048c2ecf20Sopenharmony_ci val = kvm_get_cr8(&svm->vcpu); 24058c2ecf20Sopenharmony_ci break; 24068c2ecf20Sopenharmony_ci default: 24078c2ecf20Sopenharmony_ci WARN(1, "unhandled read from CR%d", cr); 24088c2ecf20Sopenharmony_ci kvm_queue_exception(&svm->vcpu, UD_VECTOR); 24098c2ecf20Sopenharmony_ci return 1; 24108c2ecf20Sopenharmony_ci } 24118c2ecf20Sopenharmony_ci kvm_register_writel(&svm->vcpu, reg, val); 24128c2ecf20Sopenharmony_ci trace_kvm_cr_read(cr, val); 24138c2ecf20Sopenharmony_ci } 24148c2ecf20Sopenharmony_ci return kvm_complete_insn_gp(&svm->vcpu, err); 24158c2ecf20Sopenharmony_ci} 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_cistatic int dr_interception(struct vcpu_svm *svm) 24188c2ecf20Sopenharmony_ci{ 24198c2ecf20Sopenharmony_ci int reg, dr; 24208c2ecf20Sopenharmony_ci unsigned long val; 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ci if (svm->vcpu.guest_debug == 0) { 24238c2ecf20Sopenharmony_ci /* 24248c2ecf20Sopenharmony_ci * No more DR vmexits; force a reload of the debug registers 24258c2ecf20Sopenharmony_ci * and reenter on this instruction. The next vmexit will 24268c2ecf20Sopenharmony_ci * retrieve the full state of the debug registers. 24278c2ecf20Sopenharmony_ci */ 24288c2ecf20Sopenharmony_ci clr_dr_intercepts(svm); 24298c2ecf20Sopenharmony_ci svm->vcpu.arch.switch_db_regs |= KVM_DEBUGREG_WONT_EXIT; 24308c2ecf20Sopenharmony_ci return 1; 24318c2ecf20Sopenharmony_ci } 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_DECODEASSISTS)) 24348c2ecf20Sopenharmony_ci return emulate_on_interception(svm); 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci reg = svm->vmcb->control.exit_info_1 & SVM_EXITINFO_REG_MASK; 24378c2ecf20Sopenharmony_ci dr = svm->vmcb->control.exit_code - SVM_EXIT_READ_DR0; 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_ci if (dr >= 16) { /* mov to DRn */ 24408c2ecf20Sopenharmony_ci if (!kvm_require_dr(&svm->vcpu, dr - 16)) 24418c2ecf20Sopenharmony_ci return 1; 24428c2ecf20Sopenharmony_ci val = kvm_register_readl(&svm->vcpu, reg); 24438c2ecf20Sopenharmony_ci kvm_set_dr(&svm->vcpu, dr - 16, val); 24448c2ecf20Sopenharmony_ci } else { 24458c2ecf20Sopenharmony_ci if (!kvm_require_dr(&svm->vcpu, dr)) 24468c2ecf20Sopenharmony_ci return 1; 24478c2ecf20Sopenharmony_ci kvm_get_dr(&svm->vcpu, dr, &val); 24488c2ecf20Sopenharmony_ci kvm_register_writel(&svm->vcpu, reg, val); 24498c2ecf20Sopenharmony_ci } 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci return kvm_skip_emulated_instruction(&svm->vcpu); 24528c2ecf20Sopenharmony_ci} 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_cistatic int cr8_write_interception(struct vcpu_svm *svm) 24558c2ecf20Sopenharmony_ci{ 24568c2ecf20Sopenharmony_ci struct kvm_run *kvm_run = svm->vcpu.run; 24578c2ecf20Sopenharmony_ci int r; 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_ci u8 cr8_prev = kvm_get_cr8(&svm->vcpu); 24608c2ecf20Sopenharmony_ci /* instruction emulation calls kvm_set_cr8() */ 24618c2ecf20Sopenharmony_ci r = cr_interception(svm); 24628c2ecf20Sopenharmony_ci if (lapic_in_kernel(&svm->vcpu)) 24638c2ecf20Sopenharmony_ci return r; 24648c2ecf20Sopenharmony_ci if (cr8_prev <= kvm_get_cr8(&svm->vcpu)) 24658c2ecf20Sopenharmony_ci return r; 24668c2ecf20Sopenharmony_ci kvm_run->exit_reason = KVM_EXIT_SET_TPR; 24678c2ecf20Sopenharmony_ci return 0; 24688c2ecf20Sopenharmony_ci} 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_cistatic int svm_get_msr_feature(struct kvm_msr_entry *msr) 24718c2ecf20Sopenharmony_ci{ 24728c2ecf20Sopenharmony_ci msr->data = 0; 24738c2ecf20Sopenharmony_ci 24748c2ecf20Sopenharmony_ci switch (msr->index) { 24758c2ecf20Sopenharmony_ci case MSR_AMD64_DE_CFG: 24768c2ecf20Sopenharmony_ci if (cpu_feature_enabled(X86_FEATURE_LFENCE_RDTSC)) 24778c2ecf20Sopenharmony_ci msr->data |= MSR_AMD64_DE_CFG_LFENCE_SERIALIZE; 24788c2ecf20Sopenharmony_ci break; 24798c2ecf20Sopenharmony_ci case MSR_IA32_PERF_CAPABILITIES: 24808c2ecf20Sopenharmony_ci return 0; 24818c2ecf20Sopenharmony_ci default: 24828c2ecf20Sopenharmony_ci return KVM_MSR_RET_INVALID; 24838c2ecf20Sopenharmony_ci } 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_ci return 0; 24868c2ecf20Sopenharmony_ci} 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_cistatic int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) 24898c2ecf20Sopenharmony_ci{ 24908c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 24918c2ecf20Sopenharmony_ci 24928c2ecf20Sopenharmony_ci switch (msr_info->index) { 24938c2ecf20Sopenharmony_ci case MSR_STAR: 24948c2ecf20Sopenharmony_ci msr_info->data = svm->vmcb->save.star; 24958c2ecf20Sopenharmony_ci break; 24968c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 24978c2ecf20Sopenharmony_ci case MSR_LSTAR: 24988c2ecf20Sopenharmony_ci msr_info->data = svm->vmcb->save.lstar; 24998c2ecf20Sopenharmony_ci break; 25008c2ecf20Sopenharmony_ci case MSR_CSTAR: 25018c2ecf20Sopenharmony_ci msr_info->data = svm->vmcb->save.cstar; 25028c2ecf20Sopenharmony_ci break; 25038c2ecf20Sopenharmony_ci case MSR_KERNEL_GS_BASE: 25048c2ecf20Sopenharmony_ci msr_info->data = svm->vmcb->save.kernel_gs_base; 25058c2ecf20Sopenharmony_ci break; 25068c2ecf20Sopenharmony_ci case MSR_SYSCALL_MASK: 25078c2ecf20Sopenharmony_ci msr_info->data = svm->vmcb->save.sfmask; 25088c2ecf20Sopenharmony_ci break; 25098c2ecf20Sopenharmony_ci#endif 25108c2ecf20Sopenharmony_ci case MSR_IA32_SYSENTER_CS: 25118c2ecf20Sopenharmony_ci msr_info->data = svm->vmcb->save.sysenter_cs; 25128c2ecf20Sopenharmony_ci break; 25138c2ecf20Sopenharmony_ci case MSR_IA32_SYSENTER_EIP: 25148c2ecf20Sopenharmony_ci msr_info->data = svm->sysenter_eip; 25158c2ecf20Sopenharmony_ci break; 25168c2ecf20Sopenharmony_ci case MSR_IA32_SYSENTER_ESP: 25178c2ecf20Sopenharmony_ci msr_info->data = svm->sysenter_esp; 25188c2ecf20Sopenharmony_ci break; 25198c2ecf20Sopenharmony_ci case MSR_TSC_AUX: 25208c2ecf20Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_RDTSCP)) 25218c2ecf20Sopenharmony_ci return 1; 25228c2ecf20Sopenharmony_ci if (!msr_info->host_initiated && 25238c2ecf20Sopenharmony_ci !guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP)) 25248c2ecf20Sopenharmony_ci return 1; 25258c2ecf20Sopenharmony_ci msr_info->data = svm->tsc_aux; 25268c2ecf20Sopenharmony_ci break; 25278c2ecf20Sopenharmony_ci /* 25288c2ecf20Sopenharmony_ci * Nobody will change the following 5 values in the VMCB so we can 25298c2ecf20Sopenharmony_ci * safely return them on rdmsr. They will always be 0 until LBRV is 25308c2ecf20Sopenharmony_ci * implemented. 25318c2ecf20Sopenharmony_ci */ 25328c2ecf20Sopenharmony_ci case MSR_IA32_DEBUGCTLMSR: 25338c2ecf20Sopenharmony_ci msr_info->data = svm->vmcb->save.dbgctl; 25348c2ecf20Sopenharmony_ci break; 25358c2ecf20Sopenharmony_ci case MSR_IA32_LASTBRANCHFROMIP: 25368c2ecf20Sopenharmony_ci msr_info->data = svm->vmcb->save.br_from; 25378c2ecf20Sopenharmony_ci break; 25388c2ecf20Sopenharmony_ci case MSR_IA32_LASTBRANCHTOIP: 25398c2ecf20Sopenharmony_ci msr_info->data = svm->vmcb->save.br_to; 25408c2ecf20Sopenharmony_ci break; 25418c2ecf20Sopenharmony_ci case MSR_IA32_LASTINTFROMIP: 25428c2ecf20Sopenharmony_ci msr_info->data = svm->vmcb->save.last_excp_from; 25438c2ecf20Sopenharmony_ci break; 25448c2ecf20Sopenharmony_ci case MSR_IA32_LASTINTTOIP: 25458c2ecf20Sopenharmony_ci msr_info->data = svm->vmcb->save.last_excp_to; 25468c2ecf20Sopenharmony_ci break; 25478c2ecf20Sopenharmony_ci case MSR_VM_HSAVE_PA: 25488c2ecf20Sopenharmony_ci msr_info->data = svm->nested.hsave_msr; 25498c2ecf20Sopenharmony_ci break; 25508c2ecf20Sopenharmony_ci case MSR_VM_CR: 25518c2ecf20Sopenharmony_ci msr_info->data = svm->nested.vm_cr_msr; 25528c2ecf20Sopenharmony_ci break; 25538c2ecf20Sopenharmony_ci case MSR_IA32_SPEC_CTRL: 25548c2ecf20Sopenharmony_ci if (!msr_info->host_initiated && 25558c2ecf20Sopenharmony_ci !guest_has_spec_ctrl_msr(vcpu)) 25568c2ecf20Sopenharmony_ci return 1; 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_ci msr_info->data = svm->spec_ctrl; 25598c2ecf20Sopenharmony_ci break; 25608c2ecf20Sopenharmony_ci case MSR_AMD64_VIRT_SPEC_CTRL: 25618c2ecf20Sopenharmony_ci if (!msr_info->host_initiated && 25628c2ecf20Sopenharmony_ci !guest_cpuid_has(vcpu, X86_FEATURE_VIRT_SSBD)) 25638c2ecf20Sopenharmony_ci return 1; 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci msr_info->data = svm->virt_spec_ctrl; 25668c2ecf20Sopenharmony_ci break; 25678c2ecf20Sopenharmony_ci case MSR_F15H_IC_CFG: { 25688c2ecf20Sopenharmony_ci 25698c2ecf20Sopenharmony_ci int family, model; 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci family = guest_cpuid_family(vcpu); 25728c2ecf20Sopenharmony_ci model = guest_cpuid_model(vcpu); 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci if (family < 0 || model < 0) 25758c2ecf20Sopenharmony_ci return kvm_get_msr_common(vcpu, msr_info); 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_ci msr_info->data = 0; 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci if (family == 0x15 && 25808c2ecf20Sopenharmony_ci (model >= 0x2 && model < 0x20)) 25818c2ecf20Sopenharmony_ci msr_info->data = 0x1E; 25828c2ecf20Sopenharmony_ci } 25838c2ecf20Sopenharmony_ci break; 25848c2ecf20Sopenharmony_ci case MSR_AMD64_DE_CFG: 25858c2ecf20Sopenharmony_ci msr_info->data = svm->msr_decfg; 25868c2ecf20Sopenharmony_ci break; 25878c2ecf20Sopenharmony_ci default: 25888c2ecf20Sopenharmony_ci return kvm_get_msr_common(vcpu, msr_info); 25898c2ecf20Sopenharmony_ci } 25908c2ecf20Sopenharmony_ci return 0; 25918c2ecf20Sopenharmony_ci} 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_cistatic int rdmsr_interception(struct vcpu_svm *svm) 25948c2ecf20Sopenharmony_ci{ 25958c2ecf20Sopenharmony_ci return kvm_emulate_rdmsr(&svm->vcpu); 25968c2ecf20Sopenharmony_ci} 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_cistatic int svm_set_vm_cr(struct kvm_vcpu *vcpu, u64 data) 25998c2ecf20Sopenharmony_ci{ 26008c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 26018c2ecf20Sopenharmony_ci int svm_dis, chg_mask; 26028c2ecf20Sopenharmony_ci 26038c2ecf20Sopenharmony_ci if (data & ~SVM_VM_CR_VALID_MASK) 26048c2ecf20Sopenharmony_ci return 1; 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci chg_mask = SVM_VM_CR_VALID_MASK; 26078c2ecf20Sopenharmony_ci 26088c2ecf20Sopenharmony_ci if (svm->nested.vm_cr_msr & SVM_VM_CR_SVM_DIS_MASK) 26098c2ecf20Sopenharmony_ci chg_mask &= ~(SVM_VM_CR_SVM_LOCK_MASK | SVM_VM_CR_SVM_DIS_MASK); 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_ci svm->nested.vm_cr_msr &= ~chg_mask; 26128c2ecf20Sopenharmony_ci svm->nested.vm_cr_msr |= (data & chg_mask); 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci svm_dis = svm->nested.vm_cr_msr & SVM_VM_CR_SVM_DIS_MASK; 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_ci /* check for svm_disable while efer.svme is set */ 26178c2ecf20Sopenharmony_ci if (svm_dis && (vcpu->arch.efer & EFER_SVME)) 26188c2ecf20Sopenharmony_ci return 1; 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci return 0; 26218c2ecf20Sopenharmony_ci} 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_cistatic int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) 26248c2ecf20Sopenharmony_ci{ 26258c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci u32 ecx = msr->index; 26288c2ecf20Sopenharmony_ci u64 data = msr->data; 26298c2ecf20Sopenharmony_ci switch (ecx) { 26308c2ecf20Sopenharmony_ci case MSR_IA32_CR_PAT: 26318c2ecf20Sopenharmony_ci if (!kvm_mtrr_valid(vcpu, MSR_IA32_CR_PAT, data)) 26328c2ecf20Sopenharmony_ci return 1; 26338c2ecf20Sopenharmony_ci vcpu->arch.pat = data; 26348c2ecf20Sopenharmony_ci svm->vmcb->save.g_pat = data; 26358c2ecf20Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_NPT); 26368c2ecf20Sopenharmony_ci break; 26378c2ecf20Sopenharmony_ci case MSR_IA32_SPEC_CTRL: 26388c2ecf20Sopenharmony_ci if (!msr->host_initiated && 26398c2ecf20Sopenharmony_ci !guest_has_spec_ctrl_msr(vcpu)) 26408c2ecf20Sopenharmony_ci return 1; 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_ci if (kvm_spec_ctrl_test_value(data)) 26438c2ecf20Sopenharmony_ci return 1; 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ci svm->spec_ctrl = data; 26468c2ecf20Sopenharmony_ci if (!data) 26478c2ecf20Sopenharmony_ci break; 26488c2ecf20Sopenharmony_ci 26498c2ecf20Sopenharmony_ci /* 26508c2ecf20Sopenharmony_ci * For non-nested: 26518c2ecf20Sopenharmony_ci * When it's written (to non-zero) for the first time, pass 26528c2ecf20Sopenharmony_ci * it through. 26538c2ecf20Sopenharmony_ci * 26548c2ecf20Sopenharmony_ci * For nested: 26558c2ecf20Sopenharmony_ci * The handling of the MSR bitmap for L2 guests is done in 26568c2ecf20Sopenharmony_ci * nested_svm_vmrun_msrpm. 26578c2ecf20Sopenharmony_ci * We update the L1 MSR bit as well since it will end up 26588c2ecf20Sopenharmony_ci * touching the MSR anyway now. 26598c2ecf20Sopenharmony_ci */ 26608c2ecf20Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_SPEC_CTRL, 1, 1); 26618c2ecf20Sopenharmony_ci break; 26628c2ecf20Sopenharmony_ci case MSR_IA32_PRED_CMD: 26638c2ecf20Sopenharmony_ci if (!msr->host_initiated && 26648c2ecf20Sopenharmony_ci !guest_has_pred_cmd_msr(vcpu)) 26658c2ecf20Sopenharmony_ci return 1; 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci if (data & ~PRED_CMD_IBPB) 26688c2ecf20Sopenharmony_ci return 1; 26698c2ecf20Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_IBPB)) 26708c2ecf20Sopenharmony_ci return 1; 26718c2ecf20Sopenharmony_ci if (!data) 26728c2ecf20Sopenharmony_ci break; 26738c2ecf20Sopenharmony_ci 26748c2ecf20Sopenharmony_ci wrmsrl(MSR_IA32_PRED_CMD, PRED_CMD_IBPB); 26758c2ecf20Sopenharmony_ci set_msr_interception(vcpu, svm->msrpm, MSR_IA32_PRED_CMD, 0, 1); 26768c2ecf20Sopenharmony_ci break; 26778c2ecf20Sopenharmony_ci case MSR_AMD64_VIRT_SPEC_CTRL: 26788c2ecf20Sopenharmony_ci if (!msr->host_initiated && 26798c2ecf20Sopenharmony_ci !guest_cpuid_has(vcpu, X86_FEATURE_VIRT_SSBD)) 26808c2ecf20Sopenharmony_ci return 1; 26818c2ecf20Sopenharmony_ci 26828c2ecf20Sopenharmony_ci if (data & ~SPEC_CTRL_SSBD) 26838c2ecf20Sopenharmony_ci return 1; 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ci svm->virt_spec_ctrl = data; 26868c2ecf20Sopenharmony_ci break; 26878c2ecf20Sopenharmony_ci case MSR_STAR: 26888c2ecf20Sopenharmony_ci svm->vmcb->save.star = data; 26898c2ecf20Sopenharmony_ci break; 26908c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 26918c2ecf20Sopenharmony_ci case MSR_LSTAR: 26928c2ecf20Sopenharmony_ci svm->vmcb->save.lstar = data; 26938c2ecf20Sopenharmony_ci break; 26948c2ecf20Sopenharmony_ci case MSR_CSTAR: 26958c2ecf20Sopenharmony_ci svm->vmcb->save.cstar = data; 26968c2ecf20Sopenharmony_ci break; 26978c2ecf20Sopenharmony_ci case MSR_KERNEL_GS_BASE: 26988c2ecf20Sopenharmony_ci svm->vmcb->save.kernel_gs_base = data; 26998c2ecf20Sopenharmony_ci break; 27008c2ecf20Sopenharmony_ci case MSR_SYSCALL_MASK: 27018c2ecf20Sopenharmony_ci svm->vmcb->save.sfmask = data; 27028c2ecf20Sopenharmony_ci break; 27038c2ecf20Sopenharmony_ci#endif 27048c2ecf20Sopenharmony_ci case MSR_IA32_SYSENTER_CS: 27058c2ecf20Sopenharmony_ci svm->vmcb->save.sysenter_cs = data; 27068c2ecf20Sopenharmony_ci break; 27078c2ecf20Sopenharmony_ci case MSR_IA32_SYSENTER_EIP: 27088c2ecf20Sopenharmony_ci svm->sysenter_eip = data; 27098c2ecf20Sopenharmony_ci svm->vmcb->save.sysenter_eip = data; 27108c2ecf20Sopenharmony_ci break; 27118c2ecf20Sopenharmony_ci case MSR_IA32_SYSENTER_ESP: 27128c2ecf20Sopenharmony_ci svm->sysenter_esp = data; 27138c2ecf20Sopenharmony_ci svm->vmcb->save.sysenter_esp = data; 27148c2ecf20Sopenharmony_ci break; 27158c2ecf20Sopenharmony_ci case MSR_TSC_AUX: 27168c2ecf20Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_RDTSCP)) 27178c2ecf20Sopenharmony_ci return 1; 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ci if (!msr->host_initiated && 27208c2ecf20Sopenharmony_ci !guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP)) 27218c2ecf20Sopenharmony_ci return 1; 27228c2ecf20Sopenharmony_ci 27238c2ecf20Sopenharmony_ci /* 27248c2ecf20Sopenharmony_ci * This is rare, so we update the MSR here instead of using 27258c2ecf20Sopenharmony_ci * direct_access_msrs. Doing that would require a rdmsr in 27268c2ecf20Sopenharmony_ci * svm_vcpu_put. 27278c2ecf20Sopenharmony_ci */ 27288c2ecf20Sopenharmony_ci svm->tsc_aux = data; 27298c2ecf20Sopenharmony_ci wrmsrl(MSR_TSC_AUX, svm->tsc_aux); 27308c2ecf20Sopenharmony_ci break; 27318c2ecf20Sopenharmony_ci case MSR_IA32_DEBUGCTLMSR: 27328c2ecf20Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_LBRV)) { 27338c2ecf20Sopenharmony_ci vcpu_unimpl(vcpu, "%s: MSR_IA32_DEBUGCTL 0x%llx, nop\n", 27348c2ecf20Sopenharmony_ci __func__, data); 27358c2ecf20Sopenharmony_ci break; 27368c2ecf20Sopenharmony_ci } 27378c2ecf20Sopenharmony_ci if (data & DEBUGCTL_RESERVED_BITS) 27388c2ecf20Sopenharmony_ci return 1; 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_ci svm->vmcb->save.dbgctl = data; 27418c2ecf20Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_LBR); 27428c2ecf20Sopenharmony_ci if (data & (1ULL<<0)) 27438c2ecf20Sopenharmony_ci svm_enable_lbrv(vcpu); 27448c2ecf20Sopenharmony_ci else 27458c2ecf20Sopenharmony_ci svm_disable_lbrv(vcpu); 27468c2ecf20Sopenharmony_ci break; 27478c2ecf20Sopenharmony_ci case MSR_VM_HSAVE_PA: 27488c2ecf20Sopenharmony_ci /* 27498c2ecf20Sopenharmony_ci * Old kernels did not validate the value written to 27508c2ecf20Sopenharmony_ci * MSR_VM_HSAVE_PA. Allow KVM_SET_MSR to set an invalid 27518c2ecf20Sopenharmony_ci * value to allow live migrating buggy or malicious guests 27528c2ecf20Sopenharmony_ci * originating from those kernels. 27538c2ecf20Sopenharmony_ci */ 27548c2ecf20Sopenharmony_ci if (!msr->host_initiated && !page_address_valid(vcpu, data)) 27558c2ecf20Sopenharmony_ci return 1; 27568c2ecf20Sopenharmony_ci 27578c2ecf20Sopenharmony_ci svm->nested.hsave_msr = data & PAGE_MASK; 27588c2ecf20Sopenharmony_ci break; 27598c2ecf20Sopenharmony_ci case MSR_VM_CR: 27608c2ecf20Sopenharmony_ci return svm_set_vm_cr(vcpu, data); 27618c2ecf20Sopenharmony_ci case MSR_VM_IGNNE: 27628c2ecf20Sopenharmony_ci vcpu_unimpl(vcpu, "unimplemented wrmsr: 0x%x data 0x%llx\n", ecx, data); 27638c2ecf20Sopenharmony_ci break; 27648c2ecf20Sopenharmony_ci case MSR_AMD64_DE_CFG: { 27658c2ecf20Sopenharmony_ci struct kvm_msr_entry msr_entry; 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci msr_entry.index = msr->index; 27688c2ecf20Sopenharmony_ci if (svm_get_msr_feature(&msr_entry)) 27698c2ecf20Sopenharmony_ci return 1; 27708c2ecf20Sopenharmony_ci 27718c2ecf20Sopenharmony_ci /* Check the supported bits */ 27728c2ecf20Sopenharmony_ci if (data & ~msr_entry.data) 27738c2ecf20Sopenharmony_ci return 1; 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci /* Don't allow the guest to change a bit, #GP */ 27768c2ecf20Sopenharmony_ci if (!msr->host_initiated && (data ^ msr_entry.data)) 27778c2ecf20Sopenharmony_ci return 1; 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci svm->msr_decfg = data; 27808c2ecf20Sopenharmony_ci break; 27818c2ecf20Sopenharmony_ci } 27828c2ecf20Sopenharmony_ci case MSR_IA32_APICBASE: 27838c2ecf20Sopenharmony_ci if (kvm_vcpu_apicv_active(vcpu)) 27848c2ecf20Sopenharmony_ci avic_update_vapic_bar(to_svm(vcpu), data); 27858c2ecf20Sopenharmony_ci fallthrough; 27868c2ecf20Sopenharmony_ci default: 27878c2ecf20Sopenharmony_ci return kvm_set_msr_common(vcpu, msr); 27888c2ecf20Sopenharmony_ci } 27898c2ecf20Sopenharmony_ci return 0; 27908c2ecf20Sopenharmony_ci} 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_cistatic int wrmsr_interception(struct vcpu_svm *svm) 27938c2ecf20Sopenharmony_ci{ 27948c2ecf20Sopenharmony_ci return kvm_emulate_wrmsr(&svm->vcpu); 27958c2ecf20Sopenharmony_ci} 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_cistatic int msr_interception(struct vcpu_svm *svm) 27988c2ecf20Sopenharmony_ci{ 27998c2ecf20Sopenharmony_ci if (svm->vmcb->control.exit_info_1) 28008c2ecf20Sopenharmony_ci return wrmsr_interception(svm); 28018c2ecf20Sopenharmony_ci else 28028c2ecf20Sopenharmony_ci return rdmsr_interception(svm); 28038c2ecf20Sopenharmony_ci} 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_cistatic int interrupt_window_interception(struct vcpu_svm *svm) 28068c2ecf20Sopenharmony_ci{ 28078c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_EVENT, &svm->vcpu); 28088c2ecf20Sopenharmony_ci svm_clear_vintr(svm); 28098c2ecf20Sopenharmony_ci 28108c2ecf20Sopenharmony_ci /* 28118c2ecf20Sopenharmony_ci * For AVIC, the only reason to end up here is ExtINTs. 28128c2ecf20Sopenharmony_ci * In this case AVIC was temporarily disabled for 28138c2ecf20Sopenharmony_ci * requesting the IRQ window and we have to re-enable it. 28148c2ecf20Sopenharmony_ci */ 28158c2ecf20Sopenharmony_ci svm_toggle_avic_for_irq_window(&svm->vcpu, true); 28168c2ecf20Sopenharmony_ci 28178c2ecf20Sopenharmony_ci ++svm->vcpu.stat.irq_window_exits; 28188c2ecf20Sopenharmony_ci return 1; 28198c2ecf20Sopenharmony_ci} 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_cistatic int pause_interception(struct vcpu_svm *svm) 28228c2ecf20Sopenharmony_ci{ 28238c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = &svm->vcpu; 28248c2ecf20Sopenharmony_ci bool in_kernel = (svm_get_cpl(vcpu) == 0); 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_ci if (!kvm_pause_in_guest(vcpu->kvm)) 28278c2ecf20Sopenharmony_ci grow_ple_window(vcpu); 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_ci kvm_vcpu_on_spin(vcpu, in_kernel); 28308c2ecf20Sopenharmony_ci return 1; 28318c2ecf20Sopenharmony_ci} 28328c2ecf20Sopenharmony_ci 28338c2ecf20Sopenharmony_cistatic int nop_interception(struct vcpu_svm *svm) 28348c2ecf20Sopenharmony_ci{ 28358c2ecf20Sopenharmony_ci return kvm_skip_emulated_instruction(&(svm->vcpu)); 28368c2ecf20Sopenharmony_ci} 28378c2ecf20Sopenharmony_ci 28388c2ecf20Sopenharmony_cistatic int monitor_interception(struct vcpu_svm *svm) 28398c2ecf20Sopenharmony_ci{ 28408c2ecf20Sopenharmony_ci printk_once(KERN_WARNING "kvm: MONITOR instruction emulated as NOP!\n"); 28418c2ecf20Sopenharmony_ci return nop_interception(svm); 28428c2ecf20Sopenharmony_ci} 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_cistatic int mwait_interception(struct vcpu_svm *svm) 28458c2ecf20Sopenharmony_ci{ 28468c2ecf20Sopenharmony_ci printk_once(KERN_WARNING "kvm: MWAIT instruction emulated as NOP!\n"); 28478c2ecf20Sopenharmony_ci return nop_interception(svm); 28488c2ecf20Sopenharmony_ci} 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_cistatic int invpcid_interception(struct vcpu_svm *svm) 28518c2ecf20Sopenharmony_ci{ 28528c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = &svm->vcpu; 28538c2ecf20Sopenharmony_ci unsigned long type; 28548c2ecf20Sopenharmony_ci gva_t gva; 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_ci if (!guest_cpuid_has(vcpu, X86_FEATURE_INVPCID)) { 28578c2ecf20Sopenharmony_ci kvm_queue_exception(vcpu, UD_VECTOR); 28588c2ecf20Sopenharmony_ci return 1; 28598c2ecf20Sopenharmony_ci } 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ci /* 28628c2ecf20Sopenharmony_ci * For an INVPCID intercept: 28638c2ecf20Sopenharmony_ci * EXITINFO1 provides the linear address of the memory operand. 28648c2ecf20Sopenharmony_ci * EXITINFO2 provides the contents of the register operand. 28658c2ecf20Sopenharmony_ci */ 28668c2ecf20Sopenharmony_ci type = svm->vmcb->control.exit_info_2; 28678c2ecf20Sopenharmony_ci gva = svm->vmcb->control.exit_info_1; 28688c2ecf20Sopenharmony_ci 28698c2ecf20Sopenharmony_ci if (type > 3) { 28708c2ecf20Sopenharmony_ci kvm_inject_gp(vcpu, 0); 28718c2ecf20Sopenharmony_ci return 1; 28728c2ecf20Sopenharmony_ci } 28738c2ecf20Sopenharmony_ci 28748c2ecf20Sopenharmony_ci return kvm_handle_invpcid(vcpu, type, gva); 28758c2ecf20Sopenharmony_ci} 28768c2ecf20Sopenharmony_ci 28778c2ecf20Sopenharmony_cistatic int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = { 28788c2ecf20Sopenharmony_ci [SVM_EXIT_READ_CR0] = cr_interception, 28798c2ecf20Sopenharmony_ci [SVM_EXIT_READ_CR3] = cr_interception, 28808c2ecf20Sopenharmony_ci [SVM_EXIT_READ_CR4] = cr_interception, 28818c2ecf20Sopenharmony_ci [SVM_EXIT_READ_CR8] = cr_interception, 28828c2ecf20Sopenharmony_ci [SVM_EXIT_CR0_SEL_WRITE] = cr_interception, 28838c2ecf20Sopenharmony_ci [SVM_EXIT_WRITE_CR0] = cr_interception, 28848c2ecf20Sopenharmony_ci [SVM_EXIT_WRITE_CR3] = cr_interception, 28858c2ecf20Sopenharmony_ci [SVM_EXIT_WRITE_CR4] = cr_interception, 28868c2ecf20Sopenharmony_ci [SVM_EXIT_WRITE_CR8] = cr8_write_interception, 28878c2ecf20Sopenharmony_ci [SVM_EXIT_READ_DR0] = dr_interception, 28888c2ecf20Sopenharmony_ci [SVM_EXIT_READ_DR1] = dr_interception, 28898c2ecf20Sopenharmony_ci [SVM_EXIT_READ_DR2] = dr_interception, 28908c2ecf20Sopenharmony_ci [SVM_EXIT_READ_DR3] = dr_interception, 28918c2ecf20Sopenharmony_ci [SVM_EXIT_READ_DR4] = dr_interception, 28928c2ecf20Sopenharmony_ci [SVM_EXIT_READ_DR5] = dr_interception, 28938c2ecf20Sopenharmony_ci [SVM_EXIT_READ_DR6] = dr_interception, 28948c2ecf20Sopenharmony_ci [SVM_EXIT_READ_DR7] = dr_interception, 28958c2ecf20Sopenharmony_ci [SVM_EXIT_WRITE_DR0] = dr_interception, 28968c2ecf20Sopenharmony_ci [SVM_EXIT_WRITE_DR1] = dr_interception, 28978c2ecf20Sopenharmony_ci [SVM_EXIT_WRITE_DR2] = dr_interception, 28988c2ecf20Sopenharmony_ci [SVM_EXIT_WRITE_DR3] = dr_interception, 28998c2ecf20Sopenharmony_ci [SVM_EXIT_WRITE_DR4] = dr_interception, 29008c2ecf20Sopenharmony_ci [SVM_EXIT_WRITE_DR5] = dr_interception, 29018c2ecf20Sopenharmony_ci [SVM_EXIT_WRITE_DR6] = dr_interception, 29028c2ecf20Sopenharmony_ci [SVM_EXIT_WRITE_DR7] = dr_interception, 29038c2ecf20Sopenharmony_ci [SVM_EXIT_EXCP_BASE + DB_VECTOR] = db_interception, 29048c2ecf20Sopenharmony_ci [SVM_EXIT_EXCP_BASE + BP_VECTOR] = bp_interception, 29058c2ecf20Sopenharmony_ci [SVM_EXIT_EXCP_BASE + UD_VECTOR] = ud_interception, 29068c2ecf20Sopenharmony_ci [SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception, 29078c2ecf20Sopenharmony_ci [SVM_EXIT_EXCP_BASE + MC_VECTOR] = mc_interception, 29088c2ecf20Sopenharmony_ci [SVM_EXIT_EXCP_BASE + AC_VECTOR] = ac_interception, 29098c2ecf20Sopenharmony_ci [SVM_EXIT_EXCP_BASE + GP_VECTOR] = gp_interception, 29108c2ecf20Sopenharmony_ci [SVM_EXIT_INTR] = intr_interception, 29118c2ecf20Sopenharmony_ci [SVM_EXIT_NMI] = nmi_interception, 29128c2ecf20Sopenharmony_ci [SVM_EXIT_SMI] = nop_on_interception, 29138c2ecf20Sopenharmony_ci [SVM_EXIT_INIT] = nop_on_interception, 29148c2ecf20Sopenharmony_ci [SVM_EXIT_VINTR] = interrupt_window_interception, 29158c2ecf20Sopenharmony_ci [SVM_EXIT_RDPMC] = rdpmc_interception, 29168c2ecf20Sopenharmony_ci [SVM_EXIT_CPUID] = cpuid_interception, 29178c2ecf20Sopenharmony_ci [SVM_EXIT_IRET] = iret_interception, 29188c2ecf20Sopenharmony_ci [SVM_EXIT_INVD] = invd_interception, 29198c2ecf20Sopenharmony_ci [SVM_EXIT_PAUSE] = pause_interception, 29208c2ecf20Sopenharmony_ci [SVM_EXIT_HLT] = halt_interception, 29218c2ecf20Sopenharmony_ci [SVM_EXIT_INVLPG] = invlpg_interception, 29228c2ecf20Sopenharmony_ci [SVM_EXIT_INVLPGA] = invlpga_interception, 29238c2ecf20Sopenharmony_ci [SVM_EXIT_IOIO] = io_interception, 29248c2ecf20Sopenharmony_ci [SVM_EXIT_MSR] = msr_interception, 29258c2ecf20Sopenharmony_ci [SVM_EXIT_TASK_SWITCH] = task_switch_interception, 29268c2ecf20Sopenharmony_ci [SVM_EXIT_SHUTDOWN] = shutdown_interception, 29278c2ecf20Sopenharmony_ci [SVM_EXIT_VMRUN] = vmrun_interception, 29288c2ecf20Sopenharmony_ci [SVM_EXIT_VMMCALL] = vmmcall_interception, 29298c2ecf20Sopenharmony_ci [SVM_EXIT_VMLOAD] = vmload_interception, 29308c2ecf20Sopenharmony_ci [SVM_EXIT_VMSAVE] = vmsave_interception, 29318c2ecf20Sopenharmony_ci [SVM_EXIT_STGI] = stgi_interception, 29328c2ecf20Sopenharmony_ci [SVM_EXIT_CLGI] = clgi_interception, 29338c2ecf20Sopenharmony_ci [SVM_EXIT_SKINIT] = skinit_interception, 29348c2ecf20Sopenharmony_ci [SVM_EXIT_WBINVD] = wbinvd_interception, 29358c2ecf20Sopenharmony_ci [SVM_EXIT_MONITOR] = monitor_interception, 29368c2ecf20Sopenharmony_ci [SVM_EXIT_MWAIT] = mwait_interception, 29378c2ecf20Sopenharmony_ci [SVM_EXIT_XSETBV] = xsetbv_interception, 29388c2ecf20Sopenharmony_ci [SVM_EXIT_RDPRU] = rdpru_interception, 29398c2ecf20Sopenharmony_ci [SVM_EXIT_INVPCID] = invpcid_interception, 29408c2ecf20Sopenharmony_ci [SVM_EXIT_NPF] = npf_interception, 29418c2ecf20Sopenharmony_ci [SVM_EXIT_RSM] = rsm_interception, 29428c2ecf20Sopenharmony_ci [SVM_EXIT_AVIC_INCOMPLETE_IPI] = avic_incomplete_ipi_interception, 29438c2ecf20Sopenharmony_ci [SVM_EXIT_AVIC_UNACCELERATED_ACCESS] = avic_unaccelerated_access_interception, 29448c2ecf20Sopenharmony_ci}; 29458c2ecf20Sopenharmony_ci 29468c2ecf20Sopenharmony_cistatic void dump_vmcb(struct kvm_vcpu *vcpu) 29478c2ecf20Sopenharmony_ci{ 29488c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 29498c2ecf20Sopenharmony_ci struct vmcb_control_area *control = &svm->vmcb->control; 29508c2ecf20Sopenharmony_ci struct vmcb_save_area *save = &svm->vmcb->save; 29518c2ecf20Sopenharmony_ci 29528c2ecf20Sopenharmony_ci if (!dump_invalid_vmcb) { 29538c2ecf20Sopenharmony_ci pr_warn_ratelimited("set kvm_amd.dump_invalid_vmcb=1 to dump internal KVM state.\n"); 29548c2ecf20Sopenharmony_ci return; 29558c2ecf20Sopenharmony_ci } 29568c2ecf20Sopenharmony_ci 29578c2ecf20Sopenharmony_ci pr_err("VMCB Control Area:\n"); 29588c2ecf20Sopenharmony_ci pr_err("%-20s%04x\n", "cr_read:", control->intercepts[INTERCEPT_CR] & 0xffff); 29598c2ecf20Sopenharmony_ci pr_err("%-20s%04x\n", "cr_write:", control->intercepts[INTERCEPT_CR] >> 16); 29608c2ecf20Sopenharmony_ci pr_err("%-20s%04x\n", "dr_read:", control->intercepts[INTERCEPT_DR] & 0xffff); 29618c2ecf20Sopenharmony_ci pr_err("%-20s%04x\n", "dr_write:", control->intercepts[INTERCEPT_DR] >> 16); 29628c2ecf20Sopenharmony_ci pr_err("%-20s%08x\n", "exceptions:", control->intercepts[INTERCEPT_EXCEPTION]); 29638c2ecf20Sopenharmony_ci pr_err("%-20s%08x %08x\n", "intercepts:", 29648c2ecf20Sopenharmony_ci control->intercepts[INTERCEPT_WORD3], 29658c2ecf20Sopenharmony_ci control->intercepts[INTERCEPT_WORD4]); 29668c2ecf20Sopenharmony_ci pr_err("%-20s%d\n", "pause filter count:", control->pause_filter_count); 29678c2ecf20Sopenharmony_ci pr_err("%-20s%d\n", "pause filter threshold:", 29688c2ecf20Sopenharmony_ci control->pause_filter_thresh); 29698c2ecf20Sopenharmony_ci pr_err("%-20s%016llx\n", "iopm_base_pa:", control->iopm_base_pa); 29708c2ecf20Sopenharmony_ci pr_err("%-20s%016llx\n", "msrpm_base_pa:", control->msrpm_base_pa); 29718c2ecf20Sopenharmony_ci pr_err("%-20s%016llx\n", "tsc_offset:", control->tsc_offset); 29728c2ecf20Sopenharmony_ci pr_err("%-20s%d\n", "asid:", control->asid); 29738c2ecf20Sopenharmony_ci pr_err("%-20s%d\n", "tlb_ctl:", control->tlb_ctl); 29748c2ecf20Sopenharmony_ci pr_err("%-20s%08x\n", "int_ctl:", control->int_ctl); 29758c2ecf20Sopenharmony_ci pr_err("%-20s%08x\n", "int_vector:", control->int_vector); 29768c2ecf20Sopenharmony_ci pr_err("%-20s%08x\n", "int_state:", control->int_state); 29778c2ecf20Sopenharmony_ci pr_err("%-20s%08x\n", "exit_code:", control->exit_code); 29788c2ecf20Sopenharmony_ci pr_err("%-20s%016llx\n", "exit_info1:", control->exit_info_1); 29798c2ecf20Sopenharmony_ci pr_err("%-20s%016llx\n", "exit_info2:", control->exit_info_2); 29808c2ecf20Sopenharmony_ci pr_err("%-20s%08x\n", "exit_int_info:", control->exit_int_info); 29818c2ecf20Sopenharmony_ci pr_err("%-20s%08x\n", "exit_int_info_err:", control->exit_int_info_err); 29828c2ecf20Sopenharmony_ci pr_err("%-20s%lld\n", "nested_ctl:", control->nested_ctl); 29838c2ecf20Sopenharmony_ci pr_err("%-20s%016llx\n", "nested_cr3:", control->nested_cr3); 29848c2ecf20Sopenharmony_ci pr_err("%-20s%016llx\n", "avic_vapic_bar:", control->avic_vapic_bar); 29858c2ecf20Sopenharmony_ci pr_err("%-20s%08x\n", "event_inj:", control->event_inj); 29868c2ecf20Sopenharmony_ci pr_err("%-20s%08x\n", "event_inj_err:", control->event_inj_err); 29878c2ecf20Sopenharmony_ci pr_err("%-20s%lld\n", "virt_ext:", control->virt_ext); 29888c2ecf20Sopenharmony_ci pr_err("%-20s%016llx\n", "next_rip:", control->next_rip); 29898c2ecf20Sopenharmony_ci pr_err("%-20s%016llx\n", "avic_backing_page:", control->avic_backing_page); 29908c2ecf20Sopenharmony_ci pr_err("%-20s%016llx\n", "avic_logical_id:", control->avic_logical_id); 29918c2ecf20Sopenharmony_ci pr_err("%-20s%016llx\n", "avic_physical_id:", control->avic_physical_id); 29928c2ecf20Sopenharmony_ci pr_err("VMCB State Save Area:\n"); 29938c2ecf20Sopenharmony_ci pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", 29948c2ecf20Sopenharmony_ci "es:", 29958c2ecf20Sopenharmony_ci save->es.selector, save->es.attrib, 29968c2ecf20Sopenharmony_ci save->es.limit, save->es.base); 29978c2ecf20Sopenharmony_ci pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", 29988c2ecf20Sopenharmony_ci "cs:", 29998c2ecf20Sopenharmony_ci save->cs.selector, save->cs.attrib, 30008c2ecf20Sopenharmony_ci save->cs.limit, save->cs.base); 30018c2ecf20Sopenharmony_ci pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", 30028c2ecf20Sopenharmony_ci "ss:", 30038c2ecf20Sopenharmony_ci save->ss.selector, save->ss.attrib, 30048c2ecf20Sopenharmony_ci save->ss.limit, save->ss.base); 30058c2ecf20Sopenharmony_ci pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", 30068c2ecf20Sopenharmony_ci "ds:", 30078c2ecf20Sopenharmony_ci save->ds.selector, save->ds.attrib, 30088c2ecf20Sopenharmony_ci save->ds.limit, save->ds.base); 30098c2ecf20Sopenharmony_ci pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", 30108c2ecf20Sopenharmony_ci "fs:", 30118c2ecf20Sopenharmony_ci save->fs.selector, save->fs.attrib, 30128c2ecf20Sopenharmony_ci save->fs.limit, save->fs.base); 30138c2ecf20Sopenharmony_ci pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", 30148c2ecf20Sopenharmony_ci "gs:", 30158c2ecf20Sopenharmony_ci save->gs.selector, save->gs.attrib, 30168c2ecf20Sopenharmony_ci save->gs.limit, save->gs.base); 30178c2ecf20Sopenharmony_ci pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", 30188c2ecf20Sopenharmony_ci "gdtr:", 30198c2ecf20Sopenharmony_ci save->gdtr.selector, save->gdtr.attrib, 30208c2ecf20Sopenharmony_ci save->gdtr.limit, save->gdtr.base); 30218c2ecf20Sopenharmony_ci pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", 30228c2ecf20Sopenharmony_ci "ldtr:", 30238c2ecf20Sopenharmony_ci save->ldtr.selector, save->ldtr.attrib, 30248c2ecf20Sopenharmony_ci save->ldtr.limit, save->ldtr.base); 30258c2ecf20Sopenharmony_ci pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", 30268c2ecf20Sopenharmony_ci "idtr:", 30278c2ecf20Sopenharmony_ci save->idtr.selector, save->idtr.attrib, 30288c2ecf20Sopenharmony_ci save->idtr.limit, save->idtr.base); 30298c2ecf20Sopenharmony_ci pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", 30308c2ecf20Sopenharmony_ci "tr:", 30318c2ecf20Sopenharmony_ci save->tr.selector, save->tr.attrib, 30328c2ecf20Sopenharmony_ci save->tr.limit, save->tr.base); 30338c2ecf20Sopenharmony_ci pr_err("cpl: %d efer: %016llx\n", 30348c2ecf20Sopenharmony_ci save->cpl, save->efer); 30358c2ecf20Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 30368c2ecf20Sopenharmony_ci "cr0:", save->cr0, "cr2:", save->cr2); 30378c2ecf20Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 30388c2ecf20Sopenharmony_ci "cr3:", save->cr3, "cr4:", save->cr4); 30398c2ecf20Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 30408c2ecf20Sopenharmony_ci "dr6:", save->dr6, "dr7:", save->dr7); 30418c2ecf20Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 30428c2ecf20Sopenharmony_ci "rip:", save->rip, "rflags:", save->rflags); 30438c2ecf20Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 30448c2ecf20Sopenharmony_ci "rsp:", save->rsp, "rax:", save->rax); 30458c2ecf20Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 30468c2ecf20Sopenharmony_ci "star:", save->star, "lstar:", save->lstar); 30478c2ecf20Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 30488c2ecf20Sopenharmony_ci "cstar:", save->cstar, "sfmask:", save->sfmask); 30498c2ecf20Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 30508c2ecf20Sopenharmony_ci "kernel_gs_base:", save->kernel_gs_base, 30518c2ecf20Sopenharmony_ci "sysenter_cs:", save->sysenter_cs); 30528c2ecf20Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 30538c2ecf20Sopenharmony_ci "sysenter_esp:", save->sysenter_esp, 30548c2ecf20Sopenharmony_ci "sysenter_eip:", save->sysenter_eip); 30558c2ecf20Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 30568c2ecf20Sopenharmony_ci "gpat:", save->g_pat, "dbgctl:", save->dbgctl); 30578c2ecf20Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 30588c2ecf20Sopenharmony_ci "br_from:", save->br_from, "br_to:", save->br_to); 30598c2ecf20Sopenharmony_ci pr_err("%-15s %016llx %-13s %016llx\n", 30608c2ecf20Sopenharmony_ci "excp_from:", save->last_excp_from, 30618c2ecf20Sopenharmony_ci "excp_to:", save->last_excp_to); 30628c2ecf20Sopenharmony_ci} 30638c2ecf20Sopenharmony_ci 30648c2ecf20Sopenharmony_cistatic void svm_get_exit_info(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2, 30658c2ecf20Sopenharmony_ci u32 *intr_info, u32 *error_code) 30668c2ecf20Sopenharmony_ci{ 30678c2ecf20Sopenharmony_ci struct vmcb_control_area *control = &to_svm(vcpu)->vmcb->control; 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci *info1 = control->exit_info_1; 30708c2ecf20Sopenharmony_ci *info2 = control->exit_info_2; 30718c2ecf20Sopenharmony_ci *intr_info = control->exit_int_info; 30728c2ecf20Sopenharmony_ci if ((*intr_info & SVM_EXITINTINFO_VALID) && 30738c2ecf20Sopenharmony_ci (*intr_info & SVM_EXITINTINFO_VALID_ERR)) 30748c2ecf20Sopenharmony_ci *error_code = control->exit_int_info_err; 30758c2ecf20Sopenharmony_ci else 30768c2ecf20Sopenharmony_ci *error_code = 0; 30778c2ecf20Sopenharmony_ci} 30788c2ecf20Sopenharmony_ci 30798c2ecf20Sopenharmony_cistatic int handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath) 30808c2ecf20Sopenharmony_ci{ 30818c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 30828c2ecf20Sopenharmony_ci struct kvm_run *kvm_run = vcpu->run; 30838c2ecf20Sopenharmony_ci u32 exit_code = svm->vmcb->control.exit_code; 30848c2ecf20Sopenharmony_ci 30858c2ecf20Sopenharmony_ci trace_kvm_exit(exit_code, vcpu, KVM_ISA_SVM); 30868c2ecf20Sopenharmony_ci 30878c2ecf20Sopenharmony_ci if (!svm_is_intercept(svm, INTERCEPT_CR0_WRITE)) 30888c2ecf20Sopenharmony_ci vcpu->arch.cr0 = svm->vmcb->save.cr0; 30898c2ecf20Sopenharmony_ci if (npt_enabled) 30908c2ecf20Sopenharmony_ci vcpu->arch.cr3 = svm->vmcb->save.cr3; 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_ci if (is_guest_mode(vcpu)) { 30938c2ecf20Sopenharmony_ci int vmexit; 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci trace_kvm_nested_vmexit(exit_code, vcpu, KVM_ISA_SVM); 30968c2ecf20Sopenharmony_ci 30978c2ecf20Sopenharmony_ci vmexit = nested_svm_exit_special(svm); 30988c2ecf20Sopenharmony_ci 30998c2ecf20Sopenharmony_ci if (vmexit == NESTED_EXIT_CONTINUE) 31008c2ecf20Sopenharmony_ci vmexit = nested_svm_exit_handled(svm); 31018c2ecf20Sopenharmony_ci 31028c2ecf20Sopenharmony_ci if (vmexit == NESTED_EXIT_DONE) 31038c2ecf20Sopenharmony_ci return 1; 31048c2ecf20Sopenharmony_ci } 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_ci if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) { 31078c2ecf20Sopenharmony_ci kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; 31088c2ecf20Sopenharmony_ci kvm_run->fail_entry.hardware_entry_failure_reason 31098c2ecf20Sopenharmony_ci = svm->vmcb->control.exit_code; 31108c2ecf20Sopenharmony_ci kvm_run->fail_entry.cpu = vcpu->arch.last_vmentry_cpu; 31118c2ecf20Sopenharmony_ci dump_vmcb(vcpu); 31128c2ecf20Sopenharmony_ci return 0; 31138c2ecf20Sopenharmony_ci } 31148c2ecf20Sopenharmony_ci 31158c2ecf20Sopenharmony_ci if (exit_fastpath != EXIT_FASTPATH_NONE) 31168c2ecf20Sopenharmony_ci return 1; 31178c2ecf20Sopenharmony_ci 31188c2ecf20Sopenharmony_ci if (exit_code >= ARRAY_SIZE(svm_exit_handlers) 31198c2ecf20Sopenharmony_ci || !svm_exit_handlers[exit_code]) { 31208c2ecf20Sopenharmony_ci vcpu_unimpl(vcpu, "svm: unexpected exit reason 0x%x\n", exit_code); 31218c2ecf20Sopenharmony_ci dump_vmcb(vcpu); 31228c2ecf20Sopenharmony_ci vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 31238c2ecf20Sopenharmony_ci vcpu->run->internal.suberror = 31248c2ecf20Sopenharmony_ci KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON; 31258c2ecf20Sopenharmony_ci vcpu->run->internal.ndata = 2; 31268c2ecf20Sopenharmony_ci vcpu->run->internal.data[0] = exit_code; 31278c2ecf20Sopenharmony_ci vcpu->run->internal.data[1] = vcpu->arch.last_vmentry_cpu; 31288c2ecf20Sopenharmony_ci return 0; 31298c2ecf20Sopenharmony_ci } 31308c2ecf20Sopenharmony_ci 31318c2ecf20Sopenharmony_ci#ifdef CONFIG_RETPOLINE 31328c2ecf20Sopenharmony_ci if (exit_code == SVM_EXIT_MSR) 31338c2ecf20Sopenharmony_ci return msr_interception(svm); 31348c2ecf20Sopenharmony_ci else if (exit_code == SVM_EXIT_VINTR) 31358c2ecf20Sopenharmony_ci return interrupt_window_interception(svm); 31368c2ecf20Sopenharmony_ci else if (exit_code == SVM_EXIT_INTR) 31378c2ecf20Sopenharmony_ci return intr_interception(svm); 31388c2ecf20Sopenharmony_ci else if (exit_code == SVM_EXIT_HLT) 31398c2ecf20Sopenharmony_ci return halt_interception(svm); 31408c2ecf20Sopenharmony_ci else if (exit_code == SVM_EXIT_NPF) 31418c2ecf20Sopenharmony_ci return npf_interception(svm); 31428c2ecf20Sopenharmony_ci#endif 31438c2ecf20Sopenharmony_ci return svm_exit_handlers[exit_code](svm); 31448c2ecf20Sopenharmony_ci} 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_cistatic void reload_tss(struct kvm_vcpu *vcpu) 31478c2ecf20Sopenharmony_ci{ 31488c2ecf20Sopenharmony_ci struct svm_cpu_data *sd = per_cpu(svm_data, vcpu->cpu); 31498c2ecf20Sopenharmony_ci 31508c2ecf20Sopenharmony_ci sd->tss_desc->type = 9; /* available 32/64-bit TSS */ 31518c2ecf20Sopenharmony_ci load_TR_desc(); 31528c2ecf20Sopenharmony_ci} 31538c2ecf20Sopenharmony_ci 31548c2ecf20Sopenharmony_cistatic void pre_svm_run(struct vcpu_svm *svm) 31558c2ecf20Sopenharmony_ci{ 31568c2ecf20Sopenharmony_ci struct svm_cpu_data *sd = per_cpu(svm_data, svm->vcpu.cpu); 31578c2ecf20Sopenharmony_ci 31588c2ecf20Sopenharmony_ci if (sev_guest(svm->vcpu.kvm)) 31598c2ecf20Sopenharmony_ci return pre_sev_run(svm, svm->vcpu.cpu); 31608c2ecf20Sopenharmony_ci 31618c2ecf20Sopenharmony_ci /* FIXME: handle wraparound of asid_generation */ 31628c2ecf20Sopenharmony_ci if (svm->asid_generation != sd->asid_generation) 31638c2ecf20Sopenharmony_ci new_asid(svm, sd); 31648c2ecf20Sopenharmony_ci} 31658c2ecf20Sopenharmony_ci 31668c2ecf20Sopenharmony_cistatic void svm_inject_nmi(struct kvm_vcpu *vcpu) 31678c2ecf20Sopenharmony_ci{ 31688c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 31698c2ecf20Sopenharmony_ci 31708c2ecf20Sopenharmony_ci svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_NMI; 31718c2ecf20Sopenharmony_ci vcpu->arch.hflags |= HF_NMI_MASK; 31728c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_IRET); 31738c2ecf20Sopenharmony_ci ++vcpu->stat.nmi_injections; 31748c2ecf20Sopenharmony_ci} 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_cistatic void svm_set_irq(struct kvm_vcpu *vcpu) 31778c2ecf20Sopenharmony_ci{ 31788c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 31798c2ecf20Sopenharmony_ci 31808c2ecf20Sopenharmony_ci trace_kvm_inj_virq(vcpu->arch.interrupt.nr); 31818c2ecf20Sopenharmony_ci ++vcpu->stat.irq_injections; 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci svm->vmcb->control.event_inj = vcpu->arch.interrupt.nr | 31848c2ecf20Sopenharmony_ci SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR; 31858c2ecf20Sopenharmony_ci} 31868c2ecf20Sopenharmony_ci 31878c2ecf20Sopenharmony_cistatic void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) 31888c2ecf20Sopenharmony_ci{ 31898c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 31908c2ecf20Sopenharmony_ci 31918c2ecf20Sopenharmony_ci if (nested_svm_virtualize_tpr(vcpu)) 31928c2ecf20Sopenharmony_ci return; 31938c2ecf20Sopenharmony_ci 31948c2ecf20Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_CR8_WRITE); 31958c2ecf20Sopenharmony_ci 31968c2ecf20Sopenharmony_ci if (irr == -1) 31978c2ecf20Sopenharmony_ci return; 31988c2ecf20Sopenharmony_ci 31998c2ecf20Sopenharmony_ci if (tpr >= irr) 32008c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_CR8_WRITE); 32018c2ecf20Sopenharmony_ci} 32028c2ecf20Sopenharmony_ci 32038c2ecf20Sopenharmony_cibool svm_nmi_blocked(struct kvm_vcpu *vcpu) 32048c2ecf20Sopenharmony_ci{ 32058c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 32068c2ecf20Sopenharmony_ci struct vmcb *vmcb = svm->vmcb; 32078c2ecf20Sopenharmony_ci bool ret; 32088c2ecf20Sopenharmony_ci 32098c2ecf20Sopenharmony_ci if (!gif_set(svm)) 32108c2ecf20Sopenharmony_ci return true; 32118c2ecf20Sopenharmony_ci 32128c2ecf20Sopenharmony_ci if (is_guest_mode(vcpu) && nested_exit_on_nmi(svm)) 32138c2ecf20Sopenharmony_ci return false; 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_ci ret = (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) || 32168c2ecf20Sopenharmony_ci (svm->vcpu.arch.hflags & HF_NMI_MASK); 32178c2ecf20Sopenharmony_ci 32188c2ecf20Sopenharmony_ci return ret; 32198c2ecf20Sopenharmony_ci} 32208c2ecf20Sopenharmony_ci 32218c2ecf20Sopenharmony_cistatic int svm_nmi_allowed(struct kvm_vcpu *vcpu, bool for_injection) 32228c2ecf20Sopenharmony_ci{ 32238c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 32248c2ecf20Sopenharmony_ci if (svm->nested.nested_run_pending) 32258c2ecf20Sopenharmony_ci return -EBUSY; 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_ci /* An NMI must not be injected into L2 if it's supposed to VM-Exit. */ 32288c2ecf20Sopenharmony_ci if (for_injection && is_guest_mode(vcpu) && nested_exit_on_nmi(svm)) 32298c2ecf20Sopenharmony_ci return -EBUSY; 32308c2ecf20Sopenharmony_ci 32318c2ecf20Sopenharmony_ci return !svm_nmi_blocked(vcpu); 32328c2ecf20Sopenharmony_ci} 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_cistatic bool svm_get_nmi_mask(struct kvm_vcpu *vcpu) 32358c2ecf20Sopenharmony_ci{ 32368c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 32378c2ecf20Sopenharmony_ci 32388c2ecf20Sopenharmony_ci return !!(svm->vcpu.arch.hflags & HF_NMI_MASK); 32398c2ecf20Sopenharmony_ci} 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_cistatic void svm_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked) 32428c2ecf20Sopenharmony_ci{ 32438c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 32448c2ecf20Sopenharmony_ci 32458c2ecf20Sopenharmony_ci if (masked) { 32468c2ecf20Sopenharmony_ci svm->vcpu.arch.hflags |= HF_NMI_MASK; 32478c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_IRET); 32488c2ecf20Sopenharmony_ci } else { 32498c2ecf20Sopenharmony_ci svm->vcpu.arch.hflags &= ~HF_NMI_MASK; 32508c2ecf20Sopenharmony_ci svm_clr_intercept(svm, INTERCEPT_IRET); 32518c2ecf20Sopenharmony_ci } 32528c2ecf20Sopenharmony_ci} 32538c2ecf20Sopenharmony_ci 32548c2ecf20Sopenharmony_cibool svm_interrupt_blocked(struct kvm_vcpu *vcpu) 32558c2ecf20Sopenharmony_ci{ 32568c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 32578c2ecf20Sopenharmony_ci struct vmcb *vmcb = svm->vmcb; 32588c2ecf20Sopenharmony_ci 32598c2ecf20Sopenharmony_ci if (!gif_set(svm)) 32608c2ecf20Sopenharmony_ci return true; 32618c2ecf20Sopenharmony_ci 32628c2ecf20Sopenharmony_ci if (is_guest_mode(vcpu)) { 32638c2ecf20Sopenharmony_ci /* As long as interrupts are being delivered... */ 32648c2ecf20Sopenharmony_ci if ((svm->nested.ctl.int_ctl & V_INTR_MASKING_MASK) 32658c2ecf20Sopenharmony_ci ? !(svm->nested.hsave->save.rflags & X86_EFLAGS_IF) 32668c2ecf20Sopenharmony_ci : !(kvm_get_rflags(vcpu) & X86_EFLAGS_IF)) 32678c2ecf20Sopenharmony_ci return true; 32688c2ecf20Sopenharmony_ci 32698c2ecf20Sopenharmony_ci /* ... vmexits aren't blocked by the interrupt shadow */ 32708c2ecf20Sopenharmony_ci if (nested_exit_on_intr(svm)) 32718c2ecf20Sopenharmony_ci return false; 32728c2ecf20Sopenharmony_ci } else { 32738c2ecf20Sopenharmony_ci if (!(kvm_get_rflags(vcpu) & X86_EFLAGS_IF)) 32748c2ecf20Sopenharmony_ci return true; 32758c2ecf20Sopenharmony_ci } 32768c2ecf20Sopenharmony_ci 32778c2ecf20Sopenharmony_ci return (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK); 32788c2ecf20Sopenharmony_ci} 32798c2ecf20Sopenharmony_ci 32808c2ecf20Sopenharmony_cistatic int svm_interrupt_allowed(struct kvm_vcpu *vcpu, bool for_injection) 32818c2ecf20Sopenharmony_ci{ 32828c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 32838c2ecf20Sopenharmony_ci if (svm->nested.nested_run_pending) 32848c2ecf20Sopenharmony_ci return -EBUSY; 32858c2ecf20Sopenharmony_ci 32868c2ecf20Sopenharmony_ci /* 32878c2ecf20Sopenharmony_ci * An IRQ must not be injected into L2 if it's supposed to VM-Exit, 32888c2ecf20Sopenharmony_ci * e.g. if the IRQ arrived asynchronously after checking nested events. 32898c2ecf20Sopenharmony_ci */ 32908c2ecf20Sopenharmony_ci if (for_injection && is_guest_mode(vcpu) && nested_exit_on_intr(svm)) 32918c2ecf20Sopenharmony_ci return -EBUSY; 32928c2ecf20Sopenharmony_ci 32938c2ecf20Sopenharmony_ci return !svm_interrupt_blocked(vcpu); 32948c2ecf20Sopenharmony_ci} 32958c2ecf20Sopenharmony_ci 32968c2ecf20Sopenharmony_cistatic void enable_irq_window(struct kvm_vcpu *vcpu) 32978c2ecf20Sopenharmony_ci{ 32988c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 32998c2ecf20Sopenharmony_ci 33008c2ecf20Sopenharmony_ci /* 33018c2ecf20Sopenharmony_ci * In case GIF=0 we can't rely on the CPU to tell us when GIF becomes 33028c2ecf20Sopenharmony_ci * 1, because that's a separate STGI/VMRUN intercept. The next time we 33038c2ecf20Sopenharmony_ci * get that intercept, this function will be called again though and 33048c2ecf20Sopenharmony_ci * we'll get the vintr intercept. However, if the vGIF feature is 33058c2ecf20Sopenharmony_ci * enabled, the STGI interception will not occur. Enable the irq 33068c2ecf20Sopenharmony_ci * window under the assumption that the hardware will set the GIF. 33078c2ecf20Sopenharmony_ci */ 33088c2ecf20Sopenharmony_ci if (vgif_enabled(svm) || gif_set(svm)) { 33098c2ecf20Sopenharmony_ci /* 33108c2ecf20Sopenharmony_ci * IRQ window is not needed when AVIC is enabled, 33118c2ecf20Sopenharmony_ci * unless we have pending ExtINT since it cannot be injected 33128c2ecf20Sopenharmony_ci * via AVIC. In such case, we need to temporarily disable AVIC, 33138c2ecf20Sopenharmony_ci * and fallback to injecting IRQ via V_IRQ. 33148c2ecf20Sopenharmony_ci */ 33158c2ecf20Sopenharmony_ci svm_toggle_avic_for_irq_window(vcpu, false); 33168c2ecf20Sopenharmony_ci svm_set_vintr(svm); 33178c2ecf20Sopenharmony_ci } 33188c2ecf20Sopenharmony_ci} 33198c2ecf20Sopenharmony_ci 33208c2ecf20Sopenharmony_cistatic void enable_nmi_window(struct kvm_vcpu *vcpu) 33218c2ecf20Sopenharmony_ci{ 33228c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 33238c2ecf20Sopenharmony_ci 33248c2ecf20Sopenharmony_ci if ((svm->vcpu.arch.hflags & (HF_NMI_MASK | HF_IRET_MASK)) 33258c2ecf20Sopenharmony_ci == HF_NMI_MASK) 33268c2ecf20Sopenharmony_ci return; /* IRET will cause a vm exit */ 33278c2ecf20Sopenharmony_ci 33288c2ecf20Sopenharmony_ci if (!gif_set(svm)) { 33298c2ecf20Sopenharmony_ci if (vgif_enabled(svm)) 33308c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_STGI); 33318c2ecf20Sopenharmony_ci return; /* STGI will cause a vm exit */ 33328c2ecf20Sopenharmony_ci } 33338c2ecf20Sopenharmony_ci 33348c2ecf20Sopenharmony_ci /* 33358c2ecf20Sopenharmony_ci * Something prevents NMI from been injected. Single step over possible 33368c2ecf20Sopenharmony_ci * problem (IRET or exception injection or interrupt shadow) 33378c2ecf20Sopenharmony_ci */ 33388c2ecf20Sopenharmony_ci svm->nmi_singlestep_guest_rflags = svm_get_rflags(vcpu); 33398c2ecf20Sopenharmony_ci svm->nmi_singlestep = true; 33408c2ecf20Sopenharmony_ci svm->vmcb->save.rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF); 33418c2ecf20Sopenharmony_ci} 33428c2ecf20Sopenharmony_ci 33438c2ecf20Sopenharmony_cistatic int svm_set_tss_addr(struct kvm *kvm, unsigned int addr) 33448c2ecf20Sopenharmony_ci{ 33458c2ecf20Sopenharmony_ci return 0; 33468c2ecf20Sopenharmony_ci} 33478c2ecf20Sopenharmony_ci 33488c2ecf20Sopenharmony_cistatic int svm_set_identity_map_addr(struct kvm *kvm, u64 ident_addr) 33498c2ecf20Sopenharmony_ci{ 33508c2ecf20Sopenharmony_ci return 0; 33518c2ecf20Sopenharmony_ci} 33528c2ecf20Sopenharmony_ci 33538c2ecf20Sopenharmony_civoid svm_flush_tlb(struct kvm_vcpu *vcpu) 33548c2ecf20Sopenharmony_ci{ 33558c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 33568c2ecf20Sopenharmony_ci 33578c2ecf20Sopenharmony_ci /* 33588c2ecf20Sopenharmony_ci * Flush only the current ASID even if the TLB flush was invoked via 33598c2ecf20Sopenharmony_ci * kvm_flush_remote_tlbs(). Although flushing remote TLBs requires all 33608c2ecf20Sopenharmony_ci * ASIDs to be flushed, KVM uses a single ASID for L1 and L2, and 33618c2ecf20Sopenharmony_ci * unconditionally does a TLB flush on both nested VM-Enter and nested 33628c2ecf20Sopenharmony_ci * VM-Exit (via kvm_mmu_reset_context()). 33638c2ecf20Sopenharmony_ci */ 33648c2ecf20Sopenharmony_ci if (static_cpu_has(X86_FEATURE_FLUSHBYASID)) 33658c2ecf20Sopenharmony_ci svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ASID; 33668c2ecf20Sopenharmony_ci else 33678c2ecf20Sopenharmony_ci svm->asid_generation--; 33688c2ecf20Sopenharmony_ci} 33698c2ecf20Sopenharmony_ci 33708c2ecf20Sopenharmony_cistatic void svm_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t gva) 33718c2ecf20Sopenharmony_ci{ 33728c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 33738c2ecf20Sopenharmony_ci 33748c2ecf20Sopenharmony_ci invlpga(gva, svm->vmcb->control.asid); 33758c2ecf20Sopenharmony_ci} 33768c2ecf20Sopenharmony_ci 33778c2ecf20Sopenharmony_cistatic void svm_prepare_guest_switch(struct kvm_vcpu *vcpu) 33788c2ecf20Sopenharmony_ci{ 33798c2ecf20Sopenharmony_ci amd_clear_divider(); 33808c2ecf20Sopenharmony_ci} 33818c2ecf20Sopenharmony_ci 33828c2ecf20Sopenharmony_cistatic inline void sync_cr8_to_lapic(struct kvm_vcpu *vcpu) 33838c2ecf20Sopenharmony_ci{ 33848c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 33858c2ecf20Sopenharmony_ci 33868c2ecf20Sopenharmony_ci if (nested_svm_virtualize_tpr(vcpu)) 33878c2ecf20Sopenharmony_ci return; 33888c2ecf20Sopenharmony_ci 33898c2ecf20Sopenharmony_ci if (!svm_is_intercept(svm, INTERCEPT_CR8_WRITE)) { 33908c2ecf20Sopenharmony_ci int cr8 = svm->vmcb->control.int_ctl & V_TPR_MASK; 33918c2ecf20Sopenharmony_ci kvm_set_cr8(vcpu, cr8); 33928c2ecf20Sopenharmony_ci } 33938c2ecf20Sopenharmony_ci} 33948c2ecf20Sopenharmony_ci 33958c2ecf20Sopenharmony_cistatic inline void sync_lapic_to_cr8(struct kvm_vcpu *vcpu) 33968c2ecf20Sopenharmony_ci{ 33978c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 33988c2ecf20Sopenharmony_ci u64 cr8; 33998c2ecf20Sopenharmony_ci 34008c2ecf20Sopenharmony_ci if (nested_svm_virtualize_tpr(vcpu) || 34018c2ecf20Sopenharmony_ci kvm_vcpu_apicv_active(vcpu)) 34028c2ecf20Sopenharmony_ci return; 34038c2ecf20Sopenharmony_ci 34048c2ecf20Sopenharmony_ci cr8 = kvm_get_cr8(vcpu); 34058c2ecf20Sopenharmony_ci svm->vmcb->control.int_ctl &= ~V_TPR_MASK; 34068c2ecf20Sopenharmony_ci svm->vmcb->control.int_ctl |= cr8 & V_TPR_MASK; 34078c2ecf20Sopenharmony_ci} 34088c2ecf20Sopenharmony_ci 34098c2ecf20Sopenharmony_cistatic void svm_complete_interrupts(struct vcpu_svm *svm) 34108c2ecf20Sopenharmony_ci{ 34118c2ecf20Sopenharmony_ci u8 vector; 34128c2ecf20Sopenharmony_ci int type; 34138c2ecf20Sopenharmony_ci u32 exitintinfo = svm->vmcb->control.exit_int_info; 34148c2ecf20Sopenharmony_ci unsigned int3_injected = svm->int3_injected; 34158c2ecf20Sopenharmony_ci 34168c2ecf20Sopenharmony_ci svm->int3_injected = 0; 34178c2ecf20Sopenharmony_ci 34188c2ecf20Sopenharmony_ci /* 34198c2ecf20Sopenharmony_ci * If we've made progress since setting HF_IRET_MASK, we've 34208c2ecf20Sopenharmony_ci * executed an IRET and can allow NMI injection. 34218c2ecf20Sopenharmony_ci */ 34228c2ecf20Sopenharmony_ci if ((svm->vcpu.arch.hflags & HF_IRET_MASK) 34238c2ecf20Sopenharmony_ci && kvm_rip_read(&svm->vcpu) != svm->nmi_iret_rip) { 34248c2ecf20Sopenharmony_ci svm->vcpu.arch.hflags &= ~(HF_NMI_MASK | HF_IRET_MASK); 34258c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_EVENT, &svm->vcpu); 34268c2ecf20Sopenharmony_ci } 34278c2ecf20Sopenharmony_ci 34288c2ecf20Sopenharmony_ci svm->vcpu.arch.nmi_injected = false; 34298c2ecf20Sopenharmony_ci kvm_clear_exception_queue(&svm->vcpu); 34308c2ecf20Sopenharmony_ci kvm_clear_interrupt_queue(&svm->vcpu); 34318c2ecf20Sopenharmony_ci 34328c2ecf20Sopenharmony_ci if (!(exitintinfo & SVM_EXITINTINFO_VALID)) 34338c2ecf20Sopenharmony_ci return; 34348c2ecf20Sopenharmony_ci 34358c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_EVENT, &svm->vcpu); 34368c2ecf20Sopenharmony_ci 34378c2ecf20Sopenharmony_ci vector = exitintinfo & SVM_EXITINTINFO_VEC_MASK; 34388c2ecf20Sopenharmony_ci type = exitintinfo & SVM_EXITINTINFO_TYPE_MASK; 34398c2ecf20Sopenharmony_ci 34408c2ecf20Sopenharmony_ci switch (type) { 34418c2ecf20Sopenharmony_ci case SVM_EXITINTINFO_TYPE_NMI: 34428c2ecf20Sopenharmony_ci svm->vcpu.arch.nmi_injected = true; 34438c2ecf20Sopenharmony_ci break; 34448c2ecf20Sopenharmony_ci case SVM_EXITINTINFO_TYPE_EXEPT: 34458c2ecf20Sopenharmony_ci /* 34468c2ecf20Sopenharmony_ci * In case of software exceptions, do not reinject the vector, 34478c2ecf20Sopenharmony_ci * but re-execute the instruction instead. Rewind RIP first 34488c2ecf20Sopenharmony_ci * if we emulated INT3 before. 34498c2ecf20Sopenharmony_ci */ 34508c2ecf20Sopenharmony_ci if (kvm_exception_is_soft(vector)) { 34518c2ecf20Sopenharmony_ci if (vector == BP_VECTOR && int3_injected && 34528c2ecf20Sopenharmony_ci kvm_is_linear_rip(&svm->vcpu, svm->int3_rip)) 34538c2ecf20Sopenharmony_ci kvm_rip_write(&svm->vcpu, 34548c2ecf20Sopenharmony_ci kvm_rip_read(&svm->vcpu) - 34558c2ecf20Sopenharmony_ci int3_injected); 34568c2ecf20Sopenharmony_ci break; 34578c2ecf20Sopenharmony_ci } 34588c2ecf20Sopenharmony_ci if (exitintinfo & SVM_EXITINTINFO_VALID_ERR) { 34598c2ecf20Sopenharmony_ci u32 err = svm->vmcb->control.exit_int_info_err; 34608c2ecf20Sopenharmony_ci kvm_requeue_exception_e(&svm->vcpu, vector, err); 34618c2ecf20Sopenharmony_ci 34628c2ecf20Sopenharmony_ci } else 34638c2ecf20Sopenharmony_ci kvm_requeue_exception(&svm->vcpu, vector); 34648c2ecf20Sopenharmony_ci break; 34658c2ecf20Sopenharmony_ci case SVM_EXITINTINFO_TYPE_INTR: 34668c2ecf20Sopenharmony_ci kvm_queue_interrupt(&svm->vcpu, vector, false); 34678c2ecf20Sopenharmony_ci break; 34688c2ecf20Sopenharmony_ci default: 34698c2ecf20Sopenharmony_ci break; 34708c2ecf20Sopenharmony_ci } 34718c2ecf20Sopenharmony_ci} 34728c2ecf20Sopenharmony_ci 34738c2ecf20Sopenharmony_cistatic void svm_cancel_injection(struct kvm_vcpu *vcpu) 34748c2ecf20Sopenharmony_ci{ 34758c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 34768c2ecf20Sopenharmony_ci struct vmcb_control_area *control = &svm->vmcb->control; 34778c2ecf20Sopenharmony_ci 34788c2ecf20Sopenharmony_ci control->exit_int_info = control->event_inj; 34798c2ecf20Sopenharmony_ci control->exit_int_info_err = control->event_inj_err; 34808c2ecf20Sopenharmony_ci control->event_inj = 0; 34818c2ecf20Sopenharmony_ci svm_complete_interrupts(svm); 34828c2ecf20Sopenharmony_ci} 34838c2ecf20Sopenharmony_ci 34848c2ecf20Sopenharmony_cistatic fastpath_t svm_exit_handlers_fastpath(struct kvm_vcpu *vcpu) 34858c2ecf20Sopenharmony_ci{ 34868c2ecf20Sopenharmony_ci struct vmcb_control_area *control = &to_svm(vcpu)->vmcb->control; 34878c2ecf20Sopenharmony_ci 34888c2ecf20Sopenharmony_ci /* 34898c2ecf20Sopenharmony_ci * Note, the next RIP must be provided as SRCU isn't held, i.e. KVM 34908c2ecf20Sopenharmony_ci * can't read guest memory (dereference memslots) to decode the WRMSR. 34918c2ecf20Sopenharmony_ci */ 34928c2ecf20Sopenharmony_ci if (control->exit_code == SVM_EXIT_MSR && control->exit_info_1 && 34938c2ecf20Sopenharmony_ci nrips && control->next_rip) 34948c2ecf20Sopenharmony_ci return handle_fastpath_set_msr_irqoff(vcpu); 34958c2ecf20Sopenharmony_ci 34968c2ecf20Sopenharmony_ci return EXIT_FASTPATH_NONE; 34978c2ecf20Sopenharmony_ci} 34988c2ecf20Sopenharmony_ci 34998c2ecf20Sopenharmony_civoid __svm_vcpu_run(unsigned long vmcb_pa, unsigned long *regs); 35008c2ecf20Sopenharmony_ci 35018c2ecf20Sopenharmony_cistatic noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu, 35028c2ecf20Sopenharmony_ci struct vcpu_svm *svm) 35038c2ecf20Sopenharmony_ci{ 35048c2ecf20Sopenharmony_ci /* 35058c2ecf20Sopenharmony_ci * VMENTER enables interrupts (host state), but the kernel state is 35068c2ecf20Sopenharmony_ci * interrupts disabled when this is invoked. Also tell RCU about 35078c2ecf20Sopenharmony_ci * it. This is the same logic as for exit_to_user_mode(). 35088c2ecf20Sopenharmony_ci * 35098c2ecf20Sopenharmony_ci * This ensures that e.g. latency analysis on the host observes 35108c2ecf20Sopenharmony_ci * guest mode as interrupt enabled. 35118c2ecf20Sopenharmony_ci * 35128c2ecf20Sopenharmony_ci * guest_enter_irqoff() informs context tracking about the 35138c2ecf20Sopenharmony_ci * transition to guest mode and if enabled adjusts RCU state 35148c2ecf20Sopenharmony_ci * accordingly. 35158c2ecf20Sopenharmony_ci */ 35168c2ecf20Sopenharmony_ci instrumentation_begin(); 35178c2ecf20Sopenharmony_ci trace_hardirqs_on_prepare(); 35188c2ecf20Sopenharmony_ci lockdep_hardirqs_on_prepare(CALLER_ADDR0); 35198c2ecf20Sopenharmony_ci instrumentation_end(); 35208c2ecf20Sopenharmony_ci 35218c2ecf20Sopenharmony_ci guest_enter_irqoff(); 35228c2ecf20Sopenharmony_ci lockdep_hardirqs_on(CALLER_ADDR0); 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_ci __svm_vcpu_run(svm->vmcb_pa, (unsigned long *)&svm->vcpu.arch.regs); 35258c2ecf20Sopenharmony_ci 35268c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 35278c2ecf20Sopenharmony_ci native_wrmsrl(MSR_GS_BASE, svm->host.gs_base); 35288c2ecf20Sopenharmony_ci#else 35298c2ecf20Sopenharmony_ci loadsegment(fs, svm->host.fs); 35308c2ecf20Sopenharmony_ci#ifndef CONFIG_X86_32_LAZY_GS 35318c2ecf20Sopenharmony_ci loadsegment(gs, svm->host.gs); 35328c2ecf20Sopenharmony_ci#endif 35338c2ecf20Sopenharmony_ci#endif 35348c2ecf20Sopenharmony_ci 35358c2ecf20Sopenharmony_ci /* 35368c2ecf20Sopenharmony_ci * VMEXIT disables interrupts (host state), but tracing and lockdep 35378c2ecf20Sopenharmony_ci * have them in state 'on' as recorded before entering guest mode. 35388c2ecf20Sopenharmony_ci * Same as enter_from_user_mode(). 35398c2ecf20Sopenharmony_ci * 35408c2ecf20Sopenharmony_ci * context_tracking_guest_exit() restores host context and reinstates 35418c2ecf20Sopenharmony_ci * RCU if enabled and required. 35428c2ecf20Sopenharmony_ci * 35438c2ecf20Sopenharmony_ci * This needs to be done before the below as native_read_msr() 35448c2ecf20Sopenharmony_ci * contains a tracepoint and x86_spec_ctrl_restore_host() calls 35458c2ecf20Sopenharmony_ci * into world and some more. 35468c2ecf20Sopenharmony_ci */ 35478c2ecf20Sopenharmony_ci lockdep_hardirqs_off(CALLER_ADDR0); 35488c2ecf20Sopenharmony_ci context_tracking_guest_exit(); 35498c2ecf20Sopenharmony_ci 35508c2ecf20Sopenharmony_ci instrumentation_begin(); 35518c2ecf20Sopenharmony_ci trace_hardirqs_off_finish(); 35528c2ecf20Sopenharmony_ci instrumentation_end(); 35538c2ecf20Sopenharmony_ci} 35548c2ecf20Sopenharmony_ci 35558c2ecf20Sopenharmony_cistatic __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu) 35568c2ecf20Sopenharmony_ci{ 35578c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 35588c2ecf20Sopenharmony_ci 35598c2ecf20Sopenharmony_ci svm->vmcb->save.rax = vcpu->arch.regs[VCPU_REGS_RAX]; 35608c2ecf20Sopenharmony_ci svm->vmcb->save.rsp = vcpu->arch.regs[VCPU_REGS_RSP]; 35618c2ecf20Sopenharmony_ci svm->vmcb->save.rip = vcpu->arch.regs[VCPU_REGS_RIP]; 35628c2ecf20Sopenharmony_ci 35638c2ecf20Sopenharmony_ci /* 35648c2ecf20Sopenharmony_ci * Disable singlestep if we're injecting an interrupt/exception. 35658c2ecf20Sopenharmony_ci * We don't want our modified rflags to be pushed on the stack where 35668c2ecf20Sopenharmony_ci * we might not be able to easily reset them if we disabled NMI 35678c2ecf20Sopenharmony_ci * singlestep later. 35688c2ecf20Sopenharmony_ci */ 35698c2ecf20Sopenharmony_ci if (svm->nmi_singlestep && svm->vmcb->control.event_inj) { 35708c2ecf20Sopenharmony_ci /* 35718c2ecf20Sopenharmony_ci * Event injection happens before external interrupts cause a 35728c2ecf20Sopenharmony_ci * vmexit and interrupts are disabled here, so smp_send_reschedule 35738c2ecf20Sopenharmony_ci * is enough to force an immediate vmexit. 35748c2ecf20Sopenharmony_ci */ 35758c2ecf20Sopenharmony_ci disable_nmi_singlestep(svm); 35768c2ecf20Sopenharmony_ci smp_send_reschedule(vcpu->cpu); 35778c2ecf20Sopenharmony_ci } 35788c2ecf20Sopenharmony_ci 35798c2ecf20Sopenharmony_ci pre_svm_run(svm); 35808c2ecf20Sopenharmony_ci 35818c2ecf20Sopenharmony_ci sync_lapic_to_cr8(vcpu); 35828c2ecf20Sopenharmony_ci 35838c2ecf20Sopenharmony_ci svm->vmcb->save.cr2 = vcpu->arch.cr2; 35848c2ecf20Sopenharmony_ci 35858c2ecf20Sopenharmony_ci /* 35868c2ecf20Sopenharmony_ci * Run with all-zero DR6 unless needed, so that we can get the exact cause 35878c2ecf20Sopenharmony_ci * of a #DB. 35888c2ecf20Sopenharmony_ci */ 35898c2ecf20Sopenharmony_ci if (unlikely(svm->vcpu.arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)) 35908c2ecf20Sopenharmony_ci svm_set_dr6(svm, vcpu->arch.dr6); 35918c2ecf20Sopenharmony_ci else 35928c2ecf20Sopenharmony_ci svm_set_dr6(svm, DR6_FIXED_1 | DR6_RTM); 35938c2ecf20Sopenharmony_ci 35948c2ecf20Sopenharmony_ci clgi(); 35958c2ecf20Sopenharmony_ci kvm_load_guest_xsave_state(vcpu); 35968c2ecf20Sopenharmony_ci 35978c2ecf20Sopenharmony_ci kvm_wait_lapic_expire(vcpu); 35988c2ecf20Sopenharmony_ci 35998c2ecf20Sopenharmony_ci /* 36008c2ecf20Sopenharmony_ci * If this vCPU has touched SPEC_CTRL, restore the guest's value if 36018c2ecf20Sopenharmony_ci * it's non-zero. Since vmentry is serialising on affected CPUs, there 36028c2ecf20Sopenharmony_ci * is no need to worry about the conditional branch over the wrmsr 36038c2ecf20Sopenharmony_ci * being speculatively taken. 36048c2ecf20Sopenharmony_ci */ 36058c2ecf20Sopenharmony_ci x86_spec_ctrl_set_guest(svm->spec_ctrl, svm->virt_spec_ctrl); 36068c2ecf20Sopenharmony_ci 36078c2ecf20Sopenharmony_ci svm_vcpu_enter_exit(vcpu, svm); 36088c2ecf20Sopenharmony_ci 36098c2ecf20Sopenharmony_ci /* 36108c2ecf20Sopenharmony_ci * We do not use IBRS in the kernel. If this vCPU has used the 36118c2ecf20Sopenharmony_ci * SPEC_CTRL MSR it may have left it on; save the value and 36128c2ecf20Sopenharmony_ci * turn it off. This is much more efficient than blindly adding 36138c2ecf20Sopenharmony_ci * it to the atomic save/restore list. Especially as the former 36148c2ecf20Sopenharmony_ci * (Saving guest MSRs on vmexit) doesn't even exist in KVM. 36158c2ecf20Sopenharmony_ci * 36168c2ecf20Sopenharmony_ci * For non-nested case: 36178c2ecf20Sopenharmony_ci * If the L01 MSR bitmap does not intercept the MSR, then we need to 36188c2ecf20Sopenharmony_ci * save it. 36198c2ecf20Sopenharmony_ci * 36208c2ecf20Sopenharmony_ci * For nested case: 36218c2ecf20Sopenharmony_ci * If the L02 MSR bitmap does not intercept the MSR, then we need to 36228c2ecf20Sopenharmony_ci * save it. 36238c2ecf20Sopenharmony_ci */ 36248c2ecf20Sopenharmony_ci if (unlikely(!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL))) 36258c2ecf20Sopenharmony_ci svm->spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL); 36268c2ecf20Sopenharmony_ci 36278c2ecf20Sopenharmony_ci reload_tss(vcpu); 36288c2ecf20Sopenharmony_ci 36298c2ecf20Sopenharmony_ci x86_spec_ctrl_restore_host(svm->spec_ctrl, svm->virt_spec_ctrl); 36308c2ecf20Sopenharmony_ci 36318c2ecf20Sopenharmony_ci vcpu->arch.cr2 = svm->vmcb->save.cr2; 36328c2ecf20Sopenharmony_ci vcpu->arch.regs[VCPU_REGS_RAX] = svm->vmcb->save.rax; 36338c2ecf20Sopenharmony_ci vcpu->arch.regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp; 36348c2ecf20Sopenharmony_ci vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip; 36358c2ecf20Sopenharmony_ci 36368c2ecf20Sopenharmony_ci if (unlikely(svm->vmcb->control.exit_code == SVM_EXIT_NMI)) 36378c2ecf20Sopenharmony_ci kvm_before_interrupt(&svm->vcpu); 36388c2ecf20Sopenharmony_ci 36398c2ecf20Sopenharmony_ci kvm_load_host_xsave_state(vcpu); 36408c2ecf20Sopenharmony_ci stgi(); 36418c2ecf20Sopenharmony_ci 36428c2ecf20Sopenharmony_ci /* Any pending NMI will happen here */ 36438c2ecf20Sopenharmony_ci 36448c2ecf20Sopenharmony_ci if (unlikely(svm->vmcb->control.exit_code == SVM_EXIT_NMI)) 36458c2ecf20Sopenharmony_ci kvm_after_interrupt(&svm->vcpu); 36468c2ecf20Sopenharmony_ci 36478c2ecf20Sopenharmony_ci sync_cr8_to_lapic(vcpu); 36488c2ecf20Sopenharmony_ci 36498c2ecf20Sopenharmony_ci svm->next_rip = 0; 36508c2ecf20Sopenharmony_ci if (is_guest_mode(&svm->vcpu)) { 36518c2ecf20Sopenharmony_ci sync_nested_vmcb_control(svm); 36528c2ecf20Sopenharmony_ci svm->nested.nested_run_pending = 0; 36538c2ecf20Sopenharmony_ci } 36548c2ecf20Sopenharmony_ci 36558c2ecf20Sopenharmony_ci svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING; 36568c2ecf20Sopenharmony_ci vmcb_mark_all_clean(svm->vmcb); 36578c2ecf20Sopenharmony_ci 36588c2ecf20Sopenharmony_ci /* if exit due to PF check for async PF */ 36598c2ecf20Sopenharmony_ci if (svm->vmcb->control.exit_code == SVM_EXIT_EXCP_BASE + PF_VECTOR) 36608c2ecf20Sopenharmony_ci svm->vcpu.arch.apf.host_apf_flags = 36618c2ecf20Sopenharmony_ci kvm_read_and_reset_apf_flags(); 36628c2ecf20Sopenharmony_ci 36638c2ecf20Sopenharmony_ci if (npt_enabled) { 36648c2ecf20Sopenharmony_ci vcpu->arch.regs_avail &= ~(1 << VCPU_EXREG_PDPTR); 36658c2ecf20Sopenharmony_ci vcpu->arch.regs_dirty &= ~(1 << VCPU_EXREG_PDPTR); 36668c2ecf20Sopenharmony_ci } 36678c2ecf20Sopenharmony_ci 36688c2ecf20Sopenharmony_ci /* 36698c2ecf20Sopenharmony_ci * We need to handle MC intercepts here before the vcpu has a chance to 36708c2ecf20Sopenharmony_ci * change the physical cpu 36718c2ecf20Sopenharmony_ci */ 36728c2ecf20Sopenharmony_ci if (unlikely(svm->vmcb->control.exit_code == 36738c2ecf20Sopenharmony_ci SVM_EXIT_EXCP_BASE + MC_VECTOR)) 36748c2ecf20Sopenharmony_ci svm_handle_mce(svm); 36758c2ecf20Sopenharmony_ci 36768c2ecf20Sopenharmony_ci svm_complete_interrupts(svm); 36778c2ecf20Sopenharmony_ci 36788c2ecf20Sopenharmony_ci if (is_guest_mode(vcpu)) 36798c2ecf20Sopenharmony_ci return EXIT_FASTPATH_NONE; 36808c2ecf20Sopenharmony_ci 36818c2ecf20Sopenharmony_ci return svm_exit_handlers_fastpath(vcpu); 36828c2ecf20Sopenharmony_ci} 36838c2ecf20Sopenharmony_ci 36848c2ecf20Sopenharmony_cistatic void svm_load_mmu_pgd(struct kvm_vcpu *vcpu, unsigned long root, 36858c2ecf20Sopenharmony_ci int root_level) 36868c2ecf20Sopenharmony_ci{ 36878c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 36888c2ecf20Sopenharmony_ci unsigned long cr3; 36898c2ecf20Sopenharmony_ci 36908c2ecf20Sopenharmony_ci cr3 = __sme_set(root); 36918c2ecf20Sopenharmony_ci if (npt_enabled) { 36928c2ecf20Sopenharmony_ci svm->vmcb->control.nested_cr3 = cr3; 36938c2ecf20Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_NPT); 36948c2ecf20Sopenharmony_ci 36958c2ecf20Sopenharmony_ci /* Loading L2's CR3 is handled by enter_svm_guest_mode. */ 36968c2ecf20Sopenharmony_ci if (!test_bit(VCPU_EXREG_CR3, (ulong *)&vcpu->arch.regs_avail)) 36978c2ecf20Sopenharmony_ci return; 36988c2ecf20Sopenharmony_ci cr3 = vcpu->arch.cr3; 36998c2ecf20Sopenharmony_ci } 37008c2ecf20Sopenharmony_ci 37018c2ecf20Sopenharmony_ci svm->vmcb->save.cr3 = cr3; 37028c2ecf20Sopenharmony_ci vmcb_mark_dirty(svm->vmcb, VMCB_CR); 37038c2ecf20Sopenharmony_ci} 37048c2ecf20Sopenharmony_ci 37058c2ecf20Sopenharmony_cistatic int is_disabled(void) 37068c2ecf20Sopenharmony_ci{ 37078c2ecf20Sopenharmony_ci u64 vm_cr; 37088c2ecf20Sopenharmony_ci 37098c2ecf20Sopenharmony_ci rdmsrl(MSR_VM_CR, vm_cr); 37108c2ecf20Sopenharmony_ci if (vm_cr & (1 << SVM_VM_CR_SVM_DISABLE)) 37118c2ecf20Sopenharmony_ci return 1; 37128c2ecf20Sopenharmony_ci 37138c2ecf20Sopenharmony_ci return 0; 37148c2ecf20Sopenharmony_ci} 37158c2ecf20Sopenharmony_ci 37168c2ecf20Sopenharmony_cistatic void 37178c2ecf20Sopenharmony_cisvm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) 37188c2ecf20Sopenharmony_ci{ 37198c2ecf20Sopenharmony_ci /* 37208c2ecf20Sopenharmony_ci * Patch in the VMMCALL instruction: 37218c2ecf20Sopenharmony_ci */ 37228c2ecf20Sopenharmony_ci hypercall[0] = 0x0f; 37238c2ecf20Sopenharmony_ci hypercall[1] = 0x01; 37248c2ecf20Sopenharmony_ci hypercall[2] = 0xd9; 37258c2ecf20Sopenharmony_ci} 37268c2ecf20Sopenharmony_ci 37278c2ecf20Sopenharmony_cistatic int __init svm_check_processor_compat(void) 37288c2ecf20Sopenharmony_ci{ 37298c2ecf20Sopenharmony_ci return 0; 37308c2ecf20Sopenharmony_ci} 37318c2ecf20Sopenharmony_ci 37328c2ecf20Sopenharmony_cistatic bool svm_cpu_has_accelerated_tpr(void) 37338c2ecf20Sopenharmony_ci{ 37348c2ecf20Sopenharmony_ci return false; 37358c2ecf20Sopenharmony_ci} 37368c2ecf20Sopenharmony_ci 37378c2ecf20Sopenharmony_cistatic bool svm_has_emulated_msr(u32 index) 37388c2ecf20Sopenharmony_ci{ 37398c2ecf20Sopenharmony_ci switch (index) { 37408c2ecf20Sopenharmony_ci case MSR_IA32_MCG_EXT_CTL: 37418c2ecf20Sopenharmony_ci case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC: 37428c2ecf20Sopenharmony_ci return false; 37438c2ecf20Sopenharmony_ci default: 37448c2ecf20Sopenharmony_ci break; 37458c2ecf20Sopenharmony_ci } 37468c2ecf20Sopenharmony_ci 37478c2ecf20Sopenharmony_ci return true; 37488c2ecf20Sopenharmony_ci} 37498c2ecf20Sopenharmony_ci 37508c2ecf20Sopenharmony_cistatic u64 svm_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio) 37518c2ecf20Sopenharmony_ci{ 37528c2ecf20Sopenharmony_ci return 0; 37538c2ecf20Sopenharmony_ci} 37548c2ecf20Sopenharmony_ci 37558c2ecf20Sopenharmony_cistatic void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) 37568c2ecf20Sopenharmony_ci{ 37578c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 37588c2ecf20Sopenharmony_ci struct kvm_cpuid_entry2 *best; 37598c2ecf20Sopenharmony_ci 37608c2ecf20Sopenharmony_ci vcpu->arch.xsaves_enabled = guest_cpuid_has(vcpu, X86_FEATURE_XSAVE) && 37618c2ecf20Sopenharmony_ci boot_cpu_has(X86_FEATURE_XSAVE) && 37628c2ecf20Sopenharmony_ci boot_cpu_has(X86_FEATURE_XSAVES); 37638c2ecf20Sopenharmony_ci 37648c2ecf20Sopenharmony_ci /* Update nrips enabled cache */ 37658c2ecf20Sopenharmony_ci svm->nrips_enabled = kvm_cpu_cap_has(X86_FEATURE_NRIPS) && 37668c2ecf20Sopenharmony_ci guest_cpuid_has(&svm->vcpu, X86_FEATURE_NRIPS); 37678c2ecf20Sopenharmony_ci 37688c2ecf20Sopenharmony_ci /* Check again if INVPCID interception if required */ 37698c2ecf20Sopenharmony_ci svm_check_invpcid(svm); 37708c2ecf20Sopenharmony_ci 37718c2ecf20Sopenharmony_ci /* For sev guests, the memory encryption bit is not reserved in CR3. */ 37728c2ecf20Sopenharmony_ci if (sev_guest(vcpu->kvm)) { 37738c2ecf20Sopenharmony_ci best = kvm_find_cpuid_entry(vcpu, 0x8000001F, 0); 37748c2ecf20Sopenharmony_ci if (best) 37758c2ecf20Sopenharmony_ci vcpu->arch.cr3_lm_rsvd_bits &= ~(1UL << (best->ebx & 0x3f)); 37768c2ecf20Sopenharmony_ci } 37778c2ecf20Sopenharmony_ci 37788c2ecf20Sopenharmony_ci if (!kvm_vcpu_apicv_active(vcpu)) 37798c2ecf20Sopenharmony_ci return; 37808c2ecf20Sopenharmony_ci 37818c2ecf20Sopenharmony_ci /* 37828c2ecf20Sopenharmony_ci * AVIC does not work with an x2APIC mode guest. If the X2APIC feature 37838c2ecf20Sopenharmony_ci * is exposed to the guest, disable AVIC. 37848c2ecf20Sopenharmony_ci */ 37858c2ecf20Sopenharmony_ci if (guest_cpuid_has(vcpu, X86_FEATURE_X2APIC)) 37868c2ecf20Sopenharmony_ci kvm_request_apicv_update(vcpu->kvm, false, 37878c2ecf20Sopenharmony_ci APICV_INHIBIT_REASON_X2APIC); 37888c2ecf20Sopenharmony_ci 37898c2ecf20Sopenharmony_ci /* 37908c2ecf20Sopenharmony_ci * Currently, AVIC does not work with nested virtualization. 37918c2ecf20Sopenharmony_ci * So, we disable AVIC when cpuid for SVM is set in the L1 guest. 37928c2ecf20Sopenharmony_ci */ 37938c2ecf20Sopenharmony_ci if (nested && guest_cpuid_has(vcpu, X86_FEATURE_SVM)) 37948c2ecf20Sopenharmony_ci kvm_request_apicv_update(vcpu->kvm, false, 37958c2ecf20Sopenharmony_ci APICV_INHIBIT_REASON_NESTED); 37968c2ecf20Sopenharmony_ci} 37978c2ecf20Sopenharmony_ci 37988c2ecf20Sopenharmony_cistatic bool svm_has_wbinvd_exit(void) 37998c2ecf20Sopenharmony_ci{ 38008c2ecf20Sopenharmony_ci return true; 38018c2ecf20Sopenharmony_ci} 38028c2ecf20Sopenharmony_ci 38038c2ecf20Sopenharmony_ci#define PRE_EX(exit) { .exit_code = (exit), \ 38048c2ecf20Sopenharmony_ci .stage = X86_ICPT_PRE_EXCEPT, } 38058c2ecf20Sopenharmony_ci#define POST_EX(exit) { .exit_code = (exit), \ 38068c2ecf20Sopenharmony_ci .stage = X86_ICPT_POST_EXCEPT, } 38078c2ecf20Sopenharmony_ci#define POST_MEM(exit) { .exit_code = (exit), \ 38088c2ecf20Sopenharmony_ci .stage = X86_ICPT_POST_MEMACCESS, } 38098c2ecf20Sopenharmony_ci 38108c2ecf20Sopenharmony_cistatic const struct __x86_intercept { 38118c2ecf20Sopenharmony_ci u32 exit_code; 38128c2ecf20Sopenharmony_ci enum x86_intercept_stage stage; 38138c2ecf20Sopenharmony_ci} x86_intercept_map[] = { 38148c2ecf20Sopenharmony_ci [x86_intercept_cr_read] = POST_EX(SVM_EXIT_READ_CR0), 38158c2ecf20Sopenharmony_ci [x86_intercept_cr_write] = POST_EX(SVM_EXIT_WRITE_CR0), 38168c2ecf20Sopenharmony_ci [x86_intercept_clts] = POST_EX(SVM_EXIT_WRITE_CR0), 38178c2ecf20Sopenharmony_ci [x86_intercept_lmsw] = POST_EX(SVM_EXIT_WRITE_CR0), 38188c2ecf20Sopenharmony_ci [x86_intercept_smsw] = POST_EX(SVM_EXIT_READ_CR0), 38198c2ecf20Sopenharmony_ci [x86_intercept_dr_read] = POST_EX(SVM_EXIT_READ_DR0), 38208c2ecf20Sopenharmony_ci [x86_intercept_dr_write] = POST_EX(SVM_EXIT_WRITE_DR0), 38218c2ecf20Sopenharmony_ci [x86_intercept_sldt] = POST_EX(SVM_EXIT_LDTR_READ), 38228c2ecf20Sopenharmony_ci [x86_intercept_str] = POST_EX(SVM_EXIT_TR_READ), 38238c2ecf20Sopenharmony_ci [x86_intercept_lldt] = POST_EX(SVM_EXIT_LDTR_WRITE), 38248c2ecf20Sopenharmony_ci [x86_intercept_ltr] = POST_EX(SVM_EXIT_TR_WRITE), 38258c2ecf20Sopenharmony_ci [x86_intercept_sgdt] = POST_EX(SVM_EXIT_GDTR_READ), 38268c2ecf20Sopenharmony_ci [x86_intercept_sidt] = POST_EX(SVM_EXIT_IDTR_READ), 38278c2ecf20Sopenharmony_ci [x86_intercept_lgdt] = POST_EX(SVM_EXIT_GDTR_WRITE), 38288c2ecf20Sopenharmony_ci [x86_intercept_lidt] = POST_EX(SVM_EXIT_IDTR_WRITE), 38298c2ecf20Sopenharmony_ci [x86_intercept_vmrun] = POST_EX(SVM_EXIT_VMRUN), 38308c2ecf20Sopenharmony_ci [x86_intercept_vmmcall] = POST_EX(SVM_EXIT_VMMCALL), 38318c2ecf20Sopenharmony_ci [x86_intercept_vmload] = POST_EX(SVM_EXIT_VMLOAD), 38328c2ecf20Sopenharmony_ci [x86_intercept_vmsave] = POST_EX(SVM_EXIT_VMSAVE), 38338c2ecf20Sopenharmony_ci [x86_intercept_stgi] = POST_EX(SVM_EXIT_STGI), 38348c2ecf20Sopenharmony_ci [x86_intercept_clgi] = POST_EX(SVM_EXIT_CLGI), 38358c2ecf20Sopenharmony_ci [x86_intercept_skinit] = POST_EX(SVM_EXIT_SKINIT), 38368c2ecf20Sopenharmony_ci [x86_intercept_invlpga] = POST_EX(SVM_EXIT_INVLPGA), 38378c2ecf20Sopenharmony_ci [x86_intercept_rdtscp] = POST_EX(SVM_EXIT_RDTSCP), 38388c2ecf20Sopenharmony_ci [x86_intercept_monitor] = POST_MEM(SVM_EXIT_MONITOR), 38398c2ecf20Sopenharmony_ci [x86_intercept_mwait] = POST_EX(SVM_EXIT_MWAIT), 38408c2ecf20Sopenharmony_ci [x86_intercept_invlpg] = POST_EX(SVM_EXIT_INVLPG), 38418c2ecf20Sopenharmony_ci [x86_intercept_invd] = POST_EX(SVM_EXIT_INVD), 38428c2ecf20Sopenharmony_ci [x86_intercept_wbinvd] = POST_EX(SVM_EXIT_WBINVD), 38438c2ecf20Sopenharmony_ci [x86_intercept_wrmsr] = POST_EX(SVM_EXIT_MSR), 38448c2ecf20Sopenharmony_ci [x86_intercept_rdtsc] = POST_EX(SVM_EXIT_RDTSC), 38458c2ecf20Sopenharmony_ci [x86_intercept_rdmsr] = POST_EX(SVM_EXIT_MSR), 38468c2ecf20Sopenharmony_ci [x86_intercept_rdpmc] = POST_EX(SVM_EXIT_RDPMC), 38478c2ecf20Sopenharmony_ci [x86_intercept_cpuid] = PRE_EX(SVM_EXIT_CPUID), 38488c2ecf20Sopenharmony_ci [x86_intercept_rsm] = PRE_EX(SVM_EXIT_RSM), 38498c2ecf20Sopenharmony_ci [x86_intercept_pause] = PRE_EX(SVM_EXIT_PAUSE), 38508c2ecf20Sopenharmony_ci [x86_intercept_pushf] = PRE_EX(SVM_EXIT_PUSHF), 38518c2ecf20Sopenharmony_ci [x86_intercept_popf] = PRE_EX(SVM_EXIT_POPF), 38528c2ecf20Sopenharmony_ci [x86_intercept_intn] = PRE_EX(SVM_EXIT_SWINT), 38538c2ecf20Sopenharmony_ci [x86_intercept_iret] = PRE_EX(SVM_EXIT_IRET), 38548c2ecf20Sopenharmony_ci [x86_intercept_icebp] = PRE_EX(SVM_EXIT_ICEBP), 38558c2ecf20Sopenharmony_ci [x86_intercept_hlt] = POST_EX(SVM_EXIT_HLT), 38568c2ecf20Sopenharmony_ci [x86_intercept_in] = POST_EX(SVM_EXIT_IOIO), 38578c2ecf20Sopenharmony_ci [x86_intercept_ins] = POST_EX(SVM_EXIT_IOIO), 38588c2ecf20Sopenharmony_ci [x86_intercept_out] = POST_EX(SVM_EXIT_IOIO), 38598c2ecf20Sopenharmony_ci [x86_intercept_outs] = POST_EX(SVM_EXIT_IOIO), 38608c2ecf20Sopenharmony_ci [x86_intercept_xsetbv] = PRE_EX(SVM_EXIT_XSETBV), 38618c2ecf20Sopenharmony_ci}; 38628c2ecf20Sopenharmony_ci 38638c2ecf20Sopenharmony_ci#undef PRE_EX 38648c2ecf20Sopenharmony_ci#undef POST_EX 38658c2ecf20Sopenharmony_ci#undef POST_MEM 38668c2ecf20Sopenharmony_ci 38678c2ecf20Sopenharmony_cistatic int svm_check_intercept(struct kvm_vcpu *vcpu, 38688c2ecf20Sopenharmony_ci struct x86_instruction_info *info, 38698c2ecf20Sopenharmony_ci enum x86_intercept_stage stage, 38708c2ecf20Sopenharmony_ci struct x86_exception *exception) 38718c2ecf20Sopenharmony_ci{ 38728c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 38738c2ecf20Sopenharmony_ci int vmexit, ret = X86EMUL_CONTINUE; 38748c2ecf20Sopenharmony_ci struct __x86_intercept icpt_info; 38758c2ecf20Sopenharmony_ci struct vmcb *vmcb = svm->vmcb; 38768c2ecf20Sopenharmony_ci 38778c2ecf20Sopenharmony_ci if (info->intercept >= ARRAY_SIZE(x86_intercept_map)) 38788c2ecf20Sopenharmony_ci goto out; 38798c2ecf20Sopenharmony_ci 38808c2ecf20Sopenharmony_ci icpt_info = x86_intercept_map[info->intercept]; 38818c2ecf20Sopenharmony_ci 38828c2ecf20Sopenharmony_ci if (stage != icpt_info.stage) 38838c2ecf20Sopenharmony_ci goto out; 38848c2ecf20Sopenharmony_ci 38858c2ecf20Sopenharmony_ci switch (icpt_info.exit_code) { 38868c2ecf20Sopenharmony_ci case SVM_EXIT_READ_CR0: 38878c2ecf20Sopenharmony_ci if (info->intercept == x86_intercept_cr_read) 38888c2ecf20Sopenharmony_ci icpt_info.exit_code += info->modrm_reg; 38898c2ecf20Sopenharmony_ci break; 38908c2ecf20Sopenharmony_ci case SVM_EXIT_WRITE_CR0: { 38918c2ecf20Sopenharmony_ci unsigned long cr0, val; 38928c2ecf20Sopenharmony_ci 38938c2ecf20Sopenharmony_ci if (info->intercept == x86_intercept_cr_write) 38948c2ecf20Sopenharmony_ci icpt_info.exit_code += info->modrm_reg; 38958c2ecf20Sopenharmony_ci 38968c2ecf20Sopenharmony_ci if (icpt_info.exit_code != SVM_EXIT_WRITE_CR0 || 38978c2ecf20Sopenharmony_ci info->intercept == x86_intercept_clts) 38988c2ecf20Sopenharmony_ci break; 38998c2ecf20Sopenharmony_ci 39008c2ecf20Sopenharmony_ci if (!(vmcb_is_intercept(&svm->nested.ctl, 39018c2ecf20Sopenharmony_ci INTERCEPT_SELECTIVE_CR0))) 39028c2ecf20Sopenharmony_ci break; 39038c2ecf20Sopenharmony_ci 39048c2ecf20Sopenharmony_ci cr0 = vcpu->arch.cr0 & ~SVM_CR0_SELECTIVE_MASK; 39058c2ecf20Sopenharmony_ci val = info->src_val & ~SVM_CR0_SELECTIVE_MASK; 39068c2ecf20Sopenharmony_ci 39078c2ecf20Sopenharmony_ci if (info->intercept == x86_intercept_lmsw) { 39088c2ecf20Sopenharmony_ci cr0 &= 0xfUL; 39098c2ecf20Sopenharmony_ci val &= 0xfUL; 39108c2ecf20Sopenharmony_ci /* lmsw can't clear PE - catch this here */ 39118c2ecf20Sopenharmony_ci if (cr0 & X86_CR0_PE) 39128c2ecf20Sopenharmony_ci val |= X86_CR0_PE; 39138c2ecf20Sopenharmony_ci } 39148c2ecf20Sopenharmony_ci 39158c2ecf20Sopenharmony_ci if (cr0 ^ val) 39168c2ecf20Sopenharmony_ci icpt_info.exit_code = SVM_EXIT_CR0_SEL_WRITE; 39178c2ecf20Sopenharmony_ci 39188c2ecf20Sopenharmony_ci break; 39198c2ecf20Sopenharmony_ci } 39208c2ecf20Sopenharmony_ci case SVM_EXIT_READ_DR0: 39218c2ecf20Sopenharmony_ci case SVM_EXIT_WRITE_DR0: 39228c2ecf20Sopenharmony_ci icpt_info.exit_code += info->modrm_reg; 39238c2ecf20Sopenharmony_ci break; 39248c2ecf20Sopenharmony_ci case SVM_EXIT_MSR: 39258c2ecf20Sopenharmony_ci if (info->intercept == x86_intercept_wrmsr) 39268c2ecf20Sopenharmony_ci vmcb->control.exit_info_1 = 1; 39278c2ecf20Sopenharmony_ci else 39288c2ecf20Sopenharmony_ci vmcb->control.exit_info_1 = 0; 39298c2ecf20Sopenharmony_ci break; 39308c2ecf20Sopenharmony_ci case SVM_EXIT_PAUSE: 39318c2ecf20Sopenharmony_ci /* 39328c2ecf20Sopenharmony_ci * We get this for NOP only, but pause 39338c2ecf20Sopenharmony_ci * is rep not, check this here 39348c2ecf20Sopenharmony_ci */ 39358c2ecf20Sopenharmony_ci if (info->rep_prefix != REPE_PREFIX) 39368c2ecf20Sopenharmony_ci goto out; 39378c2ecf20Sopenharmony_ci break; 39388c2ecf20Sopenharmony_ci case SVM_EXIT_IOIO: { 39398c2ecf20Sopenharmony_ci u64 exit_info; 39408c2ecf20Sopenharmony_ci u32 bytes; 39418c2ecf20Sopenharmony_ci 39428c2ecf20Sopenharmony_ci if (info->intercept == x86_intercept_in || 39438c2ecf20Sopenharmony_ci info->intercept == x86_intercept_ins) { 39448c2ecf20Sopenharmony_ci exit_info = ((info->src_val & 0xffff) << 16) | 39458c2ecf20Sopenharmony_ci SVM_IOIO_TYPE_MASK; 39468c2ecf20Sopenharmony_ci bytes = info->dst_bytes; 39478c2ecf20Sopenharmony_ci } else { 39488c2ecf20Sopenharmony_ci exit_info = (info->dst_val & 0xffff) << 16; 39498c2ecf20Sopenharmony_ci bytes = info->src_bytes; 39508c2ecf20Sopenharmony_ci } 39518c2ecf20Sopenharmony_ci 39528c2ecf20Sopenharmony_ci if (info->intercept == x86_intercept_outs || 39538c2ecf20Sopenharmony_ci info->intercept == x86_intercept_ins) 39548c2ecf20Sopenharmony_ci exit_info |= SVM_IOIO_STR_MASK; 39558c2ecf20Sopenharmony_ci 39568c2ecf20Sopenharmony_ci if (info->rep_prefix) 39578c2ecf20Sopenharmony_ci exit_info |= SVM_IOIO_REP_MASK; 39588c2ecf20Sopenharmony_ci 39598c2ecf20Sopenharmony_ci bytes = min(bytes, 4u); 39608c2ecf20Sopenharmony_ci 39618c2ecf20Sopenharmony_ci exit_info |= bytes << SVM_IOIO_SIZE_SHIFT; 39628c2ecf20Sopenharmony_ci 39638c2ecf20Sopenharmony_ci exit_info |= (u32)info->ad_bytes << (SVM_IOIO_ASIZE_SHIFT - 1); 39648c2ecf20Sopenharmony_ci 39658c2ecf20Sopenharmony_ci vmcb->control.exit_info_1 = exit_info; 39668c2ecf20Sopenharmony_ci vmcb->control.exit_info_2 = info->next_rip; 39678c2ecf20Sopenharmony_ci 39688c2ecf20Sopenharmony_ci break; 39698c2ecf20Sopenharmony_ci } 39708c2ecf20Sopenharmony_ci default: 39718c2ecf20Sopenharmony_ci break; 39728c2ecf20Sopenharmony_ci } 39738c2ecf20Sopenharmony_ci 39748c2ecf20Sopenharmony_ci /* TODO: Advertise NRIPS to guest hypervisor unconditionally */ 39758c2ecf20Sopenharmony_ci if (static_cpu_has(X86_FEATURE_NRIPS)) 39768c2ecf20Sopenharmony_ci vmcb->control.next_rip = info->next_rip; 39778c2ecf20Sopenharmony_ci vmcb->control.exit_code = icpt_info.exit_code; 39788c2ecf20Sopenharmony_ci vmexit = nested_svm_exit_handled(svm); 39798c2ecf20Sopenharmony_ci 39808c2ecf20Sopenharmony_ci ret = (vmexit == NESTED_EXIT_DONE) ? X86EMUL_INTERCEPTED 39818c2ecf20Sopenharmony_ci : X86EMUL_CONTINUE; 39828c2ecf20Sopenharmony_ci 39838c2ecf20Sopenharmony_ciout: 39848c2ecf20Sopenharmony_ci return ret; 39858c2ecf20Sopenharmony_ci} 39868c2ecf20Sopenharmony_ci 39878c2ecf20Sopenharmony_cistatic void svm_handle_exit_irqoff(struct kvm_vcpu *vcpu) 39888c2ecf20Sopenharmony_ci{ 39898c2ecf20Sopenharmony_ci if (to_svm(vcpu)->vmcb->control.exit_code == SVM_EXIT_INTR) 39908c2ecf20Sopenharmony_ci vcpu->arch.at_instruction_boundary = true; 39918c2ecf20Sopenharmony_ci} 39928c2ecf20Sopenharmony_ci 39938c2ecf20Sopenharmony_cistatic void svm_sched_in(struct kvm_vcpu *vcpu, int cpu) 39948c2ecf20Sopenharmony_ci{ 39958c2ecf20Sopenharmony_ci if (!kvm_pause_in_guest(vcpu->kvm)) 39968c2ecf20Sopenharmony_ci shrink_ple_window(vcpu); 39978c2ecf20Sopenharmony_ci} 39988c2ecf20Sopenharmony_ci 39998c2ecf20Sopenharmony_cistatic void svm_setup_mce(struct kvm_vcpu *vcpu) 40008c2ecf20Sopenharmony_ci{ 40018c2ecf20Sopenharmony_ci /* [63:9] are reserved. */ 40028c2ecf20Sopenharmony_ci vcpu->arch.mcg_cap &= 0x1ff; 40038c2ecf20Sopenharmony_ci} 40048c2ecf20Sopenharmony_ci 40058c2ecf20Sopenharmony_cibool svm_smi_blocked(struct kvm_vcpu *vcpu) 40068c2ecf20Sopenharmony_ci{ 40078c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 40088c2ecf20Sopenharmony_ci 40098c2ecf20Sopenharmony_ci /* Per APM Vol.2 15.22.2 "Response to SMI" */ 40108c2ecf20Sopenharmony_ci if (!gif_set(svm)) 40118c2ecf20Sopenharmony_ci return true; 40128c2ecf20Sopenharmony_ci 40138c2ecf20Sopenharmony_ci return is_smm(vcpu); 40148c2ecf20Sopenharmony_ci} 40158c2ecf20Sopenharmony_ci 40168c2ecf20Sopenharmony_cistatic int svm_smi_allowed(struct kvm_vcpu *vcpu, bool for_injection) 40178c2ecf20Sopenharmony_ci{ 40188c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 40198c2ecf20Sopenharmony_ci if (svm->nested.nested_run_pending) 40208c2ecf20Sopenharmony_ci return -EBUSY; 40218c2ecf20Sopenharmony_ci 40228c2ecf20Sopenharmony_ci /* An SMI must not be injected into L2 if it's supposed to VM-Exit. */ 40238c2ecf20Sopenharmony_ci if (for_injection && is_guest_mode(vcpu) && nested_exit_on_smi(svm)) 40248c2ecf20Sopenharmony_ci return -EBUSY; 40258c2ecf20Sopenharmony_ci 40268c2ecf20Sopenharmony_ci return !svm_smi_blocked(vcpu); 40278c2ecf20Sopenharmony_ci} 40288c2ecf20Sopenharmony_ci 40298c2ecf20Sopenharmony_cistatic int svm_pre_enter_smm(struct kvm_vcpu *vcpu, char *smstate) 40308c2ecf20Sopenharmony_ci{ 40318c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 40328c2ecf20Sopenharmony_ci int ret; 40338c2ecf20Sopenharmony_ci 40348c2ecf20Sopenharmony_ci if (is_guest_mode(vcpu)) { 40358c2ecf20Sopenharmony_ci /* FED8h - SVM Guest */ 40368c2ecf20Sopenharmony_ci put_smstate(u64, smstate, 0x7ed8, 1); 40378c2ecf20Sopenharmony_ci /* FEE0h - SVM Guest VMCB Physical Address */ 40388c2ecf20Sopenharmony_ci put_smstate(u64, smstate, 0x7ee0, svm->nested.vmcb12_gpa); 40398c2ecf20Sopenharmony_ci 40408c2ecf20Sopenharmony_ci svm->vmcb->save.rax = vcpu->arch.regs[VCPU_REGS_RAX]; 40418c2ecf20Sopenharmony_ci svm->vmcb->save.rsp = vcpu->arch.regs[VCPU_REGS_RSP]; 40428c2ecf20Sopenharmony_ci svm->vmcb->save.rip = vcpu->arch.regs[VCPU_REGS_RIP]; 40438c2ecf20Sopenharmony_ci 40448c2ecf20Sopenharmony_ci ret = nested_svm_vmexit(svm); 40458c2ecf20Sopenharmony_ci if (ret) 40468c2ecf20Sopenharmony_ci return ret; 40478c2ecf20Sopenharmony_ci } 40488c2ecf20Sopenharmony_ci return 0; 40498c2ecf20Sopenharmony_ci} 40508c2ecf20Sopenharmony_ci 40518c2ecf20Sopenharmony_cistatic int svm_pre_leave_smm(struct kvm_vcpu *vcpu, const char *smstate) 40528c2ecf20Sopenharmony_ci{ 40538c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 40548c2ecf20Sopenharmony_ci struct kvm_host_map map; 40558c2ecf20Sopenharmony_ci int ret = 0; 40568c2ecf20Sopenharmony_ci 40578c2ecf20Sopenharmony_ci if (guest_cpuid_has(vcpu, X86_FEATURE_LM)) { 40588c2ecf20Sopenharmony_ci u64 saved_efer = GET_SMSTATE(u64, smstate, 0x7ed0); 40598c2ecf20Sopenharmony_ci u64 guest = GET_SMSTATE(u64, smstate, 0x7ed8); 40608c2ecf20Sopenharmony_ci u64 vmcb12_gpa = GET_SMSTATE(u64, smstate, 0x7ee0); 40618c2ecf20Sopenharmony_ci 40628c2ecf20Sopenharmony_ci if (guest) { 40638c2ecf20Sopenharmony_ci if (!guest_cpuid_has(vcpu, X86_FEATURE_SVM)) 40648c2ecf20Sopenharmony_ci return 1; 40658c2ecf20Sopenharmony_ci 40668c2ecf20Sopenharmony_ci if (!(saved_efer & EFER_SVME)) 40678c2ecf20Sopenharmony_ci return 1; 40688c2ecf20Sopenharmony_ci 40698c2ecf20Sopenharmony_ci if (kvm_vcpu_map(&svm->vcpu, 40708c2ecf20Sopenharmony_ci gpa_to_gfn(vmcb12_gpa), &map) == -EINVAL) 40718c2ecf20Sopenharmony_ci return 1; 40728c2ecf20Sopenharmony_ci 40738c2ecf20Sopenharmony_ci if (svm_allocate_nested(svm)) 40748c2ecf20Sopenharmony_ci return 1; 40758c2ecf20Sopenharmony_ci 40768c2ecf20Sopenharmony_ci ret = enter_svm_guest_mode(svm, vmcb12_gpa, map.hva); 40778c2ecf20Sopenharmony_ci kvm_vcpu_unmap(&svm->vcpu, &map, true); 40788c2ecf20Sopenharmony_ci } 40798c2ecf20Sopenharmony_ci } 40808c2ecf20Sopenharmony_ci 40818c2ecf20Sopenharmony_ci return ret; 40828c2ecf20Sopenharmony_ci} 40838c2ecf20Sopenharmony_ci 40848c2ecf20Sopenharmony_cistatic void enable_smi_window(struct kvm_vcpu *vcpu) 40858c2ecf20Sopenharmony_ci{ 40868c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 40878c2ecf20Sopenharmony_ci 40888c2ecf20Sopenharmony_ci if (!gif_set(svm)) { 40898c2ecf20Sopenharmony_ci if (vgif_enabled(svm)) 40908c2ecf20Sopenharmony_ci svm_set_intercept(svm, INTERCEPT_STGI); 40918c2ecf20Sopenharmony_ci /* STGI will cause a vm exit */ 40928c2ecf20Sopenharmony_ci } else { 40938c2ecf20Sopenharmony_ci /* We must be in SMM; RSM will cause a vmexit anyway. */ 40948c2ecf20Sopenharmony_ci } 40958c2ecf20Sopenharmony_ci} 40968c2ecf20Sopenharmony_ci 40978c2ecf20Sopenharmony_cistatic bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, void *insn, int insn_len) 40988c2ecf20Sopenharmony_ci{ 40998c2ecf20Sopenharmony_ci bool smep, smap, is_user; 41008c2ecf20Sopenharmony_ci unsigned long cr4; 41018c2ecf20Sopenharmony_ci 41028c2ecf20Sopenharmony_ci /* Emulation is always possible when KVM has access to all guest state. */ 41038c2ecf20Sopenharmony_ci if (!sev_guest(vcpu->kvm)) 41048c2ecf20Sopenharmony_ci return true; 41058c2ecf20Sopenharmony_ci 41068c2ecf20Sopenharmony_ci /* 41078c2ecf20Sopenharmony_ci * Detect and workaround Errata 1096 Fam_17h_00_0Fh. 41088c2ecf20Sopenharmony_ci * 41098c2ecf20Sopenharmony_ci * Errata: 41108c2ecf20Sopenharmony_ci * When CPU raise #NPF on guest data access and vCPU CR4.SMAP=1, it is 41118c2ecf20Sopenharmony_ci * possible that CPU microcode implementing DecodeAssist will fail 41128c2ecf20Sopenharmony_ci * to read bytes of instruction which caused #NPF. In this case, 41138c2ecf20Sopenharmony_ci * GuestIntrBytes field of the VMCB on a VMEXIT will incorrectly 41148c2ecf20Sopenharmony_ci * return 0 instead of the correct guest instruction bytes. 41158c2ecf20Sopenharmony_ci * 41168c2ecf20Sopenharmony_ci * This happens because CPU microcode reading instruction bytes 41178c2ecf20Sopenharmony_ci * uses a special opcode which attempts to read data using CPL=0 41188c2ecf20Sopenharmony_ci * priviledges. The microcode reads CS:RIP and if it hits a SMAP 41198c2ecf20Sopenharmony_ci * fault, it gives up and returns no instruction bytes. 41208c2ecf20Sopenharmony_ci * 41218c2ecf20Sopenharmony_ci * Detection: 41228c2ecf20Sopenharmony_ci * We reach here in case CPU supports DecodeAssist, raised #NPF and 41238c2ecf20Sopenharmony_ci * returned 0 in GuestIntrBytes field of the VMCB. 41248c2ecf20Sopenharmony_ci * First, errata can only be triggered in case vCPU CR4.SMAP=1. 41258c2ecf20Sopenharmony_ci * Second, if vCPU CR4.SMEP=1, errata could only be triggered 41268c2ecf20Sopenharmony_ci * in case vCPU CPL==3 (Because otherwise guest would have triggered 41278c2ecf20Sopenharmony_ci * a SMEP fault instead of #NPF). 41288c2ecf20Sopenharmony_ci * Otherwise, vCPU CR4.SMEP=0, errata could be triggered by any vCPU CPL. 41298c2ecf20Sopenharmony_ci * As most guests enable SMAP if they have also enabled SMEP, use above 41308c2ecf20Sopenharmony_ci * logic in order to attempt minimize false-positive of detecting errata 41318c2ecf20Sopenharmony_ci * while still preserving all cases semantic correctness. 41328c2ecf20Sopenharmony_ci * 41338c2ecf20Sopenharmony_ci * Workaround: 41348c2ecf20Sopenharmony_ci * To determine what instruction the guest was executing, the hypervisor 41358c2ecf20Sopenharmony_ci * will have to decode the instruction at the instruction pointer. 41368c2ecf20Sopenharmony_ci * 41378c2ecf20Sopenharmony_ci * In non SEV guest, hypervisor will be able to read the guest 41388c2ecf20Sopenharmony_ci * memory to decode the instruction pointer when insn_len is zero 41398c2ecf20Sopenharmony_ci * so we return true to indicate that decoding is possible. 41408c2ecf20Sopenharmony_ci * 41418c2ecf20Sopenharmony_ci * But in the SEV guest, the guest memory is encrypted with the 41428c2ecf20Sopenharmony_ci * guest specific key and hypervisor will not be able to decode the 41438c2ecf20Sopenharmony_ci * instruction pointer so we will not able to workaround it. Lets 41448c2ecf20Sopenharmony_ci * print the error and request to kill the guest. 41458c2ecf20Sopenharmony_ci */ 41468c2ecf20Sopenharmony_ci if (likely(!insn || insn_len)) 41478c2ecf20Sopenharmony_ci return true; 41488c2ecf20Sopenharmony_ci 41498c2ecf20Sopenharmony_ci cr4 = kvm_read_cr4(vcpu); 41508c2ecf20Sopenharmony_ci smep = cr4 & X86_CR4_SMEP; 41518c2ecf20Sopenharmony_ci smap = cr4 & X86_CR4_SMAP; 41528c2ecf20Sopenharmony_ci is_user = svm_get_cpl(vcpu) == 3; 41538c2ecf20Sopenharmony_ci if (smap && (!smep || is_user)) { 41548c2ecf20Sopenharmony_ci pr_err_ratelimited("KVM: SEV Guest triggered AMD Erratum 1096\n"); 41558c2ecf20Sopenharmony_ci 41568c2ecf20Sopenharmony_ci /* 41578c2ecf20Sopenharmony_ci * If the fault occurred in userspace, arbitrarily inject #GP 41588c2ecf20Sopenharmony_ci * to avoid killing the guest and to hopefully avoid confusing 41598c2ecf20Sopenharmony_ci * the guest kernel too much, e.g. injecting #PF would not be 41608c2ecf20Sopenharmony_ci * coherent with respect to the guest's page tables. Request 41618c2ecf20Sopenharmony_ci * triple fault if the fault occurred in the kernel as there's 41628c2ecf20Sopenharmony_ci * no fault that KVM can inject without confusing the guest. 41638c2ecf20Sopenharmony_ci * In practice, the triple fault is moot as no sane SEV kernel 41648c2ecf20Sopenharmony_ci * will execute from user memory while also running with SMAP=1. 41658c2ecf20Sopenharmony_ci */ 41668c2ecf20Sopenharmony_ci if (is_user) 41678c2ecf20Sopenharmony_ci kvm_inject_gp(vcpu, 0); 41688c2ecf20Sopenharmony_ci else 41698c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu); 41708c2ecf20Sopenharmony_ci } 41718c2ecf20Sopenharmony_ci 41728c2ecf20Sopenharmony_ci return false; 41738c2ecf20Sopenharmony_ci} 41748c2ecf20Sopenharmony_ci 41758c2ecf20Sopenharmony_cistatic bool svm_apic_init_signal_blocked(struct kvm_vcpu *vcpu) 41768c2ecf20Sopenharmony_ci{ 41778c2ecf20Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 41788c2ecf20Sopenharmony_ci 41798c2ecf20Sopenharmony_ci /* 41808c2ecf20Sopenharmony_ci * TODO: Last condition latch INIT signals on vCPU when 41818c2ecf20Sopenharmony_ci * vCPU is in guest-mode and vmcb12 defines intercept on INIT. 41828c2ecf20Sopenharmony_ci * To properly emulate the INIT intercept, 41838c2ecf20Sopenharmony_ci * svm_check_nested_events() should call nested_svm_vmexit() 41848c2ecf20Sopenharmony_ci * if an INIT signal is pending. 41858c2ecf20Sopenharmony_ci */ 41868c2ecf20Sopenharmony_ci return !gif_set(svm) || 41878c2ecf20Sopenharmony_ci (vmcb_is_intercept(&svm->vmcb->control, INTERCEPT_INIT)); 41888c2ecf20Sopenharmony_ci} 41898c2ecf20Sopenharmony_ci 41908c2ecf20Sopenharmony_cistatic void svm_vm_destroy(struct kvm *kvm) 41918c2ecf20Sopenharmony_ci{ 41928c2ecf20Sopenharmony_ci avic_vm_destroy(kvm); 41938c2ecf20Sopenharmony_ci sev_vm_destroy(kvm); 41948c2ecf20Sopenharmony_ci} 41958c2ecf20Sopenharmony_ci 41968c2ecf20Sopenharmony_cistatic int svm_vm_init(struct kvm *kvm) 41978c2ecf20Sopenharmony_ci{ 41988c2ecf20Sopenharmony_ci if (!pause_filter_count || !pause_filter_thresh) 41998c2ecf20Sopenharmony_ci kvm->arch.pause_in_guest = true; 42008c2ecf20Sopenharmony_ci 42018c2ecf20Sopenharmony_ci if (avic) { 42028c2ecf20Sopenharmony_ci int ret = avic_vm_init(kvm); 42038c2ecf20Sopenharmony_ci if (ret) 42048c2ecf20Sopenharmony_ci return ret; 42058c2ecf20Sopenharmony_ci } 42068c2ecf20Sopenharmony_ci 42078c2ecf20Sopenharmony_ci kvm_apicv_init(kvm, avic); 42088c2ecf20Sopenharmony_ci return 0; 42098c2ecf20Sopenharmony_ci} 42108c2ecf20Sopenharmony_ci 42118c2ecf20Sopenharmony_cistatic struct kvm_x86_ops svm_x86_ops __initdata = { 42128c2ecf20Sopenharmony_ci .hardware_unsetup = svm_hardware_teardown, 42138c2ecf20Sopenharmony_ci .hardware_enable = svm_hardware_enable, 42148c2ecf20Sopenharmony_ci .hardware_disable = svm_hardware_disable, 42158c2ecf20Sopenharmony_ci .cpu_has_accelerated_tpr = svm_cpu_has_accelerated_tpr, 42168c2ecf20Sopenharmony_ci .has_emulated_msr = svm_has_emulated_msr, 42178c2ecf20Sopenharmony_ci 42188c2ecf20Sopenharmony_ci .vcpu_create = svm_create_vcpu, 42198c2ecf20Sopenharmony_ci .vcpu_free = svm_free_vcpu, 42208c2ecf20Sopenharmony_ci .vcpu_reset = svm_vcpu_reset, 42218c2ecf20Sopenharmony_ci 42228c2ecf20Sopenharmony_ci .vm_size = sizeof(struct kvm_svm), 42238c2ecf20Sopenharmony_ci .vm_init = svm_vm_init, 42248c2ecf20Sopenharmony_ci .vm_destroy = svm_vm_destroy, 42258c2ecf20Sopenharmony_ci 42268c2ecf20Sopenharmony_ci .prepare_guest_switch = svm_prepare_guest_switch, 42278c2ecf20Sopenharmony_ci .vcpu_load = svm_vcpu_load, 42288c2ecf20Sopenharmony_ci .vcpu_put = svm_vcpu_put, 42298c2ecf20Sopenharmony_ci .vcpu_blocking = svm_vcpu_blocking, 42308c2ecf20Sopenharmony_ci .vcpu_unblocking = svm_vcpu_unblocking, 42318c2ecf20Sopenharmony_ci 42328c2ecf20Sopenharmony_ci .update_exception_bitmap = update_exception_bitmap, 42338c2ecf20Sopenharmony_ci .get_msr_feature = svm_get_msr_feature, 42348c2ecf20Sopenharmony_ci .get_msr = svm_get_msr, 42358c2ecf20Sopenharmony_ci .set_msr = svm_set_msr, 42368c2ecf20Sopenharmony_ci .get_segment_base = svm_get_segment_base, 42378c2ecf20Sopenharmony_ci .get_segment = svm_get_segment, 42388c2ecf20Sopenharmony_ci .set_segment = svm_set_segment, 42398c2ecf20Sopenharmony_ci .get_cpl = svm_get_cpl, 42408c2ecf20Sopenharmony_ci .get_cs_db_l_bits = kvm_get_cs_db_l_bits, 42418c2ecf20Sopenharmony_ci .set_cr0 = svm_set_cr0, 42428c2ecf20Sopenharmony_ci .is_valid_cr4 = svm_is_valid_cr4, 42438c2ecf20Sopenharmony_ci .set_cr4 = svm_set_cr4, 42448c2ecf20Sopenharmony_ci .set_efer = svm_set_efer, 42458c2ecf20Sopenharmony_ci .get_idt = svm_get_idt, 42468c2ecf20Sopenharmony_ci .set_idt = svm_set_idt, 42478c2ecf20Sopenharmony_ci .get_gdt = svm_get_gdt, 42488c2ecf20Sopenharmony_ci .set_gdt = svm_set_gdt, 42498c2ecf20Sopenharmony_ci .set_dr7 = svm_set_dr7, 42508c2ecf20Sopenharmony_ci .sync_dirty_debug_regs = svm_sync_dirty_debug_regs, 42518c2ecf20Sopenharmony_ci .cache_reg = svm_cache_reg, 42528c2ecf20Sopenharmony_ci .get_rflags = svm_get_rflags, 42538c2ecf20Sopenharmony_ci .set_rflags = svm_set_rflags, 42548c2ecf20Sopenharmony_ci 42558c2ecf20Sopenharmony_ci .tlb_flush_all = svm_flush_tlb, 42568c2ecf20Sopenharmony_ci .tlb_flush_current = svm_flush_tlb, 42578c2ecf20Sopenharmony_ci .tlb_flush_gva = svm_flush_tlb_gva, 42588c2ecf20Sopenharmony_ci .tlb_flush_guest = svm_flush_tlb, 42598c2ecf20Sopenharmony_ci 42608c2ecf20Sopenharmony_ci .run = svm_vcpu_run, 42618c2ecf20Sopenharmony_ci .handle_exit = handle_exit, 42628c2ecf20Sopenharmony_ci .skip_emulated_instruction = skip_emulated_instruction, 42638c2ecf20Sopenharmony_ci .update_emulated_instruction = NULL, 42648c2ecf20Sopenharmony_ci .set_interrupt_shadow = svm_set_interrupt_shadow, 42658c2ecf20Sopenharmony_ci .get_interrupt_shadow = svm_get_interrupt_shadow, 42668c2ecf20Sopenharmony_ci .patch_hypercall = svm_patch_hypercall, 42678c2ecf20Sopenharmony_ci .set_irq = svm_set_irq, 42688c2ecf20Sopenharmony_ci .set_nmi = svm_inject_nmi, 42698c2ecf20Sopenharmony_ci .queue_exception = svm_queue_exception, 42708c2ecf20Sopenharmony_ci .cancel_injection = svm_cancel_injection, 42718c2ecf20Sopenharmony_ci .interrupt_allowed = svm_interrupt_allowed, 42728c2ecf20Sopenharmony_ci .nmi_allowed = svm_nmi_allowed, 42738c2ecf20Sopenharmony_ci .get_nmi_mask = svm_get_nmi_mask, 42748c2ecf20Sopenharmony_ci .set_nmi_mask = svm_set_nmi_mask, 42758c2ecf20Sopenharmony_ci .enable_nmi_window = enable_nmi_window, 42768c2ecf20Sopenharmony_ci .enable_irq_window = enable_irq_window, 42778c2ecf20Sopenharmony_ci .update_cr8_intercept = update_cr8_intercept, 42788c2ecf20Sopenharmony_ci .set_virtual_apic_mode = svm_set_virtual_apic_mode, 42798c2ecf20Sopenharmony_ci .refresh_apicv_exec_ctrl = svm_refresh_apicv_exec_ctrl, 42808c2ecf20Sopenharmony_ci .check_apicv_inhibit_reasons = svm_check_apicv_inhibit_reasons, 42818c2ecf20Sopenharmony_ci .pre_update_apicv_exec_ctrl = svm_pre_update_apicv_exec_ctrl, 42828c2ecf20Sopenharmony_ci .load_eoi_exitmap = svm_load_eoi_exitmap, 42838c2ecf20Sopenharmony_ci .hwapic_irr_update = svm_hwapic_irr_update, 42848c2ecf20Sopenharmony_ci .hwapic_isr_update = svm_hwapic_isr_update, 42858c2ecf20Sopenharmony_ci .sync_pir_to_irr = kvm_lapic_find_highest_irr, 42868c2ecf20Sopenharmony_ci .apicv_post_state_restore = avic_post_state_restore, 42878c2ecf20Sopenharmony_ci 42888c2ecf20Sopenharmony_ci .set_tss_addr = svm_set_tss_addr, 42898c2ecf20Sopenharmony_ci .set_identity_map_addr = svm_set_identity_map_addr, 42908c2ecf20Sopenharmony_ci .get_mt_mask = svm_get_mt_mask, 42918c2ecf20Sopenharmony_ci 42928c2ecf20Sopenharmony_ci .get_exit_info = svm_get_exit_info, 42938c2ecf20Sopenharmony_ci 42948c2ecf20Sopenharmony_ci .vcpu_after_set_cpuid = svm_vcpu_after_set_cpuid, 42958c2ecf20Sopenharmony_ci 42968c2ecf20Sopenharmony_ci .has_wbinvd_exit = svm_has_wbinvd_exit, 42978c2ecf20Sopenharmony_ci 42988c2ecf20Sopenharmony_ci .write_l1_tsc_offset = svm_write_l1_tsc_offset, 42998c2ecf20Sopenharmony_ci 43008c2ecf20Sopenharmony_ci .load_mmu_pgd = svm_load_mmu_pgd, 43018c2ecf20Sopenharmony_ci 43028c2ecf20Sopenharmony_ci .check_intercept = svm_check_intercept, 43038c2ecf20Sopenharmony_ci .handle_exit_irqoff = svm_handle_exit_irqoff, 43048c2ecf20Sopenharmony_ci 43058c2ecf20Sopenharmony_ci .request_immediate_exit = __kvm_request_immediate_exit, 43068c2ecf20Sopenharmony_ci 43078c2ecf20Sopenharmony_ci .sched_in = svm_sched_in, 43088c2ecf20Sopenharmony_ci 43098c2ecf20Sopenharmony_ci .pmu_ops = &amd_pmu_ops, 43108c2ecf20Sopenharmony_ci .nested_ops = &svm_nested_ops, 43118c2ecf20Sopenharmony_ci 43128c2ecf20Sopenharmony_ci .deliver_posted_interrupt = svm_deliver_avic_intr, 43138c2ecf20Sopenharmony_ci .dy_apicv_has_pending_interrupt = svm_dy_apicv_has_pending_interrupt, 43148c2ecf20Sopenharmony_ci .update_pi_irte = svm_update_pi_irte, 43158c2ecf20Sopenharmony_ci .setup_mce = svm_setup_mce, 43168c2ecf20Sopenharmony_ci 43178c2ecf20Sopenharmony_ci .smi_allowed = svm_smi_allowed, 43188c2ecf20Sopenharmony_ci .pre_enter_smm = svm_pre_enter_smm, 43198c2ecf20Sopenharmony_ci .pre_leave_smm = svm_pre_leave_smm, 43208c2ecf20Sopenharmony_ci .enable_smi_window = enable_smi_window, 43218c2ecf20Sopenharmony_ci 43228c2ecf20Sopenharmony_ci .mem_enc_op = svm_mem_enc_op, 43238c2ecf20Sopenharmony_ci .mem_enc_reg_region = svm_register_enc_region, 43248c2ecf20Sopenharmony_ci .mem_enc_unreg_region = svm_unregister_enc_region, 43258c2ecf20Sopenharmony_ci .guest_memory_reclaimed = sev_guest_memory_reclaimed, 43268c2ecf20Sopenharmony_ci 43278c2ecf20Sopenharmony_ci .can_emulate_instruction = svm_can_emulate_instruction, 43288c2ecf20Sopenharmony_ci 43298c2ecf20Sopenharmony_ci .apic_init_signal_blocked = svm_apic_init_signal_blocked, 43308c2ecf20Sopenharmony_ci 43318c2ecf20Sopenharmony_ci .msr_filter_changed = svm_msr_filter_changed, 43328c2ecf20Sopenharmony_ci}; 43338c2ecf20Sopenharmony_ci 43348c2ecf20Sopenharmony_cistatic struct kvm_x86_init_ops svm_init_ops __initdata = { 43358c2ecf20Sopenharmony_ci .cpu_has_kvm_support = has_svm, 43368c2ecf20Sopenharmony_ci .disabled_by_bios = is_disabled, 43378c2ecf20Sopenharmony_ci .hardware_setup = svm_hardware_setup, 43388c2ecf20Sopenharmony_ci .check_processor_compatibility = svm_check_processor_compat, 43398c2ecf20Sopenharmony_ci 43408c2ecf20Sopenharmony_ci .runtime_ops = &svm_x86_ops, 43418c2ecf20Sopenharmony_ci}; 43428c2ecf20Sopenharmony_ci 43438c2ecf20Sopenharmony_cistatic int __init svm_init(void) 43448c2ecf20Sopenharmony_ci{ 43458c2ecf20Sopenharmony_ci __unused_size_checks(); 43468c2ecf20Sopenharmony_ci 43478c2ecf20Sopenharmony_ci return kvm_init(&svm_init_ops, sizeof(struct vcpu_svm), 43488c2ecf20Sopenharmony_ci __alignof__(struct vcpu_svm), THIS_MODULE); 43498c2ecf20Sopenharmony_ci} 43508c2ecf20Sopenharmony_ci 43518c2ecf20Sopenharmony_cistatic void __exit svm_exit(void) 43528c2ecf20Sopenharmony_ci{ 43538c2ecf20Sopenharmony_ci kvm_exit(); 43548c2ecf20Sopenharmony_ci} 43558c2ecf20Sopenharmony_ci 43568c2ecf20Sopenharmony_cimodule_init(svm_init) 43578c2ecf20Sopenharmony_cimodule_exit(svm_exit) 4358