summaryrefslogtreecommitdiffstats
path: root/lib/crypto/sparc/aes.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/crypto/sparc/aes.h')
-rw-r--r--lib/crypto/sparc/aes.h149
1 files changed, 149 insertions, 0 deletions
diff --git a/lib/crypto/sparc/aes.h b/lib/crypto/sparc/aes.h
new file mode 100644
index 000000000..e354aa507
--- /dev/null
+++ b/lib/crypto/sparc/aes.h
@@ -0,0 +1,149 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * AES accelerated using the sparc64 aes opcodes
+ *
+ * Copyright (C) 2008, Intel Corp.
+ * Copyright (c) 2010, Intel Corporation.
+ * Copyright 2026 Google LLC
+ */
+
+#include <asm/fpumacro.h>
+#include <asm/opcodes.h>
+#include <asm/pstate.h>
+#include <asm/elf.h>
+
+static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_aes_opcodes);
+
+EXPORT_SYMBOL_GPL(aes_sparc64_key_expand);
+EXPORT_SYMBOL_GPL(aes_sparc64_load_encrypt_keys_128);
+EXPORT_SYMBOL_GPL(aes_sparc64_load_encrypt_keys_192);
+EXPORT_SYMBOL_GPL(aes_sparc64_load_encrypt_keys_256);
+EXPORT_SYMBOL_GPL(aes_sparc64_load_decrypt_keys_128);
+EXPORT_SYMBOL_GPL(aes_sparc64_load_decrypt_keys_192);
+EXPORT_SYMBOL_GPL(aes_sparc64_load_decrypt_keys_256);
+EXPORT_SYMBOL_GPL(aes_sparc64_ecb_encrypt_128);
+EXPORT_SYMBOL_GPL(aes_sparc64_ecb_encrypt_192);
+EXPORT_SYMBOL_GPL(aes_sparc64_ecb_encrypt_256);
+EXPORT_SYMBOL_GPL(aes_sparc64_ecb_decrypt_128);
+EXPORT_SYMBOL_GPL(aes_sparc64_ecb_decrypt_192);
+EXPORT_SYMBOL_GPL(aes_sparc64_ecb_decrypt_256);
+EXPORT_SYMBOL_GPL(aes_sparc64_cbc_encrypt_128);
+EXPORT_SYMBOL_GPL(aes_sparc64_cbc_encrypt_192);
+EXPORT_SYMBOL_GPL(aes_sparc64_cbc_encrypt_256);
+EXPORT_SYMBOL_GPL(aes_sparc64_cbc_decrypt_128);
+EXPORT_SYMBOL_GPL(aes_sparc64_cbc_decrypt_192);
+EXPORT_SYMBOL_GPL(aes_sparc64_cbc_decrypt_256);
+EXPORT_SYMBOL_GPL(aes_sparc64_ctr_crypt_128);
+EXPORT_SYMBOL_GPL(aes_sparc64_ctr_crypt_192);
+EXPORT_SYMBOL_GPL(aes_sparc64_ctr_crypt_256);
+
+void aes_sparc64_encrypt_128(const u64 *key, const u32 *input, u32 *output);
+void aes_sparc64_encrypt_192(const u64 *key, const u32 *input, u32 *output);
+void aes_sparc64_encrypt_256(const u64 *key, const u32 *input, u32 *output);
+void aes_sparc64_decrypt_128(const u64 *key, const u32 *input, u32 *output);
+void aes_sparc64_decrypt_192(const u64 *key, const u32 *input, u32 *output);
+void aes_sparc64_decrypt_256(const u64 *key, const u32 *input, u32 *output);
+
+static void aes_preparekey_arch(union aes_enckey_arch *k,
+ union aes_invkey_arch *inv_k,
+ const u8 *in_key, int key_len, int nrounds)
+{
+ if (static_branch_likely(&have_aes_opcodes)) {
+ u32 aligned_key[AES_MAX_KEY_SIZE / 4];
+
+ if (IS_ALIGNED((uintptr_t)in_key, 4)) {
+ aes_sparc64_key_expand((const u32 *)in_key,
+ k->sparc_rndkeys, key_len);
+ } else {
+ memcpy(aligned_key, in_key, key_len);
+ aes_sparc64_key_expand(aligned_key,
+ k->sparc_rndkeys, key_len);
+ memzero_explicit(aligned_key, key_len);
+ }
+ /*
+ * Note that nothing needs to be written to inv_k (if it's
+ * non-NULL) here, since the SPARC64 assembly code uses
+ * k->sparc_rndkeys for both encryption and decryption.
+ */
+ } else {
+ aes_expandkey_generic(k->rndkeys,
+ inv_k ? inv_k->inv_rndkeys : NULL,
+ in_key, key_len);
+ }
+}
+
+static void aes_sparc64_encrypt(const struct aes_enckey *key,
+ const u32 *input, u32 *output)
+{
+ if (key->len == AES_KEYSIZE_128)
+ aes_sparc64_encrypt_128(key->k.sparc_rndkeys, input, output);
+ else if (key->len == AES_KEYSIZE_192)
+ aes_sparc64_encrypt_192(key->k.sparc_rndkeys, input, output);
+ else
+ aes_sparc64_encrypt_256(key->k.sparc_rndkeys, input, output);
+}
+
+static void aes_encrypt_arch(const struct aes_enckey *key,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ u32 bounce_buf[AES_BLOCK_SIZE / 4];
+
+ if (static_branch_likely(&have_aes_opcodes)) {
+ if (IS_ALIGNED((uintptr_t)in | (uintptr_t)out, 4)) {
+ aes_sparc64_encrypt(key, (const u32 *)in, (u32 *)out);
+ } else {
+ memcpy(bounce_buf, in, AES_BLOCK_SIZE);
+ aes_sparc64_encrypt(key, bounce_buf, bounce_buf);
+ memcpy(out, bounce_buf, AES_BLOCK_SIZE);
+ }
+ } else {
+ aes_encrypt_generic(key->k.rndkeys, key->nrounds, out, in);
+ }
+}
+
+static void aes_sparc64_decrypt(const struct aes_key *key,
+ const u32 *input, u32 *output)
+{
+ if (key->len == AES_KEYSIZE_128)
+ aes_sparc64_decrypt_128(key->k.sparc_rndkeys, input, output);
+ else if (key->len == AES_KEYSIZE_192)
+ aes_sparc64_decrypt_192(key->k.sparc_rndkeys, input, output);
+ else
+ aes_sparc64_decrypt_256(key->k.sparc_rndkeys, input, output);
+}
+
+static void aes_decrypt_arch(const struct aes_key *key,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ u32 bounce_buf[AES_BLOCK_SIZE / 4];
+
+ if (static_branch_likely(&have_aes_opcodes)) {
+ if (IS_ALIGNED((uintptr_t)in | (uintptr_t)out, 4)) {
+ aes_sparc64_decrypt(key, (const u32 *)in, (u32 *)out);
+ } else {
+ memcpy(bounce_buf, in, AES_BLOCK_SIZE);
+ aes_sparc64_decrypt(key, bounce_buf, bounce_buf);
+ memcpy(out, bounce_buf, AES_BLOCK_SIZE);
+ }
+ } else {
+ aes_decrypt_generic(key->inv_k.inv_rndkeys, key->nrounds,
+ out, in);
+ }
+}
+
+#define aes_mod_init_arch aes_mod_init_arch
+static void aes_mod_init_arch(void)
+{
+ unsigned long cfr;
+
+ if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO))
+ return;
+
+ __asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr));
+ if (!(cfr & CFR_AES))
+ return;
+
+ static_branch_enable(&have_aes_opcodes);
+}