From patchwork Sun Dec 23 15:32:46 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Herv=C3=A9_Poussineau?= X-Patchwork-Id: 207982 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 34BD52C008A for ; Mon, 24 Dec 2012 02:33:32 +1100 (EST) Received: from localhost ([::1]:41957 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TmnYQ-0001Ud-9X for incoming@patchwork.ozlabs.org; Sun, 23 Dec 2012 10:33:30 -0500 Received: from eggs.gnu.org ([208.118.235.92]:34600) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TmnXY-0008MJ-SF for qemu-devel@nongnu.org; Sun, 23 Dec 2012 10:32:42 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TmnXS-0007St-0j for qemu-devel@nongnu.org; Sun, 23 Dec 2012 10:32:36 -0500 Received: from smtp1-g21.free.fr ([2a01:e0c:1:1599::10]:43613) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TmnXR-0007So-FK for qemu-devel@nongnu.org; Sun, 23 Dec 2012 10:32:29 -0500 Received: from localhost.localdomain (unknown [82.227.227.196]) by smtp1-g21.free.fr (Postfix) with ESMTP id D739B940078; Sun, 23 Dec 2012 16:32:23 +0100 (CET) From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= To: qemu-devel@nongnu.org Date: Sun, 23 Dec 2012 16:32:46 +0100 Message-Id: <1356276769-7357-7-git-send-email-hpoussin@reactos.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1356276769-7357-1-git-send-email-hpoussin@reactos.org> References: <1356276769-7357-1-git-send-email-hpoussin@reactos.org> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a01:e0c:1:1599::10 Cc: =?UTF-8?q?Andreas=20F=C3=A4rber?= , =?UTF-8?q?Herv=C3=A9=20Poussineau?= , Gerd Hoffmann Subject: [Qemu-devel] [RFC 6/8] isa: use memory regions instead of portio_list_* functions 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 Signed-off-by: Hervé Poussineau --- hw/isa-bus.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- hw/isa.h | 2 +- 2 files changed, 125 insertions(+), 4 deletions(-) diff --git a/hw/isa-bus.c b/hw/isa-bus.c index 144a88e..d22f432 100644 --- a/hw/isa-bus.c +++ b/hw/isa-bus.c @@ -104,19 +104,140 @@ void isa_register_ioport(ISADevice *dev, MemoryRegion *io, uint16_t start) isa_init_ioport(dev, start); } +typedef struct PortioState { + const char *name; /* debug purposes */ + uint16_t start; + uint16_t offset; + const MemoryRegionPortio *pio_start; + void *opaque; +} PortioState; + +static const MemoryRegionPortio *portio_find(const MemoryRegionPortio *mrp, + uint64_t offset, + unsigned int width, bool write, + bool smaller) +{ + for (; mrp->size; ++mrp) { + if (offset >= mrp->offset && offset < mrp->offset + mrp->len + && (width == mrp->size || (smaller && width < mrp->size)) + && (write ? (bool)mrp->write : (bool)mrp->read)) { + return mrp; + } + } + return NULL; +} + +static uint64_t portio_read(void *opaque, hwaddr addr, unsigned int size) +{ + const PortioState *s = opaque; + const MemoryRegionPortio *mrp; + + addr += s->offset; + mrp = portio_find(s->pio_start, addr, size, false, false); + if (mrp) { + return mrp->read(s->opaque, s->start + addr); + } else if (size == 2) { + uint64_t data; + mrp = portio_find(s->pio_start, addr, 1, false, false); + assert(mrp); + data = mrp->read(s->opaque, s->start + addr) | + (mrp->read(s->opaque, s->start + addr + 1) << 8); + return data; + } + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid read from 0x%x size=%d", + s->name, s->start + (int)addr, size); + return -1U; +} + +static void portio_write(void *opaque, hwaddr addr, uint64_t data, + unsigned int size) +{ + const PortioState *s = opaque; + const MemoryRegionPortio *mrp; + + addr += s->offset; + mrp = portio_find(s->pio_start, addr, size, true, false); + if (mrp) { + mrp->write(s->opaque, s->start + addr, data); + return; + } else if (size == 2) { + mrp = portio_find(s->pio_start, addr, 1, true, false); + assert(mrp); + mrp->write(s->opaque, s->start + addr, data & 0xff); + mrp->write(s->opaque, s->start + addr + 1, data >> 8); + return; + } + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid write to 0x%x size=%d", + s->name, s->start + (int)addr, size); +} + +static bool portio_accepts(void *opaque, hwaddr addr, unsigned int size, + bool is_write) +{ + const PortioState *s = opaque; + const MemoryRegionPortio *mrp; + + addr += s->offset; + mrp = portio_find(s->pio_start, addr, size, is_write, true); + return (mrp != NULL); +} + +const MemoryRegionOps portio_ops = { + .read = portio_read, + .write = portio_write, + .valid.accepts = portio_accepts, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void isa_register_portio_list_1(ISADevice *dev, uint16_t start, + uint16_t offset, uint16_t end, + const MemoryRegionPortio *pio_start, + void *opaque, const char *name) +{ + MemoryRegion *mr = g_new(MemoryRegion, 1); + PortioState *s = g_new(PortioState, 1); + + s->name = name; + s->start = start; + s->offset = offset; + s->pio_start = pio_start; + s->opaque = opaque; + memory_region_init_io(mr, &portio_ops, s, name, end - offset); + memory_region_add_subregion(isa_address_space_io(dev), + start + offset, mr); +} + void isa_register_portio_list(ISADevice *dev, uint16_t start, const MemoryRegionPortio *pio_start, void *opaque, const char *name) { - PortioList *piolist = g_new(PortioList, 1); + const MemoryRegionPortio *pio, *first; + uint16_t end; /* START is how we should treat DEV, regardless of the actual contents of the portio array. This is how the old code actually handled e.g. the FDC device. */ isa_init_ioport(dev, start); - portio_list_init(piolist, pio_start, opaque, name); - portio_list_add(piolist, isabus->address_space_io, start); + assert(pio_start->size); + + first = pio_start; + end = 0; + for (pio = pio_start; pio->size; pio++) { + assert(pio->offset >= first->offset); + if (pio->offset > first->offset + first->len) { + isa_register_portio_list_1(dev, start, first->offset, end, + pio_start, opaque, name); + first = pio; + end = 0; + } + if (pio->offset + pio->len > end) { + end = pio->offset + pio->len; + } + } + + isa_register_portio_list_1(dev, start, first->offset, end, + pio_start, opaque, name); } static int isa_qdev_init(DeviceState *qdev) diff --git a/hw/isa.h b/hw/isa.h index 9d719fa..d44d16d 100644 --- a/hw/isa.h +++ b/hw/isa.h @@ -73,7 +73,7 @@ void isa_register_ioport(ISADevice *dev, MemoryRegion *io, uint16_t start); * @dev: the ISADevice against which these are registered; may be NULL. * @start: the base I/O port against which the portio->offset is applied. * @portio: the ports, sorted by offset. - * @opaque: passed into the old_portio callbacks. + * @opaque: passed into the portio callbacks. * @name: passed into memory_region_init_io. */ void isa_register_portio_list(ISADevice *dev, uint16_t start,