Commit 97fb409286 for qemu.org
commit 97fb40928644e434b525f92c83bf46661b8d84ca
Author: Harald Freudenberger <freude@linux.ibm.com>
Date: Mon Aug 24 10:31:49 2026 +0200
target/s390x: Add helper functions for copy memory to and from guest
Add some simple helper functions to copy memory from guest to a local
buffer and the other way around:
- read_guest_wrap_u8()
- write_guest_wrap_u8()
- read_guest_wrap_u32()
- write_guest_wrap_u32()
- read_guest_wrap_u64()
- write_guest_wrap_u64()
The reader functions read from guest memory into an array of
u8/u32/u64 with BE conversion. Similar the writer functions write an
array of u8/u32/u64 into guest memory with BE conversion.
All these functions are intended to be used for the crypto
implementations thus are located in crypto_helper.h.
Rework and simplify the sha 256 and sha 512 implementations to use
these helper functions.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Ilya Leoshkevich <iii@linux.ibm.com>
Link: https://lore.kernel.org/qemu-devel/20260824083204.40877-6-freude@linux.ibm.com
Signed-off-by: Eric Farman <farman@linux.ibm.com>
diff --git a/target/s390x/tcg/cpacf_sha256.c b/target/s390x/tcg/cpacf_sha256.c
index 30754dbdd4..67321b565c 100644
--- a/target/s390x/tcg/cpacf_sha256.c
+++ b/target/s390x/tcg/cpacf_sha256.c
@@ -19,6 +19,7 @@
#include "accel/tcg/cpu-mmu-index.h"
#include "target/s390x/tcg/cpacf-arch.h"
#include "target/s390x/tcg/cpacf.h"
+#include "target/s390x/tcg/crypto_helper.h"
static uint32_t R(uint32_t x, int c)
{
@@ -104,53 +105,13 @@ static void sha256_bda_be32(uint32_t a[8], uint32_t w[16])
sha256_bda(a, t);
}
-static void sha256_read_icv(CPUS390XState *env, const int mmu_idx,
- uint64_t addr, uint32_t a[8], uintptr_t ra)
-{
- const MemOpIdx oi = make_memop_idx(MO_BE | MO_32 | MO_UNALN, mmu_idx);
-
- for (int i = 0; i < 8; i++, addr += 4) {
- a[i] = cpu_ldl_mmu(env, wrap_address(env, addr), oi, ra);
- }
-}
-
-static void sha256_write_ocv(CPUS390XState *env, const int mmu_idx,
- uint64_t addr, uint32_t a[8], uintptr_t ra)
-{
- const MemOpIdx oi = make_memop_idx(MO_BE | MO_32 | MO_UNALN, mmu_idx);
-
- for (int i = 0; i < 8; i++, addr += 4) {
- cpu_stl_mmu(env, wrap_address(env, addr), a[i], oi, ra);
- }
-}
-
-static void sha256_read_block(CPUS390XState *env, const int mmu_idx,
- uint64_t addr, uint32_t a[16], uintptr_t ra)
-{
- const MemOpIdx oi = make_memop_idx(MO_BE | MO_32 | MO_UNALN, mmu_idx);
-
- for (int i = 0; i < 16; i++, addr += 4) {
- a[i] = cpu_ldl_mmu(env, wrap_address(env, addr), oi, ra);
- }
-}
-
-static void sha256_read_mbl_be32(CPUS390XState *env, const int mmu_idx,
- uint64_t addr, uint8_t a[8], uintptr_t ra)
-{
- const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
-
- for (int i = 0; i < 8; i++, addr += 1) {
- a[i] = cpu_ldb_mmu(env, wrap_address(env, addr), oi, ra);
- }
-}
-
int cpacf_sha256(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint64_t param_addr, uint64_t *message_reg, uint64_t *len_reg,
uint32_t type)
{
enum { MAX_BLOCKS_PER_RUN = 128 }; /* 128 * 64 = 8K */
uint64_t len = *len_reg, processed = 0;
- int i, message_reg_len = 64;
+ int message_reg_len = 64;
uint32_t a[8];
g_assert(type == S390_FEAT_TYPE_KIMD || type == S390_FEAT_TYPE_KLMD);
@@ -165,7 +126,8 @@ int cpacf_sha256(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
- sha256_read_icv(env, mmu_idx, param_addr, a, ra);
+ /* read icv (8 * u32) */
+ read_guest_wrap_u32(env, mmu_idx, ra, param_addr, a, 8);
/* Process full blocks first. */
for (; len >= 64; len -= 64, processed += 64) {
@@ -175,21 +137,18 @@ int cpacf_sha256(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
break;
}
- sha256_read_block(env, mmu_idx, *message_reg + processed, w, ra);
+ /* read sha256 block (16 * u32) */
+ read_guest_wrap_u32(env, mmu_idx, ra, *message_reg + processed, w, 16);
sha256_bda(a, w);
}
/* KLMD: Process partial/empty block last. */
if (type == S390_FEAT_TYPE_KLMD && len < 64) {
- const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
uint8_t x[64];
- /* Read the remainder of the message byte-per-byte. */
- for (i = 0; i < len; i++) {
- uint64_t addr = wrap_address(env, *message_reg + processed + i);
+ /* Read the remainder of the message. */
+ read_guest_wrap_u8(env, mmu_idx, ra, *message_reg + processed, x, len);
- x[i] = cpu_ldb_mmu(env, addr, oi, ra);
- }
/* Pad the remainder with zero and set the top bit. */
memset(x + len, 0, 64 - len);
x[len] = 0x80;
@@ -199,13 +158,13 @@ int cpacf_sha256(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
* or use an additional one.
*/
if (len < 56) {
- sha256_read_mbl_be32(env, mmu_idx, param_addr + 32, x + 56, ra);
+ read_guest_wrap_u8(env, mmu_idx, ra, param_addr + 32, x + 56, 8);
}
sha256_bda_be32(a, (uint32_t *)x);
if (len >= 56) {
memset(x, 0, 56);
- sha256_read_mbl_be32(env, mmu_idx, param_addr + 32, x + 56, ra);
+ read_guest_wrap_u8(env, mmu_idx, ra, param_addr + 32, x + 56, 8);
sha256_bda_be32(a, (uint32_t *)x);
}
@@ -220,7 +179,7 @@ int cpacf_sha256(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
* TODO: if writing fails halfway through (e.g., when crossing page
* boundaries), we're in trouble. We'd need something like access_prepare().
*/
- sha256_write_ocv(env, mmu_idx, param_addr, a, ra);
+ write_guest_wrap_u32(env, mmu_idx, ra, param_addr, a, 8);
*message_reg = deposit64(*message_reg, 0, message_reg_len,
*message_reg + processed);
*len_reg -= processed;
diff --git a/target/s390x/tcg/cpacf_sha512.c b/target/s390x/tcg/cpacf_sha512.c
index 2a1ff38c58..edd8dae78f 100644
--- a/target/s390x/tcg/cpacf_sha512.c
+++ b/target/s390x/tcg/cpacf_sha512.c
@@ -18,6 +18,7 @@
#include "accel/tcg/cpu-mmu-index.h"
#include "target/s390x/tcg/cpacf-arch.h"
#include "target/s390x/tcg/cpacf.h"
+#include "target/s390x/tcg/crypto_helper.h"
static uint64_t R(uint64_t x, int c)
{
@@ -119,53 +120,13 @@ static void sha512_bda_be64(uint64_t a[8], uint64_t w[16])
sha512_bda(a, t);
}
-static void sha512_read_icv(CPUS390XState *env, const int mmu_idx,
- uint64_t addr, uint64_t a[8], uintptr_t ra)
-{
- const MemOpIdx oi = make_memop_idx(MO_BE | MO_64 | MO_UNALN, mmu_idx);
-
- for (int i = 0; i < 8; i++, addr += 8) {
- a[i] = cpu_ldq_mmu(env, wrap_address(env, addr), oi, ra);
- }
-}
-
-static void sha512_write_ocv(CPUS390XState *env, const int mmu_idx,
- uint64_t addr, uint64_t a[8], uintptr_t ra)
-{
- const MemOpIdx oi = make_memop_idx(MO_BE | MO_64 | MO_UNALN, mmu_idx);
-
- for (int i = 0; i < 8; i++, addr += 8) {
- cpu_stq_mmu(env, wrap_address(env, addr), a[i], oi, ra);
- }
-}
-
-static void sha512_read_block(CPUS390XState *env, const int mmu_idx,
- uint64_t addr, uint64_t a[16], uintptr_t ra)
-{
- const MemOpIdx oi = make_memop_idx(MO_BE | MO_64 | MO_UNALN, mmu_idx);
-
- for (int i = 0; i < 16; i++, addr += 8) {
- a[i] = cpu_ldq_mmu(env, wrap_address(env, addr), oi, ra);
- }
-}
-
-static void sha512_read_mbl_be64(CPUS390XState *env, const int mmu_idx,
- uint64_t addr, uint8_t a[16], uintptr_t ra)
-{
- const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
-
- for (int i = 0; i < 16; i++, addr += 1) {
- a[i] = cpu_ldb_mmu(env, wrap_address(env, addr), oi, ra);
- }
-}
-
int cpacf_sha512(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint64_t param_addr, uint64_t *message_reg, uint64_t *len_reg,
uint32_t type)
{
enum { MAX_BLOCKS_PER_RUN = 64 }; /* Arbitrary: keep interactivity. */
uint64_t len = *len_reg, a[8], processed = 0;
- int i, message_reg_len = 64;
+ int message_reg_len = 64;
g_assert(type == S390_FEAT_TYPE_KIMD || type == S390_FEAT_TYPE_KLMD);
@@ -179,7 +140,8 @@ int cpacf_sha512(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
- sha512_read_icv(env, mmu_idx, param_addr, a, ra);
+ /* read icv (8 * u64) */
+ read_guest_wrap_u64(env, mmu_idx, ra, param_addr, a, 8);
/* Process full blocks first. */
for (; len >= 128; len -= 128, processed += 128) {
@@ -189,21 +151,18 @@ int cpacf_sha512(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
break;
}
- sha512_read_block(env, mmu_idx, *message_reg + processed, w, ra);
+ /* read sha512 block (16 * u64) */
+ read_guest_wrap_u64(env, mmu_idx, ra, *message_reg + processed, w, 16);
sha512_bda(a, w);
}
/* KLMD: Process partial/empty block last. */
if (type == S390_FEAT_TYPE_KLMD && len < 128) {
- const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
uint8_t x[128];
- /* Read the remainder of the message byte-per-byte. */
- for (i = 0; i < len; i++) {
- uint64_t addr = wrap_address(env, *message_reg + processed + i);
+ /* Read the remainder of the message. */
+ read_guest_wrap_u8(env, mmu_idx, ra, *message_reg + processed, x, len);
- x[i] = cpu_ldb_mmu(env, addr, oi, ra);
- }
/* Pad the remainder with zero and set the top bit. */
memset(x + len, 0, 128 - len);
x[len] = 128;
@@ -213,13 +172,13 @@ int cpacf_sha512(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
* or use an additional one.
*/
if (len < 112) {
- sha512_read_mbl_be64(env, mmu_idx, param_addr + 64, x + 112, ra);
+ read_guest_wrap_u8(env, mmu_idx, ra, param_addr + 64, x + 112, 16);
}
sha512_bda_be64(a, (uint64_t *)x);
if (len >= 112) {
memset(x, 0, 112);
- sha512_read_mbl_be64(env, mmu_idx, param_addr + 64, x + 112, ra);
+ read_guest_wrap_u8(env, mmu_idx, ra, param_addr + 64, x + 112, 16);
sha512_bda_be64(a, (uint64_t *)x);
}
@@ -234,7 +193,7 @@ int cpacf_sha512(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
* TODO: if writing fails halfway through (e.g., when crossing page
* boundaries), we're in trouble. We'd need something like access_prepare().
*/
- sha512_write_ocv(env, mmu_idx, param_addr, a, ra);
+ write_guest_wrap_u64(env, mmu_idx, ra, param_addr, a, 8);
*message_reg = deposit64(*message_reg, 0, message_reg_len,
*message_reg + processed);
*len_reg -= processed;
diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c
index 4d1b9a54f2..27decdda63 100644
--- a/target/s390x/tcg/crypto_helper.c
+++ b/target/s390x/tcg/crypto_helper.c
@@ -22,6 +22,7 @@
#include "accel/tcg/cpu-mmu-index.h"
#include "target/s390x/tcg/cpacf-arch.h"
#include "target/s390x/tcg/cpacf.h"
+#include "target/s390x/tcg/crypto_helper.h"
static int fill_buf_random(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint64_t *buf_reg, uint64_t *len_reg)
diff --git a/target/s390x/tcg/crypto_helper.h b/target/s390x/tcg/crypto_helper.h
new file mode 100644
index 0000000000..2364e46029
--- /dev/null
+++ b/target/s390x/tcg/crypto_helper.h
@@ -0,0 +1,100 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Crypto helper functions
+ */
+
+#ifndef TARGET_S390_CRYPTO_HELPER_H
+#define TARGET_S390_CRYPTO_HELPER_H
+
+/*
+ * helper function to read len * u8 from guest to local buffer
+ */
+static inline void read_guest_wrap_u8(CPUS390XState *env, const int mmu_idx,
+ const uintptr_t ra, uint64_t guest_addr,
+ uint8_t *dest, size_t len)
+{
+ const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
+
+ for (size_t i = 0; i < len; i++, guest_addr++) {
+ uint64_t waddr = wrap_address(env, guest_addr);
+ dest[i] = cpu_ldb_mmu(env, waddr, oi, ra);
+ }
+}
+
+/*
+ * helper function to write len * u8 from local buffer to guest
+ */
+static inline void write_guest_wrap_u8(CPUS390XState *env, const int mmu_idx,
+ const uintptr_t ra, uint64_t guest_addr,
+ const uint8_t *src, size_t len)
+{
+ const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
+
+ for (size_t i = 0; i < len; i++, guest_addr++) {
+ uint64_t waddr = wrap_address(env, guest_addr);
+ cpu_stb_mmu(env, waddr, src[i], oi, ra);
+ }
+}
+
+/*
+ * helper function to read len * u32 from guest to local buffer
+ */
+static inline void read_guest_wrap_u32(CPUS390XState *env, const int mmu_idx,
+ const uintptr_t ra, uint64_t guest_addr,
+ uint32_t *dest, size_t len)
+{
+ const MemOpIdx oi = make_memop_idx(MO_BE | MO_32 | MO_UNALN, mmu_idx);
+
+ for (size_t i = 0; i < len; i++, guest_addr += 4) {
+ uint64_t waddr = wrap_address(env, guest_addr);
+ dest[i] = cpu_ldl_mmu(env, waddr, oi, ra);
+ }
+}
+
+/*
+ * helper function to write len * u32 from local buffer to guest
+ */
+static inline void write_guest_wrap_u32(CPUS390XState *env, const int mmu_idx,
+ const uintptr_t ra, uint64_t guest_addr,
+ const uint32_t *src, size_t len)
+{
+ const MemOpIdx oi = make_memop_idx(MO_BE | MO_32 | MO_UNALN, mmu_idx);
+
+ for (size_t i = 0; i < len; i++, guest_addr += 4) {
+ uint64_t waddr = wrap_address(env, guest_addr);
+ cpu_stl_mmu(env, waddr, src[i], oi, ra);
+ }
+}
+
+/*
+ * helper function to read len * u64 from guest to local buffer
+ */
+static inline void read_guest_wrap_u64(CPUS390XState *env, const int mmu_idx,
+ const uintptr_t ra, uint64_t guest_addr,
+ uint64_t *dest, size_t len)
+{
+ const MemOpIdx oi = make_memop_idx(MO_BE | MO_64 | MO_UNALN, mmu_idx);
+
+ for (size_t i = 0; i < len; i++, guest_addr += 8) {
+ uint64_t waddr = wrap_address(env, guest_addr);
+ dest[i] = cpu_ldq_mmu(env, waddr, oi, ra);
+ }
+}
+
+/*
+ * helper function to write len * u64 from local buffer to guest
+ */
+static inline void write_guest_wrap_u64(CPUS390XState *env, const int mmu_idx,
+ const uintptr_t ra, uint64_t guest_addr,
+ const uint64_t *src, size_t len)
+{
+ const MemOpIdx oi = make_memop_idx(MO_BE | MO_64 | MO_UNALN, mmu_idx);
+
+ for (size_t i = 0; i < len; i++, guest_addr += 8) {
+ uint64_t waddr = wrap_address(env, guest_addr);
+ cpu_stq_mmu(env, waddr, src[i], oi, ra);
+ }
+}
+
+#endif /* TARGET_S390_CRYPTO_HELPER_H */