1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Glue code for MD5 hashing optimized for sparc64 crypto opcodes. 3 * 4 * This is based largely upon arch/x86/crypto/sha1_ssse3_glue.c 5 * and crypto/md5.c which are: 6 * 7 * Copyright (c) Alan Smithee. 8 * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk> 9 * Copyright (c) Jean-Francois Dive <jef@linuxbe.org> 10 * Copyright (c) Mathias Krause <minipli@googlemail.com> 11 * Copyright (c) Cryptoapi developers. 12 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> 13 */ 14 15 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 16 17 #include <asm/elf.h> 18 #include <asm/opcodes.h> 19 #include <asm/pstate.h> 20 #include <crypto/internal/hash.h> 21 #include <crypto/md5.h> 22 #include <linux/errno.h> 23 #include <linux/kernel.h> 24 #include <linux/module.h> 25 #include <linux/string.h> 26 #include <linux/unaligned.h> 27 28 struct sparc_md5_state { 29 __le32 hash[MD5_HASH_WORDS]; 30 u64 byte_count; 31 }; 32 33 asmlinkage void md5_sparc64_transform(__le32 *digest, const char *data, 34 unsigned int rounds); 35 36 static int md5_sparc64_init(struct shash_desc *desc) 37 { 38 struct sparc_md5_state *mctx = shash_desc_ctx(desc); 39 40 mctx->hash[0] = cpu_to_le32(MD5_H0); 41 mctx->hash[1] = cpu_to_le32(MD5_H1); 42 mctx->hash[2] = cpu_to_le32(MD5_H2); 43 mctx->hash[3] = cpu_to_le32(MD5_H3); 44 mctx->byte_count = 0; 45 46 return 0; 47 } 48 49 static int md5_sparc64_update(struct shash_desc *desc, const u8 *data, 50 unsigned int len) 51 { 52 struct sparc_md5_state *sctx = shash_desc_ctx(desc); 53 54 sctx->byte_count += round_down(len, MD5_HMAC_BLOCK_SIZE); 55 md5_sparc64_transform(sctx->hash, data, len / MD5_HMAC_BLOCK_SIZE); 56 return len - round_down(len, MD5_HMAC_BLOCK_SIZE); 57 } 58 59 /* Add padding and return the message digest. */ 60 static int md5_sparc64_finup(struct shash_desc *desc, const u8 *src, 61 unsigned int offset, u8 *out) 62 { 63 struct sparc_md5_state *sctx = shash_desc_ctx(desc); 64 __le64 block[MD5_BLOCK_WORDS] = {}; 65 u8 *p = memcpy(block, src, offset); 66 __le32 *dst = (__le32 *)out; 67 __le64 *pbits; 68 int i; 69 70 src = p; 71 p += offset; 72 *p++ = 0x80; 73 sctx->byte_count += offset; 74 pbits = &block[(MD5_BLOCK_WORDS / (offset > 55 ? 1 : 2)) - 1]; 75 *pbits = cpu_to_le64(sctx->byte_count << 3); 76 md5_sparc64_transform(sctx->hash, src, (pbits - block + 1) / 8); 77 memzero_explicit(block, sizeof(block)); 78 79 /* Store state in digest */ 80 for (i = 0; i < MD5_HASH_WORDS; i++) 81 dst[i] = sctx->hash[i]; 82 83 return 0; 84 } 85 86 static int md5_sparc64_export(struct shash_desc *desc, void *out) 87 { 88 struct sparc_md5_state *sctx = shash_desc_ctx(desc); 89 union { 90 u8 *u8; 91 u32 *u32; 92 u64 *u64; 93 } p = { .u8 = out }; 94 int i; 95 96 for (i = 0; i < MD5_HASH_WORDS; i++) 97 put_unaligned(le32_to_cpu(sctx->hash[i]), p.u32++); 98 put_unaligned(sctx->byte_count, p.u64); 99 return 0; 100 } 101 102 static int md5_sparc64_import(struct shash_desc *desc, const void *in) 103 { 104 struct sparc_md5_state *sctx = shash_desc_ctx(desc); 105 union { 106 const u8 *u8; 107 const u32 *u32; 108 const u64 *u64; 109 } p = { .u8 = in }; 110 int i; 111 112 for (i = 0; i < MD5_HASH_WORDS; i++) 113 sctx->hash[i] = cpu_to_le32(get_unaligned(p.u32++)); 114 sctx->byte_count = get_unaligned(p.u64); 115 return 0; 116 } 117 118 static struct shash_alg alg = { 119 .digestsize = MD5_DIGEST_SIZE, 120 .init = md5_sparc64_init, 121 .update = md5_sparc64_update, 122 .finup = md5_sparc64_finup, 123 .export = md5_sparc64_export, 124 .import = md5_sparc64_import, 125 .descsize = sizeof(struct sparc_md5_state), 126 .statesize = sizeof(struct sparc_md5_state), 127 .base = { 128 .cra_name = "md5", 129 .cra_driver_name= "md5-sparc64", 130 .cra_priority = SPARC_CR_OPCODE_PRIORITY, 131 .cra_flags = CRYPTO_AHASH_ALG_BLOCK_ONLY, 132 .cra_blocksize = MD5_HMAC_BLOCK_SIZE, 133 .cra_module = THIS_MODULE, 134 } 135 }; 136 137 static bool __init sparc64_has_md5_opcode(void) 138 { 139 unsigned long cfr; 140 141 if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO)) 142 return false; 143 144 __asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr)); 145 if (!(cfr & CFR_MD5)) 146 return false; 147 148 return true; 149 } 150 151 static int __init md5_sparc64_mod_init(void) 152 { 153 if (sparc64_has_md5_opcode()) { 154 pr_info("Using sparc64 md5 opcode optimized MD5 implementation\n"); 155 return crypto_register_shash(&alg); 156 } 157 pr_info("sparc64 md5 opcode not available.\n"); 158 return -ENODEV; 159 } 160 161 static void __exit md5_sparc64_mod_fini(void) 162 { 163 crypto_unregister_shash(&alg); 164 } 165 166 module_init(md5_sparc64_mod_init); 167 module_exit(md5_sparc64_mod_fini); 168 169 MODULE_LICENSE("GPL"); 170 MODULE_DESCRIPTION("MD5 Message Digest Algorithm, sparc64 md5 opcode accelerated"); 171 172 MODULE_ALIAS_CRYPTO("md5"); 173 174 #include "crop_devid.c" 175