When MMIO 0x18[IntCapXTEn]=1, interrupts originating from the IOMMU itself are
sent based on the programming in XT IOMMU Interrupt Control Registers in MMIO
0x170-0x180 instead of the programming in the IOMMU's MSI capability registers.
The guest programs these registers with appropriate vector and destination
ID instead of writing to PCI MSI capability.
Current AMD vIOMMU is capable of generating interrupts only through PCI
MSI capability and does not care about xt mode. Because of this AMD
vIOMMU cannot generate event log interrupts using XT event log register
(0x170) when the guest has enabled xt mode.
Introduce a new flag "intcapxten" which is set when guest writes control
register [IntCapXTEn] (bit 51) and use vector and destination field in
the XT MMIO register (0x170) to support XT mode.
Signed-off-by: Sairaj Kodilkar <sarunkod@amd.com>
Reviewed-by: Vasant Hegde <vasant.hegde@amd.com>
---
hw/i386/amd_iommu.c | 43 +++++++++++++++++++++++++++++++++++++------
hw/i386/amd_iommu.h | 17 +++++++++++++++++
hw/i386/trace-events | 1 +
3 files changed, 55 insertions(+), 6 deletions(-)
diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index 850d3920a76d..742ef5d42561 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -194,18 +194,38 @@ static void amdvi_assign_andq(AMDVIState *s, hwaddr addr, uint64_t val)
amdvi_writeq_raw(s, addr, amdvi_readq(s, addr) & val);
}
+static void amdvi_build_xt_msi_msg(AMDVIState *s, MSIMessage *msg)
+{
+ union mmio_xt_intr xt_reg;
+ struct X86IOMMUIrq irq;
+
+ xt_reg.val = amdvi_readq(s, AMDVI_MMIO_XT_GEN_INTR);
+
+ irq.vector = xt_reg.vector;
+ irq.delivery_mode = xt_reg.delivery_mode;
+ irq.dest_mode = xt_reg.destination_mode;
+ irq.dest = (xt_reg.destination_hi << 24) | xt_reg.destination_lo;
+ irq.trigger_mode = 0;
+ irq.redir_hint = 0;
+
+ x86_iommu_irq_to_msi_message(&irq, msg);
+}
+
static void amdvi_generate_msi_interrupt(AMDVIState *s)
{
MSIMessage msg = {};
- MemTxAttrs attrs = {
- .requester_id = pci_requester_id(&s->pci->dev)
- };
- if (msi_enabled(&s->pci->dev)) {
+ if (s->intcapxten) {
+ trace_amdvi_generate_msi_interrupt("XT GEN");
+ amdvi_build_xt_msi_msg(s, &msg);
+ } else if (msi_enabled(&s->pci->dev)) {
+ trace_amdvi_generate_msi_interrupt("MSI");
msg = msi_get_message(&s->pci->dev, 0);
- address_space_stl_le(&address_space_memory, msg.address, msg.data,
- attrs, NULL);
+ } else {
+ trace_amdvi_generate_msi_interrupt("NO MSI");
+ return;
}
+ apic_get_class(NULL)->send_msi(&msg);
}
static uint32_t get_next_eventlog_entry(AMDVIState *s)
@@ -1483,6 +1503,7 @@ const char *amdvi_mmio_get_name(hwaddr addr)
MMIO_REG_TO_STRING(AMDVI_MMIO_PPR_BASE);
MMIO_REG_TO_STRING(AMDVI_MMIO_PPR_HEAD);
MMIO_REG_TO_STRING(AMDVI_MMIO_PPR_TAIL);
+ MMIO_REG_TO_STRING(AMDVI_MMIO_XT_GEN_INTR);
default:
return "UNHANDLED";
}
@@ -1537,6 +1558,11 @@ static void amdvi_handle_control_write(AMDVIState *s)
s->ga_enabled = !!(control & AMDVI_MMIO_CONTROL_GAEN);
s->xten = !!(control & AMDVI_MMIO_CONTROL_XTEN) && s->xtsup &&
s->ga_enabled;
+ /*
+ * intcapxten does not depend on xten flag because IOMMU spec does not
+ * specify any dependency between these two flags
+ */
+ s->intcapxten = !!(control & AMDVI_MMIO_CONTROL_INTCAPXTEN) && s->xtsup;
/* update the flags depending on the control register */
if (s->cmdbuf_enabled) {
@@ -1743,6 +1769,9 @@ static void amdvi_mmio_write(void *opaque, hwaddr addr, uint64_t val,
case AMDVI_MMIO_STATUS:
amdvi_mmio_reg_write(s, size, val, addr);
break;
+ case AMDVI_MMIO_XT_GEN_INTR:
+ amdvi_mmio_reg_write(s, size, val, addr);
+ break;
}
}
@@ -2393,6 +2422,7 @@ static void amdvi_init(AMDVIState *s)
s->enabled = false;
s->cmdbuf_enabled = false;
s->xten = false;
+ s->intcapxten = false;
/* reset MMIO */
memset(s->mmior, 0, AMDVI_MMIO_SIZE);
@@ -2463,6 +2493,7 @@ static const VMStateDescription vmstate_xt = {
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_BOOL(xten, AMDVIState),
+ VMSTATE_BOOL(intcapxten, AMDVIState),
VMSTATE_END_OF_LIST()
}
};
diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h
index e9401f3a5c27..886814770276 100644
--- a/hw/i386/amd_iommu.h
+++ b/hw/i386/amd_iommu.h
@@ -57,6 +57,7 @@
#define AMDVI_MMIO_EXCL_BASE 0x0020
#define AMDVI_MMIO_EXCL_LIMIT 0x0028
#define AMDVI_MMIO_EXT_FEATURES 0x0030
+#define AMDVI_MMIO_XT_GEN_INTR 0x0170
#define AMDVI_MMIO_COMMAND_HEAD 0x2000
#define AMDVI_MMIO_COMMAND_TAIL 0x2008
#define AMDVI_MMIO_EVENT_HEAD 0x2010
@@ -107,6 +108,7 @@
#define AMDVI_MMIO_CONTROL_CMDBUFLEN (1ULL << 12)
#define AMDVI_MMIO_CONTROL_GAEN (1ULL << 17)
#define AMDVI_MMIO_CONTROL_XTEN (1ULL << 50)
+#define AMDVI_MMIO_CONTROL_INTCAPXTEN (1ULL << 51)
/* MMIO status register bits */
#define AMDVI_MMIO_STATUS_CMDBUF_RUN (1 << 4)
@@ -343,6 +345,20 @@ struct irte_ga {
union irte_ga_hi hi;
};
+union mmio_xt_intr {
+ uint64_t val;
+ struct {
+ uint64_t rsvd_1:2,
+ destination_mode:1,
+ rsvd_2:5,
+ destination_lo:24,
+ vector:8,
+ delivery_mode:1,
+ rsvd_3:15,
+ destination_hi:8;
+ };
+};
+
#define TYPE_AMD_IOMMU_DEVICE "amd-iommu"
OBJECT_DECLARE_SIMPLE_TYPE(AMDVIState, AMD_IOMMU_DEVICE)
@@ -421,6 +437,7 @@ struct AMDVIState {
bool ga_enabled;
bool xtsup; /* xtsup=on command line */
bool xten; /* guest controlled, x2apic mode enabled */
+ bool intcapxten; /* guest controlled, IOMMU x2apic interrupts enabled */
/* DMA address translation */
bool dma_remap;
diff --git a/hw/i386/trace-events b/hw/i386/trace-events
index 5fa5e93b68dc..a1dfade20f18 100644
--- a/hw/i386/trace-events
+++ b/hw/i386/trace-events
@@ -118,6 +118,7 @@ amdvi_ir_intctl(uint8_t val) "int_ctl 0x%"PRIx8
amdvi_ir_target_abort(const char *str) "%s"
amdvi_ir_delivery_mode(const char *str) "%s"
amdvi_ir_irte_ga_val(uint64_t hi, uint64_t lo) "hi 0x%"PRIx64" lo 0x%"PRIx64
+amdvi_generate_msi_interrupt(const char *str) "Mode: %s"
# vmport.c
vmport_register(unsigned char command, void *func, void *opaque) "command: 0x%02x func: %p opaque: %p"
--
2.34.1
On 1/29/26 5:28 AM, Sairaj Kodilkar wrote:
> When MMIO 0x18[IntCapXTEn]=1, interrupts originating from the IOMMU itself are
> sent based on the programming in XT IOMMU Interrupt Control Registers in MMIO
> 0x170-0x180 instead of the programming in the IOMMU's MSI capability registers.
> The guest programs these registers with appropriate vector and destination
> ID instead of writing to PCI MSI capability.
>
> Current AMD vIOMMU is capable of generating interrupts only through PCI
> MSI capability and does not care about xt mode. Because of this AMD
> vIOMMU cannot generate event log interrupts using XT event log register
> (0x170) when the guest has enabled xt mode.
I see that you slightly modified this from the initial version, but I would
leave it as it was i.e.:
"Because of this AMD vIOMMU cannot generate event log interrupts when the
guest has enabled xt mode."
There is no "XT event log register (0x170)", it is the "MMIO Offset 0x170h
XT IOMMU General Interrupt Control Register" as you mention in the next
sentence.
>
> Introduce a new flag "intcapxten" which is set when guest writes control
> register [IntCapXTEn] (bit 51) and use vector and destination field in
> the XT MMIO register (0x170) to support XT mode.
>
> Signed-off-by: Sairaj Kodilkar <sarunkod@amd.com>
> Reviewed-by: Vasant Hegde <vasant.hegde@amd.com>
> ---
> hw/i386/amd_iommu.c | 43 +++++++++++++++++++++++++++++++++++++------
> hw/i386/amd_iommu.h | 17 +++++++++++++++++
> hw/i386/trace-events | 1 +
> 3 files changed, 55 insertions(+), 6 deletions(-)
>
> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
> index 850d3920a76d..742ef5d42561 100644
> --- a/hw/i386/amd_iommu.c
> +++ b/hw/i386/amd_iommu.c
> @@ -194,18 +194,38 @@ static void amdvi_assign_andq(AMDVIState *s, hwaddr addr, uint64_t val)
> amdvi_writeq_raw(s, addr, amdvi_readq(s, addr) & val);
> }
>
> +static void amdvi_build_xt_msi_msg(AMDVIState *s, MSIMessage *msg)
> +{
> + union mmio_xt_intr xt_reg;
> + struct X86IOMMUIrq irq;
> +
> + xt_reg.val = amdvi_readq(s, AMDVI_MMIO_XT_GEN_INTR);
> +
> + irq.vector = xt_reg.vector;
> + irq.delivery_mode = xt_reg.delivery_mode;
> + irq.dest_mode = xt_reg.destination_mode;
> + irq.dest = (xt_reg.destination_hi << 24) | xt_reg.destination_lo;
> + irq.trigger_mode = 0;
> + irq.redir_hint = 0;
> +
> + x86_iommu_irq_to_msi_message(&irq, msg);
> +}
> +
> static void amdvi_generate_msi_interrupt(AMDVIState *s)
> {
> MSIMessage msg = {};
> - MemTxAttrs attrs = {
> - .requester_id = pci_requester_id(&s->pci->dev)
> - };
>
> - if (msi_enabled(&s->pci->dev)) {
> + if (s->intcapxten) {
> + trace_amdvi_generate_msi_interrupt("XT GEN");
> + amdvi_build_xt_msi_msg(s, &msg);
> + } else if (msi_enabled(&s->pci->dev)) {
> + trace_amdvi_generate_msi_interrupt("MSI");
> msg = msi_get_message(&s->pci->dev, 0);
> - address_space_stl_le(&address_space_memory, msg.address, msg.data,
> - attrs, NULL);
> + } else {
> + trace_amdvi_generate_msi_interrupt("NO MSI");
> + return;
> }
> + apic_get_class(NULL)->send_msi(&msg);
> }
>
> static uint32_t get_next_eventlog_entry(AMDVIState *s)
> @@ -1483,6 +1503,7 @@ const char *amdvi_mmio_get_name(hwaddr addr)
> MMIO_REG_TO_STRING(AMDVI_MMIO_PPR_BASE);
> MMIO_REG_TO_STRING(AMDVI_MMIO_PPR_HEAD);
> MMIO_REG_TO_STRING(AMDVI_MMIO_PPR_TAIL);
> + MMIO_REG_TO_STRING(AMDVI_MMIO_XT_GEN_INTR);
> default:
> return "UNHANDLED";
> }
> @@ -1537,6 +1558,11 @@ static void amdvi_handle_control_write(AMDVIState *s)
> s->ga_enabled = !!(control & AMDVI_MMIO_CONTROL_GAEN);
> s->xten = !!(control & AMDVI_MMIO_CONTROL_XTEN) && s->xtsup &&
> s->ga_enabled;
> + /*
> + * intcapxten does not depend on xten flag because IOMMU spec does not
> + * specify any dependency between these two flags
> + */
I'd like to modify the comment to add more info/breadcrumbs e.g.:
"
IntCapXTEn controls whether IOMMU-originated interrupts are sent based on
the information in XT IOMMU Interrupt Control Registers rather than the
IOMMU’s MSI capability registers. Therefore it requires IOMMU x2APIC
support capabilities (i.e. XTSup=1), but it is independent of whether a
driver chooses to enable x2APIC mode for interrupt remapping (i.e. XTEn=1)
"
This conveys your reasoning for not linking intcapxten and xten, while also
giving the exact search terms to query the spec and find the relevant
sections. Any concerns with this?
Otherwise,
Reviewed-by: Alejandro Jimenez <alejandro.j.jimenez@oracle.com>
> + s->intcapxten = !!(control & AMDVI_MMIO_CONTROL_INTCAPXTEN) && s->xtsup;
>
> /* update the flags depending on the control register */
> if (s->cmdbuf_enabled) {
> @@ -1743,6 +1769,9 @@ static void amdvi_mmio_write(void *opaque, hwaddr addr, uint64_t val,
> case AMDVI_MMIO_STATUS:
> amdvi_mmio_reg_write(s, size, val, addr);
> break;
> + case AMDVI_MMIO_XT_GEN_INTR:
> + amdvi_mmio_reg_write(s, size, val, addr);
> + break;
> }
> }
>
> @@ -2393,6 +2422,7 @@ static void amdvi_init(AMDVIState *s)
> s->enabled = false;
> s->cmdbuf_enabled = false;
> s->xten = false;
> + s->intcapxten = false;
>
> /* reset MMIO */
> memset(s->mmior, 0, AMDVI_MMIO_SIZE);
> @@ -2463,6 +2493,7 @@ static const VMStateDescription vmstate_xt = {
> .minimum_version_id = 1,
> .fields = (VMStateField[]) {
> VMSTATE_BOOL(xten, AMDVIState),
> + VMSTATE_BOOL(intcapxten, AMDVIState),
> VMSTATE_END_OF_LIST()
> }
> };
> diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h
> index e9401f3a5c27..886814770276 100644
> --- a/hw/i386/amd_iommu.h
> +++ b/hw/i386/amd_iommu.h
> @@ -57,6 +57,7 @@
> #define AMDVI_MMIO_EXCL_BASE 0x0020
> #define AMDVI_MMIO_EXCL_LIMIT 0x0028
> #define AMDVI_MMIO_EXT_FEATURES 0x0030
> +#define AMDVI_MMIO_XT_GEN_INTR 0x0170
> #define AMDVI_MMIO_COMMAND_HEAD 0x2000
> #define AMDVI_MMIO_COMMAND_TAIL 0x2008
> #define AMDVI_MMIO_EVENT_HEAD 0x2010
> @@ -107,6 +108,7 @@
> #define AMDVI_MMIO_CONTROL_CMDBUFLEN (1ULL << 12)
> #define AMDVI_MMIO_CONTROL_GAEN (1ULL << 17)
> #define AMDVI_MMIO_CONTROL_XTEN (1ULL << 50)
> +#define AMDVI_MMIO_CONTROL_INTCAPXTEN (1ULL << 51)
>
> /* MMIO status register bits */
> #define AMDVI_MMIO_STATUS_CMDBUF_RUN (1 << 4)
> @@ -343,6 +345,20 @@ struct irte_ga {
> union irte_ga_hi hi;
> };
>
> +union mmio_xt_intr {
> + uint64_t val;
> + struct {
> + uint64_t rsvd_1:2,
> + destination_mode:1,
> + rsvd_2:5,
> + destination_lo:24,
> + vector:8,
> + delivery_mode:1,
> + rsvd_3:15,
> + destination_hi:8;
> + };
> +};
> +
> #define TYPE_AMD_IOMMU_DEVICE "amd-iommu"
> OBJECT_DECLARE_SIMPLE_TYPE(AMDVIState, AMD_IOMMU_DEVICE)
>
> @@ -421,6 +437,7 @@ struct AMDVIState {
> bool ga_enabled;
> bool xtsup; /* xtsup=on command line */
> bool xten; /* guest controlled, x2apic mode enabled */
> + bool intcapxten; /* guest controlled, IOMMU x2apic interrupts enabled */
>
> /* DMA address translation */
> bool dma_remap;
> diff --git a/hw/i386/trace-events b/hw/i386/trace-events
> index 5fa5e93b68dc..a1dfade20f18 100644
> --- a/hw/i386/trace-events
> +++ b/hw/i386/trace-events
> @@ -118,6 +118,7 @@ amdvi_ir_intctl(uint8_t val) "int_ctl 0x%"PRIx8
> amdvi_ir_target_abort(const char *str) "%s"
> amdvi_ir_delivery_mode(const char *str) "%s"
> amdvi_ir_irte_ga_val(uint64_t hi, uint64_t lo) "hi 0x%"PRIx64" lo 0x%"PRIx64
> +amdvi_generate_msi_interrupt(const char *str) "Mode: %s"
>
> # vmport.c
> vmport_register(unsigned char command, void *func, void *opaque) "command: 0x%02x func: %p opaque: %p"
On 2/3/2026 4:59 AM, Alejandro Jimenez wrote:
>
> On 1/29/26 5:28 AM, Sairaj Kodilkar wrote:
>> When MMIO 0x18[IntCapXTEn]=1, interrupts originating from the IOMMU itself are
>> sent based on the programming in XT IOMMU Interrupt Control Registers in MMIO
>> 0x170-0x180 instead of the programming in the IOMMU's MSI capability registers.
>> The guest programs these registers with appropriate vector and destination
>> ID instead of writing to PCI MSI capability.
>>
>> Current AMD vIOMMU is capable of generating interrupts only through PCI
>> MSI capability and does not care about xt mode. Because of this AMD
>> vIOMMU cannot generate event log interrupts using XT event log register
>> (0x170) when the guest has enabled xt mode.
> I see that you slightly modified this from the initial version, but I would
> leave it as it was i.e.:
>
> "Because of this AMD vIOMMU cannot generate event log interrupts when the
> guest has enabled xt mode."
>
> There is no "XT event log register (0x170)", it is the "MMIO Offset 0x170h
> XT IOMMU General Interrupt Control Register" as you mention in the next
> sentence.
Sure
>> Introduce a new flag "intcapxten" which is set when guest writes control
>> register [IntCapXTEn] (bit 51) and use vector and destination field in
>> the XT MMIO register (0x170) to support XT mode.
>>
>> Signed-off-by: Sairaj Kodilkar <sarunkod@amd.com>
>> Reviewed-by: Vasant Hegde <vasant.hegde@amd.com>
>> ---
>> hw/i386/amd_iommu.c | 43 +++++++++++++++++++++++++++++++++++++------
>> hw/i386/amd_iommu.h | 17 +++++++++++++++++
>> hw/i386/trace-events | 1 +
>> 3 files changed, 55 insertions(+), 6 deletions(-)
>>
>> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
>> index 850d3920a76d..742ef5d42561 100644
>> --- a/hw/i386/amd_iommu.c
>> +++ b/hw/i386/amd_iommu.c
>> @@ -194,18 +194,38 @@ static void amdvi_assign_andq(AMDVIState *s, hwaddr addr, uint64_t val)
>> amdvi_writeq_raw(s, addr, amdvi_readq(s, addr) & val);
>> }
>>
>> +static void amdvi_build_xt_msi_msg(AMDVIState *s, MSIMessage *msg)
>> +{
>> + union mmio_xt_intr xt_reg;
>> + struct X86IOMMUIrq irq;
>> +
>> + xt_reg.val = amdvi_readq(s, AMDVI_MMIO_XT_GEN_INTR);
>> +
>> + irq.vector = xt_reg.vector;
>> + irq.delivery_mode = xt_reg.delivery_mode;
>> + irq.dest_mode = xt_reg.destination_mode;
>> + irq.dest = (xt_reg.destination_hi << 24) | xt_reg.destination_lo;
>> + irq.trigger_mode = 0;
>> + irq.redir_hint = 0;
>> +
>> + x86_iommu_irq_to_msi_message(&irq, msg);
>> +}
>> +
>> static void amdvi_generate_msi_interrupt(AMDVIState *s)
>> {
>> MSIMessage msg = {};
>> - MemTxAttrs attrs = {
>> - .requester_id = pci_requester_id(&s->pci->dev)
>> - };
>>
>> - if (msi_enabled(&s->pci->dev)) {
>> + if (s->intcapxten) {
>> + trace_amdvi_generate_msi_interrupt("XT GEN");
>> + amdvi_build_xt_msi_msg(s, &msg);
>> + } else if (msi_enabled(&s->pci->dev)) {
>> + trace_amdvi_generate_msi_interrupt("MSI");
>> msg = msi_get_message(&s->pci->dev, 0);
>> - address_space_stl_le(&address_space_memory, msg.address, msg.data,
>> - attrs, NULL);
>> + } else {
>> + trace_amdvi_generate_msi_interrupt("NO MSI");
>> + return;
>> }
>> + apic_get_class(NULL)->send_msi(&msg);
>> }
>>
>> static uint32_t get_next_eventlog_entry(AMDVIState *s)
>> @@ -1483,6 +1503,7 @@ const char *amdvi_mmio_get_name(hwaddr addr)
>> MMIO_REG_TO_STRING(AMDVI_MMIO_PPR_BASE);
>> MMIO_REG_TO_STRING(AMDVI_MMIO_PPR_HEAD);
>> MMIO_REG_TO_STRING(AMDVI_MMIO_PPR_TAIL);
>> + MMIO_REG_TO_STRING(AMDVI_MMIO_XT_GEN_INTR);
>> default:
>> return "UNHANDLED";
>> }
>> @@ -1537,6 +1558,11 @@ static void amdvi_handle_control_write(AMDVIState *s)
>> s->ga_enabled = !!(control & AMDVI_MMIO_CONTROL_GAEN);
>> s->xten = !!(control & AMDVI_MMIO_CONTROL_XTEN) && s->xtsup &&
>> s->ga_enabled;
>> + /*
>> + * intcapxten does not depend on xten flag because IOMMU spec does not
>> + * specify any dependency between these two flags
>> + */
> I'd like to modify the comment to add more info/breadcrumbs e.g.:
>
> "
> IntCapXTEn controls whether IOMMU-originated interrupts are sent based on
> the information in XT IOMMU Interrupt Control Registers rather than the
> IOMMU’s MSI capability registers. Therefore it requires IOMMU x2APIC
> support capabilities (i.e. XTSup=1), but it is independent of whether a
> driver chooses to enable x2APIC mode for interrupt remapping (i.e. XTEn=1)
> "
>
> This conveys your reasoning for not linking intcapxten and xten, while also
> giving the exact search terms to query the spec and find the relevant
> sections. Any concerns with this?
>
> Otherwise,
>
> Reviewed-by: Alejandro Jimenez <alejandro.j.jimenez@oracle.com>
Hi
Thanks for suggestion. I will expand the comment.
Also I hope the confusion around RH bit is clear now
Thanks
Sairaj
>> + s->intcapxten = !!(control & AMDVI_MMIO_CONTROL_INTCAPXTEN) && s->xtsup;
>>
>> /* update the flags depending on the control register */
>> if (s->cmdbuf_enabled) {
>> @@ -1743,6 +1769,9 @@ static void amdvi_mmio_write(void *opaque, hwaddr addr, uint64_t val,
>> case AMDVI_MMIO_STATUS:
>> amdvi_mmio_reg_write(s, size, val, addr);
>> break;
>> + case AMDVI_MMIO_XT_GEN_INTR:
>> + amdvi_mmio_reg_write(s, size, val, addr);
>> + break;
>> }
>> }
>>
>> @@ -2393,6 +2422,7 @@ static void amdvi_init(AMDVIState *s)
>> s->enabled = false;
>> s->cmdbuf_enabled = false;
>> s->xten = false;
>> + s->intcapxten = false;
>>
>> /* reset MMIO */
>> memset(s->mmior, 0, AMDVI_MMIO_SIZE);
>> @@ -2463,6 +2493,7 @@ static const VMStateDescription vmstate_xt = {
>> .minimum_version_id = 1,
>> .fields = (VMStateField[]) {
>> VMSTATE_BOOL(xten, AMDVIState),
>> + VMSTATE_BOOL(intcapxten, AMDVIState),
>> VMSTATE_END_OF_LIST()
>> }
>> };
>> diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h
>> index e9401f3a5c27..886814770276 100644
>> --- a/hw/i386/amd_iommu.h
>> +++ b/hw/i386/amd_iommu.h
>> @@ -57,6 +57,7 @@
>> #define AMDVI_MMIO_EXCL_BASE 0x0020
>> #define AMDVI_MMIO_EXCL_LIMIT 0x0028
>> #define AMDVI_MMIO_EXT_FEATURES 0x0030
>> +#define AMDVI_MMIO_XT_GEN_INTR 0x0170
>> #define AMDVI_MMIO_COMMAND_HEAD 0x2000
>> #define AMDVI_MMIO_COMMAND_TAIL 0x2008
>> #define AMDVI_MMIO_EVENT_HEAD 0x2010
>> @@ -107,6 +108,7 @@
>> #define AMDVI_MMIO_CONTROL_CMDBUFLEN (1ULL << 12)
>> #define AMDVI_MMIO_CONTROL_GAEN (1ULL << 17)
>> #define AMDVI_MMIO_CONTROL_XTEN (1ULL << 50)
>> +#define AMDVI_MMIO_CONTROL_INTCAPXTEN (1ULL << 51)
>>
>> /* MMIO status register bits */
>> #define AMDVI_MMIO_STATUS_CMDBUF_RUN (1 << 4)
>> @@ -343,6 +345,20 @@ struct irte_ga {
>> union irte_ga_hi hi;
>> };
>>
>> +union mmio_xt_intr {
>> + uint64_t val;
>> + struct {
>> + uint64_t rsvd_1:2,
>> + destination_mode:1,
>> + rsvd_2:5,
>> + destination_lo:24,
>> + vector:8,
>> + delivery_mode:1,
>> + rsvd_3:15,
>> + destination_hi:8;
>> + };
>> +};
>> +
>> #define TYPE_AMD_IOMMU_DEVICE "amd-iommu"
>> OBJECT_DECLARE_SIMPLE_TYPE(AMDVIState, AMD_IOMMU_DEVICE)
>>
>> @@ -421,6 +437,7 @@ struct AMDVIState {
>> bool ga_enabled;
>> bool xtsup; /* xtsup=on command line */
>> bool xten; /* guest controlled, x2apic mode enabled */
>> + bool intcapxten; /* guest controlled, IOMMU x2apic interrupts enabled */
>>
>> /* DMA address translation */
>> bool dma_remap;
>> diff --git a/hw/i386/trace-events b/hw/i386/trace-events
>> index 5fa5e93b68dc..a1dfade20f18 100644
>> --- a/hw/i386/trace-events
>> +++ b/hw/i386/trace-events
>> @@ -118,6 +118,7 @@ amdvi_ir_intctl(uint8_t val) "int_ctl 0x%"PRIx8
>> amdvi_ir_target_abort(const char *str) "%s"
>> amdvi_ir_delivery_mode(const char *str) "%s"
>> amdvi_ir_irte_ga_val(uint64_t hi, uint64_t lo) "hi 0x%"PRIx64" lo 0x%"PRIx64
>> +amdvi_generate_msi_interrupt(const char *str) "Mode: %s"
>>
>> # vmport.c
>> vmport_register(unsigned char command, void *func, void *opaque) "command: 0x%02x func: %p opaque: %p"
© 2016 - 2026 Red Hat, Inc.