@@ -3029,6 +3029,8 @@ static u8 vmx_has_apicv_interrupt(struct kvm_vcpu *vcpu)
static void load_vmcs12_host_state(struct kvm_vcpu *vcpu,
struct vmcs12 *vmcs12);
+extern struct vmx_msr_entry *vmcs12_invalid_msr_load_area;
+
/*
* If from_vmentry is false, this is being called from state restore (either RSM
* or KVM_SET_NESTED_STATE). Otherwise it's called from vmlaunch/vmresume.
@@ -3100,12 +3102,38 @@ int nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, bool from_vmentry)
goto vmentry_fail_vmexit_guest_mode;
if (from_vmentry) {
- exit_reason = EXIT_REASON_MSR_LOAD_FAIL;
exit_qual = nested_vmx_load_msr(vcpu,
vmcs12->vm_entry_msr_load_addr,
vmcs12->vm_entry_msr_load_count);
- if (exit_qual)
- goto vmentry_fail_vmexit_guest_mode;
+ if (exit_qual) {
+ /*
+ * According to section “VM Entries” in Intel SDM
+ * vol 3C, VM-entry checks are performed in a certain
+ * order. Checks on MSRs that are loaded on VM-entry
+ * from VM-entry MSR-load area, should be done after
+ * verifying VMCS controls, host-state area and
+ * guest-state area. As KVM relies on CPU hardware to
+ * perform some of these checks, we need to defer
+ * VM-exit due to invalid VM-entry MSR-load area to
+ * until after CPU hardware completes the earlier
+ * checks and is ready to do VMLAUNCH/VMRESUME.
+ *
+ * In order to defer errors arising from invalid
+ * VM-entry MSR-load area in vmcs12, we set up a
+ * single invalid entry, which is illegal according
+ * to section "Loading MSRs in Intel SDM vol 3C, in
+ * VM-entry MSR-load area of vmcs02. This will cause
+ * the CPU hardware to VM-exit with "VM-entry
+ * failure due to MSR loading" after it completes
+ * checks on VMCS controls, host-state area and
+ * guest-state area.
+ */
+ vmx->nested.invalid_msr_load_exit_qual = exit_qual;
+ vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 1);
+ vmcs_write64(VM_ENTRY_MSR_LOAD_ADDR,
+ __pa(vmcs12_invalid_msr_load_area));
+ vmx->nested.dirty_vmcs12 = true;
+ }
} else {
/*
* The MMU is not initialized to point at the right entities yet and
@@ -64,7 +64,9 @@ static inline bool nested_ept_ad_enabled(struct kvm_vcpu *vcpu)
static inline int nested_vmx_reflect_vmexit(struct kvm_vcpu *vcpu,
u32 exit_reason)
{
+ u32 exit_qual;
u32 exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
+ struct vmx_msr_entry *addr;
/*
* At this point, the exit interruption info in exit_intr_info
@@ -81,8 +83,17 @@ static inline int nested_vmx_reflect_vmexit(struct kvm_vcpu *vcpu,
vmcs_read32(VM_EXIT_INTR_ERROR_CODE);
}
- nested_vmx_vmexit(vcpu, exit_reason, exit_intr_info,
- vmcs_readl(EXIT_QUALIFICATION));
+ exit_qual = vmcs_readl(EXIT_QUALIFICATION);
+
+ addr = __va(vmcs_read64(VM_ENTRY_MSR_LOAD_ADDR));
+ if (addr && addr->index == MSR_FS_BASE &&
+ (exit_reason == (VMX_EXIT_REASONS_FAILED_VMENTRY |
+ EXIT_REASON_MSR_LOAD_FAIL))) {
+ exit_qual = (to_vmx(vcpu))->nested.invalid_msr_load_exit_qual;
+ }
+
+ nested_vmx_vmexit(vcpu, exit_reason, exit_intr_info, exit_qual);
+
return 1;
}
@@ -7914,6 +7914,13 @@ static void vmx_cleanup_l1d_flush(void)
l1tf_vmx_mitigation = VMENTER_L1D_FLUSH_AUTO;
}
+/*
+ * This is used to set up an invalid VM-entry MSR-load area for vmcs02
+ * if an error is detected while processing the entries in VM-entry
+ * MSR-load area of vmcs12.
+ */
+struct vmx_msr_entry *vmcs12_invalid_msr_load_area = NULL;
+
static void vmx_exit(void)
{
#ifdef CONFIG_KEXEC_CORE
@@ -7947,6 +7954,9 @@ static void vmx_exit(void)
}
#endif
vmx_cleanup_l1d_flush();
+
+ if (vmcs12_invalid_msr_load_area)
+ kfree(vmcs12_invalid_msr_load_area);
}
module_exit(vmx_exit);
@@ -8012,6 +8022,14 @@ static int __init vmx_init(void)
#endif
vmx_check_vmcs12_offsets();
+ vmcs12_invalid_msr_load_area =
+ kzalloc(sizeof(struct vmx_msr_entry), GFP_KERNEL_ACCOUNT);
+ if (!vmcs12_invalid_msr_load_area) {
+ vmx_exit();
+ return 15;
+ }
+ vmcs12_invalid_msr_load_area->index = MSR_FS_BASE;
+
return 0;
}
module_init(vmx_init);
@@ -183,6 +183,12 @@ struct nested_vmx {
gpa_t hv_evmcs_vmptr;
struct kvm_host_map hv_evmcs_map;
struct hv_enlightened_vmcs *hv_evmcs;
+
+ /*
+ * This field is used for Exit Qualification when VM-entry fails
+ * due to invalid VM-entry MSR-load area in vmcs12.
+ */
+ u32 invalid_msr_load_exit_qual;
};
struct vcpu_vmx {