Introduce PortioList
Add a type and methods for manipulating a list of disjoint I/O ports, used in some older hardware devices. Based on original patch by Richard Henderson. Signed-off-by: Richard Henderson <rth@twiddle.net> Signed-off-by: Avi Kivity <avi@redhat.com>
This commit is contained in:
parent
ebf47c24b0
commit
6bf9fd43cf
@ -82,7 +82,7 @@ common-obj-$(CONFIG_WIN32) += os-win32.o
|
||||
common-obj-$(CONFIG_POSIX) += os-posix.o
|
||||
|
||||
common-obj-y += tcg-runtime.o host-utils.o
|
||||
common-obj-y += irq.o ioport.o input.o
|
||||
common-obj-y += irq.o input.o
|
||||
common-obj-$(CONFIG_PTIMER) += ptimer.o
|
||||
common-obj-$(CONFIG_MAX7310) += max7310.o
|
||||
common-obj-$(CONFIG_WM8750) += wm8750.o
|
||||
|
@ -183,7 +183,7 @@ endif #CONFIG_BSD_USER
|
||||
# System emulator target
|
||||
ifdef CONFIG_SOFTMMU
|
||||
|
||||
obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o
|
||||
obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o ioport.o
|
||||
# virtio has to be here due to weird dependency between PCI and virtio-net.
|
||||
# need to fix this properly
|
||||
obj-$(CONFIG_NO_PCI) += pci-stub.o
|
||||
|
108
ioport.c
108
ioport.c
@ -27,6 +27,7 @@
|
||||
|
||||
#include "ioport.h"
|
||||
#include "trace.h"
|
||||
#include "memory.h"
|
||||
|
||||
/***********************************************************/
|
||||
/* IO Port */
|
||||
@ -313,3 +314,110 @@ uint32_t cpu_inl(pio_addr_t addr)
|
||||
LOG_IOPORT("inl : %04"FMT_pioaddr" %08"PRIx32"\n", addr, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
void portio_list_init(PortioList *piolist,
|
||||
const MemoryRegionPortio *callbacks,
|
||||
void *opaque, const char *name)
|
||||
{
|
||||
unsigned n = 0;
|
||||
|
||||
while (callbacks[n].size) {
|
||||
++n;
|
||||
}
|
||||
|
||||
piolist->ports = callbacks;
|
||||
piolist->nr = 0;
|
||||
piolist->regions = g_new0(MemoryRegion *, n);
|
||||
piolist->address_space = NULL;
|
||||
piolist->opaque = opaque;
|
||||
piolist->name = name;
|
||||
}
|
||||
|
||||
void portio_list_destroy(PortioList *piolist)
|
||||
{
|
||||
g_free(piolist->regions);
|
||||
}
|
||||
|
||||
static void portio_list_add_1(PortioList *piolist,
|
||||
const MemoryRegionPortio *pio_init,
|
||||
unsigned count, unsigned start,
|
||||
unsigned off_low, unsigned off_high)
|
||||
{
|
||||
MemoryRegionPortio *pio;
|
||||
MemoryRegionOps *ops;
|
||||
MemoryRegion *region;
|
||||
unsigned i;
|
||||
|
||||
/* Copy the sub-list and null-terminate it. */
|
||||
pio = g_new(MemoryRegionPortio, count + 1);
|
||||
memcpy(pio, pio_init, sizeof(MemoryRegionPortio) * count);
|
||||
memset(pio + count, 0, sizeof(MemoryRegionPortio));
|
||||
|
||||
/* Adjust the offsets to all be zero-based for the region. */
|
||||
for (i = 0; i < count; ++i) {
|
||||
pio[i].offset -= off_low;
|
||||
}
|
||||
|
||||
ops = g_new0(MemoryRegionOps, 1);
|
||||
ops->old_portio = pio;
|
||||
|
||||
region = g_new(MemoryRegion, 1);
|
||||
memory_region_init_io(region, ops, piolist->opaque, piolist->name,
|
||||
off_high - off_low);
|
||||
memory_region_set_offset(region, start + off_low);
|
||||
memory_region_add_subregion(piolist->address_space,
|
||||
start + off_low, region);
|
||||
piolist->regions[piolist->nr++] = region;
|
||||
}
|
||||
|
||||
void portio_list_add(PortioList *piolist,
|
||||
MemoryRegion *address_space,
|
||||
uint32_t start)
|
||||
{
|
||||
const MemoryRegionPortio *pio, *pio_start = piolist->ports;
|
||||
unsigned int off_low, off_high, off_last, count;
|
||||
|
||||
piolist->address_space = address_space;
|
||||
|
||||
/* Handle the first entry specially. */
|
||||
off_last = off_low = pio_start->offset;
|
||||
off_high = off_low + pio_start->len;
|
||||
count = 1;
|
||||
|
||||
for (pio = pio_start + 1; pio->size != 0; pio++, count++) {
|
||||
/* All entries must be sorted by offset. */
|
||||
assert(pio->offset >= off_last);
|
||||
off_last = pio->offset;
|
||||
|
||||
/* If we see a hole, break the region. */
|
||||
if (off_last > off_high) {
|
||||
portio_list_add_1(piolist, pio_start, count, start, off_low,
|
||||
off_high);
|
||||
/* ... and start collecting anew. */
|
||||
pio_start = pio;
|
||||
off_low = off_last;
|
||||
off_high = off_low + pio->len;
|
||||
count = 0;
|
||||
} else if (off_last + pio->len > off_high) {
|
||||
off_high = off_last + pio->len;
|
||||
}
|
||||
}
|
||||
|
||||
/* There will always be an open sub-list. */
|
||||
portio_list_add_1(piolist, pio_start, count, start, off_low, off_high);
|
||||
}
|
||||
|
||||
void portio_list_del(PortioList *piolist)
|
||||
{
|
||||
MemoryRegion *mr;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < piolist->nr; ++i) {
|
||||
mr = piolist->regions[i];
|
||||
memory_region_del_subregion(piolist->address_space, mr);
|
||||
memory_region_destroy(mr);
|
||||
g_free((MemoryRegionOps *)mr->ops);
|
||||
g_free(mr);
|
||||
piolist->regions[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
21
ioport.h
21
ioport.h
@ -52,4 +52,25 @@ uint8_t cpu_inb(pio_addr_t addr);
|
||||
uint16_t cpu_inw(pio_addr_t addr);
|
||||
uint32_t cpu_inl(pio_addr_t addr);
|
||||
|
||||
struct MemoryRegion;
|
||||
struct MemoryRegionPortio;
|
||||
|
||||
typedef struct PortioList {
|
||||
const struct MemoryRegionPortio *ports;
|
||||
struct MemoryRegion *address_space;
|
||||
unsigned nr;
|
||||
struct MemoryRegion **regions;
|
||||
void *opaque;
|
||||
const char *name;
|
||||
} PortioList;
|
||||
|
||||
void portio_list_init(PortioList *piolist,
|
||||
const struct MemoryRegionPortio *callbacks,
|
||||
void *opaque, const char *name);
|
||||
void portio_list_destroy(PortioList *piolist);
|
||||
void portio_list_add(PortioList *piolist,
|
||||
struct MemoryRegion *address_space,
|
||||
uint32_t addr);
|
||||
void portio_list_del(PortioList *piolist);
|
||||
|
||||
#endif /* IOPORT_H */
|
||||
|
8
memory.c
8
memory.c
@ -403,12 +403,12 @@ static void memory_region_iorange_read(IORange *iorange,
|
||||
|
||||
*data = ((uint64_t)1 << (width * 8)) - 1;
|
||||
if (mrp) {
|
||||
*data = mrp->read(mr->opaque, offset);
|
||||
*data = mrp->read(mr->opaque, offset + mr->offset);
|
||||
}
|
||||
return;
|
||||
}
|
||||
*data = 0;
|
||||
access_with_adjusted_size(offset, data, width,
|
||||
access_with_adjusted_size(offset + mr->offset, data, width,
|
||||
mr->ops->impl.min_access_size,
|
||||
mr->ops->impl.max_access_size,
|
||||
memory_region_read_accessor, mr);
|
||||
@ -425,11 +425,11 @@ static void memory_region_iorange_write(IORange *iorange,
|
||||
const MemoryRegionPortio *mrp = find_portio(mr, offset, width, true);
|
||||
|
||||
if (mrp) {
|
||||
mrp->write(mr->opaque, offset, data);
|
||||
mrp->write(mr->opaque, offset + mr->offset, data);
|
||||
}
|
||||
return;
|
||||
}
|
||||
access_with_adjusted_size(offset, &data, width,
|
||||
access_with_adjusted_size(offset + mr->offset, &data, width,
|
||||
mr->ops->impl.min_access_size,
|
||||
mr->ops->impl.max_access_size,
|
||||
memory_region_write_accessor, mr);
|
||||
|
Loading…
Reference in New Issue
Block a user