18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* Glue code for SHA512 hashing optimized for sparc64 crypto opcodes. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This is based largely upon crypto/sha512_generic.c 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com> 78c2ecf20Sopenharmony_ci * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk> 88c2ecf20Sopenharmony_ci * Copyright (c) 2003 Kyle McMartin <kyle@debian.org> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h> 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/mm.h> 178c2ecf20Sopenharmony_ci#include <linux/types.h> 188c2ecf20Sopenharmony_ci#include <crypto/sha.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <asm/pstate.h> 218c2ecf20Sopenharmony_ci#include <asm/elf.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "opcodes.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ciasmlinkage void sha512_sparc64_transform(u64 *digest, const char *data, 268c2ecf20Sopenharmony_ci unsigned int rounds); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic int sha512_sparc64_init(struct shash_desc *desc) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci struct sha512_state *sctx = shash_desc_ctx(desc); 318c2ecf20Sopenharmony_ci sctx->state[0] = SHA512_H0; 328c2ecf20Sopenharmony_ci sctx->state[1] = SHA512_H1; 338c2ecf20Sopenharmony_ci sctx->state[2] = SHA512_H2; 348c2ecf20Sopenharmony_ci sctx->state[3] = SHA512_H3; 358c2ecf20Sopenharmony_ci sctx->state[4] = SHA512_H4; 368c2ecf20Sopenharmony_ci sctx->state[5] = SHA512_H5; 378c2ecf20Sopenharmony_ci sctx->state[6] = SHA512_H6; 388c2ecf20Sopenharmony_ci sctx->state[7] = SHA512_H7; 398c2ecf20Sopenharmony_ci sctx->count[0] = sctx->count[1] = 0; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci return 0; 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic int sha384_sparc64_init(struct shash_desc *desc) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci struct sha512_state *sctx = shash_desc_ctx(desc); 478c2ecf20Sopenharmony_ci sctx->state[0] = SHA384_H0; 488c2ecf20Sopenharmony_ci sctx->state[1] = SHA384_H1; 498c2ecf20Sopenharmony_ci sctx->state[2] = SHA384_H2; 508c2ecf20Sopenharmony_ci sctx->state[3] = SHA384_H3; 518c2ecf20Sopenharmony_ci sctx->state[4] = SHA384_H4; 528c2ecf20Sopenharmony_ci sctx->state[5] = SHA384_H5; 538c2ecf20Sopenharmony_ci sctx->state[6] = SHA384_H6; 548c2ecf20Sopenharmony_ci sctx->state[7] = SHA384_H7; 558c2ecf20Sopenharmony_ci sctx->count[0] = sctx->count[1] = 0; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci return 0; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic void __sha512_sparc64_update(struct sha512_state *sctx, const u8 *data, 618c2ecf20Sopenharmony_ci unsigned int len, unsigned int partial) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci unsigned int done = 0; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if ((sctx->count[0] += len) < len) 668c2ecf20Sopenharmony_ci sctx->count[1]++; 678c2ecf20Sopenharmony_ci if (partial) { 688c2ecf20Sopenharmony_ci done = SHA512_BLOCK_SIZE - partial; 698c2ecf20Sopenharmony_ci memcpy(sctx->buf + partial, data, done); 708c2ecf20Sopenharmony_ci sha512_sparc64_transform(sctx->state, sctx->buf, 1); 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci if (len - done >= SHA512_BLOCK_SIZE) { 738c2ecf20Sopenharmony_ci const unsigned int rounds = (len - done) / SHA512_BLOCK_SIZE; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci sha512_sparc64_transform(sctx->state, data + done, rounds); 768c2ecf20Sopenharmony_ci done += rounds * SHA512_BLOCK_SIZE; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci memcpy(sctx->buf, data + done, len - done); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int sha512_sparc64_update(struct shash_desc *desc, const u8 *data, 838c2ecf20Sopenharmony_ci unsigned int len) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct sha512_state *sctx = shash_desc_ctx(desc); 868c2ecf20Sopenharmony_ci unsigned int partial = sctx->count[0] % SHA512_BLOCK_SIZE; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* Handle the fast case right here */ 898c2ecf20Sopenharmony_ci if (partial + len < SHA512_BLOCK_SIZE) { 908c2ecf20Sopenharmony_ci if ((sctx->count[0] += len) < len) 918c2ecf20Sopenharmony_ci sctx->count[1]++; 928c2ecf20Sopenharmony_ci memcpy(sctx->buf + partial, data, len); 938c2ecf20Sopenharmony_ci } else 948c2ecf20Sopenharmony_ci __sha512_sparc64_update(sctx, data, len, partial); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return 0; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int sha512_sparc64_final(struct shash_desc *desc, u8 *out) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci struct sha512_state *sctx = shash_desc_ctx(desc); 1028c2ecf20Sopenharmony_ci unsigned int i, index, padlen; 1038c2ecf20Sopenharmony_ci __be64 *dst = (__be64 *)out; 1048c2ecf20Sopenharmony_ci __be64 bits[2]; 1058c2ecf20Sopenharmony_ci static const u8 padding[SHA512_BLOCK_SIZE] = { 0x80, }; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* Save number of bits */ 1088c2ecf20Sopenharmony_ci bits[1] = cpu_to_be64(sctx->count[0] << 3); 1098c2ecf20Sopenharmony_ci bits[0] = cpu_to_be64(sctx->count[1] << 3 | sctx->count[0] >> 61); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* Pad out to 112 mod 128 and append length */ 1128c2ecf20Sopenharmony_ci index = sctx->count[0] % SHA512_BLOCK_SIZE; 1138c2ecf20Sopenharmony_ci padlen = (index < 112) ? (112 - index) : ((SHA512_BLOCK_SIZE+112) - index); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* We need to fill a whole block for __sha512_sparc64_update() */ 1168c2ecf20Sopenharmony_ci if (padlen <= 112) { 1178c2ecf20Sopenharmony_ci if ((sctx->count[0] += padlen) < padlen) 1188c2ecf20Sopenharmony_ci sctx->count[1]++; 1198c2ecf20Sopenharmony_ci memcpy(sctx->buf + index, padding, padlen); 1208c2ecf20Sopenharmony_ci } else { 1218c2ecf20Sopenharmony_ci __sha512_sparc64_update(sctx, padding, padlen, index); 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci __sha512_sparc64_update(sctx, (const u8 *)&bits, sizeof(bits), 112); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* Store state in digest */ 1268c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 1278c2ecf20Sopenharmony_ci dst[i] = cpu_to_be64(sctx->state[i]); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* Wipe context */ 1308c2ecf20Sopenharmony_ci memset(sctx, 0, sizeof(*sctx)); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci return 0; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int sha384_sparc64_final(struct shash_desc *desc, u8 *hash) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci u8 D[64]; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci sha512_sparc64_final(desc, D); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci memcpy(hash, D, 48); 1428c2ecf20Sopenharmony_ci memzero_explicit(D, 64); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic struct shash_alg sha512 = { 1488c2ecf20Sopenharmony_ci .digestsize = SHA512_DIGEST_SIZE, 1498c2ecf20Sopenharmony_ci .init = sha512_sparc64_init, 1508c2ecf20Sopenharmony_ci .update = sha512_sparc64_update, 1518c2ecf20Sopenharmony_ci .final = sha512_sparc64_final, 1528c2ecf20Sopenharmony_ci .descsize = sizeof(struct sha512_state), 1538c2ecf20Sopenharmony_ci .base = { 1548c2ecf20Sopenharmony_ci .cra_name = "sha512", 1558c2ecf20Sopenharmony_ci .cra_driver_name= "sha512-sparc64", 1568c2ecf20Sopenharmony_ci .cra_priority = SPARC_CR_OPCODE_PRIORITY, 1578c2ecf20Sopenharmony_ci .cra_blocksize = SHA512_BLOCK_SIZE, 1588c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci}; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic struct shash_alg sha384 = { 1638c2ecf20Sopenharmony_ci .digestsize = SHA384_DIGEST_SIZE, 1648c2ecf20Sopenharmony_ci .init = sha384_sparc64_init, 1658c2ecf20Sopenharmony_ci .update = sha512_sparc64_update, 1668c2ecf20Sopenharmony_ci .final = sha384_sparc64_final, 1678c2ecf20Sopenharmony_ci .descsize = sizeof(struct sha512_state), 1688c2ecf20Sopenharmony_ci .base = { 1698c2ecf20Sopenharmony_ci .cra_name = "sha384", 1708c2ecf20Sopenharmony_ci .cra_driver_name= "sha384-sparc64", 1718c2ecf20Sopenharmony_ci .cra_priority = SPARC_CR_OPCODE_PRIORITY, 1728c2ecf20Sopenharmony_ci .cra_blocksize = SHA384_BLOCK_SIZE, 1738c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci}; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic bool __init sparc64_has_sha512_opcode(void) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci unsigned long cfr; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO)) 1828c2ecf20Sopenharmony_ci return false; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci __asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr)); 1858c2ecf20Sopenharmony_ci if (!(cfr & CFR_SHA512)) 1868c2ecf20Sopenharmony_ci return false; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci return true; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic int __init sha512_sparc64_mod_init(void) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci if (sparc64_has_sha512_opcode()) { 1948c2ecf20Sopenharmony_ci int ret = crypto_register_shash(&sha384); 1958c2ecf20Sopenharmony_ci if (ret < 0) 1968c2ecf20Sopenharmony_ci return ret; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci ret = crypto_register_shash(&sha512); 1998c2ecf20Sopenharmony_ci if (ret < 0) { 2008c2ecf20Sopenharmony_ci crypto_unregister_shash(&sha384); 2018c2ecf20Sopenharmony_ci return ret; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci pr_info("Using sparc64 sha512 opcode optimized SHA-512/SHA-384 implementation\n"); 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci pr_info("sparc64 sha512 opcode not available.\n"); 2088c2ecf20Sopenharmony_ci return -ENODEV; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic void __exit sha512_sparc64_mod_fini(void) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci crypto_unregister_shash(&sha384); 2148c2ecf20Sopenharmony_ci crypto_unregister_shash(&sha512); 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cimodule_init(sha512_sparc64_mod_init); 2188c2ecf20Sopenharmony_cimodule_exit(sha512_sparc64_mod_fini); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2218c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SHA-384 and SHA-512 Secure Hash Algorithm, sparc64 sha512 opcode accelerated"); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("sha384"); 2248c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("sha512"); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci#include "crop_devid.c" 227