* [PATCH v2 1/2] target/s390x: Make PRNO TRNG interruptible
2026-07-14 19:17 [PATCH v2 0/2] target/s390x: Make PRNO TRNG interruptible Ilya Leoshkevich
@ 2026-07-14 19:17 ` Ilya Leoshkevich
2026-07-14 19:17 ` [PATCH v2 2/2] tests/tcg/s390x: Test PRNO TRNG interruptibility Ilya Leoshkevich
1 sibling, 0 replies; 3+ messages in thread
From: Ilya Leoshkevich @ 2026-07-14 19:17 UTC (permalink / raw)
To: Richard Henderson, Cornelia Huck, Eric Farman, Matthew Rosato
Cc: David Hildenbrand, qemu-s390x, qemu-devel, Harald Freudenberger,
Ilya Leoshkevich, Christian Borntraeger, qemu-stable
fill_buf_random() writes the entire guest-requested amount of random
bytes in one go. Since the length is a full 64-bit value, a guest can
request several gigabytes and keep the vCPU spinning inside the helper,
without a chance to react to interrupts.
Do the same thing as HELPER(mvcl): check cpu_loop_exit_requested() at the
bottom of the loop, and when a return to the main loop is pending, stop
and report partial completion with condition code 3.
Reported-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Fixes: 3dbc5fdacb5a ("target/s390x: support PRNO_TRNG instruction")
Cc: qemu-stable@nongnu.org
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
target/s390x/tcg/crypto_helper.c | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c
index 8fe0a222198..6a5dbe1cafa 100644
--- a/target/s390x/tcg/crypto_helper.c
+++ b/target/s390x/tcg/crypto_helper.c
@@ -16,6 +16,7 @@
#include "qemu/guest-random.h"
#include "s390x-internal.h"
#include "tcg_s390x.h"
+#include "exec/cpu-common.h"
#include "exec/helper-proto.h"
#include "accel/tcg/cpu-ldst-common.h"
#include "accel/tcg/cpu-mmu-index.h"
@@ -242,8 +243,8 @@ static int cpacf_sha512(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
return !len ? 0 : 3;
}
-static void fill_buf_random(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
- uint64_t *buf_reg, uint64_t *len_reg)
+static int fill_buf_random(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t *buf_reg, uint64_t *len_reg)
{
const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
uint8_t tmp[256];
@@ -265,7 +266,13 @@ static void fill_buf_random(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
--*len_reg;
}
len -= block;
+
+ if (cpu_loop_exit_requested(env_cpu(env))) {
+ break;
+ }
}
+
+ return len == 0 ? 0 : 3;
}
uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3,
@@ -278,6 +285,7 @@ uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3,
uint8_t subfunc[16] = { 0 };
uint64_t param_addr;
MemOpIdx oi;
+ int cc;
switch (type) {
case S390_FEAT_TYPE_KMAC:
@@ -308,9 +316,13 @@ uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3,
return cpacf_sha512(env, mmu_idx, ra, env->regs[1], &env->regs[r2],
&env->regs[r2 + 1], type);
case 114: /* CPACF_PRNO_TRNG */
- fill_buf_random(env, mmu_idx, ra, &env->regs[r1], &env->regs[r1 + 1]);
- fill_buf_random(env, mmu_idx, ra, &env->regs[r2], &env->regs[r2 + 1]);
- break;
+ cc = fill_buf_random(env, mmu_idx, ra,
+ &env->regs[r1], &env->regs[r1 + 1]);
+ if (cc == 0) {
+ cc = fill_buf_random(env, mmu_idx, ra,
+ &env->regs[r2], &env->regs[r2 + 1]);
+ }
+ return cc;
default:
/* we don't implement any other subfunction yet */
g_assert_not_reached();
--
2.55.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* [PATCH v2 2/2] tests/tcg/s390x: Test PRNO TRNG interruptibility
2026-07-14 19:17 [PATCH v2 0/2] target/s390x: Make PRNO TRNG interruptible Ilya Leoshkevich
2026-07-14 19:17 ` [PATCH v2 1/2] " Ilya Leoshkevich
@ 2026-07-14 19:17 ` Ilya Leoshkevich
1 sibling, 0 replies; 3+ messages in thread
From: Ilya Leoshkevich @ 2026-07-14 19:17 UTC (permalink / raw)
To: Richard Henderson, Cornelia Huck, Eric Farman, Matthew Rosato
Cc: David Hildenbrand, qemu-s390x, qemu-devel, Harald Freudenberger,
Ilya Leoshkevich
Add a small test that issues a large PRNO TRNG request while a timer is
running, and checks that the timer interrupts it several times.
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
tests/tcg/s390x/Makefile.target | 1 +
tests/tcg/s390x/prno-trng.c | 67 +++++++++++++++++++++++++++++++++
2 files changed, 68 insertions(+)
create mode 100644 tests/tcg/s390x/prno-trng.c
diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target
index 0ca030ded01..48cba4cdfa4 100644
--- a/tests/tcg/s390x/Makefile.target
+++ b/tests/tcg/s390x/Makefile.target
@@ -75,6 +75,7 @@ Z13_TESTS+=vcksm
Z13_TESTS+=vstl
Z13_TESTS+=vrep
Z13_TESTS+=precise-smc-user
+Z13_TESTS+=prno-trng
$(Z13_TESTS): CFLAGS+=-march=z13 -O2
TESTS+=$(Z13_TESTS)
diff --git a/tests/tcg/s390x/prno-trng.c b/tests/tcg/s390x/prno-trng.c
new file mode 100644
index 00000000000..43eea5db1dc
--- /dev/null
+++ b/tests/tcg/s390x/prno-trng.c
@@ -0,0 +1,67 @@
+/*
+ * Test that PERFORM RANDOM NUMBER OPERATION TRNG is interruptible.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <asm/ucontext.h>
+
+static unsigned char buf1[16 * 1024 * 1024];
+static unsigned char buf2[16 * 1024 * 1024];
+
+static volatile sig_atomic_t interrupted;
+
+static void sigprof_handler(int sig, siginfo_t *info, void *ucontext)
+{
+ struct ucontext *uc = ucontext;
+ unsigned long addr = uc->uc_mcontext.regs.psw.addr;
+
+ if (*(unsigned short *)(addr - 4) == 0xb93c) {
+ interrupted++;
+ }
+}
+
+static void prno_trng(void *b1, unsigned long l1, void *b2, unsigned long l2)
+{
+ register unsigned long r0 asm("r0") = 114; /* TRNG */
+ register unsigned long r2 asm("r2") = (unsigned long)b1;
+ register unsigned long r3 asm("r3") = l1;
+ register unsigned long r4 asm("r4") = (unsigned long)b2;
+ register unsigned long r5 asm("r5") = l2;
+
+ asm volatile("0: ppno %[r2],%[r4]\n" /* prno alias for old toolchains */
+ " jo 0b"
+ : [r2] "+r" (r2), [r3] "+r" (r3)
+ , [r4] "+r" (r4), [r5] "+r" (r5)
+ : "r" (r0)
+ : "cc", "memory");
+}
+
+int main(void)
+{
+ struct itimerval it = {
+ .it_interval = { .tv_usec = 10000 }, /* 0.01s */
+ .it_value = { .tv_usec = 10000 },
+ };
+ struct sigaction act = {
+ .sa_sigaction = sigprof_handler,
+ .sa_flags = SA_SIGINFO,
+ };
+ int err;
+
+ err = sigaction(SIGPROF, &act, NULL);
+ assert(err == 0);
+ err = setitimer(ITIMER_PROF, &it, NULL);
+ assert(err == 0);
+
+ prno_trng(buf1, sizeof(buf1), buf2, sizeof(buf2));
+ printf("interrupted %d times\n", interrupted);
+ assert(interrupted >= 3);
+
+ return EXIT_SUCCESS;
+}
--
2.55.0
^ permalink raw reply related [flat|nested] 3+ messages in thread