1 // ppc_power8.cpp - written and placed in the public domain by
2 // Jeffrey Walton, Uri Blumenthal and Marcel Raad.
3 //
4 // This source file uses intrinsics and built-ins to gain access to
5 // Power8 instructions. A separate source file is needed because
6 // additional CXXFLAGS are required to enable the appropriate
7 // instructions sets in some build configurations.
8
9 #include "pch.h"
10 #include "config.h"
11
12 #ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY
13 # include <signal.h>
14 # include <setjmp.h>
15 #endif
16
17 #if defined(_ARCH_PWR8) || defined(__CRYPTO__)
18 # include "ppc_simd.h"
19 #endif
20
21 // Squash MS LNK4221 and libtool warnings
22 extern const char PPC_POWER8_FNAME[] = __FILE__;
23
NAMESPACE_BEGIN(CryptoPP)24 NAMESPACE_BEGIN(CryptoPP)
25
26 // ************************* Feature Probes ************************* //
27
28 #ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY
29 extern "C" {
30 typedef void (*SigHandler)(int);
31
32 static jmp_buf s_jmpSIGILL;
33 static void SigIllHandler(int)
34 {
35 longjmp(s_jmpSIGILL, 1);
36 }
37 }
38 #endif // CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
39
40 #if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64)
41
CPU_ProbePower8()42 bool CPU_ProbePower8()
43 {
44 #if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES)
45 return false;
46 #elif (_ARCH_PWR8) && defined(CRYPTOPP_POWER8_AVAILABLE)
47 # if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY)
48
49 // longjmp and clobber warnings. Volatile is required.
50 // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
51 volatile int result = true;
52
53 volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler);
54 if (oldHandler == SIG_ERR)
55 return false;
56
57 volatile sigset_t oldMask;
58 if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
59 {
60 signal(SIGILL, oldHandler);
61 return false;
62 }
63
64 if (setjmp(s_jmpSIGILL))
65 result = false;
66 else
67 {
68 // POWER8 added 64-bit SIMD operations
69 const word64 x = W64LIT(0xffffffffffffffff);
70 word64 w1[2] = {x, x}, w2[2] = {4, 6}, w3[2];
71
72 // Specifically call the VSX loads and stores with 64-bit types
73 #if defined(__ibmxl__) || (defined(_AIX) && defined(__xlC__)) || defined(__clang__)
74 const uint64x2_p v1 = vec_xl(0, (unsigned long long*)w1);
75 const uint64x2_p v2 = vec_xl(0, (unsigned long long*)w2);
76 const uint64x2_p v3 = vec_add(v1, v2); // 64-bit add
77 vec_xst(v3, 0, (unsigned long long*)w3);
78 #else
79 const uint64x2_p v1 = (uint64x2_p)vec_vsx_ld(0, (const byte*)w1);
80 const uint64x2_p v2 = (uint64x2_p)vec_vsx_ld(0, (const byte*)w2);
81 const uint64x2_p v3 = vec_add(v1, v2); // 64-bit add
82 vec_vsx_st((uint8x16_p)v3, 0, (byte*)w3);
83 #endif
84
85 // Relies on integer wrap
86 result = (w3[0] == 3 && w3[1] == 5);
87 }
88
89 sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
90 signal(SIGILL, oldHandler);
91 return result;
92 # endif
93 #else
94 return false;
95 #endif // _ARCH_PWR8
96 }
97
CPU_ProbeAES()98 bool CPU_ProbeAES()
99 {
100 #if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES)
101 return false;
102 #elif (__CRYPTO__) && defined(CRYPTOPP_POWER8_AES_AVAILABLE)
103 # if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY)
104
105 // longjmp and clobber warnings. Volatile is required.
106 // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
107 volatile int result = true;
108
109 volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler);
110 if (oldHandler == SIG_ERR)
111 return false;
112
113 volatile sigset_t oldMask;
114 if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
115 {
116 signal(SIGILL, oldHandler);
117 return false;
118 }
119
120 if (setjmp(s_jmpSIGILL))
121 result = false;
122 else
123 {
124 byte key[16] = {0xA0, 0xFA, 0xFE, 0x17, 0x88, 0x54, 0x2c, 0xb1,
125 0x23, 0xa3, 0x39, 0x39, 0x2a, 0x6c, 0x76, 0x05};
126 byte state[16] = {0x19, 0x3d, 0xe3, 0xb3, 0xa0, 0xf4, 0xe2, 0x2b,
127 0x9a, 0xc6, 0x8d, 0x2a, 0xe9, 0xf8, 0x48, 0x08};
128 byte r[16] = {255}, z[16] = {};
129
130 uint8x16_p k = (uint8x16_p)VecLoad(0, key);
131 uint8x16_p s = (uint8x16_p)VecLoad(0, state);
132 s = VecEncrypt(s, k);
133 s = VecEncryptLast(s, k);
134 s = VecDecrypt(s, k);
135 s = VecDecryptLast(s, k);
136 VecStore(s, r);
137
138 result = (0 != std::memcmp(r, z, 16));
139 }
140
141 sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
142 signal(SIGILL, oldHandler);
143 return result;
144 # endif
145 #else
146 return false;
147 #endif // __CRYPTO__
148 }
149
CPU_ProbeSHA256()150 bool CPU_ProbeSHA256()
151 {
152 #if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES)
153 return false;
154 #elif (__CRYPTO__) && defined(CRYPTOPP_POWER8_SHA_AVAILABLE)
155 # if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY)
156
157 // longjmp and clobber warnings. Volatile is required.
158 // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
159 volatile int result = false;
160
161 volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler);
162 if (oldHandler == SIG_ERR)
163 return false;
164
165 volatile sigset_t oldMask;
166 if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
167 {
168 signal(SIGILL, oldHandler);
169 return false;
170 }
171
172 if (setjmp(s_jmpSIGILL))
173 result = false;
174 else
175 {
176 byte r[16], z[16] = {0};
177 uint8x16_p x = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
178
179 x = VecSHA256<0,0>(x);
180 x = VecSHA256<0,0xf>(x);
181 x = VecSHA256<1,0>(x);
182 x = VecSHA256<1,0xf>(x);
183 VecStore(x, r);
184
185 result = (0 == std::memcmp(r, z, 16));
186 }
187
188 sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
189 signal(SIGILL, oldHandler);
190 return result;
191 # endif
192 #else
193 return false;
194 #endif // CRYPTOPP_ALTIVEC_AVAILABLE
195 }
196
CPU_ProbeSHA512()197 bool CPU_ProbeSHA512()
198 {
199 #if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES)
200 return false;
201 #elif (__CRYPTO__) && defined(CRYPTOPP_POWER8_SHA_AVAILABLE)
202 # if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY)
203
204 // longjmp and clobber warnings. Volatile is required.
205 // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
206 volatile int result = false;
207
208 volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler);
209 if (oldHandler == SIG_ERR)
210 return false;
211
212 volatile sigset_t oldMask;
213 if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
214 {
215 signal(SIGILL, oldHandler);
216 return false;
217 }
218
219 if (setjmp(s_jmpSIGILL))
220 result = false;
221 else
222 {
223 byte r[16], z[16] = {0};
224 uint8x16_p x = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
225
226 x = VecSHA512<0,0>(x);
227 x = VecSHA512<0,0xf>(x);
228 x = VecSHA512<1,0>(x);
229 x = VecSHA512<1,0xf>(x);
230 VecStore(x, r);
231
232 result = (0 == std::memcmp(r, z, 16));
233 }
234
235 sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
236 signal(SIGILL, oldHandler);
237 return result;
238 # endif
239 #else
240 return false;
241 #endif // CRYPTOPP_POWER8_AVAILABLE
242 }
243
244 #endif // PPC32 or PPC64
245
246 NAMESPACE_END
247