[PATCH] hw/intc/apic: mask LVTs when software disabling the APIC

Daniel Paziyski posted 1 patch 1 month, 2 weeks ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260225180555.154428-1-danielpaziyski@gmail.com
Maintainers: "Michael S. Tsirkin" <mst@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>
hw/intc/apic.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
[PATCH] hw/intc/apic: mask LVTs when software disabling the APIC
Posted by Daniel Paziyski 1 month, 2 weeks ago
According to the Intel SDM Vol. 3 and the AMD64 Programmer's Manual Vol. 2, when
the APIC is software disabled, doing so by clearing the software enable bit from
the spurious interrupt register, the LVT entries must then have their mask bit set,
and any attempts to clear them must be ignored until the APIC is software enabled
again. This patch implements that behavior.

Signed-off-by: Daniel Paziyski <danielpaziyski@gmail.com>
---
 hw/intc/apic.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/hw/intc/apic.c b/hw/intc/apic.c
index 8766ed0..ef52961 100644
--- a/hw/intc/apic.c
+++ b/hw/intc/apic.c
@@ -919,6 +919,13 @@ static void apic_send_msi(MSIMessage *msi)
     apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode);
 }
 
+static void apic_mask_lvts(APICCommonState *s)
+{
+    for (int i = 0; i < APIC_LVT_NB; i++) {
+        s->lvt[i] |= APIC_LVT_MASKED;
+    }
+}
+
 static int apic_register_write(APICCommonState *s, int index, uint64_t val)
 {
     trace_apic_register_write(index, val);
@@ -964,6 +971,11 @@ static int apic_register_write(APICCommonState *s, int index, uint64_t val)
     case 0x0f:
         s->spurious_vec = val & 0x1ff;
         apic_update_irq(s);
+
+        if (!(val & APIC_SV_ENABLE)) {
+            apic_mask_lvts(s);
+        }
+
         break;
     case 0x10 ... 0x17:
     case 0x18 ... 0x1f:
@@ -997,6 +1009,9 @@ static int apic_register_write(APICCommonState *s, int index, uint64_t val)
         {
             int n = index - 0x32;
             s->lvt[n] = val;
+            if (!(s->spurious_vec & APIC_SV_ENABLE)) {
+                s->lvt[n] |= APIC_LVT_MASKED;
+            }
             if (n == APIC_LVT_TIMER) {
                 apic_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
             } else if (n == APIC_LVT_LINT0 && apic_check_pic(s)) {
-- 
2.53.0