From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jan Kiszka Subject: [PATCH] qemu-kvm: x86: Add support for NMI states Date: Wed, 14 Oct 2009 10:52:37 +0200 Message-ID: <4AD59155.5050706@siemens.com> References: <20091013160647.27006.58598.stgit@mchn012c.ww002.siemens.net> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit Cc: kvm@vger.kernel.org To: Avi Kivity , Marcelo Tosatti Return-path: Received: from david.siemens.de ([192.35.17.14]:23652 "EHLO david.siemens.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754582AbZJNIx1 (ORCPT ); Wed, 14 Oct 2009 04:53:27 -0400 In-Reply-To: <20091013160647.27006.58598.stgit@mchn012c.ww002.siemens.net> Sender: kvm-owner@vger.kernel.org List-ID: This adds the required bit to retrieve and set the so far hidden NMI pending and NMI masked states of the KVM kernel side. It also extends CPU VMState for proper saving/restoring. We can now savely reset a VM while NMIs are on the fly, and we can live migrate etc. too. Fortunately, the probability that this deficit bit normal VMs in practice was very low. Signed-off-by: Jan Kiszka --- qemu-kvm-x86.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ target-i386/cpu.h | 1 + target-i386/machine.c | 1 + 3 files changed, 54 insertions(+), 0 deletions(-) diff --git a/qemu-kvm-x86.c b/qemu-kvm-x86.c index acb1b91..86fd341 100644 --- a/qemu-kvm-x86.c +++ b/qemu-kvm-x86.c @@ -901,6 +901,53 @@ static void get_seg(SegmentCache *lhs, const struct kvm_segment *rhs) | (rhs->avl * DESC_AVL_MASK); } +static void kvm_get_nmi_state(CPUState *env) +{ +#ifdef KVM_CAP_VCPU_STATE + kvm_vcpu_context_t vcpu = env->kvm_cpu_state.vcpu_ctx; + struct { + struct kvm_vcpu_state header; + struct kvm_vcpu_substate substates[1]; + } request; + struct kvm_nmi_state nmi_state; + int r; + + request.header.nsubstates = 1; + request.header.substates[0].type = KVM_X86_VCPU_NMI; + request.header.substates[0].offset = (size_t)&nmi_state - (size_t)&request; + r = ioctl(vcpu->fd, KVM_GET_VCPU_STATE, &request); + if (r == 0) { + env->nmi_pending = nmi_state.pending; + if (nmi_state.masked) { + env->hflags2 |= HF2_NMI_MASK; + } else { + env->hflags2 &= ~HF2_NMI_MASK; + } + } +#endif + env->nmi_pending = 0; + env->hflags2 &= ~HF2_NMI_MASK; +} + +static void kvm_set_nmi_state(CPUState *env) +{ +#ifdef KVM_CAP_VCPU_STATE + kvm_vcpu_context_t vcpu = env->kvm_cpu_state.vcpu_ctx; + struct { + struct kvm_vcpu_state header; + struct kvm_vcpu_substate substates[1]; + } request; + struct kvm_nmi_state nmi_state; + + request.header.nsubstates = 1; + request.header.substates[0].type = KVM_X86_VCPU_NMI; + request.header.substates[0].offset = (size_t)&nmi_state - (size_t)&request; + nmi_state.pending = env->nmi_pending; + nmi_state.masked = !!(env->hflags2 & HF2_NMI_MASK); + ioctl(vcpu->fd, KVM_SET_VCPU_STATE, &request); +#endif +} + void kvm_arch_load_regs(CPUState *env) { struct kvm_regs regs; @@ -1010,6 +1057,8 @@ void kvm_arch_load_regs(CPUState *env) rc = kvm_set_msrs(env->kvm_cpu_state.vcpu_ctx, msrs, n); if (rc == -1) perror("kvm_set_msrs FAILED"); + + kvm_set_nmi_state(env); } void kvm_load_tsc(CPUState *env) @@ -1195,6 +1244,8 @@ void kvm_arch_save_regs(CPUState *env) return; } } + + kvm_get_nmi_state(env); } static void do_cpuid_ent(struct kvm_cpuid_entry2 *e, uint32_t function, @@ -1438,6 +1489,7 @@ void kvm_arch_push_nmi(void *opaque) void kvm_arch_cpu_reset(CPUState *env) { + env->nmi_pending = 0; kvm_arch_load_regs(env); if (!cpu_is_bsp(env)) { if (kvm_irqchip_in_kernel(kvm_context)) { diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 278d3e3..620822a 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -709,6 +709,7 @@ typedef struct CPUX86State { /* For KVM */ uint64_t interrupt_bitmap[256 / 64]; uint32_t mp_state; + uint32_t nmi_pending; /* in order to simplify APIC support, we leave this pointer to the user */ diff --git a/target-i386/machine.c b/target-i386/machine.c index e640dad..5c290f3 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -469,6 +469,7 @@ const VMStateDescription vmstate_cpu = { VMSTATE_INT32_V(pending_irq_vmstate, CPUState, 9), VMSTATE_UINT32_V(mp_state, CPUState, 9), VMSTATE_UINT64_V(tsc, CPUState, 9), + VMSTATE_UINT32_V(nmi_pending, CPUState, 11), /* MCE */ VMSTATE_UINT64_V(mcg_cap, CPUState, 10), VMSTATE_UINT64_V(mcg_status, CPUState, 10),