Patchwork [RFC] pci: handle BAR mapping at pci level

login
register
mail settings
Submitter Blue Swirl
Date July 7, 2010, 5:53 p.m.
Message ID <AANLkTim5y9JcKEduGP4A5rtGDaGW1dCngczppNXvItQz@mail.gmail.com>
Download mbox | patch
Permalink /patch/58137/
State New
Headers show

Comments

Blue Swirl - July 7, 2010, 5:53 p.m.
Add I/O port registration functions which separate registration
from the mapping stage.

Move IOIO and MMIO BAR mapping to pci.c.

TODO: fix dirty logging, coalesced MMIO and base address comparisons
(eepro100 etc). Bridge filtering may be broken. Broke virtio-pci and MSIX.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
---
i386 boots but resets. PPC and Sparc64 can't even start.

Patch also available at
git://repo.or.cz/qemu/blueswirl.git

It may be worthwhile to break this into some kind of smaller steps.

 hw/ac97.c         |   60 +++++++++++---------
 hw/cirrus_vga.c   |   40 +++-----------
 hw/e1000.c        |   37 +-----------
 hw/eepro100.c     |   77 ++++++++++----------------
 hw/es1370.c       |   32 +++++------
 hw/ide/cmd646.c   |  149 +++++++++++++++++++++++++++++++-------------------
 hw/ide/piix.c     |   74 ++++++++++++++++---------
 hw/ide/via.c      |   67 ++++++++++++++--------
 hw/isa.h          |    1 +
 hw/isa_mmio.c     |   17 +++++-
 hw/lsi53c895a.c   |   60 ++++++--------------
 hw/macio.c        |  107 +++++++++++-------------------------
 hw/ne2000.c       |   66 +++++++++++++++-------
 hw/openpic.c      |   36 ++----------
 hw/pci.c          |  158 ++++++++++++++++++++++++++++++++--------------------
 hw/pci.h          |   18 +++++-
 hw/pcnet.c        |   62 ++++++++++-----------
 hw/ppc_mac.h      |    5 +-
 hw/ppc_newworld.c |    2 +-
 hw/ppc_oldworld.c |    4 +-
 hw/rtl8139.c      |   42 +++++---------
 hw/sun4u.c        |   29 +++------
 hw/usb-ohci.c     |   10 +---
 hw/usb-uhci.c     |   31 +++++-----
 hw/vga-pci.c      |   22 +------
 hw/virtio-pci.c   |   39 ++++++-------
 hw/vmware_vga.c   |  107 ++++++++++++++++++------------------
 hw/wdt_i6300esb.c |   38 +++++--------
 ioport.c          |  119 ++++++++++++++++++++++++++++++++++++----
 ioport.h          |    6 ++
 30 files changed, 778 insertions(+), 737 deletions(-)
Michael S. Tsirkin - July 7, 2010, 5:55 p.m.
On Wed, Jul 07, 2010 at 05:53:08PM +0000, Blue Swirl wrote:
> Add I/O port registration functions which separate registration
> from the mapping stage.
> 
> Move IOIO and MMIO BAR mapping to pci.c.
> 
> TODO: fix dirty logging, coalesced MMIO and base address comparisons
> (eepro100 etc). Bridge filtering may be broken. Broke virtio-pci and MSIX.

legacy vga regions too?

> Signed-off-by: Blue Swirl <blauwirbel@gmail.com>

Looks like a good direction to take.

> ---
> i386 boots but resets. PPC and Sparc64 can't even start.
> 
> Patch also available at
> git://repo.or.cz/qemu/blueswirl.git
> 
> It may be worthwhile to break this into some kind of smaller steps.

Definitely.
Blue Swirl - July 7, 2010, 6:12 p.m.
On Wed, Jul 7, 2010 at 5:55 PM, Michael S. Tsirkin <mst@redhat.com> wrote:
> On Wed, Jul 07, 2010 at 05:53:08PM +0000, Blue Swirl wrote:
>> Add I/O port registration functions which separate registration
>> from the mapping stage.
>>
>> Move IOIO and MMIO BAR mapping to pci.c.
>>
>> TODO: fix dirty logging, coalesced MMIO and base address comparisons
>> (eepro100 etc). Bridge filtering may be broken. Broke virtio-pci and MSIX.
>
> legacy vga regions too?

Probably not, because VGA still works nicely at PC boot.

>
>> Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
>
> Looks like a good direction to take.
>
>> ---
>> i386 boots but resets. PPC and Sparc64 can't even start.
>>
>> Patch also available at
>> git://repo.or.cz/qemu/blueswirl.git
>>
>> It may be worthwhile to break this into some kind of smaller steps.
>
> Definitely.
>

One way could be to leave map_func in place but if it's NULL, use
newer system. When all callers have converted cleanly, remove extra
NULL argument and map_func.

It would be nice to have some plan how to convert KVM stuff like dirty
logging and coalescing. Any ideas?
malc - July 7, 2010, 6:15 p.m.
On Wed, 7 Jul 2010, Blue Swirl wrote:

> Add I/O port registration functions which separate registration
> from the mapping stage.

Why?

