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