11e349143e
When Enlightened VMCS is in use, it is valid to do VMCLEAR and, according to TLFS, this should "transition an enlightened VMCS from the active to the non-active state". It is, however, wrong to assume that it is only valid to do VMCLEAR for the eVMCS which is currently active on the vCPU performing VMCLEAR. Currently, the logic in handle_vmclear() is broken: in case, there is no active eVMCS on the vCPU doing VMCLEAR we treat the argument as a 'normal' VMCS and kvm_vcpu_write_guest() to the 'launch_state' field irreversibly corrupts the memory area. So, in case the VMCLEAR argument is not the current active eVMCS on the vCPU, how can we know if the area it is pointing to is a normal or an enlightened VMCS? Thanks to the bug in Hyper-V (see commit72aeb60c52
("KVM: nVMX: Verify eVMCS revision id match supported eVMCS version on eVMCS VMPTRLD")) we can not, the revision can't be used to distinguish between them. So let's assume it is always enlightened in case enlightened vmentry is enabled in the assist page. Also, check if vmx->nested.enlightened_vmcs_enabled to minimize the impact for 'unenlightened' workloads. Fixes:b8bbab928f
("KVM: nVMX: implement enlightened VMPTRLD and VMCLEAR") Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
372 lines
16 KiB
C
372 lines
16 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
#include <linux/errno.h>
|
|
#include <linux/smp.h>
|
|
|
|
#include "../hyperv.h"
|
|
#include "evmcs.h"
|
|
#include "vmcs.h"
|
|
#include "vmx.h"
|
|
|
|
DEFINE_STATIC_KEY_FALSE(enable_evmcs);
|
|
|
|
#if IS_ENABLED(CONFIG_HYPERV)
|
|
|
|
#define ROL16(val, n) ((u16)(((u16)(val) << (n)) | ((u16)(val) >> (16 - (n)))))
|
|
#define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x)
|
|
#define EVMCS1_FIELD(number, name, clean_field)[ROL16(number, 6)] = \
|
|
{EVMCS1_OFFSET(name), clean_field}
|
|
|
|
const struct evmcs_field vmcs_field_to_evmcs_1[] = {
|
|
/* 64 bit rw */
|
|
EVMCS1_FIELD(GUEST_RIP, guest_rip,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
|
|
EVMCS1_FIELD(GUEST_RSP, guest_rsp,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
|
|
EVMCS1_FIELD(GUEST_RFLAGS, guest_rflags,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
|
|
EVMCS1_FIELD(HOST_IA32_PAT, host_ia32_pat,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
|
|
EVMCS1_FIELD(HOST_IA32_EFER, host_ia32_efer,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
|
|
EVMCS1_FIELD(HOST_CR0, host_cr0,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
|
|
EVMCS1_FIELD(HOST_CR3, host_cr3,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
|
|
EVMCS1_FIELD(HOST_CR4, host_cr4,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
|
|
EVMCS1_FIELD(HOST_IA32_SYSENTER_ESP, host_ia32_sysenter_esp,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
|
|
EVMCS1_FIELD(HOST_IA32_SYSENTER_EIP, host_ia32_sysenter_eip,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
|
|
EVMCS1_FIELD(HOST_RIP, host_rip,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
|
|
EVMCS1_FIELD(IO_BITMAP_A, io_bitmap_a,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP),
|
|
EVMCS1_FIELD(IO_BITMAP_B, io_bitmap_b,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP),
|
|
EVMCS1_FIELD(MSR_BITMAP, msr_bitmap,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP),
|
|
EVMCS1_FIELD(GUEST_ES_BASE, guest_es_base,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_CS_BASE, guest_cs_base,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_SS_BASE, guest_ss_base,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_DS_BASE, guest_ds_base,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_FS_BASE, guest_fs_base,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_GS_BASE, guest_gs_base,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_LDTR_BASE, guest_ldtr_base,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_TR_BASE, guest_tr_base,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_GDTR_BASE, guest_gdtr_base,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_IDTR_BASE, guest_idtr_base,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(TSC_OFFSET, tsc_offset,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
|
|
EVMCS1_FIELD(VIRTUAL_APIC_PAGE_ADDR, virtual_apic_page_addr,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
|
|
EVMCS1_FIELD(VMCS_LINK_POINTER, vmcs_link_pointer,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
|
|
EVMCS1_FIELD(GUEST_IA32_DEBUGCTL, guest_ia32_debugctl,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
|
|
EVMCS1_FIELD(GUEST_IA32_PAT, guest_ia32_pat,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
|
|
EVMCS1_FIELD(GUEST_IA32_EFER, guest_ia32_efer,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
|
|
EVMCS1_FIELD(GUEST_PDPTR0, guest_pdptr0,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
|
|
EVMCS1_FIELD(GUEST_PDPTR1, guest_pdptr1,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
|
|
EVMCS1_FIELD(GUEST_PDPTR2, guest_pdptr2,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
|
|
EVMCS1_FIELD(GUEST_PDPTR3, guest_pdptr3,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
|
|
EVMCS1_FIELD(GUEST_PENDING_DBG_EXCEPTIONS, guest_pending_dbg_exceptions,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
|
|
EVMCS1_FIELD(GUEST_SYSENTER_ESP, guest_sysenter_esp,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
|
|
EVMCS1_FIELD(GUEST_SYSENTER_EIP, guest_sysenter_eip,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
|
|
EVMCS1_FIELD(CR0_GUEST_HOST_MASK, cr0_guest_host_mask,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
|
|
EVMCS1_FIELD(CR4_GUEST_HOST_MASK, cr4_guest_host_mask,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
|
|
EVMCS1_FIELD(CR0_READ_SHADOW, cr0_read_shadow,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
|
|
EVMCS1_FIELD(CR4_READ_SHADOW, cr4_read_shadow,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
|
|
EVMCS1_FIELD(GUEST_CR0, guest_cr0,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
|
|
EVMCS1_FIELD(GUEST_CR3, guest_cr3,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
|
|
EVMCS1_FIELD(GUEST_CR4, guest_cr4,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
|
|
EVMCS1_FIELD(GUEST_DR7, guest_dr7,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
|
|
EVMCS1_FIELD(HOST_FS_BASE, host_fs_base,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
|
|
EVMCS1_FIELD(HOST_GS_BASE, host_gs_base,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
|
|
EVMCS1_FIELD(HOST_TR_BASE, host_tr_base,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
|
|
EVMCS1_FIELD(HOST_GDTR_BASE, host_gdtr_base,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
|
|
EVMCS1_FIELD(HOST_IDTR_BASE, host_idtr_base,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
|
|
EVMCS1_FIELD(HOST_RSP, host_rsp,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
|
|
EVMCS1_FIELD(EPT_POINTER, ept_pointer,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT),
|
|
EVMCS1_FIELD(GUEST_BNDCFGS, guest_bndcfgs,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
|
|
EVMCS1_FIELD(XSS_EXIT_BITMAP, xss_exit_bitmap,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
|
|
|
|
/* 64 bit read only */
|
|
EVMCS1_FIELD(GUEST_PHYSICAL_ADDRESS, guest_physical_address,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
|
|
EVMCS1_FIELD(EXIT_QUALIFICATION, exit_qualification,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
|
|
/*
|
|
* Not defined in KVM:
|
|
*
|
|
* EVMCS1_FIELD(0x00006402, exit_io_instruction_ecx,
|
|
* HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
|
|
* EVMCS1_FIELD(0x00006404, exit_io_instruction_esi,
|
|
* HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
|
|
* EVMCS1_FIELD(0x00006406, exit_io_instruction_esi,
|
|
* HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
|
|
* EVMCS1_FIELD(0x00006408, exit_io_instruction_eip,
|
|
* HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
|
|
*/
|
|
EVMCS1_FIELD(GUEST_LINEAR_ADDRESS, guest_linear_address,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
|
|
|
|
/*
|
|
* No mask defined in the spec as Hyper-V doesn't currently support
|
|
* these. Future proof by resetting the whole clean field mask on
|
|
* access.
|
|
*/
|
|
EVMCS1_FIELD(VM_EXIT_MSR_STORE_ADDR, vm_exit_msr_store_addr,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
|
|
EVMCS1_FIELD(VM_EXIT_MSR_LOAD_ADDR, vm_exit_msr_load_addr,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
|
|
EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_ADDR, vm_entry_msr_load_addr,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
|
|
EVMCS1_FIELD(CR3_TARGET_VALUE0, cr3_target_value0,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
|
|
EVMCS1_FIELD(CR3_TARGET_VALUE1, cr3_target_value1,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
|
|
EVMCS1_FIELD(CR3_TARGET_VALUE2, cr3_target_value2,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
|
|
EVMCS1_FIELD(CR3_TARGET_VALUE3, cr3_target_value3,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
|
|
|
|
/* 32 bit rw */
|
|
EVMCS1_FIELD(TPR_THRESHOLD, tpr_threshold,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
|
|
EVMCS1_FIELD(GUEST_INTERRUPTIBILITY_INFO, guest_interruptibility_info,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
|
|
EVMCS1_FIELD(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_PROC),
|
|
EVMCS1_FIELD(EXCEPTION_BITMAP, exception_bitmap,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EXCPN),
|
|
EVMCS1_FIELD(VM_ENTRY_CONTROLS, vm_entry_controls,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_ENTRY),
|
|
EVMCS1_FIELD(VM_ENTRY_INTR_INFO_FIELD, vm_entry_intr_info_field,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
|
|
EVMCS1_FIELD(VM_ENTRY_EXCEPTION_ERROR_CODE,
|
|
vm_entry_exception_error_code,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
|
|
EVMCS1_FIELD(VM_ENTRY_INSTRUCTION_LEN, vm_entry_instruction_len,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
|
|
EVMCS1_FIELD(HOST_IA32_SYSENTER_CS, host_ia32_sysenter_cs,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
|
|
EVMCS1_FIELD(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_control,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
|
|
EVMCS1_FIELD(VM_EXIT_CONTROLS, vm_exit_controls,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
|
|
EVMCS1_FIELD(SECONDARY_VM_EXEC_CONTROL, secondary_vm_exec_control,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
|
|
EVMCS1_FIELD(GUEST_ES_LIMIT, guest_es_limit,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_CS_LIMIT, guest_cs_limit,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_SS_LIMIT, guest_ss_limit,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_DS_LIMIT, guest_ds_limit,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_FS_LIMIT, guest_fs_limit,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_GS_LIMIT, guest_gs_limit,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_LDTR_LIMIT, guest_ldtr_limit,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_TR_LIMIT, guest_tr_limit,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_GDTR_LIMIT, guest_gdtr_limit,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_IDTR_LIMIT, guest_idtr_limit,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_ES_AR_BYTES, guest_es_ar_bytes,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_CS_AR_BYTES, guest_cs_ar_bytes,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_SS_AR_BYTES, guest_ss_ar_bytes,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_DS_AR_BYTES, guest_ds_ar_bytes,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_FS_AR_BYTES, guest_fs_ar_bytes,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_GS_AR_BYTES, guest_gs_ar_bytes,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_LDTR_AR_BYTES, guest_ldtr_ar_bytes,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_TR_AR_BYTES, guest_tr_ar_bytes,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_ACTIVITY_STATE, guest_activity_state,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
|
|
EVMCS1_FIELD(GUEST_SYSENTER_CS, guest_sysenter_cs,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
|
|
|
|
/* 32 bit read only */
|
|
EVMCS1_FIELD(VM_INSTRUCTION_ERROR, vm_instruction_error,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
|
|
EVMCS1_FIELD(VM_EXIT_REASON, vm_exit_reason,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
|
|
EVMCS1_FIELD(VM_EXIT_INTR_INFO, vm_exit_intr_info,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
|
|
EVMCS1_FIELD(VM_EXIT_INTR_ERROR_CODE, vm_exit_intr_error_code,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
|
|
EVMCS1_FIELD(IDT_VECTORING_INFO_FIELD, idt_vectoring_info_field,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
|
|
EVMCS1_FIELD(IDT_VECTORING_ERROR_CODE, idt_vectoring_error_code,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
|
|
EVMCS1_FIELD(VM_EXIT_INSTRUCTION_LEN, vm_exit_instruction_len,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
|
|
EVMCS1_FIELD(VMX_INSTRUCTION_INFO, vmx_instruction_info,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
|
|
|
|
/* No mask defined in the spec (not used) */
|
|
EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MASK, page_fault_error_code_mask,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
|
|
EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MATCH, page_fault_error_code_match,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
|
|
EVMCS1_FIELD(CR3_TARGET_COUNT, cr3_target_count,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
|
|
EVMCS1_FIELD(VM_EXIT_MSR_STORE_COUNT, vm_exit_msr_store_count,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
|
|
EVMCS1_FIELD(VM_EXIT_MSR_LOAD_COUNT, vm_exit_msr_load_count,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
|
|
EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_COUNT, vm_entry_msr_load_count,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
|
|
|
|
/* 16 bit rw */
|
|
EVMCS1_FIELD(HOST_ES_SELECTOR, host_es_selector,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
|
|
EVMCS1_FIELD(HOST_CS_SELECTOR, host_cs_selector,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
|
|
EVMCS1_FIELD(HOST_SS_SELECTOR, host_ss_selector,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
|
|
EVMCS1_FIELD(HOST_DS_SELECTOR, host_ds_selector,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
|
|
EVMCS1_FIELD(HOST_FS_SELECTOR, host_fs_selector,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
|
|
EVMCS1_FIELD(HOST_GS_SELECTOR, host_gs_selector,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
|
|
EVMCS1_FIELD(HOST_TR_SELECTOR, host_tr_selector,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
|
|
EVMCS1_FIELD(GUEST_ES_SELECTOR, guest_es_selector,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_CS_SELECTOR, guest_cs_selector,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_SS_SELECTOR, guest_ss_selector,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_DS_SELECTOR, guest_ds_selector,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_FS_SELECTOR, guest_fs_selector,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_GS_SELECTOR, guest_gs_selector,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_LDTR_SELECTOR, guest_ldtr_selector,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(GUEST_TR_SELECTOR, guest_tr_selector,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
|
|
EVMCS1_FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id,
|
|
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT),
|
|
};
|
|
const unsigned int nr_evmcs_1_fields = ARRAY_SIZE(vmcs_field_to_evmcs_1);
|
|
|
|
void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf)
|
|
{
|
|
vmcs_conf->pin_based_exec_ctrl &= ~EVMCS1_UNSUPPORTED_PINCTRL;
|
|
vmcs_conf->cpu_based_2nd_exec_ctrl &= ~EVMCS1_UNSUPPORTED_2NDEXEC;
|
|
|
|
vmcs_conf->vmexit_ctrl &= ~EVMCS1_UNSUPPORTED_VMEXIT_CTRL;
|
|
vmcs_conf->vmentry_ctrl &= ~EVMCS1_UNSUPPORTED_VMENTRY_CTRL;
|
|
|
|
}
|
|
#endif
|
|
|
|
bool nested_enlightened_vmentry(struct kvm_vcpu *vcpu, u64 *evmcs_gpa)
|
|
{
|
|
struct hv_vp_assist_page assist_page;
|
|
|
|
*evmcs_gpa = -1ull;
|
|
|
|
if (unlikely(!kvm_hv_get_assist_page(vcpu, &assist_page)))
|
|
return false;
|
|
|
|
if (unlikely(!assist_page.enlighten_vmentry))
|
|
return false;
|
|
|
|
*evmcs_gpa = assist_page.current_nested_vmcs;
|
|
|
|
return true;
|
|
}
|
|
|
|
uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu)
|
|
{
|
|
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
|
/*
|
|
* vmcs_version represents the range of supported Enlightened VMCS
|
|
* versions: lower 8 bits is the minimal version, higher 8 bits is the
|
|
* maximum supported version. KVM supports versions from 1 to
|
|
* KVM_EVMCS_VERSION.
|
|
*/
|
|
if (vmx->nested.enlightened_vmcs_enabled)
|
|
return (KVM_EVMCS_VERSION << 8) | 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int nested_enable_evmcs(struct kvm_vcpu *vcpu,
|
|
uint16_t *vmcs_version)
|
|
{
|
|
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
|
bool evmcs_already_enabled = vmx->nested.enlightened_vmcs_enabled;
|
|
|
|
vmx->nested.enlightened_vmcs_enabled = true;
|
|
|
|
if (vmcs_version)
|
|
*vmcs_version = nested_get_evmcs_version(vcpu);
|
|
|
|
/* We don't support disabling the feature for simplicity. */
|
|
if (evmcs_already_enabled)
|
|
return 0;
|
|
|
|
vmx->nested.msrs.pinbased_ctls_high &= ~EVMCS1_UNSUPPORTED_PINCTRL;
|
|
vmx->nested.msrs.entry_ctls_high &= ~EVMCS1_UNSUPPORTED_VMENTRY_CTRL;
|
|
vmx->nested.msrs.exit_ctls_high &= ~EVMCS1_UNSUPPORTED_VMEXIT_CTRL;
|
|
vmx->nested.msrs.secondary_ctls_high &= ~EVMCS1_UNSUPPORTED_2NDEXEC;
|
|
vmx->nested.msrs.vmfunc_controls &= ~EVMCS1_UNSUPPORTED_VMFUNC;
|
|
|
|
return 0;
|
|
}
|