[..snip..]
Anthony Liguori - July 7, 2010, 7:02 p.m.
On 07/07/2010 12:53 PM, Blue Swirl wrote:
> Add I/O port registration functions which separate registration
> from the mapping stage.
>
> Move IOIO and MMIO BAR mapping to pci.c.
>
> TODO: fix dirty logging, coalesced MMIO and base address comparisons
> (eepro100 etc). Bridge filtering may be broken. Broke virtio-pci and MSIX.
>
> Signed-off-by: Blue Swirl<blauwirbel@gmail.com>
> ---
> i386 boots but resets. PPC and Sparc64 can't even start.
>
> Patch also available at
> git://repo.or.cz/qemu/blueswirl.git
>
> It may be worthwhile to break this into some kind of smaller steps.
>
>   hw/ac97.c         |   60 +++++++++++---------
>   hw/cirrus_vga.c   |   40 +++-----------
>   hw/e1000.c        |   37 +-----------
>   hw/eepro100.c     |   77 ++++++++++----------------
>   hw/es1370.c       |   32 +++++------
>   hw/ide/cmd646.c   |  149 +++++++++++++++++++++++++++++++-------------------
>   hw/ide/piix.c     |   74 ++++++++++++++++---------
>   hw/ide/via.c      |   67 ++++++++++++++--------
>   hw/isa.h          |    1 +
>   hw/isa_mmio.c     |   17 +++++-
>   hw/lsi53c895a.c   |   60 ++++++--------------
>   hw/macio.c        |  107 +++++++++++-------------------------
>   hw/ne2000.c       |   66 +++++++++++++++-------
>   hw/openpic.c      |   36 ++----------
>   hw/pci.c          |  158 ++++++++++++++++++++++++++++++++--------------------
>   hw/pci.h          |   18 +++++-
>   hw/pcnet.c        |   62 ++++++++++-----------
>   hw/ppc_mac.h      |    5 +-
>   hw/ppc_newworld.c |    2 +-
>   hw/ppc_oldworld.c |    4 +-
>   hw/rtl8139.c      |   42 +++++---------
>   hw/sun4u.c        |   29 +++------
>   hw/usb-ohci.c     |   10 +---
>   hw/usb-uhci.c     |   31 +++++-----
>   hw/vga-pci.c      |   22 +------
>   hw/virtio-pci.c   |   39 ++++++-------
>   hw/vmware_vga.c   |  107 ++++++++++++++++++------------------
>   hw/wdt_i6300esb.c |   38 +++++--------
>   ioport.c          |  119 ++++++++++++++++++++++++++++++++++++----
>   ioport.h          |    6 ++
>   30 files changed, 778 insertions(+), 737 deletions(-)
>
> diff --git a/hw/ac97.c b/hw/ac97.c
> index 4319bc8..28d0c19 100644
> --- a/hw/ac97.c
> +++ b/hw/ac97.c
> @@ -1234,31 +1234,29 @@ static const VMStateDescription vmstate_ac97 = {
>       }
>   };
>
> -static void ac97_map (PCIDevice *pci_dev, int region_num,
> -                      pcibus_t addr, pcibus_t size, int type)
> -{
> -    AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, pci_dev);
> -    PCIDevice *d =&s->dev;
> -
> -    if (!region_num) {
> -        s->base[0] = addr;
> -        register_ioport_read (addr, 256 * 1, 1, nam_readb, d);
> -        register_ioport_read (addr, 256 * 2, 2, nam_readw, d);
> -        register_ioport_read (addr, 256 * 4, 4, nam_readl, d);
> -        register_ioport_write (addr, 256 * 1, 1, nam_writeb, d);
> -        register_ioport_write (addr, 256 * 2, 2, nam_writew, d);
> -        register_ioport_write (addr, 256 * 4, 4, nam_writel, d);
> -    }
> -    else {
> -        s->base[1] = addr;
> -        register_ioport_read (addr, 64 * 1, 1, nabm_readb, d);
> -        register_ioport_read (addr, 64 * 2, 2, nabm_readw, d);
> -        register_ioport_read (addr, 64 * 4, 4, nabm_readl, d);
> -        register_ioport_write (addr, 64 * 1, 1, nabm_writeb, d);
> -        register_ioport_write (addr, 64 * 2, 2, nabm_writew, d);
> -        register_ioport_write (addr, 64 * 4, 4, nabm_writel, d);
> -    }
> -}
> +static IOPortWriteFunc * const nam_writes[] = {
> +    nam_writeb,
> +    nam_writew,
> +    nam_writel,
> +};
> +
> +static IOPortReadFunc * const nam_reads[] = {
> +    nam_readb,
> +    nam_readw,
> +    nam_readl,
> +};
> +
> +static IOPortWriteFunc * const nabm_writes[] = {
> +    nabm_writeb,
> +    nabm_writew,
> +    nabm_writel,
> +};
> +
> +static IOPortReadFunc * const nabm_reads[] = {
> +    nabm_readb,
> +    nabm_readw,
> +    nabm_readl,
> +};
>
>   static void ac97_on_reset (void *opaque)
>   {
> @@ -1280,6 +1278,7 @@ static int ac97_initfn (PCIDevice *dev)
>   {
>       AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev);
>       uint8_t *c = s->dev.config;
> +    int io_index;
>
>       pci_config_set_vendor_id (c, PCI_VENDOR_ID_INTEL); /* ro */
>       pci_config_set_device_id (c, PCI_DEVICE_ID_INTEL_82801AA_5); /* ro */
> @@ -1321,9 +1320,14 @@ static int ac97_initfn (PCIDevice *dev)
>       /* TODO: RST# value should be 0. */
>       c[PCI_INTERRUPT_PIN] = 0x01;      /* intr_pn interrupt pin ro */
>
> -    pci_register_bar (&s->dev, 0, 256 * 4, PCI_BASE_ADDRESS_SPACE_IO,
> -                      ac97_map);
> -    pci_register_bar (&s->dev, 1, 64 * 4, PCI_BASE_ADDRESS_SPACE_IO, ac97_map);
> +    pci_register_bar(&s->dev, 0, 256 * 4, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(nam_reads, nam_writes, 256 * 4, s);
> +    pci_bar_map(&s->dev, 0, 0, 0, 256 * 4, io_index);
> +
> +    pci_register_bar(&s->dev, 1, 64 * 4, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(nabm_reads, nabm_writes, 64 * 4, s);
> +    pci_bar_map(&s->dev, 1, 0, 0, 64 * 4, io_index);
>    

Any reason to keep this a three step process?  I see no reason not to 
unify the io and mem function pointers into a single type.  These 
callbacks should be working off of pci bus addresses and should not be 
tied directly to CPU memory/pio callbacks.

Regards,

Anthony Liguori

> +
>       qemu_register_reset (ac97_on_reset, s);
>       AUD_register_card ("ac97",&s->card);
>       ac97_on_reset (s);
> diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
> index bbd4b08..829d837 100644
> --- a/hw/cirrus_vga.c
> +++ b/hw/cirrus_vga.c
> @@ -3139,36 +3139,6 @@ void isa_cirrus_vga_init(void)
>    *
>    ***************************************/
>
> -static void cirrus_pci_lfb_map(PCIDevice *d, int region_num,
> -			       pcibus_t addr, pcibus_t size, int type)
> -{
> -    CirrusVGAState *s =&DO_UPCAST(PCICirrusVGAState, dev, d)->cirrus_vga;
> -
> -    /* XXX: add byte swapping apertures */
> -    cpu_register_physical_memory(addr, s->vga.vram_size,
> -				 s->cirrus_linear_io_addr);
> -    cpu_register_physical_memory(addr + 0x1000000, 0x400000,
> -				 s->cirrus_linear_bitblt_io_addr);
> -
> -    s->vga.map_addr = s->vga.map_end = 0;
> -    s->vga.lfb_addr = addr&  TARGET_PAGE_MASK;
> -    s->vga.lfb_end = ((addr + VGA_RAM_SIZE) + TARGET_PAGE_SIZE - 1)&
> TARGET_PAGE_MASK;
> -    /* account for overflow */
> -    if (s->vga.lfb_end<  addr + VGA_RAM_SIZE)
> -        s->vga.lfb_end = addr + VGA_RAM_SIZE;
> -
> -    vga_dirty_log_start(&s->vga);
> -}
> -
> -static void cirrus_pci_mmio_map(PCIDevice *d, int region_num,
> -				pcibus_t addr, pcibus_t size, int type)
> -{
> -    CirrusVGAState *s =&DO_UPCAST(PCICirrusVGAState, dev, d)->cirrus_vga;
> -
> -    cpu_register_physical_memory(addr, CIRRUS_PNPMMIO_SIZE,
> -				 s->cirrus_mmio_io_addr);
> -}
> -
>   static void pci_cirrus_write_config(PCIDevice *d,
>                                       uint32_t address, uint32_t val, int len)
>   {
> @@ -3205,10 +3175,16 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
>        /* memory #1 memory-mapped I/O */
>        /* XXX: s->vga.vram_size must be a power of two */
>        pci_register_bar((PCIDevice *)d, 0, 0x2000000,
> -                      PCI_BASE_ADDRESS_MEM_PREFETCH, cirrus_pci_lfb_map);
> +                      PCI_BASE_ADDRESS_MEM_PREFETCH);
> +     pci_bar_map((PCIDevice *)d, 0, 0, 0, s->vga.vram_size,
> +                 s->cirrus_linear_io_addr);
> +     pci_bar_map((PCIDevice *)d, 0, 1, 0x1000000, 0x400000,
> +                 s->cirrus_linear_bitblt_io_addr);
>        if (device_id == CIRRUS_ID_CLGD5446) {
>            pci_register_bar((PCIDevice *)d, 1, CIRRUS_PNPMMIO_SIZE,
> -                          PCI_BASE_ADDRESS_SPACE_MEMORY, cirrus_pci_mmio_map);
> +                          PCI_BASE_ADDRESS_SPACE_MEMORY);
> +         pci_bar_map((PCIDevice *)d, 1, 0, 0, CIRRUS_PNPMMIO_SIZE,
> +                     s->cirrus_mmio_io_addr);
>        }
>        return 0;
>   }
> diff --git a/hw/e1000.c b/hw/e1000.c
> index 0da65f9..b5e9143 100644
> --- a/hw/e1000.c
> +++ b/hw/e1000.c
> @@ -149,14 +149,6 @@ static const char phy_regcap[0x20] = {
>   };
>
>   static void
> -ioport_map(PCIDevice *pci_dev, int region_num, pcibus_t addr,
> -           pcibus_t size, int type)
> -{
> -    DBGOUT(IO, "e1000_ioport_map addr=0x%04"FMT_PCIBUS
> -           " size=0x%08"FMT_PCIBUS"\n", addr, size);
> -}
> -
> -static void
>   set_interrupt_cause(E1000State *s, int index, uint32_t val)
>   {
>       if (val)
> @@ -1018,30 +1010,6 @@ static CPUReadMemoryFunc * const e1000_mmio_read[] = {
>   };
>
>   static void
> -e1000_mmio_map(PCIDevice *pci_dev, int region_num,
> -                pcibus_t addr, pcibus_t size, int type)
> -{
> -    E1000State *d = DO_UPCAST(E1000State, dev, pci_dev);
> -    int i;
> -    const uint32_t excluded_regs[] = {
> -        E1000_MDIC, E1000_ICR, E1000_ICS, E1000_IMS,
> -        E1000_IMC, E1000_TCTL, E1000_TDT, PNPMMIO_SIZE
> -    };
> -
> -
> -    DBGOUT(MMIO, "e1000_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n",
> -           addr, size);
> -
> -    cpu_register_physical_memory(addr, PNPMMIO_SIZE, d->mmio_index);
> -    qemu_register_coalesced_mmio(addr, excluded_regs[0]);
> -
> -    for (i = 0; excluded_regs[i] != PNPMMIO_SIZE; i++)
> -        qemu_register_coalesced_mmio(addr + excluded_regs[i] + 4,
> -                                     excluded_regs[i + 1] -
> -                                     excluded_regs[i] - 4);
> -}
> -
> -static void
>   e1000_cleanup(VLANClientState *nc)
>   {
>       E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
> @@ -1106,10 +1074,11 @@ static int pci_e1000_init(PCIDevice *pci_dev)
>               e1000_mmio_write, d);
>
>       pci_register_bar((PCIDevice *)d, 0, PNPMMIO_SIZE,
> -                           PCI_BASE_ADDRESS_SPACE_MEMORY, e1000_mmio_map);
> +                     PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    pci_bar_map((PCIDevice *)d, 0, 0, 0, PNPMMIO_SIZE, d->mmio_index);
>
>       pci_register_bar((PCIDevice *)d, 1, IOPORT_SIZE,
> -                           PCI_BASE_ADDRESS_SPACE_IO, ioport_map);
> +                     PCI_BASE_ADDRESS_SPACE_IO);
>
>       memmove(d->eeprom_data, e1000_eeprom_template,
>           sizeof e1000_eeprom_template);
> diff --git a/hw/eepro100.c b/hw/eepro100.c
> index 2b75c8f..da41476 100644
> --- a/hw/eepro100.c
> +++ b/hw/eepro100.c
> @@ -226,7 +226,7 @@ typedef struct {
>       uint8_t scb_stat;           /* SCB stat/ack byte */
>       uint8_t int_stat;           /* PCI interrupt status */
>       /* region must not be saved by nic_save. */
> -    uint32_t region[3];         /* PCI region addresses */
> +    uint32_t region;         /* PCI region addresses */
>       uint16_t mdimem[32];
>       eeprom_t *eeprom;
>       uint32_t device;            /* device variant */
> @@ -1479,19 +1479,19 @@ static uint32_t ioport_read1(void *opaque,
> uint32_t addr)
>   #if 0
>       logout("addr=%s\n", regname(addr));
>   #endif
> -    return eepro100_read1(s, addr - s->region[1]);
> +    return eepro100_read1(s, addr - s->region);
>   }
>
>   static uint32_t ioport_read2(void *opaque, uint32_t addr)
>   {
>       EEPRO100State *s = opaque;
> -    return eepro100_read2(s, addr - s->region[1]);
> +    return eepro100_read2(s, addr - s->region);
>   }
>
>   static uint32_t ioport_read4(void *opaque, uint32_t addr)
>   {
>       EEPRO100State *s = opaque;
> -    return eepro100_read4(s, addr - s->region[1]);
> +    return eepro100_read4(s, addr - s->region);
>   }
>
>   static void ioport_write1(void *opaque, uint32_t addr, uint32_t val)
> @@ -1500,43 +1500,35 @@ static void ioport_write1(void *opaque,
> uint32_t addr, uint32_t val)
>   #if 0
>       logout("addr=%s val=0x%02x\n", regname(addr), val);
>   #endif
> -    eepro100_write1(s, addr - s->region[1], val);
> +    eepro100_write1(s, addr - s->region, val);
>   }
>
>   static void ioport_write2(void *opaque, uint32_t addr, uint32_t val)
>   {
>       EEPRO100State *s = opaque;
> -    eepro100_write2(s, addr - s->region[1], val);
> +    eepro100_write2(s, addr - s->region, val);
>   }
>
>   static void ioport_write4(void *opaque, uint32_t addr, uint32_t val)
>   {
>       EEPRO100State *s = opaque;
> -    eepro100_write4(s, addr - s->region[1], val);
> +    eepro100_write4(s, addr - s->region, val);
>   }
>
>   /***********************************************************/
>   /* PCI EEPRO100 definitions */
>
> -static void pci_map(PCIDevice * pci_dev, int region_num,
> -                    pcibus_t addr, pcibus_t size, int type)
> -{
> -    EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
> -
> -    TRACE(OTHER, logout("region %d, addr=0x%08"FMT_PCIBUS", "
> -          "size=0x%08"FMT_PCIBUS", type=%d\n",
> -          region_num, addr, size, type));
> -
> -    assert(region_num == 1);
> -    register_ioport_write(addr, size, 1, ioport_write1, s);
> -    register_ioport_read(addr, size, 1, ioport_read1, s);
> -    register_ioport_write(addr, size, 2, ioport_write2, s);
> -    register_ioport_read(addr, size, 2, ioport_read2, s);
> -    register_ioport_write(addr, size, 4, ioport_write4, s);
> -    register_ioport_read(addr, size, 4, ioport_read4, s);
> +static IOPortWriteFunc * const io_writes[] = {
> +    ioport_write1,
> +    ioport_write2,
> +    ioport_write4,
> +};
>
> -    s->region[region_num] = addr;
> -}
> +static IOPortReadFunc * const io_reads[] = {
> +    ioport_read1,
> +    ioport_read2,
> +    ioport_read4,
> +};
>
>   /*****************************************************************************
>    *
> @@ -1610,22 +1602,6 @@ static CPUReadMemoryFunc * const pci_mmio_read[] = {
>       pci_mmio_readl
>   };
>
> -static void pci_mmio_map(PCIDevice * pci_dev, int region_num,
> -                         pcibus_t addr, pcibus_t size, int type)
> -{
> -    EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
> -
> -    TRACE(OTHER, logout("region %d, addr=0x%08"FMT_PCIBUS", "
> -          "size=0x%08"FMT_PCIBUS", type=%d\n",
> -          region_num, addr, size, type));
> -
> -    assert(region_num == 0 || region_num == 2);
> -
> -    /* Map control / status registers and flash. */
> -    cpu_register_physical_memory(addr, size, s->mmio_index);
> -    s->region[region_num] = addr;
> -}
> -
>   static int nic_can_receive(VLANClientState *nc)
>   {
>       EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque;
> @@ -1853,6 +1829,7 @@ static int e100_nic_init(PCIDevice *pci_dev)
>       EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
>       E100PCIDeviceInfo *e100_device = DO_UPCAST(E100PCIDeviceInfo, pci.qdev,
>                                                  pci_dev->qdev.info);
> +    int io_index;
>
>       TRACE(OTHER, logout("\n"));
>
> @@ -1868,17 +1845,23 @@ static int e100_nic_init(PCIDevice *pci_dev)
>       s->mmio_index =
>           cpu_register_io_memory(pci_mmio_read, pci_mmio_write, s);
>
> +    /* Map control / status registers. */
>       pci_register_bar(&s->dev, 0, PCI_MEM_SIZE,
>                              PCI_BASE_ADDRESS_SPACE_MEMORY |
> -                           PCI_BASE_ADDRESS_MEM_PREFETCH, pci_mmio_map);
> -    pci_register_bar(&s->dev, 1, PCI_IO_SIZE, PCI_BASE_ADDRESS_SPACE_IO,
> -                           pci_map);
> -    pci_register_bar(&s->dev, 2, PCI_FLASH_SIZE, PCI_BASE_ADDRESS_SPACE_MEMORY,
> -                           pci_mmio_map);
> +                           PCI_BASE_ADDRESS_MEM_PREFETCH);
> +    pci_bar_map(&s->dev, 0, 0, 0, PCI_IO_SIZE, s->mmio_index);
> +
> +    io_index = cpu_register_io(io_reads, io_writes, PCI_IO_SIZE, s);
> +    pci_register_bar(&s->dev, 1, PCI_IO_SIZE, PCI_BASE_ADDRESS_SPACE_IO);
> +    pci_bar_map(&s->dev, 1, 0, 0, PCI_IO_SIZE, io_index);
> +
> +    /* Map flash. */
> +    pci_register_bar(&s->dev, 2, PCI_FLASH_SIZE,
> +                     PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    pci_bar_map(&s->dev, 2, 0, 0, PCI_FLASH_SIZE, s->mmio_index);
>
>       qemu_macaddr_default_if_unset(&s->conf.macaddr);
>       logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6));
> -    assert(s->region[1] == 0);
>
>       nic_reset(s);
>
> diff --git a/hw/es1370.c b/hw/es1370.c
> index 40cb48c..652f0d4 100644
> --- a/hw/es1370.c
> +++ b/hw/es1370.c
> @@ -906,23 +906,17 @@ static void es1370_adc_callback (void *opaque, int avail)
>       es1370_run_channel (s, ADC_CHANNEL, avail);
>   }
>
> -static void es1370_map (PCIDevice *pci_dev, int region_num,
> -                        pcibus_t addr, pcibus_t size, int type)
> -{
> -    ES1370State *s = DO_UPCAST (ES1370State, dev, pci_dev);
> -
> -    (void) region_num;
> -    (void) size;
> -    (void) type;
> -
> -    register_ioport_write (addr, 0x40 * 4, 1, es1370_writeb, s);
> -    register_ioport_write (addr, 0x40 * 2, 2, es1370_writew, s);
> -    register_ioport_write (addr, 0x40, 4, es1370_writel, s);
> +static IOPortWriteFunc * const es1370_writes[] = {
> +    es1370_writeb,
> +    es1370_writew,
> +    es1370_writel,
> +};
>
> -    register_ioport_read (addr, 0x40 * 4, 1, es1370_readb, s);
> -    register_ioport_read (addr, 0x40 * 2, 2, es1370_readw, s);
> -    register_ioport_read (addr, 0x40, 4, es1370_readl, s);
> -}
> +static IOPortReadFunc * const es1370_reads[] = {
> +    es1370_readb,
> +    es1370_readw,
> +    es1370_readl,
> +};
>
>   static const VMStateDescription vmstate_es1370_channel = {
>       .name = "es1370_channel",
> @@ -997,6 +991,7 @@ static int es1370_initfn (PCIDevice *dev)
>   {
>       ES1370State *s = DO_UPCAST (ES1370State, dev, dev);
>       uint8_t *c = s->dev.config;
> +    int io_index;
>
>       pci_config_set_vendor_id (c, PCI_VENDOR_ID_ENSONIQ);
>       pci_config_set_device_id (c, PCI_DEVICE_ID_ENSONIQ_ES1370);
> @@ -1023,7 +1018,10 @@ static int es1370_initfn (PCIDevice *dev)
>       c[PCI_MIN_GNT] = 0x0c;
>       c[PCI_MAX_LAT] = 0x80;
>
> -    pci_register_bar (&s->dev, 0, 256, PCI_BASE_ADDRESS_SPACE_IO, es1370_map);
> +    pci_register_bar (&s->dev, 0, 256, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(es1370_reads, es1370_writes, 256, s);
> +    pci_bar_map(&s->dev, 0, 0, 0, 256, io_index);
> +
>       qemu_register_reset (es1370_on_reset, s);
>
>       AUD_register_card ("es1370",&s->card);
> diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
> index 8b71a13..b30e279 100644
> --- a/hw/ide/cmd646.c
> +++ b/hw/ide/cmd646.c
> @@ -44,29 +44,29 @@
>
>   static void cmd646_update_irq(PCIIDEState *d);
>
> -static void ide_map(PCIDevice *pci_dev, int region_num,
> -                    pcibus_t addr, pcibus_t size, int type)
> -{
> -    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
> -    IDEBus *bus;
> -
> -    if (region_num<= 3) {
> -        bus =&d->bus[(region_num>>  1)];
> -        if (region_num&  1) {
> -            register_ioport_read(addr + 2, 1, 1, ide_status_read, bus);
> -            register_ioport_write(addr + 2, 1, 1, ide_cmd_write, bus);
> -        } else {
> -            register_ioport_write(addr, 8, 1, ide_ioport_write, bus);
> -            register_ioport_read(addr, 8, 1, ide_ioport_read, bus);
> -
> -            /* data ports */
> -            register_ioport_write(addr, 2, 2, ide_data_writew, bus);
> -            register_ioport_read(addr, 2, 2, ide_data_readw, bus);
> -            register_ioport_write(addr, 4, 4, ide_data_writel, bus);
> -            register_ioport_read(addr, 4, 4, ide_data_readl, bus);
> -        }
> -    }
> -}
> +static IOPortWriteFunc * const ide_cmd_writes[] = {
> +    ide_cmd_write,
> +    NULL,
> +    NULL,
> +};
> +
> +static IOPortReadFunc * const ide_status_reads[] = {
> +    ide_status_read,
> +    NULL,
> +    NULL,
> +};
> +
> +static IOPortWriteFunc * const ide_ioport_writes[] = {
> +    ide_ioport_write,
> +    ide_data_writew,
> +    ide_data_writel,
> +};
> +
> +static IOPortReadFunc * const ide_ioport_reads[] = {
> +    ide_ioport_read,
> +    ide_data_readw,
> +    ide_data_readl,
> +};
>
>   static uint32_t bmdma_readb_common(PCIIDEState *pci_dev, BMDMAState *bm,
>                                      uint32_t addr)
> @@ -159,35 +159,41 @@ static void bmdma_writeb_1(void *opaque,
> uint32_t addr, uint32_t val)
>       bmdma_writeb_common(pci_dev, bm, addr, val);
>   }
>
> -static void bmdma_map(PCIDevice *pci_dev, int region_num,
> -                    pcibus_t addr, pcibus_t size, int type)
> -{
> -    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
> -    int i;
> +static IOPortWriteFunc * const bmdma_io_writes_0[] = {
> +    bmdma_writeb_0,
> +    NULL,
> +    NULL,
> +};
>
> -    for(i = 0;i<  2; i++) {
> -        BMDMAState *bm =&d->bmdma[i];
> -        d->bus[i].bmdma = bm;
> -        bm->bus = d->bus+i;
> -        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
> +static IOPortReadFunc * const bmdma_io_reads_0[] = {
> +    bmdma_readb_0,
> +    NULL,
> +    NULL,
> +};
>
> -        if (i == 0) {
> -            register_ioport_write(addr, 4, 1, bmdma_writeb_0, d);
> -            register_ioport_read(addr, 4, 1, bmdma_readb_0, d);
> -        } else {
> -            register_ioport_write(addr, 4, 1, bmdma_writeb_1, d);
> -            register_ioport_read(addr, 4, 1, bmdma_readb_1, d);
> -        }
> +static IOPortWriteFunc * const bmdma_io_writes_1[] = {
> +    bmdma_writeb_1,
> +    NULL,
> +    NULL,
> +};
>
> -        register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
> -        register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
> -        register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
> -        register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
> -        register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
> -        register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
> -        addr += 8;
> -    }
> -}
> +static IOPortReadFunc * const bmdma_io_reads_1[] = {
> +    bmdma_readb_1,
> +    NULL,
> +    NULL,
> +};
> +
> +static IOPortWriteFunc * const bmdma_addr_writes[] = {
> +    bmdma_addr_writeb,
> +    bmdma_addr_writew,
> +    bmdma_addr_writel,
> +};
> +
> +static IOPortReadFunc * const bmdma_addr_reads[] = {
> +    bmdma_addr_readb,
> +    bmdma_addr_readw,
> +    bmdma_addr_readl,
> +};
>
>   /* XXX: call it also when the MRDMODE is changed from the PCI config
>      registers */
> @@ -232,6 +238,8 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
>       PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
>       uint8_t *pci_conf = d->dev.config;
>       qemu_irq *irq;
> +    unsigned int i;
> +    int io_index;
>
>       pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_CMD);
>       pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_CMD_646);
> @@ -248,11 +256,38 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
>           pci_conf[0x51] |= 0x08; /* enable IDE1 */
>       }
>
> -    pci_register_bar(dev, 0, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
> -    pci_register_bar(dev, 1, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
> -    pci_register_bar(dev, 2, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
> -    pci_register_bar(dev, 3, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
> -    pci_register_bar(dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
> +    pci_register_bar(dev, 0, 0x8, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(ide_ioport_reads, ide_ioport_writes,
> 8,&d->bus[0]);
> +    pci_bar_map(&d->dev, 0, 0, 8, 8, io_index);
> +    pci_register_bar(dev, 1, 0x4, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(ide_status_reads, ide_cmd_writes, 1,
> &d->bus[0]);
> +    pci_bar_map(&d->dev, 1, 0, 1, 1, io_index);
> +    pci_register_bar(dev, 2, 0x8, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(ide_ioport_reads, ide_ioport_writes,
> 8,&d->bus[1]);
> +    pci_bar_map(&d->dev, 2, 0, 8, 8, io_index);
> +    pci_register_bar(dev, 3, 0x4, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(ide_status_reads, ide_cmd_writes, 1,
> &d->bus[1]);
> +    pci_bar_map(&d->dev, 3, 0, 1, 1, io_index);
> +    pci_register_bar(dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO);
> +    for (i = 0; i<  2; i++) {
> +        BMDMAState *bm =&d->bmdma[i];
> +
> +        d->bus[i].bmdma = bm;
> +        bm->bus = d->bus+i;
> +        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
> +
> +        if (i == 0) {
> +            io_index = cpu_register_io(bmdma_io_reads_0, bmdma_io_writes_0,
> +                                       1, d);
> +        } else {
> +            io_index = cpu_register_io(bmdma_io_reads_1, bmdma_io_writes_1,
> +                                       1, d);
> +        }
> +        pci_bar_map(&d->dev, 4, i * 4 + 0, 0, 1, io_index);
> +
> +        io_index = cpu_register_io(bmdma_addr_reads, bmdma_addr_writes, 4, bm);
> +        pci_bar_map(&d->dev, 4, i * 4 + 4, 4, 4, io_index);
> +    }
>
>       /* TODO: RST# value should be 0 */
>       pci_conf[PCI_INTERRUPT_PIN] = 0x01; // interrupt on pin 1
> diff --git a/hw/ide/piix.c b/hw/ide/piix.c
> index 9223834..0506990 100644
> --- a/hw/ide/piix.c
> +++ b/hw/ide/piix.c
> @@ -68,32 +68,35 @@ static void bmdma_writeb(void *opaque, uint32_t
> addr, uint32_t val)
>       }
>   }
>
> -static void bmdma_map(PCIDevice *pci_dev, int region_num,
> -                    pcibus_t addr, pcibus_t size, int type)
> -{
> -    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
> -    int i;
> +static IOPortWriteFunc * const bmdma_cmd_io_writes[] = {
> +    bmdma_cmd_writeb,
> +    NULL,
> +    NULL,
> +};
>
> -    for(i = 0;i<  2; i++) {
> -        BMDMAState *bm =&d->bmdma[i];
> -        d->bus[i].bmdma = bm;
> -        bm->bus = d->bus+i;
> -        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
> +static IOPortWriteFunc * const bmdma_io_writes[] = {
> +    bmdma_writeb,
> +    NULL,
> +    NULL,
> +};
>
> -        register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
> +static IOPortReadFunc * const bmdma_io_reads[] = {
> +    bmdma_readb,
> +    NULL,
> +    NULL,
> +};
>
> -        register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
> -        register_ioport_read(addr, 4, 1, bmdma_readb, bm);
> +static IOPortWriteFunc * const bmdma_addr_writes[] = {
> +    bmdma_addr_writeb,
> +    bmdma_addr_writew,
> +    bmdma_addr_writel,
> +};
>
> -        register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
> -        register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
> -        register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
> -        register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
> -        register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
> -        register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
> -        addr += 8;
> -    }
> -}
> +static IOPortReadFunc * const bmdma_addr_reads[] = {
> +    bmdma_addr_readb,
> +    bmdma_addr_readw,
> +    bmdma_addr_readl,
> +};
>
>   static void piix3_reset(void *opaque)
>   {
> @@ -119,6 +122,8 @@ static void piix3_reset(void *opaque)
>   static int pci_piix_ide_initfn(PCIIDEState *d)
>   {
>       uint8_t *pci_conf = d->dev.config;
> +    unsigned int i;
> +    int io_index;
>
>       pci_conf[PCI_CLASS_PROG] = 0x80; // legacy ATA mode
>       pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE);
> @@ -126,7 +131,22 @@ static int pci_piix_ide_initfn(PCIIDEState *d)
>
>       qemu_register_reset(piix3_reset, d);
>
> -    pci_register_bar(&d->dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
> +    pci_register_bar(&d->dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO);
> +    for (i = 0; i<  2; i++) {
> +        BMDMAState *bm =&d->bmdma[i];
> +
> +        d->bus[i].bmdma = bm;
> +        bm->bus = d->bus + i;
> +        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
> +        io_index = cpu_register_io(NULL, bmdma_cmd_io_writes, 1, bm);
> +        pci_bar_map(&d->dev, 0, i * 4 + 0, 0, 1, io_index);
> +        io_index = cpu_register_io(NULL, bmdma_io_writes, 3, bm);
> +        pci_bar_map(&d->dev, 0, i * 4 + 1, 1, 3, io_index);
> +        io_index = cpu_register_io(bmdma_io_reads, NULL, 4, bm);
> +        pci_bar_map(&d->dev, 0, i * 4 + 2, 0, 4, io_index);
> +        io_index = cpu_register_io(bmdma_addr_reads, bmdma_addr_writes, 4, bm);
> +        pci_bar_map(&d->dev, 0, i * 4 + 3, 4, 4, io_index);
> +    }
>
>       vmstate_register(&d->dev.qdev, 0,&vmstate_ide_pci, d);
>
> diff --git a/hw/ide/via.c b/hw/ide/via.c
> index a403e8c..d2f5d00 100644
> --- a/hw/ide/via.c
> +++ b/hw/ide/via.c
> @@ -70,32 +70,35 @@ static void bmdma_writeb(void *opaque, uint32_t
> addr, uint32_t val)
>       }
>   }
>
> -static void bmdma_map(PCIDevice *pci_dev, int region_num,
> -                    pcibus_t addr, pcibus_t size, int type)
> -{
> -    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
> -    int i;
> +static IOPortWriteFunc * const bmdma_cmd_io_writes[] = {
> +    bmdma_cmd_writeb,
> +    NULL,
> +    NULL,
> +};
>
> -    for(i = 0;i<  2; i++) {
> -        BMDMAState *bm =&d->bmdma[i];
> -        d->bus[i].bmdma = bm;
> -        bm->bus = d->bus+i;
> -        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
> +static IOPortWriteFunc * const bmdma_io_writes[] = {
> +    bmdma_writeb,
> +    NULL,
> +    NULL,
> +};
>
> -        register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
> +static IOPortReadFunc * const bmdma_io_reads[] = {
> +    bmdma_readb,
> +    NULL,
> +    NULL,
> +};
>
> -        register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
> -        register_ioport_read(addr, 4, 1, bmdma_readb, bm);
> +static IOPortWriteFunc * const bmdma_addr_writes[] = {
> +    bmdma_addr_writeb,
> +    bmdma_addr_writew,
> +    bmdma_addr_writel,
> +};
>
> -        register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
> -        register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
> -        register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
> -        register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
> -        register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
> -        register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
> -        addr += 8;
> -    }
> -}
> +static IOPortReadFunc * const bmdma_addr_reads[] = {
> +    bmdma_addr_readb,
> +    bmdma_addr_readw,
> +    bmdma_addr_readl,
> +};
>
>   static void via_reset(void *opaque)
>   {
> @@ -144,6 +147,8 @@ static int vt82c686b_ide_initfn(PCIDevice *dev)
>   {
>       PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);;
>       uint8_t *pci_conf = d->dev.config;
> +    unsigned int i;
> +    int io_index;
>
>       pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_VIA);
>       pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIA_IDE);
> @@ -154,8 +159,22 @@ static int vt82c686b_ide_initfn(PCIDevice *dev)
>       pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
>
>       qemu_register_reset(via_reset, d);
> -    pci_register_bar((PCIDevice *)d, 4, 0x10,
> -                           PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
> +    pci_register_bar((PCIDevice *)d, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO);
> +    for (i = 0; i<  2; i++) {
> +        BMDMAState *bm =&d->bmdma[i];
> +
> +        d->bus[i].bmdma = bm;
> +        bm->bus = d->bus + i;
> +        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
> +        io_index = cpu_register_io(NULL, bmdma_cmd_io_writes, 1, bm);
> +        pci_bar_map(&d->dev, 0, i * 4 + 0, 0, 1, io_index);
> +        io_index = cpu_register_io(NULL, bmdma_io_writes, 3, bm);
> +        pci_bar_map(&d->dev, 0, i * 4 + 1, 1, 3, io_index);
> +        io_index = cpu_register_io(bmdma_io_reads, NULL, 4, bm);
> +        pci_bar_map(&d->dev, 0, i * 4 + 2, 0, 4, io_index);
> +        io_index = cpu_register_io(bmdma_addr_reads, bmdma_addr_writes, 4, bm);
> +        pci_bar_map(&d->dev, 0, i * 4 + 3, 4, 4, io_index);
> +    }
>
>       vmstate_register(&dev->qdev, 0,&vmstate_ide_pci, d);
>
> diff --git a/hw/isa.h b/hw/isa.h
> index aaf0272..6fba4ac 100644
> --- a/hw/isa.h
> +++ b/hw/isa.h
> @@ -33,6 +33,7 @@ ISADevice *isa_create_simple(const char *name);
>   extern target_phys_addr_t isa_mem_base;
>
>   void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size, int be);
> +int pci_isa_mmio_init(int be);
>
>   /* dma.c */
>   int DMA_get_channel_mode (int nchan);
> diff --git a/hw/isa_mmio.c b/hw/isa_mmio.c
> index 66bdd2c..3b2de4a 100644
> --- a/hw/isa_mmio.c
> +++ b/hw/isa_mmio.c
> @@ -125,7 +125,7 @@ static CPUReadMemoryFunc * const isa_mmio_read_le[] = {
>
>   static int isa_mmio_iomemtype = 0;
>
> -void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size, int be)
> +static int isa_mmio_memtype(int be)
>   {
>       if (!isa_mmio_iomemtype) {
>           if (be) {
> @@ -138,5 +138,18 @@ void isa_mmio_init(target_phys_addr_t base,
> target_phys_addr_t size, int be)
>                                                           NULL);
>           }
>       }
> -    cpu_register_physical_memory(base, size, isa_mmio_iomemtype);
> +    return isa_mmio_iomemtype;
> +}
> +
> +void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size, int be)
> +{
> +    int isa;
> +
> +    isa = isa_mmio_memtype(be);
> +    cpu_register_physical_memory(base, size, isa);
> +}
> +
> +int pci_isa_mmio_init(int be)
> +{
> +    return isa_mmio_memtype(be);
>   }
> diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
> index bd7b661..32de5d1 100644
> --- a/hw/lsi53c895a.c
> +++ b/hw/lsi53c895a.c
> @@ -186,7 +186,6 @@ typedef struct {
>       PCIDevice dev;
>       int mmio_io_addr;
>       int ram_io_addr;
> -    uint32_t script_ram_base;
>
>       int carry; /* ??? Should this be an a visible register somewhere?  */
>       int sense;
> @@ -390,10 +389,6 @@ static inline uint32_t read_dword(LSIState *s,
> uint32_t addr)
>   {
>       uint32_t buf;
>
> -    /* Optimize reading from SCRIPTS RAM.  */
> -    if ((addr&  0xffffe000) == s->script_ram_base) {
> -        return s->script_ram[(addr&  0x1fff)>>  2];
> -    }
>       cpu_physical_memory_read(addr, (uint8_t *)&buf, 4);
>       return cpu_to_le32(buf);
>   }
> @@ -2004,39 +1999,17 @@ static void lsi_io_writel(void *opaque,
> uint32_t addr, uint32_t val)
>       lsi_reg_writeb(s, addr + 3, (val>>  24)&  0xff);
>   }
>
> -static void lsi_io_mapfunc(PCIDevice *pci_dev, int region_num,
> -                           pcibus_t addr, pcibus_t size, int type)
> -{
> -    LSIState *s = DO_UPCAST(LSIState, dev, pci_dev);
> -
> -    DPRINTF("Mapping IO at %08"FMT_PCIBUS"\n", addr);
> -
> -    register_ioport_write(addr, 256, 1, lsi_io_writeb, s);
> -    register_ioport_read(addr, 256, 1, lsi_io_readb, s);
> -    register_ioport_write(addr, 256, 2, lsi_io_writew, s);
> -    register_ioport_read(addr, 256, 2, lsi_io_readw, s);
> -    register_ioport_write(addr, 256, 4, lsi_io_writel, s);
> -    register_ioport_read(addr, 256, 4, lsi_io_readl, s);
> -}
> -
> -static void lsi_ram_mapfunc(PCIDevice *pci_dev, int region_num,
> -                            pcibus_t addr, pcibus_t size, int type)
> -{
> -    LSIState *s = DO_UPCAST(LSIState, dev, pci_dev);
> -
> -    DPRINTF("Mapping ram at %08"FMT_PCIBUS"\n", addr);
> -    s->script_ram_base = addr;
> -    cpu_register_physical_memory(addr + 0, 0x2000, s->ram_io_addr);
> -}
> -
> -static void lsi_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
> -                             pcibus_t addr, pcibus_t size, int type)
> -{
> -    LSIState *s = DO_UPCAST(LSIState, dev, pci_dev);
> +static IOPortWriteFunc * const lsi_io_writes[] = {
> +    lsi_io_writeb,
> +    lsi_io_writew,
> +    lsi_io_writel,
> +};
>
> -    DPRINTF("Mapping registers at %08"FMT_PCIBUS"\n", addr);
> -    cpu_register_physical_memory(addr + 0, 0x400, s->mmio_io_addr);
> -}
> +static IOPortReadFunc * const lsi_io_reads[] = {
> +    lsi_io_readb,
> +    lsi_io_readw,
> +    lsi_io_readl,
> +};
>
>   static void lsi_scsi_reset(DeviceState *dev)
>   {
> @@ -2153,6 +2126,7 @@ static int lsi_scsi_init(PCIDevice *dev)
>   {
>       LSIState *s = DO_UPCAST(LSIState, dev, dev);
>       uint8_t *pci_conf;
> +    int io_index;
>
>       pci_conf = s->dev.config;
>
> @@ -2177,12 +2151,16 @@ static int lsi_scsi_init(PCIDevice *dev)
>                                               lsi_ram_writefn, s);
>
>       /* TODO: use dev and get rid of cast below */
> -    pci_register_bar((struct PCIDevice *)s, 0, 256,
> -                           PCI_BASE_ADDRESS_SPACE_IO, lsi_io_mapfunc);
> +    pci_register_bar((struct PCIDevice *)s, 0, 256, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(lsi_io_reads, lsi_io_writes, 256, s);
> +    pci_bar_map((struct PCIDevice *)s, 0, 0, 0, 256, io_index);
> +
>       pci_register_bar((struct PCIDevice *)s, 1, 0x400,
> -                           PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_mmio_mapfunc);
> +                           PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    pci_bar_map((struct PCIDevice *)s, 1, 0, 0, 0x400, s->mmio_io_addr);
>       pci_register_bar((struct PCIDevice *)s, 2, 0x2000,
> -                           PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc);
> +                           PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    pci_bar_map((struct PCIDevice *)s, 2, 0, 0, 0x2000, s->ram_io_addr);
>       QTAILQ_INIT(&s->queue);
>
>       scsi_bus_new(&s->bus,&dev->qdev, 1, LSI_MAX_DEVS, lsi_command_complete);
> diff --git a/hw/macio.c b/hw/macio.c
> index e92e82a..653b4df 100644
> --- a/hw/macio.c
> +++ b/hw/macio.c
> @@ -27,83 +27,16 @@
>   #include "pci.h"
>   #include "escc.h"
>
> -typedef struct macio_state_t macio_state_t;
> -struct macio_state_t {
> -    int is_oldworld;
> -    int pic_mem_index;
> -    int dbdma_mem_index;
> -    int cuda_mem_index;
> -    int escc_mem_index;
> -    void *nvram;
> -    int nb_ide;
> -    int ide_mem_index[4];
> -};
> -
> -static void macio_map (PCIDevice *pci_dev, int region_num,
> -                       pcibus_t addr, pcibus_t size, int type)
> -{
> -    macio_state_t *macio_state;
> -    int i;
> -
> -    macio_state = (macio_state_t *)(pci_dev + 1);
> -    if (macio_state->pic_mem_index>= 0) {
> -        if (macio_state->is_oldworld) {
> -            /* Heathrow PIC */
> -            cpu_register_physical_memory(addr + 0x00000, 0x1000,
> -                                         macio_state->pic_mem_index);
> -        } else {
> -            /* OpenPIC */
> -            cpu_register_physical_memory(addr + 0x40000, 0x40000,
> -                                         macio_state->pic_mem_index);
> -        }
> -    }
> -    if (macio_state->dbdma_mem_index>= 0) {
> -        cpu_register_physical_memory(addr + 0x08000, 0x1000,
> -                                     macio_state->dbdma_mem_index);
> -    }
> -    if (macio_state->escc_mem_index>= 0) {
> -        cpu_register_physical_memory(addr + 0x13000, ESCC_SIZE<<  4,
> -                                     macio_state->escc_mem_index);
> -    }
> -    if (macio_state->cuda_mem_index>= 0) {
> -        cpu_register_physical_memory(addr + 0x16000, 0x2000,
> -                                     macio_state->cuda_mem_index);
> -    }
> -    for (i = 0; i<  macio_state->nb_ide; i++) {
> -        if (macio_state->ide_mem_index[i]>= 0) {
> -            cpu_register_physical_memory(addr + 0x1f000 + (i * 0x1000), 0x1000,
> -                                         macio_state->ide_mem_index[i]);
> -        }
> -    }
> -    if (macio_state->nvram != NULL)
> -        macio_nvram_map(macio_state->nvram, addr + 0x60000);
> -}
> -
>   void macio_init (PCIBus *bus, int device_id, int is_oldworld, int
> pic_mem_index,
> -                 int dbdma_mem_index, int cuda_mem_index, void *nvram,
> -                 int nb_ide, int *ide_mem_index, int escc_mem_index)
> +                 int dbdma_mem_index, int cuda_mem_index, int nvram_size,
> +                 int nvram_mem_index, int nb_ide, int *ide_mem_index,
> +                 int escc_mem_index)
>   {
>       PCIDevice *d;
> -    macio_state_t *macio_state;
>       int i;
>
> -    d = pci_register_device(bus, "macio",
> -                            sizeof(PCIDevice) + sizeof(macio_state_t),
> -                            -1, NULL, NULL);
> -    macio_state = (macio_state_t *)(d + 1);
> -    macio_state->is_oldworld = is_oldworld;
> -    macio_state->pic_mem_index = pic_mem_index;
> -    macio_state->dbdma_mem_index = dbdma_mem_index;
> -    macio_state->cuda_mem_index = cuda_mem_index;
> -    macio_state->escc_mem_index = escc_mem_index;
> -    macio_state->nvram = nvram;
> -    if (nb_ide>  4)
> -        nb_ide = 4;
> -    macio_state->nb_ide = nb_ide;
> -    for (i = 0; i<  nb_ide; i++)
> -        macio_state->ide_mem_index[i] = ide_mem_index[i];
> -    for (; i<  4; i++)
> -        macio_state->ide_mem_index[i] = -1;
> +    d = pci_register_device(bus, "macio", sizeof(PCIDevice), -1, NULL, NULL);
> +
>       /* Note: this code is strongly inspirated from the corresponding code
>          in PearPC */
>
> @@ -114,6 +47,32 @@ void macio_init (PCIBus *bus, int device_id, int
> is_oldworld, int pic_mem_index,
>
>       d->config[0x3d] = 0x01; // interrupt on pin 1
>
> -    pci_register_bar(d, 0, 0x80000,
> -                           PCI_BASE_ADDRESS_SPACE_MEMORY, macio_map);
> +    pci_register_bar(d, 0, 0x80000, PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    if (pic_mem_index>= 0) {
> +        if (is_oldworld) {
> +            /* Heathrow PIC */
> +            pci_bar_map(d, 0, 0, 0x1000, 0, pic_mem_index);
> +        } else {
> +            /* OpenPIC */
> +            pci_bar_map(d, 0, 0, 0x40000, 0x40000, pic_mem_index);
> +        }
> +    }
> +    if (dbdma_mem_index>= 0) {
> +        pci_bar_map(d, 0, 1, 0x8000, 0x1000, dbdma_mem_index);
> +    }
> +    if (escc_mem_index>= 0) {
> +        pci_bar_map(d, 0, 2, 0x13000, ESCC_SIZE<<  4, escc_mem_index);
> +    }
> +    if (cuda_mem_index>= 0) {
> +        pci_bar_map(d, 0, 3, 0x16000, 0x2000, cuda_mem_index);
> +    }
> +    for (i = 0; i<  nb_ide; i++) {
> +        if (ide_mem_index[i]>= 0) {
> +            pci_bar_map(d, 0, 4 + i, 0x1f000 + (i * 0x1000), 0x1000,
> +                        ide_mem_index[i]);
> +        }
> +    }
> +    if (nvram_mem_index>= 0) {
> +        pci_bar_map(d, 0, 4 + nb_ide, 0x60000, nvram_size, nvram_mem_index);
> +    }
>   }
> diff --git a/hw/ne2000.c b/hw/ne2000.c
> index 78fe14f..7598e76 100644
> --- a/hw/ne2000.c
> +++ b/hw/ne2000.c
> @@ -464,6 +464,18 @@ uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
>       return ret;
>   }
>
> +static IOPortWriteFunc * const ne2000_io_writes[] = {
> +    ne2000_ioport_write,
> +    NULL,
> +    NULL,
> +};
> +
> +static IOPortReadFunc * const ne2000_io_reads[] = {
> +    ne2000_ioport_read,
> +    NULL,
> +    NULL,
> +};
> +
>   static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr,
>                                        uint32_t val)
>   {
> @@ -611,6 +623,18 @@ static uint32_t ne2000_asic_ioport_readl(void
> *opaque, uint32_t addr)
>       return ret;
>   }
>
> +static IOPortWriteFunc * const ne2000_asic_io_writes[] = {
> +    ne2000_asic_ioport_write,
> +    ne2000_asic_ioport_write,
> +    ne2000_asic_ioport_writel,
> +};
> +
> +static IOPortReadFunc * const ne2000_asic_io_reads[] = {
> +    ne2000_asic_ioport_read,
> +    ne2000_asic_ioport_read,
> +    ne2000_asic_ioport_readl,
> +};
> +
>   void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val)
>   {
>       /* nothing to do (end of reset pulse) */
> @@ -623,6 +647,18 @@ uint32_t ne2000_reset_ioport_read(void *opaque,
> uint32_t addr)
>       return 0;
>   }
>
> +static IOPortWriteFunc * const ne2000_reset_io_writes[] = {
> +    ne2000_reset_ioport_write,
> +    NULL,
> +    NULL,
> +};
> +
> +static IOPortReadFunc * const ne2000_reset_io_reads[] = {
> +    ne2000_reset_ioport_read,
> +    NULL,
> +    NULL,
> +};
> +
>   static int ne2000_post_load(void* opaque, int version_id)
>   {
>       NE2000State* s = opaque;
> @@ -678,26 +714,6 @@ static const VMStateDescription vmstate_pci_ne2000 = {
>   /***********************************************************/
>   /* PCI NE2000 definitions */
>
> -static void ne2000_map(PCIDevice *pci_dev, int region_num,
> -                       pcibus_t addr, pcibus_t size, int type)
> -{
> -    PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
> -    NE2000State *s =&d->ne2000;
> -
> -    register_ioport_write(addr, 16, 1, ne2000_ioport_write, s);
> -    register_ioport_read(addr, 16, 1, ne2000_ioport_read, s);
> -
> -    register_ioport_write(addr + 0x10, 1, 1, ne2000_asic_ioport_write, s);
> -    register_ioport_read(addr + 0x10, 1, 1, ne2000_asic_ioport_read, s);
> -    register_ioport_write(addr + 0x10, 2, 2, ne2000_asic_ioport_write, s);
> -    register_ioport_read(addr + 0x10, 2, 2, ne2000_asic_ioport_read, s);
> -    register_ioport_write(addr + 0x10, 4, 4, ne2000_asic_ioport_writel, s);
> -    register_ioport_read(addr + 0x10, 4, 4, ne2000_asic_ioport_readl, s);
> -
> -    register_ioport_write(addr + 0x1f, 1, 1, ne2000_reset_ioport_write, s);
> -    register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
> -}
> -
>   static void ne2000_cleanup(VLANClientState *nc)
>   {
>       NE2000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
> @@ -718,6 +734,7 @@ static int pci_ne2000_init(PCIDevice *pci_dev)
>       PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
>       NE2000State *s;
>       uint8_t *pci_conf;
> +    int io_index;
>
>       pci_conf = d->dev.config;
>       pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REALTEK);
> @@ -727,9 +744,14 @@ static int pci_ne2000_init(PCIDevice *pci_dev)
>       /* TODO: RST# value should be 0. PCI spec 6.2.4 */
>       pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
>
> -    pci_register_bar(&d->dev, 0, 0x100,
> -                           PCI_BASE_ADDRESS_SPACE_IO, ne2000_map);
>       s =&d->ne2000;
> +    pci_register_bar(&d->dev, 0, 0x100, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(ne2000_io_reads, ne2000_io_writes, 16, s);
> +    pci_bar_map(&d->dev, 0, 0, 0, 16, io_index);
> +    io_index = cpu_register_io(ne2000_asic_io_reads,
> ne2000_asic_io_writes, 4, s);
> +    pci_bar_map(&d->dev, 0, 1, 0x10, 4, io_index);
> +    io_index = cpu_register_io(ne2000_reset_io_reads,
> ne2000_reset_io_writes, 1, s);
> +    pci_bar_map(&d->dev, 0, 2, 0x1f, 1, io_index);
>       s->irq = d->dev.irq[0];
>
>       qemu_macaddr_default_if_unset(&s->c.macaddr);
> diff --git a/hw/openpic.c b/hw/openpic.c
> index 2b4cb00..ed1903d 100644
> --- a/hw/openpic.c
> +++ b/hw/openpic.c
> @@ -1013,34 +1013,6 @@ static CPUReadMemoryFunc * const openpic_read[] = {
>       &openpic_readl,
>   };
>
> -static void openpic_map(PCIDevice *pci_dev, int region_num,
> -                        pcibus_t addr, pcibus_t size, int type)
> -{
> -    openpic_t *opp;
> -
> -    DPRINTF("Map OpenPIC\n");
> -    opp = (openpic_t *)pci_dev;
> -    /* Global registers */
> -    DPRINTF("Register OPENPIC gbl   %08x =>  %08x\n",
> -            addr + 0x1000, addr + 0x1000 + 0x100);
> -    /* Timer registers */
> -    DPRINTF("Register OPENPIC timer %08x =>  %08x\n",
> -            addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR);
> -    /* Interrupt source registers */
> -    DPRINTF("Register OPENPIC src   %08x =>  %08x\n",
> -            addr + 0x10000, addr + 0x10000 + 0x20 * (OPENPIC_EXT_IRQ + 2));
> -    /* Per CPU registers */
> -    DPRINTF("Register OPENPIC dst   %08x =>  %08x\n",
> -            addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU);
> -    cpu_register_physical_memory(addr, 0x40000, opp->mem_index);
> -#if 0 // Don't implement ISU for now
> -    opp_io_memory = cpu_register_io_memory(openpic_src_read,
> -                                           openpic_src_write);
> -    cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
> -                                 opp_io_memory);
> -#endif
> -}
> -
>   static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
>   {
>       unsigned int i;
> @@ -1199,12 +1171,14 @@ qemu_irq *openpic_init (PCIBus *bus, int
> *pmem_index, int nb_cpus,
>
>           /* Register I/O spaces */
>           pci_register_bar((PCIDevice *)opp, 0, 0x40000,
> -                               PCI_BASE_ADDRESS_SPACE_MEMORY,&openpic_map);
> +                               PCI_BASE_ADDRESS_SPACE_MEMORY);
>       } else {
>           opp = qemu_mallocz(sizeof(openpic_t));
>       }
> -    opp->mem_index = cpu_register_io_memory(openpic_read,
> -                                            openpic_write, opp);
> +    opp->mem_index = cpu_register_io_memory(openpic_read, openpic_write, opp);
> +    if (bus) {
> +        pci_bar_map((PCIDevice *)opp, 0, 0, 0x40000, 0, opp->mem_index);
> +    }
>
>       //    isu_base&= 0xFFFC0000;
>       opp->nb_cpus = nb_cpus;
> diff --git a/hw/pci.c b/hw/pci.c
> index a7ff566..fd4b1bb 100644
> --- a/hw/pci.c
> +++ b/hw/pci.c
> @@ -681,19 +681,28 @@ static target_phys_addr_t pci_to_cpu_addr(PCIBus *bus,
>   static void pci_unregister_io_regions(PCIDevice *pci_dev)
>   {
>       PCIIORegion *r;
> -    int i;
> +    PCIIOSubRegion *s;
> +    int i, j;
>
>       for(i = 0; i<  PCI_NUM_REGIONS; i++) {
>           r =&pci_dev->io_regions[i];
>           if (!r->size || r->addr == PCI_BAR_UNMAPPED)
>               continue;
> -        if (r->type == PCI_BASE_ADDRESS_SPACE_IO) {
> -            isa_unassign_ioport(r->addr, r->filtered_size);
> -        } else {
> -            cpu_register_physical_memory(pci_to_cpu_addr(pci_dev->bus,
> -                                                         r->addr),
> -                                         r->filtered_size,
> -                                         IO_MEM_UNASSIGNED);
> +
> +        for (j = 0; j<  PCI_NUM_SUBREGIONS; j++) {
> +            s =&r->subregions[j];
> +
> +            if (!s->size) {
> +                continue;
> +            }
> +            if (r->type == PCI_BASE_ADDRESS_SPACE_IO) {
> +                isa_unassign_ioport(r->addr + s->offset, s->filtered_size);
> +            } else {
> +                cpu_register_physical_memory(pci_to_cpu_addr(pci_dev->bus,
> +                                                         r->addr + s->offset),
> +                                             s->filtered_size,
> +                                             IO_MEM_UNASSIGNED);
> +            }
>           }
>       }
>   }
> @@ -716,8 +725,7 @@ static int pci_unregister_device(DeviceState *dev)
>   }
>
>   void pci_register_bar(PCIDevice *pci_dev, int region_num,
> -                            pcibus_t size, int type,
> -                            PCIMapIORegionFunc *map_func)
> +                      pcibus_t size, int type)
>   {
>       PCIIORegion *r;
>       uint32_t addr;
> @@ -735,9 +743,7 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
>       r =&pci_dev->io_regions[region_num];
>       r->addr = PCI_BAR_UNMAPPED;
>       r->size = size;
> -    r->filtered_size = size;
>       r->type = type;
> -    r->map_func = map_func;
>
>       wmask = ~(size - 1);
>       addr = pci_bar(pci_dev, region_num);
> @@ -756,6 +762,23 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
>       }
>   }
>
> +void pci_bar_map(PCIDevice *pci_dev, int region_num, int subregion_num,
> +                 pcibus_t offset, pcibus_t size, int ix)
> +{
> +    PCIIOSubRegion *s;
> +
> +    if ((unsigned int)region_num>= PCI_NUM_REGIONS ||
> +        (unsigned int)subregion_num>= PCI_NUM_SUBREGIONS) {
> +        return;
> +    }
> +
> +    s =&pci_dev->io_regions[region_num].subregions[subregion_num];
> +
> +    s->offset = offset;
> +    s->size = size;
> +    s->ix = ix;
> +}
> +
>   static uint32_t pci_config_get_io_base(PCIDevice *d,
>                                          uint32_t base, uint32_t base_upper16)
>   {
> @@ -928,8 +951,9 @@ static pcibus_t pci_bar_address(PCIDevice *d,
>   static void pci_update_mappings(PCIDevice *d)
>   {
>       PCIIORegion *r;
> -    int i;
> -    pcibus_t new_addr, filtered_size;
> +    PCIIOSubRegion *s;
> +    int i, j;
> +    pcibus_t bar_addr, new_addr, filtered_size;
>
>       for(i = 0; i<  PCI_NUM_REGIONS; i++) {
>           r =&d->io_regions[i];
> @@ -938,54 +962,71 @@ static void pci_update_mappings(PCIDevice *d)
>           if (!r->size)
>               continue;
>
> -        new_addr = pci_bar_address(d, i, r->type, r->size);
> +        bar_addr = pci_bar_address(d, i, r->type, r->size);
>
> -        /* bridge filtering */
> -        filtered_size = r->size;
> -        if (new_addr != PCI_BAR_UNMAPPED) {
> -            pci_bridge_filter(d,&new_addr,&filtered_size, r->type);
> -        }
> +        for (j = 0; j<  PCI_NUM_SUBREGIONS; j++) {
> +            s =&r->subregions[j];
>
> -        /* This bar isn't changed */
> -        if (new_addr == r->addr&&  filtered_size == r->filtered_size)
> -            continue;
> +            /* this region isn't registered */
> +            if (!s->size) {
> +                continue;
> +            }
>
> -        /* now do the real mapping */
> -        if (r->addr != PCI_BAR_UNMAPPED) {
> -            if (r->type&  PCI_BASE_ADDRESS_SPACE_IO) {
> -                int class;
> -                /* NOTE: specific hack for IDE in PC case:
> -                   only one byte must be mapped. */
> -                class = pci_get_word(d->config + PCI_CLASS_DEVICE);
> -                if (class == 0x0101&&  r->size == 4) {
> -                    isa_unassign_ioport(r->addr + 2, 1);
> +            new_addr = bar_addr + s->offset;
> +            /* bridge filtering */
> +            filtered_size = s->size;
> +            if (bar_addr != PCI_BAR_UNMAPPED) {
> +                pci_bridge_filter(d,&new_addr,&filtered_size, r->type);
> +            }
> +
> +            /* This bar isn't changed */
> +            if (new_addr == r->addr + s->offset&&
> +                filtered_size == s->filtered_size)
> +                continue;
> +
> +            /* now do the real mapping */
> +            if (r->addr != PCI_BAR_UNMAPPED) {
> +                if (r->type&  PCI_BASE_ADDRESS_SPACE_IO) {
> +                    int class;
> +                    /* NOTE: specific hack for IDE in PC case:
> +                       only one byte must be mapped. */
> +                    class = pci_get_word(d->config + PCI_CLASS_DEVICE);
> +                    if (class == 0x0101&&  r->size == 4) {
> +                        isa_unassign_ioport(r->addr + s->offset + 2, 1);
> +                    } else {
> +                        isa_unassign_ioport(r->addr + s->offset,
> +                                            s->filtered_size);
> +                    }
>                   } else {
> -                    isa_unassign_ioport(r->addr, r->filtered_size);
> +                    cpu_register_physical_memory(pci_to_cpu_addr(d->bus,
> +                                                                 r->addr +
> +                                                                 s->offset),
> +                                                 s->filtered_size,
> +                                                 IO_MEM_UNASSIGNED);
> +                    qemu_unregister_coalesced_mmio(r->addr + s->offset,
> +                                                   s->filtered_size);
>                   }
> -            } else {
> -                cpu_register_physical_memory(pci_to_cpu_addr(d->bus, r->addr),
> -                                             r->filtered_size,
> -                                             IO_MEM_UNASSIGNED);
> -                qemu_unregister_coalesced_mmio(r->addr, r->filtered_size);
>               }
> -        }
> -        r->addr = new_addr;
> -        r->filtered_size = filtered_size;
> -        if (r->addr != PCI_BAR_UNMAPPED) {
> -            /*
> -             * TODO: currently almost all the map funcions assumes
> -             * filtered_size == size and addr&  ~(size - 1) == addr.
> -             * However with bridge filtering, they aren't always true.
> -             * Teach them such cases, such that filtered_size<  size and
> -             * addr&  (size - 1) != 0.
> -             */
> -            if (r->type&  PCI_BASE_ADDRESS_SPACE_IO) {
> -                r->map_func(d, i, r->addr, r->filtered_size, r->type);
> -            } else {
> -                r->map_func(d, i, pci_to_cpu_addr(d->bus, r->addr),
> -                            r->filtered_size, r->type);
> +            s->filtered_size = filtered_size;
> +            if (new_addr != PCI_BAR_UNMAPPED) {
> +                /*
> +                 * TODO: currently almost all the map funcions assumes
> +                 * filtered_size == size and addr&  ~(size - 1) == addr.
> +                 * However with bridge filtering, they aren't always true.
> +                 * Teach them such cases, such that filtered_size<  size and
> +                 * addr&  (size - 1) != 0.
> +                 */
> +                if (r->type&  PCI_BASE_ADDRESS_SPACE_IO) {
> +                    cpu_map_io(new_addr, s->ix);
> +                } else {
> +                    cpu_register_physical_memory(pci_to_cpu_addr(d->bus,
> +                                                                 new_addr),
> +                                                 s->filtered_size,
> +                                                 s->ix);
> +                }
>               }
>           }
> +        r->addr = bar_addr;
>       }
>   }
>
> @@ -1704,11 +1745,6 @@ static uint8_t
> pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id,
>       return next;
>   }
>
> -static void pci_map_option_rom(PCIDevice *pdev, int region_num,
> pcibus_t addr, pcibus_t size, int type)
> -{
> -    cpu_register_physical_memory(addr, size, pdev->rom_offset);
> -}
> -
>   /* Add an option rom for the device */
>   static int pci_add_option_rom(PCIDevice *pdev)
>   {
> @@ -1761,8 +1797,8 @@ static int pci_add_option_rom(PCIDevice *pdev)
>       load_image(path, ptr);
>       qemu_free(path);
>
> -    pci_register_bar(pdev, PCI_ROM_SLOT, size,
> -                     0, pci_map_option_rom);
> +    pci_register_bar(pdev, PCI_ROM_SLOT, size, 0);
> +    pci_bar_map(pdev, PCI_ROM_SLOT, 0, 0, size, pdev->rom_offset);
>
>       return 0;
>   }
> diff --git a/hw/pci.h b/hw/pci.h
> index 3a15bd4..3648105 100644
> --- a/hw/pci.h
> +++ b/hw/pci.h
> @@ -80,13 +80,21 @@ typedef void PCIMapIORegionFunc(PCIDevice
> *pci_dev, int region_num,
>                                   pcibus_t addr, pcibus_t size, int type);
>   typedef int PCIUnregisterFunc(PCIDevice *pci_dev);
>
> +typedef struct PCIIOSubRegion {
> +    pcibus_t offset; /* offset to BAR start. -1 means not mapped */
> +    pcibus_t size;
> +    pcibus_t filtered_size;
> +    int ix;
> +} PCIIOSubRegion;
> +
> +#define PCI_NUM_SUBREGIONS 8
> +
>   typedef struct PCIIORegion {
>       pcibus_t addr; /* current PCI mapping address. -1 means not mapped */
>   #define PCI_BAR_UNMAPPED (~(pcibus_t)0)
>       pcibus_t size;
> -    pcibus_t filtered_size;
>       uint8_t type;
> -    PCIMapIORegionFunc *map_func;
> +    PCIIOSubRegion subregions[PCI_NUM_SUBREGIONS];
>   } PCIIORegion;
>
>   #define PCI_ROM_SLOT 6
> @@ -175,8 +183,10 @@ PCIDevice *pci_register_device(PCIBus *bus, const
> char *name,
>                                  PCIConfigWriteFunc *config_write);
>
>   void pci_register_bar(PCIDevice *pci_dev, int region_num,
> -                            pcibus_t size, int type,
> -                            PCIMapIORegionFunc *map_func);
> +                      pcibus_t size, int type);
> +
> +void pci_bar_map(PCIDevice *pci_dev, int region_num, int subregion_num,
> +                 pcibus_t offset, pcibus_t size, int ix);
>
>   int pci_add_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
>   int pci_add_capability_at_offset(PCIDevice *pci_dev, uint8_t cap_id,
> diff --git a/hw/pcnet.c b/hw/pcnet.c
> index 5e63eb5..4782717 100644
> --- a/hw/pcnet.c
> +++ b/hw/pcnet.c
> @@ -1615,6 +1615,18 @@ static uint32_t pcnet_aprom_readb(void *opaque,
> uint32_t addr)
>       return val;
>   }
>
> +static IOPortWriteFunc * const pcnet_aprom_writes[] = {
> +    pcnet_aprom_writeb,
> +    NULL,
> +    NULL,
> +};
> +
> +static IOPortReadFunc * const pcnet_aprom_reads[] = {
> +    pcnet_aprom_readb,
> +    NULL,
> +    NULL,
> +};
> +
>   void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
>   {
>       PCNetState *s = opaque;
> @@ -1726,24 +1738,17 @@ static uint32_t pcnet_ioport_readl(void
> *opaque, uint32_t addr)
>       return val;
>   }
>
> -static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num,
> -                             pcibus_t addr, pcibus_t size, int type)
> -{
> -    PCNetState *d =&DO_UPCAST(PCIPCNetState, pci_dev, pci_dev)->state;
> -
> -#ifdef PCNET_DEBUG_IO
> -    printf("pcnet_ioport_map addr=0x%04"FMT_PCIBUS" size=0x%04"FMT_PCIBUS"\n",
> -           addr, size);
> -#endif
> -
> -    register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d);
> -    register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d);
> +static IOPortWriteFunc * const pcnet_ioport_writes[] = {
> +    NULL,
> +    pcnet_ioport_writew,
> +    pcnet_ioport_writel,
> +};
>
> -    register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d);
> -    register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d);
> -    register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d);
> -    register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d);
> -}
> +static IOPortReadFunc * const pcnet_ioport_reads[] = {
> +    NULL,
> +    pcnet_ioport_readw,
> +    pcnet_ioport_readl,
> +};
>
>   static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr,
> uint32_t val)
>   {
> @@ -1915,19 +1920,6 @@ static CPUReadMemoryFunc * const pcnet_mmio_read[] = {
>       &pcnet_mmio_readl
>   };
>
> -static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num,
> -                            pcibus_t addr, pcibus_t size, int type)
> -{
> -    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
> -
> -#ifdef PCNET_DEBUG_IO
> -    printf("pcnet_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n",
> -           addr, size);
> -#endif
> -
> -    cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE,
> d->state.mmio_index);
> -}
> -
>   static void pci_physical_memory_write(void *dma_opaque,
> target_phys_addr_t addr,
>                                         uint8_t *buf, int len, int do_bswap)
>   {
> @@ -1971,6 +1963,7 @@ static int pci_pcnet_init(PCIDevice *pci_dev)
>       PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
>       PCNetState *s =&d->state;
>       uint8_t *pci_conf;
> +    int io_index;
>
>   #if 0
>       printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
> @@ -2011,10 +2004,15 @@ static int pci_pcnet_init(PCIDevice *pci_dev)
>
>       /* TODO: use pci_dev, avoid cast below. */
>       pci_register_bar((PCIDevice *)d, 0, PCNET_IOPORT_SIZE,
> -                           PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map);
> +                           PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(pcnet_aprom_reads, pcnet_aprom_writes, 16, s);
> +    pci_bar_map((PCIDevice *)d, 0, 0, 0, 16, io_index);
> +    io_index = cpu_register_io(pcnet_ioport_reads, pcnet_ioport_writes, 16, s);
> +    pci_bar_map((PCIDevice *)d, 0, 1, 0x10, 16, io_index);
>
>       pci_register_bar((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE,
> -                           PCI_BASE_ADDRESS_SPACE_MEMORY, pcnet_mmio_map);
> +                           PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    pci_bar_map((PCIDevice *)d, 1, 0, 0, PCNET_PNPMMIO_SIZE, s->mmio_index);
>
>       s->irq = pci_dev->irq[0];
>       s->phys_mem_read = pci_physical_memory_read;
> diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h
> index 89f96bb..6b3e27f 100644
> --- a/hw/ppc_mac.h
> +++ b/hw/ppc_mac.h
> @@ -46,8 +46,9 @@ void cuda_init (int *cuda_mem_index, qemu_irq irq);
>
>   /* MacIO */
>   void macio_init (PCIBus *bus, int device_id, int is_oldworld, int
> pic_mem_index,
> -                 int dbdma_mem_index, int cuda_mem_index, void *nvram,
> -                 int nb_ide, int *ide_mem_index, int escc_mem_index);
> +                 int dbdma_mem_index, int cuda_mem_index, int nvram_size,
> +                 int nvram_mem_index, int nb_ide, int *ide_mem_index,
> +                 int escc_mem_index);
>
>   /* Heathrow PIC */
>   qemu_irq *heathrow_pic_init(int *pmem_index,
> diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
> index fbba9b6..75fef3c 100644
> --- a/hw/ppc_newworld.c
> +++ b/hw/ppc_newworld.c
> @@ -383,7 +383,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
>       adb_mouse_init(&adb_bus);
>
>       macio_init(pci_bus, PCI_DEVICE_ID_APPLE_UNI_N_KEYL, 0, pic_mem_index,
> -               dbdma_mem_index, cuda_mem_index, NULL, 3, ide_mem_index,
> +               dbdma_mem_index, cuda_mem_index, -1, 0, 3, ide_mem_index,
>                  escc_mem_index);
>
>       if (usb_enabled) {
> diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
> index 6b3ab89..220dca7 100644
> --- a/hw/ppc_oldworld.c
> +++ b/hw/ppc_oldworld.c
> @@ -366,8 +366,8 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
>       pmac_format_nvram_partition(nvr, 0x2000);
>
>       macio_init(pci_bus, PCI_DEVICE_ID_APPLE_343S1201, 1, pic_mem_index,
> -               dbdma_mem_index, cuda_mem_index, nvr, 2, ide_mem_index,
> -               escc_mem_index);
> +               dbdma_mem_index, cuda_mem_index, nvram_mem_index, 0x2000,
> +               2, ide_mem_index, escc_mem_index);
>
>       if (usb_enabled) {
>           usb_ohci_init_pci(pci_bus, -1);
> diff --git a/hw/rtl8139.c b/hw/rtl8139.c
> index 72e2242..d87f3ae 100644
> --- a/hw/rtl8139.c
> +++ b/hw/rtl8139.c
> @@ -3269,28 +3269,17 @@ static const VMStateDescription vmstate_rtl8139 = {
>   /***********************************************************/
>   /* PCI RTL8139 definitions */
>
> -static void rtl8139_mmio_map(PCIDevice *pci_dev, int region_num,
> -                       pcibus_t addr, pcibus_t size, int type)
> -{
> -    RTL8139State *s = DO_UPCAST(RTL8139State, dev, pci_dev);
> -
> -    cpu_register_physical_memory(addr + 0, 0x100, s->rtl8139_mmio_io_addr);
> -}
> -
> -static void rtl8139_ioport_map(PCIDevice *pci_dev, int region_num,
> -                       pcibus_t addr, pcibus_t size, int type)
> -{
> -    RTL8139State *s = DO_UPCAST(RTL8139State, dev, pci_dev);
> -
> -    register_ioport_write(addr, 0x100, 1, rtl8139_ioport_writeb, s);
> -    register_ioport_read( addr, 0x100, 1, rtl8139_ioport_readb,  s);
> -
> -    register_ioport_write(addr, 0x100, 2, rtl8139_ioport_writew, s);
> -    register_ioport_read( addr, 0x100, 2, rtl8139_ioport_readw,  s);
> +static IOPortWriteFunc * const rtl8139_io_writes[] = {
> +    rtl8139_ioport_writeb,
> +    rtl8139_ioport_writew,
> +    rtl8139_ioport_writel,
> +};
>
> -    register_ioport_write(addr, 0x100, 4, rtl8139_ioport_writel, s);
> -    register_ioport_read( addr, 0x100, 4, rtl8139_ioport_readl,  s);
> -}
> +static IOPortReadFunc * const rtl8139_io_reads[] = {
> +    rtl8139_ioport_readb,
> +    rtl8139_ioport_readw,
> +    rtl8139_ioport_readl,
> +};
>
>   static CPUReadMemoryFunc * const rtl8139_mmio_read[3] = {
>       rtl8139_mmio_readb,
> @@ -3353,6 +3342,7 @@ static int pci_rtl8139_init(PCIDevice *dev)
>   {
>       RTL8139State * s = DO_UPCAST(RTL8139State, dev, dev);
>       uint8_t *pci_conf;
> +    int io_index;
>
>       pci_conf = s->dev.config;
>       pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REALTEK);
> @@ -3372,11 +3362,11 @@ static int pci_rtl8139_init(PCIDevice *dev)
>       s->rtl8139_mmio_io_addr =
>           cpu_register_io_memory(rtl8139_mmio_read, rtl8139_mmio_write, s);
>
> -    pci_register_bar(&s->dev, 0, 0x100,
> -                           PCI_BASE_ADDRESS_SPACE_IO,  rtl8139_ioport_map);
> -
> -    pci_register_bar(&s->dev, 1, 0x100,
> -                           PCI_BASE_ADDRESS_SPACE_MEMORY, rtl8139_mmio_map);
> +    pci_register_bar(&s->dev, 0, 0x100, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(rtl8139_io_reads, rtl8139_io_writes, 0x100, s);
> +    pci_bar_map(&s->dev, 0, 0, 0, 0x100, io_index);
> +    pci_register_bar(&s->dev, 1, 0x100, PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    pci_bar_map(&s->dev, 1, 0, 0, 0x100, s->rtl8139_mmio_io_addr);
>
>       qemu_macaddr_default_if_unset(&s->conf.macaddr);
>
> diff --git a/hw/sun4u.c b/hw/sun4u.c
> index 2234b4e..48d89d3 100644
> --- a/hw/sun4u.c
> +++ b/hw/sun4u.c
> @@ -517,21 +517,6 @@ void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
>       }
>   }
>
> -static void ebus_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
> -                              pcibus_t addr, pcibus_t size, int type)
> -{
> -    EBUS_DPRINTF("Mapping region %d registers at %" FMT_PCIBUS "\n",
> -                 region_num, addr);
> -    switch (region_num) {
> -    case 0:
> -        isa_mmio_init(addr, 0x1000000, 1);
> -        break;
> -    case 1:
> -        isa_mmio_init(addr, 0x800000, 1);
> -        break;
> -    }
> -}
> -
>   static void dummy_isa_irq_handler(void *opaque, int n, int level)
>   {
>   }
> @@ -550,6 +535,8 @@ pci_ebus_init(PCIBus *bus, int devfn)
>   static int
>   pci_ebus_init1(PCIDevice *s)
>   {
> +    int io_index;
> +
>       isa_bus_new(&s->qdev);
>
>       pci_config_set_vendor_id(s->config, PCI_VENDOR_ID_SUN);
> @@ -564,10 +551,14 @@ pci_ebus_init1(PCIDevice *s)
>       s->config[0x0D] = 0x0a; // latency_timer
>       s->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
>
> -    pci_register_bar(s, 0, 0x1000000, PCI_BASE_ADDRESS_SPACE_MEMORY,
> -                           ebus_mmio_mapfunc);
> -    pci_register_bar(s, 1, 0x800000,  PCI_BASE_ADDRESS_SPACE_MEMORY,
> -                           ebus_mmio_mapfunc);
> +    pci_register_bar(s, 0, 0x1000000, PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    io_index = pci_isa_mmio_init(1);
> +    pci_bar_map(s, 0, 0, 0, 0x1000000, io_index);
> +
> +    pci_register_bar(s, 1, 0x800000, PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    io_index = pci_isa_mmio_init(1);
> +    pci_bar_map(s, 1, 0, 0, 0x800000, io_index);
> +
>       return 0;
>   }
>
> diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
> index c60fd8d..343603f 100644
> --- a/hw/usb-ohci.c
> +++ b/hw/usb-ohci.c
> @@ -1717,13 +1717,6 @@ typedef struct {
>       OHCIState state;
>   } OHCIPCIState;
>
> -static void ohci_mapfunc(PCIDevice *pci_dev, int i,
> -            pcibus_t addr, pcibus_t size, int type)
> -{
> -    OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, pci_dev);
> -    cpu_register_physical_memory(addr, size, ohci->state.mem);
> -}
> -
>   static int usb_ohci_initfn_pci(struct PCIDevice *dev)
>   {
>       OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, dev);
> @@ -1742,7 +1735,8 @@ static int usb_ohci_initfn_pci(struct PCIDevice *dev)
>
>       /* TODO: avoid cast below by using dev */
>       pci_register_bar((struct PCIDevice *)ohci, 0, 256,
> -                           PCI_BASE_ADDRESS_SPACE_MEMORY, ohci_mapfunc);
> +                     PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    pci_bar_map((struct PCIDevice *)ohci, 0, 0, 256, 0, ohci->state.mem);
>       return 0;
>   }
>
> diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
> index 4cdb55e..b182eb5 100644
> --- a/hw/usb-uhci.c
> +++ b/hw/usb-uhci.c
> @@ -1088,23 +1088,22 @@ static void uhci_frame_timer(void *opaque)
>       qemu_mod_timer(s->frame_timer, s->expire_time);
>   }
>
> -static void uhci_map(PCIDevice *pci_dev, int region_num,
> -                    pcibus_t addr, pcibus_t size, int type)
> -{
> -    UHCIState *s = (UHCIState *)pci_dev;
> -
> -    register_ioport_write(addr, 32, 2, uhci_ioport_writew, s);
> -    register_ioport_read(addr, 32, 2, uhci_ioport_readw, s);
> -    register_ioport_write(addr, 32, 4, uhci_ioport_writel, s);
> -    register_ioport_read(addr, 32, 4, uhci_ioport_readl, s);
> -    register_ioport_write(addr, 32, 1, uhci_ioport_writeb, s);
> -    register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
> -}
> +static IOPortWriteFunc * const uhci_io_writes[] = {
> +    uhci_ioport_writeb,
> +    uhci_ioport_writew,
> +    uhci_ioport_writel,
> +};
> +
> +static IOPortReadFunc * const uhci_io_reads[] = {
> +    uhci_ioport_readb,
> +    uhci_ioport_readw,
> +    uhci_ioport_readl,
> +};
>
>   static int usb_uhci_common_initfn(UHCIState *s)
>   {
>       uint8_t *pci_conf = s->dev.config;
> -    int i;
> +    int i, io_index;
>
>       pci_conf[PCI_REVISION_ID] = 0x01; // revision number
>       pci_conf[PCI_CLASS_PROG] = 0x00;
> @@ -1127,9 +1126,9 @@ static int usb_uhci_common_initfn(UHCIState *s)
>
>       /* Use region 4 for consistency with real hardware.  BSD guests seem
>          to rely on this.  */
> -    pci_register_bar(&s->dev, 4, 0x20,
> -                           PCI_BASE_ADDRESS_SPACE_IO, uhci_map);
> -
> +    pci_register_bar(&s->dev, 4, 0x20, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(uhci_io_reads, uhci_io_writes, 32, s);
> +    pci_bar_map(&s->dev, 4, 0, 0, 0x20, io_index);
>       return 0;
>   }
>
> diff --git a/hw/vga-pci.c b/hw/vga-pci.c
> index eef78ed..818e77f 100644
> --- a/hw/vga-pci.c
> +++ b/hw/vga-pci.c
> @@ -47,21 +47,6 @@ static const VMStateDescription vmstate_vga_pci = {
>       }
>   };
>
> -static void vga_map(PCIDevice *pci_dev, int region_num,
> -                    pcibus_t addr, pcibus_t size, int type)
> -{
> -    PCIVGAState *d = (PCIVGAState *)pci_dev;
> -    VGACommonState *s =&d->vga;
> -    if (region_num == PCI_ROM_SLOT) {
> -        cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
> -    } else {
> -        cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
> -        s->map_addr = addr;
> -        s->map_end = addr + s->vram_size;
> -        vga_dirty_log_start(s);
> -    }
> -}
> -
>   static void pci_vga_write_config(PCIDevice *d,
>                                    uint32_t address, uint32_t val, int len)
>   {
> @@ -93,8 +78,8 @@ static int pci_vga_initfn(PCIDevice *dev)
>        pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
>
>        /* XXX: VGA_RAM_SIZE must be a power of two */
> -     pci_register_bar(&d->dev, 0, VGA_RAM_SIZE,
> -                      PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
> +     pci_register_bar(&d->dev, 0, VGA_RAM_SIZE, PCI_BASE_ADDRESS_MEM_PREFETCH);
> +     pci_bar_map(&d->dev, 0, 0, 0, s->vram_size, s->vram_offset);
>
>        if (s->bios_size) {
>           unsigned int bios_total_size;
> @@ -103,7 +88,8 @@ static int pci_vga_initfn(PCIDevice *dev)
>           while (bios_total_size<  s->bios_size)
>               bios_total_size<<= 1;
>           pci_register_bar(&d->dev, PCI_ROM_SLOT, bios_total_size,
> -                         PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
> +                         PCI_BASE_ADDRESS_MEM_PREFETCH);
> +        pci_bar_map(&d->dev, PCI_ROM_SLOT, 0, 0, s->bios_size, s->bios_offset);
>        }
>
>       vga_init_vbe(s);
> diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
> index c6ef825..415acfc 100644
> --- a/hw/virtio-pci.c
> +++ b/hw/virtio-pci.c
> @@ -374,25 +374,17 @@ static void virtio_pci_config_writel(void
> *opaque, uint32_t addr, uint32_t val)
>       virtio_config_writel(proxy->vdev, addr, val);
>   }
>
> -static void virtio_map(PCIDevice *pci_dev, int region_num,
> -                       pcibus_t addr, pcibus_t size, int type)
> -{
> -    VirtIOPCIProxy *proxy = container_of(pci_dev, VirtIOPCIProxy, pci_dev);
> -    VirtIODevice *vdev = proxy->vdev;
> -    unsigned config_len = VIRTIO_PCI_REGION_SIZE(pci_dev) + vdev->config_len;
> -
> -    proxy->addr = addr;
> -
> -    register_ioport_write(addr, config_len, 1,
> virtio_pci_config_writeb, proxy);
> -    register_ioport_write(addr, config_len, 2,
> virtio_pci_config_writew, proxy);
> -    register_ioport_write(addr, config_len, 4,
> virtio_pci_config_writel, proxy);
> -    register_ioport_read(addr, config_len, 1, virtio_pci_config_readb, proxy);
> -    register_ioport_read(addr, config_len, 2, virtio_pci_config_readw, proxy);
> -    register_ioport_read(addr, config_len, 4, virtio_pci_config_readl, proxy);
> +static IOPortWriteFunc * const virtio_pci_config_io_writes[] = {
> +    virtio_pci_config_writeb,
> +    virtio_pci_config_writew,
> +    virtio_pci_config_writel,
> +};
>
> -    if (vdev->config_len)
> -        vdev->get_config(vdev, vdev->config);
> -}
> +static IOPortReadFunc * const virtio_pci_config_io_reads[] = {
> +    virtio_pci_config_readb,
> +    virtio_pci_config_readw,
> +    virtio_pci_config_readl,
> +};
>
>   static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
>                                   uint32_t val, int len)
> @@ -495,6 +487,7 @@ static void virtio_init_pci(VirtIOPCIProxy *proxy,
> VirtIODevice *vdev,
>   {
>       uint8_t *config;
>       uint32_t size;
> +    int io_index;
>
>       proxy->vdev = vdev;
>
> @@ -518,8 +511,7 @@ static void virtio_init_pci(VirtIOPCIProxy *proxy,
> VirtIODevice *vdev,
>       if (vdev->nvectors&&  !msix_init(&proxy->pci_dev, vdev->nvectors, 1, 0)) {
>           pci_register_bar(&proxy->pci_dev, 1,
>                            msix_bar_size(&proxy->pci_dev),
> -                         PCI_BASE_ADDRESS_SPACE_MEMORY,
> -                         msix_mmio_map);
> +                         PCI_BASE_ADDRESS_SPACE_MEMORY);
>       } else
>           vdev->nvectors = 0;
>
> @@ -529,8 +521,11 @@ static void virtio_init_pci(VirtIOPCIProxy
> *proxy, VirtIODevice *vdev,
>       if (size&  (size-1))
>           size = 1<<  qemu_fls(size);
>
> -    pci_register_bar(&proxy->pci_dev, 0, size, PCI_BASE_ADDRESS_SPACE_IO,
> -                           virtio_map);
> +    pci_register_bar(&proxy->pci_dev, 0, size, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(virtio_pci_config_io_reads,
> +                               virtio_pci_config_io_writes,
> +                               size,&proxy->pci_dev);
> +    pci_bar_map(&proxy->pci_dev, 0, 0, 0, size, io_index);
>
>       virtio_bind_device(vdev,&virtio_pci_bindings, proxy);
>       proxy->host_features |= 0x1<<  VIRTIO_F_NOTIFY_ON_EMPTY;
> diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
> index 9e72d2e..bf5f075 100644
> --- a/hw/vmware_vga.c
> +++ b/hw/vmware_vga.c
> @@ -1178,65 +1178,47 @@ static void vmsvga_init(struct vmsvga_state_s
> *s, int vga_ram_size)
>       vmsvga_reset(s);
>   }
>
> -static void pci_vmsvga_map_ioport(PCIDevice *pci_dev, int region_num,
> -                pcibus_t addr, pcibus_t size, int type)
> -{
> -    struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev;
> -    struct vmsvga_state_s *s =&d->chip;
> -
> -    register_ioport_read(addr + SVGA_IO_MUL * SVGA_INDEX_PORT,
> -                    1, 4, vmsvga_index_read, s);
> -    register_ioport_write(addr + SVGA_IO_MUL * SVGA_INDEX_PORT,
> -                    1, 4, vmsvga_index_write, s);
> -    register_ioport_read(addr + SVGA_IO_MUL * SVGA_VALUE_PORT,
> -                    1, 4, vmsvga_value_read, s);
> -    register_ioport_write(addr + SVGA_IO_MUL * SVGA_VALUE_PORT,
> -                    1, 4, vmsvga_value_write, s);
> -    register_ioport_read(addr + SVGA_IO_MUL * SVGA_BIOS_PORT,
> -                    1, 4, vmsvga_bios_read, s);
> -    register_ioport_write(addr + SVGA_IO_MUL * SVGA_BIOS_PORT,
> -                    1, 4, vmsvga_bios_write, s);
> -}
> +static IOPortWriteFunc * const vmsvga_index_io_writes[] = {
> +    NULL,
> +    NULL,
> +    vmsvga_index_write,
> +};
>
> -static void pci_vmsvga_map_mem(PCIDevice *pci_dev, int region_num,
> -                pcibus_t addr, pcibus_t size, int type)
> -{
> -    struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev;
> -    struct vmsvga_state_s *s =&d->chip;
> -    ram_addr_t iomemtype;
> +static IOPortReadFunc * const vmsvga_index_io_reads[] = {
> +    NULL,
> +    NULL,
> +    vmsvga_index_read,
> +};
>
> -    s->vram_base = addr;
> -#ifdef DIRECT_VRAM
> -    iomemtype = cpu_register_io_memory(vmsvga_vram_read,
> -                    vmsvga_vram_write, s);
> -#else
> -    iomemtype = s->vga.vram_offset | IO_MEM_RAM;
> -#endif
> -    cpu_register_physical_memory(s->vram_base, s->vga.vram_size,
> -                    iomemtype);
> +static IOPortWriteFunc * const vmsvga_value_io_writes[] = {
> +    NULL,
> +    NULL,
> +    vmsvga_value_write,
> +};
>
> -    s->vga.map_addr = addr;
> -    s->vga.map_end = addr + s->vga.vram_size;
> -    vga_dirty_log_restart(&s->vga);
> -}
> +static IOPortReadFunc * const vmsvga_value_io_reads[] = {
> +    NULL,
> +    NULL,
> +    vmsvga_value_read,
> +};
>
> -static void pci_vmsvga_map_fifo(PCIDevice *pci_dev, int region_num,
> -                pcibus_t addr, pcibus_t size, int type)
> -{
> -    struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev;
> -    struct vmsvga_state_s *s =&d->chip;
> -    ram_addr_t iomemtype;
> +static IOPortWriteFunc * const vmsvga_bios_io_writes[] = {
> +    NULL,
> +    NULL,
> +    vmsvga_bios_write,
> +};
>
> -    s->fifo_base = addr;
> -    iomemtype = s->fifo_offset | IO_MEM_RAM;
> -    cpu_register_physical_memory(s->fifo_base, s->fifo_size,
> -                    iomemtype);
> -}
> +static IOPortReadFunc * const vmsvga_bios_io_reads[] = {
> +    NULL,
> +    NULL,
> +    vmsvga_bios_read,
> +};
>
>   static int pci_vmsvga_initfn(PCIDevice *dev)
>   {
>       struct pci_vmsvga_state_s *s =
>           DO_UPCAST(struct pci_vmsvga_state_s, card, dev);
> +    ram_addr_t iomemtype;
>
>       pci_config_set_vendor_id(s->card.config, PCI_VENDOR_ID_VMWARE);
>       pci_config_set_device_id(s->card.config, SVGA_PCI_DEVICE_ID);
> @@ -1253,16 +1235,33 @@ static int pci_vmsvga_initfn(PCIDevice *dev)
>       s->card.config[PCI_SUBSYSTEM_ID + 1] = SVGA_PCI_DEVICE_ID>>  8;
>       s->card.config[PCI_INTERRUPT_LINE] = 0xff;		/* End */
>
> -    pci_register_bar(&s->card, 0, 0x10,
> -                    PCI_BASE_ADDRESS_SPACE_IO, pci_vmsvga_map_ioport);
> +    pci_register_bar(&s->card, 0, 0x10, PCI_BASE_ADDRESS_SPACE_IO);
> +    iomemtype = cpu_register_io(vmsvga_index_io_reads, vmsvga_index_io_writes,
> +                                4,&s->card);
> +    pci_bar_map(&s->card, 0, 0, SVGA_IO_MUL * SVGA_INDEX_PORT, 4, iomemtype);
> +    iomemtype = cpu_register_io(vmsvga_value_io_reads, vmsvga_value_io_writes,
> +                                4,&s->card);
> +    pci_bar_map(&s->card, 0, 0, SVGA_IO_MUL * SVGA_VALUE_PORT, 4, iomemtype);
> +    iomemtype = cpu_register_io(vmsvga_bios_io_reads, vmsvga_bios_io_writes,
> +                                4,&s->card);
> +    pci_bar_map(&s->card, 0, 0, SVGA_IO_MUL * SVGA_BIOS_PORT, 4, iomemtype);
>       pci_register_bar(&s->card, 1, VGA_RAM_SIZE,
> -                    PCI_BASE_ADDRESS_MEM_PREFETCH, pci_vmsvga_map_mem);
> -
> +                     PCI_BASE_ADDRESS_MEM_PREFETCH);
>       pci_register_bar(&s->card, 2, SVGA_FIFO_SIZE,
> -		     PCI_BASE_ADDRESS_MEM_PREFETCH, pci_vmsvga_map_fifo);
> +                     PCI_BASE_ADDRESS_MEM_PREFETCH);
>
>       vmsvga_init(&s->chip, VGA_RAM_SIZE);
>
> +#ifdef DIRECT_VRAM
> +    iomemtype = cpu_register_io_memory(vmsvga_vram_read,
> +                    vmsvga_vram_write, s);
> +#else
> +    iomemtype = s->chip.vga.vram_offset | IO_MEM_RAM;
> +#endif
> +    pci_bar_map(&s->card, 1, 0, 0, s->chip.vga.vram_size, iomemtype);
> +    iomemtype = s->chip.fifo_offset | IO_MEM_RAM;
> +    pci_bar_map(&s->card, 2, 0, 0, s->chip.fifo_size, iomemtype);
> +
>       return 0;
>   }
>
> diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c
> index be0e89e..4c5bb32 100644
> --- a/hw/wdt_i6300esb.c
> +++ b/hw/wdt_i6300esb.c
> @@ -342,29 +342,17 @@ static void i6300esb_mem_writel(void *vp,
> target_phys_addr_t addr, uint32_t val)
>       }
>   }
>
> -static void i6300esb_map(PCIDevice *dev, int region_num,
> -                         pcibus_t addr, pcibus_t size, int type)
> -{
> -    static CPUReadMemoryFunc * const mem_read[3] = {
> -        i6300esb_mem_readb,
> -        i6300esb_mem_readw,
> -        i6300esb_mem_readl,
> -    };
> -    static CPUWriteMemoryFunc * const mem_write[3] = {
> -        i6300esb_mem_writeb,
> -        i6300esb_mem_writew,
> -        i6300esb_mem_writel,
> -    };
> -    I6300State *d = DO_UPCAST(I6300State, dev, dev);
> -    int io_mem;
> -
> -    i6300esb_debug("addr = %"FMT_PCIBUS", size = %"FMT_PCIBUS", type = %d\n",
> -                   addr, size, type);
> +static CPUReadMemoryFunc * const mem_read[3] = {
> +    i6300esb_mem_readb,
> +    i6300esb_mem_readw,
> +    i6300esb_mem_readl,
> +};
>
> -    io_mem = cpu_register_io_memory(mem_read, mem_write, d);
> -    cpu_register_physical_memory (addr, 0x10, io_mem);
> -    /* qemu_register_coalesced_mmio (addr, 0x10); ? */
> -}
> +static CPUWriteMemoryFunc * const mem_write[3] = {
> +    i6300esb_mem_writeb,
> +    i6300esb_mem_writew,
> +    i6300esb_mem_writel,
> +};
>
>   static const VMStateDescription vmstate_i6300esb = {
>       .name = "i6300esb_wdt",
> @@ -393,6 +381,7 @@ static int i6300esb_init(PCIDevice *dev)
>   {
>       I6300State *d = DO_UPCAST(I6300State, dev, dev);
>       uint8_t *pci_conf;
> +    int io_mem;
>
>       d->reboot_enabled = 1;
>       d->clock_scale = CLOCK_SCALE_1KHZ;
> @@ -413,8 +402,9 @@ static int i6300esb_init(PCIDevice *dev)
>       pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER);
>       pci_conf[PCI_HEADER_TYPE] = 0x00;
>
> -    pci_register_bar(&d->dev, 0, 0x10,
> -                            PCI_BASE_ADDRESS_SPACE_MEMORY, i6300esb_map);
> +    pci_register_bar(&d->dev, 0, 0x10, PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    io_mem = cpu_register_io_memory(mem_read, mem_write, d);
> +    pci_bar_map(&d->dev, 0, 0, 0, 0x10, io_mem);
>
>       return 0;
>   }
> diff --git a/ioport.c b/ioport.c
> index 53dd87a..90fec90 100644
> --- a/ioport.c
> +++ b/ioport.c
> @@ -54,29 +54,39 @@ static IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
>   static IOPortReadFunc default_ioport_readb, default_ioport_readw,
> default_ioport_readl;
>   static IOPortWriteFunc default_ioport_writeb, default_ioport_writew,
> default_ioport_writel;
>
> +#define IO_NB_ENTRIES 256
> +
> +static IOPortWriteFunc *io_writes[IO_NB_ENTRIES][3];
> +static IOPortReadFunc *io_reads[IO_NB_ENTRIES][3];
> +static void *io_opaques[IO_NB_ENTRIES];
> +static int io_sizes[IO_NB_ENTRIES];
> +static char io_used[IO_NB_ENTRIES];
> +
> +static IOPortReadFunc * const default_read_func[3] = {
> +    default_ioport_readb,
> +    default_ioport_readw,
> +    default_ioport_readl
> +};
> +
>   static uint32_t ioport_read(int index, uint32_t address)
>   {
> -    static IOPortReadFunc * const default_func[3] = {
> -        default_ioport_readb,
> -        default_ioport_readw,
> -        default_ioport_readl
> -    };
>       IOPortReadFunc *func = ioport_read_table[index][address];
>       if (!func)
> -        func = default_func[index];
> +        func = default_read_func[index];
>       return func(ioport_opaque[address], address);
>   }
>
> +static IOPortWriteFunc * const default_write_func[3] = {
> +    default_ioport_writeb,
> +    default_ioport_writew,
> +    default_ioport_writel
> +};
> +
>   static void ioport_write(int index, uint32_t address, uint32_t data)
>   {
> -    static IOPortWriteFunc * const default_func[3] = {
> -        default_ioport_writeb,
> -        default_ioport_writew,
> -        default_ioport_writel
> -    };
>       IOPortWriteFunc *func = ioport_write_table[index][address];
>       if (!func)
> -        func = default_func[index];
> +        func = default_write_func[index];
>       func(ioport_opaque[address], address, data);
>   }
>
> @@ -173,6 +183,86 @@ int register_ioport_write(pio_addr_t start, int
> length, int size,
>       return 0;
>   }
>
> +static int get_free_io_mem_idx(void)
> +{
> +    int i;
> +
> +    for (i = 0; i<  IO_NB_ENTRIES; i++) {
> +        if (!io_used[i]) {
> +            io_used[i] = 1;
> +            return i;
> +        }
> +    }
> +    fprintf(stderr, "RAN out out io_mem_idx, max %d !\n", IO_NB_ENTRIES);
> +    return -1;
> +}
> +
> +/* io_read and io_write are arrays of functions containing the
> +   function to access byte (index 0), word (index 1) and dword (index
> +   2). Functions can be omitted with a NULL function pointer. (-1) is
> +   returned if error. */
> +int cpu_register_io(IOPortReadFunc * const *io_read,
> +                    IOPortWriteFunc * const *io_write,
> +                    int size, void *opaque)
> +{
> +    unsigned int i;
> +    int io_index;
> +
> +    io_index = get_free_io_mem_idx();
> +    if (io_index == -1) {
> +        return io_index;
> +    }
> +
> +    if (io_read) {
> +        for (i = 0; i<  3; ++i) {
> +            io_reads[io_index][i] = io_read[i];
> +        }
> +    }
> +    if (io_write) {
> +        for (i = 0; i<  3; ++i) {
> +            io_writes[io_index][i] = io_write[i];
> +        }
> +    }
> +    io_opaques[io_index] = opaque;
> +    io_sizes[io_index] = size;
> +
> +    return io_index;
> +}
> +
> +void cpu_unregister_io(int io_index)
> +{
> +    unsigned int i;
> +
> +    for (i = 0; i<  3; i++) {
> +        io_reads[io_index][i] = NULL;
> +        io_writes[io_index][i] = NULL;
> +    }
> +    io_opaques[io_index] = NULL;
> +    io_sizes[io_index] = 0;
> +    io_used[io_index] = 0;
> +}
> +
> +void cpu_map_io(pio_addr_t start, int io_index)
> +{
> +    unsigned int i, j;
> +
> +    assert(io_index>= 0);
> +    for (i = start; i<  start + io_sizes[io_index]; i++) {
> +        for (j = 0; j<  3; j++) {
> +            if (io_reads[io_index][j]) {
> +                register_ioport_read(i, io_sizes[io_index], 1<<  j,
> +                                     io_reads[io_index][j],
> +                                     io_opaques[io_index]);
> +            }
> +            if (io_writes[io_index][j]) {
> +                register_ioport_write(i, io_sizes[io_index], 1<<  j,
> +                                      io_writes[io_index][j],
> +                                      io_opaques[io_index]);
> +            }
> +        }
> +    }
> +}
> +
>   void isa_unassign_ioport(pio_addr_t start, int length)
>   {
>       int i;
> @@ -190,6 +280,11 @@ void isa_unassign_ioport(pio_addr_t start, int length)
>       }
>   }
>
> +void cpu_unmap_io(pio_addr_t start, int io_index)
> +{
> +    isa_unassign_ioport(start, io_sizes[io_index]);
> +}
> +
>   /***********************************************************/
>
>   void cpu_outb(pio_addr_t addr, uint8_t val)
> diff --git a/ioport.h b/ioport.h
> index 3d3c8a3..4ba78ed 100644
> --- a/ioport.h
> +++ b/ioport.h
> @@ -40,6 +40,12 @@ int register_ioport_read(pio_addr_t start, int
> length, int size,
>                            IOPortReadFunc *func, void *opaque);
>   int register_ioport_write(pio_addr_t start, int length, int size,
>                             IOPortWriteFunc *func, void *opaque);
> +int cpu_register_io(IOPortReadFunc * const *io_read,
> +                    IOPortWriteFunc * const *io_write,
> +                    int size, void *opaque);
> +void cpu_unregister_io(int io_index);
> +void cpu_map_io(pio_addr_t start, int io_index);
> +void cpu_unmap_io(pio_addr_t start, int io_index);
>   void isa_unassign_ioport(pio_addr_t start, int length);
>
>
>
Blue Swirl - July 7, 2010, 7:29 p.m.
On Wed, Jul 7, 2010 at 6:15 PM, malc <av1474@comtv.ru> wrote:
> On Wed, 7 Jul 2010, Blue Swirl wrote:
>
>> Add I/O port registration functions which separate registration
>> from the mapping stage.
>
> Why?

So that the device code can specify all other parameters except for
the I/O port, which will be handled by PCI BAR mappings.
Blue Swirl - July 7, 2010, 7:36 p.m.
On Wed, Jul 7, 2010 at 7:02 PM, Anthony Liguori <anthony@codemonkey.ws> wrote:
> On 07/07/2010 12:53 PM, Blue Swirl wrote:
>>
>> Add I/O port registration functions which separate registration
>> from the mapping stage.
>>
>> Move IOIO and MMIO BAR mapping to pci.c.
>>
>> TODO: fix dirty logging, coalesced MMIO and base address comparisons
>> (eepro100 etc). Bridge filtering may be broken. Broke virtio-pci and MSIX.
>>
>> Signed-off-by: Blue Swirl<blauwirbel@gmail.com>
>> ---
>> i386 boots but resets. PPC and Sparc64 can't even start.
>>
>> Patch also available at
>> git://repo.or.cz/qemu/blueswirl.git
>>
>> It may be worthwhile to break this into some kind of smaller steps.
>>
>>  hw/ac97.c         |   60 +++++++++++---------
>>  hw/cirrus_vga.c   |   40 +++-----------
>>  hw/e1000.c        |   37 +-----------
>>  hw/eepro100.c     |   77 ++++++++++----------------
>>  hw/es1370.c       |   32 +++++------
>>  hw/ide/cmd646.c   |  149
>> +++++++++++++++++++++++++++++++-------------------
>>  hw/ide/piix.c     |   74 ++++++++++++++++---------
>>  hw/ide/via.c      |   67 ++++++++++++++--------
>>  hw/isa.h          |    1 +
>>  hw/isa_mmio.c     |   17 +++++-
>>  hw/lsi53c895a.c   |   60 ++++++--------------
>>  hw/macio.c        |  107 +++++++++++-------------------------
>>  hw/ne2000.c       |   66 +++++++++++++++-------
>>  hw/openpic.c      |   36 ++----------
>>  hw/pci.c          |  158
>> ++++++++++++++++++++++++++++++++--------------------
>>  hw/pci.h          |   18 +++++-
>>  hw/pcnet.c        |   62 ++++++++++-----------
>>  hw/ppc_mac.h      |    5 +-
>>  hw/ppc_newworld.c |    2 +-
>>  hw/ppc_oldworld.c |    4 +-
>>  hw/rtl8139.c      |   42 +++++---------
>>  hw/sun4u.c        |   29 +++------
>>  hw/usb-ohci.c     |   10 +---
>>  hw/usb-uhci.c     |   31 +++++-----
>>  hw/vga-pci.c      |   22 +------
>>  hw/virtio-pci.c   |   39 ++++++-------
>>  hw/vmware_vga.c   |  107 ++++++++++++++++++------------------
>>  hw/wdt_i6300esb.c |   38 +++++--------
>>  ioport.c          |  119 ++++++++++++++++++++++++++++++++++++----
>>  ioport.h          |    6 ++
>>  30 files changed, 778 insertions(+), 737 deletions(-)
>>
>> diff --git a/hw/ac97.c b/hw/ac97.c
>> index 4319bc8..28d0c19 100644
>> --- a/hw/ac97.c
>> +++ b/hw/ac97.c
>> @@ -1234,31 +1234,29 @@ static const VMStateDescription vmstate_ac97 = {
>>      }
>>  };
>>
>> -static void ac97_map (PCIDevice *pci_dev, int region_num,
>> -                      pcibus_t addr, pcibus_t size, int type)
>> -{
>> -    AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, pci_dev);
>> -    PCIDevice *d =&s->dev;
>> -
>> -    if (!region_num) {
>> -        s->base[0] = addr;
>> -        register_ioport_read (addr, 256 * 1, 1, nam_readb, d);
>> -        register_ioport_read (addr, 256 * 2, 2, nam_readw, d);
>> -        register_ioport_read (addr, 256 * 4, 4, nam_readl, d);
>> -        register_ioport_write (addr, 256 * 1, 1, nam_writeb, d);
>> -        register_ioport_write (addr, 256 * 2, 2, nam_writew, d);
>> -        register_ioport_write (addr, 256 * 4, 4, nam_writel, d);
>> -    }
>> -    else {
>> -        s->base[1] = addr;
>> -        register_ioport_read (addr, 64 * 1, 1, nabm_readb, d);
>> -        register_ioport_read (addr, 64 * 2, 2, nabm_readw, d);
>> -        register_ioport_read (addr, 64 * 4, 4, nabm_readl, d);
>> -        register_ioport_write (addr, 64 * 1, 1, nabm_writeb, d);
>> -        register_ioport_write (addr, 64 * 2, 2, nabm_writew, d);
>> -        register_ioport_write (addr, 64 * 4, 4, nabm_writel, d);
>> -    }
>> -}
>> +static IOPortWriteFunc * const nam_writes[] = {
>> +    nam_writeb,
>> +    nam_writew,
>> +    nam_writel,
>> +};
>> +
>> +static IOPortReadFunc * const nam_reads[] = {
>> +    nam_readb,
>> +    nam_readw,
>> +    nam_readl,
>> +};
>> +
>> +static IOPortWriteFunc * const nabm_writes[] = {
>> +    nabm_writeb,
>> +    nabm_writew,
>> +    nabm_writel,
>> +};
>> +
>> +static IOPortReadFunc * const nabm_reads[] = {
>> +    nabm_readb,
>> +    nabm_readw,
>> +    nabm_readl,
>> +};
>>
>>  static void ac97_on_reset (void *opaque)
>>  {
>> @@ -1280,6 +1278,7 @@ static int ac97_initfn (PCIDevice *dev)
>>  {
>>      AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev);
>>      uint8_t *c = s->dev.config;
>> +    int io_index;
>>
>>      pci_config_set_vendor_id (c, PCI_VENDOR_ID_INTEL); /* ro */
>>      pci_config_set_device_id (c, PCI_DEVICE_ID_INTEL_82801AA_5); /* ro */
>> @@ -1321,9 +1320,14 @@ static int ac97_initfn (PCIDevice *dev)
>>      /* TODO: RST# value should be 0. */
>>      c[PCI_INTERRUPT_PIN] = 0x01;      /* intr_pn interrupt pin ro */
>>
>> -    pci_register_bar (&s->dev, 0, 256 * 4, PCI_BASE_ADDRESS_SPACE_IO,
>> -                      ac97_map);
>> -    pci_register_bar (&s->dev, 1, 64 * 4, PCI_BASE_ADDRESS_SPACE_IO,
>> ac97_map);
>> +    pci_register_bar(&s->dev, 0, 256 * 4, PCI_BASE_ADDRESS_SPACE_IO);
>> +    io_index = cpu_register_io(nam_reads, nam_writes, 256 * 4, s);
>> +    pci_bar_map(&s->dev, 0, 0, 0, 256 * 4, io_index);
>> +
>> +    pci_register_bar(&s->dev, 1, 64 * 4, PCI_BASE_ADDRESS_SPACE_IO);
>> +    io_index = cpu_register_io(nabm_reads, nabm_writes, 64 * 4, s);
>> +    pci_bar_map(&s->dev, 1, 0, 0, 64 * 4, io_index);
>>
>
> Any reason to keep this a three step process?  I see no reason not to unify
> the io and mem function pointers into a single type.

I was also considering this, but the function signatures don't match
now. With a lot more effort (or smaller steps) it could be doable.

>  These callbacks should
> be working off of pci bus addresses and should not be tied directly to CPU
> memory/pio callbacks.

The CPU callbacks may be useful outside of PCI code, like ISA.

Patch

diff --git a/hw/ac97.c b/hw/ac97.c
index 4319bc8..28d0c19 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -1234,31 +1234,29 @@  static const VMStateDescription vmstate_ac97 = {
     }
 };

