diff mbox

[1/2] io: Add CPUIOMemoryOps and use it.

Message ID 240cc7fe94853e95b0c632e66cbbe429cc320554.1271795219.git.rth@twiddle.net
State New
Headers show

Commit Message

Richard Henderson April 20, 2010, 7:54 p.m. UTC
Transition the core i/o bits away from a couple of flat arrays
to use a structure naming the read/write callbacks.  For now,
retain the flat array interface for the drivers.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 cpu-common.h       |   14 ++-
 exec-all.h         |    3 +-
 exec.c             |  321 ++++++++++++++++++++++++++-------------------------
 softmmu_template.h |   36 ++++--
 4 files changed, 203 insertions(+), 171 deletions(-)
diff mbox

Patch

diff --git a/cpu-common.h b/cpu-common.h
index b730ca0..0566654 100644
--- a/cpu-common.h
+++ b/cpu-common.h
@@ -25,8 +25,17 @@  typedef unsigned long ram_addr_t;
 
 /* memory API */
 
-typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
-typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
+typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t, uint32_t);
+typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t);
+
+typedef struct CPUIOMemoryOps {
+    CPUReadMemoryFunc *readb;
+    CPUReadMemoryFunc *readw;
+    CPUReadMemoryFunc *readl;
+    CPUWriteMemoryFunc *writeb;
+    CPUWriteMemoryFunc *writew;
+    CPUWriteMemoryFunc *writel;
+} CPUIOMemoryOps;
 
 void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
                                          ram_addr_t size,
@@ -47,6 +56,7 @@  void *qemu_get_ram_ptr(ram_addr_t addr);
 /* This should not be used by devices.  */
 ram_addr_t qemu_ram_addr_from_host(void *ptr);
 
+int cpu_register_io_memory_st(const CPUIOMemoryOps *mem_ops, void *opaque);
 int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
                            CPUWriteMemoryFunc * const *mem_write,
                            void *opaque);
diff --git a/exec-all.h b/exec-all.h
index 4bae1e2..5007d59 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -267,8 +267,7 @@  extern int tb_invalidated_flag;
 
 #if !defined(CONFIG_USER_ONLY)
 
-extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
-extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
+extern CPUIOMemoryOps io_mem_ops[IO_MEM_NB_ENTRIES];
 extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];
 
 void tlb_fill(target_ulong addr, int is_write, int mmu_idx,
diff --git a/exec.c b/exec.c
index 43366ac..d8691c9 100644
--- a/exec.c
+++ b/exec.c
@@ -215,8 +215,7 @@  static void *l1_phys_map[P_L1_SIZE];
 static void io_mem_init(void);
 
 /* io memory support */
-CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
-CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
+CPUIOMemoryOps io_mem_ops[IO_MEM_NB_ENTRIES];
 void *io_mem_opaque[IO_MEM_NB_ENTRIES];
 static char io_mem_used[IO_MEM_NB_ENTRIES];
 static int io_mem_watch;
@@ -2549,10 +2548,9 @@  static inline void tlb_set_dirty(CPUState *env,
 #define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
 typedef struct subpage_t {
     target_phys_addr_t base;
-    CPUReadMemoryFunc * const *mem_read[TARGET_PAGE_SIZE][4];
-    CPUWriteMemoryFunc * const *mem_write[TARGET_PAGE_SIZE][4];
-    void *opaque[TARGET_PAGE_SIZE][2][4];
-    ram_addr_t region_offset[TARGET_PAGE_SIZE][2][4];
+    CPUIOMemoryOps mem_ops[TARGET_PAGE_SIZE];
+    void *opaque[TARGET_PAGE_SIZE];
+    ram_addr_t region_offset[TARGET_PAGE_SIZE];
 } subpage_t;
 
 static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
@@ -2962,16 +2960,20 @@  static void unassigned_mem_writel(void *opaque, target_phys_addr_t addr, uint32_
 #endif
 }
 
-static CPUReadMemoryFunc * const unassigned_mem_read[3] = {
-    unassigned_mem_readb,
-    unassigned_mem_readw,
-    unassigned_mem_readl,
+static const CPUIOMemoryOps unassigned_mem_ops = {
+    .readb = unassigned_mem_readb,
+    .readw = unassigned_mem_readw,
+    .readl = unassigned_mem_readl,
+    .writeb = unassigned_mem_writeb,
+    .writew = unassigned_mem_writew,
+    .writel = unassigned_mem_writel,
 };
 
-static CPUWriteMemoryFunc * const unassigned_mem_write[3] = {
-    unassigned_mem_writeb,
-    unassigned_mem_writew,
-    unassigned_mem_writel,
+static const CPUIOMemoryOps rom_mem_ops = {
+    /* Read functions never used.  */
+    .writeb = unassigned_mem_writeb,
+    .writew = unassigned_mem_writew,
+    .writel = unassigned_mem_writel,
 };
 
 static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr,
@@ -3034,16 +3036,11 @@  static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr,
         tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
 }
 
-static CPUReadMemoryFunc * const error_mem_read[3] = {
-    NULL, /* never used */
-    NULL, /* never used */
-    NULL, /* never used */
-};
-
-static CPUWriteMemoryFunc * const notdirty_mem_write[3] = {
-    notdirty_mem_writeb,
-    notdirty_mem_writew,
-    notdirty_mem_writel,
+static const CPUIOMemoryOps notdirty_mem_ops = {
+    /* Read functions never used.  */
+    .writeb = notdirty_mem_writeb,
+    .writew = notdirty_mem_writew,
+    .writel = notdirty_mem_writel,
 };
 
 /* Generate a debug exception if a watchpoint has been hit.  */
@@ -3133,121 +3130,115 @@  static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
     stl_phys(addr, val);
 }
 
-static CPUReadMemoryFunc * const watch_mem_read[3] = {
-    watch_mem_readb,
-    watch_mem_readw,
-    watch_mem_readl,
-};
-
-static CPUWriteMemoryFunc * const watch_mem_write[3] = {
-    watch_mem_writeb,
-    watch_mem_writew,
-    watch_mem_writel,
+static const CPUIOMemoryOps watch_mem_ops = {
+    .readb = watch_mem_readb,
+    .readw = watch_mem_readw,
+    .readl = watch_mem_readl,
+    .writeb = watch_mem_writeb,
+    .writew = watch_mem_writew,
+    .writel = watch_mem_writel,
 };
 
-static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
-                                 unsigned int len)
-{
-    uint32_t ret;
-    unsigned int idx;
-
-    idx = SUBPAGE_IDX(addr);
-#if defined(DEBUG_SUBPAGE)
-    printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
-           mmio, len, addr, idx);
-#endif
-    ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len],
-                                       addr + mmio->region_offset[idx][0][len]);
-
-    return ret;
-}
-
-static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
-                              uint32_t value, unsigned int len)
-{
-    unsigned int idx;
-
-    idx = SUBPAGE_IDX(addr);
-#if defined(DEBUG_SUBPAGE)
-    printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
-           mmio, len, addr, idx, value);
-#endif
-    (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len],
-                                  addr + mmio->region_offset[idx][1][len],
-                                  value);
-}
-
 static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
 {
+    subpage_t *mmio = opaque;
+    unsigned int idx = SUBPAGE_IDX(addr);
+
 #if defined(DEBUG_SUBPAGE)
-    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+    printf("%s: subpage %p addr " TARGET_FMT_plx " idx %d\n",
+           __func__, mmio, addr, idx);
 #endif
-
-    return subpage_readlen(opaque, addr, 0);
+ 
+    return mmio->mem_ops[idx].readb(mmio->opaque[idx],
+                                    addr + mmio->region_offset[idx]);
 }
 
 static void subpage_writeb (void *opaque, target_phys_addr_t addr,
                             uint32_t value)
 {
+    subpage_t *mmio = opaque;
+    unsigned int idx = SUBPAGE_IDX(addr);
+
 #if defined(DEBUG_SUBPAGE)
-    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
+    printf("%s: subpage %p addr " TARGET_FMT_plx " idx %d\n",
+           __func__, mmio, addr, idx);
 #endif
-    subpage_writelen(opaque, addr, value, 0);
+
+    return mmio->mem_ops[idx].writeb(mmio->opaque[idx],
+                                     addr + mmio->region_offset[idx], value);
 }
 
 static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
 {
+    subpage_t *mmio = opaque;
+    unsigned int idx = SUBPAGE_IDX(addr);
+
 #if defined(DEBUG_SUBPAGE)
-    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+    printf("%s: subpage %p addr " TARGET_FMT_plx " idx %d\n",
+           __func__, mmio, addr, idx);
 #endif
-
-    return subpage_readlen(opaque, addr, 1);
+ 
+    return mmio->mem_ops[idx].readw(mmio->opaque[idx],
+                                    addr + mmio->region_offset[idx]);
 }
 
 static void subpage_writew (void *opaque, target_phys_addr_t addr,
                             uint32_t value)
 {
+    subpage_t *mmio = opaque;
+    unsigned int idx = SUBPAGE_IDX(addr);
+
 #if defined(DEBUG_SUBPAGE)
-    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
+    printf("%s: subpage %p addr " TARGET_FMT_plx " idx %d\n",
+           __func__, mmio, addr, idx);
 #endif
-    subpage_writelen(opaque, addr, value, 1);
+
+    return mmio->mem_ops[idx].writew(mmio->opaque[idx],
+                                     addr + mmio->region_offset[idx], value);
 }
 
 static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
 {
+    subpage_t *mmio = opaque;
+    unsigned int idx = SUBPAGE_IDX(addr);
+
 #if defined(DEBUG_SUBPAGE)
-    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+    printf("%s: subpage %p addr " TARGET_FMT_plx " idx %d\n",
+           __func__, mmio, addr, idx);
 #endif
-
-    return subpage_readlen(opaque, addr, 2);
+ 
+    return mmio->mem_ops[idx].readl(mmio->opaque[idx],
+                                    addr + mmio->region_offset[idx]);
 }
 
 static void subpage_writel (void *opaque,
                          target_phys_addr_t addr, uint32_t value)
 {
+    subpage_t *mmio = opaque;
+    unsigned int idx = SUBPAGE_IDX(addr);
+
 #if defined(DEBUG_SUBPAGE)
-    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
+    printf("%s: subpage %p addr " TARGET_FMT_plx " idx %d\n",
+           __func__, mmio, addr, idx);
 #endif
-    subpage_writelen(opaque, addr, value, 2);
-}
 
