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