18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* Glue code for SHA1 hashing optimized for sparc64 crypto opcodes. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This is based largely upon arch/x86/crypto/sha1_ssse3_glue.c 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (c) Alan Smithee. 78c2ecf20Sopenharmony_ci * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk> 88c2ecf20Sopenharmony_ci * Copyright (c) Jean-Francois Dive <jef@linuxbe.org> 98c2ecf20Sopenharmony_ci * Copyright (c) Mathias Krause <minipli@googlemail.com> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h> 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/mm.h> 188c2ecf20Sopenharmony_ci#include <linux/types.h> 198c2ecf20Sopenharmony_ci#include <crypto/sha.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <asm/pstate.h> 228c2ecf20Sopenharmony_ci#include <asm/elf.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "opcodes.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ciasmlinkage void sha1_sparc64_transform(u32 *digest, const char *data, 278c2ecf20Sopenharmony_ci unsigned int rounds); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic int sha1_sparc64_init(struct shash_desc *desc) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci struct sha1_state *sctx = shash_desc_ctx(desc); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci *sctx = (struct sha1_state){ 348c2ecf20Sopenharmony_ci .state = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 }, 358c2ecf20Sopenharmony_ci }; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci return 0; 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic void __sha1_sparc64_update(struct sha1_state *sctx, const u8 *data, 418c2ecf20Sopenharmony_ci unsigned int len, unsigned int partial) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci unsigned int done = 0; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci sctx->count += len; 468c2ecf20Sopenharmony_ci if (partial) { 478c2ecf20Sopenharmony_ci done = SHA1_BLOCK_SIZE - partial; 488c2ecf20Sopenharmony_ci memcpy(sctx->buffer + partial, data, done); 498c2ecf20Sopenharmony_ci sha1_sparc64_transform(sctx->state, sctx->buffer, 1); 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci if (len - done >= SHA1_BLOCK_SIZE) { 528c2ecf20Sopenharmony_ci const unsigned int rounds = (len - done) / SHA1_BLOCK_SIZE; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci sha1_sparc64_transform(sctx->state, data + done, rounds); 558c2ecf20Sopenharmony_ci done += rounds * SHA1_BLOCK_SIZE; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci memcpy(sctx->buffer, data + done, len - done); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic int sha1_sparc64_update(struct shash_desc *desc, const u8 *data, 628c2ecf20Sopenharmony_ci unsigned int len) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct sha1_state *sctx = shash_desc_ctx(desc); 658c2ecf20Sopenharmony_ci unsigned int partial = sctx->count % SHA1_BLOCK_SIZE; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci /* Handle the fast case right here */ 688c2ecf20Sopenharmony_ci if (partial + len < SHA1_BLOCK_SIZE) { 698c2ecf20Sopenharmony_ci sctx->count += len; 708c2ecf20Sopenharmony_ci memcpy(sctx->buffer + partial, data, len); 718c2ecf20Sopenharmony_ci } else 728c2ecf20Sopenharmony_ci __sha1_sparc64_update(sctx, data, len, partial); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* Add padding and return the message digest. */ 788c2ecf20Sopenharmony_cistatic int sha1_sparc64_final(struct shash_desc *desc, u8 *out) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct sha1_state *sctx = shash_desc_ctx(desc); 818c2ecf20Sopenharmony_ci unsigned int i, index, padlen; 828c2ecf20Sopenharmony_ci __be32 *dst = (__be32 *)out; 838c2ecf20Sopenharmony_ci __be64 bits; 848c2ecf20Sopenharmony_ci static const u8 padding[SHA1_BLOCK_SIZE] = { 0x80, }; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci bits = cpu_to_be64(sctx->count << 3); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* Pad out to 56 mod 64 and append length */ 898c2ecf20Sopenharmony_ci index = sctx->count % SHA1_BLOCK_SIZE; 908c2ecf20Sopenharmony_ci padlen = (index < 56) ? (56 - index) : ((SHA1_BLOCK_SIZE+56) - index); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci /* We need to fill a whole block for __sha1_sparc64_update() */ 938c2ecf20Sopenharmony_ci if (padlen <= 56) { 948c2ecf20Sopenharmony_ci sctx->count += padlen; 958c2ecf20Sopenharmony_ci memcpy(sctx->buffer + index, padding, padlen); 968c2ecf20Sopenharmony_ci } else { 978c2ecf20Sopenharmony_ci __sha1_sparc64_update(sctx, padding, padlen, index); 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci __sha1_sparc64_update(sctx, (const u8 *)&bits, sizeof(bits), 56); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* Store state in digest */ 1028c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) 1038c2ecf20Sopenharmony_ci dst[i] = cpu_to_be32(sctx->state[i]); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* Wipe context */ 1068c2ecf20Sopenharmony_ci memset(sctx, 0, sizeof(*sctx)); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci return 0; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic int sha1_sparc64_export(struct shash_desc *desc, void *out) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct sha1_state *sctx = shash_desc_ctx(desc); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci memcpy(out, sctx, sizeof(*sctx)); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return 0; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic int sha1_sparc64_import(struct shash_desc *desc, const void *in) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci struct sha1_state *sctx = shash_desc_ctx(desc); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci memcpy(sctx, in, sizeof(*sctx)); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci return 0; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic struct shash_alg alg = { 1308c2ecf20Sopenharmony_ci .digestsize = SHA1_DIGEST_SIZE, 1318c2ecf20Sopenharmony_ci .init = sha1_sparc64_init, 1328c2ecf20Sopenharmony_ci .update = sha1_sparc64_update, 1338c2ecf20Sopenharmony_ci .final = sha1_sparc64_final, 1348c2ecf20Sopenharmony_ci .export = sha1_sparc64_export, 1358c2ecf20Sopenharmony_ci .import = sha1_sparc64_import, 1368c2ecf20Sopenharmony_ci .descsize = sizeof(struct sha1_state), 1378c2ecf20Sopenharmony_ci .statesize = sizeof(struct sha1_state), 1388c2ecf20Sopenharmony_ci .base = { 1398c2ecf20Sopenharmony_ci .cra_name = "sha1", 1408c2ecf20Sopenharmony_ci .cra_driver_name= "sha1-sparc64", 1418c2ecf20Sopenharmony_ci .cra_priority = SPARC_CR_OPCODE_PRIORITY, 1428c2ecf20Sopenharmony_ci .cra_blocksize = SHA1_BLOCK_SIZE, 1438c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci}; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic bool __init sparc64_has_sha1_opcode(void) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci unsigned long cfr; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO)) 1528c2ecf20Sopenharmony_ci return false; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci __asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr)); 1558c2ecf20Sopenharmony_ci if (!(cfr & CFR_SHA1)) 1568c2ecf20Sopenharmony_ci return false; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci return true; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic int __init sha1_sparc64_mod_init(void) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci if (sparc64_has_sha1_opcode()) { 1648c2ecf20Sopenharmony_ci pr_info("Using sparc64 sha1 opcode optimized SHA-1 implementation\n"); 1658c2ecf20Sopenharmony_ci return crypto_register_shash(&alg); 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci pr_info("sparc64 sha1 opcode not available.\n"); 1688c2ecf20Sopenharmony_ci return -ENODEV; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic void __exit sha1_sparc64_mod_fini(void) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci crypto_unregister_shash(&alg); 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cimodule_init(sha1_sparc64_mod_init); 1778c2ecf20Sopenharmony_cimodule_exit(sha1_sparc64_mod_fini); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1808c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SHA1 Secure Hash Algorithm, sparc64 sha1 opcode accelerated"); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("sha1"); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci#include "crop_devid.c" 185