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

vga-pci: add qext region to mmio

Add a qemu extented register range to the standard vga mmio bar.
Right nowe there are two registers: One readonly register returning the
size of the region (so we can easily add more registers there if needed)
and one endian control register, so guests (especially ppc) can flip
the framebuffer endianness as they need it.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>

+87
+9
docs/specs/standard-vga.txt
··· 70 70 0500 - 0515 : bochs dispi interface registers, mapped flat 71 71 without index/data ports. Use (index << 1) 72 72 as offset for (16bit) register access. 73 + 74 + 0600 - 0607 : qemu extended registers. qemu 2.2+ only. 75 + The pci revision is 2 (or greater) when 76 + these registers are present. The registers 77 + are 32bit. 78 + 0600 : qemu extended register region size, in bytes. 79 + 0604 : framebuffer endianness register. 80 + - 0xbebebebe indicates big endian. 81 + - 0x1e1e1e1e indicates little endian.
+70
hw/display/vga-pci.c
··· 35 35 #define PCI_VGA_IOPORT_SIZE (0x3e0 - 0x3c0) 36 36 #define PCI_VGA_BOCHS_OFFSET 0x500 37 37 #define PCI_VGA_BOCHS_SIZE (0x0b * 2) 38 + #define PCI_VGA_QEXT_OFFSET 0x600 39 + #define PCI_VGA_QEXT_SIZE (2 * 4) 38 40 #define PCI_VGA_MMIO_SIZE 0x1000 39 41 42 + #define PCI_VGA_QEXT_REG_SIZE (0 * 4) 43 + #define PCI_VGA_QEXT_REG_BYTEORDER (1 * 4) 44 + #define PCI_VGA_QEXT_LITTLE_ENDIAN 0x1e1e1e1e 45 + #define PCI_VGA_QEXT_BIG_ENDIAN 0xbebebebe 46 + 40 47 enum vga_pci_flags { 41 48 PCI_VGA_FLAG_ENABLE_MMIO = 1, 49 + PCI_VGA_FLAG_ENABLE_QEXT = 2, 42 50 }; 43 51 44 52 typedef struct PCIVGAState { ··· 48 56 MemoryRegion mmio; 49 57 MemoryRegion ioport; 50 58 MemoryRegion bochs; 59 + MemoryRegion qext; 51 60 } PCIVGAState; 52 61 53 62 static const VMStateDescription vmstate_vga_pci = { ··· 140 149 .endianness = DEVICE_LITTLE_ENDIAN, 141 150 }; 142 151 152 + static uint64_t pci_vga_qext_read(void *ptr, hwaddr addr, unsigned size) 153 + { 154 + PCIVGAState *d = ptr; 155 + 156 + switch (addr) { 157 + case PCI_VGA_QEXT_REG_SIZE: 158 + return PCI_VGA_QEXT_SIZE; 159 + case PCI_VGA_QEXT_REG_BYTEORDER: 160 + return d->vga.big_endian_fb ? 161 + PCI_VGA_QEXT_BIG_ENDIAN : PCI_VGA_QEXT_LITTLE_ENDIAN; 162 + default: 163 + return 0; 164 + } 165 + } 166 + 167 + static void pci_vga_qext_write(void *ptr, hwaddr addr, 168 + uint64_t val, unsigned size) 169 + { 170 + PCIVGAState *d = ptr; 171 + 172 + switch (addr) { 173 + case PCI_VGA_QEXT_REG_BYTEORDER: 174 + if (val == PCI_VGA_QEXT_BIG_ENDIAN) { 175 + d->vga.big_endian_fb = true; 176 + } 177 + if (val == PCI_VGA_QEXT_LITTLE_ENDIAN) { 178 + d->vga.big_endian_fb = false; 179 + } 180 + break; 181 + } 182 + } 183 + 184 + static const MemoryRegionOps pci_vga_qext_ops = { 185 + .read = pci_vga_qext_read, 186 + .write = pci_vga_qext_write, 187 + .valid.min_access_size = 4, 188 + .valid.max_access_size = 4, 189 + .endianness = DEVICE_LITTLE_ENDIAN, 190 + }; 191 + 143 192 static int pci_std_vga_initfn(PCIDevice *dev) 144 193 { 145 194 PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev); ··· 167 216 &d->ioport); 168 217 memory_region_add_subregion(&d->mmio, PCI_VGA_BOCHS_OFFSET, 169 218 &d->bochs); 219 + 220 + if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_QEXT)) { 221 + memory_region_init_io(&d->qext, NULL, &pci_vga_qext_ops, d, 222 + "qemu extended regs", PCI_VGA_QEXT_SIZE); 223 + memory_region_add_subregion(&d->mmio, PCI_VGA_QEXT_OFFSET, 224 + &d->qext); 225 + pci_set_byte(&d->dev.config[PCI_REVISION_ID], 2); 226 + } 227 + 170 228 pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio); 171 229 } 172 230 ··· 199 257 memory_region_add_subregion(&d->mmio, PCI_VGA_BOCHS_OFFSET, 200 258 &d->bochs); 201 259 260 + if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_QEXT)) { 261 + memory_region_init_io(&d->qext, NULL, &pci_vga_qext_ops, d, 262 + "qemu extended regs", PCI_VGA_QEXT_SIZE); 263 + memory_region_add_subregion(&d->mmio, PCI_VGA_QEXT_OFFSET, 264 + &d->qext); 265 + pci_set_byte(&d->dev.config[PCI_REVISION_ID], 2); 266 + } 267 + 202 268 pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram); 203 269 pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio); 204 270 ··· 215 281 static Property vga_pci_properties[] = { 216 282 DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16), 217 283 DEFINE_PROP_BIT("mmio", PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_MMIO, true), 284 + DEFINE_PROP_BIT("qemu-extended-regs", 285 + PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_QEXT, true), 218 286 DEFINE_PROP_END_OF_LIST(), 219 287 }; 220 288 221 289 static Property secondary_pci_properties[] = { 222 290 DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16), 291 + DEFINE_PROP_BIT("qemu-extended-regs", 292 + PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_QEXT, true), 223 293 DEFINE_PROP_END_OF_LIST(), 224 294 }; 225 295
+8
include/hw/i386/pc.h
··· 306 306 .driver = "intel-hda",\ 307 307 .property = "old_msi_addr",\ 308 308 .value = "on",\ 309 + },{\ 310 + .driver = "VGA",\ 311 + .property = "qemu-extended-regs",\ 312 + .value = "off",\ 313 + },{\ 314 + .driver = "secondary-vga",\ 315 + .property = "qemu-extended-regs",\ 316 + .value = "off",\ 309 317 } 310 318 311 319 #define PC_COMPAT_2_0 \