2  *  Portable interface to the CPU cycle counter 
   4  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 
   5  *  SPDX-License-Identifier: GPL-2.0 
   7  *  This program is free software; you can redistribute it and/or modify 
   8  *  it under the terms of the GNU General Public License as published by 
   9  *  the Free Software Foundation; either version 2 of the License, or 
  10  *  (at your option) any later version. 
  12  *  This program is distributed in the hope that it will be useful, 
  13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
  14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  15  *  GNU General Public License for more details. 
  17  *  You should have received a copy of the GNU General Public License along 
  18  *  with this program; if not, write to the Free Software Foundation, Inc., 
  19  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
  21  *  This file is part of mbed TLS (https://tls.mbed.org) 
  24 #if !defined(MBEDTLS_CONFIG_FILE) 
  25 #include "mbedtls/config.h" 
  27 #include MBEDTLS_CONFIG_FILE 
  30 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_PLATFORM_C) 
  31 #include "mbedtls/platform.h" 
  34 #define mbedtls_printf     printf 
  37 #if defined(MBEDTLS_TIMING_C) 
  39 #include "mbedtls/timing.h" 
  41 #if !defined(MBEDTLS_TIMING_ALT) 
  43 #if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ 
  44     !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \ 
  46 #error "This module only works on Unix and Windows, see MBEDTLS_TIMING_C in config.h" 
  53 #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 
  66 #include <sys/types.h> 
  76 #endif /* _WIN32 && !EFIX64 && !EFI32 */ 
  78 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) &&  \ 
  79     ( defined(_MSC_VER) && defined(_M_IX86) ) || defined(__WATCOMC__) 
  81 #define HAVE_HARDCLOCK 
  83 unsigned long mbedtls_timing_hardclock( void ) 
  90 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 
  91           ( _MSC_VER && _M_IX86 ) || __WATCOMC__ */ 
  93 /* some versions of mingw-64 have 32-bit longs even on x84_64 */ 
  94 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) &&  \ 
  95     defined(__GNUC__) && ( defined(__i386__) || (                       \ 
  96     ( defined(__amd64__) || defined( __x86_64__) ) && __SIZEOF_LONG__ == 4 ) ) 
  98 #define HAVE_HARDCLOCK 
 100 unsigned long mbedtls_timing_hardclock( void ) 
 102     unsigned long lo
, hi
; 
 103     asm volatile( "rdtsc" : "=a" (lo
), "=d" (hi
) ); 
 106 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 
 107           __GNUC__ && __i386__ */ 
 109 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) &&  \ 
 110     defined(__GNUC__) && ( defined(__amd64__) || defined(__x86_64__) ) 
 112 #define HAVE_HARDCLOCK 
 114 unsigned long mbedtls_timing_hardclock( void ) 
 116     unsigned long lo
, hi
; 
 117     asm volatile( "rdtsc" : "=a" (lo
), "=d" (hi
) ); 
 118     return( lo 
| ( hi 
<< 32 ) ); 
 120 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 
 121           __GNUC__ && ( __amd64__ || __x86_64__ ) */ 
 123 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) &&  \ 
 124     defined(__GNUC__) && ( defined(__powerpc__) || defined(__ppc__) ) 
 126 #define HAVE_HARDCLOCK 
 128 unsigned long mbedtls_timing_hardclock( void ) 
 130     unsigned long tbl
, tbu0
, tbu1
; 
 134         asm volatile( "mftbu %0" : "=r" (tbu0
) ); 
 135         asm volatile( "mftb  %0" : "=r" (tbl 
) ); 
 136         asm volatile( "mftbu %0" : "=r" (tbu1
) ); 
 138     while( tbu0 
!= tbu1 
); 
 142 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 
 143           __GNUC__ && ( __powerpc__ || __ppc__ ) */ 
 145 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) &&  \ 
 146     defined(__GNUC__) && defined(__sparc64__) 
 148 #if defined(__OpenBSD__) 
 149 #warning OpenBSD does not allow access to tick register using software version instead 
 151 #define HAVE_HARDCLOCK 
 153 unsigned long mbedtls_timing_hardclock( void ) 
 156     asm volatile( "rdpr %%tick, %0;" : "=&r" (tick
) ); 
 159 #endif /* __OpenBSD__ */ 
 160 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 
 161           __GNUC__ && __sparc64__ */ 
 163 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) &&  \ 
 164     defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__) 
 166 #define HAVE_HARDCLOCK 
 168 unsigned long mbedtls_timing_hardclock( void ) 
 171     asm volatile( ".byte 0x83, 0x41, 0x00, 0x00" ); 
 172     asm volatile( "mov   %%g1, %0" : "=r" (tick
) ); 
 175 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 
 176           __GNUC__ && __sparc__ && !__sparc64__ */ 
 178 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) &&      \ 
 179     defined(__GNUC__) && defined(__alpha__) 
 181 #define HAVE_HARDCLOCK 
 183 unsigned long mbedtls_timing_hardclock( void ) 
 186     asm volatile( "rpcc %0" : "=r" (cc
) ); 
 187     return( cc 
& 0xFFFFFFFF ); 
 189 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 
 190           __GNUC__ && __alpha__ */ 
 192 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) &&      \ 
 193     defined(__GNUC__) && defined(__ia64__) 
 195 #define HAVE_HARDCLOCK 
 197 unsigned long mbedtls_timing_hardclock( void ) 
 200     asm volatile( "mov %0 = ar.itc" : "=r" (itc
) ); 
 203 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 
 204           __GNUC__ && __ia64__ */ 
 206 #if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \ 
 207     !defined(EFIX64) && !defined(EFI32) 
 209 #define HAVE_HARDCLOCK 
 211 unsigned long mbedtls_timing_hardclock( void ) 
 213     LARGE_INTEGER offset
; 
 215     QueryPerformanceCounter( &offset 
); 
 217     return( (unsigned long)( offset
.QuadPart 
) ); 
 219 #endif /* !HAVE_HARDCLOCK && _MSC_VER && !EFIX64 && !EFI32 */ 
 221 #if !defined(HAVE_HARDCLOCK) 
 223 #define HAVE_HARDCLOCK 
 225 static int hardclock_init 
= 0; 
 226 static struct timeval tv_init
; 
 228 unsigned long mbedtls_timing_hardclock( void ) 
 230     struct timeval tv_cur
; 
 232     if( hardclock_init 
== 0 ) 
 235         mingw_gettimeofday( &tv_init
, NULL 
); 
 237         gettimeofday( &tv_init
, NULL 
); 
 243     mingw_gettimeofday( &tv_cur
, NULL 
); 
 245     gettimeofday( &tv_cur
, NULL 
); 
 247     return( ( tv_cur
.tv_sec  
- tv_init
.tv_sec  
) * 1000000 
 248           + ( tv_cur
.tv_usec 
- tv_init
.tv_usec 
) ); 
 250 #endif /* !HAVE_HARDCLOCK */ 
 252 volatile int mbedtls_timing_alarmed 
= 0; 
 254 #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 
 256 unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time 
*val
, int reset 
) 
 258     struct _hr_time 
*t 
= (struct _hr_time 
*) val
; 
 262         QueryPerformanceCounter( &t
->start 
); 
 268         LARGE_INTEGER now
, hfreq
; 
 269         QueryPerformanceCounter(  &now 
); 
 270         QueryPerformanceFrequency( &hfreq 
); 
 271         delta 
= (unsigned long)( ( now
.QuadPart 
- t
->start
.QuadPart 
) * 1000ul 
 277 /* It's OK to use a global because alarm() is supposed to be global anyway */ 
 278 static DWORD alarmMs
; 
 280 static DWORD WINAPI 
TimerProc( LPVOID TimerContext 
) 
 282     ((void) TimerContext
); 
 284     mbedtls_timing_alarmed 
= 1; 
 288 void mbedtls_set_alarm( int seconds 
) 
 294         /* No need to create a thread for this simple case. 
 295          * Also, this shorcut is more reliable at least on MinGW32 */ 
 296         mbedtls_timing_alarmed 
= 1; 
 300     mbedtls_timing_alarmed 
= 0; 
 301     alarmMs 
= seconds 
* 1000; 
 302     CloseHandle( CreateThread( NULL
, 0, TimerProc
, NULL
, 0, &ThreadId 
) ); 
 305 #else /* _WIN32 && !EFIX64 && !EFI32 */ 
 307 unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time 
*val
, int reset 
) 
 309     struct _hr_time 
*t 
= (struct _hr_time 
*) val
; 
 313         gettimeofday( &t
->start
, NULL 
); 
 320         gettimeofday( &now
, NULL 
); 
 321         delta 
= ( now
.tv_sec  
- t
->start
.tv_sec  
) * 1000ul 
 322               + ( now
.tv_usec 
- t
->start
.tv_usec 
) / 1000; 
 327 static void sighandler( int signum 
) 
 329     mbedtls_timing_alarmed 
= 1; 
 330     signal( signum
, sighandler 
); 
 333 void mbedtls_set_alarm( int seconds 
) 
 335     mbedtls_timing_alarmed 
= 0; 
 336     signal( SIGALRM
, sighandler 
); 
 340         /* alarm(0) cancelled any previous pending alarm, but the 
 341            handler won't fire, so raise the flag straight away. */ 
 342         mbedtls_timing_alarmed 
= 1; 
 346 #endif /* _WIN32 && !EFIX64 && !EFI32 */ 
 349  * Set delays to watch 
 351 void mbedtls_timing_set_delay( void *data
, uint32_t int_ms
, uint32_t fin_ms 
) 
 353     mbedtls_timing_delay_context 
*ctx 
= (mbedtls_timing_delay_context 
*) data
; 
 355     ctx
->int_ms 
= int_ms
; 
 356     ctx
->fin_ms 
= fin_ms
; 
 359         (void) mbedtls_timing_get_timer( &ctx
->timer
, 1 ); 
 363  * Get number of delays expired 
 365 int mbedtls_timing_get_delay( void *data 
) 
 367     mbedtls_timing_delay_context 
*ctx 
= (mbedtls_timing_delay_context 
*) data
; 
 368     unsigned long elapsed_ms
; 
 370     if( ctx
->fin_ms 
== 0 ) 
 373     elapsed_ms 
= mbedtls_timing_get_timer( &ctx
->timer
, 0 ); 
 375     if( elapsed_ms 
>= ctx
->fin_ms 
) 
 378     if( elapsed_ms 
>= ctx
->int_ms 
) 
 384 #endif /* !MBEDTLS_TIMING_ALT */ 
 386 #if defined(MBEDTLS_SELF_TEST) 
 389  * Busy-waits for the given number of milliseconds. 
 390  * Used for testing mbedtls_timing_hardclock. 
 392 static void busy_msleep( unsigned long msec 
) 
 394     struct mbedtls_timing_hr_time hires
; 
 395     unsigned long i 
= 0; /* for busy-waiting */ 
 396     volatile unsigned long j
; /* to prevent optimisation */ 
 398     (void) mbedtls_timing_get_timer( &hires
, 1 ); 
 400     while( mbedtls_timing_get_timer( &hires
, 0 ) < msec 
) 
 411             mbedtls_printf( "failed at line %d\n", __LINE__ );          \ 
 412             mbedtls_printf( " cycles=%lu ratio=%lu millisecs=%lu secs=%lu hardfail=%d a=%lu b=%lu\n", \ 
 413                             cycles, ratio, millisecs, secs, hardfail,   \ 
 414                             (unsigned long) a, (unsigned long) b );     \ 
 415             mbedtls_printf( " elapsed(hires)=%lu elapsed(ctx)=%lu status(ctx)=%d\n", \ 
 416                             mbedtls_timing_get_timer( &hires, 0 ),      \ 
 417                             mbedtls_timing_get_timer( &ctx.timer, 0 ),  \ 
 418                             mbedtls_timing_get_delay( &ctx ) );         \ 
 426  * Warning: this is work in progress, some tests may not be reliable enough 
 427  * yet! False positives may happen. 
 429 int mbedtls_timing_self_test( int verbose 
) 
 431     unsigned long cycles 
