Add new function sysbus_pass_mmio() to allow a sysbus device to delegate MMIO to another sysbus device. This allows a limited form of composition for sysbus devices.
Signed-off-by: Peter Maydell <peter.mayd...@linaro.org> --- hw/sysbus.c | 26 ++++++++++++++++++++++++++ hw/sysbus.h | 3 +++ 2 files changed, 29 insertions(+), 0 deletions(-) diff --git a/hw/sysbus.c b/hw/sysbus.c index 01ebe47..793b0c1 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -43,6 +43,10 @@ void sysbus_mmio_unmap(SysBusDevice *dev, int n) { assert(n >= 0 && n < dev->num_mmio); + if (dev->mmio[n].delegate) { + sysbus_mmio_unmap(dev->mmio[n].delegate, dev->mmio[n].delegate_mmio); + return; + } if (dev->mmio[n].addr == (target_phys_addr_t)-1) { /* region already unmapped */ return; @@ -60,6 +64,11 @@ void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr) { assert(n >= 0 && n < dev->num_mmio); + if (dev->mmio[n].delegate) { + sysbus_mmio_map(dev->mmio[n].delegate, dev->mmio[n].delegate_mmio, + addr); + return; + } if (dev->mmio[n].addr == addr) { /* ??? region already mapped here. */ return; @@ -83,6 +92,11 @@ void sysbus_mmio_resize(SysBusDevice *dev, int n, target_phys_addr_t newsize) target_phys_addr_t addr; assert(n >= 0 && n < dev->num_mmio); + if (dev->mmio[n].delegate) { + sysbus_mmio_resize(dev->mmio[n].delegate, dev->mmio[n].delegate_mmio, + newsize); + return; + } if (newsize != dev->mmio[n].size) { addr = dev->mmio[n].addr; if (addr != (target_phys_addr_t)-1) { @@ -127,6 +141,7 @@ void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size, assert(dev->num_mmio < QDEV_MAX_MMIO); n = dev->num_mmio++; + dev->mmio[n].delegate = 0; dev->mmio[n].addr = -1; dev->mmio[n].size = size; dev->mmio[n].iofunc = iofunc; @@ -139,11 +154,22 @@ void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size, assert(dev->num_mmio < QDEV_MAX_MMIO); n = dev->num_mmio++; + dev->mmio[n].delegate = 0; dev->mmio[n].addr = -1; dev->mmio[n].size = size; dev->mmio[n].cb = cb; } +void sysbus_pass_mmio(SysBusDevice *dev, SysBusDevice *target, int target_mmio) +{ + int n; + + assert(dev->num_mmio < QDEV_MAX_MMIO); + n = dev->num_mmio++; + dev->mmio[n].delegate = target; + dev->mmio[n].delegate_mmio = target_mmio; +} + void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size) { pio_addr_t i; diff --git a/hw/sysbus.h b/hw/sysbus.h index 70e2488..789e4c5 100644 --- a/hw/sysbus.h +++ b/hw/sysbus.h @@ -19,6 +19,8 @@ struct SysBusDevice { qemu_irq *irqp[QDEV_MAX_IRQ]; int num_mmio; struct { + SysBusDevice *delegate; + int delegate_mmio; target_phys_addr_t addr; target_phys_addr_t size; mmio_mapfunc cb; @@ -46,6 +48,7 @@ void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size, ram_addr_t iofunc); void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size, mmio_mapfunc cb); +void sysbus_pass_mmio(SysBusDevice *dev, SysBusDevice *target, int target_mmio); void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p); void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target); void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size); -- 1.7.1