@samitouri / QOSamiQemu / commits / f9b16f7915

hw/dma/pl080: Ignore bottom 2 bits of LLI register

The PL080 channel LLI (linked list item) register has bits [31:2] of the address of the next LLI in bits [31:2], with bit [1] reserved and bits [0] the AHB master select. We were incorrectly using the whole register value as the address, which meant that if the guest programmed something into the AHB master select bit we would use an incorrect address, and read incorrect data from memory. The following reproducer creates a setup which has bit 0 set in an LLI value: Configuration ../configure --target-list=arm-softmmu --enable-debug Reproducer ./qemu-system-arm -M versatilepb -m 128M -nographic -S \ -device loader,addr=0x00002000,data=0x00000004,data-len=4 \ -device loader,addr=0x00002004,data=0x00001004,data-len=4 \ -device loader,addr=0x00002008,data=0x00000000,data-len=4 \ -device loader,addr=0x0000200c,data=0x9e4bf001,data-len=4 \ -device loader,addr=0x00000000,data=0x44332211,data-len=4 \ -device loader,addr=0x00000004,data=0x88776655,data-len=4 \ -device loader,addr=0x00001000,data=0x00000000,data-len=4 \ -device loader,addr=0x00001004,data=0x00000000,data-len=4 \ -device loader,addr=0x10130030,data=0x00000001,data-len=4 \ -device loader,addr=0x10130100,data=0x00000000,data-len=4 \ -device loader,addr=0x10130104,data=0x00001000,data-len=4 \ -device loader,addr=0x10130108,data=0x00002001,data-len=4 \ -device loader,addr=0x1013010C,data=0x1e4bf001,data-len=4 \ -device loader,addr=0x10130110,data=0x0000c001,data-len=4 The correct result with this bug fix: (qemu) xp /1wx 0x00001000 00001000: 0x44332211 (qemu) xp /1wx 0x00001004 00001004: 0x88776655 Cc: qemu-stable@nongnu.org Signed-off-by: Tao Ding <dingtao0430@163.com> [PMM: Adjusted commit message] Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: cb35c1b622674da7a2b70691402132f691933f2c.1773301927.git.dingtao0430@163.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Tao Ding committed Mar 12, 2026 at 16:02 UTC f9b16f791502d912cf07ec040a1a2efb1009f713
1 file changed +7 -5
hw/dma/pl080.c
+7 -5
@@ -102,6 +102,7 @@ static void pl080_run(PL080State *s)
102 int size;
103 uint8_t buff[4];
104 uint32_t req;
105 + uint32_t next_lli;
106
107 s->tc_mask = 0;
108 for (c = 0; c < s->nchannels; c++) {
@@ -198,21 +199,22 @@ again:
199 ch->ctrl = (ch->ctrl & 0xfffff000) | size;
200 if (size == 0) {
201 /* Transfer complete. */
201 - if (ch->lli) {
202 + next_lli = (ch->lli & ~3);
203 + if (next_lli) {
204 ch->src = address_space_ldl_le(&s->downstream_as,
203 - ch->lli,
205 + next_lli,
206 MEMTXATTRS_UNSPECIFIED,
207 NULL);
208 ch->dest = address_space_ldl_le(&s->downstream_as,
207 - ch->lli + 4,
209 + next_lli + 4,
210 MEMTXATTRS_UNSPECIFIED,
211 NULL);
212 ch->ctrl = address_space_ldl_le(&s->downstream_as,
211 - ch->lli + 12,
213 + next_lli + 12,
214 MEMTXATTRS_UNSPECIFIED,
215 NULL);
216 ch->lli = address_space_ldl_le(&s->downstream_as,
215 - ch->lli + 8,
217 + next_lli + 8,
218 MEMTXATTRS_UNSPECIFIED,
219 NULL);
220 } else {