= 0, ratio 
= 0; 
 432     unsigned long millisecs 
= 0, secs 
= 0; 
 434     struct mbedtls_timing_hr_time hires
; 
 435     uint32_t a 
= 0, b 
= 0; 
 436     mbedtls_timing_delay_context ctx
; 
 439         mbedtls_printf( "  TIMING tests note: will take some time!\n" ); 
 442         mbedtls_printf( "  TIMING test #1 (set_alarm / get_timer): " ); 
 447         (void) mbedtls_timing_get_timer( &hires
, 1 ); 
 449         mbedtls_set_alarm( (int) secs 
); 
 450         while( !mbedtls_timing_alarmed 
) 
 453         millisecs 
= mbedtls_timing_get_timer( &hires
, 0 ); 
 455         /* For some reason on Windows it looks like alarm has an extra delay 
 456          * (maybe related to creating a new thread). Allow some room here. */ 
 457         if( millisecs 
< 800 * secs 
|| millisecs 
> 1200 * secs 
+ 300 ) 
 462         mbedtls_printf( "passed\n" ); 
 465         mbedtls_printf( "  TIMING test #2 (set/get_delay        ): " ); 
 470         mbedtls_timing_set_delay( &ctx
, a
, a 
+ b 
);          /* T = 0 */ 
 472         busy_msleep( a 
- a 
/ 4 );                      /* T = a - a/4 */ 
 473         if( mbedtls_timing_get_delay( &ctx 
) != 0 ) 
 476         busy_msleep( a 
/ 4 + b 
/ 4 );                  /* T = a + b/4 */ 
 477         if( mbedtls_timing_get_delay( &ctx 
) != 1 ) 
 480         busy_msleep( b 
);                          /* T = a + b + b/4 */ 
 481         if( mbedtls_timing_get_delay( &ctx 
) != 2 ) 
 485     mbedtls_timing_set_delay( &ctx
, 0, 0 ); 
 487     if( mbedtls_timing_get_delay( &ctx 
) != -1 ) 
 491         mbedtls_printf( "passed\n" ); 
 494         mbedtls_printf( "  TIMING test #3 (hardclock / get_timer): " ); 
 497      * Allow one failure for possible counter wrapping. 
 498      * On a 4Ghz 32-bit machine the cycle counter wraps about once per second; 
 499      * since the whole test is about 10ms, it shouldn't happen twice in a row. 
 506             mbedtls_printf( "failed (ignored)\n" ); 
 511     /* Get a reference ratio cycles/ms */ 
 513     cycles 
= mbedtls_timing_hardclock(); 
 514     busy_msleep( millisecs 
); 
 515     cycles 
= mbedtls_timing_hardclock() - cycles
; 
 516     ratio 
= cycles 
/ millisecs
; 
 518     /* Check that the ratio is mostly constant */ 
 519     for( millisecs 
= 2; millisecs 
<= 4; millisecs
++ ) 
 521         cycles 
= mbedtls_timing_hardclock(); 
 522         busy_msleep( millisecs 
); 
 523         cycles 
= mbedtls_timing_hardclock() - cycles
; 
 525         /* Allow variation up to 20% */ 
 526         if( cycles 
/ millisecs 
< ratio 
- ratio 
/ 5 || 
 527             cycles 
/ millisecs 
> ratio 
+ ratio 
/ 5 ) 
 535         mbedtls_printf( "passed\n" ); 
 540         mbedtls_printf( "\n" ); 
 545 #endif /* MBEDTLS_SELF_TEST */ 
 547 #endif /* MBEDTLS_TIMING_C */