diff options
author | Harald Freudenberger <freude@linux.ibm.com> | 2024-05-03 12:31:42 +0300 |
---|---|---|
committer | Heiko Carstens <hca@linux.ibm.com> | 2024-05-16 11:17:11 +0300 |
commit | 830999bd7e72f4128b9dfa37090d9fa8120ce323 (patch) | |
tree | 73488ae6d716b685e46d603a03adcbd7213e72ab /arch | |
parent | 24bf80f78e5ad45bc3e0886cef86def712bdf3ed (diff) | |
download | linux-830999bd7e72f4128b9dfa37090d9fa8120ce323.tar.xz |
s390/cpacf: Split and rework cpacf query functions
Rework the cpacf query functions to use the correct RRE
or RRF instruction formats and set register fields within
instructions correctly.
Fixes: 1afd43e0fbba ("s390/crypto: allow to query all known cpacf functions")
Reported-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Suggested-by: Heiko Carstens <hca@linux.ibm.com>
Suggested-by: Juergen Christ <jchrist@linux.ibm.com>
Suggested-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Reviewed-by: Juergen Christ <jchrist@linux.ibm.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/s390/include/asm/cpacf.h | 101 |
1 files changed, 81 insertions, 20 deletions
diff --git a/arch/s390/include/asm/cpacf.h b/arch/s390/include/asm/cpacf.h index b378e2b57ad8..153dc4fcc40a 100644 --- a/arch/s390/include/asm/cpacf.h +++ b/arch/s390/include/asm/cpacf.h @@ -166,28 +166,79 @@ 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 __always_inline void __cpacf_query(unsigned int opcode, cpacf_mask_t *mask) +static __always_inline void __cpacf_query_rre(u32 opc, u8 r1, u8 r2, + cpacf_mask_t *mask) { asm volatile( - " lghi 0,0\n" /* query function */ - " lgr 1,%[mask]\n" - " 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) - : [mask] "d" ((unsigned long)mask), [opc] "i" (opcode) - : "cc", "0", "1"); + " la %%r1,%[mask]\n" + " xgr %%r0,%%r0\n" + " .insn rre,%[opc] << 16,%[r1],%[r2]\n" + : [mask] "=R" (*mask) + : [opc] "i" (opc), + [r1] "i" (r1), [r2] "i" (r2) + : "cc", "r0", "r1"); +} + +static __always_inline void __cpacf_query_rrf(u32 opc, + u8 r1, u8 r2, u8 r3, u8 m4, + cpacf_mask_t *mask) +{ + asm volatile( + " la %%r1,%[mask]\n" + " xgr %%r0,%%r0\n" + " .insn rrf,%[opc] << 16,%[r1],%[r2],%[r3],%[m4]\n" + : [mask] "=R" (*mask) + : [opc] "i" (opc), [r1] "i" (r1), [r2] "i" (r2), + [r3] "i" (r3), [m4] "i" (m4) + : "cc", "r0", "r1"); +} + +static __always_inline void __cpacf_query(unsigned int opcode, + cpacf_mask_t *mask) +{ + switch (opcode) { + case CPACF_KDSA: + __cpacf_query_rre(CPACF_KDSA, 0, 2, mask); + break; + case CPACF_KIMD: + __cpacf_query_rre(CPACF_KIMD, 0, 2, mask); + break; + case CPACF_KLMD: + __cpacf_query_rre(CPACF_KLMD, 0, 2, mask); + break; + case CPACF_KM: + __cpacf_query_rre(CPACF_KM, 2, 4, mask); + break; + case CPACF_KMA: + __cpacf_query_rrf(CPACF_KMA, 2, 4, 6, 0, mask); + break; + case CPACF_KMAC: + __cpacf_query_rre(CPACF_KMAC, 0, 2, mask); + break; + case CPACF_KMC: + __cpacf_query_rre(CPACF_KMC, 2, 4, mask); + break; + case CPACF_KMCTR: + __cpacf_query_rrf(CPACF_KMCTR, 2, 4, 6, 0, mask); + break; + case CPACF_KMF: + __cpacf_query_rre(CPACF_KMF, 2, 4, mask); + break; + case CPACF_KMO: + __cpacf_query_rre(CPACF_KMO, 2, 4, mask); + break; + case CPACF_PCC: + __cpacf_query_rre(CPACF_PCC, 0, 0, mask); + break; + case CPACF_PCKMO: + __cpacf_query_rre(CPACF_PCKMO, 0, 0, mask); + break; + case CPACF_PRNO: + __cpacf_query_rre(CPACF_PRNO, 2, 4, mask); + break; + default: + BUG(); + } } static __always_inline int __cpacf_check_opcode(unsigned int opcode) @@ -215,6 +266,16 @@ static __always_inline int __cpacf_check_opcode(unsigned int opcode) } } +/** + * 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 __always_inline int cpacf_query(unsigned int opcode, cpacf_mask_t *mask) { if (__cpacf_check_opcode(opcode)) { |