]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: SVM: Treat exit_code as an unsigned 64-bit value through all of KVM
authorSean Christopherson <seanjc@google.com>
Tue, 30 Dec 2025 21:13:44 +0000 (13:13 -0800)
committerSean Christopherson <seanjc@google.com>
Wed, 14 Jan 2026 01:37:03 +0000 (17:37 -0800)
Fix KVM's long-standing buggy handling of SVM's exit_code as a 32-bit
value.  Per the APM and Xen commit d1bd157fbc ("Big merge the HVM
full-virtualisation abstractions.") (which is arguably more trustworthy
than KVM), offset 0x70 is a single 64-bit value:

  070h 63:0 EXITCODE

Track exit_code as a single u64 to prevent reintroducing bugs where KVM
neglects to correctly set bits 63:32.

Fixes: 6aa8b732ca01 ("[PATCH] kvm: userspace interface")
Cc: Jim Mattson <jmattson@google.com>
Cc: Yosry Ahmed <yosry.ahmed@linux.dev>
Reviewed-by: Yosry Ahmed <yosry.ahmed@linux.dev>
Link: https://patch.msgid.link/20251230211347.4099600-6-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/include/asm/svm.h
arch/x86/include/uapi/asm/svm.h
arch/x86/kvm/svm/hyperv.c
arch/x86/kvm/svm/nested.c
arch/x86/kvm/svm/sev.c
arch/x86/kvm/svm/svm.c
arch/x86/kvm/svm/svm.h
arch/x86/kvm/trace.h
include/hyperv/hvgdk.h
tools/testing/selftests/kvm/include/x86/svm.h
tools/testing/selftests/kvm/x86/svm_nested_soft_inject_test.c

index 50ece197c98a40a05bb57398312ce29fd5cc66f4..edde36097ddc31a32fe1e2491efe46c000970c5e 100644 (file)
@@ -137,8 +137,7 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
        u32 int_vector;
        u32 int_state;
        u8 reserved_3[4];
-       u32 exit_code;
-       u32 exit_code_hi;
+       u64 exit_code;
        u64 exit_info_1;
        u64 exit_info_2;
        u32 exit_int_info;
index 650e3256ea7d7339091b86adfbd317ac5d25d61a..010a45c9f6147f8c2c3210d58cde36f6e41bcce2 100644 (file)
 #define SVM_EXIT_VMGEXIT       0x403
 
 /* SEV-ES software-defined VMGEXIT events */
-#define SVM_VMGEXIT_MMIO_READ                  0x80000001
-#define SVM_VMGEXIT_MMIO_WRITE                 0x80000002
-#define SVM_VMGEXIT_NMI_COMPLETE               0x80000003
-#define SVM_VMGEXIT_AP_HLT_LOOP                        0x80000004
-#define SVM_VMGEXIT_AP_JUMP_TABLE              0x80000005
+#define SVM_VMGEXIT_MMIO_READ                  0x80000001ull
+#define SVM_VMGEXIT_MMIO_WRITE                 0x80000002ull
+#define SVM_VMGEXIT_NMI_COMPLETE               0x80000003ull
+#define SVM_VMGEXIT_AP_HLT_LOOP                        0x80000004ull
+#define SVM_VMGEXIT_AP_JUMP_TABLE              0x80000005ull
 #define SVM_VMGEXIT_SET_AP_JUMP_TABLE          0
 #define SVM_VMGEXIT_GET_AP_JUMP_TABLE          1
-#define SVM_VMGEXIT_PSC                                0x80000010
-#define SVM_VMGEXIT_GUEST_REQUEST              0x80000011
-#define SVM_VMGEXIT_EXT_GUEST_REQUEST          0x80000012
-#define SVM_VMGEXIT_AP_CREATION                        0x80000013
+#define SVM_VMGEXIT_PSC                                0x80000010ull
+#define SVM_VMGEXIT_GUEST_REQUEST              0x80000011ull
+#define SVM_VMGEXIT_EXT_GUEST_REQUEST          0x80000012ull
+#define SVM_VMGEXIT_AP_CREATION                        0x80000013ull
 #define SVM_VMGEXIT_AP_CREATE_ON_INIT          0
 #define SVM_VMGEXIT_AP_CREATE                  1
 #define SVM_VMGEXIT_AP_DESTROY                 2