-static void ac97_map (PCIDevice *pci_dev, int region_num,
-                      pcibus_t addr, pcibus_t size, int type)
-{
-    AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, pci_dev);
-    PCIDevice *d = &s->dev;
-
-    if (!region_num) {
-        s->base[0] = addr;
-        register_ioport_read (addr, 256 * 1, 1, nam_readb, d);
-        register_ioport_read (addr, 256 * 2, 2, nam_readw, d);
-        register_ioport_read (addr, 256 * 4, 4, nam_readl, d);
-        register_ioport_write (addr, 256 * 1, 1, nam_writeb, d);
-        register_ioport_write (addr, 256 * 2, 2, nam_writew, d);
-        register_ioport_write (addr, 256 * 4, 4, nam_writel, d);
-    }
-    else {
-        s->base[1] = addr;
-        register_ioport_read (addr, 64 * 1, 1, nabm_readb, d);
-        register_ioport_read (addr, 64 * 2, 2, nabm_readw, d);
-        register_ioport_read (addr, 64 * 4, 4, nabm_readl, d);
-        register_ioport_write (addr, 64 * 1, 1, nabm_writeb, d);
-        register_ioport_write (addr, 64 * 2, 2, nabm_writew, d);
-        register_ioport_write (addr, 64 * 4, 4, nabm_writel, d);
-    }
-}
+static IOPortWriteFunc * const nam_writes[] = {
+    nam_writeb,
+    nam_writew,
+    nam_writel,
+};
+
+static IOPortReadFunc * const nam_reads[] = {
+    nam_readb,
+    nam_readw,
+    nam_readl,
+};
+
+static IOPortWriteFunc * const nabm_writes[] = {
+    nabm_writeb,
+    nabm_writew,
+    nabm_writel,
+};
+
+static IOPortReadFunc * const nabm_reads[] = {
+    nabm_readb,
+    nabm_readw,
+    nabm_readl,
+};

 static void ac97_on_reset (void *opaque)
 {
@@ -1280,6 +1278,7 @@  static int ac97_initfn (PCIDevice *dev)
 {
     AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev);
     uint8_t *c = s->dev.config;
+    int io_index;

     pci_config_set_vendor_id (c, PCI_VENDOR_ID_INTEL); /* ro */
     pci_config_set_device_id (c, PCI_DEVICE_ID_INTEL_82801AA_5); /* ro */
@@ -1321,9 +1320,14 @@  static int ac97_initfn (PCIDevice *dev)
     /* TODO: RST# value should be 0. */
     c[PCI_INTERRUPT_PIN] = 0x01;      /* intr_pn interrupt pin ro */

-    pci_register_bar (&s->dev, 0, 256 * 4, PCI_BASE_ADDRESS_SPACE_IO,
-                      ac97_map);
-    pci_register_bar (&s->dev, 1, 64 * 4, PCI_BASE_ADDRESS_SPACE_IO, ac97_map);
+    pci_register_bar(&s->dev, 0, 256 * 4, PCI_BASE_ADDRESS_SPACE_IO);
+    io_index = cpu_register_io(nam_reads, nam_writes, 256 * 4, s);
+    pci_bar_map(&s->dev, 0, 0, 0, 256 * 4, io_index);
+
+    pci_register_bar(&s->dev, 1, 64 * 4, PCI_BASE_ADDRESS_SPACE_IO);
+    io_index = cpu_register_io(nabm_reads, nabm_writes, 64 * 4, s);
+    pci_bar_map(&s->dev, 1, 0, 0, 64 * 4, io_index);
+
     qemu_register_reset (ac97_on_reset, s);
     AUD_register_card ("ac97", &s->card);
     ac97_on_reset (s);
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index bbd4b08..829d837 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -3139,36 +3139,6 @@  void isa_cirrus_vga_init(void)
  *
  ***************************************/

-static void cirrus_pci_lfb_map(PCIDevice *d, int region_num,
-			       pcibus_t addr, pcibus_t size, int type)
-{
-    CirrusVGAState *s = &DO_UPCAST(PCICirrusVGAState, dev, d)->cirrus_vga;
-
-    /* XXX: add byte swapping apertures */
-    cpu_register_physical_memory(addr, s->vga.vram_size,
-				 s->cirrus_linear_io_addr);
-    cpu_register_physical_memory(addr + 0x1000000, 0x400000,
-				 s->cirrus_linear_bitblt_io_addr);
-
-    s->vga.map_addr = s->vga.map_end = 0;
-    s->vga.lfb_addr = addr & TARGET_PAGE_MASK;
-    s->vga.lfb_end = ((addr + VGA_RAM_SIZE) + TARGET_PAGE_SIZE - 1) &
TARGET_PAGE_MASK;
-    /* account for overflow */
-    if (s->vga.lfb_end < addr + VGA_RAM_SIZE)
-        s->vga.lfb_end = addr + VGA_RAM_SIZE;
-
-    vga_dirty_log_start(&s->vga);
-}
-
-static void cirrus_pci_mmio_map(PCIDevice *d, int region_num,
-				pcibus_t addr, pcibus_t size, int type)
-{
-    CirrusVGAState *s = &DO_UPCAST(PCICirrusVGAState, dev, d)->cirrus_vga;
-
-    cpu_register_physical_memory(addr, CIRRUS_PNPMMIO_SIZE,
-				 s->cirrus_mmio_io_addr);
-}
-
 static void pci_cirrus_write_config(PCIDevice *d,
                                     uint32_t address, uint32_t val, int len)
 {
@@ -3205,10 +3175,16 @@  static int pci_cirrus_vga_initfn(PCIDevice *dev)
      /* memory #1 memory-mapped I/O */
      /* XXX: s->vga.vram_size must be a power of two */
      pci_register_bar((PCIDevice *)d, 0, 0x2000000,
-                      PCI_BASE_ADDRESS_MEM_PREFETCH, cirrus_pci_lfb_map);
+                      PCI_BASE_ADDRESS_MEM_PREFETCH);
+     pci_bar_map((PCIDevice *)d, 0, 0, 0, s->vga.vram_size,
+                 s->cirrus_linear_io_addr);
+     pci_bar_map((PCIDevice *)d, 0, 1, 0x1000000, 0x400000,
+                 s->cirrus_linear_bitblt_io_addr);
      if (device_id == CIRRUS_ID_CLGD5446) {
          pci_register_bar((PCIDevice *)d, 1, CIRRUS_PNPMMIO_SIZE,
-                          PCI_BASE_ADDRESS_SPACE_MEMORY, cirrus_pci_mmio_map);
+                          PCI_BASE_ADDRESS_SPACE_MEMORY);
+         pci_bar_map((PCIDevice *)d, 1, 0, 0, CIRRUS_PNPMMIO_SIZE,
+                     s->cirrus_mmio_io_addr);
      }
      return 0;
 }
