Introduce load/store helpers which take a MemOp argument.

Inspired-by: Paolo Bonzini <[email protected]>
Signed-off-by: Philippe Mathieu-Daudé <[email protected]>
---
 MAINTAINERS                   |  1 +
 include/qemu/ldst_unaligned.h | 25 +++++++++++++
 util/ldst.c                   | 69 +++++++++++++++++++++++++++++++++++
 util/meson.build              |  1 +
 4 files changed, 96 insertions(+)
 create mode 100644 util/ldst.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 2d8583cbb52..4eb4e34ce75 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3272,6 +3272,7 @@ F: system/physmem.c
 F: system/memory-internal.h
 F: system/ram-block-attributes.c
 F: scripts/coccinelle/memory-region-housekeeping.cocci
+F: util/ldst.c
 
 Memory devices
 M: David Hildenbrand <[email protected]>
diff --git a/include/qemu/ldst_unaligned.h b/include/qemu/ldst_unaligned.h
index 63a091ad401..2c5c6723802 100644
--- a/include/qemu/ldst_unaligned.h
+++ b/include/qemu/ldst_unaligned.h
@@ -6,6 +6,8 @@
 #ifndef QEMU_LDST_UNALIGNED_H
 #define QEMU_LDST_UNALIGNED_H
 
+#include "exec/memop.h"
+
 /*
  * Any compiler worth its salt will turn these memcpy into native unaligned
  * operations.  Thus we don't need to play games with packed attributes, or
@@ -64,4 +66,27 @@ static inline void stq_unaligned_p(void *ptr, uint64_t v)
     __builtin_memcpy(ptr, &v, sizeof(v));
 }
 
+/**
+ * ldm_p: Load value from host memory (byteswapping if necessary)
+ *
+ * @ptr: the host pointer to be accessed
+ * @mop: #MemOp mask containing access size and optional byteswapping
+ *
+ * Convert the value stored at @ptr in host memory and byteswap if necessary.
+ *
+ * Returns: the converted value.
+ */
+uint64_t ldm_p(const void *ptr, MemOp mop);
+
+/**
+ * stm_p: Store value to host memory (byteswapping if necessary)
+ *
+ * @ptr: the host pointer to be accessed
+ * @mop: #MemOp mask containing access size and optional byteswapping
+ * @val: the value to store
+ *
+ * Convert the value (byteswap if necessary) and stored at @ptr in host memory.
+ */
+void stm_p(void *ptr, MemOp mop, uint64_t val);
+
 #endif
diff --git a/util/ldst.c b/util/ldst.c
new file mode 100644
index 00000000000..fb11c073bcb
--- /dev/null
+++ b/util/ldst.c
@@ -0,0 +1,69 @@
+/*
+ * Load/Store helpers for QEMU
+ *
+ * Copyright (c) Linaro Ltd.
+ *
+ * Authors:
+ *   Philippe Mathieu-Daudé
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/ldst_unaligned.h"
+
+uint64_t ldm_p(const void *ptr, MemOp mop)
+{
+    const unsigned size = memop_size(mop);
+    uint64_t val;
+    uint8_t *pval = (uint8_t *)&val;
+
+    if (HOST_BIG_ENDIAN) {
+        pval += sizeof(val) - size;
+    }
+
+    __builtin_memcpy(pval, ptr, size);
+    if (unlikely(mop & MO_BSWAP)) {
+        switch (size) {
+        case sizeof(uint16_t):
+            val = __builtin_bswap16(val);
+            break;
+        case sizeof(uint32_t):
+            val = __builtin_bswap32(val);
+            break;
+        case sizeof(uint64_t):
+            val = __builtin_bswap64(val);
+            break;
+        default:
+            g_assert_not_reached();
+        }
+    }
+    return val;
+}
+
+void stm_p(void *ptr, MemOp mop, uint64_t val)
+{
+    const unsigned size = memop_size(mop);
+    const uint8_t *pval = (const uint8_t *)&val;
+
+    if (HOST_BIG_ENDIAN) {
+        pval += sizeof(val) - size;
+    }
+
+    if (unlikely(mop & MO_BSWAP)) {
+        switch (size) {
+        case sizeof(uint16_t):
+            val = __builtin_bswap16(val);
+            break;
+        case sizeof(uint32_t):
+            val = __builtin_bswap32(val);
+            break;
+        case sizeof(uint64_t):
+            val = __builtin_bswap64(val);
+            break;
+        default:
+            g_assert_not_reached();
+        }
+    }
+    __builtin_memcpy(ptr, pval, size);
+}
diff --git a/util/meson.build b/util/meson.build
index 35029380a37..b695b6e4728 100644
--- a/util/meson.build
+++ b/util/meson.build
@@ -38,6 +38,7 @@ util_ss.add(files('envlist.c', 'path.c', 'module.c'))
 util_ss.add(files('event.c'))
 util_ss.add(files('host-utils.c'))
 util_ss.add(files('bitmap.c', 'bitops.c'))
+util_ss.add(files('ldst.c'))
 util_ss.add(files('fifo8.c'))
 util_ss.add(files('cacheflush.c'))
 util_ss.add(files('error.c', 'error-report.c'))
-- 
2.52.0


Reply via email to