diff mbox

[RFC,v1,01/22] exec: add guest RAM read/write ops

Message ID 147377801488.11859.14843791313774162965.stgit@brijesh-build-machine (mailing list archive)
State New, archived
Headers show

Commit Message

Brijesh Singh Sept. 13, 2016, 2:46 p.m. UTC
In current implementation, read and write of the guest RAM is
performed using using memcpy(). This patch adds support to register
a callback which can override the memcpy() with something else.

This feature will be used in Secure Encrypted Virtualization (SEV)
guests in which read and write of guest memory should be performed
using the SEV commands.

a typical usage:

mem_read(uint8_t *dst, uint8_t *src, uint32_t len, MemTxAttrs *attrs);
mem_write(uint8_t *dst, uint8_t *src, uint32_t len, MemTxAttrs *attrs);

MemoryRegionRAMReadWriteOps ops;
ops.read = mem_read;
ops.write = mem_write;

memory_region_init_ram(mem, NULL, "memory", size, NULL);
memory_region_set_ram_ops(mem, ops);

Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 exec.c                |  304 +++++++++++++++++++++++++++++++++++++++----------
 include/exec/memory.h |   25 ++++
 2 files changed, 266 insertions(+), 63 deletions(-)
diff mbox

Patch

diff --git a/exec.c b/exec.c
index 8ffde75..d0f45b4 100644
--- a/exec.c
+++ b/exec.c
@@ -2563,6 +2563,11 @@  static MemTxResult address_space_write_continue(AddressSpace *as, hwaddr addr,
             /* RAM case */
             ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
             memcpy(ptr, buf, l);
+            if (mr->ram_ops) {
+                mr->ram_ops->write(ptr, buf, l, attrs);
+            } else {
+                memcpy(ptr, buf, l);
+            }
             invalidate_and_set_dirty(mr, addr1, l);
         }
 
