diff mbox

[2/2] io: Add readq/writeq hooks and use them.

Message ID 34811c00b8b37655d9955f6f21224709bc6ce004.1271795219.git.rth@twiddle.net
State New
Headers show

Commit Message

Richard Henderson April 20, 2010, 8:22 p.m. UTC
If the device provides full 64-bit i/o routines, use them instead
of forcing the i/o to be split into two 32-bit i/o calls.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 cpu-common.h       |    5 ++
 exec.c             |  144 ++++++++++++++++++++++++++++++++++++++++++++++------
 softmmu_template.h |    8 ++-
 3 files changed, 139 insertions(+), 18 deletions(-)
diff mbox

Patch

diff --git a/cpu-common.h b/cpu-common.h
index 0566654..df5ad32 100644
--- a/cpu-common.h
+++ b/cpu-common.h
@@ -28,13 +28,18 @@  typedef unsigned long ram_addr_t;
 typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t, uint32_t);
 typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t);
 
+typedef void CPUWriteMemory64Func(void *opaque, target_phys_addr_t, uint64_t);
+typedef uint64_t CPUReadMemory64Func(void *opaque, target_phys_addr_t);
+
 typedef struct CPUIOMemoryOps {
     CPUReadMemoryFunc *readb;
     CPUReadMemoryFunc *readw;
     CPUReadMemoryFunc *readl;
+    CPUReadMemory64Func *readq;
     CPUWriteMemoryFunc *writeb;
     CPUWriteMemoryFunc *writew;
     CPUWriteMemoryFunc *writel;
+    CPUWriteMemory64Func *writeq;
 } CPUIOMemoryOps;
 
 void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
diff --git a/exec.c b/exec.c
index d8691c9..596e2e4 100644
--- a/exec.c
+++ b/exec.c
@@ -2930,6 +2930,17 @@  static uint32_t unassigned_mem_readl(void *opaque, target_phys_addr_t addr)
     return 0;
 }
 
+static uint64_t unassigned_mem_readq(void *opaque, target_phys_addr_t addr)
+{
+#ifdef DEBUG_UNASSIGNED
+    printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
+#endif
+#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+    do_unassigned_access(addr, 0, 0, 0, 8);
+#endif
+    return 0;
+}
+
 static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
 #ifdef DEBUG_UNASSIGNED
@@ -2960,13 +2971,26 @@  static void unassigned_mem_writel(void *opaque, target_phys_addr_t addr, uint32_
 #endif
 }
 
+static void unassigned_mem_writeq(void *opaque, target_phys_addr_t addr, uint64_t val)
+{
+#ifdef DEBUG_UNASSIGNED
+    printf("Unassigned mem write " TARGET_FMT_plx " = 0x" PRIx64 "\n",
+           addr, val);
+#endif
+#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+    do_unassigned_access(addr, 1, 0, 0, 8);
+#endif
+}
+
 static const CPUIOMemoryOps unassigned_mem_ops = {
     .readb = unassigned_mem_readb,
     .readw = unassigned_mem_readw,
     .readl = unassigned_mem_readl,
+    .readq = unassigned_mem_readq,
     .writeb = unassigned_mem_writeb,
     .writew = unassigned_mem_writew,
     .writel = unassigned_mem_writel,
+    .writeq = unassigned_mem_writeq,
 };
 
 static const CPUIOMemoryOps rom_mem_ops = {
@@ -2974,6 +2998,7 @@  static const CPUIOMemoryOps rom_mem_ops = {
     .writeb = unassigned_mem_writeb,
     .writew = unassigned_mem_writew,
     .writel = unassigned_mem_writel,
+    .writeq = unassigned_mem_writeq,
 };
 
 static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr,
@@ -3036,11 +3061,32 @@  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 void notdirty_mem_writeq(void *opaque, target_phys_addr_t ram_addr,
+                                uint64_t val)
+{
+    int dirty_flags;
+    dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
+    if (!(dirty_flags & CODE_DIRTY_FLAG)) {
+#if !defined(CONFIG_USER_ONLY)
+        tb_invalidate_phys_page_fast(ram_addr, 8);
+        dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
+#endif
+    }
+    stq_p(qemu_get_ram_ptr(ram_addr), val);
+    dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
+    cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
+    /* we remove the notdirty callback only if the code has been flushed */
+    if (dirty_flags == 0xff) {
+        tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
+    }
+}
+
 static const CPUIOMemoryOps notdirty_mem_ops = {
     /* Read functions never used.  */
     .writeb = notdirty_mem_writeb,
     .writew = notdirty_mem_writew,
     .writel = notdirty_mem_writel,
+    .writeq = notdirty_mem_writeq,
 };
 
 /* Generate a debug exception if a watchpoint has been hit.  */
@@ -3109,6 +3155,12 @@  static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
     return ldl_phys(addr);
 }
 
