Line data Source code
1 : /* crc-intel-pclmul.c - Intel PCLMUL accelerated CRC implementation
2 : * Copyright (C) 2016 Jussi Kivilinna <jussi.kivilinna@iki.fi>
3 : *
4 : * This file is part of Libgcrypt.
5 : *
6 : * Libgcrypt is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU Lesser General Public License as
8 : * published by the Free Software Foundation; either version 2.1 of
9 : * the License, or (at your option) any later version.
10 : *
11 : * Libgcrypt is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU Lesser General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public
17 : * License along with this program; if not, write to the Free Software
18 : * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 : *
20 : */
21 :
22 : #include <config.h>
23 : #include <stdio.h>
24 : #include <stdlib.h>
25 : #include <string.h>
26 :
27 : #include "g10lib.h"
28 :
29 : #include "bithelp.h"
30 : #include "bufhelp.h"
31 :
32 :
33 : #if defined(ENABLE_PCLMUL_SUPPORT) && defined(ENABLE_SSE41_SUPPORT) && \
34 : __GNUC__ >= 4 && \
35 : ((defined(__i386__) && SIZEOF_UNSIGNED_LONG == 4) || defined(__x86_64__))
36 :
37 :
38 : #if _GCRY_GCC_VERSION >= 40400 /* 4.4 */
39 : /* Prevent compiler from issuing SSE instructions between asm blocks. */
40 : # pragma GCC target("no-sse")
41 : #endif
42 :
43 :
44 : #define ALIGNED_16 __attribute__ ((aligned (16)))
45 :
46 :
47 : /* Constants structure for generic reflected/non-reflected CRC32 CLMUL
48 : * functions. */
49 : struct crc32_consts_s
50 : {
51 : /* k: { x^(32*17), x^(32*15), x^(32*5), x^(32*3), x^(32*2), 0 } mod P(x) */
52 : u64 k[6];
53 : /* my_p: { floor(x^64 / P(x)), P(x) } */
54 : u64 my_p[2];
55 : };
56 :
57 :
58 : /* CLMUL constants for CRC32 and CRC32RFC1510. */
59 : static const struct crc32_consts_s crc32_consts ALIGNED_16 =
60 : {
61 : { /* k[6] = reverse_33bits( x^(32*y) mod P(x) ) */
62 : U64_C(0x154442bd4), U64_C(0x1c6e41596), /* y = { 17, 15 } */
63 : U64_C(0x1751997d0), U64_C(0x0ccaa009e), /* y = { 5, 3 } */
64 : U64_C(0x163cd6124), 0 /* y = 2 */
65 : },
66 : { /* my_p[2] = reverse_33bits ( { floor(x^64 / P(x)), P(x) } ) */
67 : U64_C(0x1f7011641), U64_C(0x1db710641)
68 : }
69 : };
70 :
71 : /* CLMUL constants for CRC24RFC2440 (polynomial multiplied with x⁸). */
72 : static const struct crc32_consts_s crc24rfc2440_consts ALIGNED_16 =
73 : {
74 : { /* k[6] = x^(32*y) mod P(x) << 32*/
75 : U64_C(0x08289a00) << 32, U64_C(0x74b44a00) << 32, /* y = { 17, 15 } */
76 : U64_C(0xc4b14d00) << 32, U64_C(0xfd7e0c00) << 32, /* y = { 5, 3 } */
77 : U64_C(0xd9fe8c00) << 32, 0 /* y = 2 */
78 : },
79 : { /* my_p[2] = { floor(x^64 / P(x)), P(x) } */
80 : U64_C(0x1f845fe24), U64_C(0x1864cfb00)
81 : }
82 : };
83 :
84 : /* Common constants for CRC32 algorithms. */
85 : static const byte crc32_refl_shuf_shift[3 * 16] ALIGNED_16 =
86 : {
87 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
88 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
89 : 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
90 : 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
91 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
92 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
93 : };
94 : static const byte crc32_shuf_shift[3 * 16] ALIGNED_16 =
95 : {
96 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
97 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
98 : 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
99 : 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
100 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
101 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
102 : };
103 : static const byte *crc32_bswap_shuf = &crc32_shuf_shift[16];
104 : static const byte crc32_partial_fold_input_mask[16 + 16] ALIGNED_16 =
105 : {
106 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
107 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
108 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
109 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
110 : };
111 : static const u64 crc32_merge9to15_shuf[15 - 9 + 1][2] ALIGNED_16 =
112 : {
113 : { U64_C(0x0706050403020100), U64_C(0xffffffffffffff0f) }, /* 9 */
114 : { U64_C(0x0706050403020100), U64_C(0xffffffffffff0f0e) },
115 : { U64_C(0x0706050403020100), U64_C(0xffffffffff0f0e0d) },
116 : { U64_C(0x0706050403020100), U64_C(0xffffffff0f0e0d0c) },
117 : { U64_C(0x0706050403020100), U64_C(0xffffff0f0e0d0c0b) },
118 : { U64_C(0x0706050403020100), U64_C(0xffff0f0e0d0c0b0a) },
119 : { U64_C(0x0706050403020100), U64_C(0xff0f0e0d0c0b0a09) }, /* 15 */
120 : };
121 : static const u64 crc32_merge5to7_shuf[7 - 5 + 1][2] ALIGNED_16 =
122 : {
123 : { U64_C(0xffffff0703020100), U64_C(0xffffffffffffffff) }, /* 5 */
124 : { U64_C(0xffff070603020100), U64_C(0xffffffffffffffff) },
125 : { U64_C(0xff07060503020100), U64_C(0xffffffffffffffff) }, /* 7 */
126 : };
127 :
128 : /* PCLMUL functions for reflected CRC32. */
129 : static inline void
130 0 : crc32_reflected_bulk (u32 *pcrc, const byte *inbuf, size_t inlen,
131 : const struct crc32_consts_s *consts)
132 : {
133 0 : if (inlen >= 8 * 16)
134 : {
135 0 : asm volatile ("movd %[crc], %%xmm4\n\t"
136 : "movdqu %[inbuf_0], %%xmm0\n\t"
137 : "movdqu %[inbuf_1], %%xmm1\n\t"
138 : "movdqu %[inbuf_2], %%xmm2\n\t"
139 : "movdqu %[inbuf_3], %%xmm3\n\t"
140 : "pxor %%xmm4, %%xmm0\n\t"
141 : :
142 : : [inbuf_0] "m" (inbuf[0 * 16]),
143 0 : [inbuf_1] "m" (inbuf[1 * 16]),
144 0 : [inbuf_2] "m" (inbuf[2 * 16]),
145 0 : [inbuf_3] "m" (inbuf[3 * 16]),
146 : [crc] "m" (*pcrc)
147 : );
148 :
149 0 : inbuf += 4 * 16;
150 0 : inlen -= 4 * 16;
151 :
152 0 : asm volatile ("movdqa %[k1k2], %%xmm4\n\t"
153 : :
154 : : [k1k2] "m" (consts->k[1 - 1])
155 : );
156 :
157 : /* Fold by 4. */
158 0 : while (inlen >= 4 * 16)
159 : {
160 0 : asm volatile ("movdqu %[inbuf_0], %%xmm5\n\t"
161 : "movdqa %%xmm0, %%xmm6\n\t"
162 : "pclmulqdq $0x00, %%xmm4, %%xmm0\n\t"
163 : "pclmulqdq $0x11, %%xmm4, %%xmm6\n\t"
164 : "pxor %%xmm5, %%xmm0\n\t"
165 : "pxor %%xmm6, %%xmm0\n\t"
166 :
167 : "movdqu %[inbuf_1], %%xmm5\n\t"
168 : "movdqa %%xmm1, %%xmm6\n\t"
169 : "pclmulqdq $0x00, %%xmm4, %%xmm1\n\t"
170 : "pclmulqdq $0x11, %%xmm4, %%xmm6\n\t"
171 : "pxor %%xmm5, %%xmm1\n\t"
172 : "pxor %%xmm6, %%xmm1\n\t"
173 :
174 : "movdqu %[inbuf_2], %%xmm5\n\t"
175 : "movdqa %%xmm2, %%xmm6\n\t"
176 : "pclmulqdq $0x00, %%xmm4, %%xmm2\n\t"
177 : "pclmulqdq $0x11, %%xmm4, %%xmm6\n\t"
178 : "pxor %%xmm5, %%xmm2\n\t"
179 : "pxor %%xmm6, %%xmm2\n\t"
180 :
181 : "movdqu %[inbuf_3], %%xmm5\n\t"
182 : "movdqa %%xmm3, %%xmm6\n\t"
183 : "pclmulqdq $0x00, %%xmm4, %%xmm3\n\t"
184 : "pclmulqdq $0x11, %%xmm4, %%xmm6\n\t"
185 : "pxor %%xmm5, %%xmm3\n\t"
186 : "pxor %%xmm6, %%xmm3\n\t"
187 : :
188 : : [inbuf_0] "m" (inbuf[0 * 16]),
189 0 : [inbuf_1] "m" (inbuf[1 * 16]),
190 0 : [inbuf_2] "m" (inbuf[2 * 16]),
191 0 : [inbuf_3] "m" (inbuf[3 * 16])
192 : );
193 :
194 0 : inbuf += 4 * 16;
195 0 : inlen -= 4 * 16;
196 : }
197 :
198 0 : asm volatile ("movdqa %[k3k4], %%xmm6\n\t"
199 : "movdqa %[my_p], %%xmm5\n\t"
200 : :
201 : : [k3k4] "m" (consts->k[3 - 1]),
202 : [my_p] "m" (consts->my_p[0])
203 : );
204 :
205 : /* Fold 4 to 1. */
206 :
207 0 : asm volatile ("movdqa %%xmm0, %%xmm4\n\t"
208 : "pclmulqdq $0x00, %%xmm6, %%xmm0\n\t"
209 : "pclmulqdq $0x11, %%xmm6, %%xmm4\n\t"
210 : "pxor %%xmm1, %%xmm0\n\t"
211 : "pxor %%xmm4, %%xmm0\n\t"
212 :
213 : "movdqa %%xmm0, %%xmm4\n\t"
214 : "pclmulqdq $0x00, %%xmm6, %%xmm0\n\t"
215 : "pclmulqdq $0x11, %%xmm6, %%xmm4\n\t"
216 : "pxor %%xmm2, %%xmm0\n\t"
217 : "pxor %%xmm4, %%xmm0\n\t"
218 :
219 : "movdqa %%xmm0, %%xmm4\n\t"
220 : "pclmulqdq $0x00, %%xmm6, %%xmm0\n\t"
221 : "pclmulqdq $0x11, %%xmm6, %%xmm4\n\t"
222 : "pxor %%xmm3, %%xmm0\n\t"
223 : "pxor %%xmm4, %%xmm0\n\t"
224 : :
225 : :
226 : );
227 : }
228 : else
229 : {
230 0 : asm volatile ("movd %[crc], %%xmm1\n\t"
231 : "movdqu %[inbuf], %%xmm0\n\t"
232 : "movdqa %[k3k4], %%xmm6\n\t"
233 : "pxor %%xmm1, %%xmm0\n\t"
234 : "movdqa %[my_p], %%xmm5\n\t"
235 : :
236 : : [inbuf] "m" (*inbuf),
237 : [crc] "m" (*pcrc),
238 : [k3k4] "m" (consts->k[3 - 1]),
239 : [my_p] "m" (consts->my_p[0])
240 : );
241 :
242 0 : inbuf += 16;
243 0 : inlen -= 16;
244 : }
245 :
246 : /* Fold by 1. */
247 0 : if (inlen >= 16)
248 : {
249 0 : while (inlen >= 16)
250 : {
251 : /* Load next block to XMM2. Fold XMM0 to XMM0:XMM1. */
252 0 : asm volatile ("movdqu %[inbuf], %%xmm2\n\t"
253 : "movdqa %%xmm0, %%xmm1\n\t"
254 : "pclmulqdq $0x00, %%xmm6, %%xmm0\n\t"
255 : "pclmulqdq $0x11, %%xmm6, %%xmm1\n\t"
256 : "pxor %%xmm2, %%xmm0\n\t"
257 : "pxor %%xmm1, %%xmm0\n\t"
258 : :
259 : : [inbuf] "m" (*inbuf)
260 : );
261 :
262 0 : inbuf += 16;
263 0 : inlen -= 16;
264 : }
265 : }
266 :
267 : /* Partial fold. */
268 0 : if (inlen)
269 : {
270 : /* Load last input and add padding zeros. */
271 0 : asm volatile ("movdqu %[shr_shuf], %%xmm3\n\t"
272 : "movdqu %[shl_shuf], %%xmm4\n\t"
273 : "movdqu %[mask], %%xmm2\n\t"
274 :
275 : "movdqa %%xmm0, %%xmm1\n\t"
276 : "pshufb %%xmm4, %%xmm0\n\t"
277 : "movdqu %[inbuf], %%xmm4\n\t"
278 : "pshufb %%xmm3, %%xmm1\n\t"
279 : "pand %%xmm4, %%xmm2\n\t"
280 : "por %%xmm1, %%xmm2\n\t"
281 :
282 : "movdqa %%xmm0, %%xmm1\n\t"
283 : "pclmulqdq $0x00, %%xmm6, %%xmm0\n\t"
284 : "pclmulqdq $0x11, %%xmm6, %%xmm1\n\t"
285 : "pxor %%xmm2, %%xmm0\n\t"
286 : "pxor %%xmm1, %%xmm0\n\t"
287 : :
288 0 : : [inbuf] "m" (*(inbuf - 16 + inlen)),
289 : [mask] "m" (crc32_partial_fold_input_mask[inlen]),
290 : [shl_shuf] "m" (crc32_refl_shuf_shift[inlen]),
291 0 : [shr_shuf] "m" (crc32_refl_shuf_shift[inlen + 16])
292 : );
293 :
294 0 : inbuf += inlen;
295 0 : inlen -= inlen;
296 : }
297 :
298 : /* Final fold. */
299 0 : asm volatile (/* reduce 128-bits to 96-bits */
300 : "movdqa %%xmm0, %%xmm1\n\t"
301 : "pclmulqdq $0x10, %%xmm6, %%xmm0\n\t"
302 : "psrldq $8, %%xmm1\n\t"
303 : "pxor %%xmm1, %%xmm0\n\t"
304 :
305 : /* reduce 96-bits to 64-bits */
306 : "pshufd $0xfc, %%xmm0, %%xmm1\n\t" /* [00][00][00][x] */
307 : "pshufd $0xf9, %%xmm0, %%xmm0\n\t" /* [00][00][x>>64][x>>32] */
308 : "pclmulqdq $0x00, %[k5], %%xmm1\n\t" /* [00][00][xx][xx] */
309 : "pxor %%xmm1, %%xmm0\n\t" /* top 64-bit are zero */
310 :
311 : /* barrett reduction */
312 : "pshufd $0xf3, %%xmm0, %%xmm1\n\t" /* [00][00][x>>32][00] */
313 : "pslldq $4, %%xmm0\n\t" /* [??][x>>32][??][??] */
314 : "pclmulqdq $0x00, %%xmm5, %%xmm1\n\t" /* [00][xx][xx][00] */
315 : "pclmulqdq $0x10, %%xmm5, %%xmm1\n\t" /* [00][xx][xx][00] */
316 : "pxor %%xmm1, %%xmm0\n\t"
317 :
318 : /* store CRC */
319 : "pextrd $2, %%xmm0, %[out]\n\t"
320 : : [out] "=m" (*pcrc)
321 : : [k5] "m" (consts->k[5 - 1])
322 : );
323 0 : }
324 :
325 : static inline void
326 0 : crc32_reflected_less_than_16 (u32 *pcrc, const byte *inbuf, size_t inlen,
327 : const struct crc32_consts_s *consts)
328 : {
329 0 : if (inlen < 4)
330 : {
331 0 : u32 crc = *pcrc;
332 : u32 data;
333 :
334 0 : asm volatile ("movdqa %[my_p], %%xmm5\n\t"
335 : :
336 : : [my_p] "m" (consts->my_p[0])
337 : );
338 :
339 0 : if (inlen == 1)
340 : {
341 0 : data = inbuf[0];
342 0 : data ^= crc;
343 0 : data <<= 24;
344 0 : crc >>= 8;
345 : }
346 0 : else if (inlen == 2)
347 : {
348 0 : data = *((const u16 *)inbuf);
349 0 : data ^= crc;
350 0 : data <<= 16;
351 0 : crc >>= 16;
352 : }
353 : else
354 : {
355 0 : data = *((const u16 *)inbuf);
356 0 : data |= inbuf[2] << 16;
357 0 : data ^= crc;
358 0 : data <<= 8;
359 0 : crc >>= 24;
360 : }
361 :
362 : /* Barrett reduction */
363 0 : asm volatile ("movd %[in], %%xmm0\n\t"
364 : "movd %[crc], %%xmm1\n\t"
365 :
366 : "pclmulqdq $0x00, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */
367 : "psllq $32, %%xmm1\n\t"
368 : "pshufd $0xfc, %%xmm0, %%xmm0\n\t" /* [00][00][00][x] */
369 : "pclmulqdq $0x10, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */
370 : "pxor %%xmm1, %%xmm0\n\t"
371 :
372 : "pextrd $1, %%xmm0, %[out]\n\t"
373 : : [out] "=m" (*pcrc)
374 : : [in] "rm" (data),
375 : [crc] "rm" (crc)
376 : );
377 : }
378 0 : else if (inlen == 4)
379 : {
380 : /* Barrett reduction */
381 0 : asm volatile ("movd %[crc], %%xmm1\n\t"
382 : "movd %[in], %%xmm0\n\t"
383 : "movdqa %[my_p], %%xmm5\n\t"
384 : "pxor %%xmm1, %%xmm0\n\t"
385 :
386 : "pclmulqdq $0x00, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */
387 : "pshufd $0xfc, %%xmm0, %%xmm0\n\t" /* [00][00][00][x] */
388 : "pclmulqdq $0x10, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */
389 :
390 : "pextrd $1, %%xmm0, %[out]\n\t"
391 : : [out] "=m" (*pcrc)
392 : : [in] "m" (*inbuf),
393 : [crc] "m" (*pcrc),
394 : [my_p] "m" (consts->my_p[0])
395 : );
396 : }
397 : else
398 : {
399 0 : asm volatile ("movdqu %[shuf], %%xmm4\n\t"
400 : "movd %[crc], %%xmm1\n\t"
401 : "movdqa %[my_p], %%xmm5\n\t"
402 : "movdqa %[k3k4], %%xmm6\n\t"
403 : :
404 : : [shuf] "m" (crc32_refl_shuf_shift[inlen]),
405 : [crc] "m" (*pcrc),
406 : [my_p] "m" (consts->my_p[0]),
407 : [k3k4] "m" (consts->k[3 - 1])
408 : );
409 :
410 0 : if (inlen >= 8)
411 : {
412 0 : asm volatile ("movq %[inbuf], %%xmm0\n\t"
413 : :
414 : : [inbuf] "m" (*inbuf)
415 : );
416 0 : if (inlen > 8)
417 : {
418 0 : asm volatile (/*"pinsrq $1, %[inbuf_tail], %%xmm0\n\t"*/
419 : "movq %[inbuf_tail], %%xmm2\n\t"
420 : "punpcklqdq %%xmm2, %%xmm0\n\t"
421 : "pshufb %[merge_shuf], %%xmm0\n\t"
422 : :
423 0 : : [inbuf_tail] "m" (inbuf[inlen - 8]),
424 : [merge_shuf] "m"
425 0 : (*crc32_merge9to15_shuf[inlen - 9])
426 : );
427 : }
428 : }
429 : else
430 : {
431 0 : asm volatile ("movd %[inbuf], %%xmm0\n\t"
432 : "pinsrd $1, %[inbuf_tail], %%xmm0\n\t"
433 : "pshufb %[merge_shuf], %%xmm0\n\t"
434 : :
435 : : [inbuf] "m" (*inbuf),
436 0 : [inbuf_tail] "m" (inbuf[inlen - 4]),
437 : [merge_shuf] "m"
438 0 : (*crc32_merge5to7_shuf[inlen - 5])
439 : );
440 : }
441 :
442 : /* Final fold. */
443 0 : asm volatile ("pxor %%xmm1, %%xmm0\n\t"
444 : "pshufb %%xmm4, %%xmm0\n\t"
445 :
446 : /* reduce 128-bits to 96-bits */
447 : "movdqa %%xmm0, %%xmm1\n\t"
448 : "pclmulqdq $0x10, %%xmm6, %%xmm0\n\t"
449 : "psrldq $8, %%xmm1\n\t"
450 : "pxor %%xmm1, %%xmm0\n\t" /* top 32-bit are zero */
451 :
452 : /* reduce 96-bits to 64-bits */
453 : "pshufd $0xfc, %%xmm0, %%xmm1\n\t" /* [00][00][00][x] */
454 : "pshufd $0xf9, %%xmm0, %%xmm0\n\t" /* [00][00][x>>64][x>>32] */
455 : "pclmulqdq $0x00, %[k5], %%xmm1\n\t" /* [00][00][xx][xx] */
456 : "pxor %%xmm1, %%xmm0\n\t" /* top 64-bit are zero */
457 :
458 : /* barrett reduction */
459 : "pshufd $0xf3, %%xmm0, %%xmm1\n\t" /* [00][00][x>>32][00] */
460 : "pslldq $4, %%xmm0\n\t" /* [??][x>>32][??][??] */
461 : "pclmulqdq $0x00, %%xmm5, %%xmm1\n\t" /* [00][xx][xx][00] */
462 : "pclmulqdq $0x10, %%xmm5, %%xmm1\n\t" /* [00][xx][xx][00] */
463 : "pxor %%xmm1, %%xmm0\n\t"
464 :
465 : /* store CRC */
466 : "pextrd $2, %%xmm0, %[out]\n\t"
467 : : [out] "=m" (*pcrc)
468 : : [k5] "m" (consts->k[5 - 1])
469 : );
470 : }
471 0 : }
472 :
473 : /* PCLMUL functions for non-reflected CRC32. */
474 : static inline void
475 0 : crc32_bulk (u32 *pcrc, const byte *inbuf, size_t inlen,
476 : const struct crc32_consts_s *consts)
477 : {
478 0 : asm volatile ("movdqa %[bswap], %%xmm7\n\t"
479 : :
480 0 : : [bswap] "m" (*crc32_bswap_shuf)
481 : );
482 :
483 0 : if (inlen >= 8 * 16)
484 : {
485 0 : asm volatile ("movd %[crc], %%xmm4\n\t"
486 : "movdqu %[inbuf_0], %%xmm0\n\t"
487 : "movdqu %[inbuf_1], %%xmm1\n\t"
488 : "movdqu %[inbuf_2], %%xmm2\n\t"
489 : "pxor %%xmm4, %%xmm0\n\t"
490 : "movdqu %[inbuf_3], %%xmm3\n\t"
491 : "pshufb %%xmm7, %%xmm0\n\t"
492 : "pshufb %%xmm7, %%xmm1\n\t"
493 : "pshufb %%xmm7, %%xmm2\n\t"
494 : "pshufb %%xmm7, %%xmm3\n\t"
495 : :
496 : : [inbuf_0] "m" (inbuf[0 * 16]),
497 0 : [inbuf_1] "m" (inbuf[1 * 16]),
498 0 : [inbuf_2] "m" (inbuf[2 * 16]),
499 0 : [inbuf_3] "m" (inbuf[3 * 16]),
500 : [crc] "m" (*pcrc)
501 : );
502 :
503 0 : inbuf += 4 * 16;
504 0 : inlen -= 4 * 16;
505 :
506 0 : asm volatile ("movdqa %[k1k2], %%xmm4\n\t"
507 : :
508 : : [k1k2] "m" (consts->k[1 - 1])
509 : );
510 :
511 : /* Fold by 4. */
512 0 : while (inlen >= 4 * 16)
513 : {
514 0 : asm volatile ("movdqu %[inbuf_0], %%xmm5\n\t"
515 : "movdqa %%xmm0, %%xmm6\n\t"
516 : "pshufb %%xmm7, %%xmm5\n\t"
517 : "pclmulqdq $0x01, %%xmm4, %%xmm0\n\t"
518 : "pclmulqdq $0x10, %%xmm4, %%xmm6\n\t"
519 : "pxor %%xmm5, %%xmm0\n\t"
520 : "pxor %%xmm6, %%xmm0\n\t"
521 :
522 : "movdqu %[inbuf_1], %%xmm5\n\t"
523 : "movdqa %%xmm1, %%xmm6\n\t"
524 : "pshufb %%xmm7, %%xmm5\n\t"
525 : "pclmulqdq $0x01, %%xmm4, %%xmm1\n\t"
526 : "pclmulqdq $0x10, %%xmm4, %%xmm6\n\t"
527 : "pxor %%xmm5, %%xmm1\n\t"
528 : "pxor %%xmm6, %%xmm1\n\t"
529 :
530 : "movdqu %[inbuf_2], %%xmm5\n\t"
531 : "movdqa %%xmm2, %%xmm6\n\t"
532 : "pshufb %%xmm7, %%xmm5\n\t"
533 : "pclmulqdq $0x01, %%xmm4, %%xmm2\n\t"
534 : "pclmulqdq $0x10, %%xmm4, %%xmm6\n\t"
535 : "pxor %%xmm5, %%xmm2\n\t"
536 : "pxor %%xmm6, %%xmm2\n\t"
537 :
538 : "movdqu %[inbuf_3], %%xmm5\n\t"
539 : "movdqa %%xmm3, %%xmm6\n\t"
540 : "pshufb %%xmm7, %%xmm5\n\t"
541 : "pclmulqdq $0x01, %%xmm4, %%xmm3\n\t"
542 : "pclmulqdq $0x10, %%xmm4, %%xmm6\n\t"
543 : "pxor %%xmm5, %%xmm3\n\t"
544 : "pxor %%xmm6, %%xmm3\n\t"
545 : :
546 : : [inbuf_0] "m" (inbuf[0 * 16]),
547 0 : [inbuf_1] "m" (inbuf[1 * 16]),
548 0 : [inbuf_2] "m" (inbuf[2 * 16]),
549 0 : [inbuf_3] "m" (inbuf[3 * 16])
550 : );
551 :
552 0 : inbuf += 4 * 16;
553 0 : inlen -= 4 * 16;
554 : }
555 :
556 0 : asm volatile ("movdqa %[k3k4], %%xmm6\n\t"
557 : "movdqa %[my_p], %%xmm5\n\t"
558 : :
559 : : [k3k4] "m" (consts->k[3 - 1]),
560 : [my_p] "m" (consts->my_p[0])
561 : );
562 :
563 : /* Fold 4 to 1. */
564 :
565 0 : asm volatile ("movdqa %%xmm0, %%xmm4\n\t"
566 : "pclmulqdq $0x01, %%xmm6, %%xmm0\n\t"
567 : "pclmulqdq $0x10, %%xmm6, %%xmm4\n\t"
568 : "pxor %%xmm1, %%xmm0\n\t"
569 : "pxor %%xmm4, %%xmm0\n\t"
570 :
571 : "movdqa %%xmm0, %%xmm4\n\t"
572 : "pclmulqdq $0x01, %%xmm6, %%xmm0\n\t"
573 : "pclmulqdq $0x10, %%xmm6, %%xmm4\n\t"
574 : "pxor %%xmm2, %%xmm0\n\t"
575 : "pxor %%xmm4, %%xmm0\n\t"
576 :
577 : "movdqa %%xmm0, %%xmm4\n\t"
578 : "pclmulqdq $0x01, %%xmm6, %%xmm0\n\t"
579 : "pclmulqdq $0x10, %%xmm6, %%xmm4\n\t"
580 : "pxor %%xmm3, %%xmm0\n\t"
581 : "pxor %%xmm4, %%xmm0\n\t"
582 : :
583 : :
584 : );
585 : }
586 : else
587 : {
588 0 : asm volatile ("movd %[crc], %%xmm1\n\t"
589 : "movdqu %[inbuf], %%xmm0\n\t"
590 : "movdqa %[k3k4], %%xmm6\n\t"
591 : "pxor %%xmm1, %%xmm0\n\t"
592 : "movdqa %[my_p], %%xmm5\n\t"
593 : "pshufb %%xmm7, %%xmm0\n\t"
594 : :
595 : : [inbuf] "m" (*inbuf),
596 : [crc] "m" (*pcrc),
597 : [k3k4] "m" (consts->k[3 - 1]),
598 : [my_p] "m" (consts->my_p[0])
599 : );
600 :
601 0 : inbuf += 16;
602 0 : inlen -= 16;
603 : }
604 :
605 : /* Fold by 1. */
606 0 : if (inlen >= 16)
607 : {
608 0 : while (inlen >= 16)
609 : {
610 : /* Load next block to XMM2. Fold XMM0 to XMM0:XMM1. */
611 0 : asm volatile ("movdqu %[inbuf], %%xmm2\n\t"
612 : "movdqa %%xmm0, %%xmm1\n\t"
613 : "pclmulqdq $0x01, %%xmm6, %%xmm0\n\t"
614 : "pshufb %%xmm7, %%xmm2\n\t"
615 : "pclmulqdq $0x10, %%xmm6, %%xmm1\n\t"
616 : "pxor %%xmm2, %%xmm0\n\t"
617 : "pxor %%xmm1, %%xmm0\n\t"
618 : :
619 : : [inbuf] "m" (*inbuf)
620 : );
621 :
622 0 : inbuf += 16;
623 0 : inlen -= 16;
624 : }
625 : }
626 :
627 : /* Partial fold. */
628 0 : if (inlen)
629 : {
630 : /* Load last input and add padding zeros. */
631 0 : asm volatile ("movdqu %[shl_shuf], %%xmm4\n\t"
632 : "movdqu %[shr_shuf], %%xmm3\n\t"
633 : "movdqu %[mask], %%xmm2\n\t"
634 :
635 : "movdqa %%xmm0, %%xmm1\n\t"
636 : "pshufb %%xmm4, %%xmm0\n\t"
637 : "movdqu %[inbuf], %%xmm4\n\t"
638 : "pshufb %%xmm3, %%xmm1\n\t"
639 : "pand %%xmm4, %%xmm2\n\t"
640 : "por %%xmm1, %%xmm2\n\t"
641 :
642 : "pshufb %%xmm7, %%xmm2\n\t"
643 :
644 : "movdqa %%xmm0, %%xmm1\n\t"
645 : "pclmulqdq $0x01, %%xmm6, %%xmm0\n\t"
646 : "pclmulqdq $0x10, %%xmm6, %%xmm1\n\t"
647 : "pxor %%xmm2, %%xmm0\n\t"
648 : "pxor %%xmm1, %%xmm0\n\t"
649 : :
650 0 : : [inbuf] "m" (*(inbuf - 16 + inlen)),
651 : [mask] "m" (crc32_partial_fold_input_mask[inlen]),
652 0 : [shl_shuf] "m" (crc32_refl_shuf_shift[32 - inlen]),
653 0 : [shr_shuf] "m" (crc32_shuf_shift[inlen + 16])
654 : );
655 :
656 0 : inbuf += inlen;
657 0 : inlen -= inlen;
658 : }
659 :
660 : /* Final fold. */
661 0 : asm volatile (/* reduce 128-bits to 96-bits */
662 : "movdqa %%xmm0, %%xmm1\n\t"
663 : "pclmulqdq $0x11, %%xmm6, %%xmm0\n\t"
664 : "pslldq $8, %%xmm1\n\t"
665 : "pxor %%xmm1, %%xmm0\n\t" /* bottom 32-bit are zero */
666 :
667 : /* reduce 96-bits to 64-bits */
668 : "pshufd $0x30, %%xmm0, %%xmm1\n\t" /* [00][x>>96][00][00] */
669 : "pshufd $0x24, %%xmm0, %%xmm0\n\t" /* [00][xx][xx][00] */
670 : "pclmulqdq $0x01, %[k5], %%xmm1\n\t" /* [00][xx][xx][00] */
671 : "pxor %%xmm1, %%xmm0\n\t" /* top and bottom 32-bit are zero */
672 :
673 : /* barrett reduction */
674 : "pshufd $0x01, %%xmm0, %%xmm1\n\t" /* [00][00][00][x>>32] */
675 : "pclmulqdq $0x01, %%xmm5, %%xmm0\n\t" /* [00][xx][xx][xx] */
676 : "psrldq $4, %%xmm0\n\t" /* [00][00][xx][xx] */
677 : "pclmulqdq $0x10, %%xmm5, %%xmm0\n\t"
678 : "pxor %%xmm1, %%xmm0\n\t"
679 :
680 : /* store CRC in input endian */
681 : "movd %%xmm0, %%eax\n\t"
682 : "bswapl %%eax\n\t"
683 : "movl %%eax, %[out]\n\t"
684 : : [out] "=m" (*pcrc)
685 : : [k5] "m" (consts->k[5 - 1])
686 : : "eax" );
687 0 : }
688 :
689 : static inline void
690 0 : crc32_less_than_16 (u32 *pcrc, const byte *inbuf, size_t inlen,
691 : const struct crc32_consts_s *consts)
692 : {
693 0 : if (inlen < 4)
694 : {
695 0 : u32 crc = *pcrc;
696 : u32 data;
697 :
698 0 : asm volatile ("movdqa %[my_p], %%xmm5\n\t"
699 : :
700 : : [my_p] "m" (consts->my_p[0])
701 : );
702 :
703 0 : if (inlen == 1)
704 : {
705 0 : data = inbuf[0];
706 0 : data ^= crc;
707 0 : data = _gcry_bswap32(data << 24);
708 0 : crc = _gcry_bswap32(crc >> 8);
709 : }
710 0 : else if (inlen == 2)
711 : {
712 0 : data = *((const u16 *)inbuf);
713 0 : data ^= crc;
714 0 : data = _gcry_bswap32(data << 16);
715 0 : crc = _gcry_bswap32(crc >> 16);
716 : }
717 : else
718 : {
719 0 : data = *((const u16 *)inbuf);
720 0 : data |= inbuf[2] << 16;
721 0 : data ^= crc;
722 0 : data = _gcry_bswap32(data << 8);
723 0 : crc = _gcry_bswap32(crc >> 24);
724 : }
725 :
726 : /* Barrett reduction */
727 0 : asm volatile ("movd %[in], %%xmm0\n\t"
728 : "psllq $32, %%xmm0\n\t" /* [00][00][xx][00] */
729 : "movd %[crc], %%xmm1\n\t"
730 :
731 : "pclmulqdq $0x00, %%xmm5, %%xmm0\n\t" /* [00][xx][xx][00] */
732 : "pclmulqdq $0x11, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */
733 : "pxor %%xmm1, %%xmm0\n\t"
734 :
735 : /* store CRC in input endian */
736 : "movd %%xmm0, %%eax\n\t"
737 : "bswapl %%eax\n\t"
738 : "movl %%eax, %[out]\n\t"
739 : : [out] "=m" (*pcrc)
740 : : [in] "r" (data),
741 : [crc] "r" (crc)
742 : : "eax" );
743 : }
744 0 : else if (inlen == 4)
745 : {
746 : /* Barrett reduction */
747 0 : asm volatile ("movd %[crc], %%xmm0\n\t"
748 : "movd %[in], %%xmm1\n\t"
749 : "movdqa %[my_p], %%xmm5\n\t"
750 : :
751 : : [in] "m" (*inbuf),
752 : [crc] "m" (*pcrc),
753 : [my_p] "m" (consts->my_p[0])
754 : : "cc" );
755 :
756 0 : asm volatile ("pxor %%xmm1, %%xmm0\n\t"
757 : "pshufb %[bswap], %%xmm0\n\t" /* [xx][00][00][00] */
758 :
759 : "pclmulqdq $0x01, %%xmm5, %%xmm0\n\t" /* [00][xx][xx][00] */
760 : "pclmulqdq $0x11, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */
761 : :
762 0 : : [bswap] "m" (*crc32_bswap_shuf)
763 : : "cc" );
764 :
765 0 : asm volatile (/* store CRC in input endian */
766 : "movd %%xmm0, %%eax\n\t"
767 : "bswapl %%eax\n\t"
768 : "movl %%eax, %[out]\n\t"
769 : : [out] "=m" (*pcrc)
770 : :
771 : : "eax", "cc" );
772 : }
773 : else
774 : {
775 0 : asm volatile ("movdqu %[shuf], %%xmm7\n\t"
776 : "movd %[crc], %%xmm1\n\t"
777 : "movdqa %[my_p], %%xmm5\n\t"
778 : "movdqa %[k3k4], %%xmm6\n\t"
779 : :
780 0 : : [shuf] "m" (crc32_shuf_shift[32 - inlen]),
781 : [crc] "m" (*pcrc),
782 : [my_p] "m" (consts->my_p[0]),
783 : [k3k4] "m" (consts->k[3 - 1])
784 : );
785 :
786 0 : if (inlen >= 8)
787 : {
788 0 : asm volatile ("movq %[inbuf], %%xmm0\n\t"
789 : :
790 : : [inbuf] "m" (*inbuf)
791 : );
792 0 : if (inlen > 8)
793 : {
794 0 : asm volatile (/*"pinsrq $1, %[inbuf_tail], %%xmm0\n\t"*/
795 : "movq %[inbuf_tail], %%xmm2\n\t"
796 : "punpcklqdq %%xmm2, %%xmm0\n\t"
797 : "pshufb %[merge_shuf], %%xmm0\n\t"
798 : :
799 0 : : [inbuf_tail] "m" (inbuf[inlen - 8]),
800 : [merge_shuf] "m"
801 0 : (*crc32_merge9to15_shuf[inlen - 9])
802 : );
803 : }
804 : }
805 : else
806 : {
807 0 : asm volatile ("movd %[inbuf], %%xmm0\n\t"
808 : "pinsrd $1, %[inbuf_tail], %%xmm0\n\t"
809 : "pshufb %[merge_shuf], %%xmm0\n\t"
810 : :
811 : : [inbuf] "m" (*inbuf),
812 0 : [inbuf_tail] "m" (inbuf[inlen - 4]),
813 : [merge_shuf] "m"
814 0 : (*crc32_merge5to7_shuf[inlen - 5])
815 : );
816 : }
817 :
818 : /* Final fold. */
819 0 : asm volatile ("pxor %%xmm1, %%xmm0\n\t"
820 : "pshufb %%xmm7, %%xmm0\n\t"
821 :
822 : /* reduce 128-bits to 96-bits */
823 : "movdqa %%xmm0, %%xmm1\n\t"
824 : "pclmulqdq $0x11, %%xmm6, %%xmm0\n\t"
825 : "pslldq $8, %%xmm1\n\t"
826 : "pxor %%xmm1, %%xmm0\n\t" /* bottom 32-bit are zero */
827 :
828 : /* reduce 96-bits to 64-bits */
829 : "pshufd $0x30, %%xmm0, %%xmm1\n\t" /* [00][x>>96][00][00] */
830 : "pshufd $0x24, %%xmm0, %%xmm0\n\t" /* [00][xx][xx][00] */
831 : "pclmulqdq $0x01, %[k5], %%xmm1\n\t" /* [00][xx][xx][00] */
832 : "pxor %%xmm1, %%xmm0\n\t" /* top and bottom 32-bit are zero */
833 :
834 : /* barrett reduction */
835 : "pshufd $0x01, %%xmm0, %%xmm1\n\t" /* [00][00][00][x>>32] */
836 : "pclmulqdq $0x01, %%xmm5, %%xmm0\n\t" /* [00][xx][xx][xx] */
837 : "psrldq $4, %%xmm0\n\t" /* [00][00][xx][xx] */
838 : "pclmulqdq $0x10, %%xmm5, %%xmm0\n\t"
839 : "pxor %%xmm1, %%xmm0\n\t"
840 :
841 : /* store CRC in input endian */
842 : "movd %%xmm0, %%eax\n\t"
843 : "bswapl %%eax\n\t"
844 : "movl %%eax, %[out]\n\t"
845 : : [out] "=m" (*pcrc)
846 : : [k5] "m" (consts->k[5 - 1])
847 : : "eax" );
848 : }
849 0 : }
850 :
851 : void
852 0 : _gcry_crc32_intel_pclmul (u32 *pcrc, const byte *inbuf, size_t inlen)
853 : {
854 0 : const struct crc32_consts_s *consts = &crc32_consts;
855 : #if defined(__x86_64__) && defined(__WIN64__)
856 : char win64tmp[2 * 16];
857 :
858 : /* XMM6-XMM7 need to be restored after use. */
859 : asm volatile ("movdqu %%xmm6, 0*16(%0)\n\t"
860 : "movdqu %%xmm7, 1*16(%0)\n\t"
861 : :
862 : : "r" (win64tmp)
863 : : "memory");
864 : #endif
865 :
866 0 : if (!inlen)
867 0 : return;
868 :
869 0 : if (inlen >= 16)
870 0 : crc32_reflected_bulk(pcrc, inbuf, inlen, consts);
871 : else
872 0 : crc32_reflected_less_than_16(pcrc, inbuf, inlen, consts);
873 :
874 : #if defined(__x86_64__) && defined(__WIN64__)
875 : /* Restore used registers. */
876 : asm volatile("movdqu 0*16(%0), %%xmm6\n\t"
877 : "movdqu 1*16(%0), %%xmm7\n\t"
878 : :
879 : : "r" (win64tmp)
880 : : "memory");
881 : #endif
882 : }
883 :
884 : void
885 0 : _gcry_crc24rfc2440_intel_pclmul (u32 *pcrc, const byte *inbuf, size_t inlen)
886 : {
887 0 : const struct crc32_consts_s *consts = &crc24rfc2440_consts;
888 : #if defined(__x86_64__) && defined(__WIN64__)
889 : char win64tmp[2 * 16];
890 :
891 : /* XMM6-XMM7 need to be restored after use. */
892 : asm volatile ("movdqu %%xmm6, 0*16(%0)\n\t"
893 : "movdqu %%xmm7, 1*16(%0)\n\t"
894 : :
895 : : "r" (win64tmp)
896 : : "memory");
897 : #endif
898 :
899 0 : if (!inlen)
900 0 : return;
901 :
902 : /* Note: *pcrc in input endian. */
903 :
904 0 : if (inlen >= 16)
905 0 : crc32_bulk(pcrc, inbuf, inlen, consts);
906 : else
907 0 : crc32_less_than_16(pcrc, inbuf, inlen, consts);
908 :
909 : #if defined(__x86_64__) && defined(__WIN64__)
910 : /* Restore used registers. */
911 : asm volatile("movdqu 0*16(%0), %%xmm6\n\t"
912 : "movdqu 1*16(%0), %%xmm7\n\t"
913 : :
914 : : "r" (win64tmp)
915 : : "memory");
916 : #endif
917 : }
918 :
919 : #endif /* USE_INTEL_PCLMUL */
|