On Tue, Sep 18, 2012 at 9:51 AM, Gerd Hoffmann <kraxel@xxxxxxxxxx> wrote: > This patch adds a mmio bar to the qemu standard vga which allows to > access the standard vga registers and bochs dispi interface registers > via mmio. > > Cc: Benjamin Herrenschmidt <benh@xxxxxxxxxxxxxxxxxxx> > Signed-off-by: Gerd Hoffmann <kraxel@xxxxxxxxxx> > --- > hw/vga-pci.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > hw/vga.c | 6 ++-- > hw/vga_int.h | 6 +++ > 3 files changed, 106 insertions(+), 3 deletions(-) > > diff --git a/hw/vga-pci.c b/hw/vga-pci.c > index 9abbada..e05e2ef 100644 > --- a/hw/vga-pci.c > +++ b/hw/vga-pci.c > @@ -30,9 +30,36 @@ > #include "qemu-timer.h" > #include "loader.h" > > +/* > + * QEMU Standard VGA -- MMIO area spec. > + * > + * Using PCI bar #2, keeping #1 free, which leaves the > + * door open to upgrade bar #0 to 64bit. > + * > + * mmio area layout: > + * 0x0000 -> 0x03ff reserved, for possible virtio extension. > + * 0x0400 -> 0x041f vga ioports (0x3c0 -> 0x3df), remapped 1:1 > + * 0x0500 -> 0x0515 bochs dispi interface registers, mapped flat without > + * index/data ports. Use (index << 1) as offset for > + * (16bit) register access. > + */ > +#define PCI_VGA_IOPORT_OFFSET 0x400 > +#define PCI_VGA_IOPORT_SIZE (0x3e0 - 0x3c0) > +#define PCI_VGA_BOCHS_OFFSET 0x500 > +#define PCI_VGA_BOCHS_SIZE (0x0b * 2) > +#define PCI_VGA_MMIO_SIZE 0x1000 > + > +enum vga_pci_flags { > + PCI_VGA_FLAG_ENABLE_MMIO = 1, > +}; > + > typedef struct PCIVGAState { > PCIDevice dev; > VGACommonState vga; > + uint32_t flags; > + MemoryRegion mmio; > + MemoryRegion ioport; > + MemoryRegion bochs; > } PCIVGAState; > > static const VMStateDescription vmstate_vga_pci = { > @@ -47,6 +74,60 @@ static const VMStateDescription vmstate_vga_pci = { > } > }; > > +static uint64_t pci_vga_ioport_read(void *ptr, target_phys_addr_t addr, > + unsigned size) > +{ > + PCIVGAState *d = ptr; > + return vga_ioport_read(&d->vga, addr); > +} > + > +static void pci_vga_ioport_write(void *ptr, target_phys_addr_t addr, > + uint64_t val, unsigned size) > +{ > + PCIVGAState *d = ptr; > + vga_ioport_write(&d->vga, addr, val); > +} > + > +static const MemoryRegionOps pci_vga_ioport_ops = { > + .read = pci_vga_ioport_read, > + .write = pci_vga_ioport_write, > + .valid.min_access_size = 1, > + .valid.max_access_size = 4, > + .impl.min_access_size = 1, > + .impl.max_access_size = 1, > + .endianness = DEVICE_LITTLE_ENDIAN, > +}; > + > +static uint64_t pci_vga_bochs_read(void *ptr, target_phys_addr_t addr, > + unsigned size) > +{ > + PCIVGAState *d = ptr; > + int index = addr >> 1; > + > + vbe_ioport_write_index(&d->vga, 0, index); > + return vbe_ioport_read_data(&d->vga, 0); These functions are only available with CONFIG_BOCHS_VBE #defined, so this code should be conditional as well. But building without CONFIG_BOCHS_VBE is not very useful since it's used by the BIOS and there's no display output without it IIRC. > +} > + > +static void pci_vga_bochs_write(void *ptr, target_phys_addr_t addr, > + uint64_t val, unsigned size) > +{ > + PCIVGAState *d = ptr; > + int index = addr >> 1; > + > + vbe_ioport_write_index(&d->vga, 0, index); > + vbe_ioport_write_data(&d->vga, 0, val); > +} > + > +static const MemoryRegionOps pci_vga_bochs_ops = { > + .read = pci_vga_bochs_read, > + .write = pci_vga_bochs_write, > + .valid.min_access_size = 1, > + .valid.max_access_size = 4, > + .impl.min_access_size = 2, > + .impl.max_access_size = 2, > + .endianness = DEVICE_LITTLE_ENDIAN, > +}; > + > static int pci_vga_initfn(PCIDevice *dev) > { > PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev); > @@ -62,6 +143,21 @@ static int pci_vga_initfn(PCIDevice *dev) > /* XXX: VGA_RAM_SIZE must be a power of two */ > pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram); > > + /* mmio bar for vga register access */ > + if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_MMIO)) { > + memory_region_init(&d->mmio, "vga.mmio", 4096); > + memory_region_init_io(&d->ioport, &pci_vga_ioport_ops, d, > + "vga ioports remapped", PCI_VGA_IOPORT_SIZE); > + memory_region_init_io(&d->bochs, &pci_vga_bochs_ops, d, > + "bochs dispi interface", PCI_VGA_BOCHS_SIZE); Also this region should only be available with CONFIG_BOCHS_VBE. > + > + memory_region_add_subregion(&d->mmio, PCI_VGA_IOPORT_OFFSET, > + &d->ioport); > + memory_region_add_subregion(&d->mmio, PCI_VGA_BOCHS_OFFSET, > + &d->bochs); > + pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio); > + } > + > if (!dev->rom_bar) { > /* compatibility with pc-0.13 and older */ > vga_init_vbe(s, pci_address_space(dev)); > @@ -77,6 +173,7 @@ DeviceState *pci_vga_init(PCIBus *bus) > > static Property vga_pci_properties[] = { > DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16), > + DEFINE_PROP_BIT("mmio", PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_MMIO, true), > DEFINE_PROP_END_OF_LIST(), > }; > > diff --git a/hw/vga.c b/hw/vga.c > index ec4f0c5..053f89d 100644 > --- a/hw/vga.c > +++ b/hw/vga.c > @@ -591,7 +591,7 @@ static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr) > return val; > } > > -static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr) > +uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr) > { > VGACommonState *s = opaque; > uint32_t val; > @@ -627,13 +627,13 @@ static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr) > return val; > } > > -static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val) > +void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val) > { > VGACommonState *s = opaque; > s->vbe_index = val; > } > > -static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) > +void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) > { > VGACommonState *s = opaque; > > diff --git a/hw/vga_int.h b/hw/vga_int.h > index 330a32f..5b68490 100644 > --- a/hw/vga_int.h > +++ b/hw/vga_int.h > @@ -208,7 +208,13 @@ void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2); > void ppm_save(const char *filename, struct DisplaySurface *ds, Error **errp); > > int vga_ioport_invalid(VGACommonState *s, uint32_t addr); > + > +#ifdef CONFIG_BOCHS_VBE > void vga_init_vbe(VGACommonState *s, MemoryRegion *address_space); > +uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr); > +void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val); > +void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val); > +#endif > > extern const uint8_t sr_mask[8]; > extern const uint8_t gr_mask[16]; > -- > 1.7.1 > > -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html