diff --git a/hw/e1000.c b/hw/e1000.c
index 0da65f9..b5e9143 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -149,14 +149,6 @@  static const char phy_regcap[0x20] = {
 };

 static void
-ioport_map(PCIDevice *pci_dev, int region_num, pcibus_t addr,
-           pcibus_t size, int type)
-{
-    DBGOUT(IO, "e1000_ioport_map addr=0x%04"FMT_PCIBUS
-           " size=0x%08"FMT_PCIBUS"\n", addr, size);
-}
-
-static void
 set_interrupt_cause(E1000State *s, int index, uint32_t val)
 {
     if (val)
@@ -1018,30 +1010,6 @@  static CPUReadMemoryFunc * const e1000_mmio_read[] = {
 };

 static void
-e1000_mmio_map(PCIDevice *pci_dev, int region_num,
-                pcibus_t addr, pcibus_t size, int type)
-{
-    E1000State *d = DO_UPCAST(E1000State, dev, pci_dev);
-    int i;
-    const uint32_t excluded_regs[] = {
-        E1000_MDIC, E1000_ICR, E1000_ICS, E1000_IMS,
-        E1000_IMC, E1000_TCTL, E1000_TDT, PNPMMIO_SIZE
-    };
-
-
-    DBGOUT(MMIO, "e1000_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n",
-           addr, size);
-
-    cpu_register_physical_memory(addr, PNPMMIO_SIZE, d->mmio_index);
-    qemu_register_coalesced_mmio(addr, excluded_regs[0]);
-
-    for (i = 0; excluded_regs[i] != PNPMMIO_SIZE; i++)
-        qemu_register_coalesced_mmio(addr + excluded_regs[i] + 4,
-                                     excluded_regs[i + 1] -
-                                     excluded_regs[i] - 4);
-}
-
-static void
 e1000_cleanup(VLANClientState *nc)
 {
     E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
@@ -1106,10 +1074,11 @@  static int pci_e1000_init(PCIDevice *pci_dev)
             e1000_mmio_write, d);

     pci_register_bar((PCIDevice *)d, 0, PNPMMIO_SIZE,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, e1000_mmio_map);
+                     PCI_BASE_ADDRESS_SPACE_MEMORY);
+    pci_bar_map((PCIDevice *)d, 0, 0, 0, PNPMMIO_SIZE, d->mmio_index);

     pci_register_bar((PCIDevice *)d, 1, IOPORT_SIZE,
-                           PCI_BASE_ADDRESS_SPACE_IO, ioport_map);
+                     PCI_BASE_ADDRESS_SPACE_IO);

     memmove(d->eeprom_data, e1000_eeprom_template,
         sizeof e1000_eeprom_template);
