From patchwork Tue Sep 18 09:51:37 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gerd Hoffmann X-Patchwork-Id: 184669 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 41DE02C0099 for ; Tue, 18 Sep 2012 19:51:59 +1000 (EST) Received: from localhost ([::1]:33256 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TDuTF-0003AH-Ca for incoming@patchwork.ozlabs.org; Tue, 18 Sep 2012 05:51:57 -0400 Received: from eggs.gnu.org ([208.118.235.92]:45477) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TDuT7-0003A0-9x for qemu-devel@nongnu.org; Tue, 18 Sep 2012 05:51:50 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TDuT0-0007OS-RE for qemu-devel@nongnu.org; Tue, 18 Sep 2012 05:51:49 -0400 Received: from mx1.redhat.com ([209.132.183.28]:63836) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TDuT0-0007OF-If for qemu-devel@nongnu.org; Tue, 18 Sep 2012 05:51:42 -0400 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q8I9peWK026446 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Tue, 18 Sep 2012 05:51:40 -0400 Received: from rincewind.home.kraxel.org (ovpn-116-27.ams2.redhat.com [10.36.116.27]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q8I9pc3O024673; Tue, 18 Sep 2012 05:51:39 -0400 Received: by rincewind.home.kraxel.org (Postfix, from userid 500) id 8282A41555; Tue, 18 Sep 2012 11:51:37 +0200 (CEST) From: Gerd Hoffmann To: qemu-devel@nongnu.org Date: Tue, 18 Sep 2012 11:51:37 +0200 Message-Id: <1347961897-28554-1-git-send-email-kraxel@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.132.183.28 Cc: Gerd Hoffmann , kvm@vger.kernel.org Subject: [Qemu-devel] [RfC PATCH] vga: add mmio bar to standard vga X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 Signed-off-by: Gerd Hoffmann --- 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); +} + +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); + + 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];