Do not process INITs immediately while in system management mode, keep
it instead in apic->pending_events.  Tell userspace if an INIT is
pending when they issue GET_VCPU_EVENTS, and similarly handle the
new field in SET_VCPU_EVENTS.

Note that the same treatment should be done while in VMX non-root mode.

Signed-off-by: Paolo Bonzini <pbonz...@redhat.com>
---
 Documentation/virtual/kvm/api.txt |  2 +-
 arch/x86/include/uapi/asm/kvm.h   |  2 +-
 arch/x86/kvm/lapic.c              | 13 ++++++++++++-
 arch/x86/kvm/lapic.h              |  5 +++++
 arch/x86/kvm/x86.c                | 11 ++++++++++-
 5 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/Documentation/virtual/kvm/api.txt 
b/Documentation/virtual/kvm/api.txt
index 91ab5f2354aa..461956a0ee8e 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -829,7 +829,7 @@ struct kvm_vcpu_events {
                __u8 smm;
                __u8 pending;
                __u8 smm_inside_nmi;
-               __u8 pad;
+               __u8 latched_init;
        } smi;
 };
 
diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h
index 30100a3c1bed..a4ae82eb82aa 100644
--- a/arch/x86/include/uapi/asm/kvm.h
+++ b/arch/x86/include/uapi/asm/kvm.h
@@ -316,7 +316,7 @@ struct kvm_vcpu_events {
                __u8 smm;
                __u8 pending;
                __u8 smm_inside_nmi;
-               __u8 pad;
+               __u8 latched_init;
        } smi;
        __u32 reserved[9];
 };
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index b8e47e2b1d94..beeef05bb4d9 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -2057,8 +2057,19 @@ void kvm_apic_accept_events(struct kvm_vcpu *vcpu)
        if (!kvm_vcpu_has_lapic(vcpu) || !apic->pending_events)
                return;
 
-       pe = xchg(&apic->pending_events, 0);
+       /*
+        * INITs are latched while in SMM.  Because an SMM CPU cannot
+        * be in KVM_MP_STATE_INIT_RECEIVED state, just eat SIPIs
+        * and delay processing of INIT until the next RSM.
+        */
+       if (is_smm(vcpu)) {
+               WARN_ON_ONCE(vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED);
+               if (test_bit(KVM_APIC_SIPI, &apic->pending_events))
+                       clear_bit(KVM_APIC_SIPI, &apic->pending_events);
+               return;
+       }
 
+       pe = xchg(&apic->pending_events, 0);
        if (test_bit(KVM_APIC_INIT, &pe)) {
                kvm_lapic_reset(vcpu, true);
                kvm_vcpu_reset(vcpu, true);
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 9d8fcde52027..f2f4e10ab772 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -159,6 +159,11 @@ static inline bool kvm_lowest_prio_delivery(struct 
kvm_lapic_irq *irq)
                        irq->msi_redir_hint);
 }
 
+static inline int kvm_lapic_latched_init(struct kvm_vcpu *vcpu)
+{
+       return kvm_vcpu_has_lapic(vcpu) && test_bit(KVM_APIC_INIT, 
&vcpu->arch.apic->pending_events);
+}
+
 bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector);
 
 void wait_lapic_expire(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 36962b7627df..5e6d19730ef9 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3240,7 +3240,7 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct 
kvm_vcpu *vcpu,
        events->smi.pending = vcpu->arch.smi_pending;
        events->smi.smm_inside_nmi =
                !!(vcpu->arch.hflags & HF_SMM_INSIDE_NMI_MASK);
-       events->smi.pad = 0;
+       events->smi.latched_init = kvm_lapic_latched_init(vcpu);
 
        events->flags = (KVM_VCPUEVENT_VALID_NMI_PENDING
                         | KVM_VCPUEVENT_VALID_SHADOW
@@ -3289,6 +3289,12 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct 
kvm_vcpu *vcpu,
                        vcpu->arch.hflags |= HF_SMM_INSIDE_NMI_MASK;
                else
                        vcpu->arch.hflags &= ~HF_SMM_INSIDE_NMI_MASK;
+               if (kvm_vcpu_has_lapic(vcpu)) {
+                       if (events->smi.latched_init)
+                               set_bit(KVM_APIC_INIT, 
&vcpu->arch.apic->pending_events);
+                       else
+                               clear_bit(KVM_APIC_INIT, 
&vcpu->arch.apic->pending_events);
+               }
        }
 
        kvm_make_request(KVM_REQ_EVENT, vcpu);
@@ -5495,6 +5501,9 @@ static void kvm_smm_changed(struct kvm_vcpu *vcpu)
                if (unlikely(vcpu->arch.smi_pending)) {
                        kvm_make_request(KVM_REQ_SMI, vcpu);
                        vcpu->arch.smi_pending = 0;
+               } else {
+                       /* Process a latched INIT, if any.  */
+                       kvm_make_request(KVM_REQ_EVENT, vcpu);
                }
        }
 
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to