@samitouri / QOSamiQemu / commits / 5bebd769ec

amd_iommu: Decode IRTEs without bitfields

Interrupt remapping table entries are data stored in guest memory in little-endian format. Decoding them with bitfields depends on host bitfield layout and the value returned from dma_memory_read() is not portable to big-endian hosts. Replace the legacy and GA IRTE bitfield definitions with explicit FIELD() definitions. Convert the guest memory values returned from dma_memory_read() with le32_to_cpu() or le64_to_cpu(), then extract relevant fields using FIELD_EX32() or FIELD_EX64() as appropriate to match the IRTE format. Fixes: b44159fe0078 ("x86_iommu/amd: Add interrupt remap support when VAPIC is not enabled") Fixes: 135f866e609c ("x86_iommu/amd: Add interrupt remap support when VAPIC is enabled") Reported-by: Peter Maydell <peter.maydell@linaro.org> Suggested-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Alejandro Jimenez <alejandro.j.jimenez@oracle.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Message-ID: <20260630220806.1758748-5-alejandro.j.jimenez@oracle.com>

Alejandro Jimenez committed Jun 30, 2026 at 22:08 UTC 5bebd769ec33aaeafbdefa7aebc0ea016ba07f09
2 files changed +69 -73
hw/i386/amd_iommu.c
+69 -24
@@ -89,6 +89,11 @@ typedef struct AMDVIIOTLBKey {
89 uint16_t devid;
90 } AMDVIIOTLBKey;
91
92 +typedef struct AMDVIIrteGA {
93 + uint64_t ga_lo;
94 + uint64_t ga_hi;
95 +} AMDVIIrteGA;
96 +
97 /* XT IOMMU General Interrupt Control Register layout */
98 FIELD(AMDVI_XT_GEN_INTR, DEST_MODE, 2, 1)
99 FIELD(AMDVI_XT_GEN_INTR, DEST_LO, 8, 24)
@@ -96,6 +101,37 @@ FIELD(AMDVI_XT_GEN_INTR, VECTOR, 32, 8)
101 FIELD(AMDVI_XT_GEN_INTR, DELIVERY_MODE, 40, 1)
102 FIELD(AMDVI_XT_GEN_INTR, DEST_HI, 56, 8)
103
104 +/* Interrupt Remapping Table Fields Formats */
105 +
106 +/* Basic 32-bit IRTE layout (GAEn=0) */
107 +FIELD(AMDVI_IRTE, VALID, 0, 1)
108 +FIELD(AMDVI_IRTE, SUP_IOPF, 1, 1)
109 +FIELD(AMDVI_IRTE, INT_TYPE, 2, 3)
110 +FIELD(AMDVI_IRTE, RQ_EOI, 5, 1)
111 +FIELD(AMDVI_IRTE, DM, 6, 1)
112 +FIELD(AMDVI_IRTE, GUEST_MODE, 7, 1)
113 +FIELD(AMDVI_IRTE, DESTINATION, 8, 8)
114 +FIELD(AMDVI_IRTE, VECTOR, 16, 8)
115 +
116 +/* 128-bit IRTE layout (GAEn=1) */
117 +FIELD(AMDVI_IRTE_GA_LO, VALID, 0, 1)
118 +FIELD(AMDVI_IRTE_GA_LO, SUP_IOPF, 1, 1)
119 +FIELD(AMDVI_IRTE_GA_LO, INT_TYPE, 2, 3)
120 +FIELD(AMDVI_IRTE_GA_LO, RQ_EOI, 5, 1)
121 +FIELD(AMDVI_IRTE_GA_LO, DM, 6, 1)
122 +FIELD(AMDVI_IRTE_GA_LO, GUEST_MODE, 7, 1)
123 +/*
124 + * In the 128-bit IRTE format, XT mode uses IRTE_GA_LOW.Destination[23:0]
125 + * together with IRTE_GA_HI.DestinationHi[7:0] to construct a 32-bit x2APIC
126 + * destination.
127 + * Without XTEn (i.e. when x2APIC support is not enabled), only
128 + * IRTE_GA_LOW.Destination[7:0] is used.
129 + */
130 +FIELD(AMDVI_IRTE_GA_LO, DESTINATION, 8, 24)
131 +
132 +FIELD(AMDVI_IRTE_GA_HI, VECTOR, 0, 8)
133 +FIELD(AMDVI_IRTE_GA_HI, DESTINATION_HI, 56, 8)
134 +
135 uint64_t amdvi_extended_feature_register(AMDVIState *s)
136 {
137 uint64_t feature = AMDVI_DEFAULT_EXT_FEATURES;
@@ -1983,7 +2019,7 @@ static IOMMUTLBEntry amdvi_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
2019 }
2020
2021 static int amdvi_get_irte(AMDVIState *s, MSIMessage *origin, uint64_t *dte,
1986 - union irte *irte, uint16_t devid)
2022 + uint32_t *irte, uint16_t devid)
2023 {
2024 uint64_t irte_root, offset;
2025
@@ -1998,7 +2034,8 @@ static int amdvi_get_irte(AMDVIState *s, MSIMessage *origin, uint64_t *dte,
2034 return -AMDVI_IR_GET_IRTE;
2035 }
2036
2001 - trace_amdvi_ir_irte_val(irte->val);
2037 + *irte = le32_to_cpu(*irte);
2038 + trace_amdvi_ir_irte_val(*irte);
2039
2040 return 0;
2041 }
@@ -2010,8 +2047,9 @@ static int amdvi_int_remap_legacy(AMDVIState *iommu,
2047 X86IOMMUIrq *irq,
2048 uint16_t sid)
2049 {
2050 + uint8_t int_type;
2051 + uint32_t irte;
2052 int ret;
2014 - union irte irte;
2053
2054 /* get interrupt remapping table */
2055 ret = amdvi_get_irte(iommu, origin, dte, &irte, sid);
@@ -2019,32 +2057,33 @@ static int amdvi_int_remap_legacy(AMDVIState *iommu,
2057 return ret;
2058 }
2059
2022 - if (!irte.fields.valid) {
2060 + if (!FIELD_EX32(irte, AMDVI_IRTE, VALID)) {
2061 trace_amdvi_ir_target_abort("RemapEn is disabled");
2062 return -AMDVI_IR_TARGET_ABORT;
2063 }
2064
2027 - if (irte.fields.guest_mode) {
2065 + if (FIELD_EX32(irte, AMDVI_IRTE, GUEST_MODE)) {
2066 error_report_once("guest mode is not zero");
2067 return -AMDVI_IR_ERR;
2068 }
2069
2032 - if (irte.fields.int_type > AMDVI_IOAPIC_INT_TYPE_ARBITRATED) {
2070 + int_type = FIELD_EX32(irte, AMDVI_IRTE, INT_TYPE);
2071 + if (int_type > AMDVI_IOAPIC_INT_TYPE_ARBITRATED) {
2072 error_report_once("reserved int_type");
2073 return -AMDVI_IR_ERR;
2074 }
2075
2037 - irq->delivery_mode = irte.fields.int_type;
2038 - irq->vector = irte.fields.vector;
2039 - irq->dest_mode = irte.fields.dm;
2040 - irq->redir_hint = irte.fields.rq_eoi;
2041 - irq->dest = irte.fields.destination;
2076 + irq->delivery_mode = int_type;
2077 + irq->vector = FIELD_EX32(irte, AMDVI_IRTE, VECTOR);
2078 + irq->dest_mode = FIELD_EX32(irte, AMDVI_IRTE, DM);
2079 + irq->redir_hint = FIELD_EX32(irte, AMDVI_IRTE, RQ_EOI);
2080 + irq->dest = FIELD_EX32(irte, AMDVI_IRTE, DESTINATION);
2081
2082 return 0;
2083 }
2084
2085 static int amdvi_get_irte_ga(AMDVIState *s, MSIMessage *origin, uint64_t *dte,
2047 - struct irte_ga *irte, uint16_t devid)
2086 + AMDVIIrteGA *irte, uint16_t devid)
2087 {
2088 uint64_t irte_root, offset;
2089
@@ -2058,7 +2097,9 @@ static int amdvi_get_irte_ga(AMDVIState *s, MSIMessage *origin, uint64_t *dte,
2097 return -AMDVI_IR_GET_IRTE;
2098 }
2099
2061 - trace_amdvi_ir_irte_ga_val(irte->hi.val, irte->lo.val);
2100 + irte->ga_lo = le64_to_cpu(irte->ga_lo);
2101 + irte->ga_hi = le64_to_cpu(irte->ga_hi);
2102 + trace_amdvi_ir_irte_ga_val(irte->ga_hi, irte->ga_lo);
2103 return 0;
2104 }
2105
@@ -2069,8 +2110,9 @@ static int amdvi_int_remap_ga(AMDVIState *iommu,
2110 X86IOMMUIrq *irq,
2111 uint16_t sid)
2112 {
2113 + AMDVIIrteGA irte;
2114 + uint8_t int_type;
2115 int ret;
2073 - struct irte_ga irte;
2116
2117 /* get interrupt remapping table */
2118 ret = amdvi_get_irte_ga(iommu, origin, dte, &irte, sid);
@@ -2078,30 +2120,33 @@ static int amdvi_int_remap_ga(AMDVIState *iommu,
2120 return ret;
2121 }
2122
2081 - if (!irte.lo.fields_remap.valid) {
2123 + if (!FIELD_EX64(irte.ga_lo, AMDVI_IRTE_GA_LO, VALID)) {
2124 trace_amdvi_ir_target_abort("RemapEn is disabled");
2125 return -AMDVI_IR_TARGET_ABORT;
2126 }
2127
2086 - if (irte.lo.fields_remap.guest_mode) {
2128 + if (FIELD_EX64(irte.ga_lo, AMDVI_IRTE_GA_LO, GUEST_MODE)) {
2129 error_report_once("guest mode is not zero");
2130 return -AMDVI_IR_ERR;
2131 }
2132
2091 - if (irte.lo.fields_remap.int_type > AMDVI_IOAPIC_INT_TYPE_ARBITRATED) {
2133 + int_type = FIELD_EX64(irte.ga_lo, AMDVI_IRTE_GA_LO, INT_TYPE);
2134 + if (int_type > AMDVI_IOAPIC_INT_TYPE_ARBITRATED) {
2135 error_report_once("reserved int_type is set");
2136 return -AMDVI_IR_ERR;
2137 }
2138
2096 - irq->delivery_mode = irte.lo.fields_remap.int_type;
2097 - irq->vector = irte.hi.fields.vector;
2098 - irq->dest_mode = irte.lo.fields_remap.dm;
2099 - irq->redir_hint = irte.lo.fields_remap.rq_eoi;
2139 + irq->delivery_mode = int_type;
2140 + irq->vector = FIELD_EX64(irte.ga_hi, AMDVI_IRTE_GA_HI, VECTOR);
2141 + irq->dest_mode = FIELD_EX64(irte.ga_lo, AMDVI_IRTE_GA_LO, DM);
2142 + irq->redir_hint = FIELD_EX64(irte.ga_lo, AMDVI_IRTE_GA_LO, RQ_EOI);
2143 if (iommu->xten) {
2101 - irq->dest = irte.lo.fields_remap.destination |
2102 - (irte.hi.fields.destination_hi << 24);
2144 + irq->dest = FIELD_EX64(irte.ga_lo, AMDVI_IRTE_GA_LO, DESTINATION) |
2145 + (FIELD_EX64(irte.ga_hi, AMDVI_IRTE_GA_HI, DESTINATION_HI)
2146 + << 24);
2147 } else {
2104 - irq->dest = irte.lo.fields_remap.destination & 0xff;
2148 + irq->dest = FIELD_EX64(irte.ga_lo, AMDVI_IRTE_GA_LO, DESTINATION) &
2149 + 0xff;
2150 }
2151
2152 return 0;
hw/i386/amd_iommu.h
-49
@@ -291,55 +291,6 @@
291 #define AMDVI_DEV_LINT0_PASS_MASK (1ULL << 62)
292 #define AMDVI_DEV_LINT1_PASS_MASK (1ULL << 63)
293
294 -/* Interrupt remapping table fields (Guest VAPIC not enabled) */
295 -union irte {
296 - uint32_t val;
297 - struct {
298 - uint32_t valid:1,
299 - no_fault:1,
300 - int_type:3,
301 - rq_eoi:1,
302 - dm:1,
303 - guest_mode:1,
304 - destination:8,
305 - vector:8,
306 - rsvd:8;
307 - } fields;
308 -};
309 -
310 -/* Interrupt remapping table fields (Guest VAPIC is enabled) */
311 -union irte_ga_lo {
312 - uint64_t val;
313 -
314 - /* For int remapping */
315 - struct {
316 - uint64_t valid:1,
317 - no_fault:1,
318 - /* ------ */
319 - int_type:3,
320 - rq_eoi:1,
321 - dm:1,
322 - /* ------ */
323 - guest_mode:1,
324 - destination:24,
325 - rsvd_1:32;
326 - } fields_remap;
327 -};
328 -
329 -union irte_ga_hi {
330 - uint64_t val;
331 - struct {
332 - uint64_t vector:8,
333 - rsvd_2:48,
334 - destination_hi:8;
335 - } fields;
336 -};
337 -
338 -struct irte_ga {
339 - union irte_ga_lo lo;
340 - union irte_ga_hi hi;
341 -};
342 -
294 #define TYPE_AMD_IOMMU_DEVICE "amd-iommu"
295 OBJECT_DECLARE_SIMPLE_TYPE(AMDVIState, AMD_IOMMU_DEVICE)
296