diff --git a/hw/eepro100.c b/hw/eepro100.c
index 2b75c8f..da41476 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -226,7 +226,7 @@  typedef struct {
     uint8_t scb_stat;           /* SCB stat/ack byte */
     uint8_t int_stat;           /* PCI interrupt status */
     /* region must not be saved by nic_save. */
-    uint32_t region[3];         /* PCI region addresses */
+    uint32_t region;         /* PCI region addresses */
     uint16_t mdimem[32];
     eeprom_t *eeprom;
     uint32_t device;            /* device variant */
@@ -1479,19 +1479,19 @@  static uint32_t ioport_read1(void *opaque,
uint32_t addr)
 #if 0
     logout("addr=%s\n", regname(addr));
 #endif
-    return eepro100_read1(s, addr - s->region[1]);
+    return eepro100_read1(s, addr - s->region);
 }

 static uint32_t ioport_read2(void *opaque, uint32_t addr)
 {
     EEPRO100State *s = opaque;
-    return eepro100_read2(s, addr - s->region[1]);
+    return eepro100_read2(s, addr - s->region);
 }

 static uint32_t ioport_read4(void *opaque, uint32_t addr)
 {
     EEPRO100State *s = opaque;
-    return eepro100_read4(s, addr - s->region[1]);
+    return eepro100_read4(s, addr - s->region);
 }

 static void ioport_write1(void *opaque, uint32_t addr, uint32_t val)
@@ -1500,43 +1500,35 @@  static void ioport_write1(void *opaque,
uint32_t addr, uint32_t val)
 #if 0
     logout("addr=%s val=0x%02x\n", regname(addr), val);
 #endif
-    eepro100_write1(s, addr - s->region[1], val);
+    eepro100_write1(s, addr - s->region, val);
 }

 static void ioport_write2(void *opaque, uint32_t addr, uint32_t val)
 {
     EEPRO100State *s = opaque;
-    eepro100_write2(s, addr - s->region[1], val);
+    eepro100_write2(s, addr - s->region, val);
 }

 static void ioport_write4(void *opaque, uint32_t addr, uint32_t val)
 {
     EEPRO100State *s = opaque;
-    eepro100_write4(s, addr - s->region[1], val);
+    eepro100_write4(s, addr - s->region, val);
 }

 /***********************************************************/
 /* PCI EEPRO100 definitions */

-static void pci_map(PCIDevice * pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
-{
-    EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
-
-    TRACE(OTHER, logout("region %d, addr=0x%08"FMT_PCIBUS", "
-          "size=0x%08"FMT_PCIBUS", type=%d\n",
-          region_num, addr, size, type));
-
-    assert(region_num == 1);
-    register_ioport_write(addr, size, 1, ioport_write1, s);
-    register_ioport_read(addr, size, 1, ioport_read1, s);
-    register_ioport_write(addr, size, 2, ioport_write2, s);
-    register_ioport_read(addr, size, 2, ioport_read2, s);
-    register_ioport_write(addr, size, 4, ioport_write4, s);
-    register_ioport_read(addr, size, 4, ioport_read4, s);
+static IOPortWriteFunc * const io_writes[] = {
+    ioport_write1,
+    ioport_write2,
+    ioport_write4,
+};

-    s->region[region_num] = addr;
-}
+static IOPortReadFunc * const io_reads[] = {
+    ioport_read1,
+    ioport_read2,
+    ioport_read4,
+};

 /*****************************************************************************
  *
@@ -1610,22 +1602,6 @@  static CPUReadMemoryFunc * const pci_mmio_read[] = {
     pci_mmio_readl
 };

-static void pci_mmio_map(PCIDevice * pci_dev, int region_num,
-                         pcibus_t addr, pcibus_t size, int type)
-{
-    EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
-
-    TRACE(OTHER, logout("region %d, addr=0x%08"FMT_PCIBUS", "
-          "size=0x%08"FMT_PCIBUS", type=%d\n",
-          region_num, addr, size, type));
-
-    assert(region_num == 0 || region_num == 2);
-
-    /* Map control / status registers and flash. */
-    cpu_register_physical_memory(addr, size, s->mmio_index);
-    s->region[region_num] = addr;
-}
-
 static int nic_can_receive(VLANClientState *nc)
 {
     EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque;
@@ -1853,6 +1829,7 @@  static int e100_nic_init(PCIDevice *pci_dev)
     EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
     E100PCIDeviceInfo *e100_device = DO_UPCAST(E100PCIDeviceInfo, pci.qdev,
                                                pci_dev->qdev.info);
+    int io_index;

     TRACE(OTHER, logout("\n"));

@@ -1868,17 +1845,23 @@  static int e100_nic_init(PCIDevice *pci_dev)
     s->mmio_index =
         cpu_register_io_memory(pci_mmio_read, pci_mmio_write, s);

+    /* Map control / status registers. */
     pci_register_bar(&s->dev, 0, PCI_MEM_SIZE,
                            PCI_BASE_ADDRESS_SPACE_MEMORY |
-                           PCI_BASE_ADDRESS_MEM_PREFETCH, pci_mmio_map);
-    pci_register_bar(&s->dev, 1, PCI_IO_SIZE, PCI_BASE_ADDRESS_SPACE_IO,
-                           pci_map);
-    pci_register_bar(&s->dev, 2, PCI_FLASH_SIZE, PCI_BASE_ADDRESS_SPACE_MEMORY,
-                           pci_mmio_map);
+                           PCI_BASE_ADDRESS_MEM_PREFETCH);
+    pci_bar_map(&s->dev, 0, 0, 0, PCI_IO_SIZE, s->mmio_index);
+
+    io_index = cpu_register_io(io_reads, io_writes, PCI_IO_SIZE, s);
+    pci_register_bar(&s->dev, 1, PCI_IO_SIZE, PCI_BASE_ADDRESS_SPACE_IO);
+    pci_bar_map(&s->dev, 1, 0, 0, PCI_IO_SIZE, io_index);
+
+    /* Map flash. */
+    pci_register_bar(&s->dev, 2, PCI_FLASH_SIZE,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY);
+    pci_bar_map(&s->dev, 2, 0, 0, PCI_FLASH_SIZE, s->mmio_index);

     qemu_macaddr_default_if_unset(&s->conf.macaddr);
     logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6));
