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