162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Cryptographic API. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Glue code for the SHA1 Secure Hash Algorithm assembler implementation using 662306a36Sopenharmony_ci * Supplemental SSE3 instructions. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This file is based on sha1_generic.c 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Copyright (c) Alan Smithee. 1162306a36Sopenharmony_ci * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk> 1262306a36Sopenharmony_ci * Copyright (c) Jean-Francois Dive <jef@linuxbe.org> 1362306a36Sopenharmony_ci * Copyright (c) Mathias Krause <minipli@googlemail.com> 1462306a36Sopenharmony_ci * Copyright (c) Chandramouli Narayanan <mouli@linux.intel.com> 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <crypto/internal/hash.h> 2062306a36Sopenharmony_ci#include <crypto/internal/simd.h> 2162306a36Sopenharmony_ci#include <linux/init.h> 2262306a36Sopenharmony_ci#include <linux/module.h> 2362306a36Sopenharmony_ci#include <linux/mm.h> 2462306a36Sopenharmony_ci#include <linux/types.h> 2562306a36Sopenharmony_ci#include <crypto/sha1.h> 2662306a36Sopenharmony_ci#include <crypto/sha1_base.h> 2762306a36Sopenharmony_ci#include <asm/cpu_device_id.h> 2862306a36Sopenharmony_ci#include <asm/simd.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic const struct x86_cpu_id module_cpu_ids[] = { 3162306a36Sopenharmony_ci X86_MATCH_FEATURE(X86_FEATURE_AVX2, NULL), 3262306a36Sopenharmony_ci X86_MATCH_FEATURE(X86_FEATURE_AVX, NULL), 3362306a36Sopenharmony_ci X86_MATCH_FEATURE(X86_FEATURE_SSSE3, NULL), 3462306a36Sopenharmony_ci {} 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(x86cpu, module_cpu_ids); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic int sha1_update(struct shash_desc *desc, const u8 *data, 3962306a36Sopenharmony_ci unsigned int len, sha1_block_fn *sha1_xform) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci struct sha1_state *sctx = shash_desc_ctx(desc); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (!crypto_simd_usable() || 4462306a36Sopenharmony_ci (sctx->count % SHA1_BLOCK_SIZE) + len < SHA1_BLOCK_SIZE) 4562306a36Sopenharmony_ci return crypto_sha1_update(desc, data, len); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci /* 4862306a36Sopenharmony_ci * Make sure struct sha1_state begins directly with the SHA1 4962306a36Sopenharmony_ci * 160-bit internal state, as this is what the asm functions expect. 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ci BUILD_BUG_ON(offsetof(struct sha1_state, state) != 0); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci kernel_fpu_begin(); 5462306a36Sopenharmony_ci sha1_base_do_update(desc, data, len, sha1_xform); 5562306a36Sopenharmony_ci kernel_fpu_end(); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci return 0; 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic int sha1_finup(struct shash_desc *desc, const u8 *data, 6162306a36Sopenharmony_ci unsigned int len, u8 *out, sha1_block_fn *sha1_xform) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci if (!crypto_simd_usable()) 6462306a36Sopenharmony_ci return crypto_sha1_finup(desc, data, len, out); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci kernel_fpu_begin(); 6762306a36Sopenharmony_ci if (len) 6862306a36Sopenharmony_ci sha1_base_do_update(desc, data, len, sha1_xform); 6962306a36Sopenharmony_ci sha1_base_do_finalize(desc, sha1_xform); 7062306a36Sopenharmony_ci kernel_fpu_end(); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci return sha1_base_finish(desc, out); 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ciasmlinkage void sha1_transform_ssse3(struct sha1_state *state, 7662306a36Sopenharmony_ci const u8 *data, int blocks); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic int sha1_ssse3_update(struct shash_desc *desc, const u8 *data, 7962306a36Sopenharmony_ci unsigned int len) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci return sha1_update(desc, data, len, sha1_transform_ssse3); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic int sha1_ssse3_finup(struct shash_desc *desc, const u8 *data, 8562306a36Sopenharmony_ci unsigned int len, u8 *out) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci return sha1_finup(desc, data, len, out, sha1_transform_ssse3); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* Add padding and return the message digest. */ 9162306a36Sopenharmony_cistatic int sha1_ssse3_final(struct shash_desc *desc, u8 *out) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci return sha1_ssse3_finup(desc, NULL, 0, out); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic struct shash_alg sha1_ssse3_alg = { 9762306a36Sopenharmony_ci .digestsize = SHA1_DIGEST_SIZE, 9862306a36Sopenharmony_ci .init = sha1_base_init, 9962306a36Sopenharmony_ci .update = sha1_ssse3_update, 10062306a36Sopenharmony_ci .final = sha1_ssse3_final, 10162306a36Sopenharmony_ci .finup = sha1_ssse3_finup, 10262306a36Sopenharmony_ci .descsize = sizeof(struct sha1_state), 10362306a36Sopenharmony_ci .base = { 10462306a36Sopenharmony_ci .cra_name = "sha1", 10562306a36Sopenharmony_ci .cra_driver_name = "sha1-ssse3", 10662306a36Sopenharmony_ci .cra_priority = 150, 10762306a36Sopenharmony_ci .cra_blocksize = SHA1_BLOCK_SIZE, 10862306a36Sopenharmony_ci .cra_module = THIS_MODULE, 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci}; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic int register_sha1_ssse3(void) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_SSSE3)) 11562306a36Sopenharmony_ci return crypto_register_shash(&sha1_ssse3_alg); 11662306a36Sopenharmony_ci return 0; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic void unregister_sha1_ssse3(void) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_SSSE3)) 12262306a36Sopenharmony_ci crypto_unregister_shash(&sha1_ssse3_alg); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ciasmlinkage void sha1_transform_avx(struct sha1_state *state, 12662306a36Sopenharmony_ci const u8 *data, int blocks); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic int sha1_avx_update(struct shash_desc *desc, const u8 *data, 12962306a36Sopenharmony_ci unsigned int len) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci return sha1_update(desc, data, len, sha1_transform_avx); 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic int sha1_avx_finup(struct shash_desc *desc, const u8 *data, 13562306a36Sopenharmony_ci unsigned int len, u8 *out) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci return sha1_finup(desc, data, len, out, sha1_transform_avx); 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic int sha1_avx_final(struct shash_desc *desc, u8 *out) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci return sha1_avx_finup(desc, NULL, 0, out); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic struct shash_alg sha1_avx_alg = { 14662306a36Sopenharmony_ci .digestsize = SHA1_DIGEST_SIZE, 14762306a36Sopenharmony_ci .init = sha1_base_init, 14862306a36Sopenharmony_ci .update = sha1_avx_update, 14962306a36Sopenharmony_ci .final = sha1_avx_final, 15062306a36Sopenharmony_ci .finup = sha1_avx_finup, 15162306a36Sopenharmony_ci .descsize = sizeof(struct sha1_state), 15262306a36Sopenharmony_ci .base = { 15362306a36Sopenharmony_ci .cra_name = "sha1", 15462306a36Sopenharmony_ci .cra_driver_name = "sha1-avx", 15562306a36Sopenharmony_ci .cra_priority = 160, 15662306a36Sopenharmony_ci .cra_blocksize = SHA1_BLOCK_SIZE, 15762306a36Sopenharmony_ci .cra_module = THIS_MODULE, 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci}; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic bool avx_usable(void) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci if (!cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL)) { 16462306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_AVX)) 16562306a36Sopenharmony_ci pr_info("AVX detected but unusable.\n"); 16662306a36Sopenharmony_ci return false; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci return true; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic int register_sha1_avx(void) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci if (avx_usable()) 17562306a36Sopenharmony_ci return crypto_register_shash(&sha1_avx_alg); 17662306a36Sopenharmony_ci return 0; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic void unregister_sha1_avx(void) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci if (avx_usable()) 18262306a36Sopenharmony_ci crypto_unregister_shash(&sha1_avx_alg); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci#define SHA1_AVX2_BLOCK_OPTSIZE 4 /* optimal 4*64 bytes of SHA1 blocks */ 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ciasmlinkage void sha1_transform_avx2(struct sha1_state *state, 18862306a36Sopenharmony_ci const u8 *data, int blocks); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic bool avx2_usable(void) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci if (avx_usable() && boot_cpu_has(X86_FEATURE_AVX2) 19362306a36Sopenharmony_ci && boot_cpu_has(X86_FEATURE_BMI1) 19462306a36Sopenharmony_ci && boot_cpu_has(X86_FEATURE_BMI2)) 19562306a36Sopenharmony_ci return true; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci return false; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic void sha1_apply_transform_avx2(struct sha1_state *state, 20162306a36Sopenharmony_ci const u8 *data, int blocks) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci /* Select the optimal transform based on data block size */ 20462306a36Sopenharmony_ci if (blocks >= SHA1_AVX2_BLOCK_OPTSIZE) 20562306a36Sopenharmony_ci sha1_transform_avx2(state, data, blocks); 20662306a36Sopenharmony_ci else 20762306a36Sopenharmony_ci sha1_transform_avx(state, data, blocks); 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic int sha1_avx2_update(struct shash_desc *desc, const u8 *data, 21162306a36Sopenharmony_ci unsigned int len) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci return sha1_update(desc, data, len, sha1_apply_transform_avx2); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic int sha1_avx2_finup(struct shash_desc *desc, const u8 *data, 21762306a36Sopenharmony_ci unsigned int len, u8 *out) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci return sha1_finup(desc, data, len, out, sha1_apply_transform_avx2); 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic int sha1_avx2_final(struct shash_desc *desc, u8 *out) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci return sha1_avx2_finup(desc, NULL, 0, out); 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic struct shash_alg sha1_avx2_alg = { 22862306a36Sopenharmony_ci .digestsize = SHA1_DIGEST_SIZE, 22962306a36Sopenharmony_ci .init = sha1_base_init, 23062306a36Sopenharmony_ci .update = sha1_avx2_update, 23162306a36Sopenharmony_ci .final = sha1_avx2_final, 23262306a36Sopenharmony_ci .finup = sha1_avx2_finup, 23362306a36Sopenharmony_ci .descsize = sizeof(struct sha1_state), 23462306a36Sopenharmony_ci .base = { 23562306a36Sopenharmony_ci .cra_name = "sha1", 23662306a36Sopenharmony_ci .cra_driver_name = "sha1-avx2", 23762306a36Sopenharmony_ci .cra_priority = 170, 23862306a36Sopenharmony_ci .cra_blocksize = SHA1_BLOCK_SIZE, 23962306a36Sopenharmony_ci .cra_module = THIS_MODULE, 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci}; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic int register_sha1_avx2(void) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci if (avx2_usable()) 24662306a36Sopenharmony_ci return crypto_register_shash(&sha1_avx2_alg); 24762306a36Sopenharmony_ci return 0; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic void unregister_sha1_avx2(void) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci if (avx2_usable()) 25362306a36Sopenharmony_ci crypto_unregister_shash(&sha1_avx2_alg); 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci#ifdef CONFIG_AS_SHA1_NI 25762306a36Sopenharmony_ciasmlinkage void sha1_ni_transform(struct sha1_state *digest, const u8 *data, 25862306a36Sopenharmony_ci int rounds); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic int sha1_ni_update(struct shash_desc *desc, const u8 *data, 26162306a36Sopenharmony_ci unsigned int len) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci return sha1_update(desc, data, len, sha1_ni_transform); 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic int sha1_ni_finup(struct shash_desc *desc, const u8 *data, 26762306a36Sopenharmony_ci unsigned int len, u8 *out) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci return sha1_finup(desc, data, len, out, sha1_ni_transform); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic int sha1_ni_final(struct shash_desc *desc, u8 *out) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci return sha1_ni_finup(desc, NULL, 0, out); 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic struct shash_alg sha1_ni_alg = { 27862306a36Sopenharmony_ci .digestsize = SHA1_DIGEST_SIZE, 27962306a36Sopenharmony_ci .init = sha1_base_init, 28062306a36Sopenharmony_ci .update = sha1_ni_update, 28162306a36Sopenharmony_ci .final = sha1_ni_final, 28262306a36Sopenharmony_ci .finup = sha1_ni_finup, 28362306a36Sopenharmony_ci .descsize = sizeof(struct sha1_state), 28462306a36Sopenharmony_ci .base = { 28562306a36Sopenharmony_ci .cra_name = "sha1", 28662306a36Sopenharmony_ci .cra_driver_name = "sha1-ni", 28762306a36Sopenharmony_ci .cra_priority = 250, 28862306a36Sopenharmony_ci .cra_blocksize = SHA1_BLOCK_SIZE, 28962306a36Sopenharmony_ci .cra_module = THIS_MODULE, 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci}; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic int register_sha1_ni(void) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_SHA_NI)) 29662306a36Sopenharmony_ci return crypto_register_shash(&sha1_ni_alg); 29762306a36Sopenharmony_ci return 0; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic void unregister_sha1_ni(void) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_SHA_NI)) 30362306a36Sopenharmony_ci crypto_unregister_shash(&sha1_ni_alg); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci#else 30762306a36Sopenharmony_cistatic inline int register_sha1_ni(void) { return 0; } 30862306a36Sopenharmony_cistatic inline void unregister_sha1_ni(void) { } 30962306a36Sopenharmony_ci#endif 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic int __init sha1_ssse3_mod_init(void) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci if (!x86_match_cpu(module_cpu_ids)) 31462306a36Sopenharmony_ci return -ENODEV; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (register_sha1_ssse3()) 31762306a36Sopenharmony_ci goto fail; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci if (register_sha1_avx()) { 32062306a36Sopenharmony_ci unregister_sha1_ssse3(); 32162306a36Sopenharmony_ci goto fail; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (register_sha1_avx2()) { 32562306a36Sopenharmony_ci unregister_sha1_avx(); 32662306a36Sopenharmony_ci unregister_sha1_ssse3(); 32762306a36Sopenharmony_ci goto fail; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (register_sha1_ni()) { 33162306a36Sopenharmony_ci unregister_sha1_avx2(); 33262306a36Sopenharmony_ci unregister_sha1_avx(); 33362306a36Sopenharmony_ci unregister_sha1_ssse3(); 33462306a36Sopenharmony_ci goto fail; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci return 0; 33862306a36Sopenharmony_cifail: 33962306a36Sopenharmony_ci return -ENODEV; 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic void __exit sha1_ssse3_mod_fini(void) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci unregister_sha1_ni(); 34562306a36Sopenharmony_ci unregister_sha1_avx2(); 34662306a36Sopenharmony_ci unregister_sha1_avx(); 34762306a36Sopenharmony_ci unregister_sha1_ssse3(); 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cimodule_init(sha1_ssse3_mod_init); 35162306a36Sopenharmony_cimodule_exit(sha1_ssse3_mod_fini); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 35462306a36Sopenharmony_ciMODULE_DESCRIPTION("SHA1 Secure Hash Algorithm, Supplemental SSE3 accelerated"); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("sha1"); 35762306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("sha1-ssse3"); 35862306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("sha1-avx"); 35962306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("sha1-avx2"); 36062306a36Sopenharmony_ci#ifdef CONFIG_AS_SHA1_NI 36162306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("sha1-ni"); 36262306a36Sopenharmony_ci#endif 363