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