qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

hw/dma/pl080: Don't use CPU address space for DMA accesses

Currently our PL080/PL081 model uses a combination of the CPU's
address space (via cpu_physical_memory_{read,write}()) and the
system address space for performing DMA accesses.

For the PL081s in the MPS FPGA images, their DMA accesses
must go via Master Security Controllers. Switch the
PL080/PL081 model to take a MemoryRegion property which
defines its downstream for making DMA accesses.

Since the PL08x are only used in two board models, we
make provision of the 'downstream' link mandatory and convert
both users at once, rather than having it be optional with
a default to the system address space.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

+49 -8
+7 -1
hw/arm/realview.c
··· 201 201 pl011_create(0x1000c000, pic[15], serial_hd(3)); 202 202 203 203 /* DMA controller is optional, apparently. */ 204 - sysbus_create_simple("pl081", 0x10030000, pic[24]); 204 + dev = qdev_create(NULL, "pl081"); 205 + object_property_set_link(OBJECT(dev), OBJECT(sysmem), "downstream", 206 + &error_fatal); 207 + qdev_init_nofail(dev); 208 + busdev = SYS_BUS_DEVICE(dev); 209 + sysbus_mmio_map(busdev, 0, 0x10030000); 210 + sysbus_connect_irq(busdev, 0, pic[24]); 205 211 206 212 sysbus_create_simple("sp804", 0x10011000, pic[4]); 207 213 sysbus_create_simple("sp804", 0x10012000, pic[5]);
+8 -1
hw/arm/versatilepb.c
··· 287 287 pl011_create(0x101f3000, pic[14], serial_hd(2)); 288 288 pl011_create(0x10009000, sic[6], serial_hd(3)); 289 289 290 - sysbus_create_simple("pl080", 0x10130000, pic[17]); 290 + dev = qdev_create(NULL, "pl080"); 291 + object_property_set_link(OBJECT(dev), OBJECT(sysmem), "downstream", 292 + &error_fatal); 293 + qdev_init_nofail(dev); 294 + busdev = SYS_BUS_DEVICE(dev); 295 + sysbus_mmio_map(busdev, 0, 0x10130000); 296 + sysbus_connect_irq(busdev, 0, pic[17]); 297 + 291 298 sysbus_create_simple("sp804", 0x101e2000, pic[4]); 292 299 sysbus_create_simple("sp804", 0x101e3000, pic[5]); 293 300
+29 -6
hw/dma/pl080.c
··· 12 12 #include "exec/address-spaces.h" 13 13 #include "qemu/log.h" 14 14 #include "hw/dma/pl080.h" 15 + #include "qapi/error.h" 15 16 16 17 #define PL080_CONF_E 0x1 17 18 #define PL080_CONF_M1 0x2 ··· 161 162 swidth = 1 << ((ch->ctrl >> 18) & 7); 162 163 dwidth = 1 << ((ch->ctrl >> 21) & 7); 163 164 for (n = 0; n < dwidth; n+= swidth) { 164 - cpu_physical_memory_read(ch->src, buff + n, swidth); 165 + address_space_read(&s->downstream_as, ch->src, 166 + MEMTXATTRS_UNSPECIFIED, buff + n, swidth); 165 167 if (ch->ctrl & PL080_CCTRL_SI) 166 168 ch->src += swidth; 167 169 } 168 170 xsize = (dwidth < swidth) ? swidth : dwidth; 169 171 /* ??? This may pad the value incorrectly for dwidth < 32. */ 170 172 for (n = 0; n < xsize; n += dwidth) { 171 - cpu_physical_memory_write(ch->dest + n, buff + n, dwidth); 173 + address_space_write(&s->downstream_as, ch->dest + n, 174 + MEMTXATTRS_UNSPECIFIED, buff + n, dwidth); 172 175 if (ch->ctrl & PL080_CCTRL_DI) 173 176 ch->dest += swidth; 174 177 } ··· 178 181 if (size == 0) { 179 182 /* Transfer complete. */ 180 183 if (ch->lli) { 181 - ch->src = address_space_ldl_le(&address_space_memory, 184 + ch->src = address_space_ldl_le(&s->downstream_as, 182 185 ch->lli, 183 186 MEMTXATTRS_UNSPECIFIED, 184 187 NULL); 185 - ch->dest = address_space_ldl_le(&address_space_memory, 188 + ch->dest = address_space_ldl_le(&s->downstream_as, 186 189 ch->lli + 4, 187 190 MEMTXATTRS_UNSPECIFIED, 188 191 NULL); 189 - ch->ctrl = address_space_ldl_le(&address_space_memory, 192 + ch->ctrl = address_space_ldl_le(&s->downstream_as, 190 193 ch->lli + 12, 191 194 MEMTXATTRS_UNSPECIFIED, 192 195 NULL); 193 - ch->lli = address_space_ldl_le(&address_space_memory, 196 + ch->lli = address_space_ldl_le(&s->downstream_as, 194 197 ch->lli + 8, 195 198 MEMTXATTRS_UNSPECIFIED, 196 199 NULL); ··· 358 361 s->nchannels = 8; 359 362 } 360 363 364 + static void pl080_realize(DeviceState *dev, Error **errp) 365 + { 366 + PL080State *s = PL080(dev); 367 + 368 + if (!s->downstream) { 369 + error_setg(errp, "PL080 'downstream' link not set"); 370 + return; 371 + } 372 + 373 + address_space_init(&s->downstream_as, s->downstream, "pl080-downstream"); 374 + } 375 + 361 376 static void pl081_init(Object *obj) 362 377 { 363 378 PL080State *s = PL080(obj); ··· 365 380 s->nchannels = 2; 366 381 } 367 382 383 + static Property pl080_properties[] = { 384 + DEFINE_PROP_LINK("downstream", PL080State, downstream, 385 + TYPE_MEMORY_REGION, MemoryRegion *), 386 + DEFINE_PROP_END_OF_LIST(), 387 + }; 388 + 368 389 static void pl080_class_init(ObjectClass *oc, void *data) 369 390 { 370 391 DeviceClass *dc = DEVICE_CLASS(oc); 371 392 372 393 dc->vmsd = &vmstate_pl080; 394 + dc->realize = pl080_realize; 395 + dc->props = pl080_properties; 373 396 } 374 397 375 398 static const TypeInfo pl080_info = {
+5
include/hw/dma/pl080.h
··· 21 21 * + sysbus IRQ 1: DMACINTERR error interrupt request 22 22 * + sysbus IRQ 2: DMACINTTC count interrupt request 23 23 * + sysbus MMIO region 0: MemoryRegion for the device's registers 24 + * + QOM property "downstream": MemoryRegion defining where DMA 25 + * bus master transactions are made 24 26 */ 25 27 26 28 #ifndef HW_DMA_PL080_H ··· 61 63 qemu_irq irq; 62 64 qemu_irq interr; 63 65 qemu_irq inttc; 66 + 67 + MemoryRegion *downstream; 68 + AddressSpace downstream_as; 64 69 } PL080State; 65 70 66 71 #endif