summaryrefslogtreecommitdiff
path: root/fat-s390x.c
diff options
context:
space:
mode:
Diffstat (limited to 'fat-s390x.c')
-rw-r--r--fat-s390x.c385
1 files changed, 385 insertions, 0 deletions
diff --git a/fat-s390x.c b/fat-s390x.c
new file mode 100644
index 00000000..690b6013
--- /dev/null
+++ b/fat-s390x.c
@@ -0,0 +1,385 @@
+/* fat-s390x.c
+
+ Copyright (C) 2020 Mamone Tarsha
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#define _GNU_SOURCE
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
+# if __GLIBC_PREREQ(2, 16)
+# define USE_GETAUXVAL 1
+# include <sys/auxv.h>
+# endif
+#endif
+
+#include "nettle-types.h"
+
+#include "aes.h"
+#include "gcm.h"
+#include "gcm-internal.h"
+#include "fat-setup.h"
+
+/* Max number of doublewords returned by STFLE */
+#define FACILITY_DOUBLEWORDS_MAX 3
+#define FACILITY_INDEX(bit) ((bit) / 64)
+/* STFLE and cipher query store doublewords as bit-reversed.
+ reverse facility bit or function code in doubleword */
+#define FACILITY_BIT(bit) (1ULL << (63 - (bit) % 64))
+
+/* Define from arch/s390/include/asm/elf.h in Linux kernel */
+#ifndef HWCAP_S390_STFLE
+#define HWCAP_S390_STFLE 4
+#endif
+
+/* Facility bits */
+#define FAC_MSA 17 /* message-security assist */
+#define FAC_MSA_X4 77 /* message-security-assist extension 4 */
+
+/* Function codes */
+#define AES_128_CODE 18
+#define AES_192_CODE 19
+#define AES_256_CODE 20
+#define GHASH_CODE 65
+
+struct s390x_features
+{
+ int have_km_aes128;
+ int have_km_aes192;
+ int have_km_aes256;
+ int have_kmid_ghash;
+};
+
+#define MATCH(s, slen, literal, llen) \
+ ((slen) == (llen) && memcmp ((s), (literal), llen) == 0)
+
+static void
+get_s390x_features (struct s390x_features *features)
+{
+ features->have_km_aes128 = 0;
+ features->have_km_aes192 = 0;
+ features->have_km_aes256 = 0;
+ features->have_kmid_ghash = 0;
+
+ const char *s = secure_getenv (ENV_OVERRIDE);
+ if (s)
+ for (;;)
+ {
+ const char *sep = strchr (s, ',');
+ size_t length = sep ? (size_t) (sep - s) : strlen(s);
+
+ if (MATCH (s, length, "msa_x1", 6))
+ {
+ features->have_km_aes128 = 1;
+ }
+ else if (MATCH (s, length, "msa_x2", 6))
+ {
+ features->have_km_aes192 = 1;
+ features->have_km_aes256 = 1;
+ }
+ else if (MATCH (s, length, "msa_x4", 6))
+ {
+ features->have_kmid_ghash = 1;
+ }
+ if (!sep)
+ break;
+ s = sep + 1;
+ }
+ else
+ {
+#if USE_GETAUXVAL
+ unsigned long hwcap = getauxval(AT_HWCAP);
+ if (hwcap & HWCAP_S390_STFLE)
+ {
+ uint64_t facilities[FACILITY_DOUBLEWORDS_MAX] = {0};
+
+ register uint64_t gr0 asm("0") = FACILITY_DOUBLEWORDS_MAX - 1;
+ asm volatile(
+ ".insn s,0xb2b00000,%1" /* stfle */
+ : "+d"(gr0), "=Q"(facilities)
+ :
+ : "cc");
+
+ if (facilities[FACILITY_INDEX(FAC_MSA)] & FACILITY_BIT(FAC_MSA))
+ {
+ uint64_t query_status[2] = {0};
+ register uint64_t *query_status_addr asm("1") = query_status;
+ asm volatile(
+ "lghi 0,0\n\t"
+ ".long 0xb92e0022" /* km %r2,%r2. Operands are ignored */
+ :
+ : "a"(query_status_addr)
+ : "memory", "cc", "r0");
+ if (query_status[FACILITY_INDEX(AES_128_CODE)] & FACILITY_BIT(AES_128_CODE))
+ features->have_km_aes128 = 1;
+ if (query_status[FACILITY_INDEX(AES_192_CODE)] & FACILITY_BIT(AES_192_CODE))
+ features->have_km_aes192 = 1;
+ if (query_status[FACILITY_INDEX(AES_256_CODE)] & FACILITY_BIT(AES_256_CODE))
+ features->have_km_aes256 = 1;
+ }
+
+ if (facilities[FACILITY_INDEX(FAC_MSA_X4)] & FACILITY_BIT(FAC_MSA_X4))
+ {
+ uint64_t query_status[2] = {0};
+ register uint64_t *query_status_addr asm("1") = query_status;
+ asm volatile(
+ "lghi 0,0\n\t"
+ ".long 0xb93e0002" /* kimd %r0,%r2. Operands are ignored */
+ :
+ : "a"(query_status_addr)
+ : "memory", "cc", "r0");
+ if (query_status[FACILITY_INDEX(GHASH_CODE)] & FACILITY_BIT(GHASH_CODE))
+ features->have_kmid_ghash = 1;
+ }
+ }
+#endif
+ }
+}
+
+/* AES128 */
+DECLARE_FAT_FUNC(nettle_aes128_set_encrypt_key, aes128_set_key_func)
+DECLARE_FAT_FUNC_VAR(aes128_set_encrypt_key, aes128_set_key_func, c)
+DECLARE_FAT_FUNC_VAR(aes128_set_encrypt_key, aes128_set_key_func, s390x)
+DECLARE_FAT_FUNC(nettle_aes128_set_decrypt_key, aes128_set_key_func)
+DECLARE_FAT_FUNC_VAR(aes128_set_decrypt_key, aes128_set_key_func, c)
+DECLARE_FAT_FUNC_VAR(aes128_set_decrypt_key, aes128_set_key_func, s390x)
+DECLARE_FAT_FUNC(nettle_aes128_invert_key, aes128_invert_key_func)
+DECLARE_FAT_FUNC_VAR(aes128_invert_key, aes128_invert_key_func, c)
+DECLARE_FAT_FUNC_VAR(aes128_invert_key, aes128_invert_key_func, s390x)
+DECLARE_FAT_FUNC(nettle_aes128_encrypt, aes128_crypt_func)
+DECLARE_FAT_FUNC_VAR(aes128_encrypt, aes128_crypt_func, c)
+DECLARE_FAT_FUNC_VAR(aes128_encrypt, aes128_crypt_func, s390x)
+DECLARE_FAT_FUNC(nettle_aes128_decrypt, aes128_crypt_func)
+DECLARE_FAT_FUNC_VAR(aes128_decrypt, aes128_crypt_func, c)
+DECLARE_FAT_FUNC_VAR(aes128_decrypt, aes128_crypt_func, s390x)
+
+/* AES192 */
+DECLARE_FAT_FUNC(nettle_aes192_set_encrypt_key, aes192_set_key_func)
+DECLARE_FAT_FUNC_VAR(aes192_set_encrypt_key, aes192_set_key_func, c)
+DECLARE_FAT_FUNC_VAR(aes192_set_encrypt_key, aes192_set_key_func, s390x)
+DECLARE_FAT_FUNC(nettle_aes192_set_decrypt_key, aes192_set_key_func)
+DECLARE_FAT_FUNC_VAR(aes192_set_decrypt_key, aes192_set_key_func, c)
+DECLARE_FAT_FUNC_VAR(aes192_set_decrypt_key, aes192_set_key_func, s390x)
+DECLARE_FAT_FUNC(nettle_aes192_invert_key, aes192_invert_key_func)
+DECLARE_FAT_FUNC_VAR(aes192_invert_key, aes192_invert_key_func, c)
+DECLARE_FAT_FUNC_VAR(aes192_invert_key, aes192_invert_key_func, s390x)
+DECLARE_FAT_FUNC(nettle_aes192_encrypt, aes192_crypt_func)
+DECLARE_FAT_FUNC_VAR(aes192_encrypt, aes192_crypt_func, c)
+DECLARE_FAT_FUNC_VAR(aes192_encrypt, aes192_crypt_func, s390x)
+DECLARE_FAT_FUNC(nettle_aes192_decrypt, aes192_crypt_func)
+DECLARE_FAT_FUNC_VAR(aes192_decrypt, aes192_crypt_func, c)
+DECLARE_FAT_FUNC_VAR(aes192_decrypt, aes192_crypt_func, s390x)
+
+/* AES256 */
+DECLARE_FAT_FUNC(nettle_aes256_set_encrypt_key, aes256_set_key_func)
+DECLARE_FAT_FUNC_VAR(aes256_set_encrypt_key, aes256_set_key_func, c)
+DECLARE_FAT_FUNC_VAR(aes256_set_encrypt_key, aes256_set_key_func, s390x)
+DECLARE_FAT_FUNC(nettle_aes256_set_decrypt_key, aes256_set_key_func)
+DECLARE_FAT_FUNC_VAR(aes256_set_decrypt_key, aes256_set_key_func, c)
+DECLARE_FAT_FUNC_VAR(aes256_set_decrypt_key, aes256_set_key_func, s390x)
+DECLARE_FAT_FUNC(nettle_aes256_invert_key, aes256_invert_key_func)
+DECLARE_FAT_FUNC_VAR(aes256_invert_key, aes256_invert_key_func, c)
+DECLARE_FAT_FUNC_VAR(aes256_invert_key, aes256_invert_key_func, s390x)
+DECLARE_FAT_FUNC(nettle_aes256_encrypt, aes256_crypt_func)
+DECLARE_FAT_FUNC_VAR(aes256_encrypt, aes256_crypt_func, c)
+DECLARE_FAT_FUNC_VAR(aes256_encrypt, aes256_crypt_func, s390x)
+DECLARE_FAT_FUNC(nettle_aes256_decrypt, aes256_crypt_func)
+DECLARE_FAT_FUNC_VAR(aes256_decrypt, aes256_crypt_func, c)
+DECLARE_FAT_FUNC_VAR(aes256_decrypt, aes256_crypt_func, s390x)
+
+/* GHASH */
+#if GCM_TABLE_BITS == 8
+DECLARE_FAT_FUNC(_nettle_gcm_init_key, gcm_init_key_func)
+DECLARE_FAT_FUNC_VAR(gcm_init_key, gcm_init_key_func, c)
+DECLARE_FAT_FUNC_VAR(gcm_init_key, gcm_init_key_func, s390x)
+
+DECLARE_FAT_FUNC(_nettle_gcm_hash, gcm_hash_func)
+DECLARE_FAT_FUNC_VAR(gcm_hash, gcm_hash_func, c)
+DECLARE_FAT_FUNC_VAR(gcm_hash, gcm_hash_func, s390x)
+#endif /* GCM_TABLE_BITS == 8 */
+
+static void CONSTRUCTOR
+fat_init (void)
+{
+ struct s390x_features features;
+ int verbose;
+
+ get_s390x_features (&features);
+ verbose = getenv (ENV_VERBOSE) != NULL;
+
+ /* AES128 */
+ if (features.have_km_aes128)
+ {
+ if (verbose)
+ fprintf (stderr, "libnettle: enabling hardware accelerated AES128 EBC mode.\n");
+ nettle_aes128_set_encrypt_key_vec = _nettle_aes128_set_encrypt_key_s390x;
+ nettle_aes128_set_decrypt_key_vec = _nettle_aes128_set_decrypt_key_s390x;
+ nettle_aes128_invert_key_vec = _nettle_aes128_invert_key_s390x;
+ nettle_aes128_encrypt_vec = _nettle_aes128_encrypt_s390x;
+ nettle_aes128_decrypt_vec = _nettle_aes128_decrypt_s390x;
+ }
+ else
+ {
+ nettle_aes128_set_encrypt_key_vec = _nettle_aes128_set_encrypt_key_c;
+ nettle_aes128_set_decrypt_key_vec = _nettle_aes128_set_decrypt_key_c;
+ nettle_aes128_invert_key_vec = _nettle_aes128_invert_key_c;
+ nettle_aes128_encrypt_vec = _nettle_aes128_encrypt_c;
+ nettle_aes128_decrypt_vec = _nettle_aes128_decrypt_c;
+ }
+
+ /* AES192 */
+ if (features.have_km_aes192)
+ {
+ if (verbose)
+ fprintf (stderr, "libnettle: enabling hardware accelerated AES192 EBC mode.\n");
+ nettle_aes192_set_encrypt_key_vec = _nettle_aes192_set_encrypt_key_s390x;
+ nettle_aes192_set_decrypt_key_vec = _nettle_aes192_set_decrypt_key_s390x;
+ nettle_aes192_invert_key_vec = _nettle_aes192_invert_key_s390x;
+ nettle_aes192_encrypt_vec = _nettle_aes192_encrypt_s390x;
+ nettle_aes192_decrypt_vec = _nettle_aes192_decrypt_s390x;
+ }
+ else
+ {
+ nettle_aes192_set_encrypt_key_vec = _nettle_aes192_set_encrypt_key_c;
+ nettle_aes192_set_decrypt_key_vec = _nettle_aes192_set_decrypt_key_c;
+ nettle_aes192_invert_key_vec = _nettle_aes192_invert_key_c;
+ nettle_aes192_encrypt_vec = _nettle_aes192_encrypt_c;
+ nettle_aes192_decrypt_vec = _nettle_aes192_decrypt_c;
+ }
+
+ /* AES256 */
+ if (features.have_km_aes256)
+ {
+ if (verbose)
+ fprintf (stderr, "libnettle: enabling hardware accelerated AES256 EBC mode.\n");
+ nettle_aes256_set_encrypt_key_vec = _nettle_aes256_set_encrypt_key_s390x;
+ nettle_aes256_set_decrypt_key_vec = _nettle_aes256_set_decrypt_key_s390x;
+ nettle_aes256_invert_key_vec = _nettle_aes256_invert_key_s390x;
+ nettle_aes256_encrypt_vec = _nettle_aes256_encrypt_s390x;
+ nettle_aes256_decrypt_vec = _nettle_aes256_decrypt_s390x;
+ }
+ else
+ {
+ nettle_aes256_set_encrypt_key_vec = _nettle_aes256_set_encrypt_key_c;
+ nettle_aes256_set_decrypt_key_vec = _nettle_aes256_set_decrypt_key_c;
+ nettle_aes256_invert_key_vec = _nettle_aes256_invert_key_c;
+ nettle_aes256_encrypt_vec = _nettle_aes256_encrypt_c;
+ nettle_aes256_decrypt_vec = _nettle_aes256_decrypt_c;
+ }
+
+ /* GHASH */
+ if (features.have_kmid_ghash)
+ {
+ if (verbose)
+ fprintf (stderr, "libnettle: enabling hardware accelerated GHASH.\n");
+ _nettle_gcm_init_key_vec = _nettle_gcm_init_key_s390x;
+ _nettle_gcm_hash_vec = _nettle_gcm_hash_s390x;
+ }
+ else
+ {
+ _nettle_gcm_init_key_vec = _nettle_gcm_init_key_c;
+ _nettle_gcm_hash_vec = _nettle_gcm_hash_c;
+ }
+}
+
+/* AES128 */
+DEFINE_FAT_FUNC(nettle_aes128_set_encrypt_key, void,
+ (struct aes128_ctx *ctx, const uint8_t *key),
+ (ctx, key))
+DEFINE_FAT_FUNC(nettle_aes128_set_decrypt_key, void,
+ (struct aes128_ctx *ctx, const uint8_t *key),
+ (ctx, key))
+DEFINE_FAT_FUNC(nettle_aes128_invert_key, void,
+ (struct aes128_ctx *dst, const struct aes128_ctx *src),
+ (dst, src))
+DEFINE_FAT_FUNC(nettle_aes128_encrypt, void,
+ (const struct aes128_ctx *ctx, size_t length,
+ uint8_t *dst,const uint8_t *src),
+ (ctx, length, dst, src))
+DEFINE_FAT_FUNC(nettle_aes128_decrypt, void,
+ (const struct aes128_ctx *ctx, size_t length,
+ uint8_t *dst,const uint8_t *src),
+ (ctx, length, dst, src))
+
+/* AES192 */
+DEFINE_FAT_FUNC(nettle_aes192_set_encrypt_key, void,
+ (struct aes192_ctx *ctx, const uint8_t *key),
+ (ctx, key))
+DEFINE_FAT_FUNC(nettle_aes192_set_decrypt_key, void,
+ (struct aes192_ctx *ctx, const uint8_t *key),
+ (ctx, key))
+DEFINE_FAT_FUNC(nettle_aes192_invert_key, void,
+ (struct aes192_ctx *dst, const struct aes192_ctx *src),
+ (dst, src))
+DEFINE_FAT_FUNC(nettle_aes192_encrypt, void,
+ (const struct aes192_ctx *ctx, size_t length,
+ uint8_t *dst,const uint8_t *src),
+ (ctx, length, dst, src))
+DEFINE_FAT_FUNC(nettle_aes192_decrypt, void,
+ (const struct aes192_ctx *ctx, size_t length,
+ uint8_t *dst,const uint8_t *src),
+ (ctx, length, dst, src))
+
+/* AES256 */
+DEFINE_FAT_FUNC(nettle_aes256_set_encrypt_key, void,
+ (struct aes256_ctx *ctx, const uint8_t *key),
+ (ctx, key))
+DEFINE_FAT_FUNC(nettle_aes256_set_decrypt_key, void,
+ (struct aes256_ctx *ctx, const uint8_t *key),
+ (ctx, key))
+DEFINE_FAT_FUNC(nettle_aes256_invert_key, void,
+ (struct aes256_ctx *dst, const struct aes256_ctx *src),
+ (dst, src))
+DEFINE_FAT_FUNC(nettle_aes256_encrypt, void,
+ (const struct aes256_ctx *ctx, size_t length,
+ uint8_t *dst,const uint8_t *src),
+ (ctx, length, dst, src))
+DEFINE_FAT_FUNC(nettle_aes256_decrypt, void,
+ (const struct aes256_ctx *ctx, size_t length,
+ uint8_t *dst,const uint8_t *src),
+ (ctx, length, dst, src))
+
+/* GHASH */
+#if GCM_TABLE_BITS == 8
+DEFINE_FAT_FUNC(_nettle_gcm_init_key, void,
+ (union nettle_block16 *table),
+ (table))
+DEFINE_FAT_FUNC(_nettle_gcm_hash, void,
+ (const struct gcm_key *key, union nettle_block16 *x,
+ size_t length, const uint8_t *data),
+ (key, x, length, data))
+#endif /* GCM_TABLE_BITS == 8 */