As I/O ports are now memory regions, they can be seen in 'info qtree'. This also removes the last use of MemoryRegionOps.old_portio field.
Some of the code has been extracted from memory.c Signed-off-by: Hervé Poussineau <hpous...@reactos.org> --- include/exec/ioport.h | 3 +- ioport.c | 132 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 107 insertions(+), 28 deletions(-) diff --git a/include/exec/ioport.h b/include/exec/ioport.h index fc28350..398fe14 100644 --- a/include/exec/ioport.h +++ b/include/exec/ioport.h @@ -55,13 +55,14 @@ uint32_t cpu_inl(pio_addr_t addr); struct MemoryRegion; struct MemoryRegionPortio; +struct PortioListState; typedef struct PortioList { const struct MemoryRegionPortio *ports; struct MemoryRegion *address_space; unsigned nr; struct MemoryRegion **regions; - struct MemoryRegion **aliases; + struct PortioListState **states; void *opaque; const char *name; } PortioList; diff --git a/ioport.c b/ioport.c index a0ac2a0..d26d3e1 100644 --- a/ioport.c +++ b/ioport.c @@ -28,6 +28,7 @@ #include "exec/ioport.h" #include "trace.h" #include "exec/memory.h" +#include "qemu/host-utils.h" /***********************************************************/ /* IO Port */ @@ -330,6 +331,12 @@ uint32_t cpu_inl(pio_addr_t addr) return val; } +typedef struct PortioListState { + const MemoryRegionPortio *portio; + uint32_t offset; + void *opaque; +} PortioListState; + void portio_list_init(PortioList *piolist, const MemoryRegionPortio *callbacks, void *opaque, const char *name) @@ -343,16 +350,95 @@ void portio_list_init(PortioList *piolist, piolist->ports = callbacks; piolist->nr = 0; piolist->regions = g_new0(MemoryRegion *, n); - piolist->aliases = g_new0(MemoryRegion *, n); + piolist->states = g_new0(PortioListState *, n); piolist->address_space = NULL; piolist->opaque = opaque; piolist->name = name; } +static const MemoryRegionPortio *portio_find(const MemoryRegionPortio *mrp, + uint64_t offset, + unsigned int width, bool write) +{ + for (; mrp->size; ++mrp) { + if (offset >= mrp->offset && offset < mrp->offset + mrp->len + && 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 PortioListState *s = opaque; + const MemoryRegionPortio *mrp; + uint16_t data; + + addr += s->portio->offset; + mrp = portio_find(s->portio, addr, size, false); + if (!mrp && size == 2) { + mrp = portio_find(s->portio, addr, 1, false); + assert(mrp); + data = mrp->read(s->opaque, addr) | + (mrp->read(s->opaque, addr + 1) << 8); + return data; + } + assert(mrp); + return mrp->read(s->opaque, addr); +} + +static void portio_write(void *opaque, hwaddr addr, uint64_t data, + unsigned int size) +{ + const PortioListState *s = opaque; + const MemoryRegionPortio *mrp; + + addr += s->offset; + mrp = portio_find(s->portio, addr, size, true); + if (!mrp && size == 2) { + mrp = portio_find(s->portio, addr, 1, true); + assert(mrp); + mrp->write(s->opaque, addr, data & 0xff); + mrp->write(s->opaque, addr + 1, data >> 8); + return; + } + assert(mrp); + mrp->write(s->opaque, addr, data); +} + +static bool portio_accepts(void *opaque, hwaddr addr, unsigned int size, + bool is_write) +{ + const PortioListState *s = opaque; + const MemoryRegionPortio *mrp; + + addr += s->offset; + mrp = portio_find(s->portio, addr, size, is_write); + if (!mrp && size == 2) { + mrp = portio_find(s->portio, addr, 1, is_write); + } + if (!mrp) { + LOG_UNUSED_IOPORT("unused %s%c: port=0x%04" HWADDR_PRIx "\n", + is_write ? "out" : "in", + size == 1 ? 'b' : size == 2 ? 'w' : 'l', + addr); + } + return mrp; +} + +const MemoryRegionOps portio_ops = { + .endianness = DEVICE_LITTLE_ENDIAN, + .read = portio_read, + .write = portio_write, + .valid.accepts = portio_accepts, +}; + void portio_list_destroy(PortioList *piolist) { g_free(piolist->regions); - g_free(piolist->aliases); + g_free(piolist->states); } static void portio_list_add_1(PortioList *piolist, @@ -361,8 +447,8 @@ static void portio_list_add_1(PortioList *piolist, unsigned off_low, unsigned off_high) { MemoryRegionPortio *pio; - MemoryRegionOps *ops; - MemoryRegion *region, *alias; + MemoryRegion *region = g_new(MemoryRegion, 1); + PortioListState *s = g_new(PortioListState, 1); unsigned i; /* Copy the sub-list and null-terminate it. */ @@ -370,28 +456,20 @@ static void portio_list_add_1(PortioList *piolist, memcpy(pio, pio_init, sizeof(MemoryRegionPortio) * count); memset(pio + count, 0, sizeof(MemoryRegionPortio)); - /* Adjust the offsets to all be zero-based for the region. */ + /* Adjust the offsets to all be address-based for the region. */ for (i = 0; i < count; ++i) { - pio[i].offset -= off_low; + pio[i].offset += start; } - ops = g_new0(MemoryRegionOps, 1); - ops->old_portio = pio; - - region = g_new(MemoryRegion, 1); - alias = g_new(MemoryRegion, 1); - /* - * Use an alias so that the callback is called with an absolute address, - * rather than an offset relative to to start + off_low. - */ - memory_region_init_io(region, ops, piolist->opaque, piolist->name, - INT64_MAX); - memory_region_init_alias(alias, piolist->name, - region, start + off_low, off_high - off_low); + s->offset = start + off_low; + s->portio = pio; + s->opaque = piolist->opaque; + memory_region_init_io(region, &portio_ops, s, piolist->name, + off_high - off_low); memory_region_add_subregion(piolist->address_space, - start + off_low, alias); + s->offset, region); piolist->regions[piolist->nr] = region; - piolist->aliases[piolist->nr] = alias; + piolist->states[piolist->nr] = s; ++piolist->nr; } @@ -434,19 +512,19 @@ void portio_list_add(PortioList *piolist, void portio_list_del(PortioList *piolist) { - MemoryRegion *mr, *alias; + MemoryRegion *mr; + PortioListState *s; unsigned i; for (i = 0; i < piolist->nr; ++i) { mr = piolist->regions[i]; - alias = piolist->aliases[i]; - memory_region_del_subregion(piolist->address_space, alias); - memory_region_destroy(alias); + s = piolist->states[i]; + memory_region_del_subregion(piolist->address_space, mr); memory_region_destroy(mr); g_free((MemoryRegionOps *)mr->ops); g_free(mr); - g_free(alias); + g_free(s); piolist->regions[i] = NULL; - piolist->aliases[i] = NULL; + piolist->states[i] = NULL; } } -- 1.7.10.4