[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC PATCH v2 35/44] ioapic: add property to disable level interrupt
From: |
isaku . yamahata |
Subject: |
[RFC PATCH v2 35/44] ioapic: add property to disable level interrupt |
Date: |
Wed, 7 Jul 2021 17:55:05 -0700 |
From: Isaku Yamahata <isaku.yamahata@intel.com>
According to TDX module spec version 344425-002US [1], VMM can inject
virtual interrupt only via posted interrupt and VMM can't get TDEXIT on
guest EOI to virtual x2APIC. Because posted interrupt is edge-trigger and
VMM needs to hook guest EOI to re-inject level-triggered interrupt if the
level still active, level-trigger isn't supported for TD Guest VM.
Prevent trigger mode from setting to be level trigger with warning.
Without this guard, qemu can result in unexpected behavior later.
[1]
https://software.intel.com/content/dam/develop/external/us/en/documents/tdx-module-1eas-v0.85.039.pdf
Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
---
hw/intc/ioapic.c | 20 ++++++++++++++++++++
hw/intc/ioapic_common.c | 27 +++++++++++++++++++++++++++
include/hw/i386/ioapic_internal.h | 1 +
3 files changed, 48 insertions(+)
diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
index 264262959d..6d61744961 100644
--- a/hw/intc/ioapic.c
+++ b/hw/intc/ioapic.c
@@ -364,6 +364,23 @@ ioapic_fix_edge_remote_irr(uint64_t *entry)
}
}
+static inline void
+ioapic_fix_level_trigger_unsupported(uint64_t *entry)
+{
+ if ((*entry & IOAPIC_LVT_TRIGGER_MODE) !=
+ IOAPIC_TRIGGER_EDGE << IOAPIC_LVT_TRIGGER_MODE_SHIFT) {
+ /*
+ * ignore a request for level trigger because
+ * level trigger requires eoi intercept to re-inject
+ * interrupt when the level is still active.
+ */
+ warn_report_once("attempting to set level-trigger mode "
+ "while eoi intercept isn't supported");
+ *entry &= ~IOAPIC_LVT_TRIGGER_MODE;
+ *entry |= IOAPIC_TRIGGER_EDGE << IOAPIC_LVT_TRIGGER_MODE_SHIFT;
+ }
+}
+
static void
ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
unsigned int size)
@@ -404,6 +421,9 @@ ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
s->ioredtbl[index] &= IOAPIC_RW_BITS;
s->ioredtbl[index] |= ro_bits;
s->irq_eoi[index] = 0;
+ if (s->level_trigger_unsupported) {
+ ioapic_fix_level_trigger_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 3cccfc1556..07ee142470 100644
--- a/hw/intc/ioapic_common.c
+++ b/hw/intc/ioapic_common.c
@@ -150,6 +150,32 @@ static int ioapic_dispatch_post_load(void *opaque, int
version_id)
return 0;
}
+static bool ioapic_common_get_level_trigger_unsupported(Object *obj,
+ Error **errp)
+{
+ IOAPICCommonState *s = IOAPIC_COMMON(obj);
+ return s->level_trigger_unsupported;
+}
+
+static void ioapic_common_set_level_trigger_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->level_trigger_unsupported);
+ s->level_trigger_unsupported = value;
+}
+
+static void ioapic_common_init(Object *obj)
+{
+ object_property_add_bool(obj, "level_trigger_unsupported",
+ ioapic_common_get_level_trigger_unsupported,
+ ioapic_common_set_level_trigger_unsupported);
+
+}
+
static void ioapic_common_realize(DeviceState *dev, Error **errp)
{
IOAPICCommonState *s = IOAPIC_COMMON(dev);
@@ -207,6 +233,7 @@ static const TypeInfo ioapic_common_type = {
.name = TYPE_IOAPIC_COMMON,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(IOAPICCommonState),
+ .instance_init = ioapic_common_init,
.class_size = sizeof(IOAPICCommonClass),
.class_init = ioapic_common_class_init,
.abstract = true,
diff --git a/include/hw/i386/ioapic_internal.h
b/include/hw/i386/ioapic_internal.h
index 021e715f11..20f2fc7897 100644
--- a/include/hw/i386/ioapic_internal.h
+++ b/include/hw/i386/ioapic_internal.h
@@ -103,6 +103,7 @@ struct IOAPICCommonState {
uint32_t irr;
uint64_t ioredtbl[IOAPIC_NUM_PINS];
Notifier machine_done;
+ bool level_trigger_unsupported;
uint8_t version;
uint64_t irq_count[IOAPIC_NUM_PINS];
int irq_level[IOAPIC_NUM_PINS];
--
2.25.1
- Re: [RFC PATCH v2 01/44] target/i386: Expose x86_cpu_get_supported_feature_word() for TDX, (continued)
- [RFC PATCH v2 13/44] i386/tdx: Frame in tdx_get_supported_cpuid with KVM_TDX_CAPABILITIES, isaku . yamahata, 2021/07/07
- [RFC PATCH v2 33/44] qmp: add query-tdx-capabilities query-tdx command, isaku . yamahata, 2021/07/07
- [RFC PATCH v2 10/44] hw/i386: Initialize TDX via KVM ioctl() when kvm_type is TDX, isaku . yamahata, 2021/07/07
- [RFC PATCH v2 09/44] target/i386: kvm: don't synchronize guest tsc for TD guest, isaku . yamahata, 2021/07/07
- [RFC PATCH v2 32/44] tdx: add kvm_tdx_enabled() accessor for later use, isaku . yamahata, 2021/07/07
- [RFC PATCH v2 12/44] target/i386/tdx: Finalize the TD's measurement when machine is done, isaku . yamahata, 2021/07/07
- [RFC PATCH v2 35/44] ioapic: add property to disable level interrupt,
isaku . yamahata <=
- [RFC PATCH v2 38/44] hw/i386: plug eoi_intercept_unsupported to ioapic, isaku . yamahata, 2021/07/07
- [RFC PATCH v2 04/44] vl: Introduce machine_init_done_late notifier, isaku . yamahata, 2021/07/07
- [RFC PATCH v2 08/44] i386/kvm: Skip KVM_X86_SETUP_MCE for TDX guests, isaku . yamahata, 2021/07/07
- [RFC PATCH v2 17/44] i386/tdx: Add definitions for TDVF metadata, isaku . yamahata, 2021/07/07
- [RFC PATCH v2 11/44] i386/tdx: Implement user specified tsc frequency, isaku . yamahata, 2021/07/07
- [RFC PATCH v2 36/44] hw/i386: add eoi_intercept_unsupported member to X86MachineState, isaku . yamahata, 2021/07/07
- [RFC PATCH v2 07/44] i386/kvm: Squash getting/putting guest state for TDX VMs, isaku . yamahata, 2021/07/07
- [RFC PATCH v2 14/44] i386/tdx: Frame in the call for KVM_TDX_INIT_VCPU, isaku . yamahata, 2021/07/07