-    assert(s->region[1] == 0);

     nic_reset(s);

diff --git a/hw/es1370.c b/hw/es1370.c
index 40cb48c..652f0d4 100644
--- a/hw/es1370.c
+++ b/hw/es1370.c
@@ -906,23 +906,17 @@  static void es1370_adc_callback (void *opaque, int avail)
     es1370_run_channel (s, ADC_CHANNEL, avail);
 }

-static void es1370_map (PCIDevice *pci_dev, int region_num,
-                        pcibus_t addr, pcibus_t size, int type)
-{
-    ES1370State *s = DO_UPCAST (ES1370State, dev, pci_dev);
-
-    (void) region_num;
-    (void) size;
-    (void) type;
-
-    register_ioport_write (addr, 0x40 * 4, 1, es1370_writeb, s);
-    register_ioport_write (addr, 0x40 * 2, 2, es1370_writew, s);
-    register_ioport_write (addr, 0x40, 4, es1370_writel, s);
+static IOPortWriteFunc * const es1370_writes[] = {
+    es1370_writeb,
+    es1370_writew,
+    es1370_writel,
+};

-    register_ioport_read (addr, 0x40 * 4, 1, es1370_readb, s);
-    register_ioport_read (addr, 0x40 * 2, 2, es1370_readw, s);
-    register_ioport_read (addr, 0x40, 4, es1370_readl, s);
-}
+static IOPortReadFunc * const es1370_reads[] = {
+    es1370_readb,
+    es1370_readw,
+    es1370_readl,
+};

 static const VMStateDescription vmstate_es1370_channel = {
     .name = "es1370_channel",
@@ -997,6 +991,7 @@  static int es1370_initfn (PCIDevice *dev)
 {
     ES1370State *s = DO_UPCAST (ES1370State, dev, dev);
     uint8_t *c = s->dev.config;
+    int io_index;

     pci_config_set_vendor_id (c, PCI_VENDOR_ID_ENSONIQ);
     pci_config_set_device_id (c, PCI_DEVICE_ID_ENSONIQ_ES1370);
@@ -1023,7 +1018,10 @@  static int es1370_initfn (PCIDevice *dev)
     c[PCI_MIN_GNT] = 0x0c;
     c[PCI_MAX_LAT] = 0x80;

-    pci_register_bar (&s->dev, 0, 256, PCI_BASE_ADDRESS_SPACE_IO, es1370_map);
+    pci_register_bar (&s->dev, 0, 256, PCI_BASE_ADDRESS_SPACE_IO);
+    io_index = cpu_register_io(es1370_reads, es1370_writes, 256, s);
+    pci_bar_map(&s->dev, 0, 0, 0, 256, io_index);
+
     qemu_register_reset (es1370_on_reset, s);

     AUD_register_card ("es1370", &s->card);
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 8b71a13..b30e279 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -44,29 +44,29 @@ 

 static void cmd646_update_irq(PCIIDEState *d);

-static void ide_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
-{
-    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
-    IDEBus *bus;
-
-    if (region_num <= 3) {
-        bus = &d->bus[(region_num >> 1)];
-        if (region_num & 1) {
-            register_ioport_read(addr + 2, 1, 1, ide_status_read, bus);
-            register_ioport_write(addr + 2, 1, 1, ide_cmd_write, bus);
-        } else {
-            register_ioport_write(addr, 8, 1, ide_ioport_write, bus);
-            register_ioport_read(addr, 8, 1, ide_ioport_read, bus);
-
-            /* data ports */
-            register_ioport_write(addr, 2, 2, ide_data_writew, bus);
-            register_ioport_read(addr, 2, 2, ide_data_readw, bus);
-            register_ioport_write(addr, 4, 4, ide_data_writel, bus);
-            register_ioport_read(addr, 4, 4, ide_data_readl, bus);
-        }
-    }
-}
+static IOPortWriteFunc * const ide_cmd_writes[] = {
+    ide_cmd_write,
+    NULL,
+    NULL,
+};
+
+static IOPortReadFunc * const ide_status_reads[] = {
+    ide_status_read,
+    NULL,
+    NULL,
+};
+
+static IOPortWriteFunc * const ide_ioport_writes[] = {
+    ide_ioport_write,
+    ide_data_writew,
+    ide_data_writel,
+};
+
+static IOPortReadFunc * const ide_ioport_reads[] = {
+    ide_ioport_read,
+    ide_data_readw,
+    ide_data_readl,
+};

 static uint32_t bmdma_readb_common(PCIIDEState *pci_dev, BMDMAState *bm,
                                    uint32_t addr)
@@ -159,35 +159,41 @@  static void bmdma_writeb_1(void *opaque,
uint32_t addr, uint32_t val)
     bmdma_writeb_common(pci_dev, bm, addr, val);
 }

-static void bmdma_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
-{
-    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
-    int i;
+static IOPortWriteFunc * const bmdma_io_writes_0[] = {
+    bmdma_writeb_0,
+    NULL,
+    NULL,
+};

-    for(i = 0;i < 2; i++) {
-        BMDMAState *bm = &d->bmdma[i];
-        d->bus[i].bmdma = bm;
-        bm->bus = d->bus+i;
-        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
+static IOPortReadFunc * const bmdma_io_reads_0[] = {
+    bmdma_readb_0,
+    NULL,
+    NULL,
+};

-        if (i == 0) {
-            register_ioport_write(addr, 4, 1, bmdma_writeb_0, d);
-            register_ioport_read(addr, 4, 1, bmdma_readb_0, d);
-        } else {
-            register_ioport_write(addr, 4, 1, bmdma_writeb_1, d);
-            register_ioport_read(addr, 4, 1, bmdma_readb_1, d);
-        }
+static IOPortWriteFunc * const bmdma_io_writes_1[] = {
+    bmdma_writeb_1,
+    NULL,
+    NULL,
+};

-        register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
-        register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
-        register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
-        register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
-        register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
-        register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
-        addr += 8;
-    }
-}
+static IOPortReadFunc * const bmdma_io_reads_1[] = {
+    bmdma_readb_1,
+    NULL,
+    NULL,
+};
+
+static IOPortWriteFunc * const bmdma_addr_writes[] = {
+    bmdma_addr_writeb,
+    bmdma_addr_writew,
+    bmdma_addr_writel,
+};
+
+static IOPortReadFunc * const bmdma_addr_reads[] = {
+    bmdma_addr_readb,
+    bmdma_addr_readw,
+    bmdma_addr_readl,
+};

 /* XXX: call it also when the MRDMODE is changed from the PCI config
    registers */
@@ -232,6 +238,8 @@  static int pci_cmd646_ide_initfn(PCIDevice *dev)
     PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
     uint8_t *pci_conf = d->dev.config;
     qemu_irq *irq;
+    unsigned int i;
+    int io_index;

     pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_CMD);
     pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_CMD_646);
@@ -248,11 +256,38 @@  static int pci_cmd646_ide_initfn(PCIDevice *dev)
         pci_conf[0x51] |= 0x08; /* enable IDE1 */
     }

-    pci_register_bar(dev, 0, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
-    pci_register_bar(dev, 1, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
-    pci_register_bar(dev, 2, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
-    pci_register_bar(dev, 3, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
-    pci_register_bar(dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
+    pci_register_bar(dev, 0, 0x8, PCI_BASE_ADDRESS_SPACE_IO);
+    io_index = cpu_register_io(ide_ioport_reads, ide_ioport_writes,
8, &d->bus[0]);
+    pci_bar_map(&d->dev, 0, 0, 8, 8, io_index);
+    pci_register_bar(dev, 1, 0x4, PCI_BASE_ADDRESS_SPACE_IO);
+    io_index = cpu_register_io(ide_status_reads, ide_cmd_writes, 1,
&d->bus[0]);
+    pci_bar_map(&d->dev, 1, 0, 1, 1, io_index);
+    pci_register_bar(dev, 2, 0x8, PCI_BASE_ADDRESS_SPACE_IO);
+    io_index = cpu_register_io(ide_ioport_reads, ide_ioport_writes,
8, &d->bus[1]);
+    pci_bar_map(&d->dev, 2, 0, 8, 8, io_index);
+    pci_register_bar(dev, 3, 0x4, PCI_BASE_ADDRESS_SPACE_IO);
+    io_index = cpu_register_io(ide_status_reads, ide_cmd_writes, 1,
&d->bus[1]);
+    pci_bar_map(&d->dev, 3, 0, 1, 1, io_index);
+    pci_register_bar(dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO);
+    for (i = 0; i < 2; i++) {
+        BMDMAState *bm = &d->bmdma[i];
+
+        d->bus[i].bmdma = bm;
+        bm->bus = d->bus+i;
+        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
+
+        if (i == 0) {
+            io_index = cpu_register_io(bmdma_io_reads_0, bmdma_io_writes_0,
+                                       1, d);
+        } else {
+            io_index = cpu_register_io(bmdma_io_reads_1, bmdma_io_writes_1,
+                                       1, d);
+        }
+        pci_bar_map(&d->dev, 4, i * 4 + 0, 0, 1, io_index);
+
+        io_index = cpu_register_io(bmdma_addr_reads, bmdma_addr_writes, 4, bm);
+        pci_bar_map(&d->dev, 4, i * 4 + 4, 4, 4, io_index);
+    }

     /* TODO: RST# value should be 0 */
     pci_conf[PCI_INTERRUPT_PIN] = 0x01; // interrupt on pin 1
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index 9223834..0506990 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -68,32 +68,35 @@  static void bmdma_writeb(void *opaque, uint32_t
addr, uint32_t val)
     }
 }

-static void bmdma_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
-{
-    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
-    int i;
+static IOPortWriteFunc * const bmdma_cmd_io_writes[] = {
+    bmdma_cmd_writeb,
+    NULL,
+    NULL,
+};

-    for(i = 0;i < 2; i++) {
-        BMDMAState *bm = &d->bmdma[i];
-        d->bus[i].bmdma = bm;
-        bm->bus = d->bus+i;
-        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
+static IOPortWriteFunc * const bmdma_io_writes[] = {
+    bmdma_writeb,
+    NULL,
+    NULL,
+};

-        register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
+static IOPortReadFunc * const bmdma_io_reads[] = {
+    bmdma_readb,
+    NULL,
+    NULL,
+};

-        register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
-        register_ioport_read(addr, 4, 1, bmdma_readb, bm);
+static IOPortWriteFunc * const bmdma_addr_writes[] = {
+    bmdma_addr_writeb,
+    bmdma_addr_writew,
+    bmdma_addr_writel,
+};

-        register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
-        register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
-        register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
-        register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
-        register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
-        register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
-        addr += 8;
-    }
-}
+static IOPortReadFunc * const bmdma_addr_reads[] = {
+    bmdma_addr_readb,
+    bmdma_addr_readw,
+    bmdma_addr_readl,
+};

 static void piix3_reset(void *opaque)
 {
@@ -119,6 +122,8 @@  static void piix3_reset(void *opaque)
 static int pci_piix_ide_initfn(PCIIDEState *d)
 {
     uint8_t *pci_conf = d->dev.config;
+    unsigned int i;
+    int io_index;

     pci_conf[PCI_CLASS_PROG] = 0x80; // legacy ATA mode
     pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE);
@@ -126,7 +131,22 @@  static int pci_piix_ide_initfn(PCIIDEState *d)

     qemu_register_reset(piix3_reset, d);

-    pci_register_bar(&d->dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
+    pci_register_bar(&d->dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO);
+    for (i = 0; i < 2; i++) {
+        BMDMAState *bm = &d->bmdma[i];
+
+        d->bus[i].bmdma = bm;
+        bm->bus = d->bus + i;
+        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
+        io_index = cpu_register_io(NULL, bmdma_cmd_io_writes, 1, bm);
+        pci_bar_map(&d->dev, 0, i * 4 + 0, 0, 1, io_index);
+        io_index = cpu_register_io(NULL, bmdma_io_writes, 3, bm);
+        pci_bar_map(&d->dev, 0, i * 4 + 1, 1, 3, io_index);
+        io_index = cpu_register_io(bmdma_io_reads, NULL, 4, bm);
+        pci_bar_map(&d->dev, 0, i * 4 + 2, 0, 4, io_index);
+        io_index = cpu_register_io(bmdma_addr_reads, bmdma_addr_writes, 4, bm);
+        pci_bar_map(&d->dev, 0, i * 4 + 3, 4, 4, io_index);
+    }

     vmstate_register(&d->dev.qdev, 0, &vmstate_ide_pci, d);

diff --git a/hw/ide/via.c b/hw/ide/via.c
index a403e8c..d2f5d00 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -70,32 +70,35 @@  static void bmdma_writeb(void *opaque, uint32_t
addr, uint32_t val)
     }
 }

-static void bmdma_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
-{
-    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
-    int i;
+static IOPortWriteFunc * const bmdma_cmd_io_writes[] = {
+    bmdma_cmd_writeb,
+    NULL,
+    NULL,
+};

-    for(i = 0;i < 2; i++) {
-        BMDMAState *bm = &d->bmdma[i];
-        d->bus[i].bmdma = bm;
-        bm->bus = d->bus+i;
-        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
+static IOPortWriteFunc * const bmdma_io_writes[] = {
+    bmdma_writeb,
+    NULL,
+    NULL,
+};

-        register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
+static IOPortReadFunc * const bmdma_io_reads[] = {
+    bmdma_readb,
+    NULL,
+    NULL,
+};

-        register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
-        register_ioport_read(addr, 4, 1, bmdma_readb, bm);
+static IOPortWriteFunc * const bmdma_addr_writes[] = {
+    bmdma_addr_writeb,
+    bmdma_addr_writew,
+    bmdma_addr_writel,
+};

-        register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
-        register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
-        register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
-        register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
-        register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
-        register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
-        addr += 8;
-    }
-}
+static IOPortReadFunc * const bmdma_addr_reads[] = {
+    bmdma_addr_readb,
+    bmdma_addr_readw,
+    bmdma_addr_readl,
+};

 static void via_reset(void *opaque)
 {
@@ -144,6 +147,8 @@  static int vt82c686b_ide_initfn(PCIDevice *dev)
 {
     PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);;
     uint8_t *pci_conf = d->dev.config;
+    unsigned int i;
+    int io_index;

     pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_VIA);
     pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIA_IDE);
@@ -154,8 +159,22 @@  static int vt82c686b_ide_initfn(PCIDevice *dev)
     pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);

     qemu_register_reset(via_reset, d);
-    pci_register_bar((PCIDevice *)d, 4, 0x10,
-                           PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
+    pci_register_bar((PCIDevice *)d, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO);
+    for (i = 0; i < 2; i++) {
+        BMDMAState *bm = &d->bmdma[i];
+
+        d->bus[i].bmdma = bm;
+        bm->bus = d->bus + i;
+        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
+        io_index = cpu_register_io(NULL, bmdma_cmd_io_writes, 1, bm);
+        pci_bar_map(&d->dev, 0, i * 4 + 0, 0, 1, io_index);
+        io_index = cpu_register_io(NULL, bmdma_io_writes, 3, bm);
+        pci_bar_map(&d->dev, 0, i * 4 + 1, 1, 3, io_index);
+        io_index = cpu_register_io(bmdma_io_reads, NULL, 4, bm);
+        pci_bar_map(&d->dev, 0, i * 4 + 2, 0, 4, io_index);
+        io_index = cpu_register_io(bmdma_addr_reads, bmdma_addr_writes, 4, bm);
+        pci_bar_map(&d->dev, 0, i * 4 + 3, 4, 4, io_index);
+    }

     vmstate_register(&dev->qdev, 0, &vmstate_ide_pci, d);

diff --git a/hw/isa.h b/hw/isa.h
index aaf0272..6fba4ac 100644
--- a/hw/isa.h
+++ b/hw/isa.h
@@ -33,6 +33,7 @@  ISADevice *isa_create_simple(const char *name);
 extern target_phys_addr_t isa_mem_base;

 void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size, int be);
+int pci_isa_mmio_init(int be);

 /* dma.c */
 int DMA_get_channel_mode (int nchan);
diff --git a/hw/isa_mmio.c b/hw/isa_mmio.c
index 66bdd2c..3b2de4a 100644
--- a/hw/isa_mmio.c
+++ b/hw/isa_mmio.c
@@ -125,7 +125,7 @@  static CPUReadMemoryFunc * const isa_mmio_read_le[] = {

 static int isa_mmio_iomemtype = 0;

-void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size, int be)
+static int isa_mmio_memtype(int be)
 {
     if (!isa_mmio_iomemtype) {
         if (be) {
@@ -138,5 +138,18 @@  void isa_mmio_init(target_phys_addr_t base,
target_phys_addr_t size, int be)
                                                         NULL);
         }
     }
-    cpu_register_physical_memory(base, size, isa_mmio_iomemtype);
+    return isa_mmio_iomemtype;
+}
+
+void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size, int be)
+{
+    int isa;
+
+    isa = isa_mmio_memtype(be);
+    cpu_register_physical_memory(base, size, isa);
+}
+
+int pci_isa_mmio_init(int be)
+{
+    return isa_mmio_memtype(be);
 }
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index bd7b661..32de5d1 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -186,7 +186,6 @@  typedef struct {
     PCIDevice dev;
     int mmio_io_addr;
     int ram_io_addr;
-    uint32_t script_ram_base;

     int carry; /* ??? Should this be an a visible register somewhere?  */
     int sense;
@@ -390,10 +389,6 @@  static inline uint32_t read_dword(LSIState *s,
uint32_t addr)
 {
     uint32_t buf;

-    /* Optimize reading from SCRIPTS RAM.  */
-    if ((addr & 0xffffe000) == s->script_ram_base) {
-        return s->script_ram[(addr & 0x1fff) >> 2];
-    }
     cpu_physical_memory_read(addr, (uint8_t *)&buf, 4);
     return cpu_to_le32(buf);
 }
@@ -2004,39 +1999,17 @@  static void lsi_io_writel(void *opaque,
uint32_t addr, uint32_t val)
     lsi_reg_writeb(s, addr + 3, (val >> 24) & 0xff);
 }

-static void lsi_io_mapfunc(PCIDevice *pci_dev, int region_num,
-                           pcibus_t addr, pcibus_t size, int type)
-{
-    LSIState *s = DO_UPCAST(LSIState, dev, pci_dev);
-
-    DPRINTF("Mapping IO at %08"FMT_PCIBUS"\n", addr);
-
-    register_ioport_write(addr, 256, 1, lsi_io_writeb, s);
-    register_ioport_read(addr, 256, 1, lsi_io_readb, s);
-    register_ioport_write(addr, 256, 2, lsi_io_writew, s);
-    register_ioport_read(addr, 256, 2, lsi_io_readw, s);
-    register_ioport_write(addr, 256, 4, lsi_io_writel, s);
-    register_ioport_read(addr, 256, 4, lsi_io_readl, s);
-}
-
-static void lsi_ram_mapfunc(PCIDevice *pci_dev, int region_num,
-                            pcibus_t addr, pcibus_t size, int type)
-{
-    LSIState *s = DO_UPCAST(LSIState, dev, pci_dev);
-
-    DPRINTF("Mapping ram at %08"FMT_PCIBUS"\n", addr);
-    s->script_ram_base = addr;
-    cpu_register_physical_memory(addr + 0, 0x2000, s->ram_io_addr);
-}
-
-static void lsi_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
-                             pcibus_t addr, pcibus_t size, int type)
-{
-    LSIState *s = DO_UPCAST(LSIState, dev, pci_dev);
+static IOPortWriteFunc * const lsi_io_writes[] = {
+    lsi_io_writeb,
+    lsi_io_writew,
+    lsi_io_writel,
+};

-    DPRINTF("Mapping registers at %08"FMT_PCIBUS"\n", addr);
-    cpu_register_physical_memory(addr + 0, 0x400, s->mmio_io_addr);
-}
+static IOPortReadFunc * const lsi_io_reads[] = {
+    lsi_io_readb,
+    lsi_io_readw,
+    lsi_io_readl,
+};

 static void lsi_scsi_reset(DeviceState *dev)
 {
@@ -2153,6 +2126,7 @@  static int lsi_scsi_init(PCIDevice *dev)
 {
     LSIState *s = DO_UPCAST(LSIState, dev, dev);
     uint8_t *pci_conf;
+    int io_index;

     pci_conf = s->dev.config;

@@ -2177,12 +2151,16 @@  static int lsi_scsi_init(PCIDevice *dev)
                                             lsi_ram_writefn, s);

     /* TODO: use dev and get rid of cast below */
-    pci_register_bar((struct PCIDevice *)s, 0, 256,
-                           PCI_BASE_ADDRESS_SPACE_IO, lsi_io_mapfunc);
+    pci_register_bar((struct PCIDevice *)s, 0, 256, PCI_BASE_ADDRESS_SPACE_IO);
+    io_index = cpu_register_io(lsi_io_reads, lsi_io_writes, 256, s);
+    pci_bar_map((struct PCIDevice *)s, 0, 0, 0, 256, io_index);
+
     pci_register_bar((struct PCIDevice *)s, 1, 0x400,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_mmio_mapfunc);
+                           PCI_BASE_ADDRESS_SPACE_MEMORY);
+    pci_bar_map((struct PCIDevice *)s, 1, 0, 0, 0x400, s->mmio_io_addr);
     pci_register_bar((struct PCIDevice *)s, 2, 0x2000,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc);
+                           PCI_BASE_ADDRESS_SPACE_MEMORY);
+    pci_bar_map((struct PCIDevice *)s, 2, 0, 0, 0x2000, s->ram_io_addr);
     QTAILQ_INIT(&s->queue);

     scsi_bus_new(&s->bus, &dev->qdev, 1, LSI_MAX_DEVS, lsi_command_complete);
diff --git a/hw/macio.c b/hw/macio.c
index e92e82a..653b4df 100644
--- a/hw/macio.c
+++ b/hw/macio.c
@@ -27,83 +27,16 @@ 
 #include "pci.h"
 #include "escc.h"

-typedef struct macio_state_t macio_state_t;
-struct macio_state_t {
-    int is_oldworld;
-    int pic_mem_index;
-    int dbdma_mem_index;
-    int cuda_mem_index;
-    int escc_mem_index;
-    void *nvram;
-    int nb_ide;
-    int ide_mem_index[4];
-};
-
-static void macio_map (PCIDevice *pci_dev, int region_num,
-                       pcibus_t addr, pcibus_t size, int type)
-{
-    macio_state_t *macio_state;
-    int i;
-
-    macio_state = (macio_state_t *)(pci_dev + 1);
-    if (macio_state->pic_mem_index >= 0) {
-        if (macio_state->is_oldworld) {
-            /* Heathrow PIC */
-            cpu_register_physical_memory(addr + 0x00000, 0x1000,
-                                         macio_state->pic_mem_index);
-        } else {
-            /* OpenPIC */
-            cpu_register_physical_memory(addr + 0x40000, 0x40000,
-                                         macio_state->pic_mem_index);
-        }
-    }
-    if (macio_state->dbdma_mem_index >= 0) {
-        cpu_register_physical_memory(addr + 0x08000, 0x1000,
-                                     macio_state->dbdma_mem_index);
-    }
-    if (macio_state->escc_mem_index >= 0) {
-        cpu_register_physical_memory(addr + 0x13000, ESCC_SIZE << 4,
-                                     macio_state->escc_mem_index);
-    }
-    if (macio_state->cuda_mem_index >= 0) {
-        cpu_register_physical_memory(addr + 0x16000, 0x2000,
-                                     macio_state->cuda_mem_index);
-    }
-    for (i = 0; i < macio_state->nb_ide; i++) {
-        if (macio_state->ide_mem_index[i] >= 0) {
-            cpu_register_physical_memory(addr + 0x1f000 + (i * 0x1000), 0x1000,
-                                         macio_state->ide_mem_index[i]);
-        }
-    }
-    if (macio_state->nvram != NULL)
-        macio_nvram_map(macio_state->nvram, addr + 0x60000);
-}
-
 void macio_init (PCIBus *bus, int device_id, int is_oldworld, int
pic_mem_index,
-                 int dbdma_mem_index, int cuda_mem_index, void *nvram,
-                 int nb_ide, int *ide_mem_index, int escc_mem_index)
+                 int dbdma_mem_index, int cuda_mem_index, int nvram_size,
+                 int nvram_mem_index, int nb_ide, int *ide_mem_index,
+                 int escc_mem_index)
 {
     PCIDevice *d;
-    macio_state_t *macio_state;
     int i;

-    d = pci_register_device(bus, "macio",
-                            sizeof(PCIDevice) + sizeof(macio_state_t),
-                            -1, NULL, NULL);
-    macio_state = (macio_state_t *)(d + 1);
-    macio_state->is_oldworld = is_oldworld;
-    macio_state->pic_mem_index = pic_mem_index;
-    macio_state->dbdma_mem_index = dbdma_mem_index;
-    macio_state->cuda_mem_index = cuda_mem_index;
-    macio_state->escc_mem_index = escc_mem_index;
-    macio_state->nvram = nvram;
-    if (nb_ide > 4)
-        nb_ide = 4;
-    macio_state->nb_ide = nb_ide;
-    for (i = 0; i < nb_ide; i++)
-        macio_state->ide_mem_index[i] = ide_mem_index[i];
-    for (; i < 4; i++)
-        macio_state->ide_mem_index[i] = -1;
+    d = pci_register_device(bus, "macio", sizeof(PCIDevice), -1, NULL, NULL);
+
     /* Note: this code is strongly inspirated from the corresponding code
        in PearPC */

@@ -114,6 +47,32 @@  void macio_init (PCIBus *bus, int device_id, int
is_oldworld, int pic_mem_index,

     d->config[0x3d] = 0x01; // interrupt on pin 1

-    pci_register_bar(d, 0, 0x80000,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, macio_map);
+    pci_register_bar(d, 0, 0x80000, PCI_BASE_ADDRESS_SPACE_MEMORY);
+    if (pic_mem_index >= 0) {
+        if (is_oldworld) {
+            /* Heathrow PIC */
+            pci_bar_map(d, 0, 0, 0x1000, 0, pic_mem_index);
+        } else {
+            /* OpenPIC */
+            pci_bar_map(d, 0, 0, 0x40000, 0x40000, pic_mem_index);
+        }
+    }
+    if (dbdma_mem_index >= 0) {
+        pci_bar_map(d, 0, 1, 0x8000, 0x1000, dbdma_mem_index);
+    }
+    if (escc_mem_index >= 0) {
+        pci_bar_map(d, 0, 2, 0x13000, ESCC_SIZE << 4, escc_mem_index);
+    }
+    if (cuda_mem_index >= 0) {
+        pci_bar_map(d, 0, 3, 0x16000, 0x2000, cuda_mem_index);
+    }
+    for (i = 0; i < nb_ide; i++) {
+        if (ide_mem_index[i] >= 0) {
+            pci_bar_map(d, 0, 4 + i, 0x1f000 + (i * 0x1000), 0x1000,
+                        ide_mem_index[i]);
+        }
+    }
+    if (nvram_mem_index >= 0) {
+        pci_bar_map(d, 0, 4 + nb_ide, 0x60000, nvram_size, nvram_mem_index);
+    }
 }
diff --git a/hw/ne2000.c b/hw/ne2000.c
index 78fe14f..7598e76 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -464,6 +464,18 @@  uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
     return ret;
 }