-static CPUReadMemoryFunc * const subpage_read[] = {
-    &subpage_readb,
-    &subpage_readw,
-    &subpage_readl,
-};
+    return mmio->mem_ops[idx].writel(mmio->opaque[idx],
+                                     addr + mmio->region_offset[idx], value);
+}
 
-static CPUWriteMemoryFunc * const subpage_write[] = {
-    &subpage_writeb,
-    &subpage_writew,
-    &subpage_writel,
+static const CPUIOMemoryOps subpage_ops = {
+    .readb = subpage_readb,
+    .readw = subpage_readw,
+    .readl = subpage_readl,
+    .writeb = subpage_writeb,
+    .writew = subpage_writew,
+    .writel = subpage_writel,
 };
 
 static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
                              ram_addr_t memory, ram_addr_t region_offset)
 {
     int idx, eidx;
-    unsigned int i;
 
     if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
         return -1;
@@ -3258,19 +3249,11 @@  static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
            mmio, start, end, idx, eidx, memory);
 #endif
     memory >>= IO_MEM_SHIFT;
+
     for (; idx <= eidx; idx++) {
-        for (i = 0; i < 4; i++) {
-            if (io_mem_read[memory][i]) {
-                mmio->mem_read[idx][i] = &io_mem_read[memory][i];
-                mmio->opaque[idx][0][i] = io_mem_opaque[memory];
-                mmio->region_offset[idx][0][i] = region_offset;
-            }
-            if (io_mem_write[memory][i]) {
-                mmio->mem_write[idx][i] = &io_mem_write[memory][i];
-                mmio->opaque[idx][1][i] = io_mem_opaque[memory];
-                mmio->region_offset[idx][1][i] = region_offset;
-            }
-        }
+        mmio->mem_ops[idx] = io_mem_ops[memory];
+        mmio->opaque[idx] = io_mem_opaque[memory];
+        mmio->region_offset[idx] = region_offset;
     }
 
     return 0;
@@ -3285,7 +3268,7 @@  static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
     mmio = qemu_mallocz(sizeof(subpage_t));
 
     mmio->base = base;
