1 /** \file external_timing_for_test.c
2 *
3 * \brief Helper functions to test an alternate timing implementation.
4 */
5
6 /*
7 * Copyright The Mbed TLS Contributors
8 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
9 */
10
11 #include <timing_alt.h>
12 #if defined(MBEDTLS_TIMING_ALT)
13
14 #if !defined(unix) && !defined(__unix__) && !defined(__unix) && \
15 !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \
16 !defined(__HAIKU__) && !defined(__midipix__)
17 #error "This module only works on Unix and Windows, see MBEDTLS_TIMING_C in config.h"
18 #endif
19
20 /* *INDENT-OFF* */
21 #ifndef asm
22 #define asm __asm
23 #endif
24 /* *INDENT-ON* */
25
26 #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
27
28 #include <windows.h>
29 #include <process.h>
30
31 struct _hr_time {
32 LARGE_INTEGER start;
33 };
34
35 #else
36
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <signal.h>
40 /* time.h should be included independently of MBEDTLS_HAVE_TIME. If the
41 * platform matches the ifdefs above, it will be used. */
42 #include <time.h>
43 #include <sys/time.h>
44 struct _hr_time {
45 struct timeval start;
46 };
47 #endif /* _WIN32 && !EFIX64 && !EFI32 */
48
49 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
50 (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
51
52 #define HAVE_HARDCLOCK
53
mbedtls_timing_hardclock(void)54 unsigned long mbedtls_timing_hardclock(void)
55 {
56 unsigned long tsc;
57 __asm rdtsc
58 __asm mov[tsc], eax
59 return tsc;
60 }
61 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
62 ( _MSC_VER && _M_IX86 ) || __WATCOMC__ */
63
64 /* some versions of mingw-64 have 32-bit longs even on x84_64 */
65 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
66 defined(__GNUC__) && (defined(__i386__) || ( \
67 (defined(__amd64__) || defined(__x86_64__)) && __SIZEOF_LONG__ == 4))
68
69 #define HAVE_HARDCLOCK
70
mbedtls_timing_hardclock(void)71 unsigned long mbedtls_timing_hardclock(void)
72 {
73 unsigned long lo, hi;
74 asm volatile ("rdtsc" : "=a" (lo), "=d" (hi));
75 return lo;
76 }
77 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
78 __GNUC__ && __i386__ */
79
80 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
81 defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__))
82
83 #define HAVE_HARDCLOCK
84
mbedtls_timing_hardclock(void)85 unsigned long mbedtls_timing_hardclock(void)
86 {
87 unsigned long lo, hi;
88 asm volatile ("rdtsc" : "=a" (lo), "=d" (hi));
89 return lo | (hi << 32);
90 }
91 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
92 __GNUC__ && ( __amd64__ || __x86_64__ ) */
93
94 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
95 defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
96
97 #define HAVE_HARDCLOCK
98
mbedtls_timing_hardclock(void)99 unsigned long mbedtls_timing_hardclock(void)
100 {
101 unsigned long tbl, tbu0, tbu1;
102
103 do {
104 asm volatile ("mftbu %0" : "=r" (tbu0));
105 asm volatile ("mftb %0" : "=r" (tbl));
106 asm volatile ("mftbu %0" : "=r" (tbu1));
107 } while (tbu0 != tbu1);
108
109 return tbl;
110 }
111 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
112 __GNUC__ && ( __powerpc__ || __ppc__ ) */
113
114 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
115 defined(__GNUC__) && defined(__sparc64__)
116
117 #if defined(__OpenBSD__)
118 #warning OpenBSD does not allow access to tick register using software version instead
119 #else
120 #define HAVE_HARDCLOCK
121
mbedtls_timing_hardclock(void)122 unsigned long mbedtls_timing_hardclock(void)
123 {
124 unsigned long tick;
125 asm volatile ("rdpr %%tick, %0;" : "=&r" (tick));
126 return tick;
127 }
128 #endif /* __OpenBSD__ */
129 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
130 __GNUC__ && __sparc64__ */
131
132 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
133 defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__)
134
135 #define HAVE_HARDCLOCK
136
mbedtls_timing_hardclock(void)137 unsigned long mbedtls_timing_hardclock(void)
138 {
139 unsigned long tick;
140 asm volatile (".byte 0x83, 0x41, 0x00, 0x00");
141 asm volatile ("mov %%g1, %0" : "=r" (tick));
142 return tick;
143 }
144 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
145 __GNUC__ && __sparc__ && !__sparc64__ */
146
147 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
148 defined(__GNUC__) && defined(__alpha__)
149
150 #define HAVE_HARDCLOCK
151
mbedtls_timing_hardclock(void)152 unsigned long mbedtls_timing_hardclock(void)
153 {
154 unsigned long cc;
155 asm volatile ("rpcc %0" : "=r" (cc));
156 return cc & 0xFFFFFFFF;
157 }
158 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
159 __GNUC__ && __alpha__ */
160
161 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
162 defined(__GNUC__) && defined(__ia64__)
163
164 #define HAVE_HARDCLOCK
165
mbedtls_timing_hardclock(void)166 unsigned long mbedtls_timing_hardclock(void)
167 {
168 unsigned long itc;
169 asm volatile ("mov %0 = ar.itc" : "=r" (itc));
170 return itc;
171 }
172 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
173 __GNUC__ && __ia64__ */
174
175 #if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \
176 !defined(EFIX64) && !defined(EFI32)
177
178 #define HAVE_HARDCLOCK
179
mbedtls_timing_hardclock(void)180 unsigned long mbedtls_timing_hardclock(void)
181 {
182 LARGE_INTEGER offset;
183
184 QueryPerformanceCounter(&offset);
185
186 return (unsigned long) (offset.QuadPart);
187 }
188 #endif /* !HAVE_HARDCLOCK && _MSC_VER && !EFIX64 && !EFI32 */
189
190 #if !defined(HAVE_HARDCLOCK)
191
192 #define HAVE_HARDCLOCK
193
194 static int hardclock_init = 0;
195 static struct timeval tv_init;
196
mbedtls_timing_hardclock(void)197 unsigned long mbedtls_timing_hardclock(void)
198 {
199 struct timeval tv_cur;
200
201 if (hardclock_init == 0) {
202 gettimeofday(&tv_init, NULL);
203 hardclock_init = 1;
204 }
205
206 gettimeofday(&tv_cur, NULL);
207 return (tv_cur.tv_sec - tv_init.tv_sec) * 1000000U
208 + (tv_cur.tv_usec - tv_init.tv_usec);
209 }
210 #endif /* !HAVE_HARDCLOCK */
211
212 volatile int mbedtls_timing_alarmed = 0;
213
214 #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
215
mbedtls_timing_get_timer(struct mbedtls_timing_hr_time * val,int reset)216 unsigned long mbedtls_timing_get_timer(struct mbedtls_timing_hr_time *val, int reset)
217 {
218 struct _hr_time *t = (struct _hr_time *) val;
219
220 if (reset) {
221 QueryPerformanceCounter(&t->start);
222 return 0;
223 } else {
224 unsigned long delta;
225 LARGE_INTEGER now, hfreq;
226 QueryPerformanceCounter(&now);
227 QueryPerformanceFrequency(&hfreq);
228 delta = (unsigned long) ((now.QuadPart - t->start.QuadPart) * 1000ul
229 / hfreq.QuadPart);
230 return delta;
231 }
232 }
233
234 /* It's OK to use a global because alarm() is supposed to be global anyway */
235 static DWORD alarmMs;
236
TimerProc(void * TimerContext)237 static void TimerProc(void *TimerContext)
238 {
239 (void) TimerContext;
240 Sleep(alarmMs);
241 mbedtls_timing_alarmed = 1;
242 /* _endthread will be called implicitly on return
243 * That ensures execution of thread function's epilogue */
244 }
245
mbedtls_set_alarm(int seconds)246 void mbedtls_set_alarm(int seconds)
247 {
248 if (seconds == 0) {
249 /* No need to create a thread for this simple case.
250 * Also, this shorcut is more reliable at least on MinGW32 */
251 mbedtls_timing_alarmed = 1;
252 return;
253 }
254
255 mbedtls_timing_alarmed = 0;
256 alarmMs = seconds * 1000;
257 (void) _beginthread(TimerProc, 0, NULL);
258 }
259
260 #else /* _WIN32 && !EFIX64 && !EFI32 */
261
mbedtls_timing_get_timer(struct mbedtls_timing_hr_time * val,int reset)262 unsigned long mbedtls_timing_get_timer(struct mbedtls_timing_hr_time *val, int reset)
263 {
264 struct _hr_time *t = (struct _hr_time *) val;
265
266 if (reset) {
267 gettimeofday(&t->start, NULL);
268 return 0;
269 } else {
270 unsigned long delta;
271 struct timeval now;
272 gettimeofday(&now, NULL);
273 delta = (now.tv_sec - t->start.tv_sec) * 1000ul
274 + (now.tv_usec - t->start.tv_usec) / 1000;
275 return delta;
276 }
277 }
278
sighandler(int signum)279 static void sighandler(int signum)
280 {
281 mbedtls_timing_alarmed = 1;
282 signal(signum, sighandler);
283 }
284
mbedtls_set_alarm(int seconds)285 void mbedtls_set_alarm(int seconds)
286 {
287 mbedtls_timing_alarmed = 0;
288 signal(SIGALRM, sighandler);
289 alarm(seconds);
290 if (seconds == 0) {
291 /* alarm(0) cancelled any previous pending alarm, but the
292 handler won't fire, so raise the flag straight away. */
293 mbedtls_timing_alarmed = 1;
294 }
295 }
296
297 #endif /* _WIN32 && !EFIX64 && !EFI32 */
298
299 /*
300 * Set delays to watch
301 */
mbedtls_timing_set_delay(void * data,uint32_t int_ms,uint32_t fin_ms)302 void mbedtls_timing_set_delay(void *data, uint32_t int_ms, uint32_t fin_ms)
303 {
304 mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data;
305
306 ctx->int_ms = int_ms;
307 ctx->fin_ms = fin_ms;
308
309 if (fin_ms != 0) {
310 (void) mbedtls_timing_get_timer(&ctx->timer, 1);
311 }
312 }
313
314 /*
315 * Get number of delays expired
316 */
mbedtls_timing_get_delay(void * data)317 int mbedtls_timing_get_delay(void *data)
318 {
319 mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data;
320 unsigned long elapsed_ms;
321
322 if (ctx->fin_ms == 0) {
323 return -1;
324 }
325
326 elapsed_ms = mbedtls_timing_get_timer(&ctx->timer, 0);
327
328 if (elapsed_ms >= ctx->fin_ms) {
329 return 2;
330 }
331
332 if (elapsed_ms >= ctx->int_ms) {
333 return 1;
334 }
335
336 return 0;
337 }
338
339 #endif /* MBEDTLS_TIMING_ALT */
340