diff options
| author | David S. Miller <davem@davemloft.net> | 2012-08-19 20:11:37 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2012-08-20 18:08:49 -0400 |
| commit | 86c93b24ef49d64062045c4e3cc2ed4609f6842a (patch) | |
| tree | 10e278a2efa93a1a2cb24ec36c01942722d65116 /arch/sparc/crypto | |
| parent | 4ff28d4ca93b182b8e181b1e1b1d03fd09fdaeb4 (diff) | |
sparc64: Add SHA224/SHA256 driver making use of the 'sha256' instruction.
Signed-off-by: David S. Miller <davem@davemloft.net>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'arch/sparc/crypto')
| -rw-r--r-- | arch/sparc/crypto/Makefile | 2 | ||||
| -rw-r--r-- | arch/sparc/crypto/sha256_asm.S | 78 | ||||
| -rw-r--r-- | arch/sparc/crypto/sha256_glue.c | 237 |
3 files changed, 317 insertions, 0 deletions
diff --git a/arch/sparc/crypto/Makefile b/arch/sparc/crypto/Makefile index 9760472fe32b..578f845a7e01 100644 --- a/arch/sparc/crypto/Makefile +++ b/arch/sparc/crypto/Makefile | |||
| @@ -3,5 +3,7 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | obj-$(CONFIG_CRYPTO_SHA1_SPARC64) += sha1-sparc64.o | 5 | obj-$(CONFIG_CRYPTO_SHA1_SPARC64) += sha1-sparc64.o |
| 6 | obj-$(CONFIG_CRYPTO_SHA256_SPARC64) += sha256-sparc64.o | ||
| 6 | 7 | ||
| 7 | sha1-sparc64-y := sha1_asm.o sha1_glue.o | 8 | sha1-sparc64-y := sha1_asm.o sha1_glue.o |
| 9 | sha256-sparc64-y := sha256_asm.o sha256_glue.o | ||
diff --git a/arch/sparc/crypto/sha256_asm.S b/arch/sparc/crypto/sha256_asm.S new file mode 100644 index 000000000000..771ce265f64a --- /dev/null +++ b/arch/sparc/crypto/sha256_asm.S | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | #include <linux/linkage.h> | ||
| 2 | #include <asm/visasm.h> | ||
| 3 | |||
| 4 | ENTRY(sha256_sparc64_transform) | ||
| 5 | /* %o0 = digest, %o1 = data, %o2 = rounds */ | ||
| 6 | VISEntryHalf | ||
| 7 | ld [%o0 + 0x00], %f0 | ||
| 8 | ld [%o0 + 0x04], %f1 | ||
| 9 | ld [%o0 + 0x08], %f2 | ||
| 10 | ld [%o0 + 0x0c], %f3 | ||
| 11 | ld [%o0 + 0x10], %f4 | ||
| 12 | ld [%o0 + 0x14], %f5 | ||
| 13 | andcc %o1, 0x7, %g0 | ||
| 14 | ld [%o0 + 0x18], %f6 | ||
| 15 | bne,pn %xcc, 10f | ||
| 16 | ld [%o0 + 0x1c], %f7 | ||
| 17 | |||
| 18 | 1: | ||
| 19 | ldd [%o1 + 0x00], %f8 | ||
| 20 | ldd [%o1 + 0x08], %f10 | ||
| 21 | ldd [%o1 + 0x10], %f12 | ||
| 22 | ldd [%o1 + 0x18], %f14 | ||
| 23 | ldd [%o1 + 0x20], %f16 | ||
| 24 | ldd [%o1 + 0x28], %f18 | ||
| 25 | ldd [%o1 + 0x30], %f20 | ||
| 26 | ldd [%o1 + 0x38], %f22 | ||
| 27 | |||
| 28 | /* sha256 */ | ||
| 29 | .word 0x81b02840 | ||
| 30 | |||
| 31 | subcc %o2, 1, %o2 | ||
| 32 | bne,pt %xcc, 1b | ||
| 33 | add %o1, 0x40, %o1 | ||
| 34 | |||
| 35 | 5: | ||
| 36 | st %f0, [%o0 + 0x00] | ||
| 37 | st %f1, [%o0 + 0x04] | ||
| 38 | st %f2, [%o0 + 0x08] | ||
| 39 | st %f3, [%o0 + 0x0c] | ||
| 40 | st %f4, [%o0 + 0x10] | ||
| 41 | st %f5, [%o0 + 0x14] | ||
| 42 | st %f6, [%o0 + 0x18] | ||
| 43 | st %f7, [%o0 + 0x1c] | ||
| 44 | retl | ||
| 45 | VISExitHalf | ||
| 46 | 10: | ||
| 47 | alignaddr %o1, %g0, %o1 | ||
| 48 | |||
| 49 | ldd [%o1 + 0x00], %f10 | ||
| 50 | 1: | ||
| 51 | ldd [%o1 + 0x08], %f12 | ||
| 52 | ldd [%o1 + 0x10], %f14 | ||
| 53 | ldd [%o1 + 0x18], %f16 | ||
| 54 | ldd [%o1 + 0x20], %f18 | ||
| 55 | ldd [%o1 + 0x28], %f20 | ||
| 56 | ldd [%o1 + 0x30], %f22 | ||
| 57 | ldd [%o1 + 0x38], %f24 | ||
| 58 | ldd [%o1 + 0x40], %f26 | ||
| 59 | |||
| 60 | faligndata %f10, %f12, %f8 | ||
| 61 | faligndata %f12, %f14, %f10 | ||
| 62 | faligndata %f14, %f16, %f12 | ||
| 63 | faligndata %f16, %f18, %f14 | ||
| 64 | faligndata %f18, %f20, %f16 | ||
| 65 | faligndata %f20, %f22, %f18 | ||
| 66 | faligndata %f22, %f24, %f20 | ||
| 67 | faligndata %f24, %f26, %f22 | ||
| 68 | |||
| 69 | /* sha256 */ | ||
| 70 | .word 0x81b02840 | ||
| 71 | |||
| 72 | subcc %o2, 1, %o2 | ||
| 73 | fsrc1 %f26, %f10 | ||
| 74 | bne,pt %xcc, 1b | ||
| 75 | add %o1, 0x40, %o1 | ||
| 76 | |||
| 77 | ba,a,pt %xcc, 5b | ||
| 78 | ENDPROC(sha256_sparc64_transform) | ||
diff --git a/arch/sparc/crypto/sha256_glue.c b/arch/sparc/crypto/sha256_glue.c new file mode 100644 index 000000000000..75e1adeeb024 --- /dev/null +++ b/arch/sparc/crypto/sha256_glue.c | |||
| @@ -0,0 +1,237 @@ | |||
| 1 | /* Glue code for SHA256 hashing optimized for sparc64 crypto opcodes. | ||
| 2 | * | ||
| 3 | * This is based largely upon crypto/sha256_generic.c | ||
| 4 | * | ||
| 5 | * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com> | ||
| 6 | * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk> | ||
| 7 | * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> | ||
| 8 | * SHA224 Support Copyright 2007 Intel Corporation <jonathan.lynch@intel.com> | ||
| 9 | */ | ||
| 10 | |||
| 11 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 12 | |||
| 13 | #include <crypto/internal/hash.h> | ||
| 14 | #include <linux/init.h> | ||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/mm.h> | ||
| 17 | #include <linux/cryptohash.h> | ||
| 18 | #include <linux/types.h> | ||
| 19 | #include <crypto/sha.h> | ||
| 20 | |||
| 21 | #include <asm/pstate.h> | ||
| 22 | #include <asm/elf.h> | ||
| 23 | |||
| 24 | asmlinkage void sha256_sparc64_transform(u32 *digest, const char *data, | ||
| 25 | unsigned int rounds); | ||
| 26 | |||
| 27 | static int sha224_sparc64_init(struct shash_desc *desc) | ||
| 28 | { | ||
| 29 | struct sha256_state *sctx = shash_desc_ctx(desc); | ||
| 30 | sctx->state[0] = SHA224_H0; | ||
| 31 | sctx->state[1] = SHA224_H1; | ||
| 32 | sctx->state[2] = SHA224_H2; | ||
| 33 | sctx->state[3] = SHA224_H3; | ||
| 34 | sctx->state[4] = SHA224_H4; | ||
| 35 | sctx->state[5] = SHA224_H5; | ||
| 36 | sctx->state[6] = SHA224_H6; | ||
| 37 | sctx->state[7] = SHA224_H7; | ||
| 38 | sctx->count = 0; | ||
| 39 | |||
| 40 | return 0; | ||
| 41 | } | ||
| 42 | |||
| 43 | static int sha256_sparc64_init(struct shash_desc *desc) | ||
| 44 | { | ||
| 45 | struct sha256_state *sctx = shash_desc_ctx(desc); | ||
| 46 | sctx->state[0] = SHA256_H0; | ||
| 47 | sctx->state[1] = SHA256_H1; | ||
| 48 | sctx->state[2] = SHA256_H2; | ||
| 49 | sctx->state[3] = SHA256_H3; | ||
| 50 | sctx->state[4] = SHA256_H4; | ||
| 51 | sctx->state[5] = SHA256_H5; | ||
| 52 | sctx->state[6] = SHA256_H6; | ||
| 53 | sctx->state[7] = SHA256_H7; | ||
| 54 | sctx->count = 0; | ||
| 55 | |||
| 56 | return 0; | ||
| 57 | } | ||
| 58 | |||
| 59 | static void __sha256_sparc64_update(struct sha256_state *sctx, const u8 *data, | ||
| 60 | unsigned int len, unsigned int partial) | ||
| 61 | { | ||
| 62 | unsigned int done = 0; | ||
| 63 | |||
| 64 | sctx->count += len; | ||
| 65 | if (partial) { | ||
| 66 | done = SHA256_BLOCK_SIZE - partial; | ||
| 67 | memcpy(sctx->buf + partial, data, done); | ||
| 68 | sha256_sparc64_transform(sctx->state, sctx->buf, 1); | ||
| 69 | } | ||
| 70 | if (len - done >= SHA256_BLOCK_SIZE) { | ||
| 71 | const unsigned int rounds = (len - done) / SHA256_BLOCK_SIZE; | ||
| 72 | |||
| 73 | sha256_sparc64_transform(sctx->state, data + done, rounds); | ||
| 74 | done += rounds * SHA256_BLOCK_SIZE; | ||
| 75 | } | ||
| 76 | |||
| 77 | memcpy(sctx->buf, data + done, len - done); | ||
| 78 | } | ||
| 79 | |||
| 80 | static int sha256_sparc64_update(struct shash_desc *desc, const u8 *data, | ||
| 81 | unsigned int len) | ||
| 82 | { | ||
| 83 | struct sha256_state *sctx = shash_desc_ctx(desc); | ||
| 84 | unsigned int partial = sctx->count % SHA256_BLOCK_SIZE; | ||
| 85 | |||
| 86 | /* Handle the fast case right here */ | ||
| 87 | if (partial + len < SHA256_BLOCK_SIZE) { | ||
| 88 | sctx->count += len; | ||
| 89 | memcpy(sctx->buf + partial, data, len); | ||
| 90 | } else | ||
| 91 | __sha256_sparc64_update(sctx, data, len, partial); | ||
| 92 | |||
| 93 | return 0; | ||
| 94 | } | ||
| 95 | |||
| 96 | static int sha256_sparc64_final(struct shash_desc *desc, u8 *out) | ||
| 97 | { | ||
| 98 | struct sha256_state *sctx = shash_desc_ctx(desc); | ||
| 99 | unsigned int i, index, padlen; | ||
| 100 | __be32 *dst = (__be32 *)out; | ||
| 101 | __be64 bits; | ||
| 102 | static const u8 padding[SHA256_BLOCK_SIZE] = { 0x80, }; | ||
| 103 | |||
| 104 | bits = cpu_to_be64(sctx->count << 3); | ||
| 105 | |||
| 106 | /* Pad out to 56 mod 64 and append length */ | ||
| 107 | index = sctx->count % SHA256_BLOCK_SIZE; | ||
| 108 | padlen = (index < 56) ? (56 - index) : ((SHA256_BLOCK_SIZE+56) - index); | ||
| 109 | |||
| 110 | /* We need to fill a whole block for __sha256_sparc64_update() */ | ||
| 111 | if (padlen <= 56) { | ||
| 112 | sctx->count += padlen; | ||
| 113 | memcpy(sctx->buf + index, padding, padlen); | ||
| 114 | } else { | ||
| 115 | __sha256_sparc64_update(sctx, padding, padlen, index); | ||
| 116 | } | ||
| 117 | __sha256_sparc64_update(sctx, (const u8 *)&bits, sizeof(bits), 56); | ||
| 118 | |||
| 119 | /* Store state in digest */ | ||
| 120 | for (i = 0; i < 8; i++) | ||
| 121 | dst[i] = cpu_to_be32(sctx->state[i]); | ||
| 122 | |||
| 123 | /* Wipe context */ | ||
| 124 | memset(sctx, 0, sizeof(*sctx)); | ||
| 125 | |||
| 126 | return 0; | ||
| 127 | } | ||
| 128 | |||
| 129 | static int sha224_sparc64_final(struct shash_desc *desc, u8 *hash) | ||
| 130 | { | ||
| 131 | u8 D[SHA256_DIGEST_SIZE]; | ||
| 132 | |||
| 133 | sha256_sparc64_final(desc, D); | ||
| 134 | |||
| 135 | memcpy(hash, D, SHA224_DIGEST_SIZE); | ||
| 136 | memset(D, 0, SHA256_DIGEST_SIZE); | ||
| 137 | |||
| 138 | return 0; | ||
| 139 | } | ||
| 140 | |||
| 141 | static int sha256_sparc64_export(struct shash_desc *desc, void *out) | ||
| 142 | { | ||
| 143 | struct sha256_state *sctx = shash_desc_ctx(desc); | ||
| 144 | |||
| 145 | memcpy(out, sctx, sizeof(*sctx)); | ||
| 146 | return 0; | ||
| 147 | } | ||
| 148 | |||
| 149 | static int sha256_sparc64_import(struct shash_desc *desc, const void *in) | ||
| 150 | { | ||
| 151 | struct sha256_state *sctx = shash_desc_ctx(desc); | ||
| 152 | |||
| 153 | memcpy(sctx, in, sizeof(*sctx)); | ||
| 154 | return 0; | ||
| 155 | } | ||
| 156 | |||
| 157 | static struct shash_alg sha256 = { | ||
| 158 | .digestsize = SHA256_DIGEST_SIZE, | ||
| 159 | .init = sha256_sparc64_init, | ||
| 160 | .update = sha256_sparc64_update, | ||
| 161 | .final = sha256_sparc64_final, | ||
| 162 | .export = sha256_sparc64_export, | ||
| 163 | .import = sha256_sparc64_import, | ||
| 164 | .descsize = sizeof(struct sha256_state), | ||
| 165 | .statesize = sizeof(struct sha256_state), | ||
| 166 | .base = { | ||
| 167 | .cra_name = "sha256", | ||
| 168 | .cra_driver_name= "sha256-sparc64", | ||
| 169 | .cra_flags = CRYPTO_ALG_TYPE_SHASH, | ||
| 170 | .cra_blocksize = SHA256_BLOCK_SIZE, | ||
| 171 | .cra_module = THIS_MODULE, | ||
| 172 | } | ||
| 173 | }; | ||
| 174 | |||
| 175 | static struct shash_alg sha224 = { | ||
| 176 | .digestsize = SHA224_DIGEST_SIZE, | ||
| 177 | .init = sha224_sparc64_init, | ||
| 178 | .update = sha256_sparc64_update, | ||
| 179 | .final = sha224_sparc64_final, | ||
| 180 | .descsize = sizeof(struct sha256_state), | ||
| 181 | .base = { | ||
| 182 | .cra_name = "sha224", | ||
| 183 | .cra_driver_name= "sha224-sparc64", | ||
| 184 | .cra_flags = CRYPTO_ALG_TYPE_SHASH, | ||
| 185 | .cra_blocksize = SHA224_BLOCK_SIZE, | ||
| 186 | .cra_module = THIS_MODULE, | ||
| 187 | } | ||
| 188 | }; | ||
| 189 | |||
| 190 | static bool __init sparc64_has_sha256_opcode(void) | ||
| 191 | { | ||
| 192 | unsigned long cfr; | ||
| 193 | |||
| 194 | if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO)) | ||
| 195 | return false; | ||
| 196 | |||
| 197 | __asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr)); | ||
| 198 | if (!(cfr & CFR_SHA256)) | ||
| 199 | return false; | ||
| 200 | |||
| 201 | return true; | ||
| 202 | } | ||
| 203 | |||
| 204 | static int __init sha256_sparc64_mod_init(void) | ||
| 205 | { | ||
| 206 | if (sparc64_has_sha256_opcode()) { | ||
| 207 | int ret = crypto_register_shash(&sha224); | ||
| 208 | if (ret < 0) | ||
| 209 | return ret; | ||
| 210 | |||
| 211 | ret = crypto_register_shash(&sha256); | ||
| 212 | if (ret < 0) { | ||
| 213 | crypto_unregister_shash(&sha224); | ||
| 214 | return ret; | ||
| 215 | } | ||
| 216 | |||
| 217 | pr_info("Using sparc64 sha256 opcode optimized SHA-256/SHA-224 implementation\n"); | ||
| 218 | return 0; | ||
| 219 | } | ||
| 220 | pr_info("sparc64 sha256 opcode not available.\n"); | ||
| 221 | return -ENODEV; | ||
| 222 | } | ||
| 223 | |||
| 224 | static void __exit sha256_sparc64_mod_fini(void) | ||
| 225 | { | ||
| 226 | crypto_unregister_shash(&sha224); | ||
| 227 | crypto_unregister_shash(&sha256); | ||
| 228 | } | ||
| 229 | |||
| 230 | module_init(sha256_sparc64_mod_init); | ||
| 231 | module_exit(sha256_sparc64_mod_fini); | ||
| 232 | |||
| 233 | MODULE_LICENSE("GPL"); | ||
| 234 | MODULE_DESCRIPTION("SHA-224 and SHA-256 Secure Hash Algorithm, sparc64 sha256 opcode accelerated"); | ||
| 235 | |||
| 236 | MODULE_ALIAS("sha224"); | ||
| 237 | MODULE_ALIAS("sha256"); | ||
