diff options
Diffstat (limited to 'arch/sparc/crypto')
-rw-r--r-- | arch/sparc/crypto/Makefile | 2 | ||||
-rw-r--r-- | arch/sparc/crypto/sha512_asm.S | 102 | ||||
-rw-r--r-- | arch/sparc/crypto/sha512_glue.c | 222 |
3 files changed, 326 insertions, 0 deletions
diff --git a/arch/sparc/crypto/Makefile b/arch/sparc/crypto/Makefile index 578f845a7e01..cfae0e874d26 100644 --- a/arch/sparc/crypto/Makefile +++ b/arch/sparc/crypto/Makefile | |||
@@ -4,6 +4,8 @@ | |||
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 | obj-$(CONFIG_CRYPTO_SHA256_SPARC64) += sha256-sparc64.o |
7 | obj-$(CONFIG_CRYPTO_SHA512_SPARC64) += sha512-sparc64.o | ||
7 | 8 | ||
8 | sha1-sparc64-y := sha1_asm.o sha1_glue.o | 9 | sha1-sparc64-y := sha1_asm.o sha1_glue.o |
9 | sha256-sparc64-y := sha256_asm.o sha256_glue.o | 10 | sha256-sparc64-y := sha256_asm.o sha256_glue.o |
11 | sha512-sparc64-y := sha512_asm.o sha512_glue.o | ||
diff --git a/arch/sparc/crypto/sha512_asm.S b/arch/sparc/crypto/sha512_asm.S new file mode 100644 index 000000000000..04244da50774 --- /dev/null +++ b/arch/sparc/crypto/sha512_asm.S | |||
@@ -0,0 +1,102 @@ | |||
1 | #include <linux/linkage.h> | ||
2 | #include <asm/visasm.h> | ||
3 | |||
4 | ENTRY(sha512_sparc64_transform) | ||
5 | /* %o0 = digest, %o1 = data, %o2 = rounds */ | ||
6 | VISEntry | ||
7 | ldd [%o0 + 0x00], %f0 | ||
8 | ldd [%o0 + 0x08], %f2 | ||
9 | ldd [%o0 + 0x10], %f4 | ||
10 | ldd [%o0 + 0x18], %f6 | ||
11 | ldd [%o0 + 0x20], %f8 | ||
12 | ldd [%o0 + 0x28], %f10 | ||
13 | andcc %o1, 0x7, %g0 | ||
14 | ldd [%o0 + 0x30], %f12 | ||
15 | bne,pn %xcc, 10f | ||
16 | ldd [%o0 + 0x38], %f14 | ||
17 | |||
18 | 1: | ||
19 | ldd [%o1 + 0x00], %f16 | ||
20 | ldd [%o1 + 0x08], %f18 | ||
21 | ldd [%o1 + 0x10], %f20 | ||
22 | ldd [%o1 + 0x18], %f22 | ||
23 | ldd [%o1 + 0x20], %f24 | ||
24 | ldd [%o1 + 0x28], %f26 | ||
25 | ldd [%o1 + 0x30], %f28 | ||
26 | ldd [%o1 + 0x38], %f30 | ||
27 | ldd [%o1 + 0x40], %f32 | ||
28 | ldd [%o1 + 0x48], %f34 | ||
29 | ldd [%o1 + 0x50], %f36 | ||
30 | ldd [%o1 + 0x58], %f38 | ||
31 | ldd [%o1 + 0x60], %f40 | ||
32 | ldd [%o1 + 0x68], %f42 | ||
33 | ldd [%o1 + 0x70], %f44 | ||
34 | ldd [%o1 + 0x78], %f46 | ||
35 | |||
36 | /* sha512 */ | ||
37 | .word 0x81b02860 | ||
38 | |||
39 | subcc %o2, 1, %o2 | ||
40 | bne,pt %xcc, 1b | ||
41 | add %o1, 0x80, %o1 | ||
42 | |||
43 | 5: | ||
44 | std %f0, [%o0 + 0x00] | ||
45 | std %f2, [%o0 + 0x08] | ||
46 | std %f4, [%o0 + 0x10] | ||
47 | std %f6, [%o0 + 0x18] | ||
48 | std %f8, [%o0 + 0x20] | ||
49 | std %f10, [%o0 + 0x28] | ||
50 | std %f12, [%o0 + 0x30] | ||
51 | std %f14, [%o0 + 0x38] | ||
52 | retl | ||
53 | VISExit | ||
54 | 10: | ||
55 | alignaddr %o1, %g0, %o1 | ||
56 | |||
57 | ldd [%o1 + 0x00], %f18 | ||
58 | 1: | ||
59 | ldd [%o1 + 0x08], %f20 | ||
60 | ldd [%o1 + 0x10], %f22 | ||
61 | ldd [%o1 + 0x18], %f24 | ||
62 | ldd [%o1 + 0x20], %f26 | ||
63 | ldd [%o1 + 0x28], %f28 | ||
64 | ldd [%o1 + 0x30], %f30 | ||
65 | ldd [%o1 + 0x38], %f32 | ||
66 | ldd [%o1 + 0x40], %f34 | ||
67 | ldd [%o1 + 0x48], %f36 | ||
68 | ldd [%o1 + 0x50], %f38 | ||
69 | ldd [%o1 + 0x58], %f40 | ||
70 | ldd [%o1 + 0x60], %f42 | ||
71 | ldd [%o1 + 0x68], %f44 | ||
72 | ldd [%o1 + 0x70], %f46 | ||
73 | ldd [%o1 + 0x78], %f48 | ||
74 | ldd [%o1 + 0x80], %f50 | ||
75 | |||
76 | faligndata %f18, %f20, %f16 | ||
77 | faligndata %f20, %f22, %f18 | ||
78 | faligndata %f22, %f24, %f20 | ||
79 | faligndata %f24, %f26, %f22 | ||
80 | faligndata %f26, %f28, %f24 | ||
81 | faligndata %f28, %f30, %f26 | ||
82 | faligndata %f30, %f32, %f28 | ||
83 | faligndata %f32, %f34, %f30 | ||
84 | faligndata %f34, %f36, %f32 | ||
85 | faligndata %f36, %f38, %f34 | ||
86 | faligndata %f38, %f40, %f36 | ||
87 | faligndata %f40, %f42, %f38 | ||
88 | faligndata %f42, %f44, %f40 | ||
89 | faligndata %f44, %f46, %f42 | ||
90 | faligndata %f46, %f48, %f44 | ||
91 | faligndata %f48, %f50, %f46 | ||
92 | |||
93 | /* sha512 */ | ||
94 | .word 0x81b02860 | ||
95 | |||
96 | subcc %o2, 1, %o2 | ||
97 | fsrc1 %f50, %f18 | ||
98 | bne,pt %xcc, 1b | ||
99 | add %o1, 0x80, %o1 | ||
100 | |||
101 | ba,a,pt %xcc, 5b | ||
102 | ENDPROC(sha512_sparc64_transform) | ||
diff --git a/arch/sparc/crypto/sha512_glue.c b/arch/sparc/crypto/sha512_glue.c new file mode 100644 index 000000000000..4d960be401c4 --- /dev/null +++ b/arch/sparc/crypto/sha512_glue.c | |||
@@ -0,0 +1,222 @@ | |||
1 | /* Glue code for SHA512 hashing optimized for sparc64 crypto opcodes. | ||
2 | * | ||
3 | * This is based largely upon crypto/sha512_generic.c | ||
4 | * | ||
5 | * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com> | ||
6 | * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk> | ||
7 | * Copyright (c) 2003 Kyle McMartin <kyle@debian.org> | ||
8 | */ | ||
9 | |||
10 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
11 | |||
12 | #include <crypto/internal/hash.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/cryptohash.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <crypto/sha.h> | ||
19 | |||
20 | #include <asm/pstate.h> | ||
21 | #include <asm/elf.h> | ||
22 | |||
23 | asmlinkage void sha512_sparc64_transform(u64 *digest, const char *data, | ||
24 | unsigned int rounds); | ||
25 | |||
26 | static int sha512_sparc64_init(struct shash_desc *desc) | ||
27 | { | ||
28 | struct sha512_state *sctx = shash_desc_ctx(desc); | ||
29 | sctx->state[0] = SHA512_H0; | ||
30 | sctx->state[1] = SHA512_H1; | ||
31 | sctx->state[2] = SHA512_H2; | ||
32 | sctx->state[3] = SHA512_H3; | ||
33 | sctx->state[4] = SHA512_H4; | ||
34 | sctx->state[5] = SHA512_H5; | ||
35 | sctx->state[6] = SHA512_H6; | ||
36 | sctx->state[7] = SHA512_H7; | ||
37 | sctx->count[0] = sctx->count[1] = 0; | ||
38 | |||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | static int sha384_sparc64_init(struct shash_desc *desc) | ||
43 | { | ||
44 | struct sha512_state *sctx = shash_desc_ctx(desc); | ||
45 | sctx->state[0] = SHA384_H0; | ||
46 | sctx->state[1] = SHA384_H1; | ||
47 | sctx->state[2] = SHA384_H2; | ||
48 | sctx->state[3] = SHA384_H3; | ||
49 | sctx->state[4] = SHA384_H4; | ||
50 | sctx->state[5] = SHA384_H5; | ||
51 | sctx->state[6] = SHA384_H6; | ||
52 | sctx->state[7] = SHA384_H7; | ||
53 | sctx->count[0] = sctx->count[1] = 0; | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static void __sha512_sparc64_update(struct sha512_state *sctx, const u8 *data, | ||
59 | unsigned int len, unsigned int partial) | ||
60 | { | ||
61 | unsigned int done = 0; | ||
62 | |||
63 | if ((sctx->count[0] += len) < len) | ||
64 | sctx->count[1]++; | ||
65 | if (partial) { | ||
66 | done = SHA512_BLOCK_SIZE - partial; | ||
67 | memcpy(sctx->buf + partial, data, done); | ||
68 | sha512_sparc64_transform(sctx->state, sctx->buf, 1); | ||
69 | } | ||
70 | if (len - done >= SHA512_BLOCK_SIZE) { | ||
71 | const unsigned int rounds = (len - done) / SHA512_BLOCK_SIZE; | ||
72 | |||
73 | sha512_sparc64_transform(sctx->state, data + done, rounds); | ||
74 | done += rounds * SHA512_BLOCK_SIZE; | ||
75 | } | ||
76 | |||
77 | memcpy(sctx->buf, data + done, len - done); | ||
78 | } | ||
79 | |||
80 | static int sha512_sparc64_update(struct shash_desc *desc, const u8 *data, | ||
81 | unsigned int len) | ||
82 | { | ||
83 | struct sha512_state *sctx = shash_desc_ctx(desc); | ||
84 | unsigned int partial = sctx->count[0] % SHA512_BLOCK_SIZE; | ||
85 | |||
86 | /* Handle the fast case right here */ | ||
87 | if (partial + len < SHA512_BLOCK_SIZE) { | ||
88 | if ((sctx->count[0] += len) < len) | ||
89 | sctx->count[1]++; | ||
90 | memcpy(sctx->buf + partial, data, len); | ||
91 | } else | ||
92 | __sha512_sparc64_update(sctx, data, len, partial); | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int sha512_sparc64_final(struct shash_desc *desc, u8 *out) | ||
98 | { | ||
99 | struct sha512_state *sctx = shash_desc_ctx(desc); | ||
100 | unsigned int i, index, padlen; | ||
101 | __be64 *dst = (__be64 *)out; | ||
102 | __be64 bits[2]; | ||
103 | static const u8 padding[SHA512_BLOCK_SIZE] = { 0x80, }; | ||
104 | |||
105 | /* Save number of bits */ | ||
106 | bits[1] = cpu_to_be64(sctx->count[0] << 3); | ||
107 | bits[0] = cpu_to_be64(sctx->count[1] << 3 | sctx->count[0] >> 61); | ||
108 | |||
109 | /* Pad out to 112 mod 128 and append length */ | ||
110 | index = sctx->count[0] % SHA512_BLOCK_SIZE; | ||
111 | padlen = (index < 112) ? (112 - index) : ((SHA512_BLOCK_SIZE+112) - index); | ||
112 | |||
113 | /* We need to fill a whole block for __sha512_sparc64_update() */ | ||
114 | if (padlen <= 112) { | ||
115 | if ((sctx->count[0] += padlen) < padlen) | ||
116 | sctx->count[1]++; | ||
117 | memcpy(sctx->buf + index, padding, padlen); | ||
118 | } else { | ||
119 | __sha512_sparc64_update(sctx, padding, padlen, index); | ||
120 | } | ||
121 | __sha512_sparc64_update(sctx, (const u8 *)&bits, sizeof(bits), 112); | ||
122 | |||
123 | /* Store state in digest */ | ||
124 | for (i = 0; i < 8; i++) | ||
125 | dst[i] = cpu_to_be64(sctx->state[i]); | ||
126 | |||
127 | /* Wipe context */ | ||
128 | memset(sctx, 0, sizeof(*sctx)); | ||
129 | |||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static int sha384_sparc64_final(struct shash_desc *desc, u8 *hash) | ||
134 | { | ||
135 | u8 D[64]; | ||
136 | |||
137 | sha512_sparc64_final(desc, D); | ||
138 | |||
139 | memcpy(hash, D, 48); | ||
140 | memset(D, 0, 64); | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static struct shash_alg sha512 = { | ||
146 | .digestsize = SHA512_DIGEST_SIZE, | ||
147 | .init = sha512_sparc64_init, | ||
148 | .update = sha512_sparc64_update, | ||
149 | .final = sha512_sparc64_final, | ||
150 | .descsize = sizeof(struct sha512_state), | ||
151 | .base = { | ||
152 | .cra_name = "sha512", | ||
153 | .cra_driver_name= "sha512-sparc64", | ||
154 | .cra_flags = CRYPTO_ALG_TYPE_SHASH, | ||
155 | .cra_blocksize = SHA512_BLOCK_SIZE, | ||
156 | .cra_module = THIS_MODULE, | ||
157 | } | ||
158 | }; | ||
159 | |||
160 | static struct shash_alg sha384 = { | ||
161 | .digestsize = SHA384_DIGEST_SIZE, | ||
162 | .init = sha384_sparc64_init, | ||
163 | .update = sha512_sparc64_update, | ||
164 | .final = sha384_sparc64_final, | ||
165 | .descsize = sizeof(struct sha512_state), | ||
166 | .base = { | ||
167 | .cra_name = "sha384", | ||
168 | .cra_driver_name= "sha384-sparc64", | ||
169 | .cra_flags = CRYPTO_ALG_TYPE_SHASH, | ||
170 | .cra_blocksize = SHA384_BLOCK_SIZE, | ||
171 | .cra_module = THIS_MODULE, | ||
172 | } | ||
173 | }; | ||
174 | |||
175 | static bool __init sparc64_has_sha512_opcode(void) | ||
176 | { | ||
177 | unsigned long cfr; | ||
178 | |||
179 | if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO)) | ||
180 | return false; | ||
181 | |||
182 | __asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr)); | ||
183 | if (!(cfr & CFR_SHA512)) | ||
184 | return false; | ||
185 | |||
186 | return true; | ||
187 | } | ||
188 | |||
189 | static int __init sha512_sparc64_mod_init(void) | ||
190 | { | ||
191 | if (sparc64_has_sha512_opcode()) { | ||
192 | int ret = crypto_register_shash(&sha384); | ||
193 | if (ret < 0) | ||
194 | return ret; | ||
195 | |||
196 | ret = crypto_register_shash(&sha512); | ||
197 | if (ret < 0) { | ||
198 | crypto_unregister_shash(&sha384); | ||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | pr_info("Using sparc64 sha512 opcode optimized SHA-512/SHA-384 implementation\n"); | ||
203 | return 0; | ||
204 | } | ||
205 | pr_info("sparc64 sha512 opcode not available.\n"); | ||
206 | return -ENODEV; | ||
207 | } | ||
208 | |||
209 | static void __exit sha512_sparc64_mod_fini(void) | ||
210 | { | ||
211 | crypto_unregister_shash(&sha384); | ||
212 | crypto_unregister_shash(&sha512); | ||
213 | } | ||
214 | |||
215 | module_init(sha512_sparc64_mod_init); | ||
216 | module_exit(sha512_sparc64_mod_fini); | ||
217 | |||
218 | MODULE_LICENSE("GPL"); | ||
219 | MODULE_DESCRIPTION("SHA-384 and SHA-512 Secure Hash Algorithm, sparc64 sha512 opcode accelerated"); | ||
220 | |||
221 | MODULE_ALIAS("sha384"); | ||
222 | MODULE_ALIAS("sha512"); | ||