diff options
-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 | ||||
-rw-r--r-- | crypto/Kconfig | 9 |
4 files changed, 326 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"); | ||
diff --git a/crypto/Kconfig b/crypto/Kconfig index 167c856f906d..4782d840d838 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig | |||
@@ -454,6 +454,15 @@ config CRYPTO_SHA256 | |||
454 | This code also includes SHA-224, a 224 bit hash with 112 bits | 454 | This code also includes SHA-224, a 224 bit hash with 112 bits |
455 | of security against collision attacks. | 455 | of security against collision attacks. |
456 | 456 | ||
457 | config CRYPTO_SHA256_SPARC64 | ||
458 | tristate "SHA224 and SHA256 digest algorithm (SPARC64)" | ||
459 | depends on SPARC64 | ||
460 | select CRYPTO_SHA256 | ||
461 | select CRYPTO_HASH | ||
462 | help | ||
463 | SHA-256 secure hash standard (DFIPS 180-2) implemented | ||
464 | using sparc64 crypto instructions, when available. | ||
465 | |||
457 | config CRYPTO_SHA512 | 466 | config CRYPTO_SHA512 |
458 | tristate "SHA384 and SHA512 digest algorithms" | 467 | tristate "SHA384 and SHA512 digest algorithms" |
459 | select CRYPTO_HASH | 468 | select CRYPTO_HASH |