From nobody Mon Feb 9 15:10:14 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1560560206; cv=none; d=zoho.com; s=zohoarc; b=hm7CMQqvyuRa58NQAA2eLYM3jh77ubF8gQcPXTxTszERbUqDUmCQOY96cUrAJX5O1F9ID8nZ5TnqPfoUy4gu5waMlwUekQyqZ5pWwubAulZ0oMtcV/2fTcBqfeCYaHJJNPvJaZrA+imrqoSzIcN781IhVQW1Nkqp3Pn4aTgsC4Q= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1560560206; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=+7Xf4ehPVEjmQK/UU3GOZut7M7AHJc9i0ZuuPNjoMyo=; b=HYZypc1H9lcsb9WYbEPRElPJWz43gHXueJa5c5HZZJnkBi/vHJnLwkeJw1hSG72+X+zPJn5AxjLJvrOTYyrrWTzFt9EP8jFbI309GkmkdoPwoMx1wZYpC5EsXvXzWynzLvOkTDKVQnVPXoCMEmn+SRNq9TXUW0GT7q7HYc+oTIk= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (209.51.188.17 [209.51.188.17]) by mx.zohomail.com with SMTPS id 1560560206500260.1574545823769; Fri, 14 Jun 2019 17:56:46 -0700 (PDT) Received: from localhost ([::1]:57892 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbwzo-0001cn-Hc for importer@patchew.org; Fri, 14 Jun 2019 20:56:40 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60453) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbwmf-0000WL-Os for qemu-devel@nongnu.org; Fri, 14 Jun 2019 20:43:09 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hbwmd-0004Ez-Ms for qemu-devel@nongnu.org; Fri, 14 Jun 2019 20:43:05 -0400 Received: from mail-wr1-x444.google.com ([2a00:1450:4864:20::444]:42849) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1hbwma-0004A8-Na for qemu-devel@nongnu.org; Fri, 14 Jun 2019 20:43:01 -0400 Received: by mail-wr1-x444.google.com with SMTP id x17so4195493wrl.9 for ; Fri, 14 Jun 2019 17:43:00 -0700 (PDT) Received: from donizetti.lan ([2001:b07:6468:f312:1da0:213e:1763:a1a8]) by smtp.gmail.com with ESMTPSA id m21sm3774234wmc.1.2019.06.14.17.42.57 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Fri, 14 Jun 2019 17:42:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=+7Xf4ehPVEjmQK/UU3GOZut7M7AHJc9i0ZuuPNjoMyo=; b=vgGYJCJVn25Rv+9xWKwQV8m6sX/bk6i4/Z9xt2pRkEuyQ6fh9HjYB1UUQFcRhr0tmh a2VFLq3RnWIFea+q+Kxe1Ov6GpK6SnUanGpAErvLeDUJ9zg17ixUblrSQ+OMmvKlyAYx yssvbDU4RAd/hCrj8oarrZjAhpczIQXuNwAgMv13KxISqOuIOUJydtmAQKVXlQ2gezwg LUzbMwWrAUW/MBkJqu+sa/Vlt94Hk2P2nVsyLO7EzCLePMq8qqvR8h1rd45PYzruNOYT fqbj/likylSael6lrcMjDxuhiI+bRgKU+Q+Xo7ky67TGSGLVhwWTljsURpw8tirUNnnX 1EaA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=+7Xf4ehPVEjmQK/UU3GOZut7M7AHJc9i0ZuuPNjoMyo=; b=FZE219nXIaKgoKrFGP1FW0WSP+9hZimYae8LeXevoZffz17FiHO03nwiaVz8njn8lK 8dmp+xdNotDWPj+a5E9rB4FOGtzbZ6sNz0pNq4PLO3YWqsf4D8R4CTIybhuHtWHQk6tk /FEXxfZSRNg20TMR2uCqtDbruaPbwSSVran5FsHxZR3JAoAhHJrLB63yOkhqdAhtGw68 +weOP4mcGMBs7xoG/3Zq4E0wpG5QJvQhLQOZFD+cAklLUiK0evydxYigkbG2L9F5XdhJ k1rKzNgB6vDNYhWmuPALAPN5Ko9xtW9e4rf5PYplG+JF8F0UHbJzp2DIk+ifydKnhBXf SXhw== X-Gm-Message-State: APjAAAW55PqsrNRc8/8oTnBKKDICfrdyK2kFn5DOr/XNwyULDhoJndif 2mBoilhO/cYMQvCBoOViys264TU+ X-Google-Smtp-Source: APXvYqzVnKL3q5aALG22650hjD/Q191mAKAlV/sHYILD9JyVaIqUrFs+M+fsvoHHXQ6tEgX4efJpzg== X-Received: by 2002:a05:6000:11cc:: with SMTP id i12mr7369109wrx.243.1560559378696; Fri, 14 Jun 2019 17:42:58 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Sat, 15 Jun 2019 02:42:52 +0200 Message-Id: <20190615004256.16367-4-pbonzini@redhat.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190615004256.16367-1-pbonzini@redhat.com> References: <20190615004256.16367-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::444 Subject: [Qemu-devel] [PATCH 3/7] KVM: i386: Add support for KVM_CAP_EXCEPTION_PAYLOAD X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: liran.alon@oracle.com, nikita.leshchenko@oracle.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" From: Liran Alon Kernel commit c4f55198c7c2 ("kvm: x86: Introduce KVM_CAP_EXCEPTION_PAYLOAD") introduced a new KVM capability which allows userspace to correctly distinguish between pending and injected exceptions. This distinguish is important in case of nested virtualization scenarios because a L2 pending exception can still be intercepted by the L1 hypervisor while a L2 injected exception cannot. Furthermore, when an exception is attempted to be injected by QEMU, QEMU should specify the exception payload (CR2 in case of #PF or DR6 in case of #DB) instead of having the payload already delivered in the respective vCPU register. Because in case exception is injected to L2 guest and is intercepted by L1 hypervisor, then payload needs to be reported to L1 intercept (VMExit handler) while still preserving respective vCPU register unchanged. This commit adds support for QEMU to properly utilise this new KVM capability (KVM_CAP_EXCEPTION_PAYLOAD). Reviewed-by: Nikita Leshenko Signed-off-by: Liran Alon Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 10 ++--- target/i386/cpu.h | 13 +++++- target/i386/hvf/hvf.c | 10 +++-- target/i386/hvf/x86hvf.c | 4 +- target/i386/kvm.c | 95 +++++++++++++++++++++++++++++++++------- target/i386/machine.c | 61 +++++++++++++++++++++++++- 6 files changed, 163 insertions(+), 30 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index c1ab86d63e..4e19969111 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -4777,7 +4777,9 @@ static void x86_cpu_reset(CPUState *s) memset(env->mtrr_fixed, 0, sizeof(env->mtrr_fixed)); =20 env->interrupt_injected =3D -1; - env->exception_injected =3D -1; + env->exception_nr =3D -1; + env->exception_pending =3D 0; + env->exception_injected =3D 0; env->nmi_injected =3D false; #if !defined(CONFIG_USER_ONLY) /* We hard-wire the BSP to the first CPU. */ @@ -5173,12 +5175,6 @@ static int x86_cpu_filter_features(X86CPU *cpu) return rv; } =20 -#define IS_INTEL_CPU(env) ((env)->cpuid_vendor1 =3D=3D CPUID_VENDOR_INTEL_= 1 && \ - (env)->cpuid_vendor2 =3D=3D CPUID_VENDOR_INTEL_= 2 && \ - (env)->cpuid_vendor3 =3D=3D CPUID_VENDOR_INTEL_= 3) -#define IS_AMD_CPU(env) ((env)->cpuid_vendor1 =3D=3D CPUID_VENDOR_AMD_1 &&= \ - (env)->cpuid_vendor2 =3D=3D CPUID_VENDOR_AMD_2 &&= \ - (env)->cpuid_vendor3 =3D=3D CPUID_VENDOR_AMD_3) static void x86_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs =3D CPU(dev); diff --git a/target/i386/cpu.h b/target/i386/cpu.h index bd06523a53..bbeb7a9521 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -729,6 +729,13 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; =20 #define CPUID_VENDOR_HYGON "HygonGenuine" =20 +#define IS_INTEL_CPU(env) ((env)->cpuid_vendor1 =3D=3D CPUID_VENDOR_INTEL_= 1 && \ + (env)->cpuid_vendor2 =3D=3D CPUID_VENDOR_INTEL_= 2 && \ + (env)->cpuid_vendor3 =3D=3D CPUID_VENDOR_INTEL_= 3) +#define IS_AMD_CPU(env) ((env)->cpuid_vendor1 =3D=3D CPUID_VENDOR_AMD_1 &&= \ + (env)->cpuid_vendor2 =3D=3D CPUID_VENDOR_AMD_2 &&= \ + (env)->cpuid_vendor3 =3D=3D CPUID_VENDOR_AMD_3) + #define CPUID_MWAIT_IBE (1U << 1) /* Interrupts can exit capability */ #define CPUID_MWAIT_EMX (1U << 0) /* enumeration supported */ =20 @@ -1332,10 +1339,14 @@ typedef struct CPUX86State { =20 /* For KVM */ uint32_t mp_state; - int32_t exception_injected; + int32_t exception_nr; int32_t interrupt_injected; uint8_t soft_interrupt; + uint8_t exception_pending; + uint8_t exception_injected; uint8_t has_error_code; + uint8_t exception_has_payload; + uint64_t exception_payload; uint32_t ins_len; uint32_t sipi_vector; bool tsc_valid; diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 2751c8125c..dc4bb63536 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -605,7 +605,9 @@ static void hvf_store_events(CPUState *cpu, uint32_t in= s_len, uint64_t idtvec_in X86CPU *x86_cpu =3D X86_CPU(cpu); CPUX86State *env =3D &x86_cpu->env; =20 - env->exception_injected =3D -1; + env->exception_nr =3D -1; + env->exception_pending =3D 0; + env->exception_injected =3D 0; env->interrupt_injected =3D -1; env->nmi_injected =3D false; if (idtvec_info & VMCS_IDT_VEC_VALID) { @@ -619,7 +621,8 @@ static void hvf_store_events(CPUState *cpu, uint32_t in= s_len, uint64_t idtvec_in break; case VMCS_IDT_VEC_HWEXCEPTION: case VMCS_IDT_VEC_SWEXCEPTION: - env->exception_injected =3D idtvec_info & VMCS_IDT_VEC_VECNUM; + env->exception_nr =3D idtvec_info & VMCS_IDT_VEC_VECNUM; + env->exception_injected =3D 1; break; case VMCS_IDT_VEC_PRIV_SWEXCEPTION: default: @@ -912,7 +915,8 @@ int hvf_vcpu_exec(CPUState *cpu) macvm_set_rip(cpu, rip + ins_len); break; case VMX_REASON_VMCALL: - env->exception_injected =3D EXCP0D_GPF; + env->exception_nr =3D EXCP0D_GPF; + env->exception_injected =3D 1; env->has_error_code =3D true; env->error_code =3D 0; break; diff --git a/target/i386/hvf/x86hvf.c b/target/i386/hvf/x86hvf.c index df8e946fbc..e0ea02d631 100644 --- a/target/i386/hvf/x86hvf.c +++ b/target/i386/hvf/x86hvf.c @@ -362,8 +362,8 @@ bool hvf_inject_interrupts(CPUState *cpu_state) if (env->interrupt_injected !=3D -1) { vector =3D env->interrupt_injected; intr_type =3D VMCS_INTR_T_SWINTR; - } else if (env->exception_injected !=3D -1) { - vector =3D env->exception_injected; + } else if (env->exception_nr !=3D -1) { + vector =3D env->exception_nr; if (vector =3D=3D EXCP03_INT3 || vector =3D=3D EXCP04_INTO) { intr_type =3D VMCS_INTR_T_SWEXCEPTION; } else { diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 53f95b02a0..dca76830ec 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -104,6 +104,7 @@ static uint32_t num_architectural_pmu_fixed_counters; static int has_xsave; static int has_xcrs; static int has_pit_state2; +static int has_exception_payload; =20 static bool has_msr_mcg_ext_ctl; =20 @@ -584,15 +585,51 @@ void kvm_arch_on_sigbus_vcpu(CPUState *c, int code, v= oid *addr) /* Hope we are lucky for AO MCE */ } =20 +static void kvm_reset_exception(CPUX86State *env) +{ + env->exception_nr =3D -1; + env->exception_pending =3D 0; + env->exception_injected =3D 0; +} + +static void kvm_queue_exception(CPUX86State *env, + int32_t exception_nr, + uint8_t exception_has_payload, + uint64_t exception_payload) +{ + assert(env->exception_nr =3D=3D -1); + assert(!env->exception_pending); + assert(!env->exception_injected); + + env->exception_nr =3D exception_nr; + + if (has_exception_payload) { + env->exception_pending =3D 1; + + env->exception_has_payload =3D exception_has_payload; + env->exception_payload =3D exception_payload; + } else { + env->exception_injected =3D 1; + + if (exception_has_payload) { + if (exception_nr =3D=3D EXCP01_DB) { + env->dr[6] =3D exception_payload; + } else if (exception_nr =3D=3D EXCP0E_PAGE) { + env->cr[2] =3D exception_payload; + } + } + } +} + static int kvm_inject_mce_oldstyle(X86CPU *cpu) { CPUX86State *env =3D &cpu->env; =20 - if (!kvm_has_vcpu_events() && env->exception_injected =3D=3D EXCP12_MC= HK) { + if (!kvm_has_vcpu_events() && env->exception_nr =3D=3D EXCP12_MCHK) { unsigned int bank, bank_num =3D env->mcg_cap & 0xff; struct kvm_x86_mce mce; =20 - env->exception_injected =3D -1; + kvm_reset_exception(env); =20 /* * There must be at least one bank in use if an MCE is pending. @@ -1573,6 +1610,16 @@ int kvm_arch_init(MachineState *ms, KVMState *s) =20 hv_vpindex_settable =3D kvm_check_extension(s, KVM_CAP_HYPERV_VP_INDEX= ); =20 + has_exception_payload =3D kvm_check_extension(s, KVM_CAP_EXCEPTION_PAY= LOAD); + if (has_exception_payload) { + ret =3D kvm_vm_enable_cap(s, KVM_CAP_EXCEPTION_PAYLOAD, 0, true); + if (ret < 0) { + error_report("kvm: Failed to enable exception payload cap: %s", + strerror(-ret)); + return ret; + } + } + ret =3D kvm_get_supported_msrs(s); if (ret < 0) { return ret; @@ -2877,8 +2924,16 @@ static int kvm_put_vcpu_events(X86CPU *cpu, int leve= l) return 0; } =20 - events.exception.injected =3D (env->exception_injected >=3D 0); - events.exception.nr =3D env->exception_injected; + events.flags =3D 0; + + if (has_exception_payload) { + events.flags |=3D KVM_VCPUEVENT_VALID_PAYLOAD; + events.exception.pending =3D env->exception_pending; + events.exception_has_payload =3D env->exception_has_payload; + events.exception_payload =3D env->exception_payload; + } + events.exception.nr =3D env->exception_nr; + events.exception.injected =3D env->exception_injected; events.exception.has_error_code =3D env->has_error_code; events.exception.error_code =3D env->error_code; =20 @@ -2891,7 +2946,6 @@ static int kvm_put_vcpu_events(X86CPU *cpu, int level) events.nmi.masked =3D !!(env->hflags2 & HF2_NMI_MASK); =20 events.sipi_vector =3D env->sipi_vector; - events.flags =3D 0; =20 if (has_msr_smbase) { events.smi.smm =3D !!(env->hflags & HF_SMM_MASK); @@ -2941,8 +2995,19 @@ static int kvm_get_vcpu_events(X86CPU *cpu) if (ret < 0) { return ret; } - env->exception_injected =3D - events.exception.injected ? events.exception.nr : -1; + + if (events.flags & KVM_VCPUEVENT_VALID_PAYLOAD) { + env->exception_pending =3D events.exception.pending; + env->exception_has_payload =3D events.exception_has_payload; + env->exception_payload =3D events.exception_payload; + } else { + env->exception_pending =3D 0; + env->exception_has_payload =3D false; + } + env->exception_injected =3D events.exception.injected; + env->exception_nr =3D + (env->exception_pending || env->exception_injected) ? + events.exception.nr : -1; env->has_error_code =3D events.exception.has_error_code; env->error_code =3D events.exception.error_code; =20 @@ -2994,12 +3059,12 @@ static int kvm_guest_debug_workarounds(X86CPU *cpu) unsigned long reinject_trap =3D 0; =20 if (!kvm_has_vcpu_events()) { - if (env->exception_injected =3D=3D EXCP01_DB) { + if (env->exception_nr =3D=3D EXCP01_DB) { reinject_trap =3D KVM_GUESTDBG_INJECT_DB; } else if (env->exception_injected =3D=3D EXCP03_INT3) { reinject_trap =3D KVM_GUESTDBG_INJECT_BP; } - env->exception_injected =3D -1; + kvm_reset_exception(env); } =20 /* @@ -3320,13 +3385,13 @@ int kvm_arch_process_async_events(CPUState *cs) =20 kvm_cpu_synchronize_state(cs); =20 - if (env->exception_injected =3D=3D EXCP08_DBLE) { + if (env->exception_nr =3D=3D EXCP08_DBLE) { /* this means triple fault */ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); cs->exit_request =3D 1; return 0; } - env->exception_injected =3D EXCP12_MCHK; + kvm_queue_exception(env, EXCP12_MCHK, 0, 0); env->has_error_code =3D 0; =20 cs->halted =3D 0; @@ -3541,14 +3606,12 @@ static int kvm_handle_debug(X86CPU *cpu, } if (ret =3D=3D 0) { cpu_synchronize_state(cs); - assert(env->exception_injected =3D=3D -1); + assert(env->exception_nr =3D=3D -1); =20 /* pass to guest */ - env->exception_injected =3D arch_info->exception; + kvm_queue_exception(env, arch_info->exception, + EXCP01_DB, arch_info->dr6); env->has_error_code =3D 0; - if (arch_info->exception =3D=3D EXCP01_DB) { - env->dr[6] =3D arch_info->dr6; - } } =20 return ret; diff --git a/target/i386/machine.c b/target/i386/machine.c index 225b5d433b..41460be54b 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -199,6 +199,21 @@ static const VMStateDescription vmstate_fpreg =3D { } }; =20 +static bool is_vmx_enabled(CPUX86State *env) +{ + return (IS_INTEL_CPU(env) && (env->cr[4] & CR4_VMXE_MASK)); +} + +static bool is_svm_enabled(CPUX86State *env) +{ + return (IS_AMD_CPU(env) && (env->efer & MSR_EFER_SVME)); +} + +static bool is_nested_virt_enabled(CPUX86State *env) +{ + return (is_vmx_enabled(env) || is_svm_enabled(env)); +} + static int cpu_pre_save(void *opaque) { X86CPU *cpu =3D opaque; @@ -278,6 +293,23 @@ static int cpu_post_load(void *opaque, int version_id) env->hflags &=3D ~HF_CPL_MASK; env->hflags |=3D (env->segs[R_SS].flags >> DESC_DPL_SHIFT) & HF_CPL_MA= SK; =20 + /* + * There are cases that we can get valid exception_nr with both + * exception_pending and exception_clear being cleared. This can happe= n in + * one of the following scenarios: + * 1) Source is older QEMU without KVM_CAP_EXCEPTION_PAYLOAD support. + * 2) Source is running on kernel without KVM_CAP_EXCEPTION_PAYLOAD su= pport. + * 3) "cpu/exception_info" subsection not sent because there is no exc= eption + * pending or guest wasn't running L2. + * + * In those cases, we can just deduce that a valid exception_nr means + * we can treat the exception as already injected. + */ + if ((env->exception_nr !=3D -1) && + !env->exception_pending && !env->exception_injected) { + env->exception_injected =3D 1; + } + env->fpstt =3D (env->fpus_vmstate >> 11) & 7; env->fpus =3D env->fpus_vmstate & ~0x3800; env->fptag_vmstate ^=3D 0xff; @@ -323,6 +355,32 @@ static bool steal_time_msr_needed(void *opaque) return cpu->env.steal_time_msr !=3D 0; } =20 +static bool exception_info_needed(void *opaque) +{ + X86CPU *cpu =3D opaque; + + /* + * Differenting between pending and injected exceptions + * is only important when running L2. + */ + return (cpu->env.exception_pending && + is_nested_virt_enabled(&cpu->env)); +} + +static const VMStateDescription vmstate_exception_info =3D { + .name =3D "cpu/exception_info", + .version_id =3D 1, + .minimum_version_id =3D 1, + .needed =3D exception_info_needed, + .fields =3D (VMStateField[]) { + VMSTATE_UINT8(env.exception_pending, X86CPU), + VMSTATE_UINT8(env.exception_injected, X86CPU), + VMSTATE_UINT8(env.exception_has_payload, X86CPU), + VMSTATE_UINT64(env.exception_payload, X86CPU), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_steal_time_msr =3D { .name =3D "cpu/steal_time_msr", .version_id =3D 1, @@ -1035,7 +1093,7 @@ VMStateDescription vmstate_x86_cpu =3D { VMSTATE_INT32(env.interrupt_injected, X86CPU), VMSTATE_UINT32(env.mp_state, X86CPU), VMSTATE_UINT64(env.tsc, X86CPU), - VMSTATE_INT32(env.exception_injected, X86CPU), + VMSTATE_INT32(env.exception_nr, X86CPU), VMSTATE_UINT8(env.soft_interrupt, X86CPU), VMSTATE_UINT8(env.nmi_injected, X86CPU), VMSTATE_UINT8(env.nmi_pending, X86CPU), @@ -1059,6 +1117,7 @@ VMStateDescription vmstate_x86_cpu =3D { /* The above list is not sorted /wrt version numbers, watch out! */ }, .subsections =3D (const VMStateDescription*[]) { + &vmstate_exception_info, &vmstate_async_pf_msr, &vmstate_pv_eoi_msr, &vmstate_steal_time_msr, --=20 2.21.0