From patchwork Thu Sep 27 07:47:51 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gerd Hoffmann X-Patchwork-Id: 187298 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 C03462C00B2 for ; Thu, 27 Sep 2012 17:48:27 +1000 (EST) Received: from localhost ([::1]:34401 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TH8pd-0008MC-NM for incoming@patchwork.ozlabs.org; Thu, 27 Sep 2012 03:48:25 -0400 Received: from eggs.gnu.org ([208.118.235.92]:50084) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TH8pM-0007wU-IL for qemu-devel@nongnu.org; Thu, 27 Sep 2012 03:48:16 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TH8pE-00014r-9C for qemu-devel@nongnu.org; Thu, 27 Sep 2012 03:48:08 -0400 Received: from mx1.redhat.com ([209.132.183.28]:58272) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TH8pE-00014h-0W for qemu-devel@nongnu.org; Thu, 27 Sep 2012 03:48:00 -0400 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q8R7luYT006216 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Thu, 27 Sep 2012 03:47:57 -0400 Received: from rincewind.home.kraxel.org (ovpn-116-20.ams2.redhat.com [10.36.116.20]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q8R7lsHI013462; Thu, 27 Sep 2012 03:47:56 -0400 Received: by rincewind.home.kraxel.org (Postfix, from userid 500) id 2EA7A4129B; Thu, 27 Sep 2012 09:47:53 +0200 (CEST) From: Gerd Hoffmann To: qemu-devel@nongnu.org Date: Thu, 27 Sep 2012 09:47:51 +0200 Message-Id: <1348732073-18986-2-git-send-email-kraxel@redhat.com> In-Reply-To: <1348732073-18986-1-git-send-email-kraxel@redhat.com> References: <1348732073-18986-1-git-send-email-kraxel@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.132.183.28 Cc: Gerd Hoffmann Subject: [Qemu-devel] [PATCH 1/3] 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/pc_piix.c | 4 ++ hw/vga-pci.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/vga.c | 6 ++-- hw/vga_int.h | 6 +++ 4 files changed, 121 insertions(+), 3 deletions(-) diff --git a/hw/pc_piix.c b/hw/pc_piix.c index fd5898f..2d136e0 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -371,6 +371,10 @@ static QEMUMachine pc_machine_v1_3 = { .driver = "ivshmem",\ .property = "use64",\ .value = "0",\ + },{\ + .driver = "VGA",\ + .property = "mmio",\ + .value = "off",\ } static QEMUMachine pc_machine_v1_2 = { diff --git a/hw/vga-pci.c b/hw/vga-pci.c index 9abbada..df1a1f1 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -30,9 +30,23 @@ #include "qemu-timer.h" #include "loader.h" +#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 +61,84 @@ 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; + uint64_t ret = 0; + + switch (size) { + case 1: + ret = vga_ioport_read(&d->vga, addr); + break; + case 2: + ret = vga_ioport_read(&d->vga, addr); + ret |= vga_ioport_read(&d->vga, addr+1) << 8; + break; + } + return ret; +} + +static void pci_vga_ioport_write(void *ptr, target_phys_addr_t addr, + uint64_t val, unsigned size) +{ + PCIVGAState *d = ptr; + switch (size) { + case 1: + vga_ioport_write(&d->vga, addr, val); + break; + case 2: + /* + * Update bytes in little endian order. Allows to update + * indexed registers with a single word write because the + * index byte is updated first. + */ + vga_ioport_write(&d->vga, addr, val & 0xff); + vga_ioport_write(&d->vga, addr+1, (val >> 8) & 0xff); + break; + } +} + +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 = 2, + .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 +154,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 +184,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];