+static IOPortWriteFunc * const ne2000_io_writes[] = {
+    ne2000_ioport_write,
+    NULL,
+    NULL,
+};
+
+static IOPortReadFunc * const ne2000_io_reads[] = {
+    ne2000_ioport_read,
+    NULL,
+    NULL,
+};
+
 static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr,
                                      uint32_t val)
 {
@@ -611,6 +623,18 @@  static uint32_t ne2000_asic_ioport_readl(void
*opaque, uint32_t addr)
     return ret;
 }

+static IOPortWriteFunc * const ne2000_asic_io_writes[] = {
+    ne2000_asic_ioport_write,
+    ne2000_asic_ioport_write,
+    ne2000_asic_ioport_writel,
+};
+
+static IOPortReadFunc * const ne2000_asic_io_reads[] = {
+    ne2000_asic_ioport_read,
+    ne2000_asic_ioport_read,
+    ne2000_asic_ioport_readl,
+};
+
 void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 {
     /* nothing to do (end of reset pulse) */
@@ -623,6 +647,18 @@  uint32_t ne2000_reset_ioport_read(void *opaque,
uint32_t addr)
     return 0;
 }

+static IOPortWriteFunc * const ne2000_reset_io_writes[] = {
+    ne2000_reset_ioport_write,
+    NULL,
+    NULL,
+};
+
+static IOPortReadFunc * const ne2000_reset_io_reads[] = {
+    ne2000_reset_ioport_read,
+    NULL,
+    NULL,
+};
+
 static int ne2000_post_load(void* opaque, int version_id)
 {
     NE2000State* s = opaque;
@@ -678,26 +714,6 @@  static const VMStateDescription vmstate_pci_ne2000 = {
 /***********************************************************/
 /* PCI NE2000 definitions */

-static void ne2000_map(PCIDevice *pci_dev, int region_num,
-                       pcibus_t addr, pcibus_t size, int type)
-{
-    PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
-    NE2000State *s = &d->ne2000;
-
-    register_ioport_write(addr, 16, 1, ne2000_ioport_write, s);
-    register_ioport_read(addr, 16, 1, ne2000_ioport_read, s);
-
-    register_ioport_write(addr + 0x10, 1, 1, ne2000_asic_ioport_write, s);
-    register_ioport_read(addr + 0x10, 1, 1, ne2000_asic_ioport_read, s);
-    register_ioport_write(addr + 0x10, 2, 2, ne2000_asic_ioport_write, s);
-    register_ioport_read(addr + 0x10, 2, 2, ne2000_asic_ioport_read, s);
-    register_ioport_write(addr + 0x10, 4, 4, ne2000_asic_ioport_writel, s);
-    register_ioport_read(addr + 0x10, 4, 4, ne2000_asic_ioport_readl, s);
-
-    register_ioport_write(addr + 0x1f, 1, 1, ne2000_reset_ioport_write, s);
-    register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
-}
-
 static void ne2000_cleanup(VLANClientState *nc)
 {
     NE2000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
@@ -718,6 +734,7 @@  static int pci_ne2000_init(PCIDevice *pci_dev)
     PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
     NE2000State *s;
     uint8_t *pci_conf;
+    int io_index;

     pci_conf = d->dev.config;
     pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REALTEK);
@@ -727,9 +744,14 @@  static int pci_ne2000_init(PCIDevice *pci_dev)
     /* TODO: RST# value should be 0. PCI spec 6.2.4 */
     pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0

-    pci_register_bar(&d->dev, 0, 0x100,
-                           PCI_BASE_ADDRESS_SPACE_IO, ne2000_map);
     s = &d->ne2000;
+    pci_register_bar(&d->dev, 0, 0x100, PCI_BASE_ADDRESS_SPACE_IO);
+    io_index = cpu_register_io(ne2000_io_reads, ne2000_io_writes, 16, s);
+    pci_bar_map(&d->dev, 0, 0, 0, 16, io_index);
+    io_index = cpu_register_io(ne2000_asic_io_reads,
ne2000_asic_io_writes, 4, s);
+    pci_bar_map(&d->dev, 0, 1, 0x10, 4, io_index);
+    io_index = cpu_register_io(ne2000_reset_io_reads,
ne2000_reset_io_writes, 1, s);
+    pci_bar_map(&d->dev, 0, 2, 0x1f, 1, io_index);
     s->irq = d->dev.irq[0];

     qemu_macaddr_default_if_unset(&s->c.macaddr);
diff --git a/hw/openpic.c b/hw/openpic.c
index 2b4cb00..ed1903d 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -1013,34 +1013,6 @@  static CPUReadMemoryFunc * const openpic_read[] = {
     &openpic_readl,
 };

-static void openpic_map(PCIDevice *pci_dev, int region_num,
-                        pcibus_t addr, pcibus_t size, int type)
-{
-    openpic_t *opp;
-
-    DPRINTF("Map OpenPIC\n");
-    opp = (openpic_t *)pci_dev;
-    /* Global registers */
-    DPRINTF("Register OPENPIC gbl   %08x => %08x\n",
-            addr + 0x1000, addr + 0x1000 + 0x100);
-    /* Timer registers */
-    DPRINTF("Register OPENPIC timer %08x => %08x\n",
-            addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR);
-    /* Interrupt source registers */
-    DPRINTF("Register OPENPIC src   %08x => %08x\n",
-            addr + 0x10000, addr + 0x10000 + 0x20 * (OPENPIC_EXT_IRQ + 2));
-    /* Per CPU registers */
-    DPRINTF("Register OPENPIC dst   %08x => %08x\n",
-            addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU);
-    cpu_register_physical_memory(addr, 0x40000, opp->mem_index);
-#if 0 // Don't implement ISU for now
-    opp_io_memory = cpu_register_io_memory(openpic_src_read,
-                                           openpic_src_write);
-    cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
-                                 opp_io_memory);
-#endif
-}
-
 static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
 {
     unsigned int i;
@@ -1199,12 +1171,14 @@  qemu_irq *openpic_init (PCIBus *bus, int
*pmem_index, int nb_cpus,

         /* Register I/O spaces */
         pci_register_bar((PCIDevice *)opp, 0, 0x40000,
-                               PCI_BASE_ADDRESS_SPACE_MEMORY, &openpic_map);
+                               PCI_BASE_ADDRESS_SPACE_MEMORY);
     } else {
         opp = qemu_mallocz(sizeof(openpic_t));
     }
-    opp->mem_index = cpu_register_io_memory(openpic_read,
-                                            openpic_write, opp);
+    opp->mem_index = cpu_register_io_memory(openpic_read, openpic_write, opp);
+    if (bus) {
+        pci_bar_map((PCIDevice *)opp, 0, 0, 0x40000, 0, opp->mem_index);
+    }

     //    isu_base &= 0xFFFC0000;
     opp->nb_cpus = nb_cpus;
diff --git a/hw/pci.c b/hw/pci.c
index a7ff566..fd4b1bb 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -681,19 +681,28 @@  static target_phys_addr_t pci_to_cpu_addr(PCIBus *bus,
 static void pci_unregister_io_regions(PCIDevice *pci_dev)
 {
     PCIIORegion *r;
-    int i;
+    PCIIOSubRegion *s;
+    int i, j;

     for(i = 0; i < PCI_NUM_REGIONS; i++) {
         r = &pci_dev->io_regions[i];
         if (!r->size || r->addr == PCI_BAR_UNMAPPED)
             continue;
-        if (r->type == PCI_BASE_ADDRESS_SPACE_IO) {
-            isa_unassign_ioport(r->addr, r->filtered_size);
-        } else {
-            cpu_register_physical_memory(pci_to_cpu_addr(pci_dev->bus,
-                                                         r->addr),
-                                         r->filtered_size,
-                                         IO_MEM_UNASSIGNED);
+
+        for (j = 0; j < PCI_NUM_SUBREGIONS; j++) {
+            s = &r->subregions[j];
+
+            if (!s->size) {
+                continue;
+            }
+            if (r->type == PCI_BASE_ADDRESS_SPACE_IO) {
+                isa_unassign_ioport(r->addr + s->offset, s->filtered_size);
+            } else {
+                cpu_register_physical_memory(pci_to_cpu_addr(pci_dev->bus,
+                                                         r->addr + s->offset),
+                                             s->filtered_size,
+                                             IO_MEM_UNASSIGNED);
+            }
         }
     }
 }
@@ -716,8 +725,7 @@  static int pci_unregister_device(DeviceState *dev)
 }

 void pci_register_bar(PCIDevice *pci_dev, int region_num,
-                            pcibus_t size, int type,
-                            PCIMapIORegionFunc *map_func)
+                      pcibus_t size, int type)
 {
     PCIIORegion *r;
     uint32_t addr;
@@ -735,9 +743,7 @@  void pci_register_bar(PCIDevice *pci_dev, int region_num,
     r = &pci_dev->io_regions[region_num];
     r->addr = PCI_BAR_UNMAPPED;
     r->size = size;
-    r->filtered_size = size;
     r->type = type;
-    r->map_func = map_func;

     wmask = ~(size - 1);
     addr = pci_bar(pci_dev, region_num);
@@ -756,6 +762,23 @@  void pci_register_bar(PCIDevice *pci_dev, int region_num,
     }
 }

+void pci_bar_map(PCIDevice *pci_dev, int region_num, int subregion_num,
+                 pcibus_t offset, pcibus_t size, int ix)
+{
+    PCIIOSubRegion *s;
+
+    if ((unsigned int)region_num >= PCI_NUM_REGIONS ||
+        (unsigned int)subregion_num >= PCI_NUM_SUBREGIONS) {
+        return;
+    }
+
+    s = &pci_dev->io_regions[region_num].subregions[subregion_num];
+
+    s->offset = offset;
+    s->size = size;
+    s->ix = ix;
+}
+
 static uint32_t pci_config_get_io_base(PCIDevice *d,
                                        uint32_t base, uint32_t base_upper16)
 {
@@ -928,8 +951,9 @@  static pcibus_t pci_bar_address(PCIDevice *d,
 static void pci_update_mappings(PCIDevice *d)
 {
     PCIIORegion *r;
-    int i;
-    pcibus_t new_addr, filtered_size;
+    PCIIOSubRegion *s;
+    int i, j;
+    pcibus_t bar_addr, new_addr, filtered_size;

     for(i = 0; i < PCI_NUM_REGIONS; i++) {
         r = &d->io_regions[i];
@@ -938,54 +962,71 @@  static void pci_update_mappings(PCIDevice *d)
         if (!r->size)
             continue;

-        new_addr = pci_bar_address(d, i, r->type, r->size);
+        bar_addr = pci_bar_address(d, i, r->type, r->size);

-        /* bridge filtering */
-        filtered_size = r->size;
-        if (new_addr != PCI_BAR_UNMAPPED) {
-            pci_bridge_filter(d, &new_addr, &filtered_size, r->type);
-        }
+        for (j = 0; j < PCI_NUM_SUBREGIONS; j++) {
+            s = &r->subregions[j];

-        /* This bar isn't changed */
-        if (new_addr == r->addr && filtered_size == r->filtered_size)
-            continue;
+            /* this region isn't registered */
+            if (!s->size) {
+                continue;
+            }

-        /* now do the real mapping */
-        if (r->addr != PCI_BAR_UNMAPPED) {
-            if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
-                int class;
-                /* NOTE: specific hack for IDE in PC case:
-                   only one byte must be mapped. */
-                class = pci_get_word(d->config + PCI_CLASS_DEVICE);
-                if (class == 0x0101 && r->size == 4) {
-                    isa_unassign_ioport(r->addr + 2, 1);
+            new_addr = bar_addr + s->offset;
+            /* bridge filtering */
+            filtered_size = s->size;
+            if (bar_addr != PCI_BAR_UNMAPPED) {
+                pci_bridge_filter(d, &new_addr, &filtered_size, r->type);
+            }
+
+            /* This bar isn't changed */
+            if (new_addr == r->addr + s->offset &&
+                filtered_size == s->filtered_size)
+                continue;
+
+            /* now do the real mapping */
+            if (r->addr != PCI_BAR_UNMAPPED) {
+                if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
+                    int class;
+                    /* NOTE: specific hack for IDE in PC case:
+                       only one byte must be mapped. */
+                    class = pci_get_word(d->config + PCI_CLASS_DEVICE);
+                    if (class == 0x0101 && r->size == 4) {
+                        isa_unassign_ioport(r->addr + s->offset + 2, 1);
+                    } else {
+                        isa_unassign_ioport(r->addr + s->offset,
+                                            s->filtered_size);
+                    }
                 } else {
-                    isa_unassign_ioport(r->addr, r->filtered_size);
+                    cpu_register_physical_memory(pci_to_cpu_addr(d->bus,
+                                                                 r->addr +
+                                                                 s->offset),
+                                                 s->filtered_size,
+                                                 IO_MEM_UNASSIGNED);
+                    qemu_unregister_coalesced_mmio(r->addr + s->offset,
+                                                   s->filtered_size);
                 }
-            } else {
-                cpu_register_physical_memory(pci_to_cpu_addr(d->bus, r->addr),
-                                             r->filtered_size,
-                                             IO_MEM_UNASSIGNED);
-                qemu_unregister_coalesced_mmio(r->addr, r->filtered_size);
             }
-        }
-        r->addr = new_addr;
-        r->filtered_size = filtered_size;
-        if (r->addr != PCI_BAR_UNMAPPED) {
-            /*
-             * TODO: currently almost all the map funcions assumes
-             * filtered_size == size and addr & ~(size - 1) == addr.
-             * However with bridge filtering, they aren't always true.
-             * Teach them such cases, such that filtered_size < size and
-             * addr & (size - 1) != 0.
-             */
-            if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
-                r->map_func(d, i, r->addr, r->filtered_size, r->type);
-            } else {
-                r->map_func(d, i, pci_to_cpu_addr(d->bus, r->addr),
-                            r->filtered_size, r->type);
+            s->filtered_size = filtered_size;
+            if (new_addr != PCI_BAR_UNMAPPED) {
+                /*
+                 * TODO: currently almost all the map funcions assumes
+                 * filtered_size == size and addr & ~(size - 1) == addr.
+                 * However with bridge filtering, they aren't always true.
+                 * Teach them such cases, such that filtered_size < size and
+                 * addr & (size - 1) != 0.
+                 */
+                if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
+                    cpu_map_io(new_addr, s->ix);
+                } else {
+                    cpu_register_physical_memory(pci_to_cpu_addr(d->bus,
+                                                                 new_addr),
+                                                 s->filtered_size,
+                                                 s->ix);
+                }
             }
         }
+        r->addr = bar_addr;
     }
 }

@@ -1704,11 +1745,6 @@  static uint8_t
pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id,
     return next;
 }

-static void pci_map_option_rom(PCIDevice *pdev, int region_num,
pcibus_t addr, pcibus_t size, int type)
-{
-    cpu_register_physical_memory(addr, size, pdev->rom_offset);
-}
-
 /* Add an option rom for the device */
 static int pci_add_option_rom(PCIDevice *pdev)
 {
@@ -1761,8 +1797,8 @@  static int pci_add_option_rom(PCIDevice *pdev)
     load_image(path, ptr);
     qemu_free(path);

-    pci_register_bar(pdev, PCI_ROM_SLOT, size,
-                     0, pci_map_option_rom);
+    pci_register_bar(pdev, PCI_ROM_SLOT, size, 0);
+    pci_bar_map(pdev, PCI_ROM_SLOT, 0, 0, size, pdev->rom_offset);

     return 0;
 }
diff --git a/hw/pci.h b/hw/pci.h
index 3a15bd4..3648105 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -80,13 +80,21 @@  typedef void PCIMapIORegionFunc(PCIDevice
*pci_dev, int region_num,
                                 pcibus_t addr, pcibus_t size, int type);
 typedef int PCIUnregisterFunc(PCIDevice *pci_dev);

+typedef struct PCIIOSubRegion {
+    pcibus_t offset; /* offset to BAR start. -1 means not mapped */
+    pcibus_t size;
+    pcibus_t filtered_size;
+    int ix;
+} PCIIOSubRegion;
+
+#define PCI_NUM_SUBREGIONS 8
+
 typedef struct PCIIORegion {
     pcibus_t addr; /* current PCI mapping address. -1 means not mapped */
 #define PCI_BAR_UNMAPPED (~(pcibus_t)0)
     pcibus_t size;
-    pcibus_t filtered_size;
     uint8_t type;
-    PCIMapIORegionFunc *map_func;
+    PCIIOSubRegion subregions[PCI_NUM_SUBREGIONS];
 } PCIIORegion;

 #define PCI_ROM_SLOT 6
@@ -175,8 +183,10 @@  PCIDevice *pci_register_device(PCIBus *bus, const
char *name,
                                PCIConfigWriteFunc *config_write);

 void pci_register_bar(PCIDevice *pci_dev, int region_num,
-                            pcibus_t size, int type,
-                            PCIMapIORegionFunc *map_func);
+                      pcibus_t size, int type);
+
+void pci_bar_map(PCIDevice *pci_dev, int region_num, int subregion_num,
+                 pcibus_t offset, pcibus_t size, int ix);

 int pci_add_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
 int pci_add_capability_at_offset(PCIDevice *pci_dev, uint8_t cap_id,
diff --git a/hw/pcnet.c b/hw/pcnet.c
index 5e63eb5..4782717 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -1615,6 +1615,18 @@  static uint32_t pcnet_aprom_readb(void *opaque,
uint32_t addr)
     return val;
 }

+static IOPortWriteFunc * const pcnet_aprom_writes[] = {
+    pcnet_aprom_writeb,
+    NULL,
+    NULL,
+};
+
+static IOPortReadFunc * const pcnet_aprom_reads[] = {
+    pcnet_aprom_readb,
+    NULL,
+    NULL,
+};
+
 void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
 {
     PCNetState *s = opaque;
@@ -1726,24 +1738,17 @@  static uint32_t pcnet_ioport_readl(void
*opaque, uint32_t addr)
     return val;
 }

-static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num,
-                             pcibus_t addr, pcibus_t size, int type)
-{
-    PCNetState *d = &DO_UPCAST(PCIPCNetState, pci_dev, pci_dev)->state;
-
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_ioport_map addr=0x%04"FMT_PCIBUS" size=0x%04"FMT_PCIBUS"\n",
-           addr, size);
-#endif
-
-    register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d);
-    register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d);
+static IOPortWriteFunc * const pcnet_ioport_writes[] = {
+    NULL,
+    pcnet_ioport_writew,
+    pcnet_ioport_writel,
+};

-    register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d);
-    register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d);
-    register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d);
-    register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d);
-}
+static IOPortReadFunc * const pcnet_ioport_reads[] = {
+    NULL,
+    pcnet_ioport_readw,
+    pcnet_ioport_readl,
+};

 static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr,
uint32_t val)
 {
@@ -1915,19 +1920,6 @@  static CPUReadMemoryFunc * const pcnet_mmio_read[] = {
     &pcnet_mmio_readl
 };

-static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num,
-                            pcibus_t addr, pcibus_t size, int type)
-{
-    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
-
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n",
-           addr, size);
-#endif
-
-    cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE,
d->state.mmio_index);
-}
-
 static void pci_physical_memory_write(void *dma_opaque,
target_phys_addr_t addr,
                                       uint8_t *buf, int len, int do_bswap)
 {
@@ -1971,6 +1963,7 @@  static int pci_pcnet_init(PCIDevice *pci_dev)
     PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
     PCNetState *s = &d->state;
     uint8_t *pci_conf;
+    int io_index;

 #if 0
     printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
@@ -2011,10 +2004,15 @@  static int pci_pcnet_init(PCIDevice *pci_dev)

     /* TODO: use pci_dev, avoid cast below. */
     pci_register_bar((PCIDevice *)d, 0, PCNET_IOPORT_SIZE,
-                           PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map);
+                           PCI_BASE_ADDRESS_SPACE_IO);
+    io_index = cpu_register_io(pcnet_aprom_reads, pcnet_aprom_writes, 16, s);
+    pci_bar_map((PCIDevice *)d, 0, 0, 0, 16, io_index);
+    io_index = cpu_register_io(pcnet_ioport_reads, pcnet_ioport_writes, 16, s);
+    pci_bar_map((PCIDevice *)d, 0, 1, 0x10, 16, io_index);

     pci_register_bar((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, pcnet_mmio_map);
+                           PCI_BASE_ADDRESS_SPACE_MEMORY);
+    pci_bar_map((PCIDevice *)d, 1, 0, 0, PCNET_PNPMMIO_SIZE, s->mmio_index);

     s->irq = pci_dev->irq[0];
     s->phys_mem_read = pci_physical_memory_read;
diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h
index 89f96bb..6b3e27f 100644
--- a/hw/ppc_mac.h
+++ b/hw/ppc_mac.h
@@ -46,8 +46,9 @@  void cuda_init (int *cuda_mem_index, qemu_irq irq);

 /* MacIO */
 void macio_init (PCIBus *bus, int device_id, int is_oldworld, int
pic_mem_index,
-                 int dbdma_mem_index, int cuda_mem_index, void *nvram,
-                 int nb_ide, int *ide_mem_index, int escc_mem_index);
+                 int dbdma_mem_index, int cuda_mem_index, int nvram_size,
+                 int nvram_mem_index, int nb_ide, int *ide_mem_index,
+                 int escc_mem_index);

 /* Heathrow PIC */
 qemu_irq *heathrow_pic_init(int *pmem_index,
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index fbba9b6..75fef3c 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -383,7 +383,7 @@  static void ppc_core99_init (ram_addr_t ram_size,
     adb_mouse_init(&adb_bus);

     macio_init(pci_bus, PCI_DEVICE_ID_APPLE_UNI_N_KEYL, 0, pic_mem_index,
-               dbdma_mem_index, cuda_mem_index, NULL, 3, ide_mem_index,
+               dbdma_mem_index, cuda_mem_index, -1, 0, 3, ide_mem_index,
                escc_mem_index);

     if (usb_enabled) {
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index 6b3ab89..220dca7 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -366,8 +366,8 @@  static void ppc_heathrow_init (ram_addr_t ram_size,
     pmac_format_nvram_partition(nvr, 0x2000);

     macio_init(pci_bus, PCI_DEVICE_ID_APPLE_343S1201, 1, pic_mem_index,
-               dbdma_mem_index, cuda_mem_index, nvr, 2, ide_mem_index,
-               escc_mem_index);
+               dbdma_mem_index, cuda_mem_index, nvram_mem_index, 0x2000,
+               2, ide_mem_index, escc_mem_index);

     if (usb_enabled) {
         usb_ohci_init_pci(pci_bus, -1);
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 72e2242..d87f3ae 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -3269,28 +3269,17 @@  static const VMStateDescription vmstate_rtl8139 = {
 /***********************************************************/
 /* PCI RTL8139 definitions */

-static void rtl8139_mmio_map(PCIDevice *pci_dev, int region_num,
-                       pcibus_t addr, pcibus_t size, int type)
-{
-    RTL8139State *s = DO_UPCAST(RTL8139State, dev, pci_dev);
-
-    cpu_register_physical_memory(addr + 0, 0x100, s->rtl8139_mmio_io_addr);
-}
-
-static void rtl8139_ioport_map(PCIDevice *pci_dev, int region_num,
-                       pcibus_t addr, pcibus_t size, int type)
-{
-    RTL8139State *s = DO_UPCAST(RTL8139State, dev, pci_dev);
-
-    register_ioport_write(addr, 0x100, 1, rtl8139_ioport_writeb, s);
-    register_ioport_read( addr, 0x100, 1, rtl8139_ioport_readb,  s);
-
-    register_ioport_write(addr, 0x100, 2, rtl8139_ioport_writew, s);
-    register_ioport_read( addr, 0x100, 2, rtl8139_ioport_readw,  s);
+static IOPortWriteFunc * const rtl8139_io_writes[] = {
+    rtl8139_ioport_writeb,
+    rtl8139_ioport_writew,
+    rtl8139_ioport_writel,
+};

-    register_ioport_write(addr, 0x100, 4, rtl8139_ioport_writel, s);
-    register_ioport_read( addr, 0x100, 4, rtl8139_ioport_readl,  s);
-}
+static IOPortReadFunc * const rtl8139_io_reads[] = {
+    rtl8139_ioport_readb,
+    rtl8139_ioport_readw,
+    rtl8139_ioport_readl,
+};

 static CPUReadMemoryFunc * const rtl8139_mmio_read[3] = {
     rtl8139_mmio_readb,
@@ -3353,6 +3342,7 @@  static int pci_rtl8139_init(PCIDevice *dev)
 {
     RTL8139State * s = DO_UPCAST(RTL8139State, dev, dev);
     uint8_t *pci_conf;
+    int io_index;

     pci_conf = s->dev.config;
     pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REALTEK);
@@ -3372,11 +3362,11 @@  static int pci_rtl8139_init(PCIDevice *dev)
     s->rtl8139_mmio_io_addr =
         cpu_register_io_memory(rtl8139_mmio_read, rtl8139_mmio_write, s);

-    pci_register_bar(&s->dev, 0, 0x100,
-                           PCI_BASE_ADDRESS_SPACE_IO,  rtl8139_ioport_map);
-
-    pci_register_bar(&s->dev, 1, 0x100,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, rtl8139_mmio_map);
+    pci_register_bar(&s->dev, 0, 0x100, PCI_BASE_ADDRESS_SPACE_IO);
+    io_index = cpu_register_io(rtl8139_io_reads, rtl8139_io_writes, 0x100, s);
+    pci_bar_map(&s->dev, 0, 0, 0, 0x100, io_index);
+    pci_register_bar(&s->dev, 1, 0x100, PCI_BASE_ADDRESS_SPACE_MEMORY);
+    pci_bar_map(&s->dev, 1, 0, 0, 0x100, s->rtl8139_mmio_io_addr);

     qemu_macaddr_default_if_unset(&s->conf.macaddr);

diff --git a/hw/sun4u.c b/hw/sun4u.c
index 2234b4e..48d89d3 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -517,21 +517,6 @@  void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
     }
 }

-static void ebus_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
-                              pcibus_t addr, pcibus_t size, int type)
-{
-    EBUS_DPRINTF("Mapping region %d registers at %" FMT_PCIBUS "\n",
-                 region_num, addr);
-    switch (region_num) {
-    case 0:
-        isa_mmio_init(addr, 0x1000000, 1);
-        break;
-    case 1:
-        isa_mmio_init(addr, 0x800000, 1);
-        break;
-    }
-}
-
 static void dummy_isa_irq_handler(void *opaque, int n, int level)
 {
 }
@@ -550,6 +535,8 @@  pci_ebus_init(PCIBus *bus, int devfn)
 static int
 pci_ebus_init1(PCIDevice *s)
 {
+    int io_index;
+
     isa_bus_new(&s->qdev);

     pci_config_set_vendor_id(s->config, PCI_VENDOR_ID_SUN);
@@ -564,10 +551,14 @@  pci_ebus_init1(PCIDevice *s)
     s->config[0x0D] = 0x0a; // latency_timer
     s->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type

-    pci_register_bar(s, 0, 0x1000000, PCI_BASE_ADDRESS_SPACE_MEMORY,
-                           ebus_mmio_mapfunc);
-    pci_register_bar(s, 1, 0x800000,  PCI_BASE_ADDRESS_SPACE_MEMORY,
-                           ebus_mmio_mapfunc);
+    pci_register_bar(s, 0, 0x1000000, PCI_BASE_ADDRESS_SPACE_MEMORY);
+    io_index = pci_isa_mmio_init(1);
+    pci_bar_map(s, 0, 0, 0, 0x1000000, io_index);
+
+    pci_register_bar(s, 1, 0x800000, PCI_BASE_ADDRESS_SPACE_MEMORY);
+    io_index = pci_isa_mmio_init(1);
+    pci_bar_map(s, 1, 0, 0, 0x800000, io_index);
+
     return 0;
 }

diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index c60fd8d..343603f 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1717,13 +1717,6 @@  typedef struct {
     OHCIState state;
 } OHCIPCIState;

-static void ohci_mapfunc(PCIDevice *pci_dev, int i,
-            pcibus_t addr, pcibus_t size, int type)
-{
-    OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, pci_dev);
-    cpu_register_physical_memory(addr, size, ohci->state.mem);
-}
-
 static int usb_ohci_initfn_pci(struct PCIDevice *dev)
 {
     OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, dev);
@@ -1742,7 +1735,8 @@  static int usb_ohci_initfn_pci(struct PCIDevice *dev)

     /* TODO: avoid cast below by using dev */
     pci_register_bar((struct PCIDevice *)ohci, 0, 256,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, ohci_mapfunc);
+                     PCI_BASE_ADDRESS_SPACE_MEMORY);
+    pci_bar_map((struct PCIDevice *)ohci, 0, 0, 256, 0, ohci->state.mem);
     return 0;
 }

diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 4cdb55e..b182eb5 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -1088,23 +1088,22 @@  static void uhci_frame_timer(void *opaque)
     qemu_mod_timer(s->frame_timer, s->expire_time);
 }

-static void uhci_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
-{
-    UHCIState *s = (UHCIState *)pci_dev;
-
-    register_ioport_write(addr, 32, 2, uhci_ioport_writew, s);
-    register_ioport_read(addr, 32, 2, uhci_ioport_readw, s);
-    register_ioport_write(addr, 32, 4, uhci_ioport_writel, s);
-    register_ioport_read(addr, 32, 4, uhci_ioport_readl, s);
-    register_ioport_write(addr, 32, 1, uhci_ioport_writeb, s);
-    register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
-}
+static IOPortWriteFunc * const uhci_io_writes[] = {
+    uhci_ioport_writeb,
+    uhci_ioport_writew,
+    uhci_ioport_writel,
+};
+
+static IOPortReadFunc * const uhci_io_reads[] = {
+    uhci_ioport_readb,
+    uhci_ioport_readw,
+    uhci_ioport_readl,
+};

 static int usb_uhci_common_initfn(UHCIState *s)
 {
     uint8_t *pci_conf = s->dev.config;
-    int i;
+    int i, io_index;

     pci_conf[PCI_REVISION_ID] = 0x01; // revision number
     pci_conf[PCI_CLASS_PROG] = 0x00;
@@ -1127,9 +1126,9 @@  static int usb_uhci_common_initfn(UHCIState *s)

     /* Use region 4 for consistency with real hardware.  BSD guests seem
        to rely on this.  */
-    pci_register_bar(&s->dev, 4, 0x20,
-                           PCI_BASE_ADDRESS_SPACE_IO, uhci_map);
-
+    pci_register_bar(&s->dev, 4, 0x20, PCI_BASE_ADDRESS_SPACE_IO);
+    io_index = cpu_register_io(uhci_io_reads, uhci_io_writes, 32, s);
+    pci_bar_map(&s->dev, 4, 0, 0, 0x20, io_index);
     return 0;
 }

diff --git a/hw/vga-pci.c b/hw/vga-pci.c
index eef78ed..818e77f 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -47,21 +47,6 @@  static const VMStateDescription vmstate_vga_pci = {
     }
 };

-static void vga_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
-{
-    PCIVGAState *d = (PCIVGAState *)pci_dev;
-    VGACommonState *s = &d->vga;
-    if (region_num == PCI_ROM_SLOT) {
-        cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
-    } else {
-        cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
-        s->map_addr = addr;
-        s->map_end = addr + s->vram_size;
-        vga_dirty_log_start(s);
-    }
-}
-
 static void pci_vga_write_config(PCIDevice *d,
                                  uint32_t address, uint32_t val, int len)
 {
@@ -93,8 +78,8 @@  static int pci_vga_initfn(PCIDevice *dev)
      pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type

      /* XXX: VGA_RAM_SIZE must be a power of two */
-     pci_register_bar(&d->dev, 0, VGA_RAM_SIZE,
-                      PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
+     pci_register_bar(&d->dev, 0, VGA_RAM_SIZE, PCI_BASE_ADDRESS_MEM_PREFETCH);
+     pci_bar_map(&d->dev, 0, 0, 0, s->vram_size, s->vram_offset);

      if (s->bios_size) {
         unsigned int bios_total_size;
@@ -103,7 +88,8 @@  static int pci_vga_initfn(PCIDevice *dev)
         while (bios_total_size < s->bios_size)
             bios_total_size <<= 1;
         pci_register_bar(&d->dev, PCI_ROM_SLOT, bios_total_size,
-                         PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
+                         PCI_BASE_ADDRESS_MEM_PREFETCH);
+        pci_bar_map(&d->dev, PCI_ROM_SLOT, 0, 0, s->bios_size, s->bios_offset);
      }

     vga_init_vbe(s);
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index c6ef825..415acfc 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -374,25 +374,17 @@  static void virtio_pci_config_writel(void
*opaque, uint32_t addr, uint32_t val)
     virtio_config_writel(proxy->vdev, addr, val);
 }

-static void virtio_map(PCIDevice *pci_dev, int region_num,
-                       pcibus_t addr, pcibus_t size, int type)
-{
-    VirtIOPCIProxy *proxy = container_of(pci_dev, VirtIOPCIProxy, pci_dev);
-    VirtIODevice *vdev = proxy->vdev;
-    unsigned config_len = VIRTIO_PCI_REGION_SIZE(pci_dev) + vdev->config_len;
-
-    proxy->addr = addr;
-
-    register_ioport_write(addr, config_len, 1,
virtio_pci_config_writeb, proxy);
-    register_ioport_write(addr, config_len, 2,
virtio_pci_config_writew, proxy);
-    register_ioport_write(addr, config_len, 4,
virtio_pci_config_writel, proxy);
-    register_ioport_read(addr, config_len, 1, virtio_pci_config_readb, proxy);
-    register_ioport_read(addr, config_len, 2, virtio_pci_config_readw, proxy);
-    register_ioport_read(addr, config_len, 4, virtio_pci_config_readl, proxy);
+static IOPortWriteFunc * const virtio_pci_config_io_writes[] = {
+    virtio_pci_config_writeb,
+    virtio_pci_config_writew,
+    virtio_pci_config_writel,
+};

-    if (vdev->config_len)
-        vdev->get_config(vdev, vdev->config);
-}
+static IOPortReadFunc * const virtio_pci_config_io_reads[] = {
+    virtio_pci_config_readb,
+    virtio_pci_config_readw,
+    virtio_pci_config_readl,
+};

 static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
                                 uint32_t val, int len)
@@ -495,6 +487,7 @@  static void virtio_init_pci(VirtIOPCIProxy *proxy,
VirtIODevice *vdev,
 {
     uint8_t *config;
     uint32_t size;
+    int io_index;

     proxy->vdev = vdev;

@@ -518,8 +511,7 @@  static void virtio_init_pci(VirtIOPCIProxy *proxy,
VirtIODevice *vdev,
     if (vdev->nvectors && !msix_init(&proxy->pci_dev, vdev->nvectors, 1, 0)) {
         pci_register_bar(&proxy->pci_dev, 1,
                          msix_bar_size(&proxy->pci_dev),
-                         PCI_BASE_ADDRESS_SPACE_MEMORY,
-                         msix_mmio_map);
+                         PCI_BASE_ADDRESS_SPACE_MEMORY);
     } else
         vdev->nvectors = 0;

@@ -529,8 +521,11 @@  static void virtio_init_pci(VirtIOPCIProxy
*proxy, VirtIODevice *vdev,
     if (size & (size-1))
         size = 1 << qemu_fls(size);

-    pci_register_bar(&proxy->pci_dev, 0, size, PCI_BASE_ADDRESS_SPACE_IO,
-                           virtio_map);
+    pci_register_bar(&proxy->pci_dev, 0, size, PCI_BASE_ADDRESS_SPACE_IO);
+    io_index = cpu_register_io(virtio_pci_config_io_reads,
+                               virtio_pci_config_io_writes,
+                               size, &proxy->pci_dev);
+    pci_bar_map(&proxy->pci_dev, 0, 0, 0, size, io_index);

     virtio_bind_device(vdev, &virtio_pci_bindings, proxy);
     proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY;
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index 9e72d2e..bf5f075 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -1178,65 +1178,47 @@  static void vmsvga_init(struct vmsvga_state_s
*s, int vga_ram_size)
     vmsvga_reset(s);
 }

-static void pci_vmsvga_map_ioport(PCIDevice *pci_dev, int region_num,
-                pcibus_t addr, pcibus_t size, int type)
-{
-    struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev;
-    struct vmsvga_state_s *s = &d->chip;
-
-    register_ioport_read(addr + SVGA_IO_MUL * SVGA_INDEX_PORT,
-                    1, 4, vmsvga_index_read, s);
-    register_ioport_write(addr + SVGA_IO_MUL * SVGA_INDEX_PORT,
-                    1, 4, vmsvga_index_write, s);
-    register_ioport_read(addr + SVGA_IO_MUL * SVGA_VALUE_PORT,
-                    1, 4, vmsvga_value_read, s);
-    register_ioport_write(addr + SVGA_IO_MUL * SVGA_VALUE_PORT,
-                    1, 4, vmsvga_value_write, s);
-    register_ioport_read(addr + SVGA_IO_MUL * SVGA_BIOS_PORT,
-                    1, 4, vmsvga_bios_read, s);
-    register_ioport_write(addr + SVGA_IO_MUL * SVGA_BIOS_PORT,
-                    1, 4, vmsvga_bios_write, s);
-}
+static IOPortWriteFunc * const vmsvga_index_io_writes[] = {
+    NULL,
+    NULL,
+    vmsvga_index_write,
+};

-static void pci_vmsvga_map_mem(PCIDevice *pci_dev, int region_num,
-                pcibus_t addr, pcibus_t size, int type)
-{
-    struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev;
-    struct vmsvga_state_s *s = &d->chip;
-    ram_addr_t iomemtype;
+static IOPortReadFunc * const vmsvga_index_io_reads[] = {
+    NULL,
+    NULL,
+    vmsvga_index_read,
+};

-    s->vram_base = addr;
-#ifdef DIRECT_VRAM
-    iomemtype = cpu_register_io_memory(vmsvga_vram_read,
-                    vmsvga_vram_write, s);
-#else
-    iomemtype = s->vga.vram_offset | IO_MEM_RAM;
-#endif
-    cpu_register_physical_memory(s->vram_base, s->vga.vram_size,
-                    iomemtype);
+static IOPortWriteFunc * const vmsvga_value_io_writes[] = {
+    NULL,
+    NULL,
+    vmsvga_value_write,
+};

-    s->vga.map_addr = addr;
-    s->vga.map_end = addr + s->vga.vram_size;
-    vga_dirty_log_restart(&s->vga);
-}
+static IOPortReadFunc * const vmsvga_value_io_reads[] = {
+    NULL,
+    NULL,
+    vmsvga_value_read,
+};

-static void pci_vmsvga_map_fifo(PCIDevice *pci_dev, int region_num,
-                pcibus_t addr, pcibus_t size, int type)
-{
-    struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev;
-    struct vmsvga_state_s *s = &d->chip;
-    ram_addr_t iomemtype;
+static IOPortWriteFunc * const vmsvga_bios_io_writes[] = {
+    NULL,
+    NULL,
+    vmsvga_bios_write,
+};

-    s->fifo_base = addr;
-    iomemtype = s->fifo_offset | IO_MEM_RAM;
-    cpu_register_physical_memory(s->fifo_base, s->fifo_size,
-                    iomemtype);
-}
+static IOPortReadFunc * const vmsvga_bios_io_reads[] = {
+    NULL,
+    NULL,
+    vmsvga_bios_read,
+};

 static int pci_vmsvga_initfn(PCIDevice *dev)
 {
     struct pci_vmsvga_state_s *s =
         DO_UPCAST(struct pci_vmsvga_state_s, card, dev);
+    ram_addr_t iomemtype;

     pci_config_set_vendor_id(s->card.config, PCI_VENDOR_ID_VMWARE);
     pci_config_set_device_id(s->card.config, SVGA_PCI_DEVICE_ID);
@@ -1253,16 +1235,33 @@  static int pci_vmsvga_initfn(PCIDevice *dev)
     s->card.config[PCI_SUBSYSTEM_ID + 1] = SVGA_PCI_DEVICE_ID >> 8;
     s->card.config[PCI_INTERRUPT_LINE] = 0xff;		/* End */

-    pci_register_bar(&s->card, 0, 0x10,
-                    PCI_BASE_ADDRESS_SPACE_IO, pci_vmsvga_map_ioport);
+    pci_register_bar(&s->card, 0, 0x10, PCI_BASE_ADDRESS_SPACE_IO);
+    iomemtype = cpu_register_io(vmsvga_index_io_reads, vmsvga_index_io_writes,
+                                4, &s->card);
+    pci_bar_map(&s->card, 0, 0, SVGA_IO_MUL * SVGA_INDEX_PORT, 4, iomemtype);
+    iomemtype = cpu_register_io(vmsvga_value_io_reads, vmsvga_value_io_writes,
+                                4, &s->card);
+    pci_bar_map(&s->card, 0, 0, SVGA_IO_MUL * SVGA_VALUE_PORT, 4, iomemtype);
+    iomemtype = cpu_register_io(vmsvga_bios_io_reads, vmsvga_bios_io_writes,
+                                4, &s->card);
+    pci_bar_map(&s->card, 0, 0, SVGA_IO_MUL * SVGA_BIOS_PORT, 4, iomemtype);
     pci_register_bar(&s->card, 1, VGA_RAM_SIZE,
-                    PCI_BASE_ADDRESS_MEM_PREFETCH, pci_vmsvga_map_mem);
-
+                     PCI_BASE_ADDRESS_MEM_PREFETCH);
     pci_register_bar(&s->card, 2, SVGA_FIFO_SIZE,
-		     PCI_BASE_ADDRESS_MEM_PREFETCH, pci_vmsvga_map_fifo);
+                     PCI_BASE_ADDRESS_MEM_PREFETCH);

     vmsvga_init(&s->chip, VGA_RAM_SIZE);

+#ifdef DIRECT_VRAM
+    iomemtype = cpu_register_io_memory(vmsvga_vram_read,
+                    vmsvga_vram_write, s);
+#else
+    iomemtype = s->chip.vga.vram_offset | IO_MEM_RAM;
+#endif
+    pci_bar_map(&s->card, 1, 0, 0, s->chip.vga.vram_size, iomemtype);
+    iomemtype = s->chip.fifo_offset | IO_MEM_RAM;
+    pci_bar_map(&s->card, 2, 0, 0, s->chip.fifo_size, iomemtype);
+
     return 0;
 }

diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c
index be0e89e..4c5bb32 100644
--- a/hw/wdt_i6300esb.c
+++ b/hw/wdt_i6300esb.c
@@ -342,29 +342,17 @@  static void i6300esb_mem_writel(void *vp,
target_phys_addr_t addr, uint32_t val)
     }
 }

-static void i6300esb_map(PCIDevice *dev, int region_num,
-                         pcibus_t addr, pcibus_t size, int type)
-{
-    static CPUReadMemoryFunc * const mem_read[3] = {
-        i6300esb_mem_readb,
-        i6300esb_mem_readw,
-        i6300esb_mem_readl,
-    };
-    static CPUWriteMemoryFunc * const mem_write[3] = {
-        i6300esb_mem_writeb,
-        i6300esb_mem_writew,
-        i6300esb_mem_writel,
-    };
-    I6300State *d = DO_UPCAST(I6300State, dev, dev);
-    int io_mem;
-
-    i6300esb_debug("addr = %"FMT_PCIBUS", size = %"FMT_PCIBUS", type = %d\n",
-                   addr, size, type);
+static CPUReadMemoryFunc * const mem_read[3] = {
+    i6300esb_mem_readb,
+    i6300esb_mem_readw,
+    i6300esb_mem_readl,
+};

-    io_mem = cpu_register_io_memory(mem_read, mem_write, d);
-    cpu_register_physical_memory (addr, 0x10, io_mem);
-    /* qemu_register_coalesced_mmio (addr, 0x10); ? */
-}
+static CPUWriteMemoryFunc * const mem_write[3] = {
+    i6300esb_mem_writeb,
+    i6300esb_mem_writew,
+    i6300esb_mem_writel,
+};

 static const VMStateDescription vmstate_i6300esb = {
     .name = "i6300esb_wdt",
@@ -393,6 +381,7 @@  static int i6300esb_init(PCIDevice *dev)
 {
     I6300State *d = DO_UPCAST(I6300State, dev, dev);
     uint8_t *pci_conf;
+    int io_mem;

     d->reboot_enabled = 1;
     d->clock_scale = CLOCK_SCALE_1KHZ;
@@ -413,8 +402,9 @@  static int i6300esb_init(PCIDevice *dev)
     pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER);
     pci_conf[PCI_HEADER_TYPE] = 0x00;

-    pci_register_bar(&d->dev, 0, 0x10,
-                            PCI_BASE_ADDRESS_SPACE_MEMORY, i6300esb_map);
+    pci_register_bar(&d->dev, 0, 0x10, PCI_BASE_ADDRESS_SPACE_MEMORY);
+    io_mem = cpu_register_io_memory(mem_read, mem_write, d);
+    pci_bar_map(&d->dev, 0, 0, 0, 0x10, io_mem);

     return 0;
 }
diff --git a/ioport.c b/ioport.c
index 53dd87a..90fec90 100644
--- a/ioport.c
+++ b/ioport.c
@@ -54,29 +54,39 @@  static IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
 static IOPortReadFunc default_ioport_readb, default_ioport_readw,
default_ioport_readl;
 static IOPortWriteFunc default_ioport_writeb, default_ioport_writew,
default_ioport_writel;

+#define IO_NB_ENTRIES 256
+
+static IOPortWriteFunc *io_writes[IO_NB_ENTRIES][3];
+static IOPortReadFunc *io_reads[IO_NB_ENTRIES][3];
+static void *io_opaques[IO_NB_ENTRIES];
+static int io_sizes[IO_NB_ENTRIES];
+static char io_used[IO_NB_ENTRIES];
+
+static IOPortReadFunc * const default_read_func[3] = {
+    default_ioport_readb,
+    default_ioport_readw,
+    default_ioport_readl
+};
+
 static uint32_t ioport_read(int index, uint32_t address)
 {
-    static IOPortReadFunc * const default_func[3] = {
-        default_ioport_readb,
-        default_ioport_readw,
-        default_ioport_readl
-    };
     IOPortReadFunc *func = ioport_read_table[index][address];
     if (!func)
-        func = default_func[index];
+        func = default_read_func[index];
     return func(ioport_opaque[address], address);
 }

+static IOPortWriteFunc * const default_write_func[3] = {
+    default_ioport_writeb,
+    default_ioport_writew,
+    default_ioport_writel
+};
+
 static void ioport_write(int index, uint32_t address, uint32_t data)
 {
-    static IOPortWriteFunc * const default_func[3] = {
-        default_ioport_writeb,
-        default_ioport_writew,
-        default_ioport_writel
-    };
     IOPortWriteFunc *func = ioport_write_table[index][address];
     if (!func)
-        func = default_func[index];
+        func = default_write_func[index];
     func(ioport_opaque[address], address, data);
 }

@@ -173,6 +183,86 @@  int register_ioport_write(pio_addr_t start, int
length, int size,
     return 0;
 }

+static int get_free_io_mem_idx(void)
+{
+    int i;
+
+    for (i = 0; i < IO_NB_ENTRIES; i++) {
+        if (!io_used[i]) {
+            io_used[i] = 1;
+            return i;
+        }
+    }
+    fprintf(stderr, "RAN out out io_mem_idx, max %d !\n", IO_NB_ENTRIES);
+    return -1;
+}
+
+/* io_read and io_write are arrays of functions containing the
+   function to access byte (index 0), word (index 1) and dword (index
+   2). Functions can be omitted with a NULL function pointer. (-1) is
+   returned if error. */
+int cpu_register_io(IOPortReadFunc * const *io_read,
+                    IOPortWriteFunc * const *io_write,
+                    int size, void *opaque)
+{
+    unsigned int i;
+    int io_index;
+
+    io_index = get_free_io_mem_idx();
+    if (io_index == -1) {
+        return io_index;
+    }
+
+    if (io_read) {
+        for (i = 0; i < 3; ++i) {
+            io_reads[io_index][i] = io_read[i];
+        }
+    }
+    if (io_write) {
+        for (i = 0; i < 3; ++i) {
+            io_writes[io_index][i] = io_write[i];
+        }
+    }
+    io_opaques[io_index] = opaque;
+    io_sizes[io_index] = size;
+
+    return io_index;
+}
+
+void cpu_unregister_io(int io_index)
+{
+    unsigned int i;
+
+    for (i = 0; i < 3; i++) {
+        io_reads[io_index][i] = NULL;
+        io_writes[io_index][i] = NULL;
+    }
+    io_opaques[io_index] = NULL;
+    io_sizes[io_index] = 0;
+    io_used[io_index] = 0;
+}
+
+void cpu_map_io(pio_addr_t start, int io_index)
+{
+    unsigned int i, j;
+
+    assert(io_index >= 0);
+    for (i = start; i < start + io_sizes[io_index]; i++) {
+        for (j = 0; j < 3; j++) {
+            if (io_reads[io_index][j]) {
+                register_ioport_read(i, io_sizes[io_index], 1 << j,
+                                     io_reads[io_index][j],
+                                     io_opaques[io_index]);
+            }
+            if (io_writes[io_index][j]) {
+                register_ioport_write(i, io_sizes[io_index], 1 << j,
+                                      io_writes[io_index][j],
+                                      io_opaques[io_index]);
+            }
+        }
+    }
+}
+
 void isa_unassign_ioport(pio_addr_t start, int length)
 {
     int i;
@@ -190,6 +280,11 @@  void isa_unassign_ioport(pio_addr_t start, int length)
     }
 }

+void cpu_unmap_io(pio_addr_t start, int io_index)
+{
+    isa_unassign_ioport(start, io_sizes[io_index]);
+}
+
 /***********************************************************/

 void cpu_outb(pio_addr_t addr, uint8_t val)
diff --git a/ioport.h b/ioport.h
index 3d3c8a3..4ba78ed 100644
--- a/ioport.h
+++ b/ioport.h
@@ -40,6 +40,12 @@  int register_ioport_read(pio_addr_t start, int
length, int size,
                          IOPortReadFunc *func, void *opaque);
 int register_ioport_write(pio_addr_t start, int length, int size,
                           IOPortWriteFunc *func, void *opaque);
+int cpu_register_io(IOPortReadFunc * const *io_read,
+                    IOPortWriteFunc * const *io_write,
+                    int size, void *opaque);
+void cpu_unregister_io(int io_index);
+void cpu_map_io(pio_addr_t start, int io_index);
+void cpu_unmap_io(pio_addr_t start, int io_index);
 void isa_unassign_ioport(pio_addr_t start, int length);