VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID = 28,
 };
 
+/*
+ * VM-instruction errors that can be encountered on VM-Enter, used to trace
+ * nested VM-Enter failures reported by hardware.  Errors unique to VM-Enter
+ * from a SMI Transfer Monitor are not included as things have gone seriously
+ * sideways if we get one of those...
+ */
+#define VMX_VMENTER_INSTRUCTION_ERRORS \
+       { VMXERR_VMLAUNCH_NONCLEAR_VMCS,                "VMLAUNCH_NONCLEAR_VMCS" }, \
+       { VMXERR_VMRESUME_NONLAUNCHED_VMCS,             "VMRESUME_NONLAUNCHED_VMCS" }, \
+       { VMXERR_VMRESUME_AFTER_VMXOFF,                 "VMRESUME_AFTER_VMXOFF" }, \
+       { VMXERR_ENTRY_INVALID_CONTROL_FIELD,           "VMENTRY_INVALID_CONTROL_FIELD" }, \
+       { VMXERR_ENTRY_INVALID_HOST_STATE_FIELD,        "VMENTRY_INVALID_HOST_STATE_FIELD" }, \
+       { VMXERR_ENTRY_EVENTS_BLOCKED_BY_MOV_SS,        "VMENTRY_EVENTS_BLOCKED_BY_MOV_SS" }
+
 enum vmx_l1d_flush_state {
        VMENTER_L1D_FLUSH_AUTO,
        VMENTER_L1D_FLUSH_NEVER,
 
  * Tracepoint for failed nested VMX VM-Enter.
  */
 TRACE_EVENT(kvm_nested_vmenter_failed,
-       TP_PROTO(const char *msg),
-       TP_ARGS(msg),
+       TP_PROTO(const char *msg, u32 err),
+       TP_ARGS(msg, err),
 
        TP_STRUCT__entry(
                __field(const char *, msg)
+               __field(u32, err)
        ),
 
        TP_fast_assign(
                __entry->msg = msg;
+               __entry->err = err;
        ),
 
-       TP_printk("%s", __entry->msg)
+       TP_printk("%s%s", __entry->msg, !__entry->err ? "" :
+               __print_symbolic(__entry->err, VMX_VMENTER_INSTRUCTION_ERRORS))
 );
 
 #endif /* _TRACE_KVM_H */
 
 ({                                                                     \
        bool failed = (consistency_check);                              \
        if (failed)                                                     \
-               trace_kvm_nested_vmenter_failed(#consistency_check);    \
+               trace_kvm_nested_vmenter_failed(#consistency_check, 0); \
        failed;                                                         \
 })
 
                vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr);
 
        if (vm_fail) {
+               u32 error = vmcs_read32(VM_INSTRUCTION_ERROR);
+
                preempt_enable();
-               WARN_ON_ONCE(vmcs_read32(VM_INSTRUCTION_ERROR) !=
-                            VMXERR_ENTRY_INVALID_CONTROL_FIELD);
+
+               trace_kvm_nested_vmenter_failed(
+                       "early hardware check VM-instruction error: ", error);
+               WARN_ON_ONCE(error != VMXERR_ENTRY_INVALID_CONTROL_FIELD);
                return 1;
        }
 
                return false;
 
        if (unlikely(vmx->fail)) {
-               pr_info_ratelimited("%s failed vm entry %x\n", __func__,
-                                   vmcs_read32(VM_INSTRUCTION_ERROR));
+               trace_kvm_nested_vmenter_failed(
+                       "hardware VM-instruction error: ",
+                       vmcs_read32(VM_INSTRUCTION_ERROR));
                return true;
        }