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

Daniel Paziyski posted 1 patch 4 weeks ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260627162623.57385-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 v3] hw/intc/apic: mask LVTs when software disabling the APIC
Posted by Daniel Paziyski 4 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>
---
v3:
 - Ported to the latest revision.
 - Link to v2: https://patchew.org/QEMU/20260420173816.63673-1-danielpaziyski@gmail.com/

v2:
 - Be consistent with the rest of the code, and mask the LVTs before
   calling apic_update_irq.
 - Link to v1: https://patchew.org/QEMU/20260225180555.154428-1-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 74e25c6..558c68a 100644
--- a/hw/intc/apic.c
+++ b/hw/intc/apic.c
@@ -928,6 +928,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);
@@ -972,6 +979,11 @@ static int apic_register_write(APICCommonState *s, int index, uint64_t val)
         break;
     case 0x0f:
         s->spurious_vec = val & 0x1ff;
+
+        if (!(val & APIC_SV_ENABLE)) {
+            apic_mask_lvts(s);
+        }
+
         apic_update_irq(s);
         break;
     case 0x10 ... 0x17:
@@ -1006,6 +1018,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.54.0