1817466cbSJens Wiklander /* 2817466cbSJens Wiklander * Portable interface to the CPU cycle counter 3817466cbSJens Wiklander * 47901324dSJerome Forissier * Copyright The Mbed TLS Contributors 57901324dSJerome Forissier * SPDX-License-Identifier: Apache-2.0 6817466cbSJens Wiklander * 7817466cbSJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 8817466cbSJens Wiklander * not use this file except in compliance with the License. 9817466cbSJens Wiklander * You may obtain a copy of the License at 10817466cbSJens Wiklander * 11817466cbSJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 12817466cbSJens Wiklander * 13817466cbSJens Wiklander * Unless required by applicable law or agreed to in writing, software 14817466cbSJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15817466cbSJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16817466cbSJens Wiklander * See the License for the specific language governing permissions and 17817466cbSJens Wiklander * limitations under the License. 18817466cbSJens Wiklander */ 19817466cbSJens Wiklander 207901324dSJerome Forissier #include "common.h" 21817466cbSJens Wiklander 22817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_PLATFORM_C) 23817466cbSJens Wiklander #include "mbedtls/platform.h" 24817466cbSJens Wiklander #else 25817466cbSJens Wiklander #include <stdio.h> 26817466cbSJens Wiklander #define mbedtls_printf printf 27817466cbSJens Wiklander #endif 28817466cbSJens Wiklander 29817466cbSJens Wiklander #if defined(MBEDTLS_TIMING_C) 30817466cbSJens Wiklander 31817466cbSJens Wiklander #include "mbedtls/timing.h" 32817466cbSJens Wiklander 33817466cbSJens Wiklander #if !defined(MBEDTLS_TIMING_ALT) 34817466cbSJens Wiklander 35817466cbSJens Wiklander #if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ 363d3b0591SJens Wiklander !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \ 377901324dSJerome Forissier !defined(__HAIKU__) && !defined(__midipix__) 38817466cbSJens Wiklander #error "This module only works on Unix and Windows, see MBEDTLS_TIMING_C in config.h" 39817466cbSJens Wiklander #endif 40817466cbSJens Wiklander 41817466cbSJens Wiklander #ifndef asm 42817466cbSJens Wiklander #define asm __asm 43817466cbSJens Wiklander #endif 44817466cbSJens Wiklander 45817466cbSJens Wiklander #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 46817466cbSJens Wiklander 47817466cbSJens Wiklander #include <windows.h> 483d3b0591SJens Wiklander #include <process.h> 49817466cbSJens Wiklander 50817466cbSJens Wiklander struct _hr_time 51817466cbSJens Wiklander { 52817466cbSJens Wiklander LARGE_INTEGER start; 53817466cbSJens Wiklander }; 54817466cbSJens Wiklander 55817466cbSJens Wiklander #else 56817466cbSJens Wiklander 57817466cbSJens Wiklander #include <unistd.h> 58817466cbSJens Wiklander #include <sys/types.h> 59817466cbSJens Wiklander #include <signal.h> 60*039e02dfSJerome Forissier /* time.h should be included independently of MBEDTLS_HAVE_TIME. If the 61*039e02dfSJerome Forissier * platform matches the ifdefs above, it will be used. */ 62817466cbSJens Wiklander #include <time.h> 63*039e02dfSJerome Forissier #include <sys/time.h> 64817466cbSJens Wiklander struct _hr_time 65817466cbSJens Wiklander { 66817466cbSJens Wiklander struct timeval start; 67817466cbSJens Wiklander }; 68817466cbSJens Wiklander #endif /* _WIN32 && !EFIX64 && !EFI32 */ 69817466cbSJens Wiklander 70817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 71817466cbSJens Wiklander ( defined(_MSC_VER) && defined(_M_IX86) ) || defined(__WATCOMC__) 72817466cbSJens Wiklander 73817466cbSJens Wiklander #define HAVE_HARDCLOCK 74817466cbSJens Wiklander 75817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 76817466cbSJens Wiklander { 77817466cbSJens Wiklander unsigned long tsc; 78817466cbSJens Wiklander __asm rdtsc 79817466cbSJens Wiklander __asm mov [tsc], eax 80817466cbSJens Wiklander return( tsc ); 81817466cbSJens Wiklander } 82817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 83817466cbSJens Wiklander ( _MSC_VER && _M_IX86 ) || __WATCOMC__ */ 84817466cbSJens Wiklander 85817466cbSJens Wiklander /* some versions of mingw-64 have 32-bit longs even on x84_64 */ 86817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 87817466cbSJens Wiklander defined(__GNUC__) && ( defined(__i386__) || ( \ 88817466cbSJens Wiklander ( defined(__amd64__) || defined( __x86_64__) ) && __SIZEOF_LONG__ == 4 ) ) 89817466cbSJens Wiklander 90817466cbSJens Wiklander #define HAVE_HARDCLOCK 91817466cbSJens Wiklander 92817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 93817466cbSJens Wiklander { 94817466cbSJens Wiklander unsigned long lo, hi; 95817466cbSJens Wiklander asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); 96817466cbSJens Wiklander return( lo ); 97817466cbSJens Wiklander } 98817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 99817466cbSJens Wiklander __GNUC__ && __i386__ */ 100817466cbSJens Wiklander 101817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 102817466cbSJens Wiklander defined(__GNUC__) && ( defined(__amd64__) || defined(__x86_64__) ) 103817466cbSJens Wiklander 104817466cbSJens Wiklander #define HAVE_HARDCLOCK 105817466cbSJens Wiklander 106817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 107817466cbSJens Wiklander { 108817466cbSJens Wiklander unsigned long lo, hi; 109817466cbSJens Wiklander asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); 110817466cbSJens Wiklander return( lo | ( hi << 32 ) ); 111817466cbSJens Wiklander } 112817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 113817466cbSJens Wiklander __GNUC__ && ( __amd64__ || __x86_64__ ) */ 114817466cbSJens Wiklander 115817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 116817466cbSJens Wiklander defined(__GNUC__) && ( defined(__powerpc__) || defined(__ppc__) ) 117817466cbSJens Wiklander 118817466cbSJens Wiklander #define HAVE_HARDCLOCK 119817466cbSJens Wiklander 120817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 121817466cbSJens Wiklander { 122817466cbSJens Wiklander unsigned long tbl, tbu0, tbu1; 123817466cbSJens Wiklander 124817466cbSJens Wiklander do 125817466cbSJens Wiklander { 126817466cbSJens Wiklander asm volatile( "mftbu %0" : "=r" (tbu0) ); 127817466cbSJens Wiklander asm volatile( "mftb %0" : "=r" (tbl ) ); 128817466cbSJens Wiklander asm volatile( "mftbu %0" : "=r" (tbu1) ); 129817466cbSJens Wiklander } 130817466cbSJens Wiklander while( tbu0 != tbu1 ); 131817466cbSJens Wiklander 132817466cbSJens Wiklander return( tbl ); 133817466cbSJens Wiklander } 134817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 135817466cbSJens Wiklander __GNUC__ && ( __powerpc__ || __ppc__ ) */ 136817466cbSJens Wiklander 137817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 138817466cbSJens Wiklander defined(__GNUC__) && defined(__sparc64__) 139817466cbSJens Wiklander 140817466cbSJens Wiklander #if defined(__OpenBSD__) 141817466cbSJens Wiklander #warning OpenBSD does not allow access to tick register using software version instead 142817466cbSJens Wiklander #else 143817466cbSJens Wiklander #define HAVE_HARDCLOCK 144817466cbSJens Wiklander 145817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 146817466cbSJens Wiklander { 147817466cbSJens Wiklander unsigned long tick; 148817466cbSJens Wiklander asm volatile( "rdpr %%tick, %0;" : "=&r" (tick) ); 149817466cbSJens Wiklander return( tick ); 150817466cbSJens Wiklander } 151817466cbSJens Wiklander #endif /* __OpenBSD__ */ 152817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 153817466cbSJens Wiklander __GNUC__ && __sparc64__ */ 154817466cbSJens Wiklander 155817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 156817466cbSJens Wiklander defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__) 157817466cbSJens Wiklander 158817466cbSJens Wiklander #define HAVE_HARDCLOCK 159817466cbSJens Wiklander 160817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 161817466cbSJens Wiklander { 162817466cbSJens Wiklander unsigned long tick; 163817466cbSJens Wiklander asm volatile( ".byte 0x83, 0x41, 0x00, 0x00" ); 164817466cbSJens Wiklander asm volatile( "mov %%g1, %0" : "=r" (tick) ); 165817466cbSJens Wiklander return( tick ); 166817466cbSJens Wiklander } 167817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 168817466cbSJens Wiklander __GNUC__ && __sparc__ && !__sparc64__ */ 169817466cbSJens Wiklander 170817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 171817466cbSJens Wiklander defined(__GNUC__) && defined(__alpha__) 172817466cbSJens Wiklander 173817466cbSJens Wiklander #define HAVE_HARDCLOCK 174817466cbSJens Wiklander 175817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 176817466cbSJens Wiklander { 177817466cbSJens Wiklander unsigned long cc; 178817466cbSJens Wiklander asm volatile( "rpcc %0" : "=r" (cc) ); 179817466cbSJens Wiklander return( cc & 0xFFFFFFFF ); 180817466cbSJens Wiklander } 181817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 182817466cbSJens Wiklander __GNUC__ && __alpha__ */ 183817466cbSJens Wiklander 184817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 185817466cbSJens Wiklander defined(__GNUC__) && defined(__ia64__) 186817466cbSJens Wiklander 187817466cbSJens Wiklander #define HAVE_HARDCLOCK 188817466cbSJens Wiklander 189817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 190817466cbSJens Wiklander { 191817466cbSJens Wiklander unsigned long itc; 192817466cbSJens Wiklander asm volatile( "mov %0 = ar.itc" : "=r" (itc) ); 193817466cbSJens Wiklander return( itc ); 194817466cbSJens Wiklander } 195817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 196817466cbSJens Wiklander __GNUC__ && __ia64__ */ 197817466cbSJens Wiklander 198817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \ 199817466cbSJens Wiklander !defined(EFIX64) && !defined(EFI32) 200817466cbSJens Wiklander 201817466cbSJens Wiklander #define HAVE_HARDCLOCK 202817466cbSJens Wiklander 203817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 204817466cbSJens Wiklander { 205817466cbSJens Wiklander LARGE_INTEGER offset; 206817466cbSJens Wiklander 207817466cbSJens Wiklander QueryPerformanceCounter( &offset ); 208817466cbSJens Wiklander 209817466cbSJens Wiklander return( (unsigned long)( offset.QuadPart ) ); 210817466cbSJens Wiklander } 211817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && _MSC_VER && !EFIX64 && !EFI32 */ 212817466cbSJens Wiklander 213817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) 214817466cbSJens Wiklander 215817466cbSJens Wiklander #define HAVE_HARDCLOCK 216817466cbSJens Wiklander 217817466cbSJens Wiklander static int hardclock_init = 0; 218817466cbSJens Wiklander static struct timeval tv_init; 219817466cbSJens Wiklander 220817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 221817466cbSJens Wiklander { 222817466cbSJens Wiklander struct timeval tv_cur; 223817466cbSJens Wiklander 224817466cbSJens Wiklander if( hardclock_init == 0 ) 225817466cbSJens Wiklander { 226817466cbSJens Wiklander gettimeofday( &tv_init, NULL ); 227817466cbSJens Wiklander hardclock_init = 1; 228817466cbSJens Wiklander } 229817466cbSJens Wiklander 230817466cbSJens Wiklander gettimeofday( &tv_cur, NULL ); 231817466cbSJens Wiklander return( ( tv_cur.tv_sec - tv_init.tv_sec ) * 1000000 232817466cbSJens Wiklander + ( tv_cur.tv_usec - tv_init.tv_usec ) ); 233817466cbSJens Wiklander } 234817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK */ 235817466cbSJens Wiklander 236817466cbSJens Wiklander volatile int mbedtls_timing_alarmed = 0; 237817466cbSJens Wiklander 238817466cbSJens Wiklander #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 239817466cbSJens Wiklander 240817466cbSJens Wiklander unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) 241817466cbSJens Wiklander { 242817466cbSJens Wiklander struct _hr_time *t = (struct _hr_time *) val; 243817466cbSJens Wiklander 244817466cbSJens Wiklander if( reset ) 2453d3b0591SJens Wiklander { 246817466cbSJens Wiklander QueryPerformanceCounter( &t->start ); 2473d3b0591SJens Wiklander return( 0 ); 2483d3b0591SJens Wiklander } 2493d3b0591SJens Wiklander else 2503d3b0591SJens Wiklander { 2513d3b0591SJens Wiklander unsigned long delta; 2523d3b0591SJens Wiklander LARGE_INTEGER now, hfreq; 2533d3b0591SJens Wiklander QueryPerformanceCounter( &now ); 2543d3b0591SJens Wiklander QueryPerformanceFrequency( &hfreq ); 2553d3b0591SJens Wiklander delta = (unsigned long)( ( now.QuadPart - t->start.QuadPart ) * 1000ul 2563d3b0591SJens Wiklander / hfreq.QuadPart ); 257817466cbSJens Wiklander return( delta ); 258817466cbSJens Wiklander } 2593d3b0591SJens Wiklander } 260817466cbSJens Wiklander 261817466cbSJens Wiklander /* It's OK to use a global because alarm() is supposed to be global anyway */ 262817466cbSJens Wiklander static DWORD alarmMs; 263817466cbSJens Wiklander 2643d3b0591SJens Wiklander static void TimerProc( void *TimerContext ) 265817466cbSJens Wiklander { 2663d3b0591SJens Wiklander (void) TimerContext; 267817466cbSJens Wiklander Sleep( alarmMs ); 268817466cbSJens Wiklander mbedtls_timing_alarmed = 1; 2693d3b0591SJens Wiklander /* _endthread will be called implicitly on return 2703d3b0591SJens Wiklander * That ensures execution of thread funcition's epilogue */ 271817466cbSJens Wiklander } 272817466cbSJens Wiklander 273817466cbSJens Wiklander void mbedtls_set_alarm( int seconds ) 274817466cbSJens Wiklander { 2753d3b0591SJens Wiklander if( seconds == 0 ) 2763d3b0591SJens Wiklander { 2773d3b0591SJens Wiklander /* No need to create a thread for this simple case. 2783d3b0591SJens Wiklander * Also, this shorcut is more reliable at least on MinGW32 */ 2793d3b0591SJens Wiklander mbedtls_timing_alarmed = 1; 2803d3b0591SJens Wiklander return; 2813d3b0591SJens Wiklander } 282817466cbSJens Wiklander 283817466cbSJens Wiklander mbedtls_timing_alarmed = 0; 284817466cbSJens Wiklander alarmMs = seconds * 1000; 2853d3b0591SJens Wiklander (void) _beginthread( TimerProc, 0, NULL ); 286817466cbSJens Wiklander } 287817466cbSJens Wiklander 288817466cbSJens Wiklander #else /* _WIN32 && !EFIX64 && !EFI32 */ 289817466cbSJens Wiklander 290817466cbSJens Wiklander unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) 291817466cbSJens Wiklander { 292817466cbSJens Wiklander struct _hr_time *t = (struct _hr_time *) val; 293817466cbSJens Wiklander 294817466cbSJens Wiklander if( reset ) 295817466cbSJens Wiklander { 2963d3b0591SJens Wiklander gettimeofday( &t->start, NULL ); 297817466cbSJens Wiklander return( 0 ); 298817466cbSJens Wiklander } 2993d3b0591SJens Wiklander else 3003d3b0591SJens Wiklander { 3013d3b0591SJens Wiklander unsigned long delta; 3023d3b0591SJens Wiklander struct timeval now; 3033d3b0591SJens Wiklander gettimeofday( &now, NULL ); 3043d3b0591SJens Wiklander delta = ( now.tv_sec - t->start.tv_sec ) * 1000ul 3053d3b0591SJens Wiklander + ( now.tv_usec - t->start.tv_usec ) / 1000; 306817466cbSJens Wiklander return( delta ); 307817466cbSJens Wiklander } 3083d3b0591SJens Wiklander } 309817466cbSJens Wiklander 310817466cbSJens Wiklander static void sighandler( int signum ) 311817466cbSJens Wiklander { 312817466cbSJens Wiklander mbedtls_timing_alarmed = 1; 313817466cbSJens Wiklander signal( signum, sighandler ); 314817466cbSJens Wiklander } 315817466cbSJens Wiklander 316817466cbSJens Wiklander void mbedtls_set_alarm( int seconds ) 317817466cbSJens Wiklander { 318817466cbSJens Wiklander mbedtls_timing_alarmed = 0; 319817466cbSJens Wiklander signal( SIGALRM, sighandler ); 320817466cbSJens Wiklander alarm( seconds ); 3213d3b0591SJens Wiklander if( seconds == 0 ) 3223d3b0591SJens Wiklander { 3233d3b0591SJens Wiklander /* alarm(0) cancelled any previous pending alarm, but the 3243d3b0591SJens Wiklander handler won't fire, so raise the flag straight away. */ 3253d3b0591SJens Wiklander mbedtls_timing_alarmed = 1; 3263d3b0591SJens Wiklander } 327817466cbSJens Wiklander } 328817466cbSJens Wiklander 329817466cbSJens Wiklander #endif /* _WIN32 && !EFIX64 && !EFI32 */ 330817466cbSJens Wiklander 331817466cbSJens Wiklander /* 332817466cbSJens Wiklander * Set delays to watch 333817466cbSJens Wiklander */ 334817466cbSJens Wiklander void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms ) 335817466cbSJens Wiklander { 336817466cbSJens Wiklander mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data; 337817466cbSJens Wiklander 338817466cbSJens Wiklander ctx->int_ms = int_ms; 339817466cbSJens Wiklander ctx->fin_ms = fin_ms; 340817466cbSJens Wiklander 341817466cbSJens Wiklander if( fin_ms != 0 ) 342817466cbSJens Wiklander (void) mbedtls_timing_get_timer( &ctx->timer, 1 ); 343817466cbSJens Wiklander } 344817466cbSJens Wiklander 345817466cbSJens Wiklander /* 346817466cbSJens Wiklander * Get number of delays expired 347817466cbSJens Wiklander */ 348817466cbSJens Wiklander int mbedtls_timing_get_delay( void *data ) 349817466cbSJens Wiklander { 350817466cbSJens Wiklander mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data; 351817466cbSJens Wiklander unsigned long elapsed_ms; 352817466cbSJens Wiklander 353817466cbSJens Wiklander if( ctx->fin_ms == 0 ) 354817466cbSJens Wiklander return( -1 ); 355817466cbSJens Wiklander 356817466cbSJens Wiklander elapsed_ms = mbedtls_timing_get_timer( &ctx->timer, 0 ); 357817466cbSJens Wiklander 358817466cbSJens Wiklander if( elapsed_ms >= ctx->fin_ms ) 359817466cbSJens Wiklander return( 2 ); 360817466cbSJens Wiklander 361817466cbSJens Wiklander if( elapsed_ms >= ctx->int_ms ) 362817466cbSJens Wiklander return( 1 ); 363817466cbSJens Wiklander 364817466cbSJens Wiklander return( 0 ); 365817466cbSJens Wiklander } 366817466cbSJens Wiklander 367817466cbSJens Wiklander 368817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST) 369817466cbSJens Wiklander 370817466cbSJens Wiklander /* 371817466cbSJens Wiklander * Busy-waits for the given number of milliseconds. 372817466cbSJens Wiklander * Used for testing mbedtls_timing_hardclock. 373817466cbSJens Wiklander */ 374817466cbSJens Wiklander static void busy_msleep( unsigned long msec ) 375817466cbSJens Wiklander { 376817466cbSJens Wiklander struct mbedtls_timing_hr_time hires; 377817466cbSJens Wiklander unsigned long i = 0; /* for busy-waiting */ 378817466cbSJens Wiklander volatile unsigned long j; /* to prevent optimisation */ 379817466cbSJens Wiklander 380817466cbSJens Wiklander (void) mbedtls_timing_get_timer( &hires, 1 ); 381817466cbSJens Wiklander 382817466cbSJens Wiklander while( mbedtls_timing_get_timer( &hires, 0 ) < msec ) 383817466cbSJens Wiklander i++; 384817466cbSJens Wiklander 385817466cbSJens Wiklander j = i; 386817466cbSJens Wiklander (void) j; 387817466cbSJens Wiklander } 388817466cbSJens Wiklander 389817466cbSJens Wiklander #define FAIL do \ 390817466cbSJens Wiklander { \ 391817466cbSJens Wiklander if( verbose != 0 ) \ 3923d3b0591SJens Wiklander { \ 3933d3b0591SJens Wiklander mbedtls_printf( "failed at line %d\n", __LINE__ ); \ 3943d3b0591SJens Wiklander mbedtls_printf( " cycles=%lu ratio=%lu millisecs=%lu secs=%lu hardfail=%d a=%lu b=%lu\n", \ 3953d3b0591SJens Wiklander cycles, ratio, millisecs, secs, hardfail, \ 3963d3b0591SJens Wiklander (unsigned long) a, (unsigned long) b ); \ 3973d3b0591SJens Wiklander mbedtls_printf( " elapsed(hires)=%lu elapsed(ctx)=%lu status(ctx)=%d\n", \ 3983d3b0591SJens Wiklander mbedtls_timing_get_timer( &hires, 0 ), \ 3993d3b0591SJens Wiklander mbedtls_timing_get_timer( &ctx.timer, 0 ), \ 4003d3b0591SJens Wiklander mbedtls_timing_get_delay( &ctx ) ); \ 4013d3b0591SJens Wiklander } \ 402817466cbSJens Wiklander return( 1 ); \ 403817466cbSJens Wiklander } while( 0 ) 404817466cbSJens Wiklander 405817466cbSJens Wiklander /* 406817466cbSJens Wiklander * Checkup routine 407817466cbSJens Wiklander * 408817466cbSJens Wiklander * Warning: this is work in progress, some tests may not be reliable enough 409817466cbSJens Wiklander * yet! False positives may happen. 410817466cbSJens Wiklander */ 411817466cbSJens Wiklander int mbedtls_timing_self_test( int verbose ) 412817466cbSJens Wiklander { 4133d3b0591SJens Wiklander unsigned long cycles = 0, ratio = 0; 4143d3b0591SJens Wiklander unsigned long millisecs = 0, secs = 0; 4153d3b0591SJens Wiklander int hardfail = 0; 416817466cbSJens Wiklander struct mbedtls_timing_hr_time hires; 4173d3b0591SJens Wiklander uint32_t a = 0, b = 0; 418817466cbSJens Wiklander mbedtls_timing_delay_context ctx; 419817466cbSJens Wiklander 420817466cbSJens Wiklander if( verbose != 0 ) 421817466cbSJens Wiklander mbedtls_printf( " TIMING tests note: will take some time!\n" ); 422817466cbSJens Wiklander 423817466cbSJens Wiklander if( verbose != 0 ) 424817466cbSJens Wiklander mbedtls_printf( " TIMING test #1 (set_alarm / get_timer): " ); 425817466cbSJens Wiklander 426817466cbSJens Wiklander { 4273d3b0591SJens Wiklander secs = 1; 4283d3b0591SJens Wiklander 429817466cbSJens Wiklander (void) mbedtls_timing_get_timer( &hires, 1 ); 430817466cbSJens Wiklander 431817466cbSJens Wiklander mbedtls_set_alarm( (int) secs ); 432817466cbSJens Wiklander while( !mbedtls_timing_alarmed ) 433817466cbSJens Wiklander ; 434817466cbSJens Wiklander 435817466cbSJens Wiklander millisecs = mbedtls_timing_get_timer( &hires, 0 ); 436817466cbSJens Wiklander 437817466cbSJens Wiklander /* For some reason on Windows it looks like alarm has an extra delay 438817466cbSJens Wiklander * (maybe related to creating a new thread). Allow some room here. */ 439817466cbSJens Wiklander if( millisecs < 800 * secs || millisecs > 1200 * secs + 300 ) 4403d3b0591SJens Wiklander FAIL; 441817466cbSJens Wiklander } 442817466cbSJens Wiklander 443817466cbSJens Wiklander if( verbose != 0 ) 444817466cbSJens Wiklander mbedtls_printf( "passed\n" ); 445817466cbSJens Wiklander 446817466cbSJens Wiklander if( verbose != 0 ) 447817466cbSJens Wiklander mbedtls_printf( " TIMING test #2 (set/get_delay ): " ); 448817466cbSJens Wiklander 449817466cbSJens Wiklander { 4503d3b0591SJens Wiklander a = 800; 4513d3b0591SJens Wiklander b = 400; 4523d3b0591SJens Wiklander mbedtls_timing_set_delay( &ctx, a, a + b ); /* T = 0 */ 453817466cbSJens Wiklander 4543d3b0591SJens Wiklander busy_msleep( a - a / 4 ); /* T = a - a/4 */ 455817466cbSJens Wiklander if( mbedtls_timing_get_delay( &ctx ) != 0 ) 456817466cbSJens Wiklander FAIL; 457817466cbSJens Wiklander 4583d3b0591SJens Wiklander busy_msleep( a / 4 + b / 4 ); /* T = a + b/4 */ 459817466cbSJens Wiklander if( mbedtls_timing_get_delay( &ctx ) != 1 ) 460817466cbSJens Wiklander FAIL; 461817466cbSJens Wiklander 4623d3b0591SJens Wiklander busy_msleep( b ); /* T = a + b + b/4 */ 463817466cbSJens Wiklander if( mbedtls_timing_get_delay( &ctx ) != 2 ) 464817466cbSJens Wiklander FAIL; 465817466cbSJens Wiklander } 466817466cbSJens Wiklander 467817466cbSJens Wiklander mbedtls_timing_set_delay( &ctx, 0, 0 ); 468817466cbSJens Wiklander busy_msleep( 200 ); 469817466cbSJens Wiklander if( mbedtls_timing_get_delay( &ctx ) != -1 ) 470817466cbSJens Wiklander FAIL; 471817466cbSJens Wiklander 472817466cbSJens Wiklander if( verbose != 0 ) 473817466cbSJens Wiklander mbedtls_printf( "passed\n" ); 474817466cbSJens Wiklander 475817466cbSJens Wiklander if( verbose != 0 ) 476817466cbSJens Wiklander mbedtls_printf( " TIMING test #3 (hardclock / get_timer): " ); 477817466cbSJens Wiklander 478817466cbSJens Wiklander /* 479817466cbSJens Wiklander * Allow one failure for possible counter wrapping. 480817466cbSJens Wiklander * On a 4Ghz 32-bit machine the cycle counter wraps about once per second; 481817466cbSJens Wiklander * since the whole test is about 10ms, it shouldn't happen twice in a row. 482817466cbSJens Wiklander */ 483817466cbSJens Wiklander 484817466cbSJens Wiklander hard_test: 485817466cbSJens Wiklander if( hardfail > 1 ) 486817466cbSJens Wiklander { 487817466cbSJens Wiklander if( verbose != 0 ) 488817466cbSJens Wiklander mbedtls_printf( "failed (ignored)\n" ); 489817466cbSJens Wiklander 490817466cbSJens Wiklander goto hard_test_done; 491817466cbSJens Wiklander } 492817466cbSJens Wiklander 493817466cbSJens Wiklander /* Get a reference ratio cycles/ms */ 494817466cbSJens Wiklander millisecs = 1; 495817466cbSJens Wiklander cycles = mbedtls_timing_hardclock(); 496817466cbSJens Wiklander busy_msleep( millisecs ); 497817466cbSJens Wiklander cycles = mbedtls_timing_hardclock() - cycles; 498817466cbSJens Wiklander ratio = cycles / millisecs; 499817466cbSJens Wiklander 500817466cbSJens Wiklander /* Check that the ratio is mostly constant */ 501817466cbSJens Wiklander for( millisecs = 2; millisecs <= 4; millisecs++ ) 502817466cbSJens Wiklander { 503817466cbSJens Wiklander cycles = mbedtls_timing_hardclock(); 504817466cbSJens Wiklander busy_msleep( millisecs ); 505817466cbSJens Wiklander cycles = mbedtls_timing_hardclock() - cycles; 506817466cbSJens Wiklander 507817466cbSJens Wiklander /* Allow variation up to 20% */ 508817466cbSJens Wiklander if( cycles / millisecs < ratio - ratio / 5 || 509817466cbSJens Wiklander cycles / millisecs > ratio + ratio / 5 ) 510817466cbSJens Wiklander { 511817466cbSJens Wiklander hardfail++; 512817466cbSJens Wiklander goto hard_test; 513817466cbSJens Wiklander } 514817466cbSJens Wiklander } 515817466cbSJens Wiklander 516817466cbSJens Wiklander if( verbose != 0 ) 517817466cbSJens Wiklander mbedtls_printf( "passed\n" ); 518817466cbSJens Wiklander 519817466cbSJens Wiklander hard_test_done: 520817466cbSJens Wiklander 521817466cbSJens Wiklander if( verbose != 0 ) 522817466cbSJens Wiklander mbedtls_printf( "\n" ); 523817466cbSJens Wiklander 524817466cbSJens Wiklander return( 0 ); 525817466cbSJens Wiklander } 526817466cbSJens Wiklander 527817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */ 528*039e02dfSJerome Forissier #endif /* !MBEDTLS_TIMING_ALT */ 529817466cbSJens Wiklander #endif /* MBEDTLS_TIMING_C */ 530