• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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