-#define SVM_VMGEXIT_SNP_RUN_VMPL               0x80000018
-#define SVM_VMGEXIT_SAVIC                      0x8000001a
+#define SVM_VMGEXIT_SNP_RUN_VMPL               0x80000018ull
+#define SVM_VMGEXIT_SAVIC                      0x8000001aull
 #define SVM_VMGEXIT_SAVIC_REGISTER_GPA         0
 #define SVM_VMGEXIT_SAVIC_UNREGISTER_GPA       1
 #define SVM_VMGEXIT_SAVIC_SELF_GPA             ~0ULL
-#define SVM_VMGEXIT_HV_FEATURES                        0x8000fffd
-#define SVM_VMGEXIT_TERM_REQUEST               0x8000fffe
+#define SVM_VMGEXIT_HV_FEATURES                        0x8000fffdull
+#define SVM_VMGEXIT_TERM_REQUEST               0x8000fffeull
 #define SVM_VMGEXIT_TERM_REASON(reason_set, reason_code)       \
        /* SW_EXITINFO1[3:0] */                                 \
        (((((u64)reason_set) & 0xf)) |                          \
        /* SW_EXITINFO1[11:4] */                                \
        ((((u64)reason_code) & 0xff) << 4))
-#define SVM_VMGEXIT_UNSUPPORTED_EVENT          0x8000ffff
+#define SVM_VMGEXIT_UNSUPPORTED_EVENT          0x8000ffffull
 
 /* Exit code reserved for hypervisor/software use */
-#define SVM_EXIT_SW                            0xf0000000
+#define SVM_EXIT_SW                            0xf0000000ull
 
-#define SVM_EXIT_ERR           -1
+#define SVM_EXIT_ERR           -1ull
 
 #define SVM_EXIT_REASONS \
        { SVM_EXIT_READ_CR0,    "read_cr0" }, \
index 088f6429b24cef4de2dd1b7b97e3c657fc2d2f40..3ec580d687f5f60b7f696f4aa91846121a92d8a8 100644 (file)
@@ -11,7 +11,6 @@ void svm_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu)
        struct vcpu_svm *svm = to_svm(vcpu);
 
        svm->vmcb->control.exit_code = HV_SVM_EXITCODE_ENL;
-       svm->vmcb->control.exit_code_hi = 0;
        svm->vmcb->control.exit_info_1 = HV_SVM_ENL_EXITCODE_TRAP_AFTER_FLUSH;
        svm->vmcb->control.exit_info_2 = 0;
        nested_svm_vmexit(svm);
index 666b5a36c15d8a5bdff8cb16998f306f0299e2bd..5aa0512e09c9319e4b0fdda5809d0d74069b3df4 100644 (file)
@@ -45,7 +45,6 @@ static void nested_svm_inject_npf_exit(struct kvm_vcpu *vcpu,
                 * correctly fill in the high bits of exit_info_1.
                 */
                vmcb->control.exit_code = SVM_EXIT_NPF;
-               vmcb->control.exit_code_hi = 0;
                vmcb->control.exit_info_1 = (1ULL << 32);
                vmcb->control.exit_info_2 = fault->address;
        }