-    subpage_memory = cpu_register_io_memory(subpage_read, subpage_write, mmio);
+    subpage_memory = cpu_register_io_memory_st(&subpage_ops, mmio);
 #if defined(DEBUG_SUBPAGE)
     printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
            mmio, base, TARGET_PAGE_SIZE, subpage_memory);
@@ -3310,19 +3293,17 @@  static int get_free_io_mem_idx(void)
     return -1;
 }
 
-/* mem_read and mem_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.
-   If io_index is non zero, the corresponding io zone is
-   modified. If it is zero, a new io zone is allocated. The return
-   value can be used with cpu_register_physical_memory(). (-1) is
-   returned if error. */
+/* MEM_OPS contains pointers to the functions giving sized acceses to
+   the I/O.  Access functions may be omitted with a NULL function pointer.
+   If IO_INDEX is non zero, the corresponding io zone is modified.  If it
+   is zero, a new io zone is allocated.  The return value can be used with
+   cpu_register_physical_memory(); -1 is returned if error. */
+
 static int cpu_register_io_memory_fixed(int io_index,
-                                        CPUReadMemoryFunc * const *mem_read,
-                                        CPUWriteMemoryFunc * const *mem_write,
+                                        const CPUIOMemoryOps *mem_ops,
                                         void *opaque)
 {
-    int i, subwidth = 0;
+    int subwidth = 0;
 
     if (io_index <= 0) {
         io_index = get_free_io_mem_idx();
@@ -3334,32 +3315,45 @@  static int cpu_register_io_memory_fixed(int io_index,
             return -1;
     }
 
-    for(i = 0;i < 3; i++) {
-        if (!mem_read[i] || !mem_write[i])
-            subwidth = IO_MEM_SUBWIDTH;
-        io_mem_read[io_index][i] = mem_read[i];
-        io_mem_write[io_index][i] = mem_write[i];
-    }
+    io_mem_ops[io_index] = *mem_ops;
     io_mem_opaque[io_index] = opaque;
+
+    if (!mem_ops->readl || !mem_ops->writel
+        || !mem_ops->readw || !mem_ops->writew
+        || !mem_ops->readb || !mem_ops->writeb) {
+        subwidth = IO_MEM_SUBWIDTH;
+    }
+
     return (io_index << IO_MEM_SHIFT) | subwidth;
 }
 
+int cpu_register_io_memory_st(const CPUIOMemoryOps *mem_ops, void *opaque)
+{
+    return cpu_register_io_memory_fixed(0, mem_ops, opaque);
+}
+
+/* Temporarily leave the existing array-based interface in place while
+   drivers are updated.  */
 int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
                            CPUWriteMemoryFunc * const *mem_write,
                            void *opaque)
 {
-    return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque);
+    CPUIOMemoryOps ops;
+    ops.readb = mem_read[0];
+    ops.readw = mem_read[1];
+    ops.readl = mem_read[2];
+    ops.writeb = mem_write[0];
+    ops.writew = mem_write[1];
+    ops.writel = mem_write[2];
+
+    return cpu_register_io_memory_fixed(0, &ops, opaque);
 }
 
 void cpu_unregister_io_memory(int io_table_address)
 {
-    int i;
     int io_index = io_table_address >> IO_MEM_SHIFT;
 
-    for (i=0;i < 3; i++) {
-        io_mem_read[io_index][i] = unassigned_mem_read[i];
-        io_mem_write[io_index][i] = unassigned_mem_write[i];
-    }
+    io_mem_ops[io_index] = unassigned_mem_ops;
     io_mem_opaque[io_index] = NULL;
     io_mem_used[io_index] = 0;
 }
@@ -3368,14 +3362,14 @@  static void io_mem_init(void)
 {
     int i;
 
-    cpu_register_io_memory_fixed(IO_MEM_ROM, error_mem_read, unassigned_mem_write, NULL);
-    cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, unassigned_mem_read, unassigned_mem_write, NULL);
-    cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read, notdirty_mem_write, NULL);
-    for (i=0; i<5; i++)
+    cpu_register_io_memory_fixed(IO_MEM_ROM, &rom_mem_ops, NULL);
+    cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, &unassigned_mem_ops, NULL);
+    cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, &notdirty_mem_ops, NULL);
+    for (i=0; i<5; i++) {
         io_mem_used[i] = 1;
+    }
 
