/work/mbedtls-2.28.8/library/timing.c
Line  | Count  | Source  | 
1  |  | /*  | 
2  |  |  *  Portable interface to the CPU cycle counter  | 
3  |  |  *  | 
4  |  |  *  Copyright The Mbed TLS Contributors  | 
5  |  |  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later  | 
6  |  |  */  | 
7  |  |  | 
8  |  | #include <string.h>  | 
9  |  |  | 
10  |  | #include "common.h"  | 
11  |  |  | 
12  |  | #include "mbedtls/platform.h"  | 
13  |  |  | 
14  |  | #if defined(MBEDTLS_TIMING_C)  | 
15  |  |  | 
16  |  | #include "mbedtls/timing.h"  | 
17  |  |  | 
18  |  | #if !defined(MBEDTLS_TIMING_ALT)  | 
19  |  |  | 
20  |  | #if !defined(unix) && !defined(__unix__) && !defined(__unix) && \  | 
21  |  |     !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \  | 
22  |  |     !defined(__HAIKU__) && !defined(__midipix__)  | 
23  |  | #error "This module only works on Unix and Windows, see MBEDTLS_TIMING_C in config.h"  | 
24  |  | #endif  | 
25  |  |  | 
26  |  | /* *INDENT-OFF* */  | 
27  |  | #ifndef asm  | 
28  | 0  | #define asm __asm  | 
29  |  | #endif  | 
30  |  | /* *INDENT-ON* */  | 
31  |  |  | 
32  |  | #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)  | 
33  |  |  | 
34  |  | #include <windows.h>  | 
35  |  | #include <process.h>  | 
36  |  |  | 
37  |  | struct _hr_time { | 
38  |  |     LARGE_INTEGER start;  | 
39  |  | };  | 
40  |  |  | 
41  |  | #else  | 
42  |  |  | 
43  |  | #include <unistd.h>  | 
44  |  | #include <sys/types.h>  | 
45  |  | #include <signal.h>  | 
46  |  | /* time.h should be included independently of MBEDTLS_HAVE_TIME. If the  | 
47  |  |  * platform matches the ifdefs above, it will be used. */  | 
48  |  | #include <time.h>  | 
49  |  | #include <sys/time.h>  | 
50  |  | struct _hr_time { | 
51  |  |     struct timeval start;  | 
52  |  | };  | 
53  |  | #endif /* _WIN32 && !EFIX64 && !EFI32 */  | 
54  |  |  | 
55  |  | #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) &&  \  | 
56  |  |     (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)  | 
57  |  |  | 
58  |  | #define HAVE_HARDCLOCK  | 
59  |  |  | 
60  |  | unsigned long mbedtls_timing_hardclock(void)  | 
61  |  | { | 
62  |  |     unsigned long tsc;  | 
63  |  |     __asm   rdtsc  | 
64  |  |     __asm   mov[tsc], eax  | 
65  |  |     return tsc;  | 
66  |  | }  | 
67  |  | #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&  | 
68  |  |           ( _MSC_VER && _M_IX86 ) || __WATCOMC__ */  | 
69  |  |  | 
70  |  | /* some versions of mingw-64 have 32-bit longs even on x84_64 */  | 
71  |  | #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) &&  \  | 
72  |  |     defined(__GNUC__) && (defined(__i386__) || (                       \  | 
73  |  |     (defined(__amd64__) || defined(__x86_64__)) && __SIZEOF_LONG__ == 4))  | 
74  |  |  | 
75  |  | #define HAVE_HARDCLOCK  | 
76  |  |  | 
77  |  | unsigned long mbedtls_timing_hardclock(void)  | 
78  |  | { | 
79  |  |     unsigned long lo, hi;  | 
80  |  |     asm volatile ("rdtsc" : "=a" (lo), "=d" (hi)); | 
81  |  |     return lo;  | 
82  |  | }  | 
83  |  | #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&  | 
84  |  |           __GNUC__ && __i386__ */  | 
85  |  |  | 
86  |  | #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) &&  \  | 
87  |  |     defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__))  | 
88  |  |  | 
89  |  | #define HAVE_HARDCLOCK  | 
90  |  |  | 
91  |  | unsigned long mbedtls_timing_hardclock(void)  | 
92  | 0  | { | 
93  | 0  |     unsigned long lo, hi;  | 
94  | 0  |     asm volatile ("rdtsc" : "=a" (lo), "=d" (hi)); | 
95  | 0  |     return lo | (hi << 32);  | 
96  | 0  | }  | 
97  |  | #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&  | 
98  |  |           __GNUC__ && ( __amd64__ || __x86_64__ ) */  | 
99  |  |  | 
100  |  | #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) &&  \  | 
101  |  |     defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))  | 
102  |  |  | 
103  |  | #define HAVE_HARDCLOCK  | 
104  |  |  | 
105  |  | unsigned long mbedtls_timing_hardclock(void)  | 
106  |  | { | 
107  |  |     unsigned long tbl, tbu0, tbu1;  | 
108  |  |  | 
109  |  |     do { | 
110  |  |         asm volatile ("mftbu %0" : "=r" (tbu0)); | 
111  |  |         asm volatile ("mftb  %0" : "=r" (tbl)); | 
112  |  |         asm volatile ("mftbu %0" : "=r" (tbu1)); | 
113  |  |     } while (tbu0 != tbu1);  | 
114  |  |  | 
115  |  |     return tbl;  | 
116  |  | }  | 
117  |  | #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&  | 
118  |  |           __GNUC__ && ( __powerpc__ || __ppc__ ) */  | 
119  |  |  | 
120  |  | #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) &&  \  | 
121  |  |     defined(__GNUC__) && defined(__sparc64__)  | 
122  |  |  | 
123  |  | #if defined(__OpenBSD__)  | 
124  |  | #warning OpenBSD does not allow access to tick register using software version instead  | 
125  |  | #else  | 
126  |  | #define HAVE_HARDCLOCK  | 
127  |  |  | 
128  |  | unsigned long mbedtls_timing_hardclock(void)  | 
129  |  | { | 
130  |  |     unsigned long tick;  | 
131  |  |     asm volatile ("rdpr %%tick, %0;" : "=&r" (tick)); | 
132  |  |     return tick;  | 
133  |  | }  | 
134  |  | #endif /* __OpenBSD__ */  | 
135  |  | #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&  | 
136  |  |           __GNUC__ && __sparc64__ */  | 
137  |  |  | 
138  |  | #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) &&  \  | 
139  |  |     defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__)  | 
140  |  |  | 
141  |  | #define HAVE_HARDCLOCK  | 
142  |  |  | 
143  |  | unsigned long mbedtls_timing_hardclock(void)  | 
144  |  | { | 
145  |  |     unsigned long tick;  | 
146  |  |     asm volatile (".byte 0x83, 0x41, 0x00, 0x00"); | 
147  |  |     asm volatile ("mov   %%g1, %0" : "=r" (tick)); | 
148  |  |     return tick;  | 
149  |  | }  | 
150  |  | #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&  | 
151  |  |           __GNUC__ && __sparc__ && !__sparc64__ */  | 
152  |  |  | 
153  |  | #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) &&      \  | 
154  |  |     defined(__GNUC__) && defined(__alpha__)  | 
155  |  |  | 
156  |  | #define HAVE_HARDCLOCK  | 
157  |  |  | 
158  |  | unsigned long mbedtls_timing_hardclock(void)  | 
159  |  | { | 
160  |  |     unsigned long cc;  | 
161  |  |     asm volatile ("rpcc %0" : "=r" (cc)); | 
162  |  |     return cc & 0xFFFFFFFF;  | 
163  |  | }  | 
164  |  | #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&  | 
165  |  |           __GNUC__ && __alpha__ */  | 
166  |  |  | 
167  |  | #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) &&      \  | 
168  |  |     defined(__GNUC__) && defined(__ia64__)  | 
169  |  |  | 
170  |  | #define HAVE_HARDCLOCK  | 
171  |  |  | 
172  |  | unsigned long mbedtls_timing_hardclock(void)  | 
173  |  | { | 
174  |  |     unsigned long itc;  | 
175  |  |     asm volatile ("mov %0 = ar.itc" : "=r" (itc)); | 
176  |  |     return itc;  | 
177  |  | }  | 
178  |  | #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&  | 
179  |  |           __GNUC__ && __ia64__ */  | 
180  |  |  | 
181  |  | #if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \  | 
182  |  |     !defined(EFIX64) && !defined(EFI32)  | 
183  |  |  | 
184  |  | #define HAVE_HARDCLOCK  | 
185  |  |  | 
186  |  | unsigned long mbedtls_timing_hardclock(void)  | 
187  |  | { | 
188  |  |     LARGE_INTEGER offset;  | 
189  |  |  | 
190  |  |     QueryPerformanceCounter(&offset);  | 
191  |  |  | 
192  |  |     return (unsigned long) (offset.QuadPart);  | 
193  |  | }  | 
194  |  | #endif /* !HAVE_HARDCLOCK && _MSC_VER && !EFIX64 && !EFI32 */  | 
195  |  |  | 
196  |  | #if !defined(HAVE_HARDCLOCK)  | 
197  |  |  | 
198  |  | #define HAVE_HARDCLOCK  | 
199  |  |  | 
200  |  | static int hardclock_init = 0;  | 
201  |  | static struct timeval tv_init;  | 
202  |  |  | 
203  |  | unsigned long mbedtls_timing_hardclock(void)  | 
204  |  | { | 
205  |  |     struct timeval tv_cur;  | 
206  |  |  | 
207  |  |     if (hardclock_init == 0) { | 
208  |  |         gettimeofday(&tv_init, NULL);  | 
209  |  |         hardclock_init = 1;  | 
210  |  |     }  | 
211  |  |  | 
212  |  |     gettimeofday(&tv_cur, NULL);  | 
213  |  |     return (tv_cur.tv_sec  - tv_init.tv_sec) * 1000000U  | 
214  |  |            + (tv_cur.tv_usec - tv_init.tv_usec);  | 
215  |  | }  | 
216  |  | #endif /* !HAVE_HARDCLOCK */  | 
217  |  |  | 
218  |  | volatile int mbedtls_timing_alarmed = 0;  | 
219  |  |  | 
220  |  | #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)  | 
221  |  |  | 
222  |  | unsigned long mbedtls_timing_get_timer(struct mbedtls_timing_hr_time *val, int reset)  | 
223  |  | { | 
224  |  |     struct _hr_time t;  | 
225  |  |  | 
226  |  |     if (reset) { | 
227  |  |         QueryPerformanceCounter(&t.start);  | 
228  |  |         memcpy(val, &t, sizeof(struct _hr_time));  | 
229  |  |         return 0;  | 
230  |  |     } else { | 
231  |  |         unsigned long delta;  | 
232  |  |         LARGE_INTEGER now, hfreq;  | 
233  |  |         /* We can't safely cast val because it may not be aligned, so use memcpy */  | 
234  |  |         memcpy(&t, val, sizeof(struct _hr_time));  | 
235  |  |         QueryPerformanceCounter(&now);  | 
236  |  |         QueryPerformanceFrequency(&hfreq);  | 
237  |  |         delta = (unsigned long) ((now.QuadPart - t.start.QuadPart) * 1000ul  | 
238  |  |                                  / hfreq.QuadPart);  | 
239  |  |         return delta;  | 
240  |  |     }  | 
241  |  | }  | 
242  |  |  | 
243  |  | /* It's OK to use a global because alarm() is supposed to be global anyway */  | 
244  |  | static DWORD alarmMs;  | 
245  |  |  | 
246  |  | static void TimerProc(void *TimerContext)  | 
247  |  | { | 
248  |  |     (void) TimerContext;  | 
249  |  |     Sleep(alarmMs);  | 
250  |  |     mbedtls_timing_alarmed = 1;  | 
251  |  |     /* _endthread will be called implicitly on return  | 
252  |  |      * That ensures execution of thread function's epilogue */  | 
253  |  | }  | 
254  |  |  | 
255  |  | void mbedtls_set_alarm(int seconds)  | 
256  |  | { | 
257  |  |     if (seconds == 0) { | 
258  |  |         /* No need to create a thread for this simple case.  | 
259  |  |          * Also, this shorcut is more reliable at least on MinGW32 */  | 
260  |  |         mbedtls_timing_alarmed = 1;  | 
261  |  |         return;  | 
262  |  |     }  | 
263  |  |  | 
264  |  |     mbedtls_timing_alarmed = 0;  | 
265  |  |     alarmMs = seconds * 1000;  | 
266  |  |     (void) _beginthread(TimerProc, 0, NULL);  | 
267  |  | }  | 
268  |  |  | 
269  |  | #else /* _WIN32 && !EFIX64 && !EFI32 */  | 
270  |  |  | 
271  |  | unsigned long mbedtls_timing_get_timer(struct mbedtls_timing_hr_time *val, int reset)  | 
272  | 0  | { | 
273  | 0  |     struct _hr_time t;  | 
274  |  | 
  | 
275  | 0  |     if (reset) { | 
276  | 0  |         gettimeofday(&t.start, NULL);  | 
277  | 0  |         memcpy(val, &t, sizeof(struct _hr_time));  | 
278  | 0  |         return 0;  | 
279  | 0  |     } else { | 
280  | 0  |         unsigned long delta;  | 
281  | 0  |         struct timeval now;  | 
282  |  |         /* We can't safely cast val because it may not be aligned, so use memcpy */  | 
283  | 0  |         memcpy(&t, val, sizeof(struct _hr_time));  | 
284  | 0  |         gettimeofday(&now, NULL);  | 
285  | 0  |         delta = (now.tv_sec  - t.start.tv_sec) * 1000ul  | 
286  | 0  |                 + (now.tv_usec - t.start.tv_usec) / 1000;  | 
287  | 0  |         return delta;  | 
288  | 0  |     }  | 
289  | 0  | }  | 
290  |  |  | 
291  |  | static void sighandler(int signum)  | 
292  | 0  | { | 
293  | 0  |     mbedtls_timing_alarmed = 1;  | 
294  | 0  |     signal(signum, sighandler);  | 
295  | 0  | }  | 
296  |  |  | 
297  |  | void mbedtls_set_alarm(int seconds)  | 
298  | 0  | { | 
299  | 0  |     mbedtls_timing_alarmed = 0;  | 
300  | 0  |     signal(SIGALRM, sighandler);  | 
301  | 0  |     alarm(seconds);  | 
302  | 0  |     if (seconds == 0) { | 
303  |  |         /* alarm(0) cancelled any previous pending alarm, but the  | 
304  |  |            handler won't fire, so raise the flag straight away. */  | 
305  | 0  |         mbedtls_timing_alarmed = 1;  | 
306  | 0  |     }  | 
307  | 0  | }  | 
308  |  |  | 
309  |  | #endif /* _WIN32 && !EFIX64 && !EFI32 */  | 
310  |  |  | 
311  |  | /*  | 
312  |  |  * Set delays to watch  | 
313  |  |  */  | 
314  |  | void mbedtls_timing_set_delay(void *data, uint32_t int_ms, uint32_t fin_ms)  | 
315  | 0  | { | 
316  | 0  |     mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data;  | 
317  |  | 
  | 
318  | 0  |     ctx->int_ms = int_ms;  | 
319  | 0  |     ctx->fin_ms = fin_ms;  | 
320  |  | 
  | 
321  | 0  |     if (fin_ms != 0) { | 
322  | 0  |         (void) mbedtls_timing_get_timer(&ctx->timer, 1);  | 
323  | 0  |     }  | 
324  | 0  | }  | 
325  |  |  | 
326  |  | /*  | 
327  |  |  * Get number of delays expired  | 
328  |  |  */  | 
329  |  | int mbedtls_timing_get_delay(void *data)  | 
330  | 0  | { | 
331  | 0  |     mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data;  | 
332  | 0  |     unsigned long elapsed_ms;  | 
333  |  | 
  | 
334  | 0  |     if (ctx->fin_ms == 0) { | 
335  | 0  |         return -1;  | 
336  | 0  |     }  | 
337  |  |  | 
338  | 0  |     elapsed_ms = mbedtls_timing_get_timer(&ctx->timer, 0);  | 
339  |  | 
  | 
340  | 0  |     if (elapsed_ms >= ctx->fin_ms) { | 
341  | 0  |         return 2;  | 
342  | 0  |     }  | 
343  |  |  | 
344  | 0  |     if (elapsed_ms >= ctx->int_ms) { | 
345  | 0  |         return 1;  | 
346  | 0  |     }  | 
347  |  |  | 
348  | 0  |     return 0;  | 
349  | 0  | }  | 
350  |  |  | 
351  |  | #endif /* !MBEDTLS_TIMING_ALT */  | 
352  |  |  | 
353  |  | #if defined(MBEDTLS_SELF_TEST)  | 
354  |  | /*  | 
355  |  |  * Busy-waits for the given number of milliseconds.  | 
356  |  |  * Used for testing mbedtls_timing_hardclock.  | 
357  |  |  */  | 
358  |  | static void busy_msleep(unsigned long msec)  | 
359  | 0  | { | 
360  | 0  |     struct mbedtls_timing_hr_time hires;  | 
361  | 0  |     unsigned long i = 0; /* for busy-waiting */  | 
362  | 0  |     volatile unsigned long j; /* to prevent optimisation */  | 
363  |  | 
  | 
364  | 0  |     (void) mbedtls_timing_get_timer(&hires, 1);  | 
365  |  | 
  | 
366  | 0  |     while (mbedtls_timing_get_timer(&hires, 0) < msec) { | 
367  | 0  |         i++;  | 
368  | 0  |     }  | 
369  |  | 
  | 
370  | 0  |     j = i;  | 
371  | 0  |     (void) j;  | 
372  | 0  | }  | 
373  |  |  | 
374  | 0  | #define FAIL    do                                                      \  | 
375  | 0  |     {                                                                   \ | 
376  | 0  |         if (verbose != 0)                                              \  | 
377  | 0  |         {                                                               \ | 
378  | 0  |             mbedtls_printf("failed at line %d\n", __LINE__);          \ | 
379  | 0  |             mbedtls_printf(" cycles=%lu ratio=%lu millisecs=%lu secs=%lu hardfail=%d a=%lu b=%lu\n", \ | 
380  | 0  |                            cycles, ratio, millisecs, secs, hardfail,   \  | 
381  | 0  |                            (unsigned long) a, (unsigned long) b);     \  | 
382  | 0  |             mbedtls_printf(" elapsed(hires)=%lu status(ctx)=%d\n", \ | 
383  | 0  |                            mbedtls_timing_get_timer(&hires, 0),      \  | 
384  | 0  |                            mbedtls_timing_get_delay(&ctx));         \  | 
385  | 0  |         }                                                               \  | 
386  | 0  |         return 1;                                                    \  | 
387  | 0  |     } while (0)  | 
388  |  |  | 
389  |  | /*  | 
390  |  |  * Checkup routine  | 
391  |  |  *  | 
392  |  |  * Warning: this is work in progress, some tests may not be reliable enough  | 
393  |  |  * yet! False positives may happen.  | 
394  |  |  */  | 
395  |  | int mbedtls_timing_self_test(int verbose)  | 
396  | 0  | { | 
397  | 0  |     unsigned long cycles = 0, ratio = 0;  | 
398  | 0  |     unsigned long millisecs = 0, secs = 0;  | 
399  | 0  |     int hardfail = 0;  | 
400  | 0  |     struct mbedtls_timing_hr_time hires;  | 
401  | 0  |     uint32_t a = 0, b = 0;  | 
402  | 0  |     mbedtls_timing_delay_context ctx;  | 
403  |  | 
  | 
404  | 0  |     memset(&ctx, 0, sizeof(ctx));  | 
405  | 0  |     if (verbose != 0) { | 
406  | 0  |         mbedtls_printf("  TIMING tests note: will take some time!\n"); | 
407  | 0  |     }  | 
408  |  | 
  | 
409  | 0  |     if (verbose != 0) { | 
410  | 0  |         mbedtls_printf("  TIMING test #1 (set_alarm / get_timer): "); | 
411  | 0  |     }  | 
412  |  | 
  | 
413  | 0  |     { | 
414  | 0  |         secs = 1;  | 
415  |  | 
  | 
416  | 0  |         (void) mbedtls_timing_get_timer(&hires, 1);  | 
417  |  | 
  | 
418  | 0  |         mbedtls_set_alarm((int) secs);  | 
419  | 0  |         while (!mbedtls_timing_alarmed) { | 
420  | 0  |             ;  | 
421  | 0  |         }  | 
422  |  | 
  | 
423  | 0  |         millisecs = mbedtls_timing_get_timer(&hires, 0);  | 
424  |  |  | 
425  |  |         /* For some reason on Windows it looks like alarm has an extra delay  | 
426  |  |          * (maybe related to creating a new thread). Allow some room here. */  | 
427  | 0  |         if (millisecs < 800 * secs || millisecs > 1200 * secs + 300) { | 
428  | 0  |             FAIL;  | 
429  | 0  |         }  | 
430  | 0  |     }  | 
431  |  |  | 
432  | 0  |     if (verbose != 0) { | 
433  | 0  |         mbedtls_printf("passed\n"); | 
434  | 0  |     }  | 
435  |  | 
  | 
436  | 0  |     if (verbose != 0) { | 
437  | 0  |         mbedtls_printf("  TIMING test #2 (set/get_delay        ): "); | 
438  | 0  |     }  | 
439  |  | 
  | 
440  | 0  |     { | 
441  | 0  |         a = 800;  | 
442  | 0  |         b = 400;  | 
443  | 0  |         mbedtls_timing_set_delay(&ctx, a, a + b);            /* T = 0 */  | 
444  |  | 
  | 
445  | 0  |         busy_msleep(a - a / 4);                        /* T = a - a/4 */  | 
446  | 0  |         if (mbedtls_timing_get_delay(&ctx) != 0) { | 
447  | 0  |             FAIL;  | 
448  | 0  |         }  | 
449  |  |  | 
450  | 0  |         busy_msleep(a / 4 + b / 4);                    /* T = a + b/4 */  | 
451  | 0  |         if (mbedtls_timing_get_delay(&ctx) != 1) { | 
452  | 0  |             FAIL;  | 
453  | 0  |         }  | 
454  |  |  | 
455  | 0  |         busy_msleep(b);                            /* T = a + b + b/4 */  | 
456  | 0  |         if (mbedtls_timing_get_delay(&ctx) != 2) { | 
457  | 0  |             FAIL;  | 
458  | 0  |         }  | 
459  | 0  |     }  | 
460  |  |  | 
461  | 0  |     mbedtls_timing_set_delay(&ctx, 0, 0);  | 
462  | 0  |     busy_msleep(200);  | 
463  | 0  |     if (mbedtls_timing_get_delay(&ctx) != -1) { | 
464  | 0  |         FAIL;  | 
465  | 0  |     }  | 
466  |  |  | 
467  | 0  |     if (verbose != 0) { | 
468  | 0  |         mbedtls_printf("passed\n"); | 
469  | 0  |     }  | 
470  |  | 
  | 
471  | 0  |     if (verbose != 0) { | 
472  | 0  |         mbedtls_printf("  TIMING test #3 (hardclock / get_timer): "); | 
473  | 0  |     }  | 
474  |  |  | 
475  |  |     /*  | 
476  |  |      * Allow one failure for possible counter wrapping.  | 
477  |  |      * On a 4Ghz 32-bit machine the cycle counter wraps about once per second;  | 
478  |  |      * since the whole test is about 10ms, it shouldn't happen twice in a row.  | 
479  |  |      */  | 
480  |  | 
  | 
481  | 0  | hard_test:  | 
482  | 0  |     if (hardfail > 1) { | 
483  | 0  |         if (verbose != 0) { | 
484  | 0  |             mbedtls_printf("failed (ignored)\n"); | 
485  | 0  |         }  | 
486  |  | 
  | 
487  | 0  |         goto hard_test_done;  | 
488  | 0  |     }  | 
489  |  |  | 
490  |  |     /* Get a reference ratio cycles/ms */  | 
491  | 0  |     millisecs = 1;  | 
492  | 0  |     cycles = mbedtls_timing_hardclock();  | 
493  | 0  |     busy_msleep(millisecs);  | 
494  | 0  |     cycles = mbedtls_timing_hardclock() - cycles;  | 
495  | 0  |     ratio = cycles / millisecs;  | 
496  |  |  | 
497  |  |     /* Check that the ratio is mostly constant */  | 
498  | 0  |     for (millisecs = 2; millisecs <= 4; millisecs++) { | 
499  | 0  |         cycles = mbedtls_timing_hardclock();  | 
500  | 0  |         busy_msleep(millisecs);  | 
501  | 0  |         cycles = mbedtls_timing_hardclock() - cycles;  | 
502  |  |  | 
503  |  |         /* Allow variation up to 20% */  | 
504  | 0  |         if (cycles / millisecs < ratio - ratio / 5 ||  | 
505  | 0  |             cycles / millisecs > ratio + ratio / 5) { | 
506  | 0  |             hardfail++;  | 
507  | 0  |             goto hard_test;  | 
508  | 0  |         }  | 
509  | 0  |     }  | 
510  |  |  | 
511  | 0  |     if (verbose != 0) { | 
512  | 0  |         mbedtls_printf("passed\n"); | 
513  | 0  |     }  | 
514  |  | 
  | 
515  | 0  | hard_test_done:  | 
516  |  | 
  | 
517  | 0  |     if (verbose != 0) { | 
518  | 0  |         mbedtls_printf("\n"); | 
519  | 0  |     }  | 
520  |  | 
  | 
521  | 0  |     return 0;  | 
522  | 0  | }  | 
523  |  |  | 
524  |  | #endif /* MBEDTLS_SELF_TEST */  | 
525  |  | #endif /* MBEDTLS_TIMING_C */  |