@@ -441,7 +440,6 @@ void __nested_copy_vmcb_control_to_cache(struct kvm_vcpu *vcpu,
        to->int_vector          = from->int_vector;
        to->int_state           = from->int_state;
        to->exit_code           = from->exit_code;
-       to->exit_code_hi        = from->exit_code_hi;
        to->exit_info_1         = from->exit_info_1;
        to->exit_info_2         = from->exit_info_2;
        to->exit_int_info       = from->exit_int_info;
@@ -747,8 +745,8 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm,
        enter_guest_mode(vcpu);
 
        /*
-        * Filled at exit: exit_code, exit_code_hi, exit_info_1, exit_info_2,
-        * exit_int_info, exit_int_info_err, next_rip, insn_len, insn_bytes.
+        * Filled at exit: exit_code, exit_info_1, exit_info_2, exit_int_info,
+        * exit_int_info_err, next_rip, insn_len, insn_bytes.
         */
 
        if (guest_cpu_cap_has(vcpu, X86_FEATURE_VGIF) &&
@@ -1018,7 +1016,6 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu)
        if (!nested_vmcb_check_save(vcpu) ||
            !nested_vmcb_check_controls(vcpu)) {
                vmcb12->control.exit_code    = SVM_EXIT_ERR;
-               vmcb12->control.exit_code_hi = -1u;
                vmcb12->control.exit_info_1  = 0;
                vmcb12->control.exit_info_2  = 0;
                goto out;
@@ -1051,7 +1048,6 @@ out_exit_err:
        svm->soft_int_injected = false;
 
        svm->vmcb->control.exit_code    = SVM_EXIT_ERR;
-       svm->vmcb->control.exit_code_hi = -1u;
        svm->vmcb->control.exit_info_1  = 0;
        svm->vmcb->control.exit_info_2  = 0;
 
@@ -1163,7 +1159,6 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
 
        vmcb12->control.int_state         = vmcb02->control.int_state;
        vmcb12->control.exit_code         = vmcb02->control.exit_code;
-       vmcb12->control.exit_code_hi      = vmcb02->control.exit_code_hi;
        vmcb12->control.exit_info_1       = vmcb02->control.exit_info_1;
        vmcb12->control.exit_info_2       = vmcb02->control.exit_info_2;
 
@@ -1460,7 +1455,7 @@ static int nested_svm_intercept_ioio(struct vcpu_svm *svm)
 
 static int nested_svm_intercept(struct vcpu_svm *svm)
 {
-       u32 exit_code = svm->vmcb->control.exit_code;
+       u64 exit_code = svm->vmcb->control.exit_code;
        int vmexit = NESTED_EXIT_HOST;
 
        if (svm_is_vmrun_failure(exit_code))
@@ -1532,7 +1527,6 @@ static void nested_svm_inject_exception_vmexit(struct kvm_vcpu *vcpu)
        struct vmcb *vmcb = svm->vmcb;
 
        vmcb->control.exit_code = SVM_EXIT_EXCP_BASE + ex->vector;
-       vmcb->control.exit_code_hi = 0;
 
        if (ex->has_error_code)
                vmcb->control.exit_info_1 = ex->error_code;
@@ -1708,7 +1702,6 @@ static void nested_copy_vmcb_cache_to_control(struct vmcb_control_area *dst,
        dst->int_vector           = from->int_vector;
        dst->int_state            = from->int_state;
        dst->exit_code            = from->exit_code;
-       dst->exit_code_hi         = from->exit_code_hi;
        dst->exit_info_1          = from->exit_info_1;
        dst->exit_info_2          = from->exit_info_2;
        dst->exit_int_info        = from->exit_int_info;
index 28150506b18c4af62ae6c4dbdd62e083d6d63adf..f6752500708978c56f9423c547b7c6a17ea49632 100644 (file)
@@ -3270,11 +3270,6 @@ skip_vmsa_free:
                kvfree(svm->sev_es.ghcb_sa);
 }
 
-static u64 kvm_get_cached_sw_exit_code(struct vmcb_control_area *control)
-{
-       return (((u64)control->exit_code_hi) << 32) | control->exit_code;
-}
-
 static void dump_ghcb(struct vcpu_svm *svm)
 {
        struct vmcb_control_area *control = &svm->vmcb->control;
@@ -3296,7 +3291,7 @@ static void dump_ghcb(struct vcpu_svm *svm)
         */
        pr_err("GHCB (GPA=%016llx) snapshot:\n", svm->vmcb->control.ghcb_gpa);
        pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_code",
-              kvm_get_cached_sw_exit_code(control), kvm_ghcb_sw_exit_code_is_valid(svm));
+              control->exit_code, kvm_ghcb_sw_exit_code_is_valid(svm));
        pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_info_1",
               control->exit_info_1, kvm_ghcb_sw_exit_info_1_is_valid(svm));
        pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_info_2",
@@ -3330,7 +3325,6 @@ static void sev_es_sync_from_ghcb(struct vcpu_svm *svm)
        struct vmcb_control_area *control = &svm->vmcb->control;
        struct kvm_vcpu *vcpu = &svm->vcpu;
        struct ghcb *ghcb = svm->sev_es.ghcb;
-       u64 exit_code;
 
        /*
         * The GHCB protocol so far allows for the following data
@@ -3364,9 +3358,7 @@ static void sev_es_sync_from_ghcb(struct vcpu_svm *svm)
                __kvm_emulate_msr_write(vcpu, MSR_IA32_XSS, kvm_ghcb_get_xss(svm));
 
        /* Copy the GHCB exit information into the VMCB fields */
-       exit_code = kvm_ghcb_get_sw_exit_code(svm);
-       control->exit_code = lower_32_bits(exit_code);
-       control->exit_code_hi = upper_32_bits(exit_code);
+       control->exit_code = kvm_ghcb_get_sw_exit_code(svm);
        control->exit_info_1 = kvm_ghcb_get_sw_exit_info_1(svm);
        control->exit_info_2 = kvm_ghcb_get_sw_exit_info_2(svm);
        svm->sev_es.sw_scratch = kvm_ghcb_get_sw_scratch_if_valid(svm);
@@ -3379,15 +3371,8 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
 {
        struct vmcb_control_area *control = &svm->vmcb->control;
        struct kvm_vcpu *vcpu = &svm->vcpu;
-       u64 exit_code;
        u64 reason;
 
-       /*
-        * Retrieve the exit code now even though it may not be marked valid
-        * as it could help with debugging.
-        */
-       exit_code = kvm_get_cached_sw_exit_code(control);
-
        /* Only GHCB Usage code 0 is supported */
        if (svm->sev_es.ghcb->ghcb_usage) {
                reason = GHCB_ERR_INVALID_USAGE;
@@ -3401,7 +3386,7 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
            !kvm_ghcb_sw_exit_info_2_is_valid(svm))
                goto vmgexit_err;
 
-       switch (exit_code) {
+       switch (control->exit_code) {
        case SVM_EXIT_READ_DR7:
                break;
        case SVM_EXIT_WRITE_DR7:
@@ -3502,15 +3487,19 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
        return 0;
 
 vmgexit_err:
+       /*
+        * Print the exit code even though it may not be marked valid as it
+        * could help with debugging.
+        */
        if (reason == GHCB_ERR_INVALID_USAGE) {
                vcpu_unimpl(vcpu, "vmgexit: ghcb usage %#x is not valid\n",
                            svm->sev_es.ghcb->ghcb_usage);
        } else if (reason == GHCB_ERR_INVALID_EVENT) {
                vcpu_unimpl(vcpu, "vmgexit: exit code %#llx is not valid\n",
-                           exit_code);
+                           control->exit_code);
        } else {
                vcpu_unimpl(vcpu, "vmgexit: exit code %#llx input is not valid\n",
-                           exit_code);
+                           control->exit_code);
                dump_ghcb(svm);
        }
 
@@ -4349,7 +4338,7 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
        struct vmcb_control_area *control = &svm->vmcb->control;
-       u64 ghcb_gpa, exit_code;
+       u64 ghcb_gpa;
        int ret;
 
        /* Validate the GHCB */
@@ -4391,8 +4380,7 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
 
        svm_vmgexit_success(svm, 0);
 
-       exit_code = kvm_get_cached_sw_exit_code(control);
-       switch (exit_code) {
+       switch (control->exit_code) {
        case SVM_VMGEXIT_MMIO_READ:
                ret = setup_vmgexit_scratch(svm, true, control->exit_info_2);
                if (ret)
@@ -4484,7 +4472,7 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
                ret = -EINVAL;
                break;
        default:
-               ret = svm_invoke_exit_handler(vcpu, exit_code);
+               ret = svm_invoke_exit_handler(vcpu, control->exit_code);
        }
 
        return ret;
index 3caf7a21679fc366646afc7a0a76f30e1ebed90e..a28cd61d87ea6c7dd7d1ef255afe22597f5de905 100644 (file)
@@ -2466,7 +2466,6 @@ static bool check_selective_cr0_intercepted(struct kvm_vcpu *vcpu,
 
        if (cr0 ^ val) {
                svm->vmcb->control.exit_code = SVM_EXIT_CR0_SEL_WRITE;
-               svm->vmcb->control.exit_code_hi = 0;
                ret = (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE);
        }
 
@@ -3299,7 +3298,7 @@ static void dump_vmcb(struct kvm_vcpu *vcpu)
        pr_err("%-20s%08x\n", "int_ctl:", control->int_ctl);
        pr_err("%-20s%08x\n", "int_vector:", control->int_vector);
        pr_err("%-20s%08x\n", "int_state:", control->int_state);
-       pr_err("%-20s%08x\n", "exit_code:", control->exit_code);
+       pr_err("%-20s%016llx\n", "exit_code:", control->exit_code);
        pr_err("%-20s%016llx\n", "exit_info1:", control->exit_info_1);
        pr_err("%-20s%016llx\n", "exit_info2:", control->exit_info_2);
        pr_err("%-20s%08x\n", "exit_int_info:", control->exit_int_info);
@@ -3549,7 +3548,6 @@ static int svm_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
        struct kvm_run *kvm_run = vcpu->run;
-       u32 exit_code = svm->vmcb->control.exit_code;
 
        /* SEV-ES guests must use the CR write traps to track CR registers. */
        if (!sev_es_guest(vcpu->kvm)) {
@@ -3585,7 +3583,7 @@ static int svm_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
        if (exit_fastpath != EXIT_FASTPATH_NONE)
                return 1;
 
-       return svm_invoke_exit_handler(vcpu, exit_code);
+       return svm_invoke_exit_handler(vcpu, svm->vmcb->control.exit_code);
 }
 
 static int pre_svm_run(struct kvm_vcpu *vcpu)
@@ -4670,7 +4668,6 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
        if (static_cpu_has(X86_FEATURE_NRIPS))
                vmcb->control.next_rip  = info->next_rip;
        vmcb->control.exit_code = icpt_info.exit_code;
-       vmcb->control.exit_code_hi = 0;
        vmexit = nested_svm_exit_handled(svm);
 
        ret = (vmexit == NESTED_EXIT_DONE) ? X86EMUL_INTERCEPTED
index 3360ac36e07108dfeb6c715d4c1d8ecd69559568..a22433680c73db6aaf49aae3691a43a5d51655e3 100644 (file)
@@ -160,8 +160,7 @@ struct vmcb_ctrl_area_cached {
        u32 int_ctl;
        u32 int_vector;
        u32 int_state;
-       u32 exit_code;
-       u32 exit_code_hi;
+       u64 exit_code;
        u64 exit_info_1;
        u64 exit_info_2;
        u32 exit_int_info;
@@ -787,7 +786,6 @@ int nested_svm_vmexit(struct vcpu_svm *svm);
 static inline int nested_svm_simple_vmexit(struct vcpu_svm *svm, u32 exit_code)
 {
        svm->vmcb->control.exit_code    = exit_code;
-       svm->vmcb->control.exit_code_hi = 0;
        svm->vmcb->control.exit_info_1  = 0;
        svm->vmcb->control.exit_info_2  = 0;
        return nested_svm_vmexit(svm);
index e79bc9cb71623bdf4b5e6bbd272c528649aa19d9..e7fdbe9efc904c27e121bb5bcb19b506e3bb8c93 100644 (file)
@@ -383,10 +383,10 @@ TRACE_EVENT(kvm_apic,
 #define kvm_print_exit_reason(exit_reason, isa)                                \
        (isa == KVM_ISA_VMX) ?                                          \
        __print_symbolic(exit_reason & 0xffff, VMX_EXIT_REASONS) :      \
-       __print_symbolic(exit_reason, SVM_EXIT_REASONS),                \
+       __print_symbolic_u64(exit_reason, SVM_EXIT_REASONS),            \
        (isa == KVM_ISA_VMX && exit_reason & ~0xffff) ? " " : "",       \
        (isa == KVM_ISA_VMX) ?                                          \
-       __print_flags(exit_reason & ~0xffff, " ", VMX_EXIT_REASON_FLAGS) : ""
+       __print_flags_u64(exit_reason & ~0xffff, " ", VMX_EXIT_REASON_FLAGS) : ""
 
 #define TRACE_EVENT_KVM_EXIT(name)                                          \
 TRACE_EVENT(name,                                                           \
@@ -781,7 +781,7 @@ TRACE_EVENT_KVM_EXIT(kvm_nested_vmexit);
  * Tracepoint for #VMEXIT reinjected to the guest
  */
 TRACE_EVENT(kvm_nested_vmexit_inject,
-           TP_PROTO(__u32 exit_code,
+           TP_PROTO(__u64 exit_code,
                     __u64 exit_info1, __u64 exit_info2,
                     __u32 exit_int_info, __u32 exit_int_info_err, __u32 isa),
            TP_ARGS(exit_code, exit_info1, exit_info2,
index dd6d4939ea29b0ef63f9a425f96ed0d82fadcdef..384c3f3ff4a525269e369e163c9da4e2420f4486 100644 (file)
@@ -281,7 +281,7 @@ struct hv_vmcb_enlightenments {
 #define HV_VMCB_NESTED_ENLIGHTENMENTS          31
 
 /* Synthetic VM-Exit */
-#define HV_SVM_EXITCODE_ENL                    0xf0000000
+#define HV_SVM_EXITCODE_ENL                    0xf0000000ull
 #define HV_SVM_ENL_EXITCODE_TRAP_AFTER_FLUSH   (1)
 
 /* VM_PARTITION_ASSIST_PAGE */
index 29cffd0a918166fe4bf5469848d1fb6ee1ad74d2..10b30b38bb3fdecc60c58aed7ae4fe05ea828f95 100644 (file)
@@ -92,8 +92,7 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
        u32 int_vector;
        u32 int_state;
        u8 reserved_3[4];
-       u32 exit_code;
-       u32 exit_code_hi;
+       u64 exit_code;
        u64 exit_info_1;
        u64 exit_info_2;
        u32 exit_int_info;
index 7b6481d6c0d3db806be872fcee98663db65290ed..4bd1655f9e6d0d09d3df8ce7cb891849a73b7825 100644 (file)
@@ -103,7 +103,7 @@ static void l1_guest_code(struct svm_test_data *svm, uint64_t is_nmi, uint64_t i
 
        run_guest(vmcb, svm->vmcb_gpa);
        __GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_VMMCALL,
-                      "Expected VMMCAL #VMEXIT, got '0x%x', info1 = '0x%lx, info2 = '0x%lx'",
+                      "Expected VMMCAL #VMEXIT, got '0x%lx', info1 = '0x%lx, info2 = '0x%lx'",
                       vmcb->control.exit_code,
                       vmcb->control.exit_info_1, vmcb->control.exit_info_2);
 
@@ -133,7 +133,7 @@ static void l1_guest_code(struct svm_test_data *svm, uint64_t is_nmi, uint64_t i
 
        run_guest(vmcb, svm->vmcb_gpa);
        __GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_HLT,
-                      "Expected HLT #VMEXIT, got '0x%x', info1 = '0x%lx, info2 = '0x%lx'",
+                      "Expected HLT #VMEXIT, got '0x%lx', info1 = '0x%lx, info2 = '0x%lx'",
                       vmcb->control.exit_code,
                       vmcb->control.exit_info_1, vmcb->control.exit_info_2);