-    io_mem_watch = cpu_register_io_memory(watch_mem_read,
-                                          watch_mem_write, NULL);
+    io_mem_watch = cpu_register_io_memory_st(&watch_mem_ops, NULL);
 }
 
 #endif /* !defined(CONFIG_USER_ONLY) */
@@ -3425,7 +3419,7 @@  int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
 void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                             int len, int is_write)
 {
-    int l, io_index;
+    int l;
     uint8_t *ptr;
     uint32_t val;
     target_phys_addr_t page;
@@ -3447,7 +3441,8 @@  void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
         if (is_write) {
             if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
                 target_phys_addr_t addr1 = addr;
-                io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+                int io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+                void *opaque = io_mem_opaque[io_index];
                 if (p)
                     addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
                 /* XXX: could force cpu_single_env to NULL to avoid
@@ -3455,17 +3450,17 @@  void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                 if (l >= 4 && ((addr1 & 3) == 0)) {
                     /* 32 bit write access */
                     val = ldl_p(buf);
-                    io_mem_write[io_index][2](io_mem_opaque[io_index], addr1, val);
+                    io_mem_ops[io_index].writel(opaque, addr1, val);
                     l = 4;
                 } else if (l >= 2 && ((addr1 & 1) == 0)) {
                     /* 16 bit write access */
                     val = lduw_p(buf);
-                    io_mem_write[io_index][1](io_mem_opaque[io_index], addr1, val);
+                    io_mem_ops[io_index].writew(opaque, addr1, val);
                     l = 2;
                 } else {
                     /* 8 bit write access */
                     val = ldub_p(buf);
-                    io_mem_write[io_index][0](io_mem_opaque[io_index], addr1, val);
+                    io_mem_ops[io_index].writeb(opaque, addr1, val);
                     l = 1;
                 }
             } else {
@@ -3487,22 +3482,23 @@  void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                 !(pd & IO_MEM_ROMD)) {
                 target_phys_addr_t addr1 = addr;
                 /* I/O case */
-                io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+                int io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+                void *opaque = io_mem_opaque[io_index];
                 if (p)
                     addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
                 if (l >= 4 && ((addr1 & 3) == 0)) {
                     /* 32 bit read access */
-                    val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr1);
+                    val = io_mem_ops[io_index].readl(opaque, addr1);
                     stl_p(buf, val);
                     l = 4;
                 } else if (l >= 2 && ((addr1 & 1) == 0)) {
                     /* 16 bit read access */
-                    val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr1);
+                    val = io_mem_ops[io_index].readw(opaque, addr1);
                     stw_p(buf, val);
                     l = 2;
                 } else {
                     /* 8 bit read access */
-                    val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr1);
+                    val = io_mem_ops[io_index].readb(opaque, addr1);
                     stb_p(buf, val);
                     l = 1;
                 }
@@ -3724,7 +3720,7 @@  uint32_t ldl_phys(target_phys_addr_t addr)
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
         if (p)
             addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
