Add clang target pragma for mixed C/assembly x86-64 implementations
[libgcrypt.git] / cipher / sha256-intel-shaext.c
1 /* sha256-intel-shaext.S - SHAEXT accelerated SHA-256 transform function
2  * Copyright (C) 2018 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21
22 #include "types.h"
23
24 #if defined(HAVE_GCC_INLINE_ASM_SHAEXT) && \
25     defined(HAVE_GCC_INLINE_ASM_SSE41) && defined(USE_SHA256) && \
26     defined(ENABLE_SHAEXT_SUPPORT)
27
28 #if _GCRY_GCC_VERSION >= 40400 /* 4.4 */
29 /* Prevent compiler from issuing SSE instructions between asm blocks. */
30 #  pragma GCC target("no-sse")
31 #endif
32 #if __clang__
33 #  pragma clang attribute push (__attribute__((target("no-sse"))), apply_to = function)
34 #endif
35
36 /* Two macros to be called prior and after the use of SHA-EXT
37    instructions.  There should be no external function calls between
38    the use of these macros.  There purpose is to make sure that the
39    SSE regsiters are cleared and won't reveal any information about
40    the key or the data.  */
41 #ifdef __WIN64__
42 /* XMM6-XMM15 are callee-saved registers on WIN64. */
43 # define shaext_prepare_variable char win64tmp[2*16]
44 # define shaext_prepare_variable_size sizeof(win64tmp)
45 # define shaext_prepare()                                               \
46    do { asm volatile ("movdqu %%xmm6, (%0)\n"                           \
47                       "movdqu %%xmm7, (%1)\n"                           \
48                       :                                                 \
49                       : "r" (&win64tmp[0]), "r" (&win64tmp[16])         \
50                       : "memory");                                      \
51    } while (0)
52 # define shaext_cleanup(tmp0,tmp1)                                      \
53    do { asm volatile ("movdqu (%0), %%xmm6\n"                           \
54                       "movdqu (%1), %%xmm7\n"                           \
55                       "pxor %%xmm0, %%xmm0\n"                           \
56                       "pxor %%xmm1, %%xmm1\n"                           \
57                       "pxor %%xmm2, %%xmm2\n"                           \
58                       "pxor %%xmm3, %%xmm3\n"                           \
59                       "pxor %%xmm4, %%xmm4\n"                           \
60                       "pxor %%xmm5, %%xmm5\n"                           \
61                       "movdqa %%xmm0, (%2)\n\t"                         \
62                       "movdqa %%xmm0, (%3)\n\t"                         \
63                       :                                                 \
64                       : "r" (&win64tmp[0]), "r" (&win64tmp[16]),        \
65                         "r" (tmp0), "r" (tmp1)                          \
66                       : "memory");                                      \
67    } while (0)
68 #else
69 # define shaext_prepare_variable
70 # define shaext_prepare_variable_size 0
71 # define shaext_prepare() do { } while (0)
72 # define shaext_cleanup(tmp0,tmp1)                                      \
73    do { asm volatile ("pxor %%xmm0, %%xmm0\n"                           \
74                       "pxor %%xmm1, %%xmm1\n"                           \
75                       "pxor %%xmm2, %%xmm2\n"                           \
76                       "pxor %%xmm3, %%xmm3\n"                           \
77                       "pxor %%xmm4, %%xmm4\n"                           \
78                       "pxor %%xmm5, %%xmm5\n"                           \
79                       "pxor %%xmm6, %%xmm6\n"                           \
80                       "pxor %%xmm7, %%xmm7\n"                           \
81                       "movdqa %%xmm0, (%0)\n\t"                         \
82                       "movdqa %%xmm0, (%1)\n\t"                         \
83                       :                                                 \
84                       : "r" (tmp0), "r" (tmp1)                          \
85                       : "memory");                                      \
86    } while (0)
87 #endif
88
89 typedef struct u128_s
90 {
91   u32 a, b, c, d;
92 } u128_t;
93
94 /*
95  * Transform nblks*64 bytes (nblks*16 32-bit words) at DATA.
96  */
97 unsigned int
98 _gcry_sha256_transform_intel_shaext(u32 state[8], const unsigned char *data,
99                                     size_t nblks)
100 {
101   static const unsigned char bshuf_mask[16] __attribute__ ((aligned (16))) =
102     { 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 };
103   static const u128_t K[16] __attribute__ ((aligned (16))) =
104   {
105     { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5 },
106     { 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5 },
107     { 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3 },
108     { 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174 },
109     { 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc },
110     { 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da },
111     { 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7 },
112     { 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967 },
113     { 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13 },
114     { 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85 },
115     { 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3 },
116     { 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070 },
117     { 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5 },
118     { 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3 },
119     { 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208 },
120     { 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }
121   };
122   char save_buf[2 * 16 + 15];
123   char *abef_save;
124   char *cdgh_save;
125   shaext_prepare_variable;
126
127   if (nblks == 0)
128     return 0;
129
130   shaext_prepare ();
131
132   asm volatile ("" : "=r" (abef_save) : "0" (save_buf) : "memory");
133   abef_save = abef_save + (-(uintptr_t)abef_save & 15);
134   cdgh_save = abef_save + 16;
135
136   /* byteswap mask => XMM7 */
137   asm volatile ("movdqa %[mask], %%xmm7\n\t" /* Preload mask */
138                 :
139                 : [mask] "m" (*bshuf_mask)
140                 : "memory");
141
142   /* Load state.. ABEF_SAVE => STATE0 XMM1, CDGH_STATE => STATE1 XMM2 */
143   asm volatile ("movups 16(%[state]), %%xmm1\n\t" /* HGFE (xmm=EFGH) */
144                 "movups  0(%[state]), %%xmm0\n\t" /* DCBA (xmm=ABCD) */
145                 "movaps %%xmm1, %%xmm2\n\t"
146                 "shufps $0x11, %%xmm0, %%xmm1\n\t" /* ABEF (xmm=FEBA) */
147                 "shufps $0xbb, %%xmm0, %%xmm2\n\t" /* CDGH (xmm=HGDC) */
148                 :
149                 : [state] "r" (state)
150                 : "memory" );
151
152   /* Load message */
153   asm volatile ("movdqu 0*16(%[data]), %%xmm3\n\t"
154                 "movdqu 1*16(%[data]), %%xmm4\n\t"
155                 "movdqu 2*16(%[data]), %%xmm5\n\t"
156                 "movdqu 3*16(%[data]), %%xmm6\n\t"
157                 "pshufb %%xmm7, %%xmm3\n\t"
158                 "pshufb %%xmm7, %%xmm4\n\t"
159                 "pshufb %%xmm7, %%xmm5\n\t"
160                 "pshufb %%xmm7, %%xmm6\n\t"
161                 :
162                 : [data] "r" (data)
163                 : "memory" );
164   data += 64;
165
166   do
167     {
168       /* Save state */
169       asm volatile ("movdqa %%xmm1, (%[abef_save])\n\t"
170                     "movdqa %%xmm2, (%[cdgh_save])\n\t"
171                     :
172                     : [abef_save] "r" (abef_save), [cdgh_save] "r" (cdgh_save)
173                     : "memory" );
174
175       /* Round 0..3 */
176       asm volatile ("movdqa %%xmm3, %%xmm0\n\t"
177                       "paddd %[constants], %%xmm0\n\t"
178                       "sha256rnds2 %%xmm1, %%xmm2\n\t"
179                       "psrldq $8, %%xmm0\n\t"
180                       "sha256rnds2 %%xmm2, %%xmm1\n\t"
181                     :
182                     : [constants] "m" (K[0].a)
183                     : "memory" );
184
185       /* Round 4..7 */
186       asm volatile ("movdqa %%xmm4, %%xmm0\n\t"
187                       "paddd %[constants], %%xmm0\n\t"
188                       "sha256rnds2 %%xmm1, %%xmm2\n\t"
189                       "psrldq $8, %%xmm0\n\t"
190                       "sha256rnds2 %%xmm2, %%xmm1\n\t"
191                     "sha256msg1 %%xmm4, %%xmm3\n\t"
192                     :
193                     : [constants] "m" (K[1].a)
194                     : "memory" );
195
196       /* Round 8..11 */
197       asm volatile ("movdqa %%xmm5, %%xmm0\n\t"
198                       "paddd %[constants], %%xmm0\n\t"
199                       "sha256rnds2 %%xmm1, %%xmm2\n\t"
200                       "psrldq $8, %%xmm0\n\t"
201                       "sha256rnds2 %%xmm2, %%xmm1\n\t"
202                     "sha256msg1 %%xmm5, %%xmm4\n\t"
203                     :
204                     : [constants] "m" (K[2].a)
205                     : "memory" );
206
207 #define ROUND(k, MSG0, MSG1, MSG2, MSG3) \
208       asm volatile ("movdqa %%"MSG0", %%xmm0\n\t" \
209                       "paddd %[constants], %%xmm0\n\t" \
210                       "sha256rnds2 %%xmm1, %%xmm2\n\t" \
211                     "movdqa %%"MSG0", %%xmm7\n\t" \
212                     "palignr $4, %%"MSG3", %%xmm7\n\t" \
213                     "paddd %%xmm7, %%"MSG1"\n\t" \
214                     "sha256msg2 %%"MSG0", %%"MSG1"\n\t" \
215                       "psrldq $8, %%xmm0\n\t" \
216                       "sha256rnds2 %%xmm2, %%xmm1\n\t" \
217                     "sha256msg1 %%"MSG0", %%"MSG3"\n\t" \
218                     : \
219                     : [constants] "m" (K[k].a) \
220                     : "memory" )
221
222       /* Rounds 12..15 to 48..51 */
223       ROUND(3, "xmm6", "xmm3", "xmm4", "xmm5");
224       ROUND(4, "xmm3", "xmm4", "xmm5", "xmm6");
225       ROUND(5, "xmm4", "xmm5", "xmm6", "xmm3");
226       ROUND(6, "xmm5", "xmm6", "xmm3", "xmm4");
227       ROUND(7, "xmm6", "xmm3", "xmm4", "xmm5");
228       ROUND(8, "xmm3", "xmm4", "xmm5", "xmm6");
229       ROUND(9, "xmm4", "xmm5", "xmm6", "xmm3");
230       ROUND(10, "xmm5", "xmm6", "xmm3", "xmm4");
231       ROUND(11, "xmm6", "xmm3", "xmm4", "xmm5");
232       ROUND(12, "xmm3", "xmm4", "xmm5", "xmm6");
233
234       if (--nblks == 0)
235         break;
236
237       /* Round 52..55 */
238       asm volatile ("movdqa %%xmm4, %%xmm0\n\t"
239                       "paddd %[constants], %%xmm0\n\t"
240                       "sha256rnds2 %%xmm1, %%xmm2\n\t"
241                     "movdqa %%xmm4, %%xmm7\n\t"
242                     "palignr $4, %%xmm3, %%xmm7\n\t"
243                     "movdqu 0*16(%[data]), %%xmm3\n\t"
244                     "paddd %%xmm7, %%xmm5\n\t"
245                     "sha256msg2 %%xmm4, %%xmm5\n\t"
246                       "psrldq $8, %%xmm0\n\t"
247                       "sha256rnds2 %%xmm2, %%xmm1\n\t"
248                     :
249                     : [constants] "m" (K[13].a), [data] "r" (data)
250                     : "memory" );
251
252       /* Round 56..59 */
253       asm volatile ("movdqa %%xmm5, %%xmm0\n\t"
254                       "paddd %[constants], %%xmm0\n\t"
255                       "sha256rnds2 %%xmm1, %%xmm2\n\t"
256                     "movdqa %%xmm5, %%xmm7\n\t"
257                     "palignr $4, %%xmm4, %%xmm7\n\t"
258                     "movdqu 1*16(%[data]), %%xmm4\n\t"
259                     "paddd %%xmm7, %%xmm6\n\t"
260                     "movdqa %[mask], %%xmm7\n\t" /* Reload mask */
261                     "sha256msg2 %%xmm5, %%xmm6\n\t"
262                     "movdqu 2*16(%[data]), %%xmm5\n\t"
263                       "psrldq $8, %%xmm0\n\t"
264                       "sha256rnds2 %%xmm2, %%xmm1\n\t"
265                     :
266                     : [constants] "m" (K[14].a), [mask] "m" (*bshuf_mask),
267                       [data] "r" (data)
268                     : "memory" );
269
270       /* Round 60..63 */
271       asm volatile ("movdqa %%xmm6, %%xmm0\n\t"
272                     "pshufb %%xmm7, %%xmm3\n\t"
273                     "movdqu 3*16(%[data]), %%xmm6\n\t"
274                       "paddd %[constants], %%xmm0\n\t"
275                     "pshufb %%xmm7, %%xmm4\n\t"
276                       "sha256rnds2 %%xmm1, %%xmm2\n\t"
277                       "psrldq $8, %%xmm0\n\t"
278                     "pshufb %%xmm7, %%xmm5\n\t"
279                       "sha256rnds2 %%xmm2, %%xmm1\n\t"
280                     :
281                     : [constants] "m" (K[15].a), [data] "r" (data)
282                     : "memory" );
283       data += 64;
284
285       /* Merge states */
286       asm volatile ("paddd (%[abef_save]), %%xmm1\n\t"
287                     "paddd (%[cdgh_save]), %%xmm2\n\t"
288                     "pshufb %%xmm7, %%xmm6\n\t"
289                     :
290                     : [abef_save] "r" (abef_save), [cdgh_save] "r" (cdgh_save)
291                     : "memory" );
292     }
293   while (1);
294
295   /* Round 52..55 */
296   asm volatile ("movdqa %%xmm4, %%xmm0\n\t"
297                   "paddd %[constants], %%xmm0\n\t"
298                   "sha256rnds2 %%xmm1, %%xmm2\n\t"
299                 "movdqa %%xmm4, %%xmm7\n\t"
300                 "palignr $4, %%xmm3, %%xmm7\n\t"
301                 "paddd %%xmm7, %%xmm5\n\t"
302                 "sha256msg2 %%xmm4, %%xmm5\n\t"
303                   "psrldq $8, %%xmm0\n\t"
304                   "sha256rnds2 %%xmm2, %%xmm1\n\t"
305                 :
306                 : [constants] "m" (K[13].a)
307                 : "memory" );
308
309   /* Round 56..59 */
310   asm volatile ("movdqa %%xmm5, %%xmm0\n\t"
311                   "paddd %[constants], %%xmm0\n\t"
312                   "sha256rnds2 %%xmm1, %%xmm2\n\t"
313                 "movdqa %%xmm5, %%xmm7\n\t"
314                 "palignr $4, %%xmm4, %%xmm7\n\t"
315                 "paddd %%xmm7, %%xmm6\n\t"
316                 "movdqa %[mask], %%xmm7\n\t" /* Reload mask */
317                 "sha256msg2 %%xmm5, %%xmm6\n\t"
318                   "psrldq $8, %%xmm0\n\t"
319                   "sha256rnds2 %%xmm2, %%xmm1\n\t"
320                 :
321                 : [constants] "m" (K[14].a), [mask] "m" (*bshuf_mask)
322                 : "memory" );
323
324   /* Round 60..63 */
325   asm volatile ("movdqa %%xmm6, %%xmm0\n\t"
326                   "paddd %[constants], %%xmm0\n\t"
327                   "sha256rnds2 %%xmm1, %%xmm2\n\t"
328                   "psrldq $8, %%xmm0\n\t"
329                   "sha256rnds2 %%xmm2, %%xmm1\n\t"
330                 :
331                 : [constants] "m" (K[15].a)
332                 : "memory" );
333
334   /* Merge states */
335   asm volatile ("paddd (%[abef_save]), %%xmm1\n\t"
336                 "paddd (%[cdgh_save]), %%xmm2\n\t"
337                 :
338                 : [abef_save] "r" (abef_save), [cdgh_save] "r" (cdgh_save)
339                 : "memory" );
340
341   /* Save state (XMM1=FEBA, XMM2=HGDC) */
342   asm volatile ("movaps %%xmm1, %%xmm0\n\t"
343                 "shufps $0x11, %%xmm2, %%xmm1\n\t" /* xmm=ABCD */
344                 "shufps $0xbb, %%xmm2, %%xmm0\n\t" /* xmm=EFGH */
345                 "movups %%xmm1, 16(%[state])\n\t"
346                 "movups %%xmm0,  0(%[state])\n\t"
347                 :
348                 : [state] "r" (state)
349                 : "memory" );
350
351   shaext_cleanup (abef_save, cdgh_save);
352   return 0;
353 }
354
355 #if __clang__
356 #  pragma clang attribute pop
357 #endif
358
359 #endif /* HAVE_GCC_INLINE_ASM_SHA_EXT */