aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSairaj Kodilkar <sarunkod@amd.com>2025-08-01 11:35:05 +0530
committerMichael S. Tsirkin <mst@redhat.com>2025-08-01 10:23:50 -0400
commit47d3b32d6fb1c6ec8afb78d12d2420dbbb4c3499 (patch)
tree5d1cb126c8b542073bab7ecfd56797d0fbc6063e
parenta7842d94067cddc80b47ac42fb6e49e2fc02a3c5 (diff)
downloadqemu-47d3b32d6fb1c6ec8afb78d12d2420dbbb4c3499.zip
qemu-47d3b32d6fb1c6ec8afb78d12d2420dbbb4c3499.tar.gz
qemu-47d3b32d6fb1c6ec8afb78d12d2420dbbb4c3499.tar.bz2
hw/i386/amd_iommu: Fix amdvi_write*()
amdvi_write*() function do not preserve the older values of W1C bits in the MMIO register. This results in all W1C bits set to 0, when guest tries to reset a single bit by writing 1 to it. Fix this by preserving W1C bits in the old value of the MMIO register. Fixes: d29a09ca68428 ("hw/i386: Introduce AMD IOMMU") Suggested-by: Ethan MILON <ethan.milon@eviden.com> Signed-off-by: Sairaj Kodilkar <sarunkod@amd.com> Message-Id: <20250801060507.3382-5-sarunkod@amd.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
-rw-r--r--hw/i386/amd_iommu.c21
1 files changed, 18 insertions, 3 deletions
diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index 7308611..c9c32cf 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -123,8 +123,13 @@ static void amdvi_writew(AMDVIState *s, hwaddr addr, uint16_t val)
uint16_t romask = lduw_le_p(&s->romask[addr]);
uint16_t w1cmask = lduw_le_p(&s->w1cmask[addr]);
uint16_t oldval = lduw_le_p(&s->mmior[addr]);
+
+ uint16_t oldval_preserved = oldval & (romask | w1cmask);
+ uint16_t newval_write = val & ~romask;
+ uint16_t newval_w1c_set = val & w1cmask;
+
stw_le_p(&s->mmior[addr],
- ((oldval & romask) | (val & ~romask)) & ~(val & w1cmask));
+ (oldval_preserved | newval_write) & ~newval_w1c_set);
}
static void amdvi_writel(AMDVIState *s, hwaddr addr, uint32_t val)
@@ -132,8 +137,13 @@ static void amdvi_writel(AMDVIState *s, hwaddr addr, uint32_t val)
uint32_t romask = ldl_le_p(&s->romask[addr]);
uint32_t w1cmask = ldl_le_p(&s->w1cmask[addr]);
uint32_t oldval = ldl_le_p(&s->mmior[addr]);
+
+ uint32_t oldval_preserved = oldval & (romask | w1cmask);
+ uint32_t newval_write = val & ~romask;
+ uint32_t newval_w1c_set = val & w1cmask;
+
stl_le_p(&s->mmior[addr],
- ((oldval & romask) | (val & ~romask)) & ~(val & w1cmask));
+ (oldval_preserved | newval_write) & ~newval_w1c_set);
}
static void amdvi_writeq(AMDVIState *s, hwaddr addr, uint64_t val)
@@ -141,8 +151,13 @@ static void amdvi_writeq(AMDVIState *s, hwaddr addr, uint64_t val)
uint64_t romask = ldq_le_p(&s->romask[addr]);
uint64_t w1cmask = ldq_le_p(&s->w1cmask[addr]);
uint64_t oldval = ldq_le_p(&s->mmior[addr]);
+
+ uint64_t oldval_preserved = oldval & (romask | w1cmask);
+ uint64_t newval_write = val & ~romask;
+ uint64_t newval_w1c_set = val & w1cmask;
+
stq_le_p(&s->mmior[addr],
- ((oldval & romask) | (val & ~romask)) & ~(val & w1cmask));
+ (oldval_preserved | newval_write) & ~newval_w1c_set);
}
/* OR a 64-bit register with a 64-bit value */