-        val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
+        val = io_mem_ops[io_index].readl(io_mem_opaque[io_index], addr);
     } else {
         /* RAM case */
         ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
@@ -3737,7 +3733,6 @@  uint32_t ldl_phys(target_phys_addr_t addr)
 /* warning: addr must be aligned */
 uint64_t ldq_phys(target_phys_addr_t addr)
 {
-    int io_index;
     uint8_t *ptr;
     uint64_t val;
     unsigned long pd;
@@ -3753,15 +3748,22 @@  uint64_t ldq_phys(target_phys_addr_t addr)
     if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
         !(pd & IO_MEM_ROMD)) {
         /* I/O case */
-        io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        int io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        void *opaque = io_mem_opaque[io_index];
+        CPUReadMemoryFunc *readl;
+        uint32_t v1, v2;
+
         if (p)
             addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+
+        readl = io_mem_ops[io_index].readl;
+        v1 = readl(opaque, addr);
+        v2 = readl(opaque, addr + 4);
+
 #ifdef TARGET_WORDS_BIGENDIAN
-        val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
-        val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
+        val = ((uint64_t)v1 << 32) | v2;
 #else
-        val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
-        val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
+        val = ((uint64_t)v2 << 32) | v1;
 #endif
     } else {
         /* RAM case */
@@ -3809,7 +3811,7 @@  void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
         if (p)
             addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
-        io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
+        io_mem_ops[io_index].writel(io_mem_opaque[io_index], addr, val);
     } else {
         unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
         ptr = qemu_get_ram_ptr(addr1);
@@ -3829,7 +3831,6 @@  void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
 
 void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
 {
-    int io_index;
     uint8_t *ptr;
     unsigned long pd;
     PhysPageDesc *p;
@@ -3842,16 +3843,22 @@  void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
     }
 
     if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
-        io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        int io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        void *opaque = io_mem_opaque[io_index];
+        CPUWriteMemoryFunc *writel;
+        uint32_t v1, v2;
+
         if (p)
             addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
 #ifdef TARGET_WORDS_BIGENDIAN
-        io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
-        io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
+        v1 = val >> 32, v2 = val;
 #else
-        io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
-        io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
+        v1 = val, v2 = val >> 32;
 #endif
+        writel = io_mem_ops[io_index].writel;
+
+        writel(opaque, addr, v1);
+        writel(opaque, addr + 4, v2);
     } else {
         ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
             (addr & ~TARGET_PAGE_MASK);
@@ -3878,7 +3885,7 @@  void stl_phys(target_phys_addr_t addr, uint32_t val)
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
         if (p)
             addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
-        io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
+        io_mem_ops[io_index].writel(io_mem_opaque[io_index], addr, val);
     } else {
         unsigned long addr1;
         addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
diff --git a/softmmu_template.h b/softmmu_template.h
index c2df9ec..27e23c9 100644
--- a/softmmu_template.h
+++ b/softmmu_template.h
@@ -57,6 +57,8 @@  static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr,
 {
     DATA_TYPE res;
     int index;
+    void *opaque;
+
     index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
     physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
     env->mem_io_pc = (unsigned long)retaddr;
@@ -66,16 +68,21 @@  static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr,
     }
 
     env->mem_io_vaddr = addr;
+    opaque = io_mem_opaque[index];
 #if SHIFT <= 2
-    res = io_mem_read[index][SHIFT](io_mem_opaque[index], physaddr);
+    res = io_mem_ops[index].glue(read,SUFFIX)(opaque, physaddr);
 #else
+    {
+        CPUReadMemoryFunc *readl = io_mem_ops[index].readl;
+        uint32_t v1 = readl(opaque, physaddr);
+        uint32_t v2 = readl(opaque, physaddr + 4);
+
 #ifdef TARGET_WORDS_BIGENDIAN
-    res = (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr) << 32;
-    res |= io_mem_read[index][2](io_mem_opaque[index], physaddr + 4);
+        res = ((uint64_t)v1 << 32) | v2;
 #else
-    res = io_mem_read[index][2](io_mem_opaque[index], physaddr);
-    res |= (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr + 4) << 32;
+        res = ((uint64_t)v2 << 32) | v1;
 #endif
+    }
 #endif /* SHIFT > 2 */
     return res;
 }
@@ -200,6 +207,8 @@  static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr,
                                           void *retaddr)
 {
     int index;
+    void *opaque;
+
     index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
     physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
     if (index > (IO_MEM_NOTDIRTY >> IO_MEM_SHIFT)
@@ -209,16 +218,23 @@  static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr,
 
     env->mem_io_vaddr = addr;
     env->mem_io_pc = (unsigned long)retaddr;
+    opaque = io_mem_opaque[index];
 #if SHIFT <= 2
-    io_mem_write[index][SHIFT](io_mem_opaque[index], physaddr, val);
+    io_mem_ops[index].glue(write,SUFFIX)(opaque, physaddr, val);
 #else
+    {
+        CPUWriteMemoryFunc *writel = io_mem_ops[index].writel;
+        uint32_t v1, v2;
+
 #ifdef TARGET_WORDS_BIGENDIAN
-    io_mem_write[index][2](io_mem_opaque[index], physaddr, val >> 32);
-    io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val);
+        v1 = val >> 32, v2 = val;
 #else
-    io_mem_write[index][2](io_mem_opaque[index], physaddr, val);
-    io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val >> 32);
+        v1 = val, v2 = val >> 32;
 #endif
+
+        writel(opaque, physaddr, v1);
+        writel(opaque, physaddr + 4, v2);
+    }
 #endif /* SHIFT > 2 */
 }