diff options
| author | Avi Kivity <avi@redhat.com> | 2012-03-05 17:40:12 +0200 |
|---|---|---|
| committer | Avi Kivity <avi@redhat.com> | 2012-03-05 17:40:12 +0200 |
| commit | a2d335214a53b0cc6f7a4a2009d842bea1958085 (patch) | |
| tree | 51adcaa66db1f5f2f19e59d0c600aa2f6adc9a4c | |
| parent | c5b703ac2073de8b968ef058793db0294f6a2979 (diff) | |
| download | focaccia-qemu-a2d335214a53b0cc6f7a4a2009d842bea1958085.tar.gz focaccia-qemu-a2d335214a53b0cc6f7a4a2009d842bea1958085.zip | |
memory: fix I/O port aliases
Commit e58ac72b6a0 ("ioport: change portio_list not to use
memory_region_set_offset()") started using aliases of I/O memory
regions. Since the IORange used for the I/O was contained in the
target region, the alias information (specifically, the offset
into the region) was lost. This broke -vga std.
Fix by allocating an independent object to hold the IORange and
also the new offset.
Note that I/O memory regions were conceptually broken wrt aliases
in a different way: an alias can cause the same region to appear
twice in an address space, but we had just one IORange to service it.
This patch fixes that problem as well, since we can now have multiple
IORange/MemoryRegion associations.
Signed-off-by: Avi Kivity <avi@redhat.com>
| -rw-r--r-- | exec.c | 8 | ||||
| -rw-r--r-- | memory.c | 26 | ||||
| -rw-r--r-- | memory.h | 9 |
3 files changed, 34 insertions, 9 deletions
diff --git a/exec.c b/exec.c index 3ce35399d6..1e5bbd6378 100644 --- a/exec.c +++ b/exec.c @@ -3668,9 +3668,13 @@ static void io_commit(MemoryListener *listener) static void io_region_add(MemoryListener *listener, MemoryRegionSection *section) { - iorange_init(§ion->mr->iorange, &memory_region_iorange_ops, + MemoryRegionIORange *mrio = g_new(MemoryRegionIORange, 1); + + mrio->mr = section->mr; + mrio->offset = section->offset_within_region; + iorange_init(&mrio->iorange, &memory_region_iorange_ops, section->offset_within_address_space, section->size); - ioport_register(§ion->mr->iorange); + ioport_register(&mrio->iorange); } static void io_region_del(MemoryListener *listener, diff --git a/memory.c b/memory.c index 6565e2e696..4c3dc49262 100644 --- a/memory.c +++ b/memory.c @@ -382,16 +382,20 @@ static void memory_region_iorange_read(IORange *iorange, unsigned width, uint64_t *data) { - MemoryRegion *mr = container_of(iorange, MemoryRegion, iorange); + MemoryRegionIORange *mrio + = container_of(iorange, MemoryRegionIORange, iorange); + MemoryRegion *mr = mrio->mr; + offset += mrio->offset; if (mr->ops->old_portio) { - const MemoryRegionPortio *mrp = find_portio(mr, offset, width, false); + const MemoryRegionPortio *mrp = find_portio(mr, offset - mrio->offset, + width, false); *data = ((uint64_t)1 << (width * 8)) - 1; if (mrp) { *data = mrp->read(mr->opaque, offset); } else if (width == 2) { - mrp = find_portio(mr, offset, 1, false); + mrp = find_portio(mr, offset - mrio->offset, 1, false); assert(mrp); *data = mrp->read(mr->opaque, offset) | (mrp->read(mr->opaque, offset + 1) << 8); @@ -410,15 +414,19 @@ static void memory_region_iorange_write(IORange *iorange, unsigned width, uint64_t data) { - MemoryRegion *mr = container_of(iorange, MemoryRegion, iorange); + MemoryRegionIORange *mrio + = container_of(iorange, MemoryRegionIORange, iorange); + MemoryRegion *mr = mrio->mr; + offset += mrio->offset; if (mr->ops->old_portio) { - const MemoryRegionPortio *mrp = find_portio(mr, offset, width, true); + const MemoryRegionPortio *mrp = find_portio(mr, offset - mrio->offset, + width, true); if (mrp) { mrp->write(mr->opaque, offset, data); } else if (width == 2) { - mrp = find_portio(mr, offset, 1, false); + mrp = find_portio(mr, offset - mrio->offset, 1, false); assert(mrp); mrp->write(mr->opaque, offset, data & 0xff); mrp->write(mr->opaque, offset + 1, data >> 8); @@ -431,9 +439,15 @@ static void memory_region_iorange_write(IORange *iorange, memory_region_write_accessor, mr); } +static void memory_region_iorange_destructor(IORange *iorange) +{ + g_free(container_of(iorange, MemoryRegionIORange, iorange)); +} + const IORangeOps memory_region_iorange_ops = { .read = memory_region_iorange_read, .write = memory_region_iorange_write, + .destructor = memory_region_iorange_destructor, }; static AddressSpace address_space_io; diff --git a/memory.h b/memory.h index b7bccd1968..53ff62b6c0 100644 --- a/memory.h +++ b/memory.h @@ -43,6 +43,14 @@ struct MemoryRegionMmio { CPUWriteMemoryFunc *write[3]; }; +/* Internal use; thunks between old-style IORange and MemoryRegions. */ +typedef struct MemoryRegionIORange MemoryRegionIORange; +struct MemoryRegionIORange { + IORange iorange; + MemoryRegion *mr; + target_phys_addr_t offset; +}; + /* * Memory region callbacks */ @@ -117,7 +125,6 @@ struct MemoryRegion { target_phys_addr_t addr; void (*destructor)(MemoryRegion *mr); ram_addr_t ram_addr; - IORange iorange; bool subpage; bool terminates; bool readable; |