* [PATCH v7 00/17] target/s390x: Extend qemu CPACF support
@ 2026-06-17 9:48 Harald Freudenberger
2026-06-17 9:48 ` [PATCH v7 01/17] target/s390x: Rework s390 cpacf implementations Harald Freudenberger
` (17 more replies)
0 siblings, 18 replies; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-17 9:48 UTC (permalink / raw)
To: richard.henderson, iii, david, thuth, berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, fcallies, cohuck
This patch series extends the s390 qemu CPACF support to be able to
run a subset of the CPACF instruction cross platform. There have been
requests on the kernel crypto mailing list about a way to test
s390 specific crypto implementations. For example a way to test
s390 CPACF exploitation code like the s390_aes.ko kernel module.
So here now is a set of patches verified on x86 and s390 which
over (slow but working) support for a subset of the subfunctions of
some of the CPACF instructions.
Test: As this series is more or less complete, a full blown linux
can be run and the 'usual' in-kernel crpyto modules will be
automatically loaded which run a bunch of test cases. So there
is now support for these kernel modules:
* sha256_s390x (autoloaded, sha256)
* sha512_s390x (autoloaded, sha512)
* aes_s390x (autoloaded, clear key aes ecb, cbc, ctr, xts)
* pkey_pckmo (autoloaded, derive AES protected key from clear key)
* paes_s390x (not autoloaded, protected key aes ecb, cbc, ctr, xts)
All these modules run selftests if configured by the kernel (which is
enabled by default). Failures are reported via syslog. Additionally
the aes testcases from libica can be run either inside such an qemu
environment or with a static build executed with the qemu tcg
application qemu-s390x --cpu max <static-build-libica-test>.
Changelog:
v1: Initial version with
- Related code restructured
- Support KIMD SHA512 and thus SHA256
- Support KMC AES-128, AES-192 and AES-256 and thus have basic AES
support (ECB mode) enabled.
- Support PCC Compute-XTS-Parameter-AES-128 and
Compute-XTS-Parameter-AES-256 but only for block sequence number
0. This is a requirement for the next step:
- Support KM XTS-AES-128 and KM XTS-AES-256. Together with the
minimal PCC support this enables AES-XTS CPACF acceleration.
v2: - Basic PCKMO support to be able to 'derive' an AES protected key
from clear key. See header details.
- Support protected key AES-ECB.
- Support protected key AES-CBC.
- Minimal protected key AES-XTS support for CPACF PCC.
- Support protected key AES-XTS.
- Support AES-CTR.
- Support protected key AES-CTR.
v3: - Reordered patches as suggested by Finn.
- One small bug fix in CPACF_aes.c related to address translation.
v4: - Rename of the parameters based on feedback from Janosch to
make clear these are registers or ptrs to registers.
Added Tested by from Holger. Fixed typo "face" -> "fake".
v5: - Add documentation file docs/system/s390x/cpacf.rst which
describes the state of the CPACF instructions and which
functions are covered when this series is applied.
First version sent to public mailing list qemu-s390x.
v6: - Rebase/rework to build on current qemu head.
- Add docs/system/s390x/cpacf.rst to target-s390x.rst
- New file crypto/aes-helpers.c with some simple
functions to support AES modes CBC, CTR and XTS.
- Slight rewrite of the s390x CPACF implementations to
use these generic AES mode implementations.
v7: - Update on docs/system/s390x/cpacf.rst to mention
the zArchicteture Principles of Operation document
which describes all these CPAC instructions.
Harald Freudenberger (17):
target/s390x: Rework s390 cpacf implementations
target/s390x: Move cpacf sha512 code into a new file
target/s390x: Support cpacf sha256
target/s390x: Support AES ECB for cpacf km instruction
target/s390x: Support AES CBC for cpacf kmc instruction
target/s390x: Support AES CTR for cpacf kmctr instruction
target/s390x: Minimal AES XTS support for cpacf pcc instruction
target/s390x: Support AES XTS for cpacf km instruction
target/s390x: Support pckmo encrypt AES subfunctions
target/s390x: Support protected key AES ECB for cpacf km instruction
target/s390x: Support protected key AES CBC for cpacf kmc instruction
target/s390x: Support protected key AES CTR for cpacf kmctr
instruction
target/s390x: Minimal protected key AES XTS support for cpacf pcc
instruction
target/s390x: Support protected key AES XTS for cpacf km instruction
docs/s390: Document CPACF instructions support
crypto: Add aes-helpers file to support some AES modes
target/s390x: Use generic AES helper functions
crypto/aes-helpers.c | 101 ++++
crypto/meson.build | 1 +
docs/system/s390x/cpacf.rst | 116 ++++
docs/system/target-s390x.rst | 1 +
include/crypto/aes.h | 14 +
target/s390x/gen-features.c | 31 +
target/s390x/tcg/cpacf.h | 63 ++
target/s390x/tcg/cpacf_aes.c | 955 +++++++++++++++++++++++++++++++
target/s390x/tcg/cpacf_sha256.c | 232 ++++++++
target/s390x/tcg/cpacf_sha512.c | 245 ++++++++
target/s390x/tcg/crypto_helper.c | 423 +++++++-------
target/s390x/tcg/insn-data.h.inc | 1 +
target/s390x/tcg/meson.build | 3 +
target/s390x/tcg/translate.c | 2 +
14 files changed, 1972 insertions(+), 216 deletions(-)
create mode 100644 crypto/aes-helpers.c
create mode 100644 docs/system/s390x/cpacf.rst
create mode 100644 target/s390x/tcg/cpacf.h
create mode 100644 target/s390x/tcg/cpacf_aes.c
create mode 100644 target/s390x/tcg/cpacf_sha256.c
create mode 100644 target/s390x/tcg/cpacf_sha512.c
base-commit: e89049b3ba5f1f0468bc0d294173345597514a1b
--
2.43.0
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH v7 01/17] target/s390x: Rework s390 cpacf implementations
2026-06-17 9:48 [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Harald Freudenberger
@ 2026-06-17 9:48 ` Harald Freudenberger
2026-06-17 9:48 ` [PATCH v7 02/17] target/s390x: Move cpacf sha512 code into a new file Harald Freudenberger
` (16 subsequent siblings)
17 siblings, 0 replies; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-17 9:48 UTC (permalink / raw)
To: richard.henderson, iii, david, thuth, berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, fcallies, cohuck
Fix missing parts for MSA 9 kdsa and rework the cpacf
handling code so that further extensions can be made in
a clean and structured way.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Tested-by: Holger Dengler <dengler@linux.ibm.com>
---
target/s390x/tcg/crypto_helper.c | 84 +++++++++++++++++++++++++++-----
target/s390x/tcg/insn-data.h.inc | 1 +
target/s390x/tcg/translate.c | 2 +
3 files changed, 74 insertions(+), 13 deletions(-)
diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c
index ae392bce0e..35f0cc26a4 100644
--- a/target/s390x/tcg/crypto_helper.c
+++ b/target/s390x/tcg/crypto_helper.c
@@ -272,6 +272,57 @@ static void fill_buf_random(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
}
}
+static int cpacf_kimd(CPUS390XState *env, const int mmu_idx, const uintptr_t ra,
+ uint32_t r1, uint32_t r2, uint32_t r3, uint8_t fc)
+{
+ int rc = 0;
+
+ switch (fc) {
+ case 0x03: /* CPACF_KIMD_SHA_512 */
+ rc = cpacf_sha512(env, mmu_idx, ra, env->regs[1], &env->regs[r2],
+ &env->regs[r2 + 1], S390_FEAT_TYPE_KIMD);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ return rc;
+}
+
+static int cpacf_klmd(CPUS390XState *env, const int mmu_idx, const uintptr_t ra,
+ uint32_t r1, uint32_t r2, uint32_t r3, uint8_t fc)
+{
+ int rc = 0;
+
+ switch (fc) {
+ case 0x03: /* CPACF_KLMD_SHA_512 */
+ rc = cpacf_sha512(env, mmu_idx, ra, env->regs[1], &env->regs[r2],
+ &env->regs[r2 + 1], S390_FEAT_TYPE_KLMD);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ return rc;
+}
+
+static int cpacf_ppno(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint32_t r1, uint32_t r2, uint32_t r3, uint8_t fc)
+{
+ int rc = 0;
+
+ switch (fc) {
+ case 0x72: /* 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;
+ default:
+ g_assert_not_reached();
+ }
+
+ return rc;
+}
+
uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3,
uint32_t type)
{
@@ -282,13 +333,15 @@ 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 rc = 0;
switch (type) {
- case S390_FEAT_TYPE_KMAC:
+ case S390_FEAT_TYPE_KDSA:
case S390_FEAT_TYPE_KIMD:
case S390_FEAT_TYPE_KLMD:
- case S390_FEAT_TYPE_PCKMO:
+ case S390_FEAT_TYPE_KMAC:
case S390_FEAT_TYPE_PCC:
+ case S390_FEAT_TYPE_PCKMO:
if (mod) {
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
@@ -300,25 +353,30 @@ uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3,
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
- switch (fc) {
- case 0: /* query subfunction */
+ /* handle query subfunction */
+ if (fc == 0) {
oi = make_memop_idx(MO_8, mmu_idx);
- for (int i = 0; i < 16; i++) {
+ for (int i = 0; i < sizeof(subfunc); i++) {
param_addr = wrap_address(env, env->regs[1] + i);
cpu_stb_mmu(env, param_addr, subfunc[i], oi, ra);
}
+ goto out;
+ }
+
+ switch (type) {
+ case S390_FEAT_TYPE_KIMD:
+ rc = cpacf_kimd(env, mmu_idx, ra, r1, r2, r3, fc);
break;
- case 3: /* CPACF_*_SHA_512 */
- 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]);
+ case S390_FEAT_TYPE_KLMD:
+ rc = cpacf_klmd(env, mmu_idx, ra, r1, r2, r3, fc);
+ break;
+ case S390_FEAT_TYPE_PPNO:
+ rc = cpacf_ppno(env, mmu_idx, ra, r1, r2, r3, fc);
break;
default:
- /* we don't implement any other subfunction yet */
g_assert_not_reached();
}
- return 0;
+out:
+ return rc;
}
diff --git a/target/s390x/tcg/insn-data.h.inc b/target/s390x/tcg/insn-data.h.inc
index 0d5392eac5..6a0a7aacda 100644
--- a/target/s390x/tcg/insn-data.h.inc
+++ b/target/s390x/tcg/insn-data.h.inc
@@ -1015,6 +1015,7 @@
D(0xb92e, KM, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KM)
D(0xb92f, KMC, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMC)
D(0xb929, KMA, RRF_b, MSA8, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMA)
+ D(0xb93a, KDSA, RRE, MSA9, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KDSA)
E(0xb93c, PPNO, RRE, MSA5, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_PPNO, IF_IO)
D(0xb93e, KIMD, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KIMD)
D(0xb93f, KLMD, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KLMD)
diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
index 82165ac1ec..cef1b55149 100644
--- a/target/s390x/tcg/translate.c
+++ b/target/s390x/tcg/translate.c
@@ -2592,6 +2592,7 @@ static DisasJumpType op_msa(DisasContext *s, DisasOps *o)
/* FALL THROUGH */
case S390_FEAT_TYPE_PCKMO:
case S390_FEAT_TYPE_PCC:
+ case S390_FEAT_TYPE_KDSA:
break;
default:
g_assert_not_reached();
@@ -6046,6 +6047,7 @@ enum DisasInsnEnum {
#define FAC_MSA4 S390_FEAT_MSA_EXT_4 /* msa-extension-4 facility */
#define FAC_MSA5 S390_FEAT_MSA_EXT_5 /* msa-extension-5 facility */
#define FAC_MSA8 S390_FEAT_MSA_EXT_8 /* msa-extension-8 facility */
+#define FAC_MSA9 S390_FEAT_MSA_EXT_9 /* msa-extension-9 facility */
#define FAC_ECT S390_FEAT_EXTRACT_CPU_TIME
#define FAC_PCI S390_FEAT_ZPCI /* z/PCI facility */
#define FAC_AIS S390_FEAT_ADAPTER_INT_SUPPRESSION
--
2.43.0
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v7 02/17] target/s390x: Move cpacf sha512 code into a new file
2026-06-17 9:48 [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Harald Freudenberger
2026-06-17 9:48 ` [PATCH v7 01/17] target/s390x: Rework s390 cpacf implementations Harald Freudenberger
@ 2026-06-17 9:48 ` Harald Freudenberger
2026-06-18 4:54 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 03/17] target/s390x: Support cpacf sha256 Harald Freudenberger
` (15 subsequent siblings)
17 siblings, 1 reply; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-17 9:48 UTC (permalink / raw)
To: richard.henderson, iii, david, thuth, berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, fcallies, cohuck
Move the cpacf sha512 implementation into a new file
cpacf_sha512.c. Add this new file to the build and add a
new header file cpacf.h containing the prototypes for the
s390 cpacf stuff.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Tested-by: Holger Dengler <dengler@linux.ibm.com>
---
target/s390x/tcg/cpacf.h | 16 ++
target/s390x/tcg/cpacf_sha512.c | 245 +++++++++++++++++++++++++++++++
target/s390x/tcg/crypto_helper.c | 227 +---------------------------
target/s390x/tcg/meson.build | 1 +
4 files changed, 263 insertions(+), 226 deletions(-)
create mode 100644 target/s390x/tcg/cpacf.h
create mode 100644 target/s390x/tcg/cpacf_sha512.c
diff --git a/target/s390x/tcg/cpacf.h b/target/s390x/tcg/cpacf.h
new file mode 100644
index 0000000000..d27839ddd9
--- /dev/null
+++ b/target/s390x/tcg/cpacf.h
@@ -0,0 +1,16 @@
+/*
+ * s390x cpacf
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef S390X_CPACF_H
+#define S390X_CPACF_H
+
+/* from crypto_sha512.c */
+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);
+
+#endif
diff --git a/target/s390x/tcg/cpacf_sha512.c b/target/s390x/tcg/cpacf_sha512.c
new file mode 100644
index 0000000000..59b99e3a91
--- /dev/null
+++ b/target/s390x/tcg/cpacf_sha512.c
@@ -0,0 +1,245 @@
+/*
+ * s390 cpacf sha512
+ *
+ * Copyright (C) 2022 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ *
+ * Authors:
+ * Jason A. Donenfeld <Jason@zx2c4.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "s390x-internal.h"
+#include "tcg_s390x.h"
+#include "exec/helper-proto.h"
+#include "accel/tcg/cpu-ldst-common.h"
+#include "accel/tcg/cpu-mmu-index.h"
+#include "cpacf.h"
+
+static uint64_t R(uint64_t x, int c)
+{
+ return (x >> c) | (x << (64 - c));
+}
+static uint64_t Ch(uint64_t x, uint64_t y, uint64_t z)
+{
+ return (x & y) ^ (~x & z);
+}
+static uint64_t Maj(uint64_t x, uint64_t y, uint64_t z)
+{
+ return (x & y) ^ (x & z) ^ (y & z);
+}
+static uint64_t Sigma0(uint64_t x)
+{
+ return R(x, 28) ^ R(x, 34) ^ R(x, 39);
+}
+static uint64_t Sigma1(uint64_t x)
+{
+ return R(x, 14) ^ R(x, 18) ^ R(x, 41);
+}
+static uint64_t sigma0(uint64_t x)
+{
+ return R(x, 1) ^ R(x, 8) ^ (x >> 7);
+}
+static uint64_t sigma1(uint64_t x)
+{
+ return R(x, 19) ^ R(x, 61) ^ (x >> 6);
+}
+
+static const uint64_t K[80] = {
+ 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
+ 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+ 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
+ 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+ 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
+ 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+ 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
+ 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+ 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
+ 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+ 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
+ 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+ 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
+ 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+ 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
+ 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+ 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
+ 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+ 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
+ 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+ 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
+ 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+ 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
+ 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+ 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
+ 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+ 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+
+/* a is icv/ocv, w is a single message block. w will get reused internally. */
+static void sha512_bda(uint64_t a[8], uint64_t w[16])
+{
+ uint64_t t, z[8], b[8];
+ int i, j;
+
+ memcpy(z, a, sizeof(z));
+ for (i = 0; i < 80; i++) {
+ memcpy(b, a, sizeof(b));
+
+ t = a[7] + Sigma1(a[4]) + Ch(a[4], a[5], a[6]) + K[i] + w[i % 16];
+ b[7] = t + Sigma0(a[0]) + Maj(a[0], a[1], a[2]);
+ b[3] += t;
+ for (j = 0; j < 8; ++j) {
+ a[(j + 1) % 8] = b[j];
+ }
+ if (i % 16 == 15) {
+ for (j = 0; j < 16; ++j) {
+ w[j] += w[(j + 9) % 16] + sigma0(w[(j + 1) % 16]) +
+ sigma1(w[(j + 14) % 16]);
+ }
+ }
+ }
+
+ for (i = 0; i < 8; i++) {
+ a[i] += z[i];
+ }
+}
+
+/* a is icv/ocv, w is a single message block that needs be64 conversion. */
+static void sha512_bda_be64(uint64_t a[8], uint64_t w[16])
+{
+ uint64_t t[16];
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ t[i] = be64_to_cpu(w[i]);
+ }
+ 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) {
+ addr = wrap_address(env, addr);
+ a[i] = cpu_ldq_mmu(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) {
+ addr = wrap_address(env, addr);
+ cpu_stq_mmu(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) {
+ addr = wrap_address(env, addr);
+ a[i] = cpu_ldq_mmu(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) {
+ addr = wrap_address(env, addr);
+ a[i] = cpu_ldb_mmu(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;
+
+ g_assert(type == S390_FEAT_TYPE_KIMD || type == S390_FEAT_TYPE_KLMD);
+
+ if (!(env->psw.mask & PSW_MASK_64)) {
+ len = (uint32_t)len;
+ message_reg_len = (env->psw.mask & PSW_MASK_32) ? 32 : 24;
+ }
+
+ /* KIMD: length has to be properly aligned. */
+ if (type == S390_FEAT_TYPE_KIMD && !QEMU_IS_ALIGNED(len, 128)) {
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+ }
+
+ sha512_read_icv(env, mmu_idx, param_addr, a, ra);
+
+ /* Process full blocks first. */
+ for (; len >= 128; len -= 128, processed += 128) {
+ uint64_t w[16];
+
+ if (processed >= MAX_BLOCKS_PER_RUN * 128) {
+ break;
+ }
+
+ sha512_read_block(env, mmu_idx, *message_reg + processed, w, ra);
+ 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);
+
+ 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;
+
+ /*
+ * Place the MBL either into this block (if there is space left),
+ * or use an additional one.
+ */
+ if (len < 112) {
+ sha512_read_mbl_be64(env, mmu_idx, param_addr + 64, x + 112, ra);
+ }
+ 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);
+ sha512_bda_be64(a, (uint64_t *)x);
+ }
+
+ processed += len;
+ len = 0;
+ }
+
+ /*
+ * Modify memory after we read all inputs and modify registers only after
+ * writing memory succeeded.
+ *
+ * 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);
+ *message_reg = deposit64(*message_reg, 0, message_reg_len,
+ *message_reg + processed);
+ *len_reg -= processed;
+ return !len ? 0 : 3;
+}
diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c
index 35f0cc26a4..574a39258c 100644
--- a/target/s390x/tcg/crypto_helper.c
+++ b/target/s390x/tcg/crypto_helper.c
@@ -19,232 +19,7 @@
#include "exec/helper-proto.h"
#include "accel/tcg/cpu-ldst-common.h"
#include "accel/tcg/cpu-mmu-index.h"
-
-static uint64_t R(uint64_t x, int c)
-{
- return (x >> c) | (x << (64 - c));
-}
-static uint64_t Ch(uint64_t x, uint64_t y, uint64_t z)
-{
- return (x & y) ^ (~x & z);
-}
-static uint64_t Maj(uint64_t x, uint64_t y, uint64_t z)
-{
- return (x & y) ^ (x & z) ^ (y & z);
-}
-static uint64_t Sigma0(uint64_t x)
-{
- return R(x, 28) ^ R(x, 34) ^ R(x, 39);
-}
-static uint64_t Sigma1(uint64_t x)
-{
- return R(x, 14) ^ R(x, 18) ^ R(x, 41);
-}
-static uint64_t sigma0(uint64_t x)
-{
- return R(x, 1) ^ R(x, 8) ^ (x >> 7);
-}
-static uint64_t sigma1(uint64_t x)
-{
- return R(x, 19) ^ R(x, 61) ^ (x >> 6);
-}
-
-static const uint64_t K[80] = {
- 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
- 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
- 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
- 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
- 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
- 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
- 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
- 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
- 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
- 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
- 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
- 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
- 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
- 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
- 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
- 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
- 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
- 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
- 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
- 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
- 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
- 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
- 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
- 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
- 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
- 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
- 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
-};
-
-/* a is icv/ocv, w is a single message block. w will get reused internally. */
-static void sha512_bda(uint64_t a[8], uint64_t w[16])
-{
- uint64_t t, z[8], b[8];
- int i, j;
-
- memcpy(z, a, sizeof(z));
- for (i = 0; i < 80; i++) {
- memcpy(b, a, sizeof(b));
-
- t = a[7] + Sigma1(a[4]) + Ch(a[4], a[5], a[6]) + K[i] + w[i % 16];
- b[7] = t + Sigma0(a[0]) + Maj(a[0], a[1], a[2]);
- b[3] += t;
- for (j = 0; j < 8; ++j) {
- a[(j + 1) % 8] = b[j];
- }
- if (i % 16 == 15) {
- for (j = 0; j < 16; ++j) {
- w[j] += w[(j + 9) % 16] + sigma0(w[(j + 1) % 16]) +
- sigma1(w[(j + 14) % 16]);
- }
- }
- }
-
- for (i = 0; i < 8; i++) {
- a[i] += z[i];
- }
-}
-
-/* a is icv/ocv, w is a single message block that needs be64 conversion. */
-static void sha512_bda_be64(uint64_t a[8], uint64_t w[16])
-{
- uint64_t t[16];
- int i;
-
- for (i = 0; i < 16; i++) {
- t[i] = be64_to_cpu(w[i]);
- }
- 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) {
- addr = wrap_address(env, addr);
- a[i] = cpu_ldq_mmu(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) {
- addr = wrap_address(env, addr);
- cpu_stq_mmu(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) {
- addr = wrap_address(env, addr);
- a[i] = cpu_ldq_mmu(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) {
- addr = wrap_address(env, addr);
- a[i] = cpu_ldb_mmu(env, addr, oi, ra);
- }
-}
-
-static 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;
-
- g_assert(type == S390_FEAT_TYPE_KIMD || type == S390_FEAT_TYPE_KLMD);
-
- if (!(env->psw.mask & PSW_MASK_64)) {
- len = (uint32_t)len;
- message_reg_len = (env->psw.mask & PSW_MASK_32) ? 32 : 24;
- }
-
- /* KIMD: length has to be properly aligned. */
- if (type == S390_FEAT_TYPE_KIMD && !QEMU_IS_ALIGNED(len, 128)) {
- tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
- }
-
- sha512_read_icv(env, mmu_idx, param_addr, a, ra);
-
- /* Process full blocks first. */
- for (; len >= 128; len -= 128, processed += 128) {
- uint64_t w[16];
-
- if (processed >= MAX_BLOCKS_PER_RUN * 128) {
- break;
- }
-
- sha512_read_block(env, mmu_idx, *message_reg + processed, w, ra);
- 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);
-
- 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;
-
- /*
- * Place the MBL either into this block (if there is space left),
- * or use an additional one.
- */
- if (len < 112) {
- sha512_read_mbl_be64(env, mmu_idx, param_addr + 64, x + 112, ra);
- }
- 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);
- sha512_bda_be64(a, (uint64_t *)x);
- }
-
- processed += len;
- len = 0;
- }
-
- /*
- * Modify memory after we read all inputs and modify registers only after
- * writing memory succeeded.
- *
- * 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);
- *message_reg = deposit64(*message_reg, 0, message_reg_len,
- *message_reg + processed);
- *len_reg -= processed;
- return !len ? 0 : 3;
-}
+#include "cpacf.h"
static void 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/meson.build b/target/s390x/tcg/meson.build
index 36cb0e079e..54a87393a3 100644
--- a/target/s390x/tcg/meson.build
+++ b/target/s390x/tcg/meson.build
@@ -5,6 +5,7 @@ s390x_ss.add(when: 'CONFIG_TCG', if_true: files(
))
s390x_common_ss.add(when: 'CONFIG_TCG', if_true: files(
'cc_helper.c',
+ 'cpacf_sha512.c',
'crypto_helper.c',
'excp_helper.c',
'fpu_helper.c',
--
2.43.0
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v7 03/17] target/s390x: Support cpacf sha256
2026-06-17 9:48 [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Harald Freudenberger
2026-06-17 9:48 ` [PATCH v7 01/17] target/s390x: Rework s390 cpacf implementations Harald Freudenberger
2026-06-17 9:48 ` [PATCH v7 02/17] target/s390x: Move cpacf sha512 code into a new file Harald Freudenberger
@ 2026-06-17 9:48 ` Harald Freudenberger
2026-06-18 5:18 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 04/17] target/s390x: Support AES ECB for cpacf km instruction Harald Freudenberger
` (14 subsequent siblings)
17 siblings, 1 reply; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-17 9:48 UTC (permalink / raw)
To: richard.henderson, iii, david, thuth, berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, fcallies, cohuck
Add a new file cpacf_sha256.c which implements sha256.
Add support for the sha256 subfuction for CPACF kimd and klmd.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Tested-by: Holger Dengler <dengler@linux.ibm.com>
---
target/s390x/gen-features.c | 2 +
target/s390x/tcg/cpacf.h | 5 +
target/s390x/tcg/cpacf_sha256.c | 232 +++++++++++++++++++++++++++++++
target/s390x/tcg/crypto_helper.c | 8 ++
target/s390x/tcg/meson.build | 1 +
5 files changed, 248 insertions(+)
create mode 100644 target/s390x/tcg/cpacf_sha256.c
diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
index 8218e6470e..5cf5b92c37 100644
--- a/target/s390x/gen-features.c
+++ b/target/s390x/gen-features.c
@@ -916,7 +916,9 @@ static uint16_t qemu_V7_1[] = {
*/
static uint16_t qemu_MAX[] = {
S390_FEAT_MSA_EXT_5,
+ S390_FEAT_KIMD_SHA_256,
S390_FEAT_KIMD_SHA_512,
+ S390_FEAT_KLMD_SHA_256,
S390_FEAT_KLMD_SHA_512,
S390_FEAT_PRNO_TRNG,
};
diff --git a/target/s390x/tcg/cpacf.h b/target/s390x/tcg/cpacf.h
index d27839ddd9..e2c36306b2 100644
--- a/target/s390x/tcg/cpacf.h
+++ b/target/s390x/tcg/cpacf.h
@@ -8,6 +8,11 @@
#ifndef S390X_CPACF_H
#define S390X_CPACF_H
+/* from crypto_sha256.c */
+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);
+
/* from crypto_sha512.c */
int cpacf_sha512(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint64_t param_addr, uint64_t *message_reg, uint64_t *len_reg,
diff --git a/target/s390x/tcg/cpacf_sha256.c b/target/s390x/tcg/cpacf_sha256.c
new file mode 100644
index 0000000000..baffa2f44b
--- /dev/null
+++ b/target/s390x/tcg/cpacf_sha256.c
@@ -0,0 +1,232 @@
+/*
+ * s390 cpacf sha256
+ *
+ * Authors:
+ * Harald Freudenberger <freude@linux.ibm.com>
+ *
+ * The sha256 implementation here is more or less a copy-and-paste
+ * from Jason A. Donenfeld's implementation of sha 512 with adaptions
+ * for sha 256.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "s390x-internal.h"
+#include "tcg_s390x.h"
+#include "exec/helper-proto.h"
+#include "accel/tcg/cpu-ldst-common.h"
+#include "accel/tcg/cpu-mmu-index.h"
+#include "cpacf.h"
+
+static uint32_t R(uint32_t x, int c)
+{
+ return (x >> c) | (x << (32 - c));
+}
+static uint32_t Ch(uint32_t x, uint32_t y, uint32_t z)
+{
+ return (x & y) ^ (~x & z);
+}
+static uint32_t Maj(uint32_t x, uint32_t y, uint32_t z)
+{
+ return (x & y) ^ (x & z) ^ (y & z);
+}
+static uint32_t Sigma0(uint32_t x)
+{
+ return R(x, 2) ^ R(x, 13) ^ R(x, 22);
+}
+static uint32_t Sigma1(uint32_t x)
+{
+ return R(x, 6) ^ R(x, 11) ^ R(x, 25);
+}
+static uint32_t sigma0(uint32_t x)
+{
+ return R(x, 7) ^ R(x, 18) ^ (x >> 3);
+}
+static uint32_t sigma1(uint32_t x)
+{
+ return R(x, 17) ^ R(x, 19) ^ (x >> 10);
+}
+
+static const uint32_t K[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
+ 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
+ 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
+ 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
+ 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
+ 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
+};
+
+/* a is icv/ocv, w is a single message block. w will get reused internally. */
+static void sha256_bda(uint32_t a[8], uint32_t w[16])
+{
+ uint32_t t, z[8], b[8];
+ int i, j;
+
+ memcpy(z, a, sizeof(z));
+ for (i = 0; i < 64; i++) {
+ memcpy(b, a, sizeof(b));
+
+ t = a[7] + Sigma1(a[4]) + Ch(a[4], a[5], a[6]) + K[i] + w[i % 16];
+ b[7] = t + Sigma0(a[0]) + Maj(a[0], a[1], a[2]);
+ b[3] += t;
+ for (j = 0; j < 8; ++j) {
+ a[(j + 1) % 8] = b[j];
+ }
+ if (i % 16 == 15) {
+ for (j = 0; j < 16; ++j) {
+ w[j] += w[(j + 9) % 16] + sigma0(w[(j + 1) % 16]) +
+ sigma1(w[(j + 14) % 16]);
+ }
+ }
+ }
+
+ for (i = 0; i < 8; i++) {
+ a[i] += z[i];
+ }
+}
+
+/* a is icv/ocv, w is a single message block that needs be32 conversion. */
+static void sha256_bda_be32(uint32_t a[8], uint32_t w[16])
+{
+ uint32_t t[16];
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ t[i] = be32_to_cpu(w[i]);
+ }
+ 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) {
+ addr = wrap_address(env, addr);
+ a[i] = cpu_ldl_mmu(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) {
+ addr = wrap_address(env, addr);
+ cpu_stl_mmu(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) {
+ addr = wrap_address(env, addr);
+ a[i] = cpu_ldl_mmu(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) {
+ addr = wrap_address(env, addr);
+ a[i] = cpu_ldb_mmu(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;
+ uint32_t a[8];
+
+ g_assert(type == S390_FEAT_TYPE_KIMD || type == S390_FEAT_TYPE_KLMD);
+
+ if (!(env->psw.mask & PSW_MASK_64)) {
+ len = (uint32_t)len;
+ message_reg_len = (env->psw.mask & PSW_MASK_32) ? 32 : 24;
+ }
+
+ /* KIMD: length has to be properly aligned. */
+ if (type == S390_FEAT_TYPE_KIMD && !QEMU_IS_ALIGNED(len, 64)) {
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+ }
+
+ sha256_read_icv(env, mmu_idx, param_addr, a, ra);
+
+ /* Process full blocks first. */
+ for (; len >= 64; len -= 64, processed += 64) {
+ uint32_t w[16];
+
+ if (processed >= MAX_BLOCKS_PER_RUN * 64) {
+ break;
+ }
+
+ sha256_read_block(env, mmu_idx, *message_reg + processed, w, ra);
+ 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);
+
+ 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;
+
+ /*
+ * Place the MBL either into this block (if there is space left),
+ * or use an additional one.
+ */
+ if (len < 56) {
+ sha256_read_mbl_be32(env, mmu_idx, param_addr + 32, x + 56, ra);
+ }
+ 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);
+ sha256_bda_be32(a, (uint32_t *)x);
+ }
+
+ processed += len;
+ len = 0;
+ }
+
+ /*
+ * Modify memory after we read all inputs and modify registers only after
+ * writing memory succeeded.
+ *
+ * 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);
+ *message_reg = deposit64(*message_reg, 0, message_reg_len,
+ *message_reg + processed);
+ *len_reg -= processed;
+ return !len ? 0 : 3;
+}
diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c
index 574a39258c..a701dd8c6f 100644
--- a/target/s390x/tcg/crypto_helper.c
+++ b/target/s390x/tcg/crypto_helper.c
@@ -53,6 +53,10 @@ static int cpacf_kimd(CPUS390XState *env, const int mmu_idx, const uintptr_t ra,
int rc = 0;
switch (fc) {
+ case 0x02: /* CPACF_KIMD_SHA_256 */
+ rc = cpacf_sha256(env, mmu_idx, ra, env->regs[1], &env->regs[r2],
+ &env->regs[r2 + 1], S390_FEAT_TYPE_KIMD);
+ break;
case 0x03: /* CPACF_KIMD_SHA_512 */
rc = cpacf_sha512(env, mmu_idx, ra, env->regs[1], &env->regs[r2],
&env->regs[r2 + 1], S390_FEAT_TYPE_KIMD);
@@ -70,6 +74,10 @@ static int cpacf_klmd(CPUS390XState *env, const int mmu_idx, const uintptr_t ra,
int rc = 0;
switch (fc) {
+ case 0x02: /* CPACF_KLMD_SHA_256 */
+ rc = cpacf_sha256(env, mmu_idx, ra, env->regs[1], &env->regs[r2],
+ &env->regs[r2 + 1], S390_FEAT_TYPE_KLMD);
+ break;
case 0x03: /* CPACF_KLMD_SHA_512 */
rc = cpacf_sha512(env, mmu_idx, ra, env->regs[1], &env->regs[r2],
&env->regs[r2 + 1], S390_FEAT_TYPE_KLMD);
diff --git a/target/s390x/tcg/meson.build b/target/s390x/tcg/meson.build
index 54a87393a3..8ae8da9708 100644
--- a/target/s390x/tcg/meson.build
+++ b/target/s390x/tcg/meson.build
@@ -5,6 +5,7 @@ s390x_ss.add(when: 'CONFIG_TCG', if_true: files(
))
s390x_common_ss.add(when: 'CONFIG_TCG', if_true: files(
'cc_helper.c',
+ 'cpacf_sha256.c',
'cpacf_sha512.c',
'crypto_helper.c',
'excp_helper.c',
--
2.43.0
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v7 04/17] target/s390x: Support AES ECB for cpacf km instruction
2026-06-17 9:48 [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Harald Freudenberger
` (2 preceding siblings ...)
2026-06-17 9:48 ` [PATCH v7 03/17] target/s390x: Support cpacf sha256 Harald Freudenberger
@ 2026-06-17 9:48 ` Harald Freudenberger
2026-06-18 5:22 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 05/17] target/s390x: Support AES CBC for cpacf kmc instruction Harald Freudenberger
` (13 subsequent siblings)
17 siblings, 1 reply; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-17 9:48 UTC (permalink / raw)
To: richard.henderson, iii, david, thuth, berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, fcallies, cohuck
Support the subfunctions CPACF_KM_AES_128, CPACF_KM_AES_192
and CPACF_KM_AES_256 for the cpacf km instruction.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Tested-by: Holger Dengler <dengler@linux.ibm.com>
---
target/s390x/gen-features.c | 3 +
target/s390x/tcg/cpacf.h | 6 ++
target/s390x/tcg/cpacf_aes.c | 113 +++++++++++++++++++++++++++++++
target/s390x/tcg/crypto_helper.c | 24 +++++++
target/s390x/tcg/meson.build | 1 +
5 files changed, 147 insertions(+)
create mode 100644 target/s390x/tcg/cpacf_aes.c
diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
index 5cf5b92c37..a35d1fd2f9 100644
--- a/target/s390x/gen-features.c
+++ b/target/s390x/gen-features.c
@@ -921,6 +921,9 @@ static uint16_t qemu_MAX[] = {
S390_FEAT_KLMD_SHA_256,
S390_FEAT_KLMD_SHA_512,
S390_FEAT_PRNO_TRNG,
+ S390_FEAT_KM_AES_128,
+ S390_FEAT_KM_AES_192,
+ S390_FEAT_KM_AES_256,
};
/****** END FEATURE DEFS ******/
diff --git a/target/s390x/tcg/cpacf.h b/target/s390x/tcg/cpacf.h
index e2c36306b2..36d0c81893 100644
--- a/target/s390x/tcg/cpacf.h
+++ b/target/s390x/tcg/cpacf.h
@@ -18,4 +18,10 @@ 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);
+/* from crypto_aes.c */
+int cpacf_aes_ecb(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint64_t *dst_ptr_reg,
+ uint64_t *src_ptr_reg, uint64_t *src_len_reg,
+ uint32_t type, uint8_t fc, uint8_t mod);
+
#endif
diff --git a/target/s390x/tcg/cpacf_aes.c b/target/s390x/tcg/cpacf_aes.c
new file mode 100644
index 0000000000..ba836f1473
--- /dev/null
+++ b/target/s390x/tcg/cpacf_aes.c
@@ -0,0 +1,113 @@
+/*
+ * s390 cpacf aes
+ *
+ * Authors:
+ * Harald Freudenberger <freude@linux.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "s390x-internal.h"
+#include "tcg_s390x.h"
+#include "accel/tcg/cpu-ldst-common.h"
+#include "accel/tcg/cpu-mmu-index.h"
+#include "crypto/aes.h"
+#include "cpacf.h"
+
+static void aes_read_block(CPUS390XState *env, const int mmu_idx,
+ uint64_t addr, uint8_t *a, uintptr_t ra)
+{
+ const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
+ uint64_t _addr;
+
+ for (int i = 0; i < AES_BLOCK_SIZE; i++, addr += 1) {
+ _addr = wrap_address(env, addr);
+ a[i] = cpu_ldb_mmu(env, _addr, oi, ra);
+ }
+}
+
+static void aes_write_block(CPUS390XState *env, const int mmu_idx,
+ uint64_t addr, uint8_t *a, uintptr_t ra)
+{
+ const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
+ uint64_t _addr;
+
+ for (int i = 0; i < AES_BLOCK_SIZE; i++, addr += 1) {
+ _addr = wrap_address(env, addr);
+ cpu_stb_mmu(env, _addr, a[i], oi, ra);
+ }
+}
+
+int cpacf_aes_ecb(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint64_t *dst_ptr_reg,
+ uint64_t *src_ptr_reg, uint64_t *src_len_reg,
+ uint32_t type, uint8_t fc, uint8_t mod)
+{
+ enum { MAX_BLOCKS_PER_RUN = 8192 / AES_BLOCK_SIZE };
+ const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
+ uint8_t in[AES_BLOCK_SIZE], out[AES_BLOCK_SIZE];
+ uint64_t addr, len = *src_len_reg, done = 0;
+ int i, keysize, addr_reg_size = 64;
+ uint8_t key[32];
+ AES_KEY exkey;
+
+ g_assert(type == S390_FEAT_TYPE_KM);
+ switch (fc) {
+ case 0x12: /* CPACF_KM_AES_128 */
+ keysize = 16;
+ break;
+ case 0x13: /* CPACF_KM_AES_192 */
+ keysize = 24;
+ break;
+ case 0x14: /* CPACF_KM_AES_256 */
+ keysize = 32;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (!(env->psw.mask & PSW_MASK_64)) {
+ len = (uint32_t)len;
+ addr_reg_size = (env->psw.mask & PSW_MASK_32) ? 32 : 24;
+ }
+
+ /* length has to be properly aligned. */
+ if (!QEMU_IS_ALIGNED(len, AES_BLOCK_SIZE)) {
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+ }
+
+ /* fetch key from param block */
+ for (i = 0; i < keysize; i++) {
+ addr = wrap_address(env, param_addr + i);
+ key[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+
+ /* expand key */
+ if (mod) {
+ AES_set_decrypt_key(key, keysize * 8, &exkey);
+ } else {
+ AES_set_encrypt_key(key, keysize * 8, &exkey);
+ }
+
+ /* process up to MAX_BLOCKS_PER_RUN aes blocks */
+ for (i = 0; i < MAX_BLOCKS_PER_RUN && len >= AES_BLOCK_SIZE; i++) {
+ aes_read_block(env, mmu_idx, *src_ptr_reg + done, in, ra);
+ if (mod) {
+ AES_decrypt(in, out, &exkey);
+ } else {
+ AES_encrypt(in, out, &exkey);
+ }
+ aes_write_block(env, mmu_idx, *dst_ptr_reg + done, out, ra);
+ len -= AES_BLOCK_SIZE, done += AES_BLOCK_SIZE;
+ }
+
+ *src_ptr_reg = deposit64(*src_ptr_reg, 0, addr_reg_size,
+ *src_ptr_reg + done);
+ *dst_ptr_reg = deposit64(*dst_ptr_reg, 0, addr_reg_size,
+ *dst_ptr_reg + done);
+ *src_len_reg -= done;
+
+ return !len ? 0 : 3;
+}
diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c
index a701dd8c6f..6585dfd4e7 100644
--- a/target/s390x/tcg/crypto_helper.c
+++ b/target/s390x/tcg/crypto_helper.c
@@ -89,6 +89,27 @@ static int cpacf_klmd(CPUS390XState *env, const int mmu_idx, const uintptr_t ra,
return rc;
}
+static int cpacf_km(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint32_t r1, uint32_t r2, uint32_t r3,
+ uint8_t fc, uint8_t mod)
+{
+ int rc = 0;
+
+ switch (fc) {
+ case 0x12: /* CPACF_KM_AES_128 */
+ case 0x13: /* CPACF_KM_AES_192 */
+ case 0x14: /* CPACF_KM_AES_256 */
+ rc = cpacf_aes_ecb(env, mmu_idx, ra, env->regs[1],
+ &env->regs[r1], &env->regs[r2], &env->regs[r2 + 1],
+ S390_FEAT_TYPE_KM, fc, mod);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ return rc;
+}
+
static int cpacf_ppno(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint32_t r1, uint32_t r2, uint32_t r3, uint8_t fc)
{
@@ -156,6 +177,9 @@ uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3,
case S390_FEAT_TYPE_PPNO:
rc = cpacf_ppno(env, mmu_idx, ra, r1, r2, r3, fc);
break;
+ case S390_FEAT_TYPE_KM:
+ rc = cpacf_km(env, mmu_idx, ra, r1, r2, r3, fc, mod);
+ break;
default:
g_assert_not_reached();
}
diff --git a/target/s390x/tcg/meson.build b/target/s390x/tcg/meson.build
index 8ae8da9708..6f2e75764b 100644
--- a/target/s390x/tcg/meson.build
+++ b/target/s390x/tcg/meson.build
@@ -5,6 +5,7 @@ s390x_ss.add(when: 'CONFIG_TCG', if_true: files(
))
s390x_common_ss.add(when: 'CONFIG_TCG', if_true: files(
'cc_helper.c',
+ 'cpacf_aes.c',
'cpacf_sha256.c',
'cpacf_sha512.c',
'crypto_helper.c',
--
2.43.0
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v7 05/17] target/s390x: Support AES CBC for cpacf kmc instruction
2026-06-17 9:48 [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Harald Freudenberger
` (3 preceding siblings ...)
2026-06-17 9:48 ` [PATCH v7 04/17] target/s390x: Support AES ECB for cpacf km instruction Harald Freudenberger
@ 2026-06-17 9:48 ` Harald Freudenberger
2026-06-18 5:27 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 06/17] target/s390x: Support AES CTR for cpacf kmctr instruction Harald Freudenberger
` (12 subsequent siblings)
17 siblings, 1 reply; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-17 9:48 UTC (permalink / raw)
To: richard.henderson, iii, david, thuth, berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, fcallies, cohuck
Support the subfunctions CPACF_KMC_AES_128, CPACF_KMC_AES_192
and CPACF_KMC_AES_256 for the cpacf kmc instruction.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Tested-by: Holger Dengler <dengler@linux.ibm.com>
---
target/s390x/gen-features.c | 3 +
target/s390x/tcg/cpacf.h | 4 ++
target/s390x/tcg/cpacf_aes.c | 102 +++++++++++++++++++++++++++++++
target/s390x/tcg/crypto_helper.c | 24 ++++++++
4 files changed, 133 insertions(+)
diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
index a35d1fd2f9..9c0c0b229f 100644
--- a/target/s390x/gen-features.c
+++ b/target/s390x/gen-features.c
@@ -924,6 +924,9 @@ static uint16_t qemu_MAX[] = {
S390_FEAT_KM_AES_128,
S390_FEAT_KM_AES_192,
S390_FEAT_KM_AES_256,
+ S390_FEAT_KMC_AES_128,
+ S390_FEAT_KMC_AES_192,
+ S390_FEAT_KMC_AES_256,
};
/****** END FEATURE DEFS ******/
diff --git a/target/s390x/tcg/cpacf.h b/target/s390x/tcg/cpacf.h
index 36d0c81893..8b21b16147 100644
--- a/target/s390x/tcg/cpacf.h
+++ b/target/s390x/tcg/cpacf.h
@@ -23,5 +23,9 @@ int cpacf_aes_ecb(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint64_t param_addr, uint64_t *dst_ptr_reg,
uint64_t *src_ptr_reg, uint64_t *src_len_reg,
uint32_t type, uint8_t fc, uint8_t mod);
+int cpacf_aes_cbc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint64_t *dst_ptr_reg,
+ uint64_t *src_ptr_reg, uint64_t *src_len_reg,
+ uint32_t type, uint8_t fc, uint8_t mod);
#endif
diff --git a/target/s390x/tcg/cpacf_aes.c b/target/s390x/tcg/cpacf_aes.c
index ba836f1473..6412cc187d 100644
--- a/target/s390x/tcg/cpacf_aes.c
+++ b/target/s390x/tcg/cpacf_aes.c
@@ -111,3 +111,105 @@ int cpacf_aes_ecb(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
return !len ? 0 : 3;
}
+
+static void aes_xor(const uint8_t *src1, const uint8_t *src2, uint8_t *dst)
+{
+ for (int i = 0; i < AES_BLOCK_SIZE; i++) {
+ dst[i] = src1[i] ^ src2[i];
+ }
+}
+
+int cpacf_aes_cbc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint64_t *dst_ptr_reg,
+ uint64_t *src_ptr_reg, uint64_t *src_len_reg,
+ uint32_t type, uint8_t fc, uint8_t mod)
+{
+ enum { MAX_BLOCKS_PER_RUN = 8192 / AES_BLOCK_SIZE };
+ uint8_t in[AES_BLOCK_SIZE], out[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
+ const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
+ uint64_t addr, len = *src_len_reg, done = 0;
+ int i, keysize, addr_reg_size = 64;
+ uint8_t key[32], iv[AES_BLOCK_SIZE];
+ AES_KEY exkey;
+
+ g_assert(type == S390_FEAT_TYPE_KMC);
+
+ switch (fc) {
+ case 0x12: /* CPACF_KMC_AES_128 */
+ keysize = 16;
+ break;
+ case 0x13: /* CPACF_KMC_AES_192 */
+ keysize = 24;
+ break;
+ case 0x14: /* CPACF_KMC_AES_256 */
+ keysize = 32;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (!(env->psw.mask & PSW_MASK_64)) {
+ len = (uint32_t)len;
+ addr_reg_size = (env->psw.mask & PSW_MASK_32) ? 32 : 24;
+ }
+
+ /* length has to be properly aligned. */
+ if (!QEMU_IS_ALIGNED(len, AES_BLOCK_SIZE)) {
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+ }
+
+ /* fetch iv from param block */
+ for (i = 0; i < AES_BLOCK_SIZE; i++) {
+ addr = wrap_address(env, param_addr + i);
+ iv[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+
+ /* fetch key from param block */
+ for (i = 0; i < keysize; i++) {
+ addr = wrap_address(env, param_addr + AES_BLOCK_SIZE + i);
+ key[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+
+ /* expand key */
+ if (mod) {
+ AES_set_decrypt_key(key, keysize * 8, &exkey);
+ } else {
+ AES_set_encrypt_key(key, keysize * 8, &exkey);
+ }
+
+ /* process up to MAX_BLOCKS_PER_RUN aes blocks */
+ for (i = 0; i < MAX_BLOCKS_PER_RUN && len >= AES_BLOCK_SIZE; i++) {
+ aes_read_block(env, mmu_idx, *src_ptr_reg + done, in, ra);
+ if (mod) {
+ /* decrypt in => buf */
+ AES_decrypt(in, buf, &exkey);
+ /* buf xor iv => out */
+ aes_xor(buf, iv, out);
+ /* prep iv for next round */
+ memcpy(iv, in, AES_BLOCK_SIZE);
+ } else {
+ /* in xor iv => buf */
+ aes_xor(in, iv, buf);
+ /* encrypt buf => out */
+ AES_encrypt(buf, out, &exkey);
+ /* prep iv for next round */
+ memcpy(iv, out, AES_BLOCK_SIZE);
+ }
+ aes_write_block(env, mmu_idx, *dst_ptr_reg + done, out, ra);
+ len -= AES_BLOCK_SIZE, done += AES_BLOCK_SIZE;
+ }
+
+ /* update iv in param block */
+ for (i = 0; i < AES_BLOCK_SIZE; i++) {
+ addr = wrap_address(env, param_addr + i);
+ cpu_stb_mmu(env, addr, iv[i], oi, ra);
+ }
+
+ *src_ptr_reg = deposit64(*src_ptr_reg, 0, addr_reg_size,
+ *src_ptr_reg + done);
+ *dst_ptr_reg = deposit64(*dst_ptr_reg, 0, addr_reg_size,
+ *dst_ptr_reg + done);
+ *src_len_reg -= done;
+
+ return !len ? 0 : 3;
+}
diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c
index 6585dfd4e7..b6f7696809 100644
--- a/target/s390x/tcg/crypto_helper.c
+++ b/target/s390x/tcg/crypto_helper.c
@@ -110,6 +110,27 @@ static int cpacf_km(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
return rc;
}
+static int cpacf_kmc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint32_t r1, uint32_t r2, uint32_t r3,
+ uint8_t fc, uint8_t mod)
+{
+ int rc = 0;
+
+ switch (fc) {
+ case 0x12: /* CPACF_KMC_AES_128 */
+ case 0x13: /* CPACF_KMC_AES_192 */
+ case 0x14: /* CPACF_KMC_AES_256 */
+ rc = cpacf_aes_cbc(env, mmu_idx, ra, env->regs[1],
+ &env->regs[r1], &env->regs[r2], &env->regs[r2 + 1],
+ S390_FEAT_TYPE_KMC, fc, mod);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ return rc;
+}
+
static int cpacf_ppno(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint32_t r1, uint32_t r2, uint32_t r3, uint8_t fc)
{
@@ -180,6 +201,9 @@ uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3,
case S390_FEAT_TYPE_KM:
rc = cpacf_km(env, mmu_idx, ra, r1, r2, r3, fc, mod);
break;
+ case S390_FEAT_TYPE_KMC:
+ rc = cpacf_kmc(env, mmu_idx, ra, r1, r2, r3, fc, mod);
+ break;
default:
g_assert_not_reached();
}
--
2.43.0
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v7 06/17] target/s390x: Support AES CTR for cpacf kmctr instruction
2026-06-17 9:48 [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Harald Freudenberger
` (4 preceding siblings ...)
2026-06-17 9:48 ` [PATCH v7 05/17] target/s390x: Support AES CBC for cpacf kmc instruction Harald Freudenberger
@ 2026-06-17 9:48 ` Harald Freudenberger
2026-06-18 5:31 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 07/17] target/s390x: Minimal AES XTS support for cpacf pcc instruction Harald Freudenberger
` (11 subsequent siblings)
17 siblings, 1 reply; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-17 9:48 UTC (permalink / raw)
To: richard.henderson, iii, david, thuth, berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, fcallies, cohuck
Support the subfunctions CPACF_KMCTR_AES_128, CPACF_KMCTR_AES_192
and CPACF_KMCTR_AES_256 for the cpacf kmctr instruction.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
---
target/s390x/gen-features.c | 3 ++
target/s390x/tcg/cpacf.h | 5 +++
target/s390x/tcg/cpacf_aes.c | 76 ++++++++++++++++++++++++++++++++
target/s390x/tcg/crypto_helper.c | 24 ++++++++++
4 files changed, 108 insertions(+)
diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
index 9c0c0b229f..59c2a47539 100644
--- a/target/s390x/gen-features.c
+++ b/target/s390x/gen-features.c
@@ -927,6 +927,9 @@ static uint16_t qemu_MAX[] = {
S390_FEAT_KMC_AES_128,
S390_FEAT_KMC_AES_192,
S390_FEAT_KMC_AES_256,
+ S390_FEAT_KMCTR_AES_128,
+ S390_FEAT_KMCTR_AES_192,
+ S390_FEAT_KMCTR_AES_256,
};
/****** END FEATURE DEFS ******/
diff --git a/target/s390x/tcg/cpacf.h b/target/s390x/tcg/cpacf.h
index 8b21b16147..d73cb98c38 100644
--- a/target/s390x/tcg/cpacf.h
+++ b/target/s390x/tcg/cpacf.h
@@ -27,5 +27,10 @@ int cpacf_aes_cbc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint64_t param_addr, uint64_t *dst_ptr_reg,
uint64_t *src_ptr_reg, uint64_t *src_len_reg,
uint32_t type, uint8_t fc, uint8_t mod);
+int cpacf_aes_ctr(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint64_t *dst_ptr_reg,
+ uint64_t *src_ptr_reg, uint64_t *src_len_reg,
+ uint64_t *ctr_ptr_reg, uint32_t type,
+ uint8_t fc, uint8_t mod);
#endif
diff --git a/target/s390x/tcg/cpacf_aes.c b/target/s390x/tcg/cpacf_aes.c
index 6412cc187d..e200a9a87a 100644
--- a/target/s390x/tcg/cpacf_aes.c
+++ b/target/s390x/tcg/cpacf_aes.c
@@ -213,3 +213,79 @@ int cpacf_aes_cbc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
return !len ? 0 : 3;
}
+
+int cpacf_aes_ctr(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint64_t *dst_ptr_reg,
+ uint64_t *src_ptr_reg, uint64_t *src_len_reg,
+ uint64_t *ctr_ptr_reg, uint32_t type,
+ uint8_t fc, uint8_t mod)
+{
+ enum { MAX_BLOCKS_PER_RUN = 8192 / AES_BLOCK_SIZE };
+ const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
+ uint8_t ctr[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
+ uint8_t in[AES_BLOCK_SIZE], out[AES_BLOCK_SIZE];
+ uint64_t addr, len = *src_len_reg, done = 0;
+ int i, keysize, addr_reg_size = 64;
+ uint8_t key[32];
+ AES_KEY exkey;
+
+ g_assert(type == S390_FEAT_TYPE_KMCTR);
+
+ switch (fc) {
+ case 0x12: /* CPACF_KMCTR_AES_128 */
+ keysize = 16;
+ break;
+ case 0x13: /* CPACF_KMCTR_AES_192 */
+ keysize = 24;
+ break;
+ case 0x14: /* CPACF_KMCTR_AES_256 */
+ keysize = 32;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (!(env->psw.mask & PSW_MASK_64)) {
+ len = (uint32_t)len;
+ addr_reg_size = (env->psw.mask & PSW_MASK_32) ? 32 : 24;
+ }
+
+ /* length has to be properly aligned. */
+ if (!QEMU_IS_ALIGNED(len, AES_BLOCK_SIZE)) {
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+ }
+
+ /* fetch key from param block */
+ for (i = 0; i < keysize; i++) {
+ addr = wrap_address(env, param_addr + i);
+ key[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+
+ /* expand key */
+ AES_set_encrypt_key(key, keysize * 8, &exkey);
+
+ /* process up to MAX_BLOCKS_PER_RUN aes blocks */
+ for (i = 0; i < MAX_BLOCKS_PER_RUN && len >= AES_BLOCK_SIZE; i++) {
+ /* read in nonce/ctr => ctr */
+ aes_read_block(env, mmu_idx, *ctr_ptr_reg + done, ctr, ra);
+ /* encrypt ctr => buf */
+ AES_encrypt(ctr, buf, &exkey);
+ /* read in one block of input data => in */
+ aes_read_block(env, mmu_idx, *src_ptr_reg + done, in, ra);
+ /* exor input data with encrypted ctr => out */
+ aes_xor(in, buf, out);
+ /* write out the processed block */
+ aes_write_block(env, mmu_idx, *dst_ptr_reg + done, out, ra);
+ len -= AES_BLOCK_SIZE, done += AES_BLOCK_SIZE;
+ }
+
+ *src_ptr_reg = deposit64(*src_ptr_reg, 0, addr_reg_size,
+ *src_ptr_reg + done);
+ *dst_ptr_reg = deposit64(*dst_ptr_reg, 0, addr_reg_size,
+ *dst_ptr_reg + done);
+ *ctr_ptr_reg = deposit64(*ctr_ptr_reg, 0, addr_reg_size,
+ *ctr_ptr_reg + done);
+ *src_len_reg -= done;
+
+ return !len ? 0 : 3;
+}
diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c
index b6f7696809..98dfa37185 100644
--- a/target/s390x/tcg/crypto_helper.c
+++ b/target/s390x/tcg/crypto_helper.c
@@ -131,6 +131,27 @@ static int cpacf_kmc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
return rc;
}
+static int cpacf_kmctr(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint32_t r1, uint32_t r2, uint32_t r3,
+ uint8_t fc, uint8_t mod)
+{
+ int rc = 0;
+
+ switch (fc) {
+ case 0x12: /* CPACF_KMCTR_AES_128 */
+ case 0x13: /* CPACF_KMCTR_AES_192 */
+ case 0x14: /* CPACF_KMCTR_AES_256 */
+ rc = cpacf_aes_ctr(env, mmu_idx, ra, env->regs[1],
+ &env->regs[r1], &env->regs[r2], &env->regs[r2 + 1],
+ &env->regs[r3], S390_FEAT_TYPE_KMCTR, fc, mod);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ return rc;
+}
+
static int cpacf_ppno(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint32_t r1, uint32_t r2, uint32_t r3, uint8_t fc)
{
@@ -204,6 +225,9 @@ uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3,
case S390_FEAT_TYPE_KMC:
rc = cpacf_kmc(env, mmu_idx, ra, r1, r2, r3, fc, mod);
break;
+ case S390_FEAT_TYPE_KMCTR:
+ rc = cpacf_kmctr(env, mmu_idx, ra, r1, r2, r3, fc, mod);
+ break;
default:
g_assert_not_reached();
}
--
2.43.0
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v7 07/17] target/s390x: Minimal AES XTS support for cpacf pcc instruction
2026-06-17 9:48 [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Harald Freudenberger
` (5 preceding siblings ...)
2026-06-17 9:48 ` [PATCH v7 06/17] target/s390x: Support AES CTR for cpacf kmctr instruction Harald Freudenberger
@ 2026-06-17 9:48 ` Harald Freudenberger
2026-06-18 5:35 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 08/17] target/s390x: Support AES XTS for cpacf km instruction Harald Freudenberger
` (10 subsequent siblings)
17 siblings, 1 reply; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-17 9:48 UTC (permalink / raw)
To: richard.henderson, iii, david, thuth, berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, fcallies, cohuck
Support CPACF pcc subfunctions PCC-Compute-XTS-Parameter-AES-128
and PCC-Compute-XTS-Parameter-AES-128 but only for the special
case block sequential number is 0. However, this covers the s390
AES XTS implementation in the Linux kernel and Libica and thus
also Opencryptoki clear key via Libica.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Tested-by: Holger Dengler <dengler@linux.ibm.com>
---
target/s390x/gen-features.c | 2 +
target/s390x/tcg/cpacf.h | 2 +
target/s390x/tcg/cpacf_aes.c | 71 ++++++++++++++++++++++++++++++++
target/s390x/tcg/crypto_helper.c | 20 +++++++++
4 files changed, 95 insertions(+)
diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
index 59c2a47539..1b6a874b90 100644
--- a/target/s390x/gen-features.c
+++ b/target/s390x/gen-features.c
@@ -930,6 +930,8 @@ static uint16_t qemu_MAX[] = {
S390_FEAT_KMCTR_AES_128,
S390_FEAT_KMCTR_AES_192,
S390_FEAT_KMCTR_AES_256,
+ S390_FEAT_PCC_XTS_AES_128,
+ S390_FEAT_PCC_XTS_AES_256,
};
/****** END FEATURE DEFS ******/
diff --git a/target/s390x/tcg/cpacf.h b/target/s390x/tcg/cpacf.h
index d73cb98c38..381a6c3ff1 100644
--- a/target/s390x/tcg/cpacf.h
+++ b/target/s390x/tcg/cpacf.h
@@ -32,5 +32,7 @@ int cpacf_aes_ctr(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint64_t *src_ptr_reg, uint64_t *src_len_reg,
uint64_t *ctr_ptr_reg, uint32_t type,
uint8_t fc, uint8_t mod);
+int cpacf_aes_pcc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint8_t fc);
#endif
diff --git a/target/s390x/tcg/cpacf_aes.c b/target/s390x/tcg/cpacf_aes.c
index e200a9a87a..43c556f31b 100644
--- a/target/s390x/tcg/cpacf_aes.c
+++ b/target/s390x/tcg/cpacf_aes.c
@@ -16,6 +16,13 @@
#include "crypto/aes.h"
#include "cpacf.h"
+/* #define DEBUG_HELPER */
+#ifdef DEBUG_HELPER
+#define HELPER_LOG(x...) qemu_log(x)
+#else
+#define HELPER_LOG(x...)
+#endif
+
static void aes_read_block(CPUS390XState *env, const int mmu_idx,
uint64_t addr, uint8_t *a, uintptr_t ra)
{
@@ -289,3 +296,67 @@ int cpacf_aes_ctr(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
return !len ? 0 : 3;
}
+
+int cpacf_aes_pcc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint8_t fc)
+{
+ uint8_t key[32], tweak[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
+ const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
+ int keysize, i;
+ uint64_t addr;
+ AES_KEY exkey;
+
+ switch (fc) {
+ case 0x32: /* CPACF_PCC compute XTS param AES-128 */
+ keysize = 16;
+ break;
+ case 0x34: /* CPACF PCC compute XTS param AES-256 */
+ keysize = 32;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ /* fetch block sequence nr from param block into buf */
+ for (i = 0; i < AES_BLOCK_SIZE; i++) {
+ addr = wrap_address(env, param_addr + keysize + AES_BLOCK_SIZE + i);
+ buf[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+
+ /* is the block sequence nr 0 ? */
+ for (i = 0; i < AES_BLOCK_SIZE && !buf[i]; i++) {
+ ;
+ }
+ if (i < AES_BLOCK_SIZE) {
+ /* no, sorry handling of non zero block sequence is not implemented */
+ cpu_abort(env_cpu(env),
+ "PCC-compute-XTS-param with non zero block sequence is not implemented\n");
+ return 1;
+ }
+
+ /* fetch key from param block */
+ for (i = 0; i < keysize; i++) {
+ addr = wrap_address(env, param_addr + i);
+ key[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+
+ /* fetch tweak from param block into tweak */
+ for (i = 0; i < AES_BLOCK_SIZE; i++) {
+ addr = wrap_address(env, param_addr + keysize + i);
+ tweak[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+
+ /* expand key */
+ AES_set_encrypt_key(key, keysize * 8, &exkey);
+
+ /* encrypt tweak */
+ AES_encrypt(tweak, buf, &exkey);
+
+ /* store encrypted tweak into xts parameter field of the param block */
+ for (i = 0; i < AES_BLOCK_SIZE; i++) {
+ addr = wrap_address(env, param_addr + keysize + 3 * AES_BLOCK_SIZE + i);
+ cpu_stb_mmu(env, addr, buf[i], oi, ra);
+ }
+
+ return 0;
+}
diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c
index 98dfa37185..1a0a503844 100644
--- a/target/s390x/tcg/crypto_helper.c
+++ b/target/s390x/tcg/crypto_helper.c
@@ -169,6 +169,23 @@ static int cpacf_ppno(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
return rc;
}
+static int cpacf_pcc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint8_t fc)
+{
+ int rc = 0;
+
+ switch (fc) {
+ case 0x32: /* CPACF_PCC compute XTS param AES-128 */
+ case 0x34: /* CPACF PCC compute XTS param AES-256 */
+ rc = cpacf_aes_pcc(env, mmu_idx, ra, env->regs[1], fc);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ return rc;
+}
+
uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3,
uint32_t type)
{
@@ -228,6 +245,9 @@ uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3,
case S390_FEAT_TYPE_KMCTR:
rc = cpacf_kmctr(env, mmu_idx, ra, r1, r2, r3, fc, mod);
break;
+ case S390_FEAT_TYPE_PCC:
+ rc = cpacf_pcc(env, mmu_idx, ra, fc);
+ break;
default:
g_assert_not_reached();
}
--
2.43.0
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v7 08/17] target/s390x: Support AES XTS for cpacf km instruction
2026-06-17 9:48 [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Harald Freudenberger
` (6 preceding siblings ...)
2026-06-17 9:48 ` [PATCH v7 07/17] target/s390x: Minimal AES XTS support for cpacf pcc instruction Harald Freudenberger
@ 2026-06-17 9:48 ` Harald Freudenberger
2026-06-18 5:45 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 09/17] target/s390x: Support pckmo encrypt AES subfunctions Harald Freudenberger
` (9 subsequent siblings)
17 siblings, 1 reply; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-17 9:48 UTC (permalink / raw)
To: richard.henderson, iii, david, thuth, berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, fcallies, cohuck
Support the subfunctions XTS-AES-128 and XTS-AES-256
for the cpacf km instruction.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Tested-by: Holger Dengler <dengler@linux.ibm.com>
---
target/s390x/gen-features.c | 2 +
target/s390x/tcg/cpacf.h | 4 ++
target/s390x/tcg/cpacf_aes.c | 107 +++++++++++++++++++++++++++++++
target/s390x/tcg/crypto_helper.c | 6 ++
4 files changed, 119 insertions(+)
diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
index 1b6a874b90..f9b1a40c7c 100644
--- a/target/s390x/gen-features.c
+++ b/target/s390x/gen-features.c
@@ -924,6 +924,8 @@ static uint16_t qemu_MAX[] = {
S390_FEAT_KM_AES_128,
S390_FEAT_KM_AES_192,
S390_FEAT_KM_AES_256,
+ S390_FEAT_KM_XTS_AES_128,
+ S390_FEAT_KM_XTS_AES_256,
S390_FEAT_KMC_AES_128,
S390_FEAT_KMC_AES_192,
S390_FEAT_KMC_AES_256,
diff --git a/target/s390x/tcg/cpacf.h b/target/s390x/tcg/cpacf.h
index 381a6c3ff1..7e53ce2a14 100644
--- a/target/s390x/tcg/cpacf.h
+++ b/target/s390x/tcg/cpacf.h
@@ -34,5 +34,9 @@ int cpacf_aes_ctr(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint8_t fc, uint8_t mod);
int cpacf_aes_pcc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint64_t param_addr, uint8_t fc);
+int cpacf_aes_xts(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint64_t *dst_ptr_reg,
+ uint64_t *src_ptr_reg, uint64_t *src_len_reg,
+ uint32_t type, uint8_t fc, uint8_t mod);
#endif
diff --git a/target/s390x/tcg/cpacf_aes.c b/target/s390x/tcg/cpacf_aes.c
index 43c556f31b..0312436c43 100644
--- a/target/s390x/tcg/cpacf_aes.c
+++ b/target/s390x/tcg/cpacf_aes.c
@@ -360,3 +360,110 @@ int cpacf_aes_pcc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
return 0;
}
+
+static void aes_xts_prep_next_tweak(uint8_t tweak[AES_BLOCK_SIZE])
+{
+ uint8_t carry;
+ int i;
+
+ carry = tweak[AES_BLOCK_SIZE - 1] >> 7;
+
+ for (i = AES_BLOCK_SIZE - 1; i > 0; i--) {
+ tweak[i] = (uint8_t)((tweak[i] << 1) | (tweak[i - 1] >> 7));
+ }
+
+ tweak[i] = (uint8_t)(tweak[i] << 1);
+ tweak[i] ^= (uint8_t)(0x87 & (uint8_t)(-(int8_t)carry));
+}
+
+int cpacf_aes_xts(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint64_t *dst_ptr_reg,
+ uint64_t *src_ptr_reg, uint64_t *src_len_reg,
+ uint32_t type, uint8_t fc, uint8_t mod)
+{
+ enum { MAX_BLOCKS_PER_RUN = 8192 / AES_BLOCK_SIZE };
+ uint8_t buf1[AES_BLOCK_SIZE], buf2[AES_BLOCK_SIZE];
+ const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
+ uint64_t addr, len = *src_len_reg, done = 0;
+ uint8_t key[32], tweak[AES_BLOCK_SIZE];
+ int i, keysize, addr_reg_size = 64;
+ AES_KEY exkey;
+
+ g_assert(type == S390_FEAT_TYPE_KM);
+
+ switch (fc) {
+ case 0x32: /* CPACF_KM_XTS_128 */
+ keysize = 16;
+ break;
+ case 0x34: /* CPACF_KM_XTS_256 */
+ keysize = 32;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (!(env->psw.mask & PSW_MASK_64)) {
+ len = (uint32_t)len;
+ addr_reg_size = (env->psw.mask & PSW_MASK_32) ? 32 : 24;
+ }
+
+ /* length has to be properly aligned. */
+ if (!QEMU_IS_ALIGNED(len, AES_BLOCK_SIZE)) {
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+ }
+
+ /* fetch key from param block */
+ for (i = 0; i < keysize; i++) {
+ addr = wrap_address(env, param_addr + i);
+ key[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+
+ /* expand key */
+ if (mod) {
+ AES_set_decrypt_key(key, keysize * 8, &exkey);
+ } else {
+ AES_set_encrypt_key(key, keysize * 8, &exkey);
+ }
+
+ /* fetch tweak from param block */
+ for (i = 0; i < AES_BLOCK_SIZE; i++) {
+ addr = wrap_address(env, param_addr + keysize + i);
+ tweak[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+
+ /* process up to MAX_BLOCKS_PER_RUN aes blocks */
+ for (i = 0; i < MAX_BLOCKS_PER_RUN && len >= AES_BLOCK_SIZE; i++) {
+ /* fetch one AES block into buf1 */
+ aes_read_block(env, mmu_idx, *src_ptr_reg + done, buf1, ra);
+ /* buf1 xor tweak => buf2 */
+ aes_xor(buf1, tweak, buf2);
+ if (mod) {
+ /* decrypt buf2 => buf1 */
+ AES_decrypt(buf2, buf1, &exkey);
+ } else {
+ /* encrypt buf2 => buf1 */
+ AES_encrypt(buf2, buf1, &exkey);
+ }
+ /* buf1 xor tweak => buf2 */
+ aes_xor(buf1, tweak, buf2);
+ /* prep tweak for next round */
+ aes_xts_prep_next_tweak(tweak);
+ /* write out this processed block from buf2 */
+ aes_write_block(env, mmu_idx, *dst_ptr_reg + done, buf2, ra);
+ len -= AES_BLOCK_SIZE, done += AES_BLOCK_SIZE;
+ }
+
+ /* update tweak in param block */
+ for (i = 0; i < AES_BLOCK_SIZE; i++) {
+ addr = wrap_address(env, param_addr + keysize + i);
+ cpu_stb_mmu(env, addr, tweak[i], oi, ra);
+ }
+
+ *src_ptr_reg = deposit64(*src_ptr_reg, 0, addr_reg_size,
+ *src_ptr_reg + done);
+ *dst_ptr_reg = deposit64(*dst_ptr_reg, 0, addr_reg_size,
+ *dst_ptr_reg + done);
+ *src_len_reg -= done;
+
+ return !len ? 0 : 3;
+}
diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c
index 1a0a503844..19d625f37f 100644
--- a/target/s390x/tcg/crypto_helper.c
+++ b/target/s390x/tcg/crypto_helper.c
@@ -103,6 +103,12 @@ static int cpacf_km(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
&env->regs[r1], &env->regs[r2], &env->regs[r2 + 1],
S390_FEAT_TYPE_KM, fc, mod);
break;
+ case 0x32: /* CPACF_KM_XTS_128 */
+ case 0x34: /* CPACF_KM_XTS_256 */
+ rc = cpacf_aes_xts(env, mmu_idx, ra, env->regs[1],
+ &env->regs[r1], &env->regs[r2], &env->regs[r2 + 1],
+ S390_FEAT_TYPE_KM, fc, mod);
+ break;
default:
g_assert_not_reached();
}
--
2.43.0
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v7 09/17] target/s390x: Support pckmo encrypt AES subfunctions
2026-06-17 9:48 [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Harald Freudenberger
` (7 preceding siblings ...)
2026-06-17 9:48 ` [PATCH v7 08/17] target/s390x: Support AES XTS for cpacf km instruction Harald Freudenberger
@ 2026-06-17 9:48 ` Harald Freudenberger
2026-06-18 5:50 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 10/17] target/s390x: Support protected key AES ECB for cpacf km instruction Harald Freudenberger
` (8 subsequent siblings)
17 siblings, 1 reply; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-17 9:48 UTC (permalink / raw)
To: richard.henderson, iii, david, thuth, berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, fcallies, cohuck
Support the subfuctions PCKMO-Encrypt-AES-128-Key,
PCKMO-Encrypt-AES-192-Key and PCKMO-Encrypt-AES-256-Key.
These subfunctions derive a protected key from an AES clear key
by encrypting it with an internal AES wrapping key. More
details can be found in the "z/Architecture Prinziples of
Operation" document.
The qemu version provided here is only a fake indented to make
protected key available for developing and testing purpose:
* The protected key is 'derived' from the clear key by xoring
the fixed pattern 0xAAAA... onto the key value.
* The AES Wrapping Key Verification Pattern is a fixed
value of 32 bytes 0xFACEFACE...
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Tested-by: Holger Dengler <dengler@linux.ibm.com>
---
target/s390x/gen-features.c | 3 ++
target/s390x/tcg/cpacf.h | 2 +
target/s390x/tcg/cpacf_aes.c | 66 ++++++++++++++++++++++++++++++++
target/s390x/tcg/crypto_helper.c | 21 ++++++++++
4 files changed, 92 insertions(+)
diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
index f9b1a40c7c..d3e69aaca6 100644
--- a/target/s390x/gen-features.c
+++ b/target/s390x/gen-features.c
@@ -934,6 +934,9 @@ static uint16_t qemu_MAX[] = {
S390_FEAT_KMCTR_AES_256,
S390_FEAT_PCC_XTS_AES_128,
S390_FEAT_PCC_XTS_AES_256,
+ S390_FEAT_PCKMO_AES_128,
+ S390_FEAT_PCKMO_AES_192,
+ S390_FEAT_PCKMO_AES_256,
};
/****** END FEATURE DEFS ******/
diff --git a/target/s390x/tcg/cpacf.h b/target/s390x/tcg/cpacf.h
index 7e53ce2a14..5588e2bdec 100644
--- a/target/s390x/tcg/cpacf.h
+++ b/target/s390x/tcg/cpacf.h
@@ -38,5 +38,7 @@ int cpacf_aes_xts(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint64_t param_addr, uint64_t *dst_ptr_reg,
uint64_t *src_ptr_reg, uint64_t *src_len_reg,
uint32_t type, uint8_t fc, uint8_t mod);
+int cpacf_aes_pckmo(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint8_t fc);
#endif
diff --git a/target/s390x/tcg/cpacf_aes.c b/target/s390x/tcg/cpacf_aes.c
index 0312436c43..5a0a3473d5 100644
--- a/target/s390x/tcg/cpacf_aes.c
+++ b/target/s390x/tcg/cpacf_aes.c
@@ -467,3 +467,69 @@ int cpacf_aes_xts(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
return !len ? 0 : 3;
}
+
+/*
+ * Hard coded pattern xored with the AES clear key
+ * to 'produce' the protected key.
+ */
+static const uint8_t protkey_xor_pattern[32] = {
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA };
+
+/*
+ * Hard coded wkvp ("Wrapping Key Verification Pattern")
+ */
+static const uint8_t protkey_wkvp[32] = {
+ 0x0F, 0x0A, 0x0C, 0x0E, 0x0F, 0x0A, 0x0C, 0x0E,
+ 0x0F, 0x0A, 0x0C, 0x0E, 0x0F, 0x0A, 0x0C, 0x0E,
+ 0x0F, 0x0A, 0x0C, 0x0E, 0x0F, 0x0A, 0x0C, 0x0E,
+ 0x0F, 0x0A, 0x0C, 0x0E, 0x0F, 0x0A, 0x0C, 0x0E };
+
+int cpacf_aes_pckmo(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint8_t fc)
+{
+ const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
+ uint8_t key[32];
+ int keysize, i;
+ uint64_t addr;
+
+ switch (fc) {
+ case 0x12: /* CPACF_PCKMO_ENC_AES_128_KEY */
+ keysize = 16;
+ break;
+ case 0x13: /* CPACF_PCKMO_ENC_AES_192_KEY */
+ keysize = 24;
+ break;
+ case 0x14: /* CPACF_PCKMO_ENC_AES_256_KEY */
+ keysize = 32;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ /* fetch key from param block */
+ for (i = 0; i < keysize; i++) {
+ addr = wrap_address(env, param_addr + i);
+ key[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+
+ /* 'derive' the protected key */
+ for (i = 0; i < keysize; i++) {
+ key[i] ^= protkey_xor_pattern[i];
+ }
+
+ /* store the protected key into param block */
+ for (i = 0; i < keysize; i++) {
+ addr = wrap_address(env, param_addr + i);
+ cpu_stb_mmu(env, addr, key[i], oi, ra);
+ }
+ /* followed by the fake wkvp */
+ for (i = 0; i < sizeof(protkey_wkvp); i++) {
+ addr = wrap_address(env, param_addr + keysize + i);
+ cpu_stb_mmu(env, addr, protkey_wkvp[i], oi, ra);
+ }
+
+ return 0;
+}
diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c
index 19d625f37f..e1952ae4bc 100644
--- a/target/s390x/tcg/crypto_helper.c
+++ b/target/s390x/tcg/crypto_helper.c
@@ -192,6 +192,24 @@ static int cpacf_pcc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
return rc;
}
+static int cpacf_pckmo(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint8_t fc)
+{
+ int rc = 0;
+
+ switch (fc) {
+ case 0x12: /* CPACF_PCKMO_ENC_AES_128_KEY */
+ case 0x13: /* CPACF_PCKMO_ENC_AES_192_KEY */
+ case 0x14: /* CPACF_PCKMO_ENC_AES_256_KEY */
+ rc = cpacf_aes_pckmo(env, mmu_idx, ra, env->regs[1], fc);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ return rc;
+}
+
uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3,
uint32_t type)
{
@@ -254,6 +272,9 @@ uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3,
case S390_FEAT_TYPE_PCC:
rc = cpacf_pcc(env, mmu_idx, ra, fc);
break;
+ case S390_FEAT_TYPE_PCKMO:
+ rc = cpacf_pckmo(env, mmu_idx, ra, fc);
+ break;
default:
g_assert_not_reached();
}
--
2.43.0
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v7 10/17] target/s390x: Support protected key AES ECB for cpacf km instruction
2026-06-17 9:48 [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Harald Freudenberger
` (8 preceding siblings ...)
2026-06-17 9:48 ` [PATCH v7 09/17] target/s390x: Support pckmo encrypt AES subfunctions Harald Freudenberger
@ 2026-06-17 9:48 ` Harald Freudenberger
2026-06-18 5:57 ` Finn Callies
2026-06-18 6:05 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 11/17] target/s390x: Support protected key AES CBC for cpacf kmc instruction Harald Freudenberger
` (7 subsequent siblings)
17 siblings, 2 replies; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-17 9:48 UTC (permalink / raw)
To: richard.henderson, iii, david, thuth, berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, fcallies, cohuck
Support the subfunctions CPACF_KM_PAES_128, CPACF_KM_PAES_192
and CPACF_KM_PAES_256 for the cpacf km instruction.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Tested-by: Holger Dengler <dengler@linux.ibm.com>
---
target/s390x/gen-features.c | 3 ++
target/s390x/tcg/cpacf.h | 4 ++
target/s390x/tcg/cpacf_aes.c | 87 ++++++++++++++++++++++++++++++++
target/s390x/tcg/crypto_helper.c | 7 +++
4 files changed, 101 insertions(+)
diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
index d3e69aaca6..71e0e41d6e 100644
--- a/target/s390x/gen-features.c
+++ b/target/s390x/gen-features.c
@@ -924,6 +924,9 @@ static uint16_t qemu_MAX[] = {
S390_FEAT_KM_AES_128,
S390_FEAT_KM_AES_192,
S390_FEAT_KM_AES_256,
+ S390_FEAT_KM_EAES_128,
+ S390_FEAT_KM_EAES_192,
+ S390_FEAT_KM_EAES_256,
S390_FEAT_KM_XTS_AES_128,
S390_FEAT_KM_XTS_AES_256,
S390_FEAT_KMC_AES_128,
diff --git a/target/s390x/tcg/cpacf.h b/target/s390x/tcg/cpacf.h
index 5588e2bdec..7cf739e7a4 100644
--- a/target/s390x/tcg/cpacf.h
+++ b/target/s390x/tcg/cpacf.h
@@ -40,5 +40,9 @@ int cpacf_aes_xts(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint32_t type, uint8_t fc, uint8_t mod);
int cpacf_aes_pckmo(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint64_t param_addr, uint8_t fc);
+int cpacf_paes_ecb(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint64_t *dst_ptr_reg,
+ uint64_t *src_ptr_reg, uint64_t *src_len_reg,
+ uint32_t type, uint8_t fc, uint8_t mod);
#endif
diff --git a/target/s390x/tcg/cpacf_aes.c b/target/s390x/tcg/cpacf_aes.c
index 5a0a3473d5..bcfcf3b660 100644
--- a/target/s390x/tcg/cpacf_aes.c
+++ b/target/s390x/tcg/cpacf_aes.c
@@ -533,3 +533,90 @@ int cpacf_aes_pckmo(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
return 0;
}
+
+int cpacf_paes_ecb(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint64_t *dst_ptr_reg,
+ uint64_t *src_ptr_reg, uint64_t *src_len_reg,
+ uint32_t type, uint8_t fc, uint8_t mod)
+{
+ enum { MAX_BLOCKS_PER_RUN = 8192 / AES_BLOCK_SIZE };
+ const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
+ uint8_t in[AES_BLOCK_SIZE], out[AES_BLOCK_SIZE];
+ uint64_t addr, len = *src_len_reg, done = 0;
+ int i, keysize, addr_reg_size = 64;
+ uint8_t key[32], wkvp[32];
+ AES_KEY exkey;
+
+ g_assert(type == S390_FEAT_TYPE_KM);
+
+ switch (fc) {
+ case 0x1a: /* CPACF_KM_PAES_128 */
+ keysize = 16;
+ break;
+ case 0x1b: /* CPACF_KM_PAES_192 */
+ keysize = 24;
+ break;
+ case 0x1c: /* CPACF_KM_PAES_256 */
+ keysize = 32;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (!(env->psw.mask & PSW_MASK_64)) {
+ len = (uint32_t)len;
+ addr_reg_size = (env->psw.mask & PSW_MASK_32) ? 32 : 24;
+ }
+
+ /* length has to be properly aligned. */
+ if (!QEMU_IS_ALIGNED(len, AES_BLOCK_SIZE)) {
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+ }
+
+ /* fetch and check wkvp from param block */
+ for (i = 0; i < sizeof(wkvp); i++) {
+ addr = wrap_address(env, param_addr + keysize + i);
+ wkvp[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+ if (memcmp(wkvp, protkey_wkvp, sizeof(wkvp))) {
+ /* wkvp mismatch -> return with cc 1 */
+ return 1;
+ }
+
+ /* fetch protected key from param block */
+ for (i = 0; i < keysize; i++) {
+ addr = wrap_address(env, param_addr + i);
+ key[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+ /* 'decrypt' the protected key */
+ for (i = 0; i < keysize; i++) {
+ key[i] ^= protkey_xor_pattern[i];
+ }
+
+ /* expand key */
+ if (mod) {
+ AES_set_decrypt_key(key, keysize * 8, &exkey);
+ } else {
+ AES_set_encrypt_key(key, keysize * 8, &exkey);
+ }
+
+ /* process up to MAX_BLOCKS_PER_RUN aes blocks */
+ for (i = 0; i < MAX_BLOCKS_PER_RUN && len >= AES_BLOCK_SIZE; i++) {
+ aes_read_block(env, mmu_idx, *src_ptr_reg + done, in, ra);
+ if (mod) {
+ AES_decrypt(in, out, &exkey);
+ } else {
+ AES_encrypt(in, out, &exkey);
+ }
+ aes_write_block(env, mmu_idx, *dst_ptr_reg + done, out, ra);
+ len -= AES_BLOCK_SIZE, done += AES_BLOCK_SIZE;
+ }
+
+ *src_ptr_reg = deposit64(*src_ptr_reg, 0, addr_reg_size,
+ *src_ptr_reg + done);
+ *dst_ptr_reg = deposit64(*dst_ptr_reg, 0, addr_reg_size,
+ *dst_ptr_reg + done);
+ *src_len_reg -= done;
+
+ return !len ? 0 : 3;
+}
diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c
index e1952ae4bc..988226338d 100644
--- a/target/s390x/tcg/crypto_helper.c
+++ b/target/s390x/tcg/crypto_helper.c
@@ -103,6 +103,13 @@ static int cpacf_km(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
&env->regs[r1], &env->regs[r2], &env->regs[r2 + 1],
S390_FEAT_TYPE_KM, fc, mod);
break;
+ case 0x1a: /* CPACF_KM_PAES_128 */
+ case 0x1b: /* CPACF_KM_PAES_192 */
+ case 0x1c: /* CPACF_KM_PAES_256 */
+ rc = cpacf_paes_ecb(env, mmu_idx, ra, env->regs[1],
+ &env->regs[r1], &env->regs[r2], &env->regs[r2 + 1],
+ S390_FEAT_TYPE_KM, fc, mod);
+ break;
case 0x32: /* CPACF_KM_XTS_128 */
case 0x34: /* CPACF_KM_XTS_256 */
rc = cpacf_aes_xts(env, mmu_idx, ra, env->regs[1],
--
2.43.0
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v7 11/17] target/s390x: Support protected key AES CBC for cpacf kmc instruction
2026-06-17 9:48 [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Harald Freudenberger
` (9 preceding siblings ...)
2026-06-17 9:48 ` [PATCH v7 10/17] target/s390x: Support protected key AES ECB for cpacf km instruction Harald Freudenberger
@ 2026-06-17 9:48 ` Harald Freudenberger
2026-06-18 6:08 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 12/17] target/s390x: Support protected key AES CTR for cpacf kmctr instruction Harald Freudenberger
` (6 subsequent siblings)
17 siblings, 1 reply; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-17 9:48 UTC (permalink / raw)
To: richard.henderson, iii, david, thuth, berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, fcallies, cohuck
Support the subfunctions CPACF_KMC_PAES_128, CPACF_KMC_PAES_192
and CPACF_KMC_PAES_256 for the cpacf kmc instruction.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Tested-by: Holger Dengler <dengler@linux.ibm.com>
---
target/s390x/gen-features.c | 3 +
target/s390x/tcg/cpacf.h | 4 ++
target/s390x/tcg/cpacf_aes.c | 109 +++++++++++++++++++++++++++++++
target/s390x/tcg/crypto_helper.c | 7 ++
4 files changed, 123 insertions(+)
diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
index 71e0e41d6e..074c53aecd 100644
--- a/target/s390x/gen-features.c
+++ b/target/s390x/gen-features.c
@@ -932,6 +932,9 @@ static uint16_t qemu_MAX[] = {
S390_FEAT_KMC_AES_128,
S390_FEAT_KMC_AES_192,
S390_FEAT_KMC_AES_256,
+ S390_FEAT_KMC_EAES_128,
+ S390_FEAT_KMC_EAES_192,
+ S390_FEAT_KMC_EAES_256,
S390_FEAT_KMCTR_AES_128,
S390_FEAT_KMCTR_AES_192,
S390_FEAT_KMCTR_AES_256,
diff --git a/target/s390x/tcg/cpacf.h b/target/s390x/tcg/cpacf.h
index 7cf739e7a4..e302c17a2f 100644
--- a/target/s390x/tcg/cpacf.h
+++ b/target/s390x/tcg/cpacf.h
@@ -44,5 +44,9 @@ int cpacf_paes_ecb(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint64_t param_addr, uint64_t *dst_ptr_reg,
uint64_t *src_ptr_reg, uint64_t *src_len_reg,
uint32_t type, uint8_t fc, uint8_t mod);
+int cpacf_paes_cbc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint64_t *dst_ptr_reg,
+ uint64_t *src_ptr_reg, uint64_t *src_len_reg,
+ uint32_t type, uint8_t fc, uint8_t mod);
#endif
diff --git a/target/s390x/tcg/cpacf_aes.c b/target/s390x/tcg/cpacf_aes.c
index bcfcf3b660..a6487261e1 100644
--- a/target/s390x/tcg/cpacf_aes.c
+++ b/target/s390x/tcg/cpacf_aes.c
@@ -620,3 +620,112 @@ int cpacf_paes_ecb(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
return !len ? 0 : 3;
}
+
+int cpacf_paes_cbc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint64_t *dst_ptr_reg,
+ uint64_t *src_ptr_reg, uint64_t *src_len_reg,
+ uint32_t type, uint8_t fc, uint8_t mod)
+{
+ enum { MAX_BLOCKS_PER_RUN = 8192 / AES_BLOCK_SIZE };
+ uint8_t in[AES_BLOCK_SIZE], out[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
+ const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
+ uint8_t key[32], wkvp[32], iv[AES_BLOCK_SIZE];
+ uint64_t addr, len = *src_len_reg, done = 0;
+ int i, keysize, addr_reg_size = 64;
+ AES_KEY exkey;
+
+ g_assert(type == S390_FEAT_TYPE_KMC);
+
+ switch (fc) {
+ case 0x1a: /* CPACF_KMC_PAES_128 */
+ keysize = 16;
+ break;
+ case 0x1b: /* CPACF_KMC_PAES_192 */
+ keysize = 24;
+ break;
+ case 0x1c: /* CPACF_KMC_PAES_256 */
+ keysize = 32;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (!(env->psw.mask & PSW_MASK_64)) {
+ len = (uint32_t)len;
+ addr_reg_size = (env->psw.mask & PSW_MASK_32) ? 32 : 24;
+ }
+
+ /* length has to be properly aligned. */
+ if (!QEMU_IS_ALIGNED(len, AES_BLOCK_SIZE)) {
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+ }
+
+ /* fetch and check wkvp from param block */
+ for (i = 0; i < sizeof(wkvp); i++) {
+ addr = wrap_address(env, param_addr + AES_BLOCK_SIZE + keysize + i);
+ wkvp[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+ if (memcmp(wkvp, protkey_wkvp, sizeof(wkvp))) {
+ /* wkvp mismatch -> return with cc 1 */
+ return 1;
+ }
+
+ /* fetch iv from param block */
+ for (i = 0; i < AES_BLOCK_SIZE; i++) {
+ addr = wrap_address(env, param_addr + i);
+ iv[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+
+ /* fetch protected key from param block */
+ for (i = 0; i < keysize; i++) {
+ addr = wrap_address(env, param_addr + AES_BLOCK_SIZE + i);
+ key[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+ /* 'decrypt' the protected key */
+ for (i = 0; i < keysize; i++) {
+ key[i] ^= protkey_xor_pattern[i];
+ }
+
+ /* expand key */
+ if (mod) {
+ AES_set_decrypt_key(key, keysize * 8, &exkey);
+ } else {
+ AES_set_encrypt_key(key, keysize * 8, &exkey);
+ }
+
+ /* process up to MAX_BLOCKS_PER_RUN aes blocks */
+ for (i = 0; i < MAX_BLOCKS_PER_RUN && len >= AES_BLOCK_SIZE; i++) {
+ aes_read_block(env, mmu_idx, *src_ptr_reg + done, in, ra);
+ if (mod) {
+ /* decrypt in => buf */
+ AES_decrypt(in, buf, &exkey);
+ /* buf xor iv => out */
+ aes_xor(buf, iv, out);
+ /* prep iv for next round */
+ memcpy(iv, in, AES_BLOCK_SIZE);
+ } else {
+ /* in xor iv => buf */
+ aes_xor(in, iv, buf);
+ /* encrypt buf => out */
+ AES_encrypt(buf, out, &exkey);
+ /* prep iv for next round */
+ memcpy(iv, out, AES_BLOCK_SIZE);
+ }
+ aes_write_block(env, mmu_idx, *dst_ptr_reg + done, out, ra);
+ len -= AES_BLOCK_SIZE, done += AES_BLOCK_SIZE;
+ }
+
+ /* update iv in param block */
+ for (i = 0; i < AES_BLOCK_SIZE; i++) {
+ addr = wrap_address(env, param_addr + i);
+ cpu_stb_mmu(env, addr, iv[i], oi, ra);
+ }
+
+ *src_ptr_reg = deposit64(*src_ptr_reg, 0, addr_reg_size,
+ *src_ptr_reg + done);
+ *dst_ptr_reg = deposit64(*dst_ptr_reg, 0, addr_reg_size,
+ *dst_ptr_reg + done);
+ *src_len_reg -= done;
+
+ return !len ? 0 : 3;
+}
diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c
index 988226338d..3fc48bc9a1 100644
--- a/target/s390x/tcg/crypto_helper.c
+++ b/target/s390x/tcg/crypto_helper.c
@@ -137,6 +137,13 @@ static int cpacf_kmc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
&env->regs[r1], &env->regs[r2], &env->regs[r2 + 1],
S390_FEAT_TYPE_KMC, fc, mod);
break;
+ case 0x1a: /* CPACF_KMC_PAES_128 */
+ case 0x1b: /* CPACF_KMC_PAES_192 */
+ case 0x1c: /* CPACF_KMC_PAES_256 */
+ rc = cpacf_paes_cbc(env, mmu_idx, ra, env->regs[1],
+ &env->regs[r1], &env->regs[r2], &env->regs[r2 + 1],
+ S390_FEAT_TYPE_KMC, fc, mod);
+ break;
default:
g_assert_not_reached();
}
--
2.43.0
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v7 12/17] target/s390x: Support protected key AES CTR for cpacf kmctr instruction
2026-06-17 9:48 [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Harald Freudenberger
` (10 preceding siblings ...)
2026-06-17 9:48 ` [PATCH v7 11/17] target/s390x: Support protected key AES CBC for cpacf kmc instruction Harald Freudenberger
@ 2026-06-17 9:48 ` Harald Freudenberger
2026-06-18 6:10 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 13/17] target/s390x: Minimal protected key AES XTS support for cpacf pcc instruction Harald Freudenberger
` (5 subsequent siblings)
17 siblings, 1 reply; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-17 9:48 UTC (permalink / raw)
To: richard.henderson, iii, david, thuth, berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, fcallies, cohuck
Support the subfunctions CPACF_KMCTR_PAES_128, CPACF_KMCTR_PAES_192
and CPACF_KMCTR_PAES_256 for the cpacf kmctr instruction.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
---
target/s390x/gen-features.c | 3 ++
target/s390x/tcg/cpacf.h | 5 ++
target/s390x/tcg/cpacf_aes.c | 90 ++++++++++++++++++++++++++++++++
target/s390x/tcg/crypto_helper.c | 7 +++
4 files changed, 105 insertions(+)
diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
index 074c53aecd..4a131dc191 100644
--- a/target/s390x/gen-features.c
+++ b/target/s390x/gen-features.c
@@ -938,6 +938,9 @@ static uint16_t qemu_MAX[] = {
S390_FEAT_KMCTR_AES_128,
S390_FEAT_KMCTR_AES_192,
S390_FEAT_KMCTR_AES_256,
+ S390_FEAT_KMCTR_EAES_128,
+ S390_FEAT_KMCTR_EAES_192,
+ S390_FEAT_KMCTR_EAES_256,
S390_FEAT_PCC_XTS_AES_128,
S390_FEAT_PCC_XTS_AES_256,
S390_FEAT_PCKMO_AES_128,
diff --git a/target/s390x/tcg/cpacf.h b/target/s390x/tcg/cpacf.h
index e302c17a2f..223bada622 100644
--- a/target/s390x/tcg/cpacf.h
+++ b/target/s390x/tcg/cpacf.h
@@ -48,5 +48,10 @@ int cpacf_paes_cbc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint64_t param_addr, uint64_t *dst_ptr_reg,
uint64_t *src_ptr_reg, uint64_t *src_len_reg,
uint32_t type, uint8_t fc, uint8_t mod);
+int cpacf_paes_ctr(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint64_t *dst_ptr_reg,
+ uint64_t *src_ptr_reg, uint64_t *src_len_reg,
+ uint64_t *ctr_ptr_reg, uint32_t type,
+ uint8_t fc, uint8_t mod);
#endif
diff --git a/target/s390x/tcg/cpacf_aes.c b/target/s390x/tcg/cpacf_aes.c
index a6487261e1..ffa286d422 100644
--- a/target/s390x/tcg/cpacf_aes.c
+++ b/target/s390x/tcg/cpacf_aes.c
@@ -729,3 +729,93 @@ int cpacf_paes_cbc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
return !len ? 0 : 3;
}
+
+int cpacf_paes_ctr(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint64_t *dst_ptr_reg,
+ uint64_t *src_ptr_reg, uint64_t *src_len_reg,
+ uint64_t *ctr_ptr_reg, uint32_t type,
+ uint8_t fc, uint8_t mod)
+{
+ enum { MAX_BLOCKS_PER_RUN = 8192 / AES_BLOCK_SIZE };
+ const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
+ uint8_t ctr[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
+ uint8_t in[AES_BLOCK_SIZE], out[AES_BLOCK_SIZE];
+ uint64_t addr, len = *src_len_reg, done = 0;
+ int i, keysize, addr_reg_size = 64;
+ uint8_t key[32], wkvp[32];
+ AES_KEY exkey;
+
+ g_assert(type == S390_FEAT_TYPE_KMCTR);
+
+ switch (fc) {
+ case 0x1a: /* CPACF_KMCTR_PAES_128 */
+ keysize = 16;
+ break;
+ case 0x1b: /* CPACF_KMCTR_PAES_192 */
+ keysize = 24;
+ break;
+ case 0x1c: /* CPACF_KMCTR_PAES_256 */
+ keysize = 32;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (!(env->psw.mask & PSW_MASK_64)) {
+ len = (uint32_t)len;
+ addr_reg_size = (env->psw.mask & PSW_MASK_32) ? 32 : 24;
+ }
+
+ /* length has to be properly aligned. */
+ if (!QEMU_IS_ALIGNED(len, AES_BLOCK_SIZE)) {
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+ }
+
+ /* fetch and check wkvp from param block */
+ for (i = 0; i < sizeof(wkvp); i++) {
+ addr = wrap_address(env, param_addr + keysize + i);
+ wkvp[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+ if (memcmp(wkvp, protkey_wkvp, sizeof(wkvp))) {
+ /* wkvp mismatch -> return with cc 1 */
+ return 1;
+ }
+
+ /* fetch protected key from param block */
+ for (i = 0; i < keysize; i++) {
+ addr = wrap_address(env, param_addr + i);
+ key[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+ /* 'decrypt' the protected key */
+ for (i = 0; i < keysize; i++) {
+ key[i] ^= protkey_xor_pattern[i];
+ }
+
+ /* expand key */
+ AES_set_encrypt_key(key, keysize * 8, &exkey);
+
+ /* process up to MAX_BLOCKS_PER_RUN aes blocks */
+ for (i = 0; i < MAX_BLOCKS_PER_RUN && len >= AES_BLOCK_SIZE; i++) {
+ /* read in nonce/ctr => ctr */
+ aes_read_block(env, mmu_idx, *ctr_ptr_reg + done, ctr, ra);
+ /* encrypt ctr => buf */
+ AES_encrypt(ctr, buf, &exkey);
+ /* read in one block of input data => in */
+ aes_read_block(env, mmu_idx, *src_ptr_reg + done, in, ra);
+ /* exor input data with encrypted ctr => out */
+ aes_xor(in, buf, out);
+ /* write out the processed block */
+ aes_write_block(env, mmu_idx, *dst_ptr_reg + done, out, ra);
+ len -= AES_BLOCK_SIZE, done += AES_BLOCK_SIZE;
+ }
+
+ *src_ptr_reg = deposit64(*src_ptr_reg, 0, addr_reg_size,
+ *src_ptr_reg + done);
+ *dst_ptr_reg = deposit64(*dst_ptr_reg, 0, addr_reg_size,
+ *dst_ptr_reg + done);
+ *ctr_ptr_reg = deposit64(*ctr_ptr_reg, 0, addr_reg_size,
+ *ctr_ptr_reg + done);
+ *src_len_reg -= done;
+
+ return !len ? 0 : 3;
+}
diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c
index 3fc48bc9a1..60c3ebd79e 100644
--- a/target/s390x/tcg/crypto_helper.c
+++ b/target/s390x/tcg/crypto_helper.c
@@ -165,6 +165,13 @@ static int cpacf_kmctr(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
&env->regs[r1], &env->regs[r2], &env->regs[r2 + 1],
&env->regs[r3], S390_FEAT_TYPE_KMCTR, fc, mod);
break;
+ case 0x1a: /* CPACF_KMCTR_PAES_128 */
+ case 0x1b: /* CPACF_KMCTR_PAES_192 */
+ case 0x1c: /* CPACF_KMCTR_PAES_256 */
+ rc = cpacf_paes_ctr(env, mmu_idx, ra, env->regs[1],
+ &env->regs[r1], &env->regs[r2], &env->regs[r2 + 1],
+ &env->regs[r3], S390_FEAT_TYPE_KMCTR, fc, mod);
+ break;
default:
g_assert_not_reached();
}
--
2.43.0
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v7 13/17] target/s390x: Minimal protected key AES XTS support for cpacf pcc instruction
2026-06-17 9:48 [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Harald Freudenberger
` (11 preceding siblings ...)
2026-06-17 9:48 ` [PATCH v7 12/17] target/s390x: Support protected key AES CTR for cpacf kmctr instruction Harald Freudenberger
@ 2026-06-17 9:48 ` Harald Freudenberger
2026-06-18 6:18 ` Finn Callies
2026-06-18 6:21 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 14/17] target/s390x: Support protected key AES XTS for cpacf km instruction Harald Freudenberger
` (4 subsequent siblings)
17 siblings, 2 replies; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-17 9:48 UTC (permalink / raw)
To: richard.henderson, iii, david, thuth, berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, fcallies, cohuck
Support CPACF pcc subfunctions PCC-Compute-XTS-Parameter-Encrypted-AES-128
and PCC-Compute-XTS-Parameter-Encrypted-AES-128 but only for the special
case block sequential number is 0. However, this covers the s390 PAES XTS
implementation in the Linux kernel.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Tested-by: Holger Dengler <dengler@linux.ibm.com>
---
target/s390x/gen-features.c | 2 +
target/s390x/tcg/cpacf.h | 2 +
target/s390x/tcg/cpacf_aes.c | 80 ++++++++++++++++++++++++++++++++
target/s390x/tcg/crypto_helper.c | 4 ++
4 files changed, 88 insertions(+)
diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
index 4a131dc191..126bacb281 100644
--- a/target/s390x/gen-features.c
+++ b/target/s390x/gen-features.c
@@ -943,6 +943,8 @@ static uint16_t qemu_MAX[] = {
S390_FEAT_KMCTR_EAES_256,
S390_FEAT_PCC_XTS_AES_128,
S390_FEAT_PCC_XTS_AES_256,
+ S390_FEAT_PCC_XTS_EAES_128,
+ S390_FEAT_PCC_XTS_EAES_256,
S390_FEAT_PCKMO_AES_128,
S390_FEAT_PCKMO_AES_192,
S390_FEAT_PCKMO_AES_256,
diff --git a/target/s390x/tcg/cpacf.h b/target/s390x/tcg/cpacf.h
index 223bada622..6df474fbc8 100644
--- a/target/s390x/tcg/cpacf.h
+++ b/target/s390x/tcg/cpacf.h
@@ -53,5 +53,7 @@ int cpacf_paes_ctr(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint64_t *src_ptr_reg, uint64_t *src_len_reg,
uint64_t *ctr_ptr_reg, uint32_t type,
uint8_t fc, uint8_t mod);
+int cpacf_paes_pcc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint8_t fc);
#endif
diff --git a/target/s390x/tcg/cpacf_aes.c b/target/s390x/tcg/cpacf_aes.c
index ffa286d422..d454d6f302 100644
--- a/target/s390x/tcg/cpacf_aes.c
+++ b/target/s390x/tcg/cpacf_aes.c
@@ -819,3 +819,83 @@ int cpacf_paes_ctr(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
return !len ? 0 : 3;
}
+
+int cpacf_paes_pcc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint8_t fc)
+{
+ uint8_t key[32], wkvp[32], tweak[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
+ const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
+ int keysize, i;
+ uint64_t addr;
+ AES_KEY exkey;
+
+ switch (fc) {
+ case 0x3a: /* CPACF_PCC compute XTS param Encrypted AES-128 */
+ keysize = 16;
+ break;
+ case 0x3c: /* CPACF PCC compute XTS param Encrypted AES-256 */
+ keysize = 32;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ /* fetch and check wkvp from param block */
+ for (i = 0; i < sizeof(wkvp); i++) {
+ addr = wrap_address(env, param_addr + keysize + i);
+ wkvp[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+ if (memcmp(wkvp, protkey_wkvp, sizeof(wkvp))) {
+ /* wkvp mismatch -> return with cc 1 */
+ return 1;
+ }
+
+ /* fetch block sequence nr from param block into buf */
+ for (i = 0; i < AES_BLOCK_SIZE; i++) {
+ addr = wrap_address(env, param_addr + keysize +
+ sizeof(wkvp) + AES_BLOCK_SIZE + i);
+ buf[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+
+ /* is the block sequence nr 0 ? */
+ for (i = 0; i < AES_BLOCK_SIZE && !buf[i]; i++) {
+ ;
+ }
+ if (i < AES_BLOCK_SIZE) {
+ /* no, sorry handling of non zero block sequence is not implemented */
+ cpu_abort(env_cpu(env),
+ "PCC-compute-XTS-param (encrypted) with non zero block seq nr is not implemented\n");
+ return 1;
+ }
+
+ /* fetch protected key from param block */
+ for (i = 0; i < keysize; i++) {
+ addr = wrap_address(env, param_addr + i);
+ key[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+ /* 'decrypt' the protected key */
+ for (i = 0; i < keysize; i++) {
+ key[i] ^= protkey_xor_pattern[i];
+ }
+
+ /* fetch tweak from param block into tweak */
+ for (i = 0; i < AES_BLOCK_SIZE; i++) {
+ addr = wrap_address(env, param_addr + keysize + sizeof(wkvp) + i);
+ tweak[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+
+ /* expand key */
+ AES_set_encrypt_key(key, keysize * 8, &exkey);
+
+ /* encrypt tweak */
+ AES_encrypt(tweak, buf, &exkey);
+
+ /* store encrypted tweak into xts parameter field of the param block */
+ for (i = 0; i < AES_BLOCK_SIZE; i++) {
+ addr = wrap_address(env, param_addr + keysize +
+ sizeof(wkvp) + 3 * AES_BLOCK_SIZE + i);
+ cpu_stb_mmu(env, addr, buf[i], oi, ra);
+ }
+
+ return 0;
+}
diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c
index 60c3ebd79e..38f7d900fa 100644
--- a/target/s390x/tcg/crypto_helper.c
+++ b/target/s390x/tcg/crypto_helper.c
@@ -206,6 +206,10 @@ static int cpacf_pcc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
case 0x34: /* CPACF PCC compute XTS param AES-256 */
rc = cpacf_aes_pcc(env, mmu_idx, ra, env->regs[1], fc);
break;
+ case 0x3a: /* CPACF_PCC compute XTS param Encrypted AES-128 */
+ case 0x3c: /* CPACF PCC compute XTS param Encrypted AES-256 */
+ rc = cpacf_paes_pcc(env, mmu_idx, ra, env->regs[1], fc);
+ break;
default:
g_assert_not_reached();
}
--
2.43.0
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v7 14/17] target/s390x: Support protected key AES XTS for cpacf km instruction
2026-06-17 9:48 [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Harald Freudenberger
` (12 preceding siblings ...)
2026-06-17 9:48 ` [PATCH v7 13/17] target/s390x: Minimal protected key AES XTS support for cpacf pcc instruction Harald Freudenberger
@ 2026-06-17 9:48 ` Harald Freudenberger
2026-06-18 6:22 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 15/17] docs/s390: Document CPACF instructions support Harald Freudenberger
` (3 subsequent siblings)
17 siblings, 1 reply; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-17 9:48 UTC (permalink / raw)
To: richard.henderson, iii, david, thuth, berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, fcallies, cohuck
Support the subfunctions CPACF_KM_PXTS_128 and CPACF_KM_PAES_256
for the cpacf km instruction.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Tested-by: Holger Dengler <dengler@linux.ibm.com>
---
target/s390x/gen-features.c | 2 +
target/s390x/tcg/cpacf.h | 4 ++
target/s390x/tcg/cpacf_aes.c | 106 +++++++++++++++++++++++++++++++
target/s390x/tcg/crypto_helper.c | 6 ++
4 files changed, 118 insertions(+)
diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
index 126bacb281..c4c59c3504 100644
--- a/target/s390x/gen-features.c
+++ b/target/s390x/gen-features.c
@@ -929,6 +929,8 @@ static uint16_t qemu_MAX[] = {
S390_FEAT_KM_EAES_256,
S390_FEAT_KM_XTS_AES_128,
S390_FEAT_KM_XTS_AES_256,
+ S390_FEAT_KM_XTS_EAES_128,
+ S390_FEAT_KM_XTS_EAES_256,
S390_FEAT_KMC_AES_128,
S390_FEAT_KMC_AES_192,
S390_FEAT_KMC_AES_256,
diff --git a/target/s390x/tcg/cpacf.h b/target/s390x/tcg/cpacf.h
index 6df474fbc8..25990c2df6 100644
--- a/target/s390x/tcg/cpacf.h
+++ b/target/s390x/tcg/cpacf.h
@@ -55,5 +55,9 @@ int cpacf_paes_ctr(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint8_t fc, uint8_t mod);
int cpacf_paes_pcc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint64_t param_addr, uint8_t fc);
+int cpacf_paes_xts(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint64_t *dst_ptr_reg,
+ uint64_t *src_ptr_reg, uint64_t *src_len_reg,
+ uint32_t type, uint8_t fc, uint8_t mod);
#endif
diff --git a/target/s390x/tcg/cpacf_aes.c b/target/s390x/tcg/cpacf_aes.c
index d454d6f302..98d5134d5f 100644
--- a/target/s390x/tcg/cpacf_aes.c
+++ b/target/s390x/tcg/cpacf_aes.c
@@ -899,3 +899,109 @@ int cpacf_paes_pcc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
return 0;
}
+
+int cpacf_paes_xts(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t param_addr, uint64_t *dst_ptr_reg,
+ uint64_t *src_ptr_reg, uint64_t *src_len_reg,
+ uint32_t type, uint8_t fc, uint8_t mod)
+{
+ enum { MAX_BLOCKS_PER_RUN = 8192 / AES_BLOCK_SIZE };
+ uint8_t buf1[AES_BLOCK_SIZE], buf2[AES_BLOCK_SIZE];
+ const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
+ uint8_t key[32], wkvp[32], tweak[AES_BLOCK_SIZE];
+ uint64_t addr, len = *src_len_reg, done = 0;
+ int i, keysize, addr_reg_size = 64;
+ AES_KEY exkey;
+
+ g_assert(type == S390_FEAT_TYPE_KM);
+
+ switch (fc) {
+ case 0x3a: /* CPACF_KM_PXTS_128 */
+ keysize = 16;
+ break;
+ case 0x3c: /* CPACF_KM_PXTS_256 */
+ keysize = 32;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (!(env->psw.mask & PSW_MASK_64)) {
+ len = (uint32_t)len;
+ addr_reg_size = (env->psw.mask & PSW_MASK_32) ? 32 : 24;
+ }
+
+ /* length has to be properly aligned. */
+ if (!QEMU_IS_ALIGNED(len, AES_BLOCK_SIZE)) {
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+ }
+
+ /* fetch and check wkvp from param block */
+ for (i = 0; i < sizeof(wkvp); i++) {
+ addr = wrap_address(env, param_addr + keysize + i);
+ wkvp[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+ if (memcmp(wkvp, protkey_wkvp, sizeof(wkvp))) {
+ /* wkvp mismatch -> return with cc 1 */
+ return 1;
+ }
+
+ /* fetch protected key from param block */
+ for (i = 0; i < keysize; i++) {
+ addr = wrap_address(env, param_addr + i);
+ key[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+ /* 'decrypt' the protected key */
+ for (i = 0; i < keysize; i++) {
+ key[i] ^= protkey_xor_pattern[i];
+ }
+
+ /* expand key */
+ if (mod) {
+ AES_set_decrypt_key(key, keysize * 8, &exkey);
+ } else {
+ AES_set_encrypt_key(key, keysize * 8, &exkey);
+ }
+
+ /* fetch tweak from param block */
+ for (i = 0; i < AES_BLOCK_SIZE; i++) {
+ addr = wrap_address(env, param_addr + keysize + sizeof(wkvp) + i);
+ tweak[i] = cpu_ldb_mmu(env, addr, oi, ra);
+ }
+
+ /* process up to MAX_BLOCKS_PER_RUN aes blocks */
+ for (i = 0; i < MAX_BLOCKS_PER_RUN && len >= AES_BLOCK_SIZE; i++) {
+ /* fetch one AES block into buf1 */
+ aes_read_block(env, mmu_idx, *src_ptr_reg + done, buf1, ra);
+ /* buf1 xor tweak => buf2 */
+ aes_xor(buf1, tweak, buf2);
+ if (mod) {
+ /* decrypt buf2 => buf1 */
+ AES_decrypt(buf2, buf1, &exkey);
+ } else {
+ /* encrypt buf2 => buf1 */
+ AES_encrypt(buf2, buf1, &exkey);
+ }
+ /* buf1 xor tweak => buf2 */
+ aes_xor(buf1, tweak, buf2);
+ /* prep tweak for next round */
+ aes_xts_prep_next_tweak(tweak);
+ /* write out this processed block from buf2 */
+ aes_write_block(env, mmu_idx, *dst_ptr_reg + done, buf2, ra);
+ len -= AES_BLOCK_SIZE, done += AES_BLOCK_SIZE;
+ }
+
+ /* update tweak in param block */
+ for (i = 0; i < AES_BLOCK_SIZE; i++) {
+ addr = wrap_address(env, param_addr + keysize + sizeof(wkvp) + i);
+ cpu_stb_mmu(env, addr, tweak[i], oi, ra);
+ }
+
+ *src_ptr_reg = deposit64(*src_ptr_reg, 0, addr_reg_size,
+ *src_ptr_reg + done);
+ *dst_ptr_reg = deposit64(*dst_ptr_reg, 0, addr_reg_size,
+ *dst_ptr_reg + done);
+ *src_len_reg -= done;
+
+ return !len ? 0 : 3;
+}
diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c
index 38f7d900fa..8054e4facd 100644
--- a/target/s390x/tcg/crypto_helper.c
+++ b/target/s390x/tcg/crypto_helper.c
@@ -116,6 +116,12 @@ static int cpacf_km(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
&env->regs[r1], &env->regs[r2], &env->regs[r2 + 1],
S390_FEAT_TYPE_KM, fc, mod);
break;
+ case 0x3a: /* CPACF_KM_PXTS_128 */
+ case 0x3c: /* CPACF_KM_PXTS_256 */
+ rc = cpacf_paes_xts(env, mmu_idx, ra, env->regs[1],
+ &env->regs[r1], &env->regs[r2], &env->regs[r2 + 1],
+ S390_FEAT_TYPE_KM, fc, mod);
+ break;
default:
g_assert_not_reached();
}
--
2.43.0
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v7 15/17] docs/s390: Document CPACF instructions support
2026-06-17 9:48 [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Harald Freudenberger
` (13 preceding siblings ...)
2026-06-17 9:48 ` [PATCH v7 14/17] target/s390x: Support protected key AES XTS for cpacf km instruction Harald Freudenberger
@ 2026-06-17 9:48 ` Harald Freudenberger
2026-06-18 6:28 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 16/17] crypto: Add aes-helpers file to support some AES modes Harald Freudenberger
` (2 subsequent siblings)
17 siblings, 1 reply; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-17 9:48 UTC (permalink / raw)
To: richard.henderson, iii, david, thuth, berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, fcallies, cohuck
Add a first document covering the Qemu s390 CPACF instructions
and functions supported.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
---
docs/system/s390x/cpacf.rst | 116 +++++++++++++++++++++++++++++++++++
docs/system/target-s390x.rst | 1 +
2 files changed, 117 insertions(+)
create mode 100644 docs/system/s390x/cpacf.rst
diff --git a/docs/system/s390x/cpacf.rst b/docs/system/s390x/cpacf.rst
new file mode 100644
index 0000000000..85f35b4e9c
--- /dev/null
+++ b/docs/system/s390x/cpacf.rst
@@ -0,0 +1,116 @@
+CPACF Support
+=============
+
+CPACF
+-----
+
+CP Assist for Cryptographic Function (CPACF) is a hardware-integrated
+coprocessor feature built into every processor core of IBM Z and
+LinuxONE mainframes (s390x architecture). It provides high-speed,
+hardware-accelerated encryption and hashing directly on the CPU.
+
+CPACF provides a set of z/Architecture instructions (known as Message
+Security Assist or MSA) that execute cryptographic operations
+synchronously with the main processor.
+
+- Symmetric Encryption: Support for AES (128, 192, 256-bit), DES, and
+ Triple-DES (TDES).
+- Hashing: Acceleration for SHA-1, SHA-2 (up to SHA-512), SHA-3 and
+ SHAKE.
+- Random Number Generation: Pseudo Random Number Generator (PRNG) and
+ a hardware-based True Random Number Generator (TRNG).
+- Asymmetric Support: Elliptic Curve Cryptography (ECC) primitives
+ P-256, P-384, P-521, Montgomery/Edwards curves (e.g., Ed25519).
+
+Documentation about CPACF instructions is public available and
+can be found in the "z/Architecture Principles of Operation"
+accessible at the IBM documentation hub https://www.ibm.com/docs/en.
+For example the latest version as a pdf is available here:
+https://www.ibm.com/support/pages/zvm/library/other/22783214.pdf
+
+
+CPACF instructions
+------------------
+
+Here is a list of implemented CPACF instructions and the supported
+functions for each instruction:
+
+KDSA (COMPUTE DIGITAL SIGNATURE AUTHENTICATION)
+- Function code 0x00 - Function Query
+
+KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST)
+- Function code 0x00 - Function Query
+- Function code 0x02 - CPACF_KIMD_SHA_256
+- Function code 0x03 - CPACF_KIMD_SHA_512
+
+KLMD (COMPUTE LAST MESSAGE DIGEST)
+- Function code 0x00 - Function Query
+- Function code 0x02 - CPACF_KLMD_SHA_256
+- Function code 0x03 - CPACF_KLMD_SHA_512
+
+KM (CIPHER MESSAGE)
+- Function code 0x00 - Function Query
+- Function code 0x12 - CPACF_KM_AES_128
+- Function code 0x13 - CPACF_KM_AES_192
+- Function code 0x14 - CPACF_KM_AES_256
+- Function code 0x1a - CPACF_KM_PAES_128
+- Function code 0x1b - CPACF_KM_PAES_192
+- Function code 0x1c - CPACF_KM_PAES_256
+- Function code 0x32 - CPACF_KM_XTS_128
+- Function code 0x34 - CPACF_KM_XTS_256
+- Function code 0x3a - CPACF_KM_PXTS_128
+- Function code 0x3c - CPACF_KM_PXTS_256
+
+KMAC (COMPUTE MESSAGE AUTHENTICATION CODE)
+- Function code 0x00 - Function Query
+
+KMC (CIPHER MESSAGE WITH CHAINING)
+- Function code 0x00 - Function Query
+- Function code 0x12 - CPACF_KMC_AES_128
+- Function code 0x13 - CPACF_KMC_AES_192
+- Function code 0x14 - CPACF_KMC_AES_256
+- Function code 0x1a - CPACF_KMC_PAES_128
+- Function code 0x1b - CPACF_KMC_PAES_192
+- Function code 0x1c - CPACF_KMC_PAES_256
+
+KMCTR (CIPHER MESSAGE WITH COUNTER)
+- Function code 0x00 - Function Query
+- Function code 0x12 - CPACF_KMCTR_AES_128
+- Function code 0x13 - CPACF_KMCTR_AES_192
+- Function code 0x14 - CPACF_KMCTR_AES_256
+- Function code 0x1a - CPACF_KMCTR_PAES_128
+- Function code 0x1b - CPACF_KMCTR_PAES_192
+- Function code 0x1c - CPACF_KMCTR_PAES_256
+
+KMF (CIPHER MESSAGE WITH CIPHER FEEDBACK)
+- not supported
+
+KMO (CIPHER MESSAGE WITH OUTPUT FEEDBACK)
+- not supported
+
+PCC (PERFORM CRYPTOGRAPHIC COMPUTATION)
+- Function code 0x00 - Function Query
+- Function code 0x32 - compute XTS param AES-128
+- Function code 0x34 - compute XTS param AES-256
+- Function code 0x3a - compute XTS param Encrypted AES-128
+- Function code 0x3c - compute XTS param Encrypted AES-256
+
+PCKMO (PERFORM CRYPTOGRAPHIC KEY MANAGEMENT OPERATION)
+- Function code 0x00 - Function Query
+- Function code 0x12 - CPACF_PCKMO_ENC_AES_128_KEY
+- Function code 0x13 - CPACF_PCKMO_ENC_AES_192_KEY
+- Function code 0x14 - CPACF_PCKMO_ENC_AES_256_KEY
+
+PRNO (PERFORM RANDOM NUMBER OPERATION)
+- Function code 0x00 - Function Query
+- Function code 0x72 - CPACF_PRNO_TRNG
+
+Note that the use of a not supported CPACF instruction (KMF and KMO)
+or invocation of a not listed function will result in a Specification
+Exception.
+
+Not listed CPACF instructions (KMF, KMO) cause an Operation Exception
+when used. Not listed functions cause a Specification Exception when
+called. If only the query function is listed (KDSA), then the query
+function will return a function status word with all but the query
+function bit set to 0.
diff --git a/docs/system/target-s390x.rst b/docs/system/target-s390x.rst
index 94c981e732..49159826eb 100644
--- a/docs/system/target-s390x.rst
+++ b/docs/system/target-s390x.rst
@@ -35,3 +35,4 @@ Architectural features
s390x/bootdevices
s390x/protvirt
s390x/cpu-topology
+ s390x/cpacf
--
2.43.0
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v7 16/17] crypto: Add aes-helpers file to support some AES modes
2026-06-17 9:48 [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Harald Freudenberger
` (14 preceding siblings ...)
2026-06-17 9:48 ` [PATCH v7 15/17] docs/s390: Document CPACF instructions support Harald Freudenberger
@ 2026-06-17 9:48 ` Harald Freudenberger
2026-06-18 6:31 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 17/17] target/s390x: Use generic AES helper functions Harald Freudenberger
2026-06-18 5:37 ` [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Finn Callies
17 siblings, 1 reply; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-17 9:48 UTC (permalink / raw)
To: richard.henderson, iii, david, thuth, berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, fcallies, cohuck
Add a new file crypto/aes-helpers.c with simple functions
to support some AES modes:
- AES cbc: AES_cbc_encrypt() AES_cbc_decrypt()
- AES ctr: AES_ctr_encrypt()
- AES xts: AES_xts_encrypt() AES_xts_decrypt()
and some AES related helpers:
- AES_xor()
- AES_xts_prep_next_tweak()
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
---
crypto/aes-helpers.c | 101 +++++++++++++++++++++++++++++++++++++++++++
crypto/meson.build | 1 +
include/crypto/aes.h | 14 ++++++
3 files changed, 116 insertions(+)
create mode 100644 crypto/aes-helpers.c
diff --git a/crypto/aes-helpers.c b/crypto/aes-helpers.c
new file mode 100644
index 0000000000..8ad3c5132a
--- /dev/null
+++ b/crypto/aes-helpers.c
@@ -0,0 +1,101 @@
+/*
+ * AES helper functions and mode implementations
+ *
+ * Authors:
+ * Harald Freudenberger <freude@linux.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include "crypto/aes.h"
+
+void AES_xor(const unsigned char *src1, const unsigned char *src2,
+ unsigned char *dst)
+{
+ int i;
+
+ for (i = 0; i < AES_BLOCK_SIZE; i++) {
+ dst[i] = src1[i] ^ src2[i];
+ }
+}
+
+void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
+ unsigned char *iv, const AES_KEY *key)
+{
+ unsigned char buf[AES_BLOCK_SIZE];
+
+ /* in xor iv => buf */
+ AES_xor(in, iv, buf);
+ /* encrypt buf => out */
+ AES_encrypt(buf, out, key);
+ /* prep iv for next round */
+ memcpy(iv, out, AES_BLOCK_SIZE);
+}
+
+void AES_cbc_decrypt(const unsigned char *in, unsigned char *out,
+ unsigned char *iv, const AES_KEY *key)
+{
+ unsigned char buf[AES_BLOCK_SIZE];
+
+ /* decrypt in => buf */
+ AES_decrypt(in, buf, key);
+ /* buf xor iv => out */
+ AES_xor(buf, iv, out);
+ /* prep iv for next round */
+ memcpy(iv, in, AES_BLOCK_SIZE);
+}
+
+void AES_ctr_encrypt(const unsigned char *in, unsigned char *out,
+ const unsigned char *ctr, const AES_KEY *key)
+{
+ unsigned char buf[AES_BLOCK_SIZE];
+
+ /* encrypt ctr => buf */
+ AES_encrypt(ctr, buf, key);
+ /* exor input data with encrypted ctr => out */
+ AES_xor(in, buf, out);
+}
+
+void AES_xts_prep_next_tweak(unsigned char *tweak)
+{
+ unsigned char carry;
+ int i;
+
+ carry = tweak[AES_BLOCK_SIZE - 1] >> 7;
+
+ for (i = AES_BLOCK_SIZE - 1; i > 0; i--) {
+ tweak[i] = (unsigned char)((tweak[i] << 1) | (tweak[i - 1] >> 7));
+ }
+
+ tweak[i] = (unsigned char)(tweak[i] << 1);
+ tweak[i] ^= (unsigned char)(0x87 & (unsigned char)(-(unsigned char)carry));
+}
+
+void AES_xts_encrypt(const unsigned char *in, unsigned char *out,
+ const unsigned char *tweak, const AES_KEY *key)
+{
+ unsigned char buf1[AES_BLOCK_SIZE], buf2[AES_BLOCK_SIZE];
+
+ /* in xor tweak => buf1 */
+ AES_xor(in, tweak, buf1);
+ /* encrypt buf1 => buf2 */
+ AES_encrypt(buf1, buf2, key);
+ /* buf2 xor tweak => out */
+ AES_xor(buf2, tweak, out);
+}
+
+void AES_xts_decrypt(const unsigned char *in, unsigned char *out,
+ const unsigned char *tweak, const AES_KEY *key)
+{
+ unsigned char buf1[AES_BLOCK_SIZE], buf2[AES_BLOCK_SIZE];
+
+ /* in xor tweak => buf1 */
+ AES_xor(in, tweak, buf1);
+ /* encrypt buf1 => buf2 */
+ AES_decrypt(buf1, buf2, key);
+ /* buf2 xor tweak => out */
+ AES_xor(buf2, tweak, out);
+}
diff --git a/crypto/meson.build b/crypto/meson.build
index b51597a879..675f27311c 100644
--- a/crypto/meson.build
+++ b/crypto/meson.build
@@ -55,6 +55,7 @@ system_ss.add(when: gnutls, if_true: files('tls-cipher-suites.c'))
util_ss.add(files(
'aes.c',
+ 'aes-helpers.c',
'clmul.c',
'init.c',
'sm4.c',
diff --git a/include/crypto/aes.h b/include/crypto/aes.h
index 381f24c902..df6239cb9c 100644
--- a/include/crypto/aes.h
+++ b/include/crypto/aes.h
@@ -37,4 +37,18 @@ AES_Td0[x] = Si[x].[0e, 09, 0d, 0b];
extern const uint32_t AES_Te0[256], AES_Td0[256];
+void AES_xor(const unsigned char *src1, const unsigned char *src2,
+ unsigned char *dst);
+void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
+ unsigned char *iv, const AES_KEY *key);
+void AES_cbc_decrypt(const unsigned char *in, unsigned char *out,
+ unsigned char *iv, const AES_KEY *key);
+void AES_ctr_encrypt(const unsigned char *in, unsigned char *out,
+ const unsigned char *ctr, const AES_KEY *key);
+void AES_xts_prep_next_tweak(unsigned char *tweak);
+void AES_xts_encrypt(const unsigned char *in, unsigned char *out,
+ const unsigned char *tweak, const AES_KEY *key);
+void AES_xts_decrypt(const unsigned char *in, unsigned char *out,
+ const unsigned char *tweak, const AES_KEY *key);
+
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v7 17/17] target/s390x: Use generic AES helper functions
2026-06-17 9:48 [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Harald Freudenberger
` (15 preceding siblings ...)
2026-06-17 9:48 ` [PATCH v7 16/17] crypto: Add aes-helpers file to support some AES modes Harald Freudenberger
@ 2026-06-17 9:48 ` Harald Freudenberger
2026-06-18 6:35 ` Finn Callies
2026-06-18 5:37 ` [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Finn Callies
17 siblings, 1 reply; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-17 9:48 UTC (permalink / raw)
To: richard.henderson, iii, david, thuth, berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, fcallies, cohuck
Rewrite the cpacf implementations to use the generic
AES helper functions from crypto/aes-helpers.c
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
---
target/s390x/tcg/cpacf_aes.c | 124 ++++++++++-------------------------
1 file changed, 36 insertions(+), 88 deletions(-)
diff --git a/target/s390x/tcg/cpacf_aes.c b/target/s390x/tcg/cpacf_aes.c
index 98d5134d5f..9935b6b39c 100644
--- a/target/s390x/tcg/cpacf_aes.c
+++ b/target/s390x/tcg/cpacf_aes.c
@@ -119,20 +119,13 @@ int cpacf_aes_ecb(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
return !len ? 0 : 3;
}
-static void aes_xor(const uint8_t *src1, const uint8_t *src2, uint8_t *dst)
-{
- for (int i = 0; i < AES_BLOCK_SIZE; i++) {
- dst[i] = src1[i] ^ src2[i];
- }
-}
-
int cpacf_aes_cbc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint64_t param_addr, uint64_t *dst_ptr_reg,
uint64_t *src_ptr_reg, uint64_t *src_len_reg,
uint32_t type, uint8_t fc, uint8_t mod)
{
enum { MAX_BLOCKS_PER_RUN = 8192 / AES_BLOCK_SIZE };
- uint8_t in[AES_BLOCK_SIZE], out[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
+ uint8_t in[AES_BLOCK_SIZE], out[AES_BLOCK_SIZE];
const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
uint64_t addr, len = *src_len_reg, done = 0;
int i, keysize, addr_reg_size = 64;
@@ -188,19 +181,11 @@ int cpacf_aes_cbc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
for (i = 0; i < MAX_BLOCKS_PER_RUN && len >= AES_BLOCK_SIZE; i++) {
aes_read_block(env, mmu_idx, *src_ptr_reg + done, in, ra);
if (mod) {
- /* decrypt in => buf */
- AES_decrypt(in, buf, &exkey);
- /* buf xor iv => out */
- aes_xor(buf, iv, out);
- /* prep iv for next round */
- memcpy(iv, in, AES_BLOCK_SIZE);
+ /* decrypt in => out */
+ AES_cbc_decrypt(in, out, iv, &exkey);
} else {
- /* in xor iv => buf */
- aes_xor(in, iv, buf);
- /* encrypt buf => out */
- AES_encrypt(buf, out, &exkey);
- /* prep iv for next round */
- memcpy(iv, out, AES_BLOCK_SIZE);
+ /* encrypt in => out */
+ AES_cbc_encrypt(in, out, iv, &exkey);
}
aes_write_block(env, mmu_idx, *dst_ptr_reg + done, out, ra);
len -= AES_BLOCK_SIZE, done += AES_BLOCK_SIZE;
@@ -229,11 +214,10 @@ int cpacf_aes_ctr(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
{
enum { MAX_BLOCKS_PER_RUN = 8192 / AES_BLOCK_SIZE };
const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
- uint8_t ctr[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
uint8_t in[AES_BLOCK_SIZE], out[AES_BLOCK_SIZE];
uint64_t addr, len = *src_len_reg, done = 0;
+ uint8_t ctr[AES_BLOCK_SIZE], key[32];
int i, keysize, addr_reg_size = 64;
- uint8_t key[32];
AES_KEY exkey;
g_assert(type == S390_FEAT_TYPE_KMCTR);
@@ -275,12 +259,10 @@ int cpacf_aes_ctr(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
for (i = 0; i < MAX_BLOCKS_PER_RUN && len >= AES_BLOCK_SIZE; i++) {
/* read in nonce/ctr => ctr */
aes_read_block(env, mmu_idx, *ctr_ptr_reg + done, ctr, ra);
- /* encrypt ctr => buf */
- AES_encrypt(ctr, buf, &exkey);
/* read in one block of input data => in */
aes_read_block(env, mmu_idx, *src_ptr_reg + done, in, ra);
- /* exor input data with encrypted ctr => out */
- aes_xor(in, buf, out);
+ /* encrypt ctr and xor with in => out */
+ AES_ctr_encrypt(in, out, ctr, &exkey);
/* write out the processed block */
aes_write_block(env, mmu_idx, *dst_ptr_reg + done, out, ra);
len -= AES_BLOCK_SIZE, done += AES_BLOCK_SIZE;
@@ -361,28 +343,13 @@ int cpacf_aes_pcc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
return 0;
}
-static void aes_xts_prep_next_tweak(uint8_t tweak[AES_BLOCK_SIZE])
-{
- uint8_t carry;
- int i;
-
- carry = tweak[AES_BLOCK_SIZE - 1] >> 7;
-
- for (i = AES_BLOCK_SIZE - 1; i > 0; i--) {
- tweak[i] = (uint8_t)((tweak[i] << 1) | (tweak[i - 1] >> 7));
- }
-
- tweak[i] = (uint8_t)(tweak[i] << 1);
- tweak[i] ^= (uint8_t)(0x87 & (uint8_t)(-(int8_t)carry));
-}
-
int cpacf_aes_xts(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint64_t param_addr, uint64_t *dst_ptr_reg,
uint64_t *src_ptr_reg, uint64_t *src_len_reg,
uint32_t type, uint8_t fc, uint8_t mod)
{
enum { MAX_BLOCKS_PER_RUN = 8192 / AES_BLOCK_SIZE };
- uint8_t buf1[AES_BLOCK_SIZE], buf2[AES_BLOCK_SIZE];
+ uint8_t in[AES_BLOCK_SIZE], out[AES_BLOCK_SIZE];
const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
uint64_t addr, len = *src_len_reg, done = 0;
uint8_t key[32], tweak[AES_BLOCK_SIZE];
@@ -433,23 +400,19 @@ int cpacf_aes_xts(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
/* process up to MAX_BLOCKS_PER_RUN aes blocks */
for (i = 0; i < MAX_BLOCKS_PER_RUN && len >= AES_BLOCK_SIZE; i++) {
- /* fetch one AES block into buf1 */
- aes_read_block(env, mmu_idx, *src_ptr_reg + done, buf1, ra);
- /* buf1 xor tweak => buf2 */
- aes_xor(buf1, tweak, buf2);
+ /* fetch one AES block into in */
+ aes_read_block(env, mmu_idx, *src_ptr_reg + done, in, ra);
if (mod) {
- /* decrypt buf2 => buf1 */
- AES_decrypt(buf2, buf1, &exkey);
+ /* decrypt in => out */
+ AES_xts_decrypt(in, out, tweak, &exkey);
} else {
- /* encrypt buf2 => buf1 */
- AES_encrypt(buf2, buf1, &exkey);
+ /* encrypt in => out */
+ AES_xts_encrypt(in, out, tweak, &exkey);
}
- /* buf1 xor tweak => buf2 */
- aes_xor(buf1, tweak, buf2);
/* prep tweak for next round */
- aes_xts_prep_next_tweak(tweak);
- /* write out this processed block from buf2 */
- aes_write_block(env, mmu_idx, *dst_ptr_reg + done, buf2, ra);
+ AES_xts_prep_next_tweak(tweak);
+ /* write out this processed block from out */
+ aes_write_block(env, mmu_idx, *dst_ptr_reg + done, out, ra);
len -= AES_BLOCK_SIZE, done += AES_BLOCK_SIZE;
}
@@ -627,7 +590,7 @@ int cpacf_paes_cbc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint32_t type, uint8_t fc, uint8_t mod)
{
enum { MAX_BLOCKS_PER_RUN = 8192 / AES_BLOCK_SIZE };
- uint8_t in[AES_BLOCK_SIZE], out[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
+ uint8_t in[AES_BLOCK_SIZE], out[AES_BLOCK_SIZE];
const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
uint8_t key[32], wkvp[32], iv[AES_BLOCK_SIZE];
uint64_t addr, len = *src_len_reg, done = 0;
@@ -697,19 +660,11 @@ int cpacf_paes_cbc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
for (i = 0; i < MAX_BLOCKS_PER_RUN && len >= AES_BLOCK_SIZE; i++) {
aes_read_block(env, mmu_idx, *src_ptr_reg + done, in, ra);
if (mod) {
- /* decrypt in => buf */
- AES_decrypt(in, buf, &exkey);
- /* buf xor iv => out */
- aes_xor(buf, iv, out);
- /* prep iv for next round */
- memcpy(iv, in, AES_BLOCK_SIZE);
+ /* decrypt in => out */
+ AES_cbc_decrypt(in, out, iv, &exkey);
} else {
- /* in xor iv => buf */
- aes_xor(in, iv, buf);
- /* encrypt buf => out */
- AES_encrypt(buf, out, &exkey);
- /* prep iv for next round */
- memcpy(iv, out, AES_BLOCK_SIZE);
+ /* encrypt in => out */
+ AES_cbc_encrypt(in, out, iv, &exkey);
}
aes_write_block(env, mmu_idx, *dst_ptr_reg + done, out, ra);
len -= AES_BLOCK_SIZE, done += AES_BLOCK_SIZE;
@@ -738,11 +693,10 @@ int cpacf_paes_ctr(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
{
enum { MAX_BLOCKS_PER_RUN = 8192 / AES_BLOCK_SIZE };
const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
- uint8_t ctr[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
uint8_t in[AES_BLOCK_SIZE], out[AES_BLOCK_SIZE];
+ uint8_t ctr[AES_BLOCK_SIZE], key[32], wkvp[32];
uint64_t addr, len = *src_len_reg, done = 0;
int i, keysize, addr_reg_size = 64;
- uint8_t key[32], wkvp[32];
AES_KEY exkey;
g_assert(type == S390_FEAT_TYPE_KMCTR);
@@ -798,12 +752,10 @@ int cpacf_paes_ctr(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
for (i = 0; i < MAX_BLOCKS_PER_RUN && len >= AES_BLOCK_SIZE; i++) {
/* read in nonce/ctr => ctr */
aes_read_block(env, mmu_idx, *ctr_ptr_reg + done, ctr, ra);
- /* encrypt ctr => buf */
- AES_encrypt(ctr, buf, &exkey);
/* read in one block of input data => in */
aes_read_block(env, mmu_idx, *src_ptr_reg + done, in, ra);
- /* exor input data with encrypted ctr => out */
- aes_xor(in, buf, out);
+ /* encrypt ctr and xor with in => out */
+ AES_ctr_encrypt(in, out, ctr, &exkey);
/* write out the processed block */
aes_write_block(env, mmu_idx, *dst_ptr_reg + done, out, ra);
len -= AES_BLOCK_SIZE, done += AES_BLOCK_SIZE;
@@ -906,7 +858,7 @@ int cpacf_paes_xts(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint32_t type, uint8_t fc, uint8_t mod)
{
enum { MAX_BLOCKS_PER_RUN = 8192 / AES_BLOCK_SIZE };
- uint8_t buf1[AES_BLOCK_SIZE], buf2[AES_BLOCK_SIZE];
+ uint8_t in[AES_BLOCK_SIZE], out[AES_BLOCK_SIZE];
const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
uint8_t key[32], wkvp[32], tweak[AES_BLOCK_SIZE];
uint64_t addr, len = *src_len_reg, done = 0;
@@ -971,23 +923,19 @@ int cpacf_paes_xts(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
/* process up to MAX_BLOCKS_PER_RUN aes blocks */
for (i = 0; i < MAX_BLOCKS_PER_RUN && len >= AES_BLOCK_SIZE; i++) {
- /* fetch one AES block into buf1 */
- aes_read_block(env, mmu_idx, *src_ptr_reg + done, buf1, ra);
- /* buf1 xor tweak => buf2 */
- aes_xor(buf1, tweak, buf2);
+ /* fetch one AES block into in */
+ aes_read_block(env, mmu_idx, *src_ptr_reg + done, in, ra);
if (mod) {
- /* decrypt buf2 => buf1 */
- AES_decrypt(buf2, buf1, &exkey);
+ /* decrypt in => out */
+ AES_xts_decrypt(in, out, tweak, &exkey);
} else {
- /* encrypt buf2 => buf1 */
- AES_encrypt(buf2, buf1, &exkey);
+ /* encrypt in => out */
+ AES_xts_encrypt(in, out, tweak, &exkey);
}
- /* buf1 xor tweak => buf2 */
- aes_xor(buf1, tweak, buf2);
/* prep tweak for next round */
- aes_xts_prep_next_tweak(tweak);
- /* write out this processed block from buf2 */
- aes_write_block(env, mmu_idx, *dst_ptr_reg + done, buf2, ra);
+ AES_xts_prep_next_tweak(tweak);
+ /* write out this processed block from out */
+ aes_write_block(env, mmu_idx, *dst_ptr_reg + done, out, ra);
len -= AES_BLOCK_SIZE, done += AES_BLOCK_SIZE;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [PATCH v7 02/17] target/s390x: Move cpacf sha512 code into a new file
2026-06-17 9:48 ` [PATCH v7 02/17] target/s390x: Move cpacf sha512 code into a new file Harald Freudenberger
@ 2026-06-18 4:54 ` Finn Callies
0 siblings, 0 replies; 41+ messages in thread
From: Finn Callies @ 2026-06-18 4:54 UTC (permalink / raw)
To: Harald Freudenberger, richard.henderson, iii, david, thuth,
berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, cohuck
On 17.06.26 11:48, Harald Freudenberger wrote:
> Move the cpacf sha512 implementation into a new file
> cpacf_sha512.c. Add this new file to the build and add a
> new header file cpacf.h containing the prototypes for the
> s390 cpacf stuff.
>
> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
> Tested-by: Holger Dengler <dengler@linux.ibm.com>
With the one typo (see below) fixed:
Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
> ---
> target/s390x/tcg/cpacf.h | 16 ++
> target/s390x/tcg/cpacf_sha512.c | 245 +++++++++++++++++++++++++++++++
> target/s390x/tcg/crypto_helper.c | 227 +---------------------------
> target/s390x/tcg/meson.build | 1 +
> 4 files changed, 263 insertions(+), 226 deletions(-)
> create mode 100644 target/s390x/tcg/cpacf.h
> create mode 100644 target/s390x/tcg/cpacf_sha512.c
>
> diff --git a/target/s390x/tcg/cpacf.h b/target/s390x/tcg/cpacf.h
> new file mode 100644
> index 0000000000..d27839ddd9
> --- /dev/null
> +++ b/target/s390x/tcg/cpacf.h
> @@ -0,0 +1,16 @@
> +/*
> + * s390x cpacf
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#ifndef S390X_CPACF_H
> +#define S390X_CPACF_H
> +
> +/* from crypto_sha512.c */
It should be cpacf_sha512.c in the comment instead of crypto_sha512.c
> +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);
> +
[ snip ]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 03/17] target/s390x: Support cpacf sha256
2026-06-17 9:48 ` [PATCH v7 03/17] target/s390x: Support cpacf sha256 Harald Freudenberger
@ 2026-06-18 5:18 ` Finn Callies
0 siblings, 0 replies; 41+ messages in thread
From: Finn Callies @ 2026-06-18 5:18 UTC (permalink / raw)
To: Harald Freudenberger, richard.henderson, iii, david, thuth,
berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, cohuck
On 17.06.26 11:48, Harald Freudenberger wrote:
> Add a new file cpacf_sha256.c which implements sha256.
> Add support for the sha256 subfuction for CPACF kimd and klmd.
>
> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
> Tested-by: Holger Dengler <dengler@linux.ibm.com>
With the one typo (see below) fixed:
Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
> ---
> target/s390x/gen-features.c | 2 +
> target/s390x/tcg/cpacf.h | 5 +
> target/s390x/tcg/cpacf_sha256.c | 232 +++++++++++++++++++++++++++++++
> target/s390x/tcg/crypto_helper.c | 8 ++
> target/s390x/tcg/meson.build | 1 +
> 5 files changed, 248 insertions(+)
> create mode 100644 target/s390x/tcg/cpacf_sha256.c
>
> diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
> index 8218e6470e..5cf5b92c37 100644
> --- a/target/s390x/gen-features.c
> +++ b/target/s390x/gen-features.c
> @@ -916,7 +916,9 @@ static uint16_t qemu_V7_1[] = {
> */
> static uint16_t qemu_MAX[] = {
> S390_FEAT_MSA_EXT_5,
> + S390_FEAT_KIMD_SHA_256,
> S390_FEAT_KIMD_SHA_512,
> + S390_FEAT_KLMD_SHA_256,
> S390_FEAT_KLMD_SHA_512,
> S390_FEAT_PRNO_TRNG,
> };
> diff --git a/target/s390x/tcg/cpacf.h b/target/s390x/tcg/cpacf.h
> index d27839ddd9..e2c36306b2 100644
> --- a/target/s390x/tcg/cpacf.h
> +++ b/target/s390x/tcg/cpacf.h
> @@ -8,6 +8,11 @@
> #ifndef S390X_CPACF_H
> #define S390X_CPACF_H
>
> +/* from crypto_sha256.c */
The comment should be cpacf_sha256.c instead of crypto_sha256.c
> +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);
> +
[ snip ]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 04/17] target/s390x: Support AES ECB for cpacf km instruction
2026-06-17 9:48 ` [PATCH v7 04/17] target/s390x: Support AES ECB for cpacf km instruction Harald Freudenberger
@ 2026-06-18 5:22 ` Finn Callies
0 siblings, 0 replies; 41+ messages in thread
From: Finn Callies @ 2026-06-18 5:22 UTC (permalink / raw)
To: Harald Freudenberger, richard.henderson, iii, david, thuth,
berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, cohuck
On 17.06.26 11:48, Harald Freudenberger wrote:
> Support the subfunctions CPACF_KM_AES_128, CPACF_KM_AES_192
> and CPACF_KM_AES_256 for the cpacf km instruction.
>
> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
> Tested-by: Holger Dengler <dengler@linux.ibm.com>
With the one typo (see below) fixed:
Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
> ---
> target/s390x/gen-features.c | 3 +
> target/s390x/tcg/cpacf.h | 6 ++
> target/s390x/tcg/cpacf_aes.c | 113 +++++++++++++++++++++++++++++++
> target/s390x/tcg/crypto_helper.c | 24 +++++++
> target/s390x/tcg/meson.build | 1 +
> 5 files changed, 147 insertions(+)
> create mode 100644 target/s390x/tcg/cpacf_aes.c
>
> diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
> index 5cf5b92c37..a35d1fd2f9 100644
> --- a/target/s390x/gen-features.c
> +++ b/target/s390x/gen-features.c
> @@ -921,6 +921,9 @@ static uint16_t qemu_MAX[] = {
> S390_FEAT_KLMD_SHA_256,
> S390_FEAT_KLMD_SHA_512,
> S390_FEAT_PRNO_TRNG,
> + S390_FEAT_KM_AES_128,
> + S390_FEAT_KM_AES_192,
> + S390_FEAT_KM_AES_256,
> };
>
> /****** END FEATURE DEFS ******/
> diff --git a/target/s390x/tcg/cpacf.h b/target/s390x/tcg/cpacf.h
> index e2c36306b2..36d0c81893 100644
> --- a/target/s390x/tcg/cpacf.h
> +++ b/target/s390x/tcg/cpacf.h
> @@ -18,4 +18,10 @@ 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);
>
> +/* from crypto_aes.c */
Should be cpacf_aes.c instead of crypto_aes.c
> +int cpacf_aes_ecb(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
> + uint64_t param_addr, uint64_t *dst_ptr_reg,
> + uint64_t *src_ptr_reg, uint64_t *src_len_reg,
> + uint32_t type, uint8_t fc, uint8_t mod);
> +
[ snip ]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 05/17] target/s390x: Support AES CBC for cpacf kmc instruction
2026-06-17 9:48 ` [PATCH v7 05/17] target/s390x: Support AES CBC for cpacf kmc instruction Harald Freudenberger
@ 2026-06-18 5:27 ` Finn Callies
0 siblings, 0 replies; 41+ messages in thread
From: Finn Callies @ 2026-06-18 5:27 UTC (permalink / raw)
To: Harald Freudenberger, richard.henderson, iii, david, thuth,
berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, cohuck
On 17.06.26 11:48, Harald Freudenberger wrote:
> Support the subfunctions CPACF_KMC_AES_128, CPACF_KMC_AES_192
> and CPACF_KMC_AES_256 for the cpacf kmc instruction.
>
> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
> Tested-by: Holger Dengler <dengler@linux.ibm.com>
Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
> ---
> target/s390x/gen-features.c | 3 +
> target/s390x/tcg/cpacf.h | 4 ++
> target/s390x/tcg/cpacf_aes.c | 102 +++++++++++++++++++++++++++++++
> target/s390x/tcg/crypto_helper.c | 24 ++++++++
> 4 files changed, 133 insertions(+)
[ snip ]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 06/17] target/s390x: Support AES CTR for cpacf kmctr instruction
2026-06-17 9:48 ` [PATCH v7 06/17] target/s390x: Support AES CTR for cpacf kmctr instruction Harald Freudenberger
@ 2026-06-18 5:31 ` Finn Callies
0 siblings, 0 replies; 41+ messages in thread
From: Finn Callies @ 2026-06-18 5:31 UTC (permalink / raw)
To: Harald Freudenberger, richard.henderson, iii, david, thuth,
berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, cohuck
On 17.06.26 11:48, Harald Freudenberger wrote:
> Support the subfunctions CPACF_KMCTR_AES_128, CPACF_KMCTR_AES_192
> and CPACF_KMCTR_AES_256 for the cpacf kmctr instruction.
>
> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
With the one typo fixed:
Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
> ---
> target/s390x/gen-features.c | 3 ++
> target/s390x/tcg/cpacf.h | 5 +++
> target/s390x/tcg/cpacf_aes.c | 76 ++++++++++++++++++++++++++++++++
> target/s390x/tcg/crypto_helper.c | 24 ++++++++++
> 4 files changed, 108 insertions(+)
[ snip ]
> diff --git a/target/s390x/tcg/cpacf_aes.c b/target/s390x/tcg/cpacf_aes.c
> index 6412cc187d..e200a9a87a 100644
> --- a/target/s390x/tcg/cpacf_aes.c
> +++ b/target/s390x/tcg/cpacf_aes.c
> @@ -213,3 +213,79 @@ int cpacf_aes_cbc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
[ snip ]
> + /* process up to MAX_BLOCKS_PER_RUN aes blocks */
> + for (i = 0; i < MAX_BLOCKS_PER_RUN && len >= AES_BLOCK_SIZE; i++) {
> + /* read in nonce/ctr => ctr */
> + aes_read_block(env, mmu_idx, *ctr_ptr_reg + done, ctr, ra);
> + /* encrypt ctr => buf */
> + AES_encrypt(ctr, buf, &exkey);
> + /* read in one block of input data => in */
> + aes_read_block(env, mmu_idx, *src_ptr_reg + done, in, ra);
> + /* exor input data with encrypted ctr => out */
typo: exor -> xor
> + aes_xor(in, buf, out);
> + /* write out the processed block */
> + aes_write_block(env, mmu_idx, *dst_ptr_reg + done, out, ra);
> + len -= AES_BLOCK_SIZE, done += AES_BLOCK_SIZE;
> + }
[ snip ]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 07/17] target/s390x: Minimal AES XTS support for cpacf pcc instruction
2026-06-17 9:48 ` [PATCH v7 07/17] target/s390x: Minimal AES XTS support for cpacf pcc instruction Harald Freudenberger
@ 2026-06-18 5:35 ` Finn Callies
0 siblings, 0 replies; 41+ messages in thread
From: Finn Callies @ 2026-06-18 5:35 UTC (permalink / raw)
To: Harald Freudenberger, richard.henderson, iii, david, thuth,
berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, cohuck
On 17.06.26 11:48, Harald Freudenberger wrote:
> Support CPACF pcc subfunctions PCC-Compute-XTS-Parameter-AES-128
> and PCC-Compute-XTS-Parameter-AES-128 but only for the special
> case block sequential number is 0. However, this covers the s390
> AES XTS implementation in the Linux kernel and Libica and thus
> also Opencryptoki clear key via Libica.
>
> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
> Tested-by: Holger Dengler <dengler@linux.ibm.com>
> ---
> target/s390x/gen-features.c | 2 +
> target/s390x/tcg/cpacf.h | 2 +
> target/s390x/tcg/cpacf_aes.c | 71 ++++++++++++++++++++++++++++++++
> target/s390x/tcg/crypto_helper.c | 20 +++++++++
> 4 files changed, 95 insertions(+)
[ snip ]
> diff --git a/target/s390x/tcg/cpacf_aes.c b/target/s390x/tcg/cpacf_aes.c
> index e200a9a87a..43c556f31b 100644
> --- a/target/s390x/tcg/cpacf_aes.c
> +++ b/target/s390x/tcg/cpacf_aes.c
> @@ -16,6 +16,13 @@
> #include "crypto/aes.h"
> #include "cpacf.h"
>
> +/* #define DEBUG_HELPER */
> +#ifdef DEBUG_HELPER
> +#define HELPER_LOG(x...) qemu_log(x)
> +#else
> +#define HELPER_LOG(x...)
> +#endif
> +
You never use this... Seems to be unrelated to this commit so put this
in its own commit if you need it later.
> static void aes_read_block(CPUS390XState *env, const int mmu_idx,
> uint64_t addr, uint8_t *a, uintptr_t ra)
> {
[ snip ]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 00/17] target/s390x: Extend qemu CPACF support
2026-06-17 9:48 [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Harald Freudenberger
` (16 preceding siblings ...)
2026-06-17 9:48 ` [PATCH v7 17/17] target/s390x: Use generic AES helper functions Harald Freudenberger
@ 2026-06-18 5:37 ` Finn Callies
17 siblings, 0 replies; 41+ messages in thread
From: Finn Callies @ 2026-06-18 5:37 UTC (permalink / raw)
To: Harald Freudenberger, richard.henderson, iii, david, thuth,
berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, cohuck
On 17.06.26 11:48, Harald Freudenberger wrote:
> This patch series extends the s390 qemu CPACF support to be able to
> run a subset of the CPACF instruction cross platform. There have been
> requests on the kernel crypto mailing list about a way to test
> s390 specific crypto implementations. For example a way to test
> s390 CPACF exploitation code like the s390_aes.ko kernel module.
>
> So here now is a set of patches verified on x86 and s390 which
> over (slow but working) support for a subset of the subfunctions of
> some of the CPACF instructions.
>
> Test: As this series is more or less complete, a full blown linux
> can be run and the 'usual' in-kernel crpyto modules will be
> automatically loaded which run a bunch of test cases. So there
> is now support for these kernel modules:
> * sha256_s390x (autoloaded, sha256)
> * sha512_s390x (autoloaded, sha512)
> * aes_s390x (autoloaded, clear key aes ecb, cbc, ctr, xts)
> * pkey_pckmo (autoloaded, derive AES protected key from clear key)
> * paes_s390x (not autoloaded, protected key aes ecb, cbc, ctr, xts)
> All these modules run selftests if configured by the kernel (which is
> enabled by default). Failures are reported via syslog. Additionally
> the aes testcases from libica can be run either inside such an qemu
> environment or with a static build executed with the qemu tcg
> application qemu-s390x --cpu max <static-build-libica-test>.
>
> Changelog:
> v1: Initial version with
> - Related code restructured
> - Support KIMD SHA512 and thus SHA256
> - Support KMC AES-128, AES-192 and AES-256 and thus have basic AES
> support (ECB mode) enabled.
> - Support PCC Compute-XTS-Parameter-AES-128 and
> Compute-XTS-Parameter-AES-256 but only for block sequence number
> 0. This is a requirement for the next step:
> - Support KM XTS-AES-128 and KM XTS-AES-256. Together with the
> minimal PCC support this enables AES-XTS CPACF acceleration.
> v2: - Basic PCKMO support to be able to 'derive' an AES protected key
> from clear key. See header details.
> - Support protected key AES-ECB.
> - Support protected key AES-CBC.
> - Minimal protected key AES-XTS support for CPACF PCC.
> - Support protected key AES-XTS.
> - Support AES-CTR.
> - Support protected key AES-CTR.
> v3: - Reordered patches as suggested by Finn.
> - One small bug fix in CPACF_aes.c related to address translation.
> v4: - Rename of the parameters based on feedback from Janosch to
> make clear these are registers or ptrs to registers.
> Added Tested by from Holger. Fixed typo "face" -> "fake".
> v5: - Add documentation file docs/system/s390x/cpacf.rst which
> describes the state of the CPACF instructions and which
> functions are covered when this series is applied.
> First version sent to public mailing list qemu-s390x.
> v6: - Rebase/rework to build on current qemu head.
> - Add docs/system/s390x/cpacf.rst to target-s390x.rst
> - New file crypto/aes-helpers.c with some simple
> functions to support AES modes CBC, CTR and XTS.
> - Slight rewrite of the s390x CPACF implementations to
> use these generic AES mode implementations.
> v7: - Update on docs/system/s390x/cpacf.rst to mention
> the zArchicteture Principles of Operation document
> which describes all these CPAC instructions.
>
> Harald Freudenberger (17):
> target/s390x: Rework s390 cpacf implementations
> target/s390x: Move cpacf sha512 code into a new file
> target/s390x: Support cpacf sha256
> target/s390x: Support AES ECB for cpacf km instruction
> target/s390x: Support AES CBC for cpacf kmc instruction
> target/s390x: Support AES CTR for cpacf kmctr instruction
> target/s390x: Minimal AES XTS support for cpacf pcc instruction
> target/s390x: Support AES XTS for cpacf km instruction
> target/s390x: Support pckmo encrypt AES subfunctions
> target/s390x: Support protected key AES ECB for cpacf km instruction
> target/s390x: Support protected key AES CBC for cpacf kmc instruction
> target/s390x: Support protected key AES CTR for cpacf kmctr
> instruction
> target/s390x: Minimal protected key AES XTS support for cpacf pcc
> instruction
> target/s390x: Support protected key AES XTS for cpacf km instruction
> docs/s390: Document CPACF instructions support
> crypto: Add aes-helpers file to support some AES modes
> target/s390x: Use generic AES helper functions
>
> crypto/aes-helpers.c | 101 ++++
> crypto/meson.build | 1 +
> docs/system/s390x/cpacf.rst | 116 ++++
> docs/system/target-s390x.rst | 1 +
> include/crypto/aes.h | 14 +
> target/s390x/gen-features.c | 31 +
> target/s390x/tcg/cpacf.h | 63 ++
> target/s390x/tcg/cpacf_aes.c | 955 +++++++++++++++++++++++++++++++
> target/s390x/tcg/cpacf_sha256.c | 232 ++++++++
> target/s390x/tcg/cpacf_sha512.c | 245 ++++++++
Since you implemented all aes related stuff into cpacf_aes.c maybe think
about putting all sha related stuff into cpacf_sha.c instead of singular
files. Or go the singular way with the aes stuff as well.
> target/s390x/tcg/crypto_helper.c | 423 +++++++-------
> target/s390x/tcg/insn-data.h.inc | 1 +
> target/s390x/tcg/meson.build | 3 +
> target/s390x/tcg/translate.c | 2 +
> 14 files changed, 1972 insertions(+), 216 deletions(-)
> create mode 100644 crypto/aes-helpers.c
> create mode 100644 docs/system/s390x/cpacf.rst
> create mode 100644 target/s390x/tcg/cpacf.h
> create mode 100644 target/s390x/tcg/cpacf_aes.c
> create mode 100644 target/s390x/tcg/cpacf_sha256.c
> create mode 100644 target/s390x/tcg/cpacf_sha512.c
>
>
> base-commit: e89049b3ba5f1f0468bc0d294173345597514a1b
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 08/17] target/s390x: Support AES XTS for cpacf km instruction
2026-06-17 9:48 ` [PATCH v7 08/17] target/s390x: Support AES XTS for cpacf km instruction Harald Freudenberger
@ 2026-06-18 5:45 ` Finn Callies
2026-06-22 14:25 ` Harald Freudenberger
0 siblings, 1 reply; 41+ messages in thread
From: Finn Callies @ 2026-06-18 5:45 UTC (permalink / raw)
To: Harald Freudenberger, richard.henderson, iii, david, thuth,
berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, cohuck
On 17.06.26 11:48, Harald Freudenberger wrote:
> Support the subfunctions XTS-AES-128 and XTS-AES-256
> for the cpacf km instruction.
>
> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
> Tested-by: Holger Dengler <dengler@linux.ibm.com>
> ---
> target/s390x/gen-features.c | 2 +
> target/s390x/tcg/cpacf.h | 4 ++
> target/s390x/tcg/cpacf_aes.c | 107 +++++++++++++++++++++++++++++++
> target/s390x/tcg/crypto_helper.c | 6 ++
> 4 files changed, 119 insertions(+)
[ snip ]
> +
> + /* process up to MAX_BLOCKS_PER_RUN aes blocks */
> + for (i = 0; i < MAX_BLOCKS_PER_RUN && len >= AES_BLOCK_SIZE; i++) {
I guess this has the same "feature" as the real xts where the pcc part
is not included if not explicitly done beforehand by the user right? But
since CPACF does it that way I guess you can't do it the "correct" way.
Instead of XTS + PCC you could implement Full XTS... just something to
think about.
> + /* fetch one AES block into buf1 */
> + aes_read_block(env, mmu_idx, *src_ptr_reg + done, buf1, ra);
> + /* buf1 xor tweak => buf2 */
[ snip ]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 09/17] target/s390x: Support pckmo encrypt AES subfunctions
2026-06-17 9:48 ` [PATCH v7 09/17] target/s390x: Support pckmo encrypt AES subfunctions Harald Freudenberger
@ 2026-06-18 5:50 ` Finn Callies
2026-06-22 14:34 ` Harald Freudenberger
0 siblings, 1 reply; 41+ messages in thread
From: Finn Callies @ 2026-06-18 5:50 UTC (permalink / raw)
To: Harald Freudenberger, richard.henderson, iii, david, thuth,
berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, cohuck
On 17.06.26 11:48, Harald Freudenberger wrote:
> Support the subfuctions PCKMO-Encrypt-AES-128-Key,
> PCKMO-Encrypt-AES-192-Key and PCKMO-Encrypt-AES-256-Key.
>
> These subfunctions derive a protected key from an AES clear key
> by encrypting it with an internal AES wrapping key. More
> details can be found in the "z/Architecture Prinziples of
> Operation" document.
>
> The qemu version provided here is only a fake indented to make
typo: indeted -> intended
> protected key available for developing and testing purpose:
> * The protected key is 'derived' from the clear key by xoring
> the fixed pattern 0xAAAA... onto the key value.
> * The AES Wrapping Key Verification Pattern is a fixed
> value of 32 bytes 0xFACEFACE...
>
> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
> Tested-by: Holger Dengler <dengler@linux.ibm.com>
With the typo fixed and the other comments at least considered:
Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
> ---
> target/s390x/gen-features.c | 3 ++
> target/s390x/tcg/cpacf.h | 2 +
> target/s390x/tcg/cpacf_aes.c | 66 ++++++++++++++++++++++++++++++++
> target/s390x/tcg/crypto_helper.c | 21 ++++++++++
> 4 files changed, 92 insertions(+)
[ snip ]
> diff --git a/target/s390x/tcg/cpacf_aes.c b/target/s390x/tcg/cpacf_aes.c
> index 0312436c43..5a0a3473d5 100644
> --- a/target/s390x/tcg/cpacf_aes.c
> +++ b/target/s390x/tcg/cpacf_aes.c
> @@ -467,3 +467,69 @@ int cpacf_aes_xts(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
>
> return !len ? 0 : 3;
> }
> +
> +/*
> + * Hard coded pattern xored with the AES clear key
> + * to 'produce' the protected key.
> + */
> +static const uint8_t protkey_xor_pattern[32] = {
the wrapping key for protected keys is called virtual server master key
if I recall correctly. Maybe name this accordingly or at least something
with master or wrapping key in it as this describes the purpose better I
think.
> + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
> + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
> + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
> + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA };
> +
> +/*
> + * Hard coded wkvp ("Wrapping Key Verification Pattern")
> + */
> +static const uint8_t protkey_wkvp[32] = {
Since you call this protkey_wkvp you could call the wrapping key protkey_wk.
> + 0x0F, 0x0A, 0x0C, 0x0E, 0x0F, 0x0A, 0x0C, 0x0E,
> + 0x0F, 0x0A, 0x0C, 0x0E, 0x0F, 0x0A, 0x0C, 0x0E,
> + 0x0F, 0x0A, 0x0C, 0x0E, 0x0F, 0x0A, 0x0C, 0x0E,
> + 0x0F, 0x0A, 0x0C, 0x0E, 0x0F, 0x0A, 0x0C, 0x0E };
[ snip ]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 10/17] target/s390x: Support protected key AES ECB for cpacf km instruction
2026-06-17 9:48 ` [PATCH v7 10/17] target/s390x: Support protected key AES ECB for cpacf km instruction Harald Freudenberger
@ 2026-06-18 5:57 ` Finn Callies
2026-06-22 15:05 ` Harald Freudenberger
2026-06-18 6:05 ` Finn Callies
1 sibling, 1 reply; 41+ messages in thread
From: Finn Callies @ 2026-06-18 5:57 UTC (permalink / raw)
To: Harald Freudenberger, richard.henderson, iii, david, thuth,
berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, cohuck
On 17.06.26 11:48, Harald Freudenberger wrote:
> Support the subfunctions CPACF_KM_PAES_128, CPACF_KM_PAES_192
> and CPACF_KM_PAES_256 for the cpacf km instruction.
>
> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
> Tested-by: Holger Dengler <dengler@linux.ibm.com>
With the comments at least considered:
Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
> ---
> target/s390x/gen-features.c | 3 ++
> target/s390x/tcg/cpacf.h | 4 ++
> target/s390x/tcg/cpacf_aes.c | 87 ++++++++++++++++++++++++++++++++
> target/s390x/tcg/crypto_helper.c | 7 +++
> 4 files changed, 101 insertions(+)
>
> diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
> index d3e69aaca6..71e0e41d6e 100644
> --- a/target/s390x/gen-features.c
> +++ b/target/s390x/gen-features.c
> @@ -924,6 +924,9 @@ static uint16_t qemu_MAX[] = {
> S390_FEAT_KM_AES_128,
> S390_FEAT_KM_AES_192,
> S390_FEAT_KM_AES_256,
> + S390_FEAT_KM_EAES_128,
> + S390_FEAT_KM_EAES_192,
> + S390_FEAT_KM_EAES_256,
I would strongly prefer PAES instead of EAES. I know the CPACF function
is called KM...ENCRYPTED...AES... but since we use protected or PAES in
any other context and never Encrypted AES I would highly suggest PAES
here as well. Or as an alternative expand the E to
S390_FEAT_KM_ENCRYPTED_AES_128 to match the CPACF naming.
> S390_FEAT_KM_XTS_AES_128,
> S390_FEAT_KM_XTS_AES_256,
> S390_FEAT_KMC_AES_128,
[ snip ]
> diff --git a/target/s390x/tcg/cpacf_aes.c b/target/s390x/tcg/cpacf_aes.c
> index 5a0a3473d5..bcfcf3b660 100644
> --- a/target/s390x/tcg/cpacf_aes.c
> +++ b/target/s390x/tcg/cpacf_aes.c
> @@ -533,3 +533,90 @@ int cpacf_aes_pckmo(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
>
> return 0;
> }
> +
> +int cpacf_paes_ecb(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
> + uint64_t param_addr, uint64_t *dst_ptr_reg,
> + uint64_t *src_ptr_reg, uint64_t *src_len_reg,
> + uint32_t type, uint8_t fc, uint8_t mod)
> +{
[ snip ]
> +
> + /* fetch protected key from param block */
> + for (i = 0; i < keysize; i++) {
> + addr = wrap_address(env, param_addr + i);
> + key[i] = cpu_ldb_mmu(env, addr, oi, ra);
> + }
> + /* 'decrypt' the protected key */
> + for (i = 0; i < keysize; i++) {
> + key[i] ^= protkey_xor_pattern[i];
> + }
Think about outsourcing this into a function as it would improve
readability and reduce code dublication in future commits.
> +
> + /* expand key */
> + if (mod) {
> + AES_set_decrypt_key(key, keysize * 8, &exkey);
> + } else {
> + AES_set_encrypt_key(key, keysize * 8, &exkey);
> + }
[ snip ]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 10/17] target/s390x: Support protected key AES ECB for cpacf km instruction
2026-06-17 9:48 ` [PATCH v7 10/17] target/s390x: Support protected key AES ECB for cpacf km instruction Harald Freudenberger
2026-06-18 5:57 ` Finn Callies
@ 2026-06-18 6:05 ` Finn Callies
1 sibling, 0 replies; 41+ messages in thread
From: Finn Callies @ 2026-06-18 6:05 UTC (permalink / raw)
To: Harald Freudenberger, richard.henderson, iii, david, thuth,
berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, cohuck
On 17.06.26 11:48, Harald Freudenberger wrote:
> Support the subfunctions CPACF_KM_PAES_128, CPACF_KM_PAES_192
> and CPACF_KM_PAES_256 for the cpacf km instruction.
>
> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
> Tested-by: Holger Dengler <dengler@linux.ibm.com>
> ---
> target/s390x/gen-features.c | 3 ++
> target/s390x/tcg/cpacf.h | 4 ++
> target/s390x/tcg/cpacf_aes.c | 87 ++++++++++++++++++++++++++++++++
> target/s390x/tcg/crypto_helper.c | 7 +++
> 4 files changed, 101 insertions(+)
[ snip ]
> diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c
> index e1952ae4bc..988226338d 100644
> --- a/target/s390x/tcg/crypto_helper.c
> +++ b/target/s390x/tcg/crypto_helper.c
> @@ -103,6 +103,13 @@ static int cpacf_km(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
> &env->regs[r1], &env->regs[r2], &env->regs[r2 + 1],
> S390_FEAT_TYPE_KM, fc, mod);
> break;
> + case 0x1a: /* CPACF_KM_PAES_128 */
> + case 0x1b: /* CPACF_KM_PAES_192 */
> + case 0x1c: /* CPACF_KM_PAES_256 */
please order these correctly in the switch. For the switch statement it
doesn't matter but it improves readability. 0x1a is greater than 0x34.
> + rc = cpacf_paes_ecb(env, mmu_idx, ra, env->regs[1],
> + &env->regs[r1], &env->regs[r2], &env->regs[r2 + 1],
> + S390_FEAT_TYPE_KM, fc, mod);
> + break;
> case 0x32: /* CPACF_KM_XTS_128 */
> case 0x34: /* CPACF_KM_XTS_256 */
> rc = cpacf_aes_xts(env, mmu_idx, ra, env->regs[1],
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 11/17] target/s390x: Support protected key AES CBC for cpacf kmc instruction
2026-06-17 9:48 ` [PATCH v7 11/17] target/s390x: Support protected key AES CBC for cpacf kmc instruction Harald Freudenberger
@ 2026-06-18 6:08 ` Finn Callies
0 siblings, 0 replies; 41+ messages in thread
From: Finn Callies @ 2026-06-18 6:08 UTC (permalink / raw)
To: Harald Freudenberger, richard.henderson, iii, david, thuth,
berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, cohuck
On 17.06.26 11:48, Harald Freudenberger wrote:
> Support the subfunctions CPACF_KMC_PAES_128, CPACF_KMC_PAES_192
> and CPACF_KMC_PAES_256 for the cpacf kmc instruction.
>
> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
> Tested-by: Holger Dengler <dengler@linux.ibm.com>
With the suggested changes:
Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
> ---
> target/s390x/gen-features.c | 3 +
> target/s390x/tcg/cpacf.h | 4 ++
> target/s390x/tcg/cpacf_aes.c | 109 +++++++++++++++++++++++++++++++
> target/s390x/tcg/crypto_helper.c | 7 ++
> 4 files changed, 123 insertions(+)
>
> diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
> index 71e0e41d6e..074c53aecd 100644
> --- a/target/s390x/gen-features.c
> +++ b/target/s390x/gen-features.c
> @@ -932,6 +932,9 @@ static uint16_t qemu_MAX[] = {
> S390_FEAT_KMC_AES_128,
> S390_FEAT_KMC_AES_192,
> S390_FEAT_KMC_AES_256,
> + S390_FEAT_KMC_EAES_128,
> + S390_FEAT_KMC_EAES_192,
> + S390_FEAT_KMC_EAES_256,
Again, either EAES -> PAES or EAES -> ENCRYPTED_AES
> S390_FEAT_KMCTR_AES_128,
> S390_FEAT_KMCTR_AES_192,
> S390_FEAT_KMCTR_AES_256,
[ snip ]
> diff --git a/target/s390x/tcg/cpacf_aes.c b/target/s390x/tcg/cpacf_aes.c
> index bcfcf3b660..a6487261e1 100644
> --- a/target/s390x/tcg/cpacf_aes.c
> +++ b/target/s390x/tcg/cpacf_aes.c
> @@ -620,3 +620,112 @@ int cpacf_paes_ecb(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
>
> return !len ? 0 : 3;
> }
> +
> +int cpacf_paes_cbc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
> + uint64_t param_addr, uint64_t *dst_ptr_reg,
> + uint64_t *src_ptr_reg, uint64_t *src_len_reg,
> + uint32_t type, uint8_t fc, uint8_t mod)
> +{
[ snip ]
> + /* fetch protected key from param block */
> + for (i = 0; i < keysize; i++) {
> + addr = wrap_address(env, param_addr + AES_BLOCK_SIZE + i);
> + key[i] = cpu_ldb_mmu(env, addr, oi, ra);
> + }
> + /* 'decrypt' the protected key */
> + for (i = 0; i < keysize; i++) {
> + key[i] ^= protkey_xor_pattern[i];
> + }
You would already benefit from the suggested outsourcing.
> +
> + /* expand key */
> + if (mod) {
> + AES_set_decrypt_key(key, keysize * 8, &exkey);
> + } else {
> + AES_set_encrypt_key(key, keysize * 8, &exkey);
> + }
[ snip ]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 12/17] target/s390x: Support protected key AES CTR for cpacf kmctr instruction
2026-06-17 9:48 ` [PATCH v7 12/17] target/s390x: Support protected key AES CTR for cpacf kmctr instruction Harald Freudenberger
@ 2026-06-18 6:10 ` Finn Callies
0 siblings, 0 replies; 41+ messages in thread
From: Finn Callies @ 2026-06-18 6:10 UTC (permalink / raw)
To: Harald Freudenberger, richard.henderson, iii, david, thuth,
berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, cohuck
On 17.06.26 11:48, Harald Freudenberger wrote:
> Support the subfunctions CPACF_KMCTR_PAES_128, CPACF_KMCTR_PAES_192
> and CPACF_KMCTR_PAES_256 for the cpacf kmctr instruction.
>
> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
> ---
> target/s390x/gen-features.c | 3 ++
> target/s390x/tcg/cpacf.h | 5 ++
> target/s390x/tcg/cpacf_aes.c | 90 ++++++++++++++++++++++++++++++++
> target/s390x/tcg/crypto_helper.c | 7 +++
> 4 files changed, 105 insertions(+)
>
> diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
> index 074c53aecd..4a131dc191 100644
> --- a/target/s390x/gen-features.c
> +++ b/target/s390x/gen-features.c
> @@ -938,6 +938,9 @@ static uint16_t qemu_MAX[] = {
> S390_FEAT_KMCTR_AES_128,
> S390_FEAT_KMCTR_AES_192,
> S390_FEAT_KMCTR_AES_256,
> + S390_FEAT_KMCTR_EAES_128,
> + S390_FEAT_KMCTR_EAES_192,
> + S390_FEAT_KMCTR_EAES_256,
EAES -> PAES or EAES -> ENCRYPTED_AES
> S390_FEAT_PCC_XTS_AES_128,
> S390_FEAT_PCC_XTS_AES_256,
> S390_FEAT_PCKMO_AES_128,
[ snip ]
> diff --git a/target/s390x/tcg/cpacf_aes.c b/target/s390x/tcg/cpacf_aes.c
> index a6487261e1..ffa286d422 100644
> --- a/target/s390x/tcg/cpacf_aes.c
> +++ b/target/s390x/tcg/cpacf_aes.c
> @@ -729,3 +729,93 @@ int cpacf_paes_cbc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
>
> return !len ? 0 : 3;
> }
> +
> +int cpacf_paes_ctr(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
> + uint64_t param_addr, uint64_t *dst_ptr_reg,
> + uint64_t *src_ptr_reg, uint64_t *src_len_reg,
> + uint64_t *ctr_ptr_reg, uint32_t type,
> + uint8_t fc, uint8_t mod)
> +{
[ snip ]
> + /* fetch protected key from param block */
> + for (i = 0; i < keysize; i++) {
> + addr = wrap_address(env, param_addr + i);
> + key[i] = cpu_ldb_mmu(env, addr, oi, ra);
> + }
> + /* 'decrypt' the protected key */
> + for (i = 0; i < keysize; i++) {
> + key[i] ^= protkey_xor_pattern[i];
Outsourcing if you see a benefit.
> + }
> +
> + /* expand key */
> + AES_set_encrypt_key(key, keysize * 8, &exkey);
[ snip ]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 13/17] target/s390x: Minimal protected key AES XTS support for cpacf pcc instruction
2026-06-17 9:48 ` [PATCH v7 13/17] target/s390x: Minimal protected key AES XTS support for cpacf pcc instruction Harald Freudenberger
@ 2026-06-18 6:18 ` Finn Callies
2026-06-18 6:21 ` Finn Callies
1 sibling, 0 replies; 41+ messages in thread
From: Finn Callies @ 2026-06-18 6:18 UTC (permalink / raw)
To: Harald Freudenberger, richard.henderson, iii, david, thuth,
berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, cohuck
On 17.06.26 11:48, Harald Freudenberger wrote:
> Support CPACF pcc subfunctions PCC-Compute-XTS-Parameter-Encrypted-AES-128
> and PCC-Compute-XTS-Parameter-Encrypted-AES-128 but only for the special
> case block sequential number is 0. However, this covers the s390 PAES XTS
> implementation in the Linux kernel.
>
> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
> Tested-by: Holger Dengler <dengler@linux.ibm.com>
With the suggestions:
Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
> ---
> target/s390x/gen-features.c | 2 +
> target/s390x/tcg/cpacf.h | 2 +
> target/s390x/tcg/cpacf_aes.c | 80 ++++++++++++++++++++++++++++++++
> target/s390x/tcg/crypto_helper.c | 4 ++
> 4 files changed, 88 insertions(+)
>
> diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
> index 4a131dc191..126bacb281 100644
> --- a/target/s390x/gen-features.c
> +++ b/target/s390x/gen-features.c
> @@ -943,6 +943,8 @@ static uint16_t qemu_MAX[] = {
> S390_FEAT_KMCTR_EAES_256,
> S390_FEAT_PCC_XTS_AES_128,
> S390_FEAT_PCC_XTS_AES_256,
> + S390_FEAT_PCC_XTS_EAES_128,
> + S390_FEAT_PCC_XTS_EAES_256,
EAES -> PAES or EAES -> ENCRYPTED_AES
> S390_FEAT_PCKMO_AES_128,
> S390_FEAT_PCKMO_AES_192,
> S390_FEAT_PCKMO_AES_256,
[ snip ]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 13/17] target/s390x: Minimal protected key AES XTS support for cpacf pcc instruction
2026-06-17 9:48 ` [PATCH v7 13/17] target/s390x: Minimal protected key AES XTS support for cpacf pcc instruction Harald Freudenberger
2026-06-18 6:18 ` Finn Callies
@ 2026-06-18 6:21 ` Finn Callies
1 sibling, 0 replies; 41+ messages in thread
From: Finn Callies @ 2026-06-18 6:21 UTC (permalink / raw)
To: Harald Freudenberger, richard.henderson, iii, david, thuth,
berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, cohuck
On 17.06.26 11:48, Harald Freudenberger wrote:
> Support CPACF pcc subfunctions PCC-Compute-XTS-Parameter-Encrypted-AES-128
> and PCC-Compute-XTS-Parameter-Encrypted-AES-128 but only for the special
> case block sequential number is 0. However, this covers the s390 PAES XTS
> implementation in the Linux kernel.
>
> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
> Tested-by: Holger Dengler <dengler@linux.ibm.com>
With the suggestions:
Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
> ---
> target/s390x/gen-features.c | 2 +
> target/s390x/tcg/cpacf.h | 2 +
> target/s390x/tcg/cpacf_aes.c | 80 ++++++++++++++++++++++++++++++++
> target/s390x/tcg/crypto_helper.c | 4 ++
> 4 files changed, 88 insertions(+)
>
> diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
> index 4a131dc191..126bacb281 100644
> --- a/target/s390x/gen-features.c
> +++ b/target/s390x/gen-features.c
> @@ -943,6 +943,8 @@ static uint16_t qemu_MAX[] = {
> S390_FEAT_KMCTR_EAES_256,
> S390_FEAT_PCC_XTS_AES_128,
> S390_FEAT_PCC_XTS_AES_256,
> + S390_FEAT_PCC_XTS_EAES_128,
> + S390_FEAT_PCC_XTS_EAES_256,
EAES -> PAES or EAES -> ENCRYPTED_AES
> S390_FEAT_PCKMO_AES_128,
> S390_FEAT_PCKMO_AES_192,
> S390_FEAT_PCKMO_AES_256,
[ snip ]
> diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c
> index 60c3ebd79e..38f7d900fa 100644
> --- a/target/s390x/tcg/crypto_helper.c
> +++ b/target/s390x/tcg/crypto_helper.c
> @@ -206,6 +206,10 @@ static int cpacf_pcc(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
> case 0x34: /* CPACF PCC compute XTS param AES-256 */
> rc = cpacf_aes_pcc(env, mmu_idx, ra, env->regs[1], fc);
> break;
> + case 0x3a: /* CPACF_PCC compute XTS param Encrypted AES-128 */
> + case 0x3c: /* CPACF PCC compute XTS param Encrypted AES-256 */
> + rc = cpacf_paes_pcc(env, mmu_idx, ra, env->regs[1], fc);
> + break;
Funny enough that you got the ordering here correct xD
> default:
> g_assert_not_reached();
> }
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 14/17] target/s390x: Support protected key AES XTS for cpacf km instruction
2026-06-17 9:48 ` [PATCH v7 14/17] target/s390x: Support protected key AES XTS for cpacf km instruction Harald Freudenberger
@ 2026-06-18 6:22 ` Finn Callies
0 siblings, 0 replies; 41+ messages in thread
From: Finn Callies @ 2026-06-18 6:22 UTC (permalink / raw)
To: Harald Freudenberger, richard.henderson, iii, david, thuth,
berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, cohuck
On 17.06.26 11:48, Harald Freudenberger wrote:
> Support the subfunctions CPACF_KM_PXTS_128 and CPACF_KM_PAES_256
> for the cpacf km instruction.
>
> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
> Tested-by: Holger Dengler <dengler@linux.ibm.com>
With the suggestion:
Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
> ---
> target/s390x/gen-features.c | 2 +
> target/s390x/tcg/cpacf.h | 4 ++
> target/s390x/tcg/cpacf_aes.c | 106 +++++++++++++++++++++++++++++++
> target/s390x/tcg/crypto_helper.c | 6 ++
> 4 files changed, 118 insertions(+)
>
> diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
> index 126bacb281..c4c59c3504 100644
> --- a/target/s390x/gen-features.c
> +++ b/target/s390x/gen-features.c
> @@ -929,6 +929,8 @@ static uint16_t qemu_MAX[] = {
> S390_FEAT_KM_EAES_256,
> S390_FEAT_KM_XTS_AES_128,
> S390_FEAT_KM_XTS_AES_256,
> + S390_FEAT_KM_XTS_EAES_128,
> + S390_FEAT_KM_XTS_EAES_256,
PAES or ENCRYPTED_AES
> S390_FEAT_KMC_AES_128,
> S390_FEAT_KMC_AES_192,
> S390_FEAT_KMC_AES_256,
[ snip ]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 15/17] docs/s390: Document CPACF instructions support
2026-06-17 9:48 ` [PATCH v7 15/17] docs/s390: Document CPACF instructions support Harald Freudenberger
@ 2026-06-18 6:28 ` Finn Callies
0 siblings, 0 replies; 41+ messages in thread
From: Finn Callies @ 2026-06-18 6:28 UTC (permalink / raw)
To: Harald Freudenberger, richard.henderson, iii, david, thuth,
berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, cohuck
On 17.06.26 11:48, Harald Freudenberger wrote:
> Add a first document covering the Qemu s390 CPACF instructions
> and functions supported.
>
> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
With the one comment applied:
Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
> ---
> docs/system/s390x/cpacf.rst | 116 +++++++++++++++++++++++++++++++++++
> docs/system/target-s390x.rst | 1 +
> 2 files changed, 117 insertions(+)
> create mode 100644 docs/system/s390x/cpacf.rst
>
> diff --git a/docs/system/s390x/cpacf.rst b/docs/system/s390x/cpacf.rst
> new file mode 100644
> index 0000000000..85f35b4e9c
> --- /dev/null
> +++ b/docs/system/s390x/cpacf.rst
> @@ -0,0 +1,116 @@
> +CPACF Support
> +=============
> +
> +CPACF
> +-----
> +
> +CP Assist for Cryptographic Function (CPACF) is a hardware-integrated
> +coprocessor feature built into every processor core of IBM Z and
> +LinuxONE mainframes (s390x architecture). It provides high-speed,
> +hardware-accelerated encryption and hashing directly on the CPU.
> +
> +CPACF provides a set of z/Architecture instructions (known as Message
> +Security Assist or MSA) that execute cryptographic operations
> +synchronously with the main processor.
> +
> +- Symmetric Encryption: Support for AES (128, 192, 256-bit), DES, and
> + Triple-DES (TDES).
> +- Hashing: Acceleration for SHA-1, SHA-2 (up to SHA-512), SHA-3 and
> + SHAKE.
> +- Random Number Generation: Pseudo Random Number Generator (PRNG) and
> + a hardware-based True Random Number Generator (TRNG).
> +- Asymmetric Support: Elliptic Curve Cryptography (ECC) primitives
> + P-256, P-384, P-521, Montgomery/Edwards curves (e.g., Ed25519).
> +
> +Documentation about CPACF instructions is public available and
> +can be found in the "z/Architecture Principles of Operation"
> +accessible at the IBM documentation hub https://www.ibm.com/docs/en.
> +For example the latest version as a pdf is available here:
> +https://www.ibm.com/support/pages/zvm/library/other/22783214.pdf
> +
> +
> +CPACF instructions
> +------------------
> +
> +Here is a list of implemented CPACF instructions and the supported
> +functions for each instruction:
> +
> +KDSA (COMPUTE DIGITAL SIGNATURE AUTHENTICATION)
> +- Function code 0x00 - Function Query
> +
> +KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST)
> +- Function code 0x00 - Function Query
> +- Function code 0x02 - CPACF_KIMD_SHA_256
> +- Function code 0x03 - CPACF_KIMD_SHA_512
> +
> +KLMD (COMPUTE LAST MESSAGE DIGEST)
> +- Function code 0x00 - Function Query
> +- Function code 0x02 - CPACF_KLMD_SHA_256
> +- Function code 0x03 - CPACF_KLMD_SHA_512
> +
> +KM (CIPHER MESSAGE)
> +- Function code 0x00 - Function Query
> +- Function code 0x12 - CPACF_KM_AES_128
> +- Function code 0x13 - CPACF_KM_AES_192
> +- Function code 0x14 - CPACF_KM_AES_256
> +- Function code 0x1a - CPACF_KM_PAES_128
> +- Function code 0x1b - CPACF_KM_PAES_192
> +- Function code 0x1c - CPACF_KM_PAES_256
> +- Function code 0x32 - CPACF_KM_XTS_128
> +- Function code 0x34 - CPACF_KM_XTS_256
> +- Function code 0x3a - CPACF_KM_PXTS_128
> +- Function code 0x3c - CPACF_KM_PXTS_256
> +
> +KMAC (COMPUTE MESSAGE AUTHENTICATION CODE)
> +- Function code 0x00 - Function Query
> +
> +KMC (CIPHER MESSAGE WITH CHAINING)
> +- Function code 0x00 - Function Query
> +- Function code 0x12 - CPACF_KMC_AES_128
> +- Function code 0x13 - CPACF_KMC_AES_192
> +- Function code 0x14 - CPACF_KMC_AES_256
> +- Function code 0x1a - CPACF_KMC_PAES_128
> +- Function code 0x1b - CPACF_KMC_PAES_192
> +- Function code 0x1c - CPACF_KMC_PAES_256
> +
> +KMCTR (CIPHER MESSAGE WITH COUNTER)
> +- Function code 0x00 - Function Query
> +- Function code 0x12 - CPACF_KMCTR_AES_128
> +- Function code 0x13 - CPACF_KMCTR_AES_192
> +- Function code 0x14 - CPACF_KMCTR_AES_256
> +- Function code 0x1a - CPACF_KMCTR_PAES_128
> +- Function code 0x1b - CPACF_KMCTR_PAES_192
> +- Function code 0x1c - CPACF_KMCTR_PAES_256
> +
> +KMF (CIPHER MESSAGE WITH CIPHER FEEDBACK)
> +- not supported
> +
> +KMO (CIPHER MESSAGE WITH OUTPUT FEEDBACK)
> +- not supported
You list these as unsupported but KMA is missing completely. At least
mention it as unsupported as well as you do so for KMO and KMF or leave
the unsupported ones out completely.
> +
> +PCC (PERFORM CRYPTOGRAPHIC COMPUTATION)
> +- Function code 0x00 - Function Query
> +- Function code 0x32 - compute XTS param AES-128
> +- Function code 0x34 - compute XTS param AES-256
> +- Function code 0x3a - compute XTS param Encrypted AES-128
> +- Function code 0x3c - compute XTS param Encrypted AES-256
> +
> +PCKMO (PERFORM CRYPTOGRAPHIC KEY MANAGEMENT OPERATION)
> +- Function code 0x00 - Function Query
> +- Function code 0x12 - CPACF_PCKMO_ENC_AES_128_KEY
> +- Function code 0x13 - CPACF_PCKMO_ENC_AES_192_KEY
> +- Function code 0x14 - CPACF_PCKMO_ENC_AES_256_KEY
> +
> +PRNO (PERFORM RANDOM NUMBER OPERATION)
> +- Function code 0x00 - Function Query
> +- Function code 0x72 - CPACF_PRNO_TRNG
> +
> +Note that the use of a not supported CPACF instruction (KMF and KMO)
> +or invocation of a not listed function will result in a Specification
> +Exception.
> +
> +Not listed CPACF instructions (KMF, KMO) cause an Operation Exception
> +when used. Not listed functions cause a Specification Exception when
> +called. If only the query function is listed (KDSA), then the query
> +function will return a function status word with all but the query
> +function bit set to 0.
> diff --git a/docs/system/target-s390x.rst b/docs/system/target-s390x.rst
> index 94c981e732..49159826eb 100644
> --- a/docs/system/target-s390x.rst
> +++ b/docs/system/target-s390x.rst
> @@ -35,3 +35,4 @@ Architectural features
> s390x/bootdevices
> s390x/protvirt
> s390x/cpu-topology
> + s390x/cpacf
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 16/17] crypto: Add aes-helpers file to support some AES modes
2026-06-17 9:48 ` [PATCH v7 16/17] crypto: Add aes-helpers file to support some AES modes Harald Freudenberger
@ 2026-06-18 6:31 ` Finn Callies
0 siblings, 0 replies; 41+ messages in thread
From: Finn Callies @ 2026-06-18 6:31 UTC (permalink / raw)
To: Harald Freudenberger, richard.henderson, iii, david, thuth,
berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, cohuck
On 17.06.26 11:48, Harald Freudenberger wrote:
> Add a new file crypto/aes-helpers.c with simple functions
> to support some AES modes:
> - AES cbc: AES_cbc_encrypt() AES_cbc_decrypt()
> - AES ctr: AES_ctr_encrypt()
> - AES xts: AES_xts_encrypt() AES_xts_decrypt()
> and some AES related helpers:
> - AES_xor()
> - AES_xts_prep_next_tweak()
>
> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
I like this, but why do you do this so late in the series instead of
implementing it directly like that? Otherwise:
Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
> ---
> crypto/aes-helpers.c | 101 +++++++++++++++++++++++++++++++++++++++++++
> crypto/meson.build | 1 +
> include/crypto/aes.h | 14 ++++++
> 3 files changed, 116 insertions(+)
> create mode 100644 crypto/aes-helpers.c
[ snip ]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 17/17] target/s390x: Use generic AES helper functions
2026-06-17 9:48 ` [PATCH v7 17/17] target/s390x: Use generic AES helper functions Harald Freudenberger
@ 2026-06-18 6:35 ` Finn Callies
0 siblings, 0 replies; 41+ messages in thread
From: Finn Callies @ 2026-06-18 6:35 UTC (permalink / raw)
To: Harald Freudenberger, richard.henderson, iii, david, thuth,
berrange
Cc: qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, cohuck
On 17.06.26 11:48, Harald Freudenberger wrote:
> Rewrite the cpacf implementations to use the generic
> AES helper functions from crypto/aes-helpers.c
>
> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
LGTM
Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
> ---
> target/s390x/tcg/cpacf_aes.c | 124 ++++++++++-------------------------
> 1 file changed, 36 insertions(+), 88 deletions(-)
[ snip ]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 08/17] target/s390x: Support AES XTS for cpacf km instruction
2026-06-18 5:45 ` Finn Callies
@ 2026-06-22 14:25 ` Harald Freudenberger
0 siblings, 0 replies; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-22 14:25 UTC (permalink / raw)
To: Finn Callies
Cc: richard.henderson, iii, david, thuth, berrange, qemu-s390x,
qemu-devel, linux390-list, linux-s390, dengler, borntraeger,
cohuck
On 2026-06-18 07:45, Finn Callies wrote:
> On 17.06.26 11:48, Harald Freudenberger wrote:
>> Support the subfunctions XTS-AES-128 and XTS-AES-256
>> for the cpacf km instruction.
>>
>> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
>> Tested-by: Holger Dengler <dengler@linux.ibm.com>
>> ---
>> target/s390x/gen-features.c | 2 +
>> target/s390x/tcg/cpacf.h | 4 ++
>> target/s390x/tcg/cpacf_aes.c | 107
>> +++++++++++++++++++++++++++++++
>> target/s390x/tcg/crypto_helper.c | 6 ++
>> 4 files changed, 119 insertions(+)
>
> [ snip ]
>
>> +
>> + /* process up to MAX_BLOCKS_PER_RUN aes blocks */
>> + for (i = 0; i < MAX_BLOCKS_PER_RUN && len >= AES_BLOCK_SIZE; i++)
>> {
>
> I guess this has the same "feature" as the real xts where the pcc part
> is not included if not explicitly done beforehand by the user right?
> But since CPACF does it that way I guess you can't do it the "correct"
> way. Instead of XTS + PCC you could implement Full XTS... just
> something to think about.
>
>> + /* fetch one AES block into buf1 */
>> + aes_read_block(env, mmu_idx, *src_ptr_reg + done, buf1, ra);
>> + /* buf1 xor tweak => buf2 */
>
> [ snip ]
Well Finn, it is a CPACF emulation - not an emulation about what CPACF
should return if it would have been designed the right way :-)
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 09/17] target/s390x: Support pckmo encrypt AES subfunctions
2026-06-18 5:50 ` Finn Callies
@ 2026-06-22 14:34 ` Harald Freudenberger
0 siblings, 0 replies; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-22 14:34 UTC (permalink / raw)
To: Finn Callies
Cc: richard.henderson, iii, david, thuth, berrange, qemu-s390x,
qemu-devel, linux390-list, linux-s390, dengler, borntraeger,
cohuck
On 2026-06-18 07:50, Finn Callies wrote:
> On 17.06.26 11:48, Harald Freudenberger wrote:
>> Support the subfuctions PCKMO-Encrypt-AES-128-Key,
>> PCKMO-Encrypt-AES-192-Key and PCKMO-Encrypt-AES-256-Key.
>>
>> These subfunctions derive a protected key from an AES clear key
>> by encrypting it with an internal AES wrapping key. More
>> details can be found in the "z/Architecture Prinziples of
>> Operation" document.
>>
>> The qemu version provided here is only a fake indented to make
>
> typo: indeted -> intended
>
>> protected key available for developing and testing purpose:
>> * The protected key is 'derived' from the clear key by xoring
>> the fixed pattern 0xAAAA... onto the key value.
>> * The AES Wrapping Key Verification Pattern is a fixed
>> value of 32 bytes 0xFACEFACE...
>>
>> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
>> Tested-by: Holger Dengler <dengler@linux.ibm.com>
>
> With the typo fixed and the other comments at least considered:
>
> Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
>
>> ---
>> target/s390x/gen-features.c | 3 ++
>> target/s390x/tcg/cpacf.h | 2 +
>> target/s390x/tcg/cpacf_aes.c | 66
>> ++++++++++++++++++++++++++++++++
>> target/s390x/tcg/crypto_helper.c | 21 ++++++++++
>> 4 files changed, 92 insertions(+)
>
> [ snip ]
>
>> diff --git a/target/s390x/tcg/cpacf_aes.c
>> b/target/s390x/tcg/cpacf_aes.c
>> index 0312436c43..5a0a3473d5 100644
>> --- a/target/s390x/tcg/cpacf_aes.c
>> +++ b/target/s390x/tcg/cpacf_aes.c
>> @@ -467,3 +467,69 @@ int cpacf_aes_xts(CPUS390XState *env, const int
>> mmu_idx, uintptr_t ra,
>> return !len ? 0 : 3;
>> }
>> +
>> +/*
>> + * Hard coded pattern xored with the AES clear key
>> + * to 'produce' the protected key.
>> + */
>> +static const uint8_t protkey_xor_pattern[32] = {
>
> the wrapping key for protected keys is called virtual server master
> key if I recall correctly. Maybe name this accordingly or at least
> something with master or wrapping key in it as this describes the
> purpose better I think.
>
But honestly I don't want to call this a key - neither a wrapping nor
a virtual server master key. This is a simple xor pattern to be applied
to the clear key value. I don't want to call this a key in any way.
If I would label this a key someone (or AI) would immediately raise
a security finding - hard coded key / weak key / key in code ...
>> + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
>> + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
>> + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
>> + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA };
>> +
>> +/*
>> + * Hard coded wkvp ("Wrapping Key Verification Pattern")
>> + */
>> +static const uint8_t protkey_wkvp[32] = {
>
> Since you call this protkey_wkvp you could call the wrapping key
> protkey_wk.
>
>> + 0x0F, 0x0A, 0x0C, 0x0E, 0x0F, 0x0A, 0x0C, 0x0E,
>> + 0x0F, 0x0A, 0x0C, 0x0E, 0x0F, 0x0A, 0x0C, 0x0E,
>> + 0x0F, 0x0A, 0x0C, 0x0E, 0x0F, 0x0A, 0x0C, 0x0E,
>> + 0x0F, 0x0A, 0x0C, 0x0E, 0x0F, 0x0A, 0x0C, 0x0E };
>
> [ snip ]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 10/17] target/s390x: Support protected key AES ECB for cpacf km instruction
2026-06-18 5:57 ` Finn Callies
@ 2026-06-22 15:05 ` Harald Freudenberger
2026-06-22 15:41 ` Hendrik Brueckner
0 siblings, 1 reply; 41+ messages in thread
From: Harald Freudenberger @ 2026-06-22 15:05 UTC (permalink / raw)
To: Finn Callies
Cc: richard.henderson, iii, david, thuth, berrange, qemu-s390x,
qemu-devel, linux390-list, linux-s390, dengler, borntraeger,
cohuck
On 2026-06-18 07:57, Finn Callies wrote:
> On 17.06.26 11:48, Harald Freudenberger wrote:
>> Support the subfunctions CPACF_KM_PAES_128, CPACF_KM_PAES_192
>> and CPACF_KM_PAES_256 for the cpacf km instruction.
>>
>> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
>> Tested-by: Holger Dengler <dengler@linux.ibm.com>
>
> With the comments at least considered:
>
> Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
>
>> ---
>> target/s390x/gen-features.c | 3 ++
>> target/s390x/tcg/cpacf.h | 4 ++
>> target/s390x/tcg/cpacf_aes.c | 87
>> ++++++++++++++++++++++++++++++++
>> target/s390x/tcg/crypto_helper.c | 7 +++
>> 4 files changed, 101 insertions(+)
>>
>> diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
>> index d3e69aaca6..71e0e41d6e 100644
>> --- a/target/s390x/gen-features.c
>> +++ b/target/s390x/gen-features.c
>> @@ -924,6 +924,9 @@ static uint16_t qemu_MAX[] = {
>> S390_FEAT_KM_AES_128,
>> S390_FEAT_KM_AES_192,
>> S390_FEAT_KM_AES_256,
>> + S390_FEAT_KM_EAES_128,
>> + S390_FEAT_KM_EAES_192,
>> + S390_FEAT_KM_EAES_256,
>
> I would strongly prefer PAES instead of EAES. I know the CPACF
> function is called KM...ENCRYPTED...AES... but since we use protected
> or PAES in any other context and never Encrypted AES I would highly
> suggest PAES here as well. Or as an alternative expand the E to
> S390_FEAT_KM_ENCRYPTED_AES_128 to match the CPACF naming.
>
Yes, I am with you. But this is not part of this patch series.
These defines have been introduced into qemu long before this patch.
Maybe someone could rework them but not here and now with this patch
series.
>> S390_FEAT_KM_XTS_AES_128,
>> S390_FEAT_KM_XTS_AES_256,
>> S390_FEAT_KMC_AES_128,
>
> [ snip ]
>
>> diff --git a/target/s390x/tcg/cpacf_aes.c
>> b/target/s390x/tcg/cpacf_aes.c
>> index 5a0a3473d5..bcfcf3b660 100644
>> --- a/target/s390x/tcg/cpacf_aes.c
>> +++ b/target/s390x/tcg/cpacf_aes.c
>> @@ -533,3 +533,90 @@ int cpacf_aes_pckmo(CPUS390XState *env, const int
>> mmu_idx, uintptr_t ra,
>> return 0;
>> }
>> +
>> +int cpacf_paes_ecb(CPUS390XState *env, const int mmu_idx, uintptr_t
>> ra,
>> + uint64_t param_addr, uint64_t *dst_ptr_reg,
>> + uint64_t *src_ptr_reg, uint64_t *src_len_reg,
>> + uint32_t type, uint8_t fc, uint8_t mod)
>> +{
>
> [ snip ]
>
>> +
>> + /* fetch protected key from param block */
>> + for (i = 0; i < keysize; i++) {
>> + addr = wrap_address(env, param_addr + i);
>> + key[i] = cpu_ldb_mmu(env, addr, oi, ra);
>> + }
>> + /* 'decrypt' the protected key */
>> + for (i = 0; i < keysize; i++) {
>> + key[i] ^= protkey_xor_pattern[i];
>> + }
>
> Think about outsourcing this into a function as it would improve
> readability and reduce code dublication in future commits.
>
Yes, let's do this - see v8 of the patch series.
>> +
>> + /* expand key */
>> + if (mod) {
>> + AES_set_decrypt_key(key, keysize * 8, &exkey);
>> + } else {
>> + AES_set_encrypt_key(key, keysize * 8, &exkey);
>> + }
>
> [ snip ]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 10/17] target/s390x: Support protected key AES ECB for cpacf km instruction
2026-06-22 15:05 ` Harald Freudenberger
@ 2026-06-22 15:41 ` Hendrik Brueckner
0 siblings, 0 replies; 41+ messages in thread
From: Hendrik Brueckner @ 2026-06-22 15:41 UTC (permalink / raw)
To: Harald Freudenberger
Cc: Finn Callies, richard.henderson, iii, david, thuth, berrange,
qemu-s390x, qemu-devel, linux390-list, linux-s390, dengler,
borntraeger, cohuck
On Mon, Jun 22, 2026 at 05:05:28PM +0200, Harald Freudenberger wrote:
> On 2026-06-18 07:57, Finn Callies wrote:
> > On 17.06.26 11:48, Harald Freudenberger wrote:
> > > index d3e69aaca6..71e0e41d6e 100644
> > > --- a/target/s390x/gen-features.c
> > > +++ b/target/s390x/gen-features.c
> > > @@ -924,6 +924,9 @@ static uint16_t qemu_MAX[] = {
> > > S390_FEAT_KM_AES_128,
> > > S390_FEAT_KM_AES_192,
> > > S390_FEAT_KM_AES_256,
> > > + S390_FEAT_KM_EAES_128,
> > > + S390_FEAT_KM_EAES_192,
> > > + S390_FEAT_KM_EAES_256,
> >
> > I would strongly prefer PAES instead of EAES. I know the CPACF
> > function is called KM...ENCRYPTED...AES... but since we use protected
> > or PAES in any other context and never Encrypted AES I would highly
> > suggest PAES here as well. Or as an alternative expand the E to
> > S390_FEAT_KM_ENCRYPTED_AES_128 to match the CPACF naming.
> >
>
> Yes, I am with you. But this is not part of this patch series.
> These defines have been introduced into qemu long before this patch.
> Maybe someone could rework them but not here and now with this patch
> series.
They have been introduced with the CPU model for the hardware model
that introduced those. Naming should not change as we would run
into the difference for the cpu feature itself:
DEF_FEAT(KM_EAES_128, "km-eaes-128", KM, 26, "KM Encrypted-AES-128")
The "km-eaes-128" indication is actually the visible/external part
of the CPU model.
^ permalink raw reply [flat|nested] 41+ messages in thread
end of thread, other threads:[~2026-06-22 15:42 UTC | newest]
Thread overview: 41+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-17 9:48 [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Harald Freudenberger
2026-06-17 9:48 ` [PATCH v7 01/17] target/s390x: Rework s390 cpacf implementations Harald Freudenberger
2026-06-17 9:48 ` [PATCH v7 02/17] target/s390x: Move cpacf sha512 code into a new file Harald Freudenberger
2026-06-18 4:54 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 03/17] target/s390x: Support cpacf sha256 Harald Freudenberger
2026-06-18 5:18 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 04/17] target/s390x: Support AES ECB for cpacf km instruction Harald Freudenberger
2026-06-18 5:22 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 05/17] target/s390x: Support AES CBC for cpacf kmc instruction Harald Freudenberger
2026-06-18 5:27 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 06/17] target/s390x: Support AES CTR for cpacf kmctr instruction Harald Freudenberger
2026-06-18 5:31 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 07/17] target/s390x: Minimal AES XTS support for cpacf pcc instruction Harald Freudenberger
2026-06-18 5:35 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 08/17] target/s390x: Support AES XTS for cpacf km instruction Harald Freudenberger
2026-06-18 5:45 ` Finn Callies
2026-06-22 14:25 ` Harald Freudenberger
2026-06-17 9:48 ` [PATCH v7 09/17] target/s390x: Support pckmo encrypt AES subfunctions Harald Freudenberger
2026-06-18 5:50 ` Finn Callies
2026-06-22 14:34 ` Harald Freudenberger
2026-06-17 9:48 ` [PATCH v7 10/17] target/s390x: Support protected key AES ECB for cpacf km instruction Harald Freudenberger
2026-06-18 5:57 ` Finn Callies
2026-06-22 15:05 ` Harald Freudenberger
2026-06-22 15:41 ` Hendrik Brueckner
2026-06-18 6:05 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 11/17] target/s390x: Support protected key AES CBC for cpacf kmc instruction Harald Freudenberger
2026-06-18 6:08 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 12/17] target/s390x: Support protected key AES CTR for cpacf kmctr instruction Harald Freudenberger
2026-06-18 6:10 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 13/17] target/s390x: Minimal protected key AES XTS support for cpacf pcc instruction Harald Freudenberger
2026-06-18 6:18 ` Finn Callies
2026-06-18 6:21 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 14/17] target/s390x: Support protected key AES XTS for cpacf km instruction Harald Freudenberger
2026-06-18 6:22 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 15/17] docs/s390: Document CPACF instructions support Harald Freudenberger
2026-06-18 6:28 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 16/17] crypto: Add aes-helpers file to support some AES modes Harald Freudenberger
2026-06-18 6:31 ` Finn Callies
2026-06-17 9:48 ` [PATCH v7 17/17] target/s390x: Use generic AES helper functions Harald Freudenberger
2026-06-18 6:35 ` Finn Callies
2026-06-18 5:37 ` [PATCH v7 00/17] target/s390x: Extend qemu CPACF support Finn Callies
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox