1fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller/* Glue code for MD5 hashing optimized for sparc64 crypto opcodes. 2fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller * 3fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller * This is based largely upon arch/x86/crypto/sha1_ssse3_glue.c 4fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller * and crypto/md5.c which are: 5fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller * 6fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller * Copyright (c) Alan Smithee. 7fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk> 8fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller * Copyright (c) Jean-Francois Dive <jef@linuxbe.org> 9fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller * Copyright (c) Mathias Krause <minipli@googlemail.com> 10fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller * Copyright (c) Cryptoapi developers. 11fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> 12fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller */ 13fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 14fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 15fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 16fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller#include <crypto/internal/hash.h> 17fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller#include <linux/init.h> 18fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller#include <linux/module.h> 19fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller#include <linux/mm.h> 20fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller#include <linux/cryptohash.h> 21fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller#include <linux/types.h> 22fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller#include <crypto/md5.h> 23fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 24fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller#include <asm/pstate.h> 25fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller#include <asm/elf.h> 26fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 271080362425793f67e36dc690973e13e4a9631b4dDavid S. Miller#include "opcodes.h" 281080362425793f67e36dc690973e13e4a9631b4dDavid S. Miller 29fa4dfedcc23a589f953750de54eebf986336fa70David S. Millerasmlinkage void md5_sparc64_transform(u32 *digest, const char *data, 30fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller unsigned int rounds); 31fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 32fa4dfedcc23a589f953750de54eebf986336fa70David S. Millerstatic int md5_sparc64_init(struct shash_desc *desc) 33fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller{ 34fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller struct md5_state *mctx = shash_desc_ctx(desc); 35fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 36fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller mctx->hash[0] = cpu_to_le32(0x67452301); 37fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller mctx->hash[1] = cpu_to_le32(0xefcdab89); 38fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller mctx->hash[2] = cpu_to_le32(0x98badcfe); 39fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller mctx->hash[3] = cpu_to_le32(0x10325476); 40fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller mctx->byte_count = 0; 41fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 42fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller return 0; 43fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller} 44fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 45fa4dfedcc23a589f953750de54eebf986336fa70David S. Millerstatic void __md5_sparc64_update(struct md5_state *sctx, const u8 *data, 46fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller unsigned int len, unsigned int partial) 47fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller{ 48fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller unsigned int done = 0; 49fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 50fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller sctx->byte_count += len; 51fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller if (partial) { 52fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller done = MD5_HMAC_BLOCK_SIZE - partial; 53fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller memcpy((u8 *)sctx->block + partial, data, done); 54fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller md5_sparc64_transform(sctx->hash, (u8 *)sctx->block, 1); 55fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller } 56fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller if (len - done >= MD5_HMAC_BLOCK_SIZE) { 57fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller const unsigned int rounds = (len - done) / MD5_HMAC_BLOCK_SIZE; 58fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 59fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller md5_sparc64_transform(sctx->hash, data + done, rounds); 60fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller done += rounds * MD5_HMAC_BLOCK_SIZE; 61fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller } 62fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 63fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller memcpy(sctx->block, data + done, len - done); 64fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller} 65fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 66fa4dfedcc23a589f953750de54eebf986336fa70David S. Millerstatic int md5_sparc64_update(struct shash_desc *desc, const u8 *data, 67fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller unsigned int len) 68fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller{ 69fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller struct md5_state *sctx = shash_desc_ctx(desc); 70fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller unsigned int partial = sctx->byte_count % MD5_HMAC_BLOCK_SIZE; 71fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 72fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller /* Handle the fast case right here */ 73fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller if (partial + len < MD5_HMAC_BLOCK_SIZE) { 74fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller sctx->byte_count += len; 75fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller memcpy((u8 *)sctx->block + partial, data, len); 76fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller } else 77fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller __md5_sparc64_update(sctx, data, len, partial); 78fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 79fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller return 0; 80fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller} 81fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 82fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller/* Add padding and return the message digest. */ 83fa4dfedcc23a589f953750de54eebf986336fa70David S. Millerstatic int md5_sparc64_final(struct shash_desc *desc, u8 *out) 84fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller{ 85fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller struct md5_state *sctx = shash_desc_ctx(desc); 86fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller unsigned int i, index, padlen; 87fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller u32 *dst = (u32 *)out; 88fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller __le64 bits; 89fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller static const u8 padding[MD5_HMAC_BLOCK_SIZE] = { 0x80, }; 90fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 91fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller bits = cpu_to_le64(sctx->byte_count << 3); 92fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 93fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller /* Pad out to 56 mod 64 and append length */ 94fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller index = sctx->byte_count % MD5_HMAC_BLOCK_SIZE; 95fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller padlen = (index < 56) ? (56 - index) : ((MD5_HMAC_BLOCK_SIZE+56) - index); 96fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 97fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller /* We need to fill a whole block for __md5_sparc64_update() */ 98fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller if (padlen <= 56) { 99fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller sctx->byte_count += padlen; 100fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller memcpy((u8 *)sctx->block + index, padding, padlen); 101fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller } else { 102fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller __md5_sparc64_update(sctx, padding, padlen, index); 103fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller } 104fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller __md5_sparc64_update(sctx, (const u8 *)&bits, sizeof(bits), 56); 105fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 106fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller /* Store state in digest */ 107fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller for (i = 0; i < MD5_HASH_WORDS; i++) 108fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller dst[i] = sctx->hash[i]; 109fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 110fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller /* Wipe context */ 111fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller memset(sctx, 0, sizeof(*sctx)); 112fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 113fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller return 0; 114fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller} 115fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 116fa4dfedcc23a589f953750de54eebf986336fa70David S. Millerstatic int md5_sparc64_export(struct shash_desc *desc, void *out) 117fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller{ 118fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller struct md5_state *sctx = shash_desc_ctx(desc); 119fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 120fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller memcpy(out, sctx, sizeof(*sctx)); 121fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 122fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller return 0; 123fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller} 124fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 125fa4dfedcc23a589f953750de54eebf986336fa70David S. Millerstatic int md5_sparc64_import(struct shash_desc *desc, const void *in) 126fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller{ 127fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller struct md5_state *sctx = shash_desc_ctx(desc); 128fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 129fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller memcpy(sctx, in, sizeof(*sctx)); 130fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 131fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller return 0; 132fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller} 133fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 134fa4dfedcc23a589f953750de54eebf986336fa70David S. Millerstatic struct shash_alg alg = { 135fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller .digestsize = MD5_DIGEST_SIZE, 136fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller .init = md5_sparc64_init, 137fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller .update = md5_sparc64_update, 138fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller .final = md5_sparc64_final, 139fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller .export = md5_sparc64_export, 140fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller .import = md5_sparc64_import, 141fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller .descsize = sizeof(struct md5_state), 142fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller .statesize = sizeof(struct md5_state), 143fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller .base = { 144fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller .cra_name = "md5", 145fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller .cra_driver_name= "md5-sparc64", 1461080362425793f67e36dc690973e13e4a9631b4dDavid S. Miller .cra_priority = SPARC_CR_OPCODE_PRIORITY, 147fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller .cra_flags = CRYPTO_ALG_TYPE_SHASH, 148fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller .cra_blocksize = MD5_HMAC_BLOCK_SIZE, 149fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller .cra_module = THIS_MODULE, 150fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller } 151fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller}; 152fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 153fa4dfedcc23a589f953750de54eebf986336fa70David S. Millerstatic bool __init sparc64_has_md5_opcode(void) 154fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller{ 155fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller unsigned long cfr; 156fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 157fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO)) 158fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller return false; 159fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 160fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller __asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr)); 161fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller if (!(cfr & CFR_MD5)) 162fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller return false; 163fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 164fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller return true; 165fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller} 166fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 167fa4dfedcc23a589f953750de54eebf986336fa70David S. Millerstatic int __init md5_sparc64_mod_init(void) 168fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller{ 169fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller if (sparc64_has_md5_opcode()) { 170fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller pr_info("Using sparc64 md5 opcode optimized MD5 implementation\n"); 171fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller return crypto_register_shash(&alg); 172fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller } 173fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller pr_info("sparc64 md5 opcode not available.\n"); 174fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller return -ENODEV; 175fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller} 176fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 177fa4dfedcc23a589f953750de54eebf986336fa70David S. Millerstatic void __exit md5_sparc64_mod_fini(void) 178fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller{ 179fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller crypto_unregister_shash(&alg); 180fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller} 181fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 182fa4dfedcc23a589f953750de54eebf986336fa70David S. Millermodule_init(md5_sparc64_mod_init); 183fa4dfedcc23a589f953750de54eebf986336fa70David S. Millermodule_exit(md5_sparc64_mod_fini); 184fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 185fa4dfedcc23a589f953750de54eebf986336fa70David S. MillerMODULE_LICENSE("GPL"); 186fa4dfedcc23a589f953750de54eebf986336fa70David S. MillerMODULE_DESCRIPTION("MD5 Secure Hash Algorithm, sparc64 md5 opcode accelerated"); 187fa4dfedcc23a589f953750de54eebf986336fa70David S. Miller 188fa4dfedcc23a589f953750de54eebf986336fa70David S. MillerMODULE_ALIAS("md5"); 189226f7cea949303a3e1911999a9a2c71b0a708e73David S. Miller 190226f7cea949303a3e1911999a9a2c71b0a708e73David S. Miller#include "crop_devid.c" 191