diff mbox series

[RFC,v2,41/44] ioapic: add property to disallow INIT/SIPI delivery mode

Message ID a48dcb44623ece9ad543583d7e76c24885ca0c93.1625704981.git.isaku.yamahata@intel.com (mailing list archive)
State New, archived
Headers show
Series TDX support | expand

Commit Message

Isaku Yamahata July 8, 2021, 12:55 a.m. UTC
From: Isaku Yamahata <isaku.yamahata@intel.com>

Add a property to prevent ioapic from setting INIT/SIPI delivery mode.
Without this guard, qemu can result in unexpected behavior.

Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
---
 hw/intc/ioapic.c                  | 19 +++++++++++++++++++
 hw/intc/ioapic_common.c           | 21 +++++++++++++++++++++
 include/hw/i386/ioapic_internal.h |  1 +
 3 files changed, 41 insertions(+)
diff mbox series

Patch

diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
index 1815fbd282..f7eb9f7146 100644
--- a/hw/intc/ioapic.c
+++ b/hw/intc/ioapic.c
@@ -396,6 +396,22 @@  ioapic_fix_smi_unsupported(uint64_t *entry)
     }
 }
 
+static inline void
+ioapic_fix_init_sipi_unsupported(uint64_t *entry)
+{
+    uint64_t delmode = *entry & IOAPIC_LVT_DELIV_MODE;
+    if (delmode == IOAPIC_DM_INIT << IOAPIC_LVT_DELIV_MODE_SHIFT ||
+        delmode == IOAPIC_DM_SIPI << IOAPIC_LVT_DELIV_MODE_SHIFT) {
+        /*
+         * ignore a request for delivery mode of lowest SMI
+         */
+        warn_report_once("attempting to set delivery mode to INIT/SIPI"
+                         "which is not supported");
+        *entry &= ~IOAPIC_LVT_DELIV_MODE;
+        *entry |= IOAPIC_DM_FIXED << IOAPIC_LVT_DELIV_MODE_SHIFT;
+    }
+}
+
 static void
 ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
                  unsigned int size)
@@ -442,6 +458,9 @@  ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
                 if (s->smi_unsupported) {
                     ioapic_fix_smi_unsupported(&s->ioredtbl[index]);
                 }
+                if (s->init_sipi_unsupported) {
+                    ioapic_fix_init_sipi_unsupported(&s->ioredtbl[index]);
+                }
                 ioapic_fix_edge_remote_irr(&s->ioredtbl[index]);
                 ioapic_service(s);
             }
diff --git a/hw/intc/ioapic_common.c b/hw/intc/ioapic_common.c
index b8ef7efbad..018bacbf96 100644
--- a/hw/intc/ioapic_common.c
+++ b/hw/intc/ioapic_common.c
@@ -185,6 +185,23 @@  static void ioapic_common_set_smi_unsupported(Object *obj, bool value,
     s->smi_unsupported = value;
 }
 
+static bool ioapic_common_get_init_sipi_unsupported(Object *obj, Error **errp)
+{
+    IOAPICCommonState *s = IOAPIC_COMMON(obj);
+    return s->init_sipi_unsupported;
+}
+
+static void ioapic_common_set_init_sipi_unsupported(Object *obj, bool value,
+                                                       Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    IOAPICCommonState *s = IOAPIC_COMMON(obj);
+    /* only disabling before realize is allowed */
+    assert(!dev->realized);
+    assert(!s->init_sipi_unsupported);
+    s->init_sipi_unsupported = value;
+}
+
 static void ioapic_common_init(Object *obj)
 {
     object_property_add_bool(obj, "level_trigger_unsupported",
@@ -194,6 +211,10 @@  static void ioapic_common_init(Object *obj)
     object_property_add_bool(obj, "smi_unsupported",
                              ioapic_common_get_smi_unsupported,
                              ioapic_common_set_smi_unsupported);
+
+    object_property_add_bool(obj, "init_sipi_unsupported",
+                             ioapic_common_get_init_sipi_unsupported,
+                             ioapic_common_set_init_sipi_unsupported);
 }
 
 static void ioapic_common_realize(DeviceState *dev, Error **errp)
diff --git a/include/hw/i386/ioapic_internal.h b/include/hw/i386/ioapic_internal.h
index 46f22a4f85..634b97426d 100644
--- a/include/hw/i386/ioapic_internal.h
+++ b/include/hw/i386/ioapic_internal.h
@@ -105,6 +105,7 @@  struct IOAPICCommonState {
     Notifier machine_done;
     bool level_trigger_unsupported;
     bool smi_unsupported;
+    bool init_sipi_unsupported;
     uint8_t version;
     uint64_t irq_count[IOAPIC_NUM_PINS];
     int irq_level[IOAPIC_NUM_PINS];