s390x: IPM/SPM and MSA tests
cover s390x: IPM/SPM and MSA tests
Developed while working on:
https://lists.gnu.org/archive/html/qemu-devel/2017-09/msg05133.html
Only the basics for MSA instructions are tested (basically everything QEMU also implements), but no real en/decryption.
All tests seem to pass under KVM.
For TCG, only the usual low address protection tests fail. To run under TCG, the feature have to be enabled explicitly for now:
./s390x-run s390x/emulator.elf \
-cpu qemu,msa-base=on,msa3-base=on,msa4-base=on,msa5-base=on,stfle=onDavid Hildenbrand (5):
s390x: add a test case for the ipm + spm instructions
s390x: add cpacf.h from Linux
s390x: make sure cpacf.h can be used
s390x: query and store STFL(E) facilitites
s390x: test for various MSA instructions
lib/s390x/asm/cpacf.h | 472 +++++++++++++++++++++++++++++++++++++++++++++++ lib/s390x/asm/facility.h | 48 +++++ lib/s390x/io.c | 3 + s390x/Makefile | 1 + s390x/emulator.c | 292 +++++++++++++++++++++++++++++ s390x/unittests.cfg | 3 + 6 files changed, 819 insertions(+) create mode 100644 lib/s390x/asm/cpacf.h create mode 100644 lib/s390x/asm/facility.h create mode 100644 s390x/emulator.c
Signature · 1 line
2.13.5
PATCH 1/5 s390x: add a test case for the ipm + spm instructions
Add a new file "emulator.c" and keep running tests simple for now (no support for multiple iterations and such stuff). We will get this for free once we switch to a new, general API for running/defining tests.
--- s390x/Makefile | 1 + s390x/emulator.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++ s390x/unittests.cfg | 3 +++ 3 files changed, 69 insertions(+) create mode 100644 s390x/emulator.c
s390x/Makefile +1 -0
@@ -1,5 +1,6 @@ tests = $(TEST_DIR)/selftest.elf tests += $(TEST_DIR)/intercept.elf +tests += $(TEST_DIR)/emulator.elf all: directories test_cases
s390x/emulator.c new file +65 -0
65 lines not on this page · raw message
s390x/unittests.cfg +3 -0
@@ -25,3 +25,6 @@ extra_params = -append 'test 123' [intercept] file = intercept.elf + +[emulator] +file = emulator.elf
Signature · 1 line
2.13.5
PATCH 2/5 s390x: add cpacf.h from Linux
In reply to David HildenbrandAdd arch/s390/include/asm/cpacf.h from Linux v4.13.
--- lib/s390x/asm/cpacf.h | 472 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 472 insertions(+) create mode 100644 lib/s390x/asm/cpacf.h
lib/s390x/asm/cpacf.h new file +472 -0
@@ -0,0 +1,472 @@ +/* +* CP Assist for Cryptographic Functions (CPACF) +* +* Copyright IBM Corp. 2003, 2016 +* Author(s): Thomas Spatzier +* Jan Glauber +* Harald Freudenberger ([email protected]) +* Martin Schwidefsky <[email protected]> +*/ +#ifndef _ASM_S390_CPACF_H +#define _ASM_S390_CPACF_H + +#include <asm/facility.h> + +/* +* 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 */ + +/* +* En/decryption modifier bits +*/ +#define CPACF_ENCRYPT 0x00 +#define CPACF_DECRYPT 0x80 + +/* +* Function codes for the KM (CIPHER MESSAGE) instruction +*/ +#define CPACF_KM_QUERY 0x00 +#define CPACF_KM_DEA 0x01 +#define CPACF_KM_TDEA_128 0x02 +#define CPACF_KM_TDEA_192 0x03 +#define CPACF_KM_AES_128 0x12 +#define CPACF_KM_AES_192 0x13 +#define CPACF_KM_AES_256 0x14 +#define CPACF_KM_PAES_128 0x1a +#define CPACF_KM_PAES_192 0x1b +#define CPACF_KM_PAES_256 0x1c +#define CPACF_KM_XTS_128 0x32 +#define CPACF_KM_XTS_256 0x34 +#define CPACF_KM_PXTS_128 0x3a +#define CPACF_KM_PXTS_256 0x3c + +/* +* Function codes for the KMC (CIPHER MESSAGE WITH CHAINING) +* instruction +*/ +#define CPACF_KMC_QUERY 0x00 +#define CPACF_KMC_DEA 0x01 +#define CPACF_KMC_TDEA_128 0x02 +#define CPACF_KMC_TDEA_192 0x03 +#define CPACF_KMC_AES_128 0x12 +#define CPACF_KMC_AES_192 0x13 +#define CPACF_KMC_AES_256 0x14 +#define CPACF_KMC_PAES_128 0x1a +#define CPACF_KMC_PAES_192 0x1b +#define CPACF_KMC_PAES_256 0x1c +#define CPACF_KMC_PRNG 0x43 + +/* +* Function codes for the KMCTR (CIPHER MESSAGE WITH COUNTER) +* instruction +*/ +#define CPACF_KMCTR_QUERY 0x00 +#define CPACF_KMCTR_DEA 0x01 +#define CPACF_KMCTR_TDEA_128 0x02 +#define CPACF_KMCTR_TDEA_192 0x03 +#define CPACF_KMCTR_AES_128 0x12 +#define CPACF_KMCTR_AES_192 0x13 +#define CPACF_KMCTR_AES_256 0x14 +#define CPACF_KMCTR_PAES_128 0x1a +#define CPACF_KMCTR_PAES_192 0x1b +#define CPACF_KMCTR_PAES_256 0x1c + +/* +* Function codes for the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) +* instruction +*/ +#define CPACF_KIMD_QUERY 0x00 +#define CPACF_KIMD_SHA_1 0x01 +#define CPACF_KIMD_SHA_256 0x02 +#define CPACF_KIMD_SHA_512 0x03 +#define CPACF_KIMD_GHASH 0x41 + +/* +* Function codes for the KLMD (COMPUTE LAST MESSAGE DIGEST) +* instruction +*/ +#define CPACF_KLMD_QUERY 0x00 +#define CPACF_KLMD_SHA_1 0x01 +#define CPACF_KLMD_SHA_256 0x02 +#define CPACF_KLMD_SHA_512 0x03 + +/* +* function codes for the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) +* instruction +*/ +#define CPACF_KMAC_QUERY 0x00 +#define CPACF_KMAC_DEA 0x01 +#define CPACF_KMAC_TDEA_128 0x02 +#define CPACF_KMAC_TDEA_192 0x03 + +/* +* Function codes for the PCKMO (PERFORM CRYPTOGRAPHIC KEY MANAGEMENT) +* instruction +*/ +#define CPACF_PCKMO_QUERY 0x00 +#define CPACF_PCKMO_ENC_DES_KEY 0x01 +#define CPACF_PCKMO_ENC_TDES_128_KEY 0x02 +#define CPACF_PCKMO_ENC_TDES_192_KEY 0x03 +#define CPACF_PCKMO_ENC_AES_128_KEY 0x12 +#define CPACF_PCKMO_ENC_AES_192_KEY 0x13 +#define CPACF_PCKMO_ENC_AES_256_KEY 0x14 + +/* +* Function codes for the PRNO (PERFORM RANDOM NUMBER OPERATION) +* instruction +*/ +#define CPACF_PRNO_QUERY 0x00 +#define CPACF_PRNO_SHA512_DRNG_GEN 0x03 +#define CPACF_PRNO_SHA512_DRNG_SEED 0x83 +#define CPACF_PRNO_TRNG_Q_R2C_RATIO 0x70 +#define CPACF_PRNO_TRNG 0x72 + +typedef struct {unsigned char bytes[16 ]; }cpacf_mask_t ; + +/** +* cpacf_query() - check if a specific CPACF function is available +* @opcode: the opcode of the crypto instruction +* @func: the function code to test for +* +* Executes the query function for the given crypto instruction @opcode +* and checks if @func is available +* +* Returns 1 if @func is available for @opcode, 0 otherwise +*/ +static inline void __cpacf_query (unsigned int opcode,cpacf_mask_t *mask) +{ + register unsigned long r0 asm("0") = 0; /* query function */ + register unsigned long r1 asm("1") = (unsigned long) mask; + + asmvolatile ( +" spm 0\n" /* pckmo doesn't change the cc */ +/* Parameter regs are ignored, but must be nonzero and unique */ +"0: .insn rrf,%[opc] << 16,2,4,6,0\n" +" brc 1,0b\n" /* handle partial completion */ + :"=m" (*mask) + : [fc]"d" (r0), [pba]"a" (r1), [opc]"i" (opcode) + :"cc" ); +} + +static inline int __cpacf_check_opcode (unsigned int opcode) +{ +switch (opcode) { +case CPACF_KMAC : +case CPACF_KM : +case CPACF_KMC : +case CPACF_KIMD : +case CPACF_KLMD : +return test_facility (17 );/* check for MSA */ +case CPACF_PCKMO : +return test_facility (76 );/* check for MSA3 */ +case CPACF_KMF : +case CPACF_KMO : +case CPACF_PCC : +case CPACF_KMCTR : +return test_facility (77 );/* check for MSA4 */ +case CPACF_PRNO : +return test_facility (57 );/* check for MSA5 */ +default : +BUG (); + } +} + +static inline int cpacf_query (unsigned int opcode,cpacf_mask_t *mask) +{ +if (__cpacf_check_opcode (opcode)) { +__cpacf_query (opcode, mask); +return 1 ; + } +memset (mask,0 ,sizeof (*mask)); +return 0 ; +} + +static inline int cpacf_test_func (cpacf_mask_t *mask,unsigned int func) +{ +return (mask->bytes[func >>3 ] & (0x80 >> (func &7 ))) !=0 ; +} + +static inline int cpacf_query_func (unsigned int opcode,unsigned int func) +{ +cpacf_mask_t mask; + +if (cpacf_query (opcode, &mask)) +return cpacf_test_func (&mask, func); +return 0 ; +} + +/** +* cpacf_km() - executes the KM (CIPHER MESSAGE) 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, +u8 *dest,const u8 *src,long src_len) +{ + register unsigned long r0 asm("0") = (unsigned long) func; + register unsigned long r1 asm("1") = (unsigned long) param; + register unsigned long r2 asm("2") = (unsigned long) src; + register unsigned long r3 asm("3") = (unsigned long) src_len; + register unsigned long r4 asm("4") = (unsigned long) dest; + + asmvolatile ( +"0: .insn rre,%[opc] << 16,%[dst],%[src]\n" +" brc 1,0b\n" /* handle partial completion */ + : [src]"+a" (r2), [len]"+d" (r3), [dst]"+a" (r4) + : [fc]"d" (r0), [pba]"a" (r1), [opc]"i" (CPACF_KM ) + :"cc" ,"memory" ); + +return src_len - r3; +} + +/** +* cpacf_kmc() - executes the KMC (CIPHER MESSAGE WITH CHAINING) 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, +u8 *dest,const u8 *src,long src_len) +{ + register unsigned long r0 asm("0") = (unsigned long) func; + register unsigned long r1 asm("1") = (unsigned long) param; + register unsigned long r2 asm("2") = (unsigned long) src; + register unsigned long r3 asm("3") = (unsigned long) src_len; + register unsigned long r4 asm("4") = (unsigned long) dest; + + asmvolatile ( +"0: .insn rre,%[opc] << 16,%[dst],%[src]\n" +" brc 1,0b\n" /* handle partial completion */ + : [src]"+a" (r2), [len]"+d" (r3), [dst]"+a" (r4) + : [fc]"d" (r0), [pba]"a" (r1), [opc]"i" (CPACF_KMC ) + :"cc" ,"memory" ); + +return src_len - r3; +} + +/** +* cpacf_kimd() - executes the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) +* 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 u8 *src,long src_len) +{ + register unsigned long r0 asm("0") = (unsigned long) func; + register unsigned long r1 asm("1") = (unsigned long) param; + register unsigned long r2 asm("2") = (unsigned long) src; + register unsigned long r3 asm("3") = (unsigned long) src_len; + + asmvolatile ( +"0: .insn rre,%[opc] << 16,0,%[src]\n" +" brc 1,0b\n" /* handle partial completion */ + : [src]"+a" (r2), [len]"+d" (r3) + : [fc]"d" (r0), [pba]"a" (r1), [opc]"i" (CPACF_KIMD ) + :"cc" ,"memory" ); +} + +/** +* cpacf_klmd() - executes the KLMD (COMPUTE LAST MESSAGE DIGEST) 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 u8 *src,long src_len) +{ + register unsigned long r0 asm("0") = (unsigned long) func; + register unsigned long r1 asm("1") = (unsigned long) param; + register unsigned long r2 asm("2") = (unsigned long) src; + register unsigned long r3 asm("3") = (unsigned long) src_len; + + asmvolatile ( +"0: .insn rre,%[opc] << 16,0,%[src]\n" +" brc 1,0b\n" /* handle partial completion */ + : [src]"+a" (r2), [len]"+d" (r3) + : [fc]"d" (r0), [pba]"a" (r1), [opc]"i" (CPACF_KLMD ) + :"cc" ,"memory" ); +} + +/** +* cpacf_kmac() - executes the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) +* 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 u8 *src,long src_len) +{ + register unsigned long r0 asm("0") = (unsigned long) func; + register unsigned long r1 asm("1") = (unsigned long) param; + register unsigned long r2 asm("2") = (unsigned long) src; + register unsigned long r3 asm("3") = (unsigned long) src_len; + + asmvolatile ( +"0: .insn rre,%[opc] << 16,0,%[src]\n" +" brc 1,0b\n" /* handle partial completion */ + : [src]"+a" (r2), [len]"+d" (r3) + : [fc]"d" (r0), [pba]"a" (r1), [opc]"i" (CPACF_KMAC ) + :"cc" ,"memory" ); + +return src_len - r3; +} + +/** +* cpacf_kmctr() - executes the KMCTR (CIPHER MESSAGE WITH COUNTER) 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,u8 *dest, +const u8 *src,long src_len,u8 *counter) +{ + register unsigned long r0 asm("0") = (unsigned long) func; + register unsigned long r1 asm("1") = (unsigned long) param; + register unsigned long r2 asm("2") = (unsigned long) src; + register unsigned long r3 asm("3") = (unsigned long) src_len; + register unsigned long r4 asm("4") = (unsigned long) dest; + register unsigned long r6 asm("6") = (unsigned long) counter; + + asmvolatile ( +"0: .insn rrf,%[opc] << 16,%[dst],%[src],%[ctr],0\n" +" brc 1,0b\n" /* handle partial completion */ + : [src]"+a" (r2), [len]"+d" (r3), + [dst]"+a" (r4), [ctr]"+a" (r6) + : [fc]"d" (r0), [pba]"a" (r1), [opc]"i" (CPACF_KMCTR ) + :"cc" ,"memory" ); + +return src_len - r3; +} + +/** +* cpacf_prno() - executes the PRNO (PERFORM RANDOM NUMBER OPERATION) +* 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, +u8 *dest,unsigned long dest_len, +const u8 *seed,unsigned long seed_len) +{ + register unsigned long r0 asm("0") = (unsigned long) func; + register unsigned long r1 asm("1") = (unsigned long) param; + register unsigned long r2 asm("2") = (unsigned long) dest; + register unsigned long r3 asm("3") = (unsigned long) dest_len; + register unsigned long r4 asm("4") = (unsigned long) seed; + register unsigned long r5 asm("5") = (unsigned long) seed_len; + + asmvolatile ( +"0: .insn rre,%[opc] << 16,%[dst],%[seed]\n" +" brc 1,0b\n" /* handle partial completion */ + : [dst]"+a" (r2), [dlen]"+d" (r3) + : [fc]"d" (r0), [pba]"a" (r1), + [seed]"a" (r4), [slen]"d" (r5), [opc]"i" (CPACF_PRNO ) + :"cc" ,"memory" ); +} + +/** +* 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 (u8 *ucbuf,unsigned long ucbuf_len, +u8 *cbuf,unsigned long cbuf_len) +{ + register unsigned long r0 asm("0") = (unsigned long) CPACF_PRNO_TRNG; + register unsigned long r2 asm("2") = (unsigned long) ucbuf; + register unsigned long r3 asm("3") = (unsigned long) ucbuf_len; + register unsigned long r4 asm("4") = (unsigned long) cbuf; + register unsigned long r5 asm("5") = (unsigned long) cbuf_len; + + asmvolatile ( +"0: .insn rre,%[opc] << 16,%[ucbuf],%[cbuf]\n" +" brc 1,0b\n" /* handle partial completion */ + : [ucbuf]"+a" (r2), [ucbuflen]"+d" (r3), + [cbuf]"+a" (r4), [cbuflen]"+d" (r5) + : [fc]"d" (r0), [opc]"i" (CPACF_PRNO ) + :"cc" ,"memory" ); +} + +/** +* cpacf_pcc() - executes the PCC (PERFORM CRYPTOGRAPHIC COMPUTATION) +* 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) +{ + register unsigned long r0 asm("0") = (unsigned long) func; + register unsigned long r1 asm("1") = (unsigned long) param; + + asmvolatile ( +"0: .insn rre,%[opc] << 16,0,0\n" /* PCC opcode */ +" brc 1,0b\n" /* handle partial completion */ + : + : [fc]"d" (r0), [pba]"a" (r1), [opc]"i" (CPACF_PCC ) + :"cc" ,"memory" ); +} + +/** +* cpacf_pckmo() - executes the PCKMO (PERFORM CRYPTOGRAPHIC KEY +* MANAGEMENT) 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 +* +* Returns 0. +*/ +static inline void cpacf_pckmo (long func,void *param) +{ + register unsigned long r0 asm("0") = (unsigned long) func; + register unsigned long r1 asm("1") = (unsigned long) param; + + asmvolatile ( +" .insn rre,%[opc] << 16,0,0\n" /* PCKMO opcode */ + : + : [fc]"d" (r0), [pba]"a" (r1), [opc]"i" (CPACF_PCKMO ) + :"cc" ,"memory" ); +} + +#endif /* _ASM_S390_CPACF_H */
Signature · 1 line
2.13.5
PATCH 3/5 s390x: make sure cpacf.h can be used
In reply to David HildenbrandWe don't define BUG(), just use a return instead.
--- lib/s390x/asm/cpacf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
lib/s390x/asm/cpacf.h +1 -1
@@ -179,7 +179,7 @@ static inline int __cpacf_check_opcode(unsigned int opcode)case CPACF_PRNO :return test_facility (57 );/* check for MSA5 */ default : -BUG (); +return 0 ; } }
Signature · 1 line
2.13.5
PATCH 4/5 s390x: query and store STFL(E) facilitites
In reply to David Hildenbrandcpacf.h will require the test_facility() function, so let's properly query and store the STFL(E) facilities.
STFLE requires double word alignment.
--- lib/s390x/asm/facility.h | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/s390x/io.c | 3 +++ 2 files changed, 51 insertions(+) create mode 100644 lib/s390x/asm/facility.h
lib/s390x/asm/facility.h new file +48 -0
@@ -0,0 +1,48 @@ +/* +* Copyright (c) 2017 Red Hat Inc +* +* Authors: +* David Hildenbrand <[email protected]> +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU Library General Public License version 2. +*/ +#ifndef _ASM_S390X_FACILITY_H_ +#define _ASM_S390X_FACILITY_H_ + +#include <libcflat.h> +#include <asm/facility.h> +#include <asm/arch_def.h> + +#define NR_STFL_BYTES 256 +extern uint8_t stfl_bytes[]; + +static inline bool test_facility (int nr) +{ +return stfl_bytes[nr /8 ] & (0x80U >> (nr %8 )); +} + +static inline void stfl (void ) +{ + asmvolatile (" stfl 0(0)\n" ); +} + +static inline void stfle (uint8_t *fac,unsigned int len) +{ + register unsigned long r0 asm("0") = len - 1; + + asmvolatile (" .insn s,0xb2b00000,0(%1)\n" + :"+d" (r0) :"a" (fac) :"memory" ,"cc" ); +} + +static inline void setup_facilities (void ) +{ +struct lowcore *lc =NULL ; + +stfl (); +memcpy (stfl_bytes, &lc->stfl,sizeof (lc->stfl)); +if (test_facility (7 )) +stfle (stfl_bytes,NR_STFL_BYTES ); +} + +#endif
lib/s390x/io.c +3 -0
@@ -13,9 +13,11 @@#include <libcflat.h> #include <argv.h> #include <asm/spinlock.h> +#include <asm/facility.h> #include "sclp.h" extern char ipl_args[]; +uint8_t stfl_bytes[NR_STFL_BYTES] __attribute__((aligned(8)));static struct spinlock lock;
@@ -39,6 +41,7 @@ static void sigp_stop()void setup () {setup_args_progname (ipl_args); +setup_facilities ();sclp_setup (); }
Signature · 1 line
2.13.5
PATCH 5/5 s390x: test for various MSA instructions
In reply to David HildenbrandTest the parameter checks and if the query function correctly works.
Tests will only be executed if the corresponding stfl(e) bit for an instruction is indicated.
--- s390x/emulator.c | 227 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+)
s390x/emulator.c +227 -0
@@ -11,6 +11,8 @@* under the terms of the GNU Library General Public License version 2. */ #include <libcflat.h> +#include <asm/cpacf.h> +#include <asm/interrupt.h> static inline void __test_spm_ipm (uint8_t cc,uint8_t key) {
@@ -41,11 +43,236 @@ static void test_spm_ipm(void)__test_spm_ipm (0 ,0 ); } +static inline void __test_cpacf (unsigned int opcode,unsigned long func, +unsigned int r1,unsigned int r2, +unsigned int r3) +{ + register unsigned long gr0 asm("0") = func; +cpacf_mask_t mask; + register unsigned long gr1 asm("1") = (unsigned long)&mask; + + asmvolatile (".insn rrf,%[opc] << 16,%[r1],%[r2],%[r3],0\n" + : :"d" (gr0),"d" (gr1), [opc]"i" (opcode), + [r1]"i" (r1), [r2]"i" (r2), [r3]"i" (r3)); +} + +static inline void __test_cpacf_r1_odd (unsigned int opcode) +{ +report_prefix_push ("r1 odd" ); +expect_pgm_int (); +__test_cpacf (opcode,0 ,1 ,4 ,6 ); +check_pgm_int_code (PGM_INT_CODE_SPECIFICATION ); +report_prefix_pop (); +} + +static inline void __test_cpacf_r1_null (unsigned int opcode) +{ +report_prefix_push ("r1 null" ); +expect_pgm_int (); +__test_cpacf (opcode,0 ,0 ,4 ,6 ); +check_pgm_int_code (PGM_INT_CODE_SPECIFICATION ); +report_prefix_pop (); +} + +static inline void __test_cpacf_r2_odd (unsigned int opcode) +{ +report_prefix_push ("r2 odd" ); +expect_pgm_int (); +__test_cpacf (opcode,0 ,2 ,3 ,6 ); +check_pgm_int_code (PGM_INT_CODE_SPECIFICATION ); +report_prefix_pop (); +} + +static inline void __test_cpacf_r2_null (unsigned int opcode) +{ +report_prefix_push ("r2 null" ); +expect_pgm_int (); +__test_cpacf (opcode,0 ,2 ,0 ,6 ); +check_pgm_int_code (PGM_INT_CODE_SPECIFICATION ); +report_prefix_pop (); +} + +static inline void __test_cpacf_r3_odd (unsigned int opcode) +{ +report_prefix_push ("r3 odd" ); +expect_pgm_int (); +__test_cpacf (opcode,0 ,2 ,4 ,5 ); +check_pgm_int_code (PGM_INT_CODE_SPECIFICATION ); +report_prefix_pop (); +} + +static inline void __test_cpacf_r3_null (unsigned int opcode) +{ +report_prefix_push ("r3 null" ); +expect_pgm_int (); +__test_cpacf (opcode,0 ,2 ,4 ,0 ); +check_pgm_int_code (PGM_INT_CODE_SPECIFICATION ); +report_prefix_pop (); +} + +static inline void __test_cpacf_mod_bit (unsigned int opcode) +{ +report_prefix_push ("mod bit" ); +expect_pgm_int (); +__test_cpacf (opcode,CPACF_DECRYPT ,2 ,4 ,6 ); +check_pgm_int_code (PGM_INT_CODE_SPECIFICATION ); +report_prefix_pop (); +} + +static inline void __test_cpacf_invalid_func (unsigned int opcode) +{ +report_prefix_push ("invalid subfunction" ); +expect_pgm_int (); +/* 127 is unassigned for now. We don't simply use any, as HW +* might simply mask valid codes in query but they might still work */ +if (cpacf_query_func (opcode,127 )) { +report_skip ("127 not invalid" ); + }else { +__test_cpacf (opcode,127 ,2 ,4 ,6 ); + } +check_pgm_int_code (PGM_INT_CODE_SPECIFICATION ); +report_prefix_pop (); +} + +static inline void __test_cpacf_invalid_parm (unsigned int opcode) +{ +report_prefix_push ("invalid parm address" ); +expect_pgm_int (); +__cpacf_query (opcode, (void *)-1 ); +check_pgm_int_code (PGM_INT_CODE_ADDRESSING ); +report_prefix_pop (); +} + +static inline void __test_cpacf_protected_parm (unsigned int opcode) +{ +report_prefix_push ("protected parm address" ); +expect_pgm_int (); +low_prot_enable (); +__cpacf_query (opcode, (void *)8 ); +low_prot_disable (); +check_pgm_int_code (PGM_INT_CODE_PROTECTION ); +report_prefix_pop (); +} + +static inline void __test_basic_cpacf_opcode (unsigned int opcode) +{ +bool mod_bit_allowed = false; + +if (!__cpacf_check_opcode (opcode)) { +report_skip ("not available" ); +return ; + } +report ("query indicated in query" ,cpacf_query_func (opcode,0 )); + +switch (opcode) { +case CPACF_KMCTR : +__test_cpacf_r3_odd (opcode); +__test_cpacf_r3_null (opcode); +/* FALL THROUGH */ +case CPACF_PRNO : +case CPACF_KMF : +case CPACF_KMC : +case CPACF_KMO : +case CPACF_KM : +__test_cpacf_r1_odd (opcode); +__test_cpacf_r1_null (opcode); + mod_bit_allowed = true; +/* FALL THROUGH */ +case CPACF_KMAC : +case CPACF_KIMD : +case CPACF_KLMD : +__test_cpacf_r2_odd (opcode); +__test_cpacf_r2_null (opcode); +break ; + } +if (!mod_bit_allowed) +__test_cpacf_mod_bit (opcode); +__test_cpacf_invalid_func (opcode); +__test_cpacf_invalid_parm (opcode); +__test_cpacf_protected_parm (opcode); +} + +/* COMPUTE MESSAGE AUTHENTICATION CODE */ +static void test_kmac (void ) +{ +__test_basic_cpacf_opcode (CPACF_KMAC ); +} + +/* CIPHER MESSAGE */ +static void test_km (void ) +{ +__test_basic_cpacf_opcode (CPACF_KM ); +} +/* CIPHER MESSAGE WITH CHAINING */ +static void test_kmc (void ) +{ +__test_basic_cpacf_opcode (CPACF_KMC ); +} + +/* COMPUTE INTERMEDIATE MESSAGE DIGEST */ +static void test_kimd (void ) +{ +__test_basic_cpacf_opcode (CPACF_KIMD ); +} + +/* COMPUTE LAST MESSAGE DIGEST */ +static void test_klmd (void ) +{ +__test_basic_cpacf_opcode (CPACF_KLMD ); +} + +/* PERFORM CRYPTOGRAPHIC KEY MANAGEMENT OPERATION */ +static void test_pckmo (void ) +{ +__test_basic_cpacf_opcode (CPACF_PCKMO ); +} + +/* CIPHER MESSAGE WITH CIPHER FEEDBACK */ +static void test_kmf (void ) +{ +__test_basic_cpacf_opcode (CPACF_KMF ); +} + +/* PERFORM CRYPTOGRAPHIC KEY MANAGEMENT OPERATION */ +static void test_kmo (void ) +{ +__test_basic_cpacf_opcode (CPACF_KMO ); +} + +/* PERFORM CRYPTOGRAPHIC COMPUTATION */ +static void test_pcc (void ) +{ +__test_basic_cpacf_opcode (CPACF_PCC ); +} + +/* CIPHER MESSAGE WITH COUNTER */ +static void test_kmctr (void ) +{ +__test_basic_cpacf_opcode (CPACF_KMCTR ); +} + +/* PERFORM RANDOM NUMBER OPERATION (formerly PPNO) */ +static void test_prno (void ) +{ +__test_basic_cpacf_opcode (CPACF_PRNO ); +} +static struct {const char *name;void (*func)(void ); } tests[] = { {"spm/ipm" , test_spm_ipm }, + {"kmac" , test_kmac }, + {"km" , test_km }, + {"kmc" , test_kmc }, + {"kimd" , test_kimd }, + {"klmd" , test_klmd }, + {"pckmo" , test_pckmo }, + {"kmf" , test_kmf }, + {"kmo" , test_kmo }, + {"pcc" , test_pcc }, + {"kmctr" , test_kmctr }, + {"prno" , test_prno }, {NULL ,NULL } };
Signature · 1 line
2.13.5
Quoted 22 lines · David Hildenbrand
Developed while working on:
https://lists.gnu.org/archive/html/qemu-devel/2017-09/msg05133.htmlOnly the basics for MSA instructions are tested (basically everything QEMU also implements), but no real en/decryption.
All tests seem to pass under KVM.
For TCG, only the usual low address protection tests fail. To run under TCG, the feature have to be enabled explicitly for now:
./s390x-run s390x/emulator.elf \ -cpu qemu,msa-base=on,msa3-base=on,msa4-base=on,msa5-base=on,stfle=onDavid Hildenbrand (5):
s390x: add a test case for the ipm + spm instructions
s390x: addcpacf.hfrom Linux
s390x: make surecpacf.hcan be used
s390x: query and store STFL(E) facilitites
s390x: test for various MSA instructions
Quoted 11 lines
lib/s390x/asm/cpacf.h | 472 +++++++++++++++++++++++++++++++++++++++++++++++ lib/s390x/asm/facility.h | 48 +++++ lib/s390x/io.c | 3 + s390x/Makefile | 1 + s390x/emulator.c | 292 +++++++++++++++++++++++++++++ s390x/unittests.cfg | 3 + 6 files changed, 819 insertions(+) create mode 100644 lib/s390x/asm/cpacf.h create mode 100644 lib/s390x/asm/facility.h create mode 100644 s390x/emulator.c
Applied, thanks.
Paolo