@@ -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)) {
@@ -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 */
@@ -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),