qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC] Implement qword CPU access to device MMIO regions


From: Max Filippov
Subject: [Qemu-devel] [RFC] Implement qword CPU access to device MMIO regions
Date: Wed, 26 Oct 2011 16:24:48 +0400

From: Max Filippov <address@hidden>

For newly developed device verification we need to be able to distinguish qword
and dword access to its MMIO regions from CPU.

This goal is achieved with the following steps:
- io_mem_read[3] and io_mem_write[3] are used for the ldq/stq callbacks;
- softmmu io_read and io_write templates invoke these callbacks for 64 bit wide
  access if they are defined;
- new registration method (cpu_register_io_memory2) is defined for the devices
  that provide 64 bit wide MMIO access.

This implementation maintains backwards compatibility for the devices
that provide only 8-16-32 bit io memory access callbacks, allowing wider access
callbacks to be registered via cpu_register_io_memory2.

Legacy behavior of emulating 64 bit access via two adjacent 32 bit accesses
holds both for devices registered via cpu_register_io_memory and for those
registered via cpu_register_io_memory2 that do not provide 64 bit callbacks.

This implementation is developed for pre-memory API QEMU version.
If this approach proves to be useful I will port it to the new memory API. 

Signed-off-by: Max Filippov <address@hidden>
CC: Neil Turton <address@hidden>
CC: Konstantin Ushakov <address@hidden>
---
 cpu-common.h       |   23 +++++++++-
 exec.c             |  132 ++++++++++++++++++++++++++++++++++++++++------------
 softmmu_template.h |   10 ++++
 3 files changed, 134 insertions(+), 31 deletions(-)

diff --git a/cpu-common.h b/cpu-common.h
index c9878ba..173d3c2 100644
--- a/cpu-common.h
+++ b/cpu-common.h
@@ -35,8 +35,26 @@ typedef unsigned long ram_addr_t;
 
 /* memory API */
 
-typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, 
uint32_t value);
+typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr,
+        uint32_t value);
+typedef void CPUWriteMemoryFunc64(void *opaque, target_phys_addr_t addr,
+        uint64_t value);
 typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
+typedef uint64_t CPUReadMemoryFunc64(void *opaque, target_phys_addr_t addr);
+
+enum {
+    IO_MEM_FUNC32_NUM = 3,
+    IO_MEM_FUNC_NUM = 4,
+};
+typedef struct CPUWriteMemoryFuncs {
+    CPUWriteMemoryFunc * func32[IO_MEM_FUNC32_NUM];
+    CPUWriteMemoryFunc64 *func64;
+} CPUWriteMemoryFuncs;
+
+typedef struct CPUReadMemoryFuncs {
+    CPUReadMemoryFunc * func32[IO_MEM_FUNC32_NUM];
+    CPUReadMemoryFunc64 *func64;
+} CPUReadMemoryFuncs;
 
 void cpu_register_physical_memory_log(target_phys_addr_t start_addr,
                                       ram_addr_t size,
@@ -81,6 +99,9 @@ ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr);
 int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
                            CPUWriteMemoryFunc * const *mem_write,
                            void *opaque, enum device_endian endian);
+int cpu_register_io_memory2(const CPUReadMemoryFuncs *mem_read,
+                           const CPUWriteMemoryFuncs *mem_write,
+                           void *opaque, enum device_endian endian);
 void cpu_unregister_io_memory(int table_address);
 
 void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
diff --git a/exec.c b/exec.c
index d0cbf15..0133c9f 100644
--- a/exec.c
+++ b/exec.c
@@ -205,8 +205,8 @@ static void io_mem_init(void);
 static void memory_map_init(void);
 
 /* io memory support */
-CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
-CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
+CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][IO_MEM_FUNC_NUM];
+CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][IO_MEM_FUNC_NUM];
 void *io_mem_opaque[IO_MEM_NB_ENTRIES];
 static char io_mem_used[IO_MEM_NB_ENTRIES];
 static int io_mem_watch;
@@ -3310,13 +3310,13 @@ static void unassigned_mem_writel(void *opaque, 
target_phys_addr_t addr, uint32_
 #endif
 }
 
-static CPUReadMemoryFunc * const unassigned_mem_read[3] = {
+static CPUReadMemoryFunc * const unassigned_mem_read[IO_MEM_FUNC_NUM] = {
     unassigned_mem_readb,
     unassigned_mem_readw,
     unassigned_mem_readl,
 };
 
-static CPUWriteMemoryFunc * const unassigned_mem_write[3] = {
+static CPUWriteMemoryFunc * const unassigned_mem_write[IO_MEM_FUNC_NUM] = {
     unassigned_mem_writeb,
     unassigned_mem_writew,
     unassigned_mem_writel,
@@ -3640,8 +3640,8 @@ static int get_free_io_mem_idx(void)
  */
 
 typedef struct SwapEndianContainer {
-    CPUReadMemoryFunc *read[3];
-    CPUWriteMemoryFunc *write[3];
+    CPUReadMemoryFunc *read[IO_MEM_FUNC_NUM];
+    CPUWriteMemoryFunc *write[IO_MEM_FUNC_NUM];
     void *opaque;
 } SwapEndianContainer;
 
@@ -3669,10 +3669,20 @@ static uint32_t swapendian_mem_readl(void *opaque, 
target_phys_addr_t addr)
     return val;
 }
 
-static CPUReadMemoryFunc * const swapendian_readfn[3]={
+static CPUReadMemoryFunc64 swapendian_mem_readq;
+static uint64_t swapendian_mem_readq(void *opaque, target_phys_addr_t addr)
+{
+    uint64_t val;
+    SwapEndianContainer *c = opaque;
+    val = bswap64(((CPUReadMemoryFunc64 *)c->read[3])(c->opaque, addr));
+    return val;
+}
+
+static CPUReadMemoryFunc * const swapendian_readfn[IO_MEM_FUNC_NUM] = {
     swapendian_mem_readb,
     swapendian_mem_readw,
-    swapendian_mem_readl
+    swapendian_mem_readl,
+    (void *)swapendian_mem_readq,
 };
 
 static void swapendian_mem_writeb(void *opaque, target_phys_addr_t addr,
@@ -3696,10 +3706,19 @@ static void swapendian_mem_writel(void *opaque, 
target_phys_addr_t addr,
     c->write[2](c->opaque, addr, bswap32(val));
 }
 
-static CPUWriteMemoryFunc * const swapendian_writefn[3]={
+static CPUWriteMemoryFunc64 swapendian_mem_writeq;
+static void swapendian_mem_writeq(void *opaque, target_phys_addr_t addr,
+                                  uint64_t val)
+{
+    SwapEndianContainer *c = opaque;
+    ((CPUWriteMemoryFunc64 *)c->write[3])(c->opaque, addr, bswap64(val));
+}
+
+static CPUWriteMemoryFunc * const swapendian_writefn[IO_MEM_FUNC_NUM] = {
     swapendian_mem_writeb,
     swapendian_mem_writew,
-    swapendian_mem_writel
+    swapendian_mem_writel,
+    (void *)swapendian_mem_writeq,
 };
 
 static void swapendian_init(int io_index)
@@ -3709,12 +3728,16 @@ static void swapendian_init(int io_index)
 
     /* Swap mmio for big endian targets */
     c->opaque = io_mem_opaque[io_index];
-    for (i = 0; i < 3; i++) {
+    for (i = 0; i < IO_MEM_FUNC_NUM; i++) {
         c->read[i] = io_mem_read[io_index][i];
         c->write[i] = io_mem_write[io_index][i];
 
-        io_mem_read[io_index][i] = swapendian_readfn[i];
-        io_mem_write[io_index][i] = swapendian_writefn[i];
+        if (io_mem_read[io_index][i]) {
+            io_mem_read[io_index][i] = swapendian_readfn[i];
+        }
+        if (io_mem_write[io_index][i]) {
+            io_mem_write[io_index][i] = swapendian_writefn[i];
+        }
     }
     io_mem_opaque[io_index] = c;
 }
@@ -3736,6 +3759,7 @@ static void swapendian_del(int io_index)
 static int cpu_register_io_memory_fixed(int io_index,
                                         CPUReadMemoryFunc * const *mem_read,
                                         CPUWriteMemoryFunc * const *mem_write,
+                                        int func_num,
                                         void *opaque, enum device_endian 
endian)
 {
     int i;
@@ -3750,13 +3774,18 @@ static int cpu_register_io_memory_fixed(int io_index,
             return -1;
     }
 
-    for (i = 0; i < 3; ++i) {
-        io_mem_read[io_index][i]
-            = (mem_read[i] ? mem_read[i] : unassigned_mem_read[i]);
-    }
-    for (i = 0; i < 3; ++i) {
-        io_mem_write[io_index][i]
-            = (mem_write[i] ? mem_write[i] : unassigned_mem_write[i]);
+    for (i = 0; i < IO_MEM_FUNC_NUM; ++i) {
+        if (i < IO_MEM_FUNC32_NUM) {
+            io_mem_read[io_index][i]
+                = (mem_read[i] ? mem_read[i] : unassigned_mem_read[i]);
+            io_mem_write[io_index][i]
+                = (mem_write[i] ? mem_write[i] : unassigned_mem_write[i]);
+        } else {
+            io_mem_read[io_index][i]
+                = (i < func_num ? mem_read[i] : NULL);
+            io_mem_write[io_index][i]
+                = (i < func_num ? mem_write[i] : NULL);
+        }
     }
     io_mem_opaque[io_index] = opaque;
 
@@ -3783,7 +3812,27 @@ int cpu_register_io_memory(CPUReadMemoryFunc * const 
*mem_read,
                            CPUWriteMemoryFunc * const *mem_write,
                            void *opaque, enum device_endian endian)
 {
-    return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque, 
endian);
+    return cpu_register_io_memory_fixed(
+            0, mem_read, mem_write, IO_MEM_FUNC32_NUM,
+            opaque, endian);
+}
+
+int cpu_register_io_memory2(const CPUReadMemoryFuncs *mem_read,
+                           const CPUWriteMemoryFuncs *mem_write,
+                           void *opaque, enum device_endian endian)
+{
+    CPUReadMemoryFunc *mem_read_fns[IO_MEM_FUNC_NUM];
+    CPUWriteMemoryFunc *mem_write_fns[IO_MEM_FUNC_NUM];
+
+    memcpy(mem_read_fns, mem_read->func32, sizeof(mem_read->func32));
+    mem_read_fns[3] = (void *)mem_read->func64;
+
+    memcpy(mem_write_fns, mem_write->func32, sizeof(mem_write->func32));
+    mem_write_fns[3] = (void *)mem_write->func64;
+
+    return cpu_register_io_memory_fixed(
+            0, mem_read_fns, mem_write_fns, IO_MEM_FUNC_NUM,
+            opaque, endian);
 }
 
 void cpu_unregister_io_memory(int io_table_address)
@@ -3793,7 +3842,7 @@ void cpu_unregister_io_memory(int io_table_address)
 
     swapendian_del(io_index);
 
-    for (i=0;i < 3; i++) {
+    for (i = 0; i < IO_MEM_FUNC_NUM; i++) {
         io_mem_read[io_index][i] = unassigned_mem_read[i];
         io_mem_write[io_index][i] = unassigned_mem_write[i];
     }
@@ -3806,14 +3855,14 @@ static void io_mem_init(void)
     int i;
 
     cpu_register_io_memory_fixed(IO_MEM_ROM, error_mem_read,
-                                 unassigned_mem_write, NULL,
-                                 DEVICE_NATIVE_ENDIAN);
+                                 unassigned_mem_write, IO_MEM_FUNC32_NUM,
+                                 NULL, DEVICE_NATIVE_ENDIAN);
     cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, unassigned_mem_read,
-                                 unassigned_mem_write, NULL,
-                                 DEVICE_NATIVE_ENDIAN);
+                                 unassigned_mem_write, IO_MEM_FUNC32_NUM,
+                                 NULL, DEVICE_NATIVE_ENDIAN);
     cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read,
-                                 notdirty_mem_write, NULL,
-                                 DEVICE_NATIVE_ENDIAN);
+                                 notdirty_mem_write, IO_MEM_FUNC32_NUM,
+                                 NULL, DEVICE_NATIVE_ENDIAN);
     for (i=0; i<5; i++)
         io_mem_used[i] = 1;
 
@@ -3917,7 +3966,13 @@ 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_write[io_index][3]) 
{
+                    /* 32 bit write access */
+                    uint64_t val = ldq_p(buf);
+                    ((CPUWriteMemoryFunc64 *)io_mem_write[io_index][3])(
+                           io_mem_opaque[io_index], addr1, val);
+                    l = 8;
+                } else 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);
@@ -3956,7 +4011,14 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, 
uint8_t *buf,
                 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
                 if (p)
                     addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
-                if (l >= 4 && ((addr1 & 3) == 0)) {
+                if (l >= 8 && ((addr1 & 7) == 0) && io_mem_read[io_index][3]) {
+                    /* 64 bit read access */
+                    uint64_t val = ((CPUReadMemoryFunc64 *)
+                            io_mem_read[io_index][3])(
+                                io_mem_opaque[io_index], addr1);
+                    stq_p(buf, val);
+                    l = 8;
+                } else if (l >= 4 && ((addr1 & 3) == 0)) {
                     /* 32 bit read access */
                     val = io_mem_read[io_index][2](io_mem_opaque[io_index], 
addr1);
                     stl_p(buf, val);
@@ -4262,6 +4324,10 @@ static inline uint64_t 
ldq_phys_internal(target_phys_addr_t addr,
         if (p)
             addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
 
+        if (io_mem_read[io_index][3]) {
+            val = ((CPUReadMemoryFunc64 *)io_mem_read[io_index][3])(
+                    io_mem_opaque[io_index], addr);
+        } else {
         /* XXX This is broken when device endian != cpu endian.
                Fix and add "endian" variable check */
 #ifdef TARGET_WORDS_BIGENDIAN
@@ -4271,6 +4337,7 @@ static inline uint64_t 
ldq_phys_internal(target_phys_addr_t addr,
         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;
 #endif
+        }
     } else {
         /* RAM case */
         ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
@@ -4437,6 +4504,10 @@ void stq_phys_notdirty(target_phys_addr_t addr, uint64_t 
val)
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
         if (p)
             addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+        if (io_mem_write[io_index][3]) {
+            ((CPUWriteMemoryFunc64 *)io_mem_write[io_index][3])(
+                    io_mem_opaque[io_index], addr, val);
+        } else {
 #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);
@@ -4444,6 +4515,7 @@ void stq_phys_notdirty(target_phys_addr_t addr, uint64_t 
val)
         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);
 #endif
+        }
     } 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 36eb2e8..c767441 100644
--- a/softmmu_template.h
+++ b/softmmu_template.h
@@ -74,6 +74,10 @@ static inline DATA_TYPE glue(io_read, 
SUFFIX)(target_phys_addr_t physaddr,
 #if SHIFT <= 2
     res = io_mem_read[index][SHIFT](io_mem_opaque[index], physaddr);
 #else
+    if (io_mem_read[index][3]) {
+        res = ((CPUReadMemoryFunc64 *)
+                io_mem_read[index][3])(io_mem_opaque[index], physaddr);
+    } else {
 #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);
@@ -81,6 +85,7 @@ static inline DATA_TYPE glue(io_read, 
SUFFIX)(target_phys_addr_t physaddr,
     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;
 #endif
+    }
 #endif /* SHIFT > 2 */
     return res;
 }
@@ -217,6 +222,10 @@ static inline void glue(io_write, 
SUFFIX)(target_phys_addr_t physaddr,
 #if SHIFT <= 2
     io_mem_write[index][SHIFT](io_mem_opaque[index], physaddr, val);
 #else
+    if (io_mem_write[index][3]) {
+        ((CPUWriteMemoryFunc64 *)
+         io_mem_write[index][3])(io_mem_opaque[index], physaddr, val);
+    } else {
 #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);
@@ -224,6 +233,7 @@ static inline void glue(io_write, 
SUFFIX)(target_phys_addr_t physaddr,
     io_mem_write[index][2](io_mem_opaque[index], physaddr, val);
     io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val >> 32);
 #endif
+    }
 #endif /* SHIFT > 2 */
 }
 
-- 
1.7.2.5




reply via email to

[Prev in Thread] Current Thread [Next in Thread]