@@ -2653,7 +2658,10 @@  MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr,
         } else {
             /* RAM case */
             ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
-            memcpy(buf, ptr, l);
+            if (mr->ram_ops)
+                mr->ram_ops->read(buf, ptr, l, attrs);
+            else
+                memcpy(buf, ptr, l);
         }
 
         if (release_lock) {
@@ -2719,7 +2727,8 @@  enum write_rom_type {
 };
 
 static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
-    hwaddr addr, const uint8_t *buf, int len, enum write_rom_type type)
+    hwaddr addr, const uint8_t *buf, int len, MemTxAttrs attrs,
+    enum write_rom_type type)
 {
     hwaddr l;
     uint8_t *ptr;
@@ -2739,7 +2748,11 @@  static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
             ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
             switch (type) {
             case WRITE_DATA:
-                memcpy(ptr, buf, l);
+                if (mr->ram_ops) {
+                    mr->ram_ops->write(ptr, buf, l, attrs);
+                } else {
+                    memcpy(ptr, buf, l);
+                }
                 invalidate_and_set_dirty(mr, addr1, l);
                 break;
             case FLUSH_CACHE:
@@ -2758,7 +2771,8 @@  static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
 void cpu_physical_memory_write_rom(AddressSpace *as, hwaddr addr,
                                    const uint8_t *buf, int len)
 {
-    cpu_physical_memory_write_rom_internal(as, addr, buf, len, WRITE_DATA);
+    cpu_physical_memory_write_rom_internal(as, addr, buf, len,
+            MEMTXATTRS_UNSPECIFIED, WRITE_DATA);
 }
 
 void cpu_flush_icache_range(hwaddr start, int len)
@@ -2774,7 +2788,9 @@  void cpu_flush_icache_range(hwaddr start, int len)
     }
 
     cpu_physical_memory_write_rom_internal(&address_space_memory,
-                                           start, NULL, len, FLUSH_CACHE);
+                                           start, NULL, len,
+                                           MEMTXATTRS_UNSPECIFIED,
+                                           FLUSH_CACHE);
 }
 
 typedef struct {
@@ -2998,6 +3014,47 @@  void cpu_physical_memory_unmap(void *buffer, hwaddr len,
     return address_space_unmap(&address_space_memory, buffer, len, is_write, access_len);
 }
 
+#if defined(HOST_WORDS_BIGENDIAN)
+#define be_bswap(v, size) (v)
+#define le_bswap(v, size) glue(bswap, size)(v)
+#else
+#define le_bswap(v, size) (v)
+#define be_bswap(v, size) glue(bswap, size)(v)
+#endif
+
+static inline uint64_t rw_ops_ldq_internal(MemoryRegion *mr,
+                                           const uint8_t *ptr,
+                                           MemTxResult *ret,
+                                           MemTxAttrs attrs,
+                                           enum device_endian endian)
+{
+    uint64_t val;
+    uint64_t dst;
+
+    if (mr->ram_ops->read((uint8_t *)&dst, ptr, 8, attrs)) {
+        *ret = MEMTX_ERROR;
+        return 0;
+    }
+
+    switch (endian) {
+    case DEVICE_LITTLE_ENDIAN:
+        val = le_bswap(dst, 64);
+        break;
+    case DEVICE_BIG_ENDIAN:
+        val = be_bswap(dst, 64);
+        break;
+    default:
+#if defined(TARGET_WORDS_BIGENDIAN)
+        val = be_bswap(dst, 64);
+#else
+        val = le_bswap(dst, 64);
+#endif
+        break;
+    }
+
+    return val;
+}
+
 /* warning: addr must be aligned */
 static inline uint32_t address_space_ldl_internal(AddressSpace *as, hwaddr addr,
                                                   MemTxAttrs attrs,
@@ -3031,16 +3088,20 @@  static inline uint32_t address_space_ldl_internal(AddressSpace *as, hwaddr addr,
     } else {
         /* RAM case */
         ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
-        switch (endian) {
-        case DEVICE_LITTLE_ENDIAN:
-            val = ldl_le_p(ptr);
-            break;
-        case DEVICE_BIG_ENDIAN:
-            val = ldl_be_p(ptr);
-            break;
-        default:
-            val = ldl_p(ptr);
-            break;
+        if (mr->ram_ops) {
+            val = rw_ops_ldq_internal(mr, ptr, &r, attrs, endian);
+        } else {
+            switch (endian) {
+            case DEVICE_LITTLE_ENDIAN:
+                val = ldl_le_p(ptr);
+                break;
+            case DEVICE_BIG_ENDIAN:
+                val = ldl_be_p(ptr);
+                break;
+            default:
+                val = ldl_p(ptr);
+                break;
+            }
         }
         r = MEMTX_OK;
     }
@@ -3124,16 +3185,20 @@  static inline uint64_t address_space_ldq_internal(AddressSpace *as, hwaddr addr,
     } else {
         /* RAM case */
         ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
-        switch (endian) {
-        case DEVICE_LITTLE_ENDIAN:
-            val = ldq_le_p(ptr);
-            break;
-        case DEVICE_BIG_ENDIAN:
-            val = ldq_be_p(ptr);
-            break;
-        default:
-            val = ldq_p(ptr);
-            break;
+        if (mr->ram_ops) {
+            val = rw_ops_ldq_internal(mr, ptr, &r, attrs, endian);
+        } else {
+            switch (endian) {
+            case DEVICE_LITTLE_ENDIAN:
+                val = ldq_le_p(ptr);
+                break;
+            case DEVICE_BIG_ENDIAN:
+                val = ldq_be_p(ptr);
+                break;
+            default:
+                val = ldq_p(ptr);
+                break;
+            }
         }
         r = MEMTX_OK;
     }
@@ -3202,6 +3267,39 @@  uint32_t ldub_phys(AddressSpace *as, hwaddr addr)
     return address_space_ldub(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
 }
 
+static inline uint16_t rw_ops_lduw_internal(MemoryRegion *mr,
+                                            const uint8_t *ptr,
+                                            MemTxResult *ret,
+                                            MemTxAttrs attrs,
+                                            enum device_endian endian)
+{
+    uint64_t val;
+    uint64_t dst;
+
+    if (mr->ram_ops->read((uint8_t *)&dst, ptr, 2, attrs)) {
+        *ret = MEMTX_ERROR;
+        return 0;
+    }
+
+    switch (endian) {
+    case DEVICE_LITTLE_ENDIAN:
+        val = le_bswap(dst, 16);
+        break;
+    case DEVICE_BIG_ENDIAN:
+        val = be_bswap(dst, 16);
+        break;
+    default:
+#if defined(TARGET_WORDS_BIGENDIAN)
+        val = be_bswap(dst, 16);
+#else
+        val = le_bswap(dst, 16);
+#endif
+        break;
+    }
+
+    return (uint16_t) val;
+}
+
 /* warning: addr must be aligned */
 static inline uint32_t address_space_lduw_internal(AddressSpace *as,
                                                    hwaddr addr,
@@ -3237,16 +3335,20 @@  static inline uint32_t address_space_lduw_internal(AddressSpace *as,
     } else {
         /* RAM case */
         ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
-        switch (endian) {
-        case DEVICE_LITTLE_ENDIAN:
-            val = lduw_le_p(ptr);
-            break;
-        case DEVICE_BIG_ENDIAN:
-            val = lduw_be_p(ptr);
-            break;
-        default:
-            val = lduw_p(ptr);
-            break;
+        if (mr->ram_ops) {
+            val = rw_ops_lduw_internal(mr, ptr, &r, attrs, endian);
+        } else {
+            switch (endian) {
+            case DEVICE_LITTLE_ENDIAN:
+                val = lduw_le_p(ptr);
+                break;
+            case DEVICE_BIG_ENDIAN:
+                val = lduw_be_p(ptr);
+                break;
+            default:
+                val = lduw_p(ptr);
+                break;
+            }
         }
         r = MEMTX_OK;
     }
@@ -3341,6 +3443,37 @@  void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val)
     address_space_stl_notdirty(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
 }
 
+static inline void rw_ops_stl_internal(MemoryRegion *mr, MemTxResult *r,
+                                       uint8_t *ptr, uint32_t val,
+                                       MemTxAttrs attrs,
+                                       enum device_endian endian)
+{
+    uint32_t data;
+
+    switch (endian) {
+    case DEVICE_LITTLE_ENDIAN:
+        data = le_bswap(val, 32);
+        break;
+    case DEVICE_BIG_ENDIAN:
+        data = be_bswap(val, 32);
+        break;
+    default:
+#if defined(TARGET_WORDS_BIGENDIAN)
+        data = be_bswap(val, 32);
+#else
+        data = le_bswap(val, 32);
+#endif
+        break;
+    }
+
+    if (mr->ram_ops->write(ptr, (uint8_t *)&data, 4, attrs)) {
+        *r = MEMTX_ERROR;
+        return;
+    }
+
+    *r = MEMTX_OK;
+}
+
 /* warning: addr must be aligned */
 static inline void address_space_stl_internal(AddressSpace *as,
                                               hwaddr addr, uint32_t val,
@@ -3374,19 +3507,26 @@  static inline void address_space_stl_internal(AddressSpace *as,
     } else {
         /* RAM case */
         ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
-        switch (endian) {
-        case DEVICE_LITTLE_ENDIAN:
-            stl_le_p(ptr, val);
-            break;
-        case DEVICE_BIG_ENDIAN:
-            stl_be_p(ptr, val);
-            break;
-        default:
-            stl_p(ptr, val);
-            break;
+        if (mr->ram_ops) {
+            rw_ops_stl_internal(mr, &r, ptr, val, attrs, endian);
+            if (r == MEMTX_OK) {
+                invalidate_and_set_dirty(mr, addr1, 4);
+            }
+        } else {
+            switch (endian) {
+            case DEVICE_LITTLE_ENDIAN:
+                stl_le_p(ptr, val);
+                break;
+            case DEVICE_BIG_ENDIAN:
+                stl_be_p(ptr, val);
+                break;
+            default:
+                stl_p(ptr, val);
+                break;
+            }
+            invalidate_and_set_dirty(mr, addr1, 4);
+            r = MEMTX_OK;
         }
-        invalidate_and_set_dirty(mr, addr1, 4);
-        r = MEMTX_OK;
     }
     if (result) {
         *result = r;
@@ -3451,6 +3591,37 @@  void stb_phys(AddressSpace *as, hwaddr addr, uint32_t val)
     address_space_stb(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
 }
 
+static inline void rw_ops_stw_internal(MemoryRegion *mr, MemTxResult *r,
+                                       uint8_t *ptr, uint32_t val,
+                                       MemTxAttrs attrs,
+                                       enum device_endian endian)
+{
+    uint32_t data;
+
+    switch (endian) {
+    case DEVICE_LITTLE_ENDIAN:
+        data = le_bswap(val, 16);
+        break;
+    case DEVICE_BIG_ENDIAN:
+        data = be_bswap(val, 16);
+        break;
+    default:
+#if defined(TARGET_WORDS_BIGENDIAN)
+        data = be_bswap(val, 16);
+#else
+        data = le_bswap(val, 16);
+#endif
+        break;
+    }
+
+    if (mr->ram_ops->write(ptr, (uint8_t *)&data, 2, attrs)) {
+        *r = MEMTX_ERROR;
+        return;
+    }
+
+    *r = MEMTX_OK;
+}
+
 /* warning: addr must be aligned */
 static inline void address_space_stw_internal(AddressSpace *as,
                                               hwaddr addr, uint32_t val,
@@ -3483,19 +3654,26 @@  static inline void address_space_stw_internal(AddressSpace *as,
     } else {
         /* RAM case */
         ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
-        switch (endian) {
-        case DEVICE_LITTLE_ENDIAN:
-            stw_le_p(ptr, val);
-            break;
-        case DEVICE_BIG_ENDIAN:
-            stw_be_p(ptr, val);
-            break;
-        default:
-            stw_p(ptr, val);
-            break;
+        if (mr->ram_ops) {
+            rw_ops_stw_internal(mr, &r, ptr, val, attrs, endian);
+            if (r == MEMTX_OK) {
+                invalidate_and_set_dirty(mr, addr1, 2);
+            }
+        } else {
+            switch (endian) {
+            case DEVICE_LITTLE_ENDIAN:
+                stw_le_p(ptr, val);
+                break;
+            case DEVICE_BIG_ENDIAN:
+                stw_be_p(ptr, val);
+                break;
+            default:
+                stw_p(ptr, val);
+                break;
+            }
+            invalidate_and_set_dirty(mr, addr1, 2);
+            r = MEMTX_OK;
         }
-        invalidate_and_set_dirty(mr, addr1, 2);
-        r = MEMTX_OK;
     }
     if (result) {
         *result = r;
@@ -3613,12 +3791,12 @@  int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
             l = len;
         phys_addr += (addr & ~TARGET_PAGE_MASK);
         if (is_write) {
-            cpu_physical_memory_write_rom(cpu->cpu_ases[asidx].as,
-                                          phys_addr, buf, l);
+            cpu_physical_memory_write_rom_internal(cpu->cpu_ases[asidx].as,
+                                          phys_addr, buf, l, attrs,
+                                          WRITE_DATA);
         } else {
             address_space_rw(cpu->cpu_ases[asidx].as, phys_addr,
-                             MEMTXATTRS_UNSPECIFIED,
-                             buf, l, 0);
+                             attrs, buf, l, 0);
         }
         len -= l;
         buf += l;
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 3e4d416..80af3b0 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -146,6 +146,18 @@  struct MemoryRegionOps {
     const MemoryRegionMmio old_mmio;
 };
 
+/* Memory Region RAM callback */
+typedef struct MemoryRegionRAMReadWriteOps MemoryRegionRAMReadWriteOps;
+
+struct MemoryRegionRAMReadWriteOps {
+    /* Write data into guest memory */
+    int (*write) (uint8_t *dest, const uint8_t *src,
+                  uint32_t len, MemTxAttrs attrs);
+    /* Read data from guest memory */
+    int (*read) (uint8_t *dest, const uint8_t *src,
+                 uint32_t len, MemTxAttrs attrs);
+};
+
 typedef struct MemoryRegionIOMMUOps MemoryRegionIOMMUOps;
 
 struct MemoryRegionIOMMUOps {
@@ -179,6 +191,7 @@  struct MemoryRegion {
     RAMBlock *ram_block;
     Object *owner;
     const MemoryRegionIOMMUOps *iommu_ops;
+    const MemoryRegionRAMReadWriteOps *ram_ops;
 
     const MemoryRegionOps *ops;
     void *opaque;
@@ -506,6 +519,18 @@  static inline void memory_region_init_reservation(MemoryRegion *mr,
 }
 
 /**
+ * memory_region_set_ram_ops: Set the Read/Write ops for accessing the RAM
+ *
+ * @mr: the #MemoryRegion to be initialized
+ * @ops: a function that will be used to read/write @target region
+ */
+static inline void memory_region_set_ram_ops(MemoryRegion *mr,
+                               const MemoryRegionRAMReadWriteOps *ops)
+{
+    mr->ram_ops = ops;
+}
+
+/**
  * memory_region_init_iommu: Initialize a memory region that translates
  * addresses
  *