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