+static uint64_t watch_mem_readq(void *opaque, target_phys_addr_t addr)
+{
+    check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x7, BP_MEM_READ);
+    return ldq_phys(addr);
+}
+
 static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
                              uint32_t val)
 {
@@ -3130,13 +3182,22 @@  static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
     stl_phys(addr, val);
 }
 
+static void watch_mem_writeq(void *opaque, target_phys_addr_t addr,
+                             uint64_t val)
+{
+    check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x7, BP_MEM_WRITE);
+    stq_phys(addr, val);
+}
+
 static const CPUIOMemoryOps watch_mem_ops = {
     .readb = watch_mem_readb,
     .readw = watch_mem_readw,
     .readl = watch_mem_readl,
+    .readq = watch_mem_readq,
     .writeb = watch_mem_writeb,
     .writew = watch_mem_writew,
     .writel = watch_mem_writel,
+    .writeq = watch_mem_writeq,
 };
 
 static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
@@ -3226,13 +3287,44 @@  static void subpage_writel (void *opaque,
                                      addr + mmio->region_offset[idx], value);
 }
 
+static uint64_t subpage_readq (void *opaque, target_phys_addr_t addr)
+{
+    subpage_t *mmio = opaque;
+    unsigned int idx = SUBPAGE_IDX(addr);
+
+#if defined(DEBUG_SUBPAGE)
+    printf("%s: subpage %p addr " TARGET_FMT_plx " idx %d\n",
+           __func__, mmio, addr, idx);
+#endif
+ 
+    return mmio->mem_ops[idx].readq(mmio->opaque[idx],
+                                    addr + mmio->region_offset[idx]);
+}
+
+static void subpage_writeq (void *opaque,
+                            target_phys_addr_t addr, uint64_t value)
+{
+    subpage_t *mmio = opaque;
+    unsigned int idx = SUBPAGE_IDX(addr);
+
+#if defined(DEBUG_SUBPAGE)
+    printf("%s: subpage %p addr " TARGET_FMT_plx " idx %d\n",
+           __func__, mmio, addr, idx);
+#endif
+
+    return mmio->mem_ops[idx].writeq(mmio->opaque[idx],
+                                     addr + mmio->region_offset[idx], value);
+}
+
 static const CPUIOMemoryOps subpage_ops = {
     .readb = subpage_readb,
     .readw = subpage_readw,
     .readl = subpage_readl,
+    .readq = subpage_readq,
     .writeb = subpage_writeb,
     .writew = subpage_writew,
     .writel = subpage_writel,
+    .writeq = subpage_writeq,
 };
 
 static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
@@ -3342,9 +3434,11 @@  int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
     ops.readb = mem_read[0];
     ops.readw = mem_read[1];
     ops.readl = mem_read[2];
+    ops.readq = NULL;
     ops.writeb = mem_write[0];
     ops.writew = mem_write[1];
     ops.writel = mem_write[2];
+    ops.writeq = NULL;
 
     return cpu_register_io_memory_fixed(0, &ops, opaque);
 }
@@ -3447,7 +3541,11 @@  void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                     addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
                 /* XXX: could force cpu_single_env to NULL to avoid
                    potential bugs */
-                if (l >= 4 && ((addr1 & 3) == 0)) {
+                if (l >= 8 && (addr1 & 7) == 0 && io_mem_ops[io_index].writeq) {
+                    uint64_t v64 = ldq_p(buf);
+                    io_mem_ops[io_index].writeq(opaque, addr1, v64);
+                    l = 8;
+                } else if (l >= 4 && ((addr1 & 3) == 0)) {
                     /* 32 bit write access */
                     val = ldl_p(buf);
                     io_mem_ops[io_index].writel(opaque, addr1, val);
@@ -3486,7 +3584,12 @@  void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                 void *opaque = io_mem_opaque[io_index];
                 if (p)
                     addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
-                if (l >= 4 && ((addr1 & 3) == 0)) {
+                if (l >= 8 && (addr1 & 7) == 0 && io_mem_ops[io_index].readq) {
+                    uint64_t v64;
+                    v64 = io_mem_ops[io_index].readq(opaque, addr1);
+                    stq_p(buf, val);
+                    l = 8;
+                } else if (l >= 4 && ((addr1 & 3) == 0)) {
                     /* 32 bit read access */
                     val = io_mem_ops[io_index].readl(opaque, addr1);
                     stl_p(buf, val);
@@ -3750,21 +3853,25 @@  uint64_t ldq_phys(target_phys_addr_t addr)
         /* I/O case */
         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);
+        if (io_mem_ops[io_index].readq) {
+            val = io_mem_ops[io_index].readq(opaque, addr);
+        } else {
+            CPUReadMemoryFunc *readl = io_mem_ops[io_index].readl;
+            uint32_t v1, v2;
+
+            v1 = readl(opaque, addr);
+            v2 = readl(opaque, addr + 4);
 
 #ifdef TARGET_WORDS_BIGENDIAN
-        val = ((uint64_t)v1 << 32) | v2;
+            val = ((uint64_t)v1 << 32) | v2;
 #else
-        val = ((uint64_t)v2 << 32) | v1;
+            val = ((uint64_t)v2 << 32) | v1;
 #endif
+        }
     } else {
         /* RAM case */
         ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
@@ -3845,20 +3952,25 @@  void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
     if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
         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;
+
+        if (io_mem_ops[io_index].writeq) {
+            io_mem_ops[io_index].writeq(opaque, addr, val);
+        } else {
+            CPUWriteMemoryFunc *writel = io_mem_ops[io_index].writel;
+            uint32_t v1, v2;
+
 #ifdef TARGET_WORDS_BIGENDIAN
-        v1 = val >> 32, v2 = val;
+            v1 = val >> 32, v2 = val;
 #else
-        v1 = val, v2 = val >> 32;
+            v1 = val, v2 = val >> 32;
 #endif
-        writel = io_mem_ops[io_index].writel;
 
-        writel(opaque, addr, v1);
-        writel(opaque, addr + 4, v2);
+            writel(opaque, addr, v1);
+            writel(opaque, addr + 4, v2);
+        }
     } else {
         ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
             (addr & ~TARGET_PAGE_MASK);
diff --git a/softmmu_template.h b/softmmu_template.h
index 27e23c9..37992e0 100644
--- a/softmmu_template.h
+++ b/softmmu_template.h
@@ -72,7 +72,9 @@  static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr,
 #if SHIFT <= 2
     res = io_mem_ops[index].glue(read,SUFFIX)(opaque, physaddr);
 #else
-    {
+    if (io_mem_ops[index].readq) {
+        res = io_mem_ops[index].readq(opaque, physaddr);
+    } else {
         CPUReadMemoryFunc *readl = io_mem_ops[index].readl;
         uint32_t v1 = readl(opaque, physaddr);
         uint32_t v2 = readl(opaque, physaddr + 4);
@@ -222,7 +224,9 @@  static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr,
 #if SHIFT <= 2
     io_mem_ops[index].glue(write,SUFFIX)(opaque, physaddr, val);
 #else
-    {
+    if (io_mem_ops[index].writeq) {
+        io_mem_ops[index].writeq(opaque, physaddr, val);
+    } else {
         CPUWriteMemoryFunc *writel = io_mem_ops[index].writel;
         uint32_t v1, v2;