From: Harald Freudenberger <freude@linux.ibm.com>
To: richard.henderson@linaro.org, iii@linux.ibm.com,
david@kernel.org, thuth@redhat.com, berrange@redhat.com
Cc: qemu-s390x@nongnu.org, qemu-devel@nongnu.org,
linux390-list@tuxmaker.boeblingen.de.ibm.com,
linux-s390@vger.kernel.org, dengler@linux.ibm.com,
borntraeger@linux.ibm.com, fcallies@linux.ibm.com,
cohuck@redhat.com
Subject: [PATCH v9 21/21] tests/tcg/s390x: Add tests for CPACF instructions
Date: Wed, 1 Jul 2026 18:46:44 +0200 [thread overview]
Message-ID: <20260701164650.95760-22-freude@linux.ibm.com> (raw)
In-Reply-To: <20260701164650.95760-1-freude@linux.ibm.com>
Add simple tests for the CPACF instructions implemented:
- kdsa - minimal as only query is implemented
- kimd - query, sha256, sha512
- klmd - query, sha256, sha512
- km - query, aes 128, 192, 256 with clear and prot key
- kmac - minimal as only query is implemented
- kmc - query, aes 128, 192, 256 with clear and prot key
- kmctr - query, aes 128, 192, 256 with clear and prot key
- pcc - query, xts aes 128, 256 and prot key xts aes 128, 256
- prno - query, trng
No test for pckmo as this is a privileged instruction.
No test for kma, kmf, kmo as these instructions are currently
not implemented at all.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
---
target/s390x/tcg/cpacf.h | 7 +
tests/tcg/s390x/Makefile.target | 9 +
tests/tcg/s390x/cpacf-kdsa.c | 59 ++++
tests/tcg/s390x/cpacf-kimd.c | 164 +++++++++
tests/tcg/s390x/cpacf-klmd.c | 202 +++++++++++
tests/tcg/s390x/cpacf-km.c | 576 ++++++++++++++++++++++++++++++++
tests/tcg/s390x/cpacf-kmac.c | 59 ++++
tests/tcg/s390x/cpacf-kmc.c | 342 +++++++++++++++++++
tests/tcg/s390x/cpacf-kmctr.c | 354 ++++++++++++++++++++
tests/tcg/s390x/cpacf-pcc.c | 241 +++++++++++++
tests/tcg/s390x/cpacf-prno.c | 130 +++++++
tests/tcg/s390x/cpacf.h | 570 +++++++++++++++++++++++++++++++
12 files changed, 2713 insertions(+)
create mode 100644 tests/tcg/s390x/cpacf-kdsa.c
create mode 100644 tests/tcg/s390x/cpacf-kimd.c
create mode 100644 tests/tcg/s390x/cpacf-klmd.c
create mode 100644 tests/tcg/s390x/cpacf-km.c
create mode 100644 tests/tcg/s390x/cpacf-kmac.c
create mode 100644 tests/tcg/s390x/cpacf-kmc.c
create mode 100644 tests/tcg/s390x/cpacf-kmctr.c
create mode 100644 tests/tcg/s390x/cpacf-pcc.c
create mode 100644 tests/tcg/s390x/cpacf-prno.c
create mode 100644 tests/tcg/s390x/cpacf.h
diff --git a/target/s390x/tcg/cpacf.h b/target/s390x/tcg/cpacf.h
index b2223b4d64..685fd773c2 100644
--- a/target/s390x/tcg/cpacf.h
+++ b/target/s390x/tcg/cpacf.h
@@ -223,6 +223,8 @@
#define CPACF_KDSA_PSIGN_ED25519 48
#define CPACF_KDSA_PSIGN_ED448 52
+#ifndef CPACF_H_INCLUDE_FOR_TESTS
+
/* from cpacf_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,
@@ -254,6 +256,8 @@ int cpacf_aes_xts(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint64_t *src_ptr_reg, uint64_t *src_len_reg,
uint32_t type, uint8_t fc, uint8_t mod);
+#endif /* CPACF_H_INCLUDE_FOR_TESTS */
+
/*
* Support for protected key cpacf functions. Note that this is
* a fake implementation intended for debugging and development.
@@ -279,6 +283,8 @@ int cpacf_aes_xts(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
0x0F, 0x0A, 0x0C, 0x0E, 0x0F, 0x0A, 0x0C, 0x0E, \
0x0F, 0x0A, 0x0C, 0x0E, 0x0F, 0x0A, 0x0C, 0x0E }
+#ifndef CPACF_H_INCLUDE_FOR_TESTS
+
/* from cpacf_aes.c */
int cpacf_aes_pckmo(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint64_t param_addr, uint8_t fc);
@@ -302,4 +308,5 @@ int cpacf_paes_xts(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
uint64_t *src_ptr_reg, uint64_t *src_len_reg,
uint32_t type, uint8_t fc, uint8_t mod);
+#endif /* CPACF_H_INCLUDE_FOR_TESTS */
#endif /* S390X_CPACF_H */
diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target
index 0ca030ded0..68e6a1816d 100644
--- a/tests/tcg/s390x/Makefile.target
+++ b/tests/tcg/s390x/Makefile.target
@@ -50,6 +50,15 @@ TESTS+=cvb
TESTS+=ts
TESTS+=ex-smc
TESTS+=divide-to-integer
+TESTS+=cpacf-kdsa
+TESTS+=cpacf-kimd
+TESTS+=cpacf-klmd
+TESTS+=cpacf-km
+TESTS+=cpacf-kmac
+TESTS+=cpacf-kmc
+TESTS+=cpacf-kmctr
+TESTS+=cpacf-pcc
+TESTS+=cpacf-prno
cdsg: CFLAGS+=-pthread
cdsg: LDFLAGS+=-pthread
diff --git a/tests/tcg/s390x/cpacf-kdsa.c b/tests/tcg/s390x/cpacf-kdsa.c
new file mode 100644
index 0000000000..ba4b94e1a3
--- /dev/null
+++ b/tests/tcg/s390x/cpacf-kdsa.c
@@ -0,0 +1,59 @@
+/*
+ * Simple test for the CPACF KDSA instruction
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "cpacf.h"
+
+#define QUERY_BLOCK_SIZE 16
+
+/* expected kdsa query block */
+static uint8_t exp_query_block[QUERY_BLOCK_SIZE] = {
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static int test_kdsa_query(void)
+{
+ uint8_t query_block[QUERY_BLOCK_SIZE] = {0};
+ unsigned long cc = 0;
+ int i, rc = 0;
+
+ cpacf_kdsa(CPACF_KDSA_QUERY, query_block, NULL, 0, &cc);
+
+ /* compare with expected query block */
+ for (i = 0; i < QUERY_BLOCK_SIZE; i++) {
+ if (query_block[i] != exp_query_block[i]) {
+ rc++;
+ break;
+ }
+ }
+
+ if (rc) {
+ printf("%s failed\n", __func__);
+ }
+
+ return rc;
+}
+
+int main(void)
+{
+ int rc;
+
+ /* Test query function */
+ rc = test_kdsa_query();
+
+ /* As of now only KDSA query is implemented */
+
+ if (rc) {
+ printf("cpacf-kdsa: %d failures\n", rc);
+ }
+
+ return rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/tests/tcg/s390x/cpacf-kimd.c b/tests/tcg/s390x/cpacf-kimd.c
new file mode 100644
index 0000000000..a086c3bd53
--- /dev/null
+++ b/tests/tcg/s390x/cpacf-kimd.c
@@ -0,0 +1,164 @@
+/*
+ * Simple test for CPACF KIMD instruction
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "cpacf.h"
+
+#define QUERY_BLOCK_SIZE 16
+
+/* expected kimd query block */
+static uint8_t exp_query_block[QUERY_BLOCK_SIZE] = {
+ 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+/* SHA-256 test data */
+static const uint8_t sha256in[] = {
+ 0x5a, 0x86, 0xb7, 0x37, 0xea, 0xea, 0x8e, 0xe9,
+ 0x76, 0xa0, 0xa2, 0x4d, 0xa6, 0x3e, 0x7e, 0xd7,
+ 0xee, 0xfa, 0xd1, 0x8a, 0x10, 0x1c, 0x12, 0x11,
+ 0xe2, 0xb3, 0x65, 0x0c, 0x51, 0x87, 0xc2, 0xa8,
+ 0xa6, 0x50, 0x54, 0x72, 0x08, 0x25, 0x1f, 0x6d,
+ 0x42, 0x37, 0xe6, 0x61, 0xc7, 0xbf, 0x4c, 0x77,
+ 0xf3, 0x35, 0x39, 0x03, 0x94, 0xc3, 0x7f, 0xa1,
+ 0xa9, 0xf9, 0xbe, 0x83, 0x6a, 0xc2, 0x85, 0x09
+};
+
+/* SHA-512 test data */
+static const uint8_t sha512in[] = {
+ 0xfd, 0x22, 0x03, 0xe4, 0x67, 0x57, 0x4e, 0x83,
+ 0x4a, 0xb0, 0x7c, 0x90, 0x97, 0xae, 0x16, 0x45,
+ 0x32, 0xf2, 0x4b, 0xe1, 0xeb, 0x5d, 0x88, 0xf1,
+ 0xaf, 0x77, 0x48, 0xce, 0xff, 0x0d, 0x2c, 0x67,
+ 0xa2, 0x1f, 0x4e, 0x40, 0x97, 0xf9, 0xd3, 0xbb,
+ 0x4e, 0x9f, 0xbf, 0x97, 0x18, 0x6e, 0x0d, 0xb6,
+ 0xdb, 0x01, 0x00, 0x23, 0x0a, 0x52, 0xb4, 0x53,
+ 0xd4, 0x21, 0xf8, 0xab, 0x9c, 0x9a, 0x60, 0x43,
+ 0xaa, 0x32, 0x95, 0xea, 0x20, 0xd2, 0xf0, 0x6a,
+ 0x2f, 0x37, 0x47, 0x0d, 0x8a, 0x99, 0x07, 0x5f,
+ 0x1b, 0x8a, 0x83, 0x36, 0xf6, 0x22, 0x8c, 0xf0,
+ 0x8b, 0x59, 0x42, 0xfc, 0x1f, 0xb4, 0x29, 0x9c,
+ 0x7d, 0x24, 0x80, 0xe8, 0xe8, 0x2b, 0xce, 0x17,
+ 0x55, 0x40, 0xbd, 0xfa, 0xd7, 0x75, 0x2b, 0xc9,
+ 0x5b, 0x57, 0x7f, 0x22, 0x95, 0x15, 0x39, 0x4f,
+ 0x3a, 0xe5, 0xce, 0xc8, 0x70, 0xa4, 0xb2, 0xf8
+};
+
+/* query test for kimd
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_kimd_query(void)
+{
+ uint8_t query_block[QUERY_BLOCK_SIZE] = {0};
+ unsigned long cc = 0;
+ int i, rc = 0;
+
+ cpacf_kimd(CPACF_KIMD_QUERY, query_block, NULL, 0, &cc);
+
+ /* compare with expected query block */
+ for (i = 0; i < QUERY_BLOCK_SIZE; i++) {
+ if (query_block[i] != exp_query_block[i]) {
+ rc++;
+ break;
+ }
+ }
+
+ if (rc) {
+ printf("%s failed\n", __func__);
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KIMD_SHA_256 test for kimd
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_kimd_sha256(void)
+{
+ uint32_t param[8];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Initialize SHA-256 hash values */
+ param[0] = 0x6a09e667u;
+ param[1] = 0xbb67ae85u;
+ param[2] = 0x3c6ef372u;
+ param[3] = 0xa54ff53au;
+ param[4] = 0x510e527fu;
+ param[5] = 0x9b05688cu;
+ param[6] = 0x1f83d9abu;
+ param[7] = 0x5be0cd19u;
+
+ /* Process input data */
+ cpacf_kimd(CPACF_KIMD_SHA_256, param, sha256in, sizeof(sha256in), &cc);
+
+ /* No check of the result in param block as this is an intermediate value */
+
+ /* Check for correct condition code (should be 0 on success) */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KIMD_SHA_512 test for kimd
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_kimd_sha512(void)
+{
+ uint64_t param[8];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Initialize SHA-512 hash values */
+ param[0] = 0x6a09e667f3bcc908lu;
+ param[1] = 0xbb67ae8584caa73blu;
+ param[2] = 0x3c6ef372fe94f82blu;
+ param[3] = 0xa54ff53a5f1d36f1lu;
+ param[4] = 0x510e527fade682d1lu;
+ param[5] = 0x9b05688c2b3e6c1flu;
+ param[6] = 0x1f83d9abfb41bd6blu;
+ param[7] = 0x5be0cd19137e2179lu;
+
+ /* Process input data */
+ cpacf_kimd(CPACF_KIMD_SHA_512, param, sha512in, sizeof(sha512in), &cc);
+
+ /* No check of the result in param block as this is an intermediate value */
+
+ /* Check for correct condition code (should be 0 on success) */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+int main(void)
+{
+ int rc = 0;
+
+ /* Test query function */
+ rc += test_kimd_query();
+
+ /* Test SHA-256 */
+ rc += test_kimd_sha256();
+
+ /* Test SHA-512 */
+ rc += test_kimd_sha512();
+
+ if (rc) {
+ printf("cpacf-kimd: %d failures\n", rc);
+ }
+
+ return rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/tests/tcg/s390x/cpacf-klmd.c b/tests/tcg/s390x/cpacf-klmd.c
new file mode 100644
index 0000000000..3562227de8
--- /dev/null
+++ b/tests/tcg/s390x/cpacf-klmd.c
@@ -0,0 +1,202 @@
+/*
+ * Simple test for CPACF KLMD instruction
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "cpacf.h"
+
+#define QUERY_BLOCK_SIZE 16
+
+/* expected klmd query block */
+static uint8_t exp_query_block[QUERY_BLOCK_SIZE] = {
+ 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+/* SHA-256 test data */
+static const uint8_t sha256in[] = {
+ 0x5a, 0x86, 0xb7, 0x37, 0xea, 0xea, 0x8e, 0xe9,
+ 0x76, 0xa0, 0xa2, 0x4d, 0xa6, 0x3e, 0x7e, 0xd7,
+ 0xee, 0xfa, 0xd1, 0x8a, 0x10, 0x1c, 0x12, 0x11,
+ 0xe2, 0xb3, 0x65, 0x0c, 0x51, 0x87, 0xc2, 0xa8,
+ 0xa6, 0x50, 0x54, 0x72, 0x08, 0x25, 0x1f, 0x6d,
+ 0x42, 0x37, 0xe6, 0x61, 0xc7, 0xbf, 0x4c, 0x77,
+ 0xf3, 0x35, 0x39, 0x03, 0x94, 0xc3, 0x7f, 0xa1,
+ 0xa9, 0xf9, 0xbe, 0x83, 0x6a, 0xc2, 0x85, 0x09
+};
+
+static const uint8_t sha256md[] = {
+ 0x42, 0xe6, 0x1e, 0x17, 0x4f, 0xbb, 0x38, 0x97,
+ 0xd6, 0xdd, 0x6c, 0xef, 0x3d, 0xd2, 0x80, 0x2f,
+ 0xe6, 0x7b, 0x33, 0x19, 0x53, 0xb0, 0x61, 0x14,
+ 0xa6, 0x5c, 0x77, 0x28, 0x59, 0xdf, 0xc1, 0xaa
+};
+
+/* SHA-512 test data */
+static const uint8_t sha512in[] = {
+ 0xfd, 0x22, 0x03, 0xe4, 0x67, 0x57, 0x4e, 0x83,
+ 0x4a, 0xb0, 0x7c, 0x90, 0x97, 0xae, 0x16, 0x45,
+ 0x32, 0xf2, 0x4b, 0xe1, 0xeb, 0x5d, 0x88, 0xf1,
+ 0xaf, 0x77, 0x48, 0xce, 0xff, 0x0d, 0x2c, 0x67,
+ 0xa2, 0x1f, 0x4e, 0x40, 0x97, 0xf9, 0xd3, 0xbb,
+ 0x4e, 0x9f, 0xbf, 0x97, 0x18, 0x6e, 0x0d, 0xb6,
+ 0xdb, 0x01, 0x00, 0x23, 0x0a, 0x52, 0xb4, 0x53,
+ 0xd4, 0x21, 0xf8, 0xab, 0x9c, 0x9a, 0x60, 0x43,
+ 0xaa, 0x32, 0x95, 0xea, 0x20, 0xd2, 0xf0, 0x6a,
+ 0x2f, 0x37, 0x47, 0x0d, 0x8a, 0x99, 0x07, 0x5f,
+ 0x1b, 0x8a, 0x83, 0x36, 0xf6, 0x22, 0x8c, 0xf0,
+ 0x8b, 0x59, 0x42, 0xfc, 0x1f, 0xb4, 0x29, 0x9c,
+ 0x7d, 0x24, 0x80, 0xe8, 0xe8, 0x2b, 0xce, 0x17,
+ 0x55, 0x40, 0xbd, 0xfa, 0xd7, 0x75, 0x2b, 0xc9,
+ 0x5b, 0x57, 0x7f, 0x22, 0x95, 0x15, 0x39, 0x4f,
+ 0x3a, 0xe5, 0xce, 0xc8, 0x70, 0xa4, 0xb2, 0xf8
+};
+
+static const uint8_t sha512md[] = {
+ 0xa2, 0x1b, 0x10, 0x77, 0xd5, 0x2b, 0x27, 0xac,
+ 0x54, 0x5a, 0xf6, 0x3b, 0x32, 0x74, 0x6c, 0x6e,
+ 0x3c, 0x51, 0xcb, 0x0c, 0xb9, 0xf2, 0x81, 0xeb,
+ 0x9f, 0x35, 0x80, 0xa6, 0xd4, 0x99, 0x6d, 0x5c,
+ 0x99, 0x17, 0xd2, 0xa6, 0xe4, 0x84, 0x62, 0x7a,
+ 0x9d, 0x5a, 0x06, 0xfa, 0x1b, 0x25, 0x32, 0x7a,
+ 0x9d, 0x71, 0x0e, 0x02, 0x73, 0x87, 0xfc, 0x3e,
+ 0x07, 0xd7, 0xc4, 0xd1, 0x4c, 0x60, 0x86, 0xcc
+};
+
+/* query test for klmd
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_klmd_query(void)
+{
+ uint8_t query_block[QUERY_BLOCK_SIZE] = {0};
+ unsigned long cc = 0;
+ int i, rc = 0;
+
+ cpacf_klmd(CPACF_KLMD_QUERY, query_block, NULL, 0, NULL, 0, &cc);
+
+ /* compare with expected query block */
+ for (i = 0; i < QUERY_BLOCK_SIZE; i++) {
+ if (query_block[i] != exp_query_block[i]) {
+ rc++;
+ break;
+ }
+ }
+
+ if (rc) {
+ printf("%s failed\n", __func__);
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KLMD_SHA_256 test for klmd
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_klmd_sha256(void)
+{
+ uint8_t param[40]; /* 32 bytes hash + 8 bytes message bit length */
+ uint32_t *hash = (uint32_t *)param;
+ uint64_t *mbl = (uint64_t *)(param + 32);
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Initialize SHA-256 hash values (H0-H7) */
+ hash[0] = 0x6a09e667u;
+ hash[1] = 0xbb67ae85u;
+ hash[2] = 0x3c6ef372u;
+ hash[3] = 0xa54ff53au;
+ hash[4] = 0x510e527fu;
+ hash[5] = 0x9b05688cu;
+ hash[6] = 0x1f83d9abu;
+ hash[7] = 0x5be0cd19u;
+
+ /* Set message bit length for KLMD */
+ *mbl = sizeof(sha256in) * 8;
+
+ /* Process input data with KLMD (finalize hash) */
+ cpacf_klmd(CPACF_KLMD_SHA_256, param, sha256in, sizeof(sha256in), NULL, 0, &cc);
+
+ /* Check for correct condition code (should be 0 on success) */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare hash result in param with expected message digest */
+ if (memcmp(param, sha256md, sizeof(sha256md))) {
+ printf("%s failed: hash mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KLMD_SHA_512 test for klmd
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_klmd_sha512(void)
+{
+ uint8_t param[80]; /* 64 bytes hash + 16 bytes message bit length */
+ uint64_t *hash = (uint64_t *)param;
+ uint64_t *mbl_high = (uint64_t *)(param + 64);
+ uint64_t *mbl_low = (uint64_t *)(param + 72);
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Initialize SHA-512 hash values (H0-H7) */
+ hash[0] = 0x6a09e667f3bcc908lu;
+ hash[1] = 0xbb67ae8584caa73blu;
+ hash[2] = 0x3c6ef372fe94f82blu;
+ hash[3] = 0xa54ff53a5f1d36f1lu;
+ hash[4] = 0x510e527fade682d1lu;
+ hash[5] = 0x9b05688c2b3e6c1flu;
+ hash[6] = 0x1f83d9abfb41bd6blu;
+ hash[7] = 0x5be0cd19137e2179lu;
+
+ /* Set message bit length for KLMD (128-bit, high and low) */
+ *mbl_high = 0;
+ *mbl_low = sizeof(sha512in) * 8;
+
+ /* Process input data with KLMD (finalize hash) */
+ cpacf_klmd(CPACF_KLMD_SHA_512, param, sha512in, sizeof(sha512in), NULL, 0, &cc);
+
+ /* Check for correct condition code (should be 0 on success) */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare hash result in param with expected message digest */
+ if (memcmp(param, sha512md, sizeof(sha512md))) {
+ printf("%s failed: hash mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+int main(void)
+{
+ int rc = 0;
+
+ /* Test query function */
+ rc += test_klmd_query();
+
+ /* Test SHA-256 */
+ rc += test_klmd_sha256();
+
+ /* Test SHA-512 */
+ rc += test_klmd_sha512();
+
+ if (rc) {
+ printf("cpacf-klmd: %d failures\n", rc);
+ }
+
+ return rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/tests/tcg/s390x/cpacf-km.c b/tests/tcg/s390x/cpacf-km.c
new file mode 100644
index 0000000000..024fdc9c58
--- /dev/null
+++ b/tests/tcg/s390x/cpacf-km.c
@@ -0,0 +1,576 @@
+/*
+ * Simple test for CPACF KM instruction
+ *
+ * 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 <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include "cpacf.h"
+
+#define QUERY_BLOCK_SIZE 16
+
+/* expected km query block */
+static uint8_t exp_query_block[QUERY_BLOCK_SIZE] = {
+ 0x80, 0x00, 0x38, 0x38, 0x00, 0x00, 0x28, 0x28,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+/* KM AES-128 test data */
+static const uint8_t kmaes128key[] = {
+ 0xed, 0xfd, 0xb2, 0x57, 0xcb, 0x37, 0xcd, 0xf1,
+ 0x82, 0xc5, 0x45, 0x5b, 0x0c, 0x0e, 0xfe, 0xbb
+};
+static const uint8_t kmaes128plain[] = {
+ 0x16, 0x95, 0xfe, 0x47, 0x54, 0x21, 0xca, 0xce,
+ 0x35, 0x57, 0xda, 0xca, 0x01, 0xf4, 0x45, 0xff
+};
+static const uint8_t kmaes128cipher[] = {
+ 0x78, 0x88, 0xbe, 0xae, 0x6e, 0x7a, 0x42, 0x63,
+ 0x32, 0xa7, 0xea, 0xa2, 0xf8, 0x08, 0xe6, 0x37
+};
+
+/* KM AES-192 test data */
+static const uint8_t kmaes192key[] = {
+ 0x61, 0x39, 0x6c, 0x53, 0x0c, 0xc1, 0x74, 0x9a,
+ 0x5b, 0xab, 0x6f, 0xbc, 0xf9, 0x06, 0xfe, 0x67,
+ 0x2d, 0x0c, 0x4a, 0xb2, 0x01, 0xaf, 0x45, 0x54
+};
+static const uint8_t kmaes192plain[] = {
+ 0x60, 0xbc, 0xdb, 0x94, 0x16, 0xba, 0xc0, 0x8d,
+ 0x7f, 0xd0, 0xd7, 0x80, 0x35, 0x37, 0x40, 0xa5
+};
+static const uint8_t kmaes192cipher[] = {
+ 0x24, 0xf4, 0x0c, 0x4e, 0xec, 0xd9, 0xc4, 0x98,
+ 0x25, 0x00, 0x0f, 0xcb, 0x49, 0x72, 0x64, 0x7a
+};
+
+/* KM AES-256 test data */
+static const uint8_t kmaes256key[] = {
+ 0xcc, 0x22, 0xda, 0x78, 0x7f, 0x37, 0x57, 0x11,
+ 0xc7, 0x63, 0x02, 0xbe, 0xf0, 0x97, 0x9d, 0x8e,
+ 0xdd, 0xf8, 0x42, 0x82, 0x9c, 0x2b, 0x99, 0xef,
+ 0x3d, 0xd0, 0x4e, 0x23, 0xe5, 0x4c, 0xc2, 0x4b
+};
+static const uint8_t kmaes256plain[] = {
+ 0xcc, 0xc6, 0x2c, 0x6b, 0x0a, 0x09, 0xa6, 0x71,
+ 0xd6, 0x44, 0x56, 0x81, 0x8d, 0xb2, 0x9a, 0x4d
+};
+static const uint8_t kmaes256cipher[] = {
+ 0xdf, 0x86, 0x34, 0xca, 0x02, 0xb1, 0x3a, 0x12,
+ 0x5b, 0x78, 0x6e, 0x1d, 0xce, 0x90, 0x65, 0x8b
+};
+
+/* KM AES XTS-128 test data */
+static const uint8_t kmaesxts128key1[] = {
+ 0xa1, 0xb9, 0x0c, 0xba, 0x3f, 0x06, 0xac, 0x35,
+ 0x3b, 0x2c, 0x34, 0x38, 0x76, 0x08, 0x17, 0x62
+};
+static const uint8_t kmaesxts128key2[] = {
+ 0x09, 0x09, 0x23, 0x02, 0x6e, 0x91, 0x77, 0x18,
+ 0x15, 0xf2, 0x9d, 0xab, 0x01, 0x93, 0x2f, 0x2f
+};
+static const uint8_t kmaesxts128sect[] = {
+ 0x4f, 0xae, 0xf7, 0x11, 0x7c, 0xda, 0x59, 0xc6,
+ 0x6e, 0x4b, 0x92, 0x01, 0x3e, 0x76, 0x8a, 0xd5
+};
+static const uint8_t kmaesxts128plain[] = {
+ 0xeb, 0xab, 0xce, 0x95, 0xb1, 0x4d, 0x3c, 0x8d,
+ 0x6f, 0xb3, 0x50, 0x39, 0x07, 0x90, 0x31, 0x1c
+};
+static const uint8_t kmaesxts128cipher[] = {
+ 0x77, 0x8a, 0xe8, 0xb4, 0x3c, 0xb9, 0x8d, 0x5a,
+ 0x82, 0x50, 0x81, 0xd5, 0xbe, 0x47, 0x1c, 0x63
+};
+
+/* KM AES XTS-256 test data */
+static const uint8_t kmaesxts256key1[] = {
+ 0x1e, 0xa6, 0x61, 0xc5, 0x8d, 0x94, 0x3a, 0x0e,
+ 0x48, 0x01, 0xe4, 0x2f, 0x4b, 0x09, 0x47, 0x14,
+ 0x9e, 0x7f, 0x9f, 0x8e, 0x3e, 0x68, 0xd0, 0xc7,
+ 0x50, 0x52, 0x10, 0xbd, 0x31, 0x1a, 0x0e, 0x7c
+};
+static const uint8_t kmaesxts256key2[] = {
+ 0xd6, 0xe1, 0x3f, 0xfd, 0xf2, 0x41, 0x8d, 0x8d,
+ 0x19, 0x11, 0xc0, 0x04, 0xcd, 0xa5, 0x8d, 0xa3,
+ 0xd6, 0x19, 0xb7, 0xe2, 0xb9, 0x14, 0x1e, 0x58,
+ 0x31, 0x8e, 0xea, 0x39, 0x2c, 0xf4, 0x1b, 0x08
+};
+static const uint8_t kmaesxts256sect[] = {
+ 0xad, 0xf8, 0xd9, 0x26, 0x27, 0x46, 0x4a, 0xd2,
+ 0xf0, 0x42, 0x8e, 0x84, 0xa9, 0xf8, 0x75, 0x64
+};
+static const uint8_t kmaesxts256plain[] = {
+ 0x2e, 0xed, 0xea, 0x52, 0xcd, 0x82, 0x15, 0xe1,
+ 0xac, 0xc6, 0x47, 0xe8, 0x10, 0xbb, 0xc3, 0x64,
+ 0x2e, 0x87, 0x28, 0x7f, 0x8d, 0x2e, 0x57, 0xe3,
+ 0x6c, 0x0a, 0x24, 0xfb, 0xc1, 0x2a, 0x20, 0x2e
+};
+static const uint8_t kmaesxts256cipher[] = {
+ 0xcb, 0xaa, 0xd0, 0xe2, 0xf6, 0xce, 0xa3, 0xf5,
+ 0x0b, 0x37, 0xf9, 0x34, 0xd4, 0x6a, 0x9b, 0x13,
+ 0x0b, 0x9d, 0x54, 0xf0, 0x7e, 0x34, 0xf3, 0x6a,
+ 0xf7, 0x93, 0xe8, 0x6f, 0x73, 0xc6, 0xd7, 0xdb
+};
+
+/* static byte array containing the WKVP */
+static const uint8_t protkey_wkvp[32] = PROTKEY_WKVP;
+
+/* query test for km
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_km_query(void)
+{
+ uint8_t query_block[QUERY_BLOCK_SIZE] = {0};
+ unsigned long cc = 0;
+ int i, rc = 0;
+
+ cpacf_km(CPACF_KM_QUERY, query_block, NULL, NULL, 0, &cc);
+
+ /* compare with expected query block */
+ for (i = 0; i < QUERY_BLOCK_SIZE; i++) {
+ if (query_block[i] != exp_query_block[i]) {
+ rc++;
+ break;
+ }
+ }
+
+ if (rc) {
+ printf("%s failed\n", __func__);
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KM_AES_128 test for km
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_km_aes_128(void)
+{
+ uint8_t param[16]; /* key only, no IV for ECB mode */
+ uint8_t output[16];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: key only */
+ memcpy(param, kmaes128key, sizeof(kmaes128key));
+
+ /* Encrypt */
+ cpacf_km(CPACF_KM_AES_128, param, output, kmaes128plain,
+ sizeof(kmaes128plain), &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmaes128cipher, sizeof(kmaes128cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KM_AES_192 test for km
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_km_aes_192(void)
+{
+ uint8_t param[24]; /* key only, no IV for ECB mode */
+ uint8_t output[16];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: key only */
+ memcpy(param, kmaes192key, sizeof(kmaes192key));
+
+ /* Encrypt */
+ cpacf_km(CPACF_KM_AES_192, param, output, kmaes192plain,
+ sizeof(kmaes192plain), &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmaes192cipher, sizeof(kmaes192cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KM_AES_256 test for km
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_km_aes_256(void)
+{
+ uint8_t param[32]; /* key only, no IV for ECB mode */
+ uint8_t output[16];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: key only */
+ memcpy(param, kmaes256key, sizeof(kmaes256key));
+
+ /* Encrypt */
+ cpacf_km(CPACF_KM_AES_256, param, output, kmaes256plain,
+ sizeof(kmaes256plain), &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmaes256cipher, sizeof(kmaes256cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KM_PAES_128 test for km
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_km_paes_128(void)
+{
+ uint8_t param[16 + 32]; /* protected key + wkvp */
+ uint8_t output[16];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: protected key + wkvp */
+ memcpy(param, kmaes128key, sizeof(kmaes128key));
+ encrypt_clrkey(param, sizeof(kmaes128key));
+ memcpy(param + sizeof(kmaes128key), protkey_wkvp, sizeof(protkey_wkvp));
+
+ /* Encrypt */
+ cpacf_km(CPACF_KM_PAES_128, param, output, kmaes128plain,
+ sizeof(kmaes128plain), &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmaes128cipher, sizeof(kmaes128cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KM_PAES_192 test for km
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_km_paes_192(void)
+{
+ uint8_t param[24 + 32]; /* protected key + wkvp */
+ uint8_t output[16];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: protected key + wkvp */
+ memcpy(param, kmaes192key, sizeof(kmaes192key));
+ encrypt_clrkey(param, sizeof(kmaes192key));
+ memcpy(param + sizeof(kmaes192key), protkey_wkvp, sizeof(protkey_wkvp));
+
+ /* Encrypt */
+ cpacf_km(CPACF_KM_PAES_192, param, output, kmaes192plain,
+ sizeof(kmaes192plain), &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmaes192cipher, sizeof(kmaes192cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KM_PAES_256 test for km
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_km_paes_256(void)
+{
+ uint8_t param[32 + 32]; /* protected key + wkvp */
+ uint8_t output[16];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: protected key + wkvp */
+ memcpy(param, kmaes256key, sizeof(kmaes256key));
+ encrypt_clrkey(param, sizeof(kmaes256key));
+ memcpy(param + sizeof(kmaes256key), protkey_wkvp, sizeof(protkey_wkvp));
+
+ /* Encrypt */
+ cpacf_km(CPACF_KM_PAES_256, param, output, kmaes256plain,
+ sizeof(kmaes256plain), &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmaes256cipher, sizeof(kmaes256cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KM_XTS_128 test for km
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_km_xts_128(void)
+{
+ uint8_t param[16 + 16]; /* key + initial XTS value */
+ uint8_t output[16];
+ uint8_t init_xts[16];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* First compute initial XTS value using key2 and sector */
+ memcpy(param, kmaesxts128key2, sizeof(kmaesxts128key2));
+ cpacf_km(CPACF_KM_AES_128, param, init_xts, kmaesxts128sect,
+ sizeof(kmaesxts128sect), &cc);
+
+ if (cc != 0) {
+ printf("%s failed: initial XTS computation cc=%lu\n", __func__, cc);
+ return 1;
+ }
+
+ /* Setup parameter block: key1 + initial XTS value */
+ memcpy(param, kmaesxts128key1, sizeof(kmaesxts128key1));
+ memcpy(param + 16, init_xts, sizeof(init_xts));
+
+ /* Encrypt */
+ cpacf_km(CPACF_KM_XTS_128, param, output, kmaesxts128plain,
+ sizeof(kmaesxts128plain), &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmaesxts128cipher, sizeof(kmaesxts128cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KM_XTS_256 test for km
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_km_xts_256(void)
+{
+ uint8_t param[32 + 16]; /* key + initial XTS value */
+ uint8_t output[32];
+ uint8_t init_xts[16];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* First compute initial XTS value using key2 and sector */
+ memcpy(param, kmaesxts256key2, sizeof(kmaesxts256key2));
+ cpacf_km(CPACF_KM_AES_256, param, init_xts, kmaesxts256sect,
+ sizeof(kmaesxts256sect), &cc);
+
+ if (cc != 0) {
+ printf("%s failed: initial XTS computation cc=%lu\n", __func__, cc);
+ return 1;
+ }
+
+ /* Setup parameter block: key1 + initial XTS value */
+ memcpy(param, kmaesxts256key1, sizeof(kmaesxts256key1));
+ memcpy(param + 32, init_xts, sizeof(init_xts));
+
+ /* Encrypt */
+ cpacf_km(CPACF_KM_XTS_256, param, output, kmaesxts256plain,
+ sizeof(kmaesxts256plain), &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmaesxts256cipher, sizeof(kmaesxts256cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KM_PXTS_128 test for km
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_km_pxts_128(void)
+{
+ uint8_t param[16 + 32 + 16]; /* protected key + wkvp + initial XTS value */
+ uint8_t output[16];
+ uint8_t init_xts[16];
+ uint8_t key2_param[16 + 32];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* First compute initial XTS value using protected key2 and sector */
+ memcpy(key2_param, kmaesxts128key2, sizeof(kmaesxts128key2));
+ encrypt_clrkey(key2_param, sizeof(kmaesxts128key2));
+ memcpy(key2_param + sizeof(kmaesxts128key2), protkey_wkvp, sizeof(protkey_wkvp));
+
+ cpacf_km(CPACF_KM_PAES_128, key2_param, init_xts, kmaesxts128sect,
+ sizeof(kmaesxts128sect), &cc);
+
+ if (cc != 0) {
+ printf("%s failed: initial XTS computation cc=%lu\n", __func__, cc);
+ return 1;
+ }
+
+ /* Setup parameter block: protected key1 + wkvp + initial XTS value */
+ memcpy(param, kmaesxts128key1, sizeof(kmaesxts128key1));
+ encrypt_clrkey(param, sizeof(kmaesxts128key1));
+ memcpy(param + sizeof(kmaesxts128key1), protkey_wkvp, sizeof(protkey_wkvp));
+ memcpy(param + sizeof(kmaesxts128key1) + sizeof(protkey_wkvp), init_xts, sizeof(init_xts));
+
+ /* Encrypt */
+ cpacf_km(CPACF_KM_PXTS_128, param, output, kmaesxts128plain,
+ sizeof(kmaesxts128plain), &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmaesxts128cipher, sizeof(kmaesxts128cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KM_PXTS_256 test for km
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_km_pxts_256(void)
+{
+ uint8_t param[32 + 32 + 16]; /* protected key + wkvp + initial XTS value */
+ uint8_t output[32];
+ uint8_t init_xts[16];
+ uint8_t key2_param[32 + 32];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* First compute initial XTS value using protected key2 and sector */
+ memcpy(key2_param, kmaesxts256key2, sizeof(kmaesxts256key2));
+ encrypt_clrkey(key2_param, sizeof(kmaesxts256key2));
+ memcpy(key2_param + sizeof(kmaesxts256key2), protkey_wkvp, sizeof(protkey_wkvp));
+
+ cpacf_km(CPACF_KM_PAES_256, key2_param, init_xts, kmaesxts256sect,
+ sizeof(kmaesxts256sect), &cc);
+
+ if (cc != 0) {
+ printf("%s failed: initial XTS computation cc=%lu\n", __func__, cc);
+ return 1;
+ }
+
+ /* Setup parameter block: protected key1 + wkvp + initial XTS value */
+ memcpy(param, kmaesxts256key1, sizeof(kmaesxts256key1));
+ encrypt_clrkey(param, sizeof(kmaesxts256key1));
+ memcpy(param + sizeof(kmaesxts256key1), protkey_wkvp, sizeof(protkey_wkvp));
+ memcpy(param + sizeof(kmaesxts256key1) + sizeof(protkey_wkvp), init_xts, sizeof(init_xts));
+
+ /* Encrypt */
+ cpacf_km(CPACF_KM_PXTS_256, param, output, kmaesxts256plain,
+ sizeof(kmaesxts256plain), &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmaesxts256cipher, sizeof(kmaesxts256cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+int main(void)
+{
+ int rc = 0;
+
+ /* Test query function */
+ rc += test_km_query();
+
+ /* Test AES-128 */
+ rc += test_km_aes_128();
+
+ /* Test AES-192 */
+ rc += test_km_aes_192();
+
+ /* Test AES-256 */
+ rc += test_km_aes_256();
+
+ /* Test PAES-128 */
+ rc += test_km_paes_128();
+
+ /* Test PAES-192 */
+ rc += test_km_paes_192();
+
+ /* Test PAES-256 */
+ rc += test_km_paes_256();
+
+ /* Test XTS-128 */
+ rc += test_km_xts_128();
+
+ /* Test XTS-256 */
+ rc += test_km_xts_256();
+
+ /* Test PXTS-128 */
+ rc += test_km_pxts_128();
+
+ /* Test PXTS-256 */
+ rc += test_km_pxts_256();
+
+ if (rc) {
+ printf("cpacf-km: %d failures\n", rc);
+ }
+
+ return rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/tests/tcg/s390x/cpacf-kmac.c b/tests/tcg/s390x/cpacf-kmac.c
new file mode 100644
index 0000000000..e5a122b74c
--- /dev/null
+++ b/tests/tcg/s390x/cpacf-kmac.c
@@ -0,0 +1,59 @@
+/*
+ * Simple test for the CPACF KMAC instruction
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "cpacf.h"
+
+#define QUERY_BLOCK_SIZE 16
+
+/* expected kmac query block */
+static uint8_t exp_query_block[QUERY_BLOCK_SIZE] = {
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static int test_kmac_query(void)
+{
+ uint8_t query_block[QUERY_BLOCK_SIZE] = {0};
+ unsigned long cc = 0;
+ int i, rc = 0;
+
+ cpacf_kmac(CPACF_KMAC_QUERY, query_block, NULL, 0, &cc);
+
+ /* compare with expected query block */
+ for (i = 0; i < QUERY_BLOCK_SIZE; i++) {
+ if (query_block[i] != exp_query_block[i]) {
+ rc++;
+ break;
+ }
+ }
+
+ if (rc) {
+ printf("%s failed\n", __func__);
+ }
+
+ return rc;
+}
+
+int main(void)
+{
+ int rc;
+
+ /* Test query function */
+ rc = test_kmac_query();
+
+ /* As of now only KMAC query is implemented */
+
+ if (rc) {
+ printf("cpacf-kmac: %d failures\n", rc);
+ }
+
+ return rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/tests/tcg/s390x/cpacf-kmc.c b/tests/tcg/s390x/cpacf-kmc.c
new file mode 100644
index 0000000000..1ebd2e5d4a
--- /dev/null
+++ b/tests/tcg/s390x/cpacf-kmc.c
@@ -0,0 +1,342 @@
+/*
+ * Simple test for CPACF KMC instruction
+ *
+ * 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 <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include "cpacf.h"
+
+#define QUERY_BLOCK_SIZE 16
+
+/* expected kmc query block */
+static uint8_t exp_query_block[QUERY_BLOCK_SIZE] = {
+ 0x80, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+/* KMC AES-128 test data */
+static const uint8_t kmcaes128key[] = {
+ 0x1f, 0x8e, 0x49, 0x73, 0x95, 0x3f, 0x3f, 0xb0,
+ 0xbd, 0x6b, 0x16, 0x66, 0x2e, 0x9a, 0x3c, 0x17
+};
+static const uint8_t kmcaes128iv[] = {
+ 0x2f, 0xe2, 0xb3, 0x33, 0xce, 0xda, 0x8f, 0x98,
+ 0xf4, 0xa9, 0x9b, 0x40, 0xd2, 0xcd, 0x34, 0xa8
+};
+static const uint8_t kmcaes128plain[] = {
+ 0x45, 0xcf, 0x12, 0x96, 0x4f, 0xc8, 0x24, 0xab,
+ 0x76, 0x61, 0x6a, 0xe2, 0xf4, 0xbf, 0x08, 0x22
+};
+static const uint8_t kmcaes128cipher[] = {
+ 0x0f, 0x61, 0xc4, 0xd4, 0x4c, 0x51, 0x47, 0xc0,
+ 0x3c, 0x19, 0x5a, 0xd7, 0xe2, 0xcc, 0x12, 0xb2
+};
+
+/* KMC AES-192 test data */
+static const uint8_t kmcaes192key[] = {
+ 0xba, 0x75, 0xf4, 0xd1, 0xd9, 0xd7, 0xcf, 0x7f,
+ 0x55, 0x14, 0x45, 0xd5, 0x6c, 0xc1, 0xa8, 0xab,
+ 0x2a, 0x07, 0x8e, 0x15, 0xe0, 0x49, 0xdc, 0x2c
+};
+static const uint8_t kmcaes192iv[] = {
+ 0x53, 0x1c, 0xe7, 0x81, 0x76, 0x40, 0x16, 0x66,
+ 0xaa, 0x30, 0xdb, 0x94, 0xec, 0x4a, 0x30, 0xeb
+};
+static const uint8_t kmcaes192plain[] = {
+ 0xc5, 0x1f, 0xc2, 0x76, 0x77, 0x4d, 0xad, 0x94,
+ 0xbc, 0xdc, 0x1d, 0x28, 0x91, 0xec, 0x86, 0x68
+};
+static const uint8_t kmcaes192cipher[] = {
+ 0x70, 0xdd, 0x95, 0xa1, 0x4e, 0xe9, 0x75, 0xe2,
+ 0x39, 0xdf, 0x36, 0xff, 0x4a, 0xee, 0x1d, 0x5d
+};
+
+/* KMC AES-256 test data */
+static const uint8_t kmcaes256key[] = {
+ 0x6e, 0xd7, 0x6d, 0x2d, 0x97, 0xc6, 0x9f, 0xd1,
+ 0x33, 0x95, 0x89, 0x52, 0x39, 0x31, 0xf2, 0xa6,
+ 0xcf, 0xf5, 0x54, 0xb1, 0x5f, 0x73, 0x8f, 0x21,
+ 0xec, 0x72, 0xdd, 0x97, 0xa7, 0x33, 0x09, 0x07
+};
+static const uint8_t kmcaes256iv[] = {
+ 0x85, 0x1e, 0x87, 0x64, 0x77, 0x6e, 0x67, 0x96,
+ 0xaa, 0xb7, 0x22, 0xdb, 0xb6, 0x44, 0xac, 0xe8
+};
+static const uint8_t kmcaes256plain[] = {
+ 0x62, 0x82, 0xb8, 0xc0, 0x5c, 0x5c, 0x15, 0x30,
+ 0xb9, 0x7d, 0x48, 0x16, 0xca, 0x43, 0x47, 0x62
+};
+static const uint8_t kmcaes256cipher[] = {
+ 0x6a, 0xcc, 0x04, 0x14, 0x2e, 0x10, 0x0a, 0x65,
+ 0xf5, 0x1b, 0x97, 0xad, 0xf5, 0x17, 0x2c, 0x41
+};
+
+/* static byte array containing the WKVP */
+static const uint8_t protkey_wkvp[32] = PROTKEY_WKVP;
+
+/* query test for kmc
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_kmc_query(void)
+{
+ uint8_t query_block[QUERY_BLOCK_SIZE] = {0};
+ unsigned long cc = 0;
+ int i, rc = 0;
+
+ cpacf_kmc(CPACF_KMC_QUERY, query_block, NULL, NULL, 0, &cc);
+
+ /* compare with expected query block */
+ for (i = 0; i < QUERY_BLOCK_SIZE; i++) {
+ if (query_block[i] != exp_query_block[i]) {
+ rc++;
+ break;
+ }
+ }
+
+ if (rc) {
+ printf("%s failed\n", __func__);
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KMC_AES_128 test for kmc
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_kmc_aes_128(void)
+{
+ uint8_t param[16 + 16]; /* IV + key */
+ uint8_t output[16];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: IV followed by key */
+ memcpy(param, kmcaes128iv, sizeof(kmcaes128iv));
+ memcpy(param + sizeof(kmcaes128iv), kmcaes128key, sizeof(kmcaes128key));
+
+ /* Encrypt */
+ cpacf_kmc(CPACF_KMC_AES_128, param, output, kmcaes128plain,
+ sizeof(kmcaes128plain), &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmcaes128cipher, sizeof(kmcaes128cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KMC_AES_192 test for kmc
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_kmc_aes_192(void)
+{
+ uint8_t param[16 + 24]; /* IV + key */
+ uint8_t output[16];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: IV followed by key */
+ memcpy(param, kmcaes192iv, sizeof(kmcaes192iv));
+ memcpy(param + sizeof(kmcaes192iv), kmcaes192key, sizeof(kmcaes192key));
+
+ /* Encrypt */
+ cpacf_kmc(CPACF_KMC_AES_192, param, output, kmcaes192plain,
+ sizeof(kmcaes192plain), &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmcaes192cipher, sizeof(kmcaes192cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KMC_AES_256 test for kmc
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_kmc_aes_256(void)
+{
+ uint8_t param[16 + 32]; /* IV + key */
+ uint8_t output[16];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: IV followed by key */
+ memcpy(param, kmcaes256iv, sizeof(kmcaes256iv));
+ memcpy(param + sizeof(kmcaes256iv), kmcaes256key, sizeof(kmcaes256key));
+
+ /* Encrypt */
+ cpacf_kmc(CPACF_KMC_AES_256, param, output, kmcaes256plain,
+ sizeof(kmcaes256plain), &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmcaes256cipher, sizeof(kmcaes256cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KMC_PAES_128 test for kmc
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_kmc_paes_128(void)
+{
+ uint8_t param[16 + 16 + 32]; /* IV + protected key + wkvp */
+ uint8_t output[16];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: IV + protected key + wkvp */
+ memcpy(param, kmcaes128iv, sizeof(kmcaes128iv));
+ memcpy(param + sizeof(kmcaes128iv), kmcaes128key, sizeof(kmcaes128key));
+ encrypt_clrkey(param + sizeof(kmcaes128iv), sizeof(kmcaes128key));
+ memcpy(param + sizeof(kmcaes128iv) + sizeof(kmcaes128key), protkey_wkvp, sizeof(protkey_wkvp));
+
+ /* Encrypt */
+ cpacf_kmc(CPACF_KMC_PAES_128, param, output, kmcaes128plain,
+ sizeof(kmcaes128plain), &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmcaes128cipher, sizeof(kmcaes128cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KMC_PAES_192 test for kmc
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_kmc_paes_192(void)
+{
+ uint8_t param[16 + 24 + 32]; /* IV + protected key + wkvp */
+ uint8_t output[16];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: IV + protected key + wkvp */
+ memcpy(param, kmcaes192iv, sizeof(kmcaes192iv));
+ memcpy(param + sizeof(kmcaes192iv), kmcaes192key, sizeof(kmcaes192key));
+ encrypt_clrkey(param + sizeof(kmcaes192iv), sizeof(kmcaes192key));
+ memcpy(param + sizeof(kmcaes192iv) + sizeof(kmcaes192key), protkey_wkvp, sizeof(protkey_wkvp));
+
+ /* Encrypt */
+ cpacf_kmc(CPACF_KMC_PAES_192, param, output, kmcaes192plain,
+ sizeof(kmcaes192plain), &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmcaes192cipher, sizeof(kmcaes192cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KMC_PAES_256 test for kmc
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_kmc_paes_256(void)
+{
+ uint8_t param[16 + 32 + 32]; /* IV + protected key + wkvp */
+ uint8_t output[16];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: IV + protected key + wkvp */
+ memcpy(param, kmcaes256iv, sizeof(kmcaes256iv));
+ memcpy(param + sizeof(kmcaes256iv), kmcaes256key, sizeof(kmcaes256key));
+ encrypt_clrkey(param + sizeof(kmcaes256iv), sizeof(kmcaes256key));
+ memcpy(param + sizeof(kmcaes256iv) + sizeof(kmcaes256key), protkey_wkvp, sizeof(protkey_wkvp));
+
+ /* Encrypt */
+ cpacf_kmc(CPACF_KMC_PAES_256, param, output, kmcaes256plain,
+ sizeof(kmcaes256plain), &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmcaes256cipher, sizeof(kmcaes256cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+int main(void)
+{
+ int rc = 0;
+
+ /* Test query function */
+ rc += test_kmc_query();
+
+ /* Test AES-128 */
+ rc += test_kmc_aes_128();
+
+ /* Test AES-192 */
+ rc += test_kmc_aes_192();
+
+ /* Test AES-256 */
+ rc += test_kmc_aes_256();
+
+ /* Test PAES-128 */
+ rc += test_kmc_paes_128();
+
+ /* Test PAES-192 */
+ rc += test_kmc_paes_192();
+
+ /* Test PAES-256 */
+ rc += test_kmc_paes_256();
+
+ if (rc) {
+ printf("cpacf-kmc: %d failures\n", rc);
+ }
+
+ return rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/tests/tcg/s390x/cpacf-kmctr.c b/tests/tcg/s390x/cpacf-kmctr.c
new file mode 100644
index 0000000000..5b9886988b
--- /dev/null
+++ b/tests/tcg/s390x/cpacf-kmctr.c
@@ -0,0 +1,354 @@
+/*
+ * Simple test for CPACF KMCTR instruction
+ *
+ * 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 <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include "cpacf.h"
+
+#define QUERY_BLOCK_SIZE 16
+
+/* expected kmctr query block */
+static uint8_t exp_query_block[QUERY_BLOCK_SIZE] = {
+ 0x80, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+/* KMCTR AES-128 test data */
+static const uint8_t kmctraes128key[] = {
+ 0xed, 0xfd, 0xb2, 0x57, 0xcb, 0x37, 0xcd, 0xf1,
+ 0x82, 0xc5, 0x45, 0x5b, 0x0c, 0x0e, 0xfe, 0xbb
+};
+static const uint8_t kmctraes128plain[] = {
+ 0x16, 0x95, 0xfe, 0x47, 0x54, 0x21, 0xca, 0xce,
+ 0x35, 0x57, 0xda, 0xca, 0x01, 0xf4, 0x45, 0xff
+};
+static const uint8_t kmctraes128cipher[] = {
+ 0x78, 0x88, 0xbe, 0xae, 0x6e, 0x7a, 0x42, 0x63,
+ 0x32, 0xa7, 0xea, 0xa2, 0xf8, 0x08, 0xe6, 0x37
+};
+
+/* KMCTR AES-192 test data */
+static const uint8_t kmctraes192key[] = {
+ 0x61, 0x39, 0x6c, 0x53, 0x0c, 0xc1, 0x74, 0x9a,
+ 0x5b, 0xab, 0x6f, 0xbc, 0xf9, 0x06, 0xfe, 0x67,
+ 0x2d, 0x0c, 0x4a, 0xb2, 0x01, 0xaf, 0x45, 0x54
+};
+static const uint8_t kmctraes192plain[] = {
+ 0x60, 0xbc, 0xdb, 0x94, 0x16, 0xba, 0xc0, 0x8d,
+ 0x7f, 0xd0, 0xd7, 0x80, 0x35, 0x37, 0x40, 0xa5
+};
+static const uint8_t kmctraes192cipher[] = {
+ 0x24, 0xf4, 0x0c, 0x4e, 0xec, 0xd9, 0xc4, 0x98,
+ 0x25, 0x00, 0x0f, 0xcb, 0x49, 0x72, 0x64, 0x7a
+};
+
+/* KMCTR AES-256 test data */
+static const uint8_t kmctraes256key[] = {
+ 0xcc, 0x22, 0xda, 0x78, 0x7f, 0x37, 0x57, 0x11,
+ 0xc7, 0x63, 0x02, 0xbe, 0xf0, 0x97, 0x9d, 0x8e,
+ 0xdd, 0xf8, 0x42, 0x82, 0x9c, 0x2b, 0x99, 0xef,
+ 0x3d, 0xd0, 0x4e, 0x23, 0xe5, 0x4c, 0xc2, 0x4b
+};
+static const uint8_t kmctraes256plain[] = {
+ 0xcc, 0xc6, 0x2c, 0x6b, 0x0a, 0x09, 0xa6, 0x71,
+ 0xd6, 0x44, 0x56, 0x81, 0x8d, 0xb2, 0x9a, 0x4d
+};
+static const uint8_t kmctraes256cipher[] = {
+ 0xdf, 0x86, 0x34, 0xca, 0x02, 0xb1, 0x3a, 0x12,
+ 0x5b, 0x78, 0x6e, 0x1d, 0xce, 0x90, 0x65, 0x8b
+};
+
+/* static byte array containing the WKVP */
+static const uint8_t protkey_wkvp[32] = PROTKEY_WKVP;
+
+/* query test for kmctr
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_kmctr_query(void)
+{
+ uint8_t query_block[QUERY_BLOCK_SIZE] = {0};
+ unsigned long cc = 0;
+ int i, rc = 0;
+
+ cpacf_kmctr(CPACF_KMCTR_QUERY, query_block, NULL, NULL, 0, NULL, &cc);
+
+ /* compare with expected query block */
+ for (i = 0; i < QUERY_BLOCK_SIZE; i++) {
+ if (query_block[i] != exp_query_block[i]) {
+ rc++;
+ break;
+ }
+ }
+
+ if (rc) {
+ printf("%s failed\n", __func__);
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KMCTR_AES_128 test for kmctr
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_kmctr_aes_128(void)
+{
+ uint8_t param[16]; /* Parameter block: AES-128 key */
+ uint8_t src[16] = {0}; /* Source data (zeros for this test) */
+ uint8_t counter[16]; /* Counter value */
+ uint8_t output[16]; /* Output buffer */
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: key only */
+ memcpy(param, kmctraes128key, sizeof(kmctraes128key));
+
+ /* Setup counter buffer */
+ memcpy(counter, kmctraes128plain, sizeof(kmctraes128plain));
+
+ /* En/Decrypt src with given counter, note that src is all zero */
+ cpacf_kmctr(CPACF_KMCTR_AES_128, param, output, src,
+ sizeof(src), counter, &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmctraes128cipher, sizeof(kmctraes128cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KMCTR_AES_192 test for kmctr
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_kmctr_aes_192(void)
+{
+ uint8_t param[24]; /* Parameter block: AES-192 key */
+ uint8_t src[16] = {0}; /* Source data (zeros for this test) */
+ uint8_t counter[16]; /* Counter value */
+ uint8_t output[16]; /* Output buffer */
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: key only */
+ memcpy(param, kmctraes192key, sizeof(kmctraes192key));
+
+ /* Setup counter buffer */
+ memcpy(counter, kmctraes192plain, sizeof(kmctraes192plain));
+
+ /* En/Decrypt src with given counter, note that src is all zero */
+ cpacf_kmctr(CPACF_KMCTR_AES_192, param, output, src,
+ sizeof(src), counter, &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmctraes192cipher, sizeof(kmctraes192cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KMCTR_AES_256 test for kmctr
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_kmctr_aes_256(void)
+{
+ uint8_t param[32]; /* Parameter block: AES-256 key */
+ uint8_t src[16] = {0}; /* Source data (zeros for this test) */
+ uint8_t counter[16]; /* Counter value */
+ uint8_t output[16]; /* Output buffer */
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: key only */
+ memcpy(param, kmctraes256key, sizeof(kmctraes256key));
+
+ /* Setup counter buffer */
+ memcpy(counter, kmctraes256plain, sizeof(kmctraes256plain));
+
+ /* En/Decrypt src with given counter, note that src is all zero */
+ cpacf_kmctr(CPACF_KMCTR_AES_256, param, output, src,
+ sizeof(src), counter, &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmctraes256cipher, sizeof(kmctraes256cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KMCTR_PAES_128 test for kmctr
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_kmctr_paes_128(void)
+{
+ uint8_t param[16 + 32]; /* Parameter block: protected key + wkvp */
+ uint8_t src[16] = {0}; /* Source data (zeros for this test) */
+ uint8_t counter[16]; /* Counter value */
+ uint8_t output[16]; /* Output buffer */
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: protected key + wkvp */
+ memcpy(param, kmctraes128key, sizeof(kmctraes128key));
+ encrypt_clrkey(param, sizeof(kmctraes128key));
+ memcpy(param + sizeof(kmctraes128key), protkey_wkvp, sizeof(protkey_wkvp));
+
+ /* Setup counter buffer */
+ memcpy(counter, kmctraes128plain, sizeof(kmctraes128plain));
+
+ /* En/Decrypt src with given counter, note that src is all zero */
+ cpacf_kmctr(CPACF_KMCTR_PAES_128, param, output, src,
+ sizeof(src), counter, &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmctraes128cipher, sizeof(kmctraes128cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KMCTR_PAES_192 test for kmctr
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_kmctr_paes_192(void)
+{
+ uint8_t param[24 + 32]; /* Parameter block: protected key + wkvp */
+ uint8_t src[16] = {0}; /* Source data (zeros for this test) */
+ uint8_t counter[16]; /* Counter value */
+ uint8_t output[16]; /* Output buffer */
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: protected key + wkvp */
+ memcpy(param, kmctraes192key, sizeof(kmctraes192key));
+ encrypt_clrkey(param, sizeof(kmctraes192key));
+ memcpy(param + sizeof(kmctraes192key), protkey_wkvp, sizeof(protkey_wkvp));
+
+ /* Setup counter buffer */
+ memcpy(counter, kmctraes192plain, sizeof(kmctraes192plain));
+
+ /* En/Decrypt src with given counter, note that src is all zero */
+ cpacf_kmctr(CPACF_KMCTR_PAES_192, param, output, src,
+ sizeof(src), counter, &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmctraes192cipher, sizeof(kmctraes192cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_KMCTR_PAES_256 test for kmctr
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_kmctr_paes_256(void)
+{
+ uint8_t param[32 + 32]; /* Parameter block: protected key + wkvp */
+ uint8_t src[16] = {0}; /* Source data (zeros for this test) */
+ uint8_t counter[16]; /* Counter value */
+ uint8_t output[16]; /* Output buffer */
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: protected key + wkvp */
+ memcpy(param, kmctraes256key, sizeof(kmctraes256key));
+ encrypt_clrkey(param, sizeof(kmctraes256key));
+ memcpy(param + sizeof(kmctraes256key), protkey_wkvp, sizeof(protkey_wkvp));
+
+ /* Setup counter buffer */
+ memcpy(counter, kmctraes256plain, sizeof(kmctraes256plain));
+
+ /* En/Decrypt src with given counter, note that src is all zero */
+ cpacf_kmctr(CPACF_KMCTR_PAES_256, param, output, src,
+ sizeof(src), counter, &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare result with expected ciphertext */
+ if (memcmp(output, kmctraes256cipher, sizeof(kmctraes256cipher))) {
+ printf("%s failed: output mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+int main(void)
+{
+ int rc = 0;
+
+ /* Test query function */
+ rc += test_kmctr_query();
+
+ /* Test AES-128 */
+ rc += test_kmctr_aes_128();
+
+ /* Test AES-192 */
+ rc += test_kmctr_aes_192();
+
+ /* Test AES-256 */
+ rc += test_kmctr_aes_256();
+
+ /* Test PAES-128 */
+ rc += test_kmctr_paes_128();
+
+ /* Test PAES-192 */
+ rc += test_kmctr_paes_192();
+
+ /* Test PAES-256 */
+ rc += test_kmctr_paes_256();
+
+ if (rc) {
+ printf("cpacf-kmctr: %d failures\n", rc);
+ }
+
+ return rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/tests/tcg/s390x/cpacf-pcc.c b/tests/tcg/s390x/cpacf-pcc.c
new file mode 100644
index 0000000000..3ef86a5b65
--- /dev/null
+++ b/tests/tcg/s390x/cpacf-pcc.c
@@ -0,0 +1,241 @@
+/*
+ * Simple test for CPACF PCC instruction
+ *
+ * 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 <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include "cpacf.h"
+
+#define QUERY_BLOCK_SIZE 16
+
+/* expected pcc query block */
+static uint8_t exp_query_block[QUERY_BLOCK_SIZE] = {
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+/* PCC XTS AES-128 test data */
+static const uint8_t kmaes128key[] = {
+ 0xed, 0xfd, 0xb2, 0x57, 0xcb, 0x37, 0xcd, 0xf1,
+ 0x82, 0xc5, 0x45, 0x5b, 0x0c, 0x0e, 0xfe, 0xbb
+};
+static const uint8_t kmaes128plain[] = {
+ 0x16, 0x95, 0xfe, 0x47, 0x54, 0x21, 0xca, 0xce,
+ 0x35, 0x57, 0xda, 0xca, 0x01, 0xf4, 0x45, 0xff
+};
+static const uint8_t kmaes128cipher[] = {
+ 0x78, 0x88, 0xbe, 0xae, 0x6e, 0x7a, 0x42, 0x63,
+ 0x32, 0xa7, 0xea, 0xa2, 0xf8, 0x08, 0xe6, 0x37
+};
+
+/* PCC XTS AES-256 test data */
+static const uint8_t kmaes256key[] = {
+ 0xcc, 0x22, 0xda, 0x78, 0x7f, 0x37, 0x57, 0x11,
+ 0xc7, 0x63, 0x02, 0xbe, 0xf0, 0x97, 0x9d, 0x8e,
+ 0xdd, 0xf8, 0x42, 0x82, 0x9c, 0x2b, 0x99, 0xef,
+ 0x3d, 0xd0, 0x4e, 0x23, 0xe5, 0x4c, 0xc2, 0x4b
+};
+static const uint8_t kmaes256plain[] = {
+ 0xcc, 0xc6, 0x2c, 0x6b, 0x0a, 0x09, 0xa6, 0x71,
+ 0xd6, 0x44, 0x56, 0x81, 0x8d, 0xb2, 0x9a, 0x4d
+};
+static const uint8_t kmaes256cipher[] = {
+ 0xdf, 0x86, 0x34, 0xca, 0x02, 0xb1, 0x3a, 0x12,
+ 0x5b, 0x78, 0x6e, 0x1d, 0xce, 0x90, 0x65, 0x8b
+};
+
+/* static byte array containing the WKVP */
+static const uint8_t protkey_wkvp[32] = PROTKEY_WKVP;
+
+/* query test for pcc
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_pcc_query(void)
+{
+ uint8_t query_block[QUERY_BLOCK_SIZE] = {0};
+ unsigned long cc = 0;
+ int i, rc = 0;
+
+ cpacf_pcc(CPACF_PCC_QUERY, query_block, &cc);
+
+ /* compare with expected query block */
+ for (i = 0; i < QUERY_BLOCK_SIZE; i++) {
+ if (query_block[i] != exp_query_block[i]) {
+ rc++;
+ break;
+ }
+ }
+
+ if (rc) {
+ printf("%s failed\n", __func__);
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_PCC_XTS_AES_128 test for pcc
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_pcc_xts_aes_128(void)
+{
+ uint8_t param[80];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: key + plaintext + zeros */
+ memcpy(param, kmaes128key, sizeof(kmaes128key));
+ memcpy(param + 16, kmaes128plain, sizeof(kmaes128plain));
+ /* Clear Block Sequential Number, Intermediate Bit Index, and XTS Parameter */
+ memset(param + 32, 0, 48);
+
+ /* Execute PCC to compute XTS parameter */
+ cpacf_pcc(CPACF_PCC_XTS_AES_128, param, &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare computed XTS parameter (at offset 64) with expected cipher */
+ if (memcmp(param + 64, kmaes128cipher, sizeof(kmaes128cipher))) {
+ printf("%s failed: XTS parameter mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_PCC_XTS_AES_256 test for pcc
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_pcc_xts_aes_256(void)
+{
+ uint8_t param[96];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: key + plaintext + zeros */
+ memcpy(param, kmaes256key, sizeof(kmaes256key));
+ memcpy(param + 32, kmaes256plain, sizeof(kmaes256plain));
+ /* Clear Block Sequential Number, Intermediate Bit Index, and XTS Parameter */
+ memset(param + 48, 0, 48);
+
+ /* Execute PCC to compute XTS parameter */
+ cpacf_pcc(CPACF_PCC_XTS_AES_256, param, &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare computed XTS parameter (at offset 80) with expected cipher */
+ if (memcmp(param + 80, kmaes256cipher, sizeof(kmaes256cipher))) {
+ printf("%s failed: XTS parameter mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_PCC_XTS_PAES_128 test for pcc
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_pcc_xts_paes_128(void)
+{
+ uint8_t param[112];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: protected key + wkvp + plaintext + zeros */
+ memcpy(param, kmaes128key, sizeof(kmaes128key));
+ encrypt_clrkey(param, sizeof(kmaes128key));
+ memcpy(param + 16, protkey_wkvp, sizeof(protkey_wkvp));
+ memcpy(param + 48, kmaes128plain, sizeof(kmaes128plain));
+ /* Clear Block Sequential Number, Intermediate Bit Index, and XTS Parameter */
+ memset(param + 64, 0, 48);
+
+ /* Execute PCC to compute XTS parameter */
+ cpacf_pcc(CPACF_PCC_XTS_PAES_128, param, &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare computed XTS parameter (at offset 96) with expected cipher */
+ if (memcmp(param + 96, kmaes128cipher, sizeof(kmaes128cipher))) {
+ printf("%s failed: XTS parameter mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* subfunction CPACF_PCC_XTS_PAES_256 test for pcc
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_pcc_xts_paes_256(void)
+{
+ uint8_t param[128];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Setup parameter block: protected key + wkvp + plaintext + zeros */
+ memcpy(param, kmaes256key, sizeof(kmaes256key));
+ encrypt_clrkey(param, sizeof(kmaes256key));
+ memcpy(param + 32, protkey_wkvp, sizeof(protkey_wkvp));
+ memcpy(param + 64, kmaes256plain, sizeof(kmaes256plain));
+ /* Clear Block Sequential Number, Intermediate Bit Index, and XTS Parameter */
+ memset(param + 80, 0, 48);
+
+ /* Execute PCC to compute XTS parameter */
+ cpacf_pcc(CPACF_PCC_XTS_PAES_256, param, &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu\n", __func__, cc);
+ rc = 1;
+ }
+
+ /* Compare computed XTS parameter (at offset 112) with expected cipher */
+ if (memcmp(param + 112, kmaes256cipher, sizeof(kmaes256cipher))) {
+ printf("%s failed: XTS parameter mismatch\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+int main(void)
+{
+ int rc = 0;
+
+ /* Test query function */
+ rc += test_pcc_query();
+
+ /* Test XTS-AES-128 */
+ rc += test_pcc_xts_aes_128();
+
+ /* Test XTS-AES-256 */
+ rc += test_pcc_xts_aes_256();
+
+ /* Test XTS-PAES-128 */
+ rc += test_pcc_xts_paes_128();
+
+ /* Test XTS-PAES-256 */
+ rc += test_pcc_xts_paes_256();
+
+ if (rc) {
+ printf("cpacf-pcc: %d failures\n", rc);
+ }
+
+ return rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/tests/tcg/s390x/cpacf-prno.c b/tests/tcg/s390x/cpacf-prno.c
new file mode 100644
index 0000000000..133cd2e064
--- /dev/null
+++ b/tests/tcg/s390x/cpacf-prno.c
@@ -0,0 +1,130 @@
+/*
+ * Simple test for CPACF PRNO instruction
+ *
+ * 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 <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include "cpacf.h"
+
+#define QUERY_BLOCK_SIZE 16
+#define TRNG_OUTPUT_SIZE 32
+
+/* expected prno query block */
+static uint8_t exp_query_block[QUERY_BLOCK_SIZE] = {
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
+};
+
+/* query test for prno
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_prno_query(void)
+{
+ uint8_t query_block[QUERY_BLOCK_SIZE] = {0};
+ unsigned long cc = 0;
+ int i, rc = 0;
+
+ cpacf_prno(CPACF_PRNO_QUERY, query_block, NULL, 0, NULL, 0, &cc);
+
+ /* compare with expected query block */
+ for (i = 0; i < QUERY_BLOCK_SIZE; i++) {
+ if (query_block[i] != exp_query_block[i]) {
+ rc++;
+ break;
+ }
+ }
+
+ if (rc) {
+ printf("%s failed\n", __func__);
+ }
+
+ return rc;
+}
+
+/* check for buffer is all zero */
+static bool is_all_zeros(const uint8_t *buf, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (buf[i] != 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* subfunction CPACF_PRNO_TRNG test for prno
+ * returns > 0 on failure, otherwise 0
+ */
+static int test_prno_trng(void)
+{
+ uint8_t output1[TRNG_OUTPUT_SIZE];
+ uint8_t output2[TRNG_OUTPUT_SIZE];
+ unsigned long cc = 0;
+ int rc = 0;
+
+ /* Initialize outputs to detect if they get filled */
+ memset(output1, 0, sizeof(output1));
+ memset(output2, 0, sizeof(output2));
+
+ /* First TRNG call */
+ cpacf_prno(CPACF_PRNO_TRNG, NULL, output1, sizeof(output1), NULL, 0, &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu on first call\n", __func__, cc);
+ rc = 1;
+ }
+ /* Verify output is not all zeros */
+ if (is_all_zeros(output1, TRNG_OUTPUT_SIZE)) {
+ printf("%s failed: output1 is all zeros\n", __func__);
+ rc = 1;
+ }
+
+ /* Second TRNG call */
+ cpacf_prno(CPACF_PRNO_TRNG, NULL, output2, sizeof(output2), NULL, 0, &cc);
+
+ /* Check for correct condition code */
+ if (cc != 0) {
+ printf("%s failed: unexpected cc=%lu on second call\n", __func__, cc);
+ rc = 1;
+ }
+ /* Verify output is not all zeros */
+ if (is_all_zeros(output2, TRNG_OUTPUT_SIZE)) {
+ printf("%s failed: output2 is all zeros\n", __func__);
+ rc = 1;
+ }
+
+ /* Verify the two outputs are different */
+ if (memcmp(output1, output2, TRNG_OUTPUT_SIZE) == 0) {
+ printf("%s failed: two TRNG calls produced same output\n", __func__);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+int main(void)
+{
+ int rc = 0;
+
+ /* Test query function */
+ rc += test_prno_query();
+
+ /* Test TRNG */
+ rc += test_prno_trng();
+
+ if (rc) {
+ printf("cpacf-prno: %d failures\n", rc);
+ }
+
+ return rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/tests/tcg/s390x/cpacf.h b/tests/tcg/s390x/cpacf.h
new file mode 100644
index 0000000000..febb976e8c
--- /dev/null
+++ b/tests/tcg/s390x/cpacf.h
@@ -0,0 +1,570 @@
+/*
+ * Defines and inline functions around testing CPACF instructions
+ *
+ * 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 _S390_CPACF_H_
+#define _S390_CPACF_H_
+
+#define CPACF_H_INCLUDE_FOR_TESTS
+#include "../../../target/s390x/tcg/cpacf.h"
+
+union register_pair {
+ unsigned __int128 pair;
+ struct {
+ unsigned long even;
+ unsigned long odd;
+ };
+};
+
+/*
+ * Instruction opcodes for the CPACF instructions
+ */
+#define CPACF_KMAC 0xb91e /* MSA */
+#define CPACF_KM 0xb92e /* MSA */
+#define CPACF_KMC 0xb92f /* MSA */
+#define CPACF_KIMD 0xb93e /* MSA */
+#define CPACF_KLMD 0xb93f /* MSA */
+#define CPACF_PCKMO 0xb928 /* MSA3 */
+#define CPACF_KMF 0xb92a /* MSA4 */
+#define CPACF_KMO 0xb92b /* MSA4 */
+#define CPACF_PCC 0xb92c /* MSA4 */
+#define CPACF_KMCTR 0xb92d /* MSA4 */
+#define CPACF_PRNO 0xb93c /* MSA5 */
+#define CPACF_KMA 0xb929 /* MSA8 */
+#define CPACF_KDSA 0xb93a /* MSA9 */
+
+/*
+ * 'encrypt' the clear key value into a protected key
+ * by xor-ing the protkey_xor_pattern onto it.
+ */
+static inline void encrypt_clrkey(uint8_t *key, int keysize)
+{
+ const uint8_t protkey_xor_pattern[32] = PROTKEY_XOR_PATTERN;
+
+ for (int i = 0; i < keysize; i++) {
+ key[i] ^= protkey_xor_pattern[i];
+ }
+}
+
+/**
+ * cpacf_km() - executes the KM instruction
+ * @func: the function code passed to KM; see CPACF_KM_xxx defines
+ * @param: address of parameter block; see POP for details on each func
+ * @dest: address of destination memory area
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
+ * Returns 0 for the query func, number of processed bytes for
+ * encryption/decryption funcs
+ */
+static inline int cpacf_km(unsigned long func, void *param,
+ uint8_t *dest, const uint8_t *src, long src_len,
+ unsigned long *cc)
+{
+ union register_pair d, s;
+
+ *cc = 0;
+ d.even = (unsigned long)dest;
+ s.even = (unsigned long)src;
+ s.odd = (unsigned long)src_len;
+ asm volatile(
+ " lgr 0,%[fc]\n"
+ " lgr 1,%[pba]\n"
+ "0: .insn rre,%[opc] << 16,%[dst],%[src]\n"
+ " brc 1,0b\n" /* handle partial completion */
+ " brc 8,2f\n"
+ " brc 4,1f\n"
+ " agsi %[__cc],1\n"
+ "1: agsi %[__cc],1\n"
+ "2:\n"
+ : [src] "+&d" (s.pair), [dst] "+&d" (d.pair), [__cc] "+Q" (*cc)
+ : [fc] "d" (func), [pba] "d" ((unsigned long)param),
+ [opc] "i" (CPACF_KM)
+ : "cc", "memory", "0", "1");
+
+ return src_len - s.odd;
+}
+
+/**
+ * cpacf_kmc() - executes the KMC instruction
+ * @func: the function code passed to KM; see CPACF_KMC_xxx defines
+ * @param: address of parameter block; see POP for details on each func
+ * @dest: address of destination memory area
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
+ * Returns 0 for the query func, number of processed bytes for
+ * encryption/decryption funcs
+ */
+static inline int cpacf_kmc(unsigned long func, void *param,
+ uint8_t *dest, const uint8_t *src, long src_len,
+ unsigned long *cc)
+{
+ union register_pair d, s;
+
+ *cc = 0;
+ d.even = (unsigned long)dest;
+ s.even = (unsigned long)src;
+ s.odd = (unsigned long)src_len;
+ asm volatile(
+ " lgr 0,%[fc]\n"
+ " lgr 1,%[pba]\n"
+ "0: .insn rre,%[opc] << 16,%[dst],%[src]\n"
+ " brc 1,0b\n" /* handle partial completion */
+ " brc 8,2f\n"
+ " brc 4,1f\n"
+ " agsi %[__cc],1\n"
+ "1: agsi %[__cc],1\n"
+ "2:\n"
+ : [src] "+&d" (s.pair), [dst] "+&d" (d.pair), [__cc] "+Q" (*cc)
+ : [fc] "d" (func), [pba] "d" ((unsigned long)param),
+ [opc] "i" (CPACF_KMC)
+ : "cc", "memory", "0", "1");
+
+ return src_len - s.odd;
+}
+
+/**
+ * cpacf_kimd() - executes the KIMD instruction
+ * @func: the function code passed to KM; see CPACF_KIMD_xxx defines
+ * @param: address of parameter block; see POP for details on each func
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ */
+static inline void cpacf_kimd(unsigned long func, void *param,
+ const uint8_t *src, long src_len,
+ unsigned long *cc)
+{
+ union register_pair s;
+
+ *cc = 0;
+ s.even = (unsigned long)src;
+ s.odd = (unsigned long)src_len;
+ asm volatile(
+ " lgr 0,%[fc]\n"
+ " lgr 1,%[pba]\n"
+ "0: .insn rre,%[opc] << 16,0,%[src]\n"
+ " brc 1,0b\n" /* handle partial completion */
+ " brc 8,2f\n"
+ " brc 4,1f\n"
+ " agsi %[__cc],1\n"
+ "1: agsi %[__cc],1\n"
+ "2:\n"
+ : [src] "+&d" (s.pair), [__cc] "+Q" (*cc)
+ : [fc] "d" (func), [pba] "d" ((unsigned long)(param)),
+ [opc] "i" (CPACF_KIMD)
+ : "cc", "memory", "0", "1");
+}
+
+/**
+ * cpacf_klmd() - executes the KLMD instruction
+ * @func: the function code passed to KM; see CPACF_KLMD_xxx defines
+ * @param: address of parameter block; see POP for details on each func
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ */
+static inline void cpacf_klmd(unsigned long func, void *param,
+ const uint8_t *src, long src_len,
+ uint8_t *dest, long dest_len,
+ unsigned long *cc)
+{
+ union register_pair s,d;
+
+ *cc = 0;
+ s.even = (unsigned long)src;
+ s.odd = (unsigned long)src_len;
+ d.even = (unsigned long)dest;
+ d.odd = (unsigned long)dest_len;
+ asm volatile(
+ " lgr 0,%[fc]\n"
+ " lgr 1,%[pba]\n"
+ "0: .insn rre,%[opc] << 16,%[dst],%[src]\n"
+ " brc 1,0b\n" /* handle partial completion */
+ " brc 8,2f\n"
+ " brc 4,1f\n"
+ " agsi %[__cc],1\n"
+ "1: agsi %[__cc],1\n"
+ "2:\n"
+ : [src] "+&d" (s.pair), [dst] "+&d" (d.pair), [__cc] "+Q" (*cc)
+ : [fc] "d" (func), [pba] "d" ((unsigned long)param),
+ [opc] "i" (CPACF_KLMD)
+ : "cc", "memory", "0", "1");
+}
+
+/**
+ * cpacf_kmac() - executes the KMAC instruction
+ * @func: the function code passed to KM; see CPACF_KMAC_xxx defines
+ * @param: address of parameter block; see POP for details on each func
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
+ * Returns 0 for the query func, number of processed bytes for digest funcs
+ */
+static inline int cpacf_kmac(unsigned long func, void *param,
+ const uint8_t *src, long src_len,
+ unsigned long *cc)
+{
+ union register_pair s;
+
+ *cc = 0;
+ s.even = (unsigned long)src;
+ s.odd = (unsigned long)src_len;
+ asm volatile(
+ " lgr 0,%[fc]\n"
+ " lgr 1,%[pba]\n"
+ "0: .insn rre,%[opc] << 16,0,%[src]\n"
+ " brc 1,0b\n" /* handle partial completion */
+ " brc 8,2f\n"
+ " brc 4,1f\n"
+ " agsi %[__cc],1\n"
+ "1: agsi %[__cc],1\n"
+ "2:\n"
+ : [src] "+&d" (s.pair), [__cc] "+Q" (*cc)
+ : [fc] "d" (func), [pba] "d" ((unsigned long)param),
+ [opc] "i" (CPACF_KMAC)
+ : "cc", "memory", "0", "1");
+
+ return src_len - s.odd;
+}
+
+static inline int cpacf_kmac_x(unsigned long *func, void *param,
+ const uint8_t *src, long src_len,
+ unsigned long *cc)
+{
+ union register_pair s;
+ unsigned long fc = *func;
+
+ *cc = 0;
+ s.even = (unsigned long)src;
+ s.odd = (unsigned long)src_len;
+ asm volatile(
+ " lgr 0,%[fc]\n"
+ " lgr 1,%[pba]\n"
+ "0: .insn rre,%[opc] << 16,0,%[src]\n"
+ " brc 1,0b\n" /* handle partial completion */
+ " brc 8,2f\n"
+ " brc 4,1f\n"
+ " agsi %[__cc],1\n"
+ "1: agsi %[__cc],1\n"
+ "2: lgr %[fc],0\n"
+ : [fc] "+d" (fc), [src] "+&d" (s.pair), [__cc] "+Q" (*cc)
+ : [pba] "d" ((unsigned long)param),
+ [opc] "i" (CPACF_KMAC)
+ : "cc", "memory", "0", "1");
+
+ *func = fc;
+
+ return src_len - s.odd;
+}
+
+/**
+ * cpacf_kmctr() - executes the KMCTR instruction
+ * @func: the function code passed to KMCTR; see CPACF_KMCTR_xxx defines
+ * @param: address of parameter block; see POP for details on each func
+ * @dest: address of destination memory area
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ * @counter: address of counter value
+ *
+ * Returns 0 for the query func, number of processed bytes for
+ * encryption/decryption funcs
+ */
+static inline int cpacf_kmctr(unsigned long func, void *param, uint8_t *dest,
+ const uint8_t *src, long src_len, uint8_t *counter,
+ unsigned long *cc)
+{
+ union register_pair d, s, c;
+
+ *cc = 0;
+ d.even = (unsigned long)dest;
+ s.even = (unsigned long)src;
+ s.odd = (unsigned long)src_len;
+ c.even = (unsigned long)counter;
+ asm volatile(
+ " lgr 0,%[fc]\n"
+ " lgr 1,%[pba]\n"
+ "0: .insn rrf,%[opc] << 16,%[dst],%[src],%[ctr],0\n"
+ " brc 1,0b\n" /* handle partial completion */
+ " brc 8,2f\n"
+ " brc 4,1f\n"
+ " agsi %[__cc],1\n"
+ "1: agsi %[__cc],1\n"
+ "2:\n"
+ : [src] "+&d" (s.pair), [dst] "+&d" (d.pair),
+ [ctr] "+&d" (c.pair), [__cc] "+Q" (*cc)
+ : [fc] "d" (func), [pba] "d" ((unsigned long)param),
+ [opc] "i" (CPACF_KMCTR)
+ : "cc", "memory", "0", "1");
+
+ return src_len - s.odd;
+}
+
+/**
+ * cpacf_prno() - executes the PRNO instruction
+ * @func: the function code passed to PRNO; see CPACF_PRNO_xxx defines
+ * @param: address of parameter block; see POP for details on each func
+ * @dest: address of destination memory area
+ * @dest_len: size of destination memory area in bytes
+ * @seed: address of seed data
+ * @seed_len: size of seed data in bytes
+ */
+static inline void cpacf_prno(unsigned long func, void *param,
+ uint8_t *dest, unsigned long dest_len,
+ const uint8_t *seed, unsigned long seed_len,
+ unsigned long *cc)
+{
+ union register_pair d, s;
+
+ *cc = 0;
+ d.even = (unsigned long)dest;
+ d.odd = (unsigned long)dest_len;
+ s.even = (unsigned long)seed;
+ s.odd = (unsigned long)seed_len;
+ asm volatile (
+ " lgr 0,%[fc]\n"
+ " lgr 1,%[pba]\n"
+ "0: .insn rre,%[opc] << 16,%[dst],%[seed]\n"
+ " brc 1,0b\n" /* handle partial completion */
+ " brc 8,2f\n"
+ " brc 4,1f\n"
+ " agsi %[__cc],1\n"
+ "1: agsi %[__cc],1\n"
+ "2:\n"
+ : [dst] "+&d" (d.pair), [__cc] "+Q" (*cc)
+ : [fc] "d" (func), [pba] "d" ((unsigned long)param),
+ [seed] "d" (s.pair), [opc] "i" (CPACF_PRNO)
+ : "cc", "memory", "0", "1");
+}
+
+/**
+ * cpacf_trng() - executes the TRNG subfunction of the PRNO instruction
+ * @ucbuf: buffer for unconditioned data
+ * @ucbuf_len: amount of unconditioned data to fetch in bytes
+ * @cbuf: buffer for conditioned data
+ * @cbuf_len: amount of conditioned data to fetch in bytes
+ */
+static inline void cpacf_trng(uint8_t *ucbuf, unsigned long ucbuf_len,
+ uint8_t *cbuf, unsigned long cbuf_len,
+ unsigned long *cc)
+{
+ union register_pair u, c;
+
+ *cc = 0;
+ u.even = (unsigned long)ucbuf;
+ u.odd = (unsigned long)ucbuf_len;
+ c.even = (unsigned long)cbuf;
+ c.odd = (unsigned long)cbuf_len;
+ asm volatile (
+ " lghi 0,%[fc]\n"
+ "0: .insn rre,%[opc] << 16,%[ucbuf],%[cbuf]\n"
+ " brc 1,0b\n" /* handle partial completion */
+ " brc 8,2f\n"
+ " brc 4,1f\n"
+ " agsi %[__cc],1\n"
+ "1: agsi %[__cc],1\n"
+ "2:\n"
+ : [ucbuf] "+&d" (u.pair), [cbuf] "+&d" (c.pair), [__cc] "+Q" (*cc)
+ : [fc] "K" (CPACF_PRNO_TRNG), [opc] "i" (CPACF_PRNO)
+ : "cc", "memory", "0");
+}
+
+/**
+ * cpacf_pcc() - executes the PCC instruction
+ * @func: the function code passed to PCC; see CPACF_KM_xxx defines
+ * @param: address of parameter block; see POP for details on each func
+ */
+static inline void cpacf_pcc(unsigned long func, void *param, unsigned long *cc)
+{
+ *cc = 0;
+ asm volatile(
+ " lgr 0,%[fc]\n"
+ " lgr 1,%[pba]\n"
+ "0: .insn rre,%[opc] << 16,0,0\n" /* PCC opcode */
+ " brc 1,0b\n" /* handle partial completion */
+ " brc 8,2f\n"
+ " brc 4,1f\n"
+ " agsi %[__cc],1\n"
+ "1: agsi %[__cc],1\n"
+ "2:\n"
+ : [__cc] "+Q" (*cc)
+ : [fc] "d" (func), [pba] "d" ((unsigned long)param),
+ [opc] "i" (CPACF_PCC)
+ : "cc", "memory", "0", "1");
+}
+
+/**
+ * cpacf_pckmo() - executes the PCKMO instruction
+ * @func: the function code passed to PCKMO; see CPACF_PCKMO_xxx defines
+ * @param: address of parameter block; see POP for details on each func
+ */
+static inline void cpacf_pckmo(long func, void *param)
+{
+ asm volatile(
+ " lgr 0,%[fc]\n"
+ " lgr 1,%[pba]\n"
+ " .insn rre,%[opc] << 16,0,0\n" /* PCKMO opcode */
+ :
+ : [fc] "d" (func), [pba] "d" ((unsigned long)param),
+ [opc] "i" (CPACF_PCKMO)
+ : "cc", "memory", "0", "1");
+}
+
+/**
+ * cpacf_kma() - executes the KMA instruction
+ * @func: the function code passed to KMA; see CPACF_KMA_xxx defines
+ * @param: address of parameter block; see POP for details on each func
+ * @dest: address of destination memory area
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ * @aad: address of additional authenticated data memory area
+ * @aad_len: length of aad operand in bytes
+ */
+static inline void cpacf_kma(unsigned long func, void *param, uint8_t *dest,
+ const uint8_t *src, unsigned long src_len,
+ const uint8_t *aad, unsigned long aad_len,
+ unsigned long *cc)
+{
+ union register_pair d, s, a;
+
+ *cc = 0;
+ d.even = (unsigned long)dest;
+ s.even = (unsigned long)src;
+ s.odd = (unsigned long)src_len;
+ a.even = (unsigned long)aad;
+ a.odd = (unsigned long)aad_len;
+ asm volatile(
+ " lgr 0,%[fc]\n"
+ " lgr 1,%[pba]\n"
+ "0: .insn rrf,%[opc] << 16,%[dst],%[src],%[aad],0\n"
+ " brc 1,0b\n" /* handle partial completion */
+ " brc 8,2f\n"
+ " brc 4,1f\n"
+ " agsi %[__cc],1\n"
+ "1: agsi %[__cc],1\n"
+ "2:\n"
+ : [dst] "+&d" (d.pair), [src] "+&d" (s.pair),
+ [aad] "+&d" (a.pair), [__cc] "+Q" (*cc)
+ : [fc] "d" (func), [pba] "d" ((unsigned long)param),
+ [opc] "i" (CPACF_KMA)
+ : "cc", "memory", "0", "1");
+}
+
+/**
+ * cpacf_kmf() - executes the KMF instruction
+ * @func: the function code passed to KMF; see CPACF_KMF_xxx defines
+ * @param: address of parameter block; see POP for details on each func
+ * @dest: address of destination memory area
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
+ * Returns 0 for the query func, number of processed bytes for
+ * encryption/decryption funcs
+ */
+static inline int cpacf_kmf(unsigned long func, void *param,
+ uint8_t *dest, const uint8_t *src, long src_len,
+ unsigned long *cc)
+{
+ union register_pair d, s;
+
+ *cc = 0;
+ d.even = (unsigned long)dest;
+ s.even = (unsigned long)src;
+ s.odd = (unsigned long)src_len;
+ asm volatile(
+ " lgr 0,%[fc]\n"
+ " lgr 1,%[pba]\n"
+ "0: .insn rre,%[opc] << 16,%[dst],%[src]\n"
+ " brc 1,0b\n" /* handle partial completion */
+ " brc 8,2f\n"
+ " brc 4,1f\n"
+ " agsi %[__cc],1\n"
+ "1: agsi %[__cc],1\n"
+ "2:\n"
+ : [src] "+&d" (s.pair), [dst] "+&d" (d.pair), [__cc] "+Q" (*cc)
+ : [fc] "d" (func), [pba] "d" ((unsigned long)param),
+ [opc] "i" (CPACF_KMF)
+ : "cc", "memory", "0", "1");
+
+ return src_len - s.odd;
+}
+
+/**
+ * cpacf_kmo() - executes the KMO instruction
+ * @func: the function code passed to KMO; see CPACF_KMO_xxx defines
+ * @param: address of parameter block; see POP for details on each func
+ * @dest: address of destination memory area
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
+ * Returns 0 for the query func, number of processed bytes for
+ * encryption/decryption funcs
+ */
+static inline int cpacf_kmo(unsigned long func, void *param,
+ uint8_t *dest, const uint8_t *src, long src_len,
+ unsigned long *cc)
+{
+ union register_pair d, s;
+
+ *cc = 0;
+ d.even = (unsigned long)dest;
+ s.even = (unsigned long)src;
+ s.odd = (unsigned long)src_len;
+ asm volatile(
+ " lgr 0,%[fc]\n"
+ " lgr 1,%[pba]\n"
+ "0: .insn rre,%[opc] << 16,%[dst],%[src]\n"
+ " brc 1,0b\n" /* handle partial completion */
+ " brc 8,2f\n"
+ " brc 4,1f\n"
+ " agsi %[__cc],1\n"
+ "1: agsi %[__cc],1\n"
+ "2:\n"
+ : [src] "+&d" (s.pair), [dst] "+&d" (d.pair), [__cc] "+Q" (*cc)
+ : [fc] "d" (func), [pba] "d" ((unsigned long)param),
+ [opc] "i" (CPACF_KMO)
+ : "cc", "memory", "0", "1");
+
+ return src_len - s.odd;
+}
+
+/**
+ * cpacf_kdsa() - executes the KDSA instruction
+ * @func: the function code passed to KDSA; see CPACF_KDSA_xxx defines
+ * @param: address of parameter block; see POP for details on each func
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
+ * Returns 0 for the query func, otherwise the condition code is checked
+ * and 0 returned on cc 0, otherwise a value != 0 to indicate failure.
+ */
+static inline int cpacf_kdsa(unsigned long func, void *param,
+ const uint8_t *src, long src_len,
+ unsigned long *cc)
+{
+ union register_pair s;
+
+ *cc = 0;
+ s.even = (unsigned long)src;
+ s.odd = (unsigned long)src_len;
+ asm volatile(
+ " lgr 0,%[fc]\n"
+ " lgr 1,%[pba]\n"
+ "0: .insn rre,%[opc] << 16,0,%[src]\n"
+ " brc 1,0b\n" /* handle partial completion */
+ " brc 8,2f\n"
+ " brc 4,1f\n"
+ " agsi %[__cc],1\n"
+ "1: agsi %[__cc],1\n"
+ "2:\n"
+ : [src] "+&d" (s.pair), [__cc] "+Q" (*cc)
+ : [fc] "d" (func), [pba] "d" ((unsigned long)param),
+ [opc] "i" (CPACF_KDSA)
+ : "cc", "memory", "0", "1");
+
+ return (int)(*cc != 0);
+}
+
+#endif /* _S390_CPACF_H_ */
--
2.43.0
prev parent reply other threads:[~2026-07-01 16:47 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-01 16:46 [PATCH v9 00/21] target/s390x: Extend qemu CPACF support Harald Freudenberger
2026-07-01 16:46 ` [PATCH v9 01/21] target/s390x: Fix wrong address handling in address loops Harald Freudenberger
2026-07-01 16:46 ` [PATCH v9 02/21] target/s390x: Rework s390 cpacf implementations Harald Freudenberger
2026-07-01 16:46 ` [PATCH v9 03/21] target/s390x: Move cpacf sha512 code into a new file Harald Freudenberger
2026-07-01 16:46 ` [PATCH v9 04/21] target/s390x: Support cpacf sha256 Harald Freudenberger
2026-07-01 16:46 ` [PATCH v9 05/21] target/s390x: Support AES ECB for cpacf km instruction Harald Freudenberger
2026-07-01 16:46 ` [PATCH v9 06/21] target/s390x: Support AES CBC for cpacf kmc instruction Harald Freudenberger
2026-07-01 16:46 ` [PATCH v9 07/21] target/s390x: Support AES CTR for cpacf kmctr instruction Harald Freudenberger
2026-07-01 16:46 ` [PATCH v9 08/21] target/s390x: Minimal AES XTS support for cpacf pcc instruction Harald Freudenberger
2026-07-01 16:46 ` [PATCH v9 09/21] target/s390x: Support AES XTS for cpacf km instruction Harald Freudenberger
2026-07-01 16:46 ` [PATCH v9 10/21] target/s390x: Base support for cpacf protected keys Harald Freudenberger
2026-07-01 16:46 ` [PATCH v9 11/21] target/s390x: Support pckmo encrypt AES subfunctions Harald Freudenberger
2026-07-01 16:46 ` [PATCH v9 12/21] target/s390x: Support protected key AES ECB for cpacf km instruction Harald Freudenberger
2026-07-01 16:46 ` [PATCH v9 13/21] target/s390x: Support protected key AES CBC for cpacf kmc instruction Harald Freudenberger
2026-07-01 16:46 ` [PATCH v9 14/21] target/s390x: Support protected key AES CTR for cpacf kmctr instruction Harald Freudenberger
2026-07-01 16:46 ` [PATCH v9 15/21] target/s390x: Minimal protected key AES XTS support for cpacf pcc instruction Harald Freudenberger
2026-07-01 16:46 ` [PATCH v9 16/21] target/s390x: Support protected key AES XTS for cpacf km instruction Harald Freudenberger
2026-07-01 16:46 ` [PATCH v9 17/21] docs/s390: Document CPACF instructions support Harald Freudenberger
2026-07-01 16:46 ` [PATCH v9 18/21] crypto: Add aes-helpers file to support some AES modes Harald Freudenberger
2026-07-01 16:46 ` [PATCH v9 19/21] target/s390x: Use generic AES helper functions Harald Freudenberger
2026-07-01 16:46 ` [PATCH v9 20/21] target/s390x: Improve fetch and store mem from and to guest Harald Freudenberger
2026-07-01 16:46 ` Harald Freudenberger [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260701164650.95760-22-freude@linux.ibm.com \
--to=freude@linux.ibm.com \
--cc=berrange@redhat.com \
--cc=borntraeger@linux.ibm.com \
--cc=cohuck@redhat.com \
--cc=david@kernel.org \
--cc=dengler@linux.ibm.com \
--cc=fcallies@linux.ibm.com \
--cc=iii@linux.ibm.com \
--cc=linux-s390@vger.kernel.org \
--cc=linux390-list@tuxmaker.boeblingen.de.ibm.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-s390x@nongnu.org \
--cc=richard.henderson@linaro.org \
--cc=thuth@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox