1c6672fdcSEdison Ai // SPDX-License-Identifier: Apache-2.0 2817466cbSJens Wiklander /* 3817466cbSJens Wiklander * Portable interface to the CPU cycle counter 4817466cbSJens Wiklander * 5817466cbSJens Wiklander * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 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 * This file is part of mbed TLS (https://tls.mbed.org) 20817466cbSJens Wiklander */ 21817466cbSJens Wiklander 22817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE) 23817466cbSJens Wiklander #include "mbedtls/config.h" 24817466cbSJens Wiklander #else 25817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE 26817466cbSJens Wiklander #endif 27817466cbSJens Wiklander 28817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_PLATFORM_C) 29817466cbSJens Wiklander #include "mbedtls/platform.h" 30817466cbSJens Wiklander #else 31817466cbSJens Wiklander #include <stdio.h> 32817466cbSJens Wiklander #define mbedtls_printf printf 33817466cbSJens Wiklander #endif 34817466cbSJens Wiklander 35817466cbSJens Wiklander #if defined(MBEDTLS_TIMING_C) 36817466cbSJens Wiklander 37817466cbSJens Wiklander #include "mbedtls/timing.h" 38817466cbSJens Wiklander 39817466cbSJens Wiklander #if !defined(MBEDTLS_TIMING_ALT) 40817466cbSJens Wiklander 41817466cbSJens Wiklander #if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ 42*3d3b0591SJens Wiklander !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \ 43*3d3b0591SJens Wiklander !defined(__HAIKU__) 44817466cbSJens Wiklander #error "This module only works on Unix and Windows, see MBEDTLS_TIMING_C in config.h" 45817466cbSJens Wiklander #endif 46817466cbSJens Wiklander 47817466cbSJens Wiklander #ifndef asm 48817466cbSJens Wiklander #define asm __asm 49817466cbSJens Wiklander #endif 50817466cbSJens Wiklander 51817466cbSJens Wiklander #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 52817466cbSJens Wiklander 53817466cbSJens Wiklander #include <windows.h> 54817466cbSJens Wiklander #include <winbase.h> 55*3d3b0591SJens Wiklander #include <process.h> 56817466cbSJens Wiklander 57817466cbSJens Wiklander struct _hr_time 58817466cbSJens Wiklander { 59817466cbSJens Wiklander LARGE_INTEGER start; 60817466cbSJens Wiklander }; 61817466cbSJens Wiklander 62817466cbSJens Wiklander #else 63817466cbSJens Wiklander 64817466cbSJens Wiklander #include <unistd.h> 65817466cbSJens Wiklander #include <sys/types.h> 66817466cbSJens Wiklander #include <sys/time.h> 67817466cbSJens Wiklander #include <signal.h> 68817466cbSJens Wiklander #include <time.h> 69817466cbSJens Wiklander 70817466cbSJens Wiklander struct _hr_time 71817466cbSJens Wiklander { 72817466cbSJens Wiklander struct timeval start; 73817466cbSJens Wiklander }; 74817466cbSJens Wiklander 75817466cbSJens Wiklander #endif /* _WIN32 && !EFIX64 && !EFI32 */ 76817466cbSJens Wiklander 77817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 78817466cbSJens Wiklander ( defined(_MSC_VER) && defined(_M_IX86) ) || defined(__WATCOMC__) 79817466cbSJens Wiklander 80817466cbSJens Wiklander #define HAVE_HARDCLOCK 81817466cbSJens Wiklander 82817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 83817466cbSJens Wiklander { 84817466cbSJens Wiklander unsigned long tsc; 85817466cbSJens Wiklander __asm rdtsc 86817466cbSJens Wiklander __asm mov [tsc], eax 87817466cbSJens Wiklander return( tsc ); 88817466cbSJens Wiklander } 89817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 90817466cbSJens Wiklander ( _MSC_VER && _M_IX86 ) || __WATCOMC__ */ 91817466cbSJens Wiklander 92817466cbSJens Wiklander /* some versions of mingw-64 have 32-bit longs even on x84_64 */ 93817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 94817466cbSJens Wiklander defined(__GNUC__) && ( defined(__i386__) || ( \ 95817466cbSJens Wiklander ( defined(__amd64__) || defined( __x86_64__) ) && __SIZEOF_LONG__ == 4 ) ) 96817466cbSJens Wiklander 97817466cbSJens Wiklander #define HAVE_HARDCLOCK 98817466cbSJens Wiklander 99817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 100817466cbSJens Wiklander { 101817466cbSJens Wiklander unsigned long lo, hi; 102817466cbSJens Wiklander asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); 103817466cbSJens Wiklander return( lo ); 104817466cbSJens Wiklander } 105817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 106817466cbSJens Wiklander __GNUC__ && __i386__ */ 107817466cbSJens Wiklander 108817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 109817466cbSJens Wiklander defined(__GNUC__) && ( defined(__amd64__) || defined(__x86_64__) ) 110817466cbSJens Wiklander 111817466cbSJens Wiklander #define HAVE_HARDCLOCK 112817466cbSJens Wiklander 113817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 114817466cbSJens Wiklander { 115817466cbSJens Wiklander unsigned long lo, hi; 116817466cbSJens Wiklander asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); 117817466cbSJens Wiklander return( lo | ( hi << 32 ) ); 118817466cbSJens Wiklander } 119817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 120817466cbSJens Wiklander __GNUC__ && ( __amd64__ || __x86_64__ ) */ 121817466cbSJens Wiklander 122817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 123817466cbSJens Wiklander defined(__GNUC__) && ( defined(__powerpc__) || defined(__ppc__) ) 124817466cbSJens Wiklander 125817466cbSJens Wiklander #define HAVE_HARDCLOCK 126817466cbSJens Wiklander 127817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 128817466cbSJens Wiklander { 129817466cbSJens Wiklander unsigned long tbl, tbu0, tbu1; 130817466cbSJens Wiklander 131817466cbSJens Wiklander do 132817466cbSJens Wiklander { 133817466cbSJens Wiklander asm volatile( "mftbu %0" : "=r" (tbu0) ); 134817466cbSJens Wiklander asm volatile( "mftb %0" : "=r" (tbl ) ); 135817466cbSJens Wiklander asm volatile( "mftbu %0" : "=r" (tbu1) ); 136817466cbSJens Wiklander } 137817466cbSJens Wiklander while( tbu0 != tbu1 ); 138817466cbSJens Wiklander 139817466cbSJens Wiklander return( tbl ); 140817466cbSJens Wiklander } 141817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 142817466cbSJens Wiklander __GNUC__ && ( __powerpc__ || __ppc__ ) */ 143817466cbSJens Wiklander 144817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 145817466cbSJens Wiklander defined(__GNUC__) && defined(__sparc64__) 146817466cbSJens Wiklander 147817466cbSJens Wiklander #if defined(__OpenBSD__) 148817466cbSJens Wiklander #warning OpenBSD does not allow access to tick register using software version instead 149817466cbSJens Wiklander #else 150817466cbSJens Wiklander #define HAVE_HARDCLOCK 151817466cbSJens Wiklander 152817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 153817466cbSJens Wiklander { 154817466cbSJens Wiklander unsigned long tick; 155817466cbSJens Wiklander asm volatile( "rdpr %%tick, %0;" : "=&r" (tick) ); 156817466cbSJens Wiklander return( tick ); 157817466cbSJens Wiklander } 158817466cbSJens Wiklander #endif /* __OpenBSD__ */ 159817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 160817466cbSJens Wiklander __GNUC__ && __sparc64__ */ 161817466cbSJens Wiklander 162817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 163817466cbSJens Wiklander defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__) 164817466cbSJens Wiklander 165817466cbSJens Wiklander #define HAVE_HARDCLOCK 166817466cbSJens Wiklander 167817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 168817466cbSJens Wiklander { 169817466cbSJens Wiklander unsigned long tick; 170817466cbSJens Wiklander asm volatile( ".byte 0x83, 0x41, 0x00, 0x00" ); 171817466cbSJens Wiklander asm volatile( "mov %%g1, %0" : "=r" (tick) ); 172817466cbSJens Wiklander return( tick ); 173817466cbSJens Wiklander } 174817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 175817466cbSJens Wiklander __GNUC__ && __sparc__ && !__sparc64__ */ 176817466cbSJens Wiklander 177817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 178817466cbSJens Wiklander defined(__GNUC__) && defined(__alpha__) 179817466cbSJens Wiklander 180817466cbSJens Wiklander #define HAVE_HARDCLOCK 181817466cbSJens Wiklander 182817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 183817466cbSJens Wiklander { 184817466cbSJens Wiklander unsigned long cc; 185817466cbSJens Wiklander asm volatile( "rpcc %0" : "=r" (cc) ); 186817466cbSJens Wiklander return( cc & 0xFFFFFFFF ); 187817466cbSJens Wiklander } 188817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 189817466cbSJens Wiklander __GNUC__ && __alpha__ */ 190817466cbSJens Wiklander 191817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 192817466cbSJens Wiklander defined(__GNUC__) && defined(__ia64__) 193817466cbSJens Wiklander 194817466cbSJens Wiklander #define HAVE_HARDCLOCK 195817466cbSJens Wiklander 196817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 197817466cbSJens Wiklander { 198817466cbSJens Wiklander unsigned long itc; 199817466cbSJens Wiklander asm volatile( "mov %0 = ar.itc" : "=r" (itc) ); 200817466cbSJens Wiklander return( itc ); 201817466cbSJens Wiklander } 202817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 203817466cbSJens Wiklander __GNUC__ && __ia64__ */ 204817466cbSJens Wiklander 205817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \ 206817466cbSJens Wiklander !defined(EFIX64) && !defined(EFI32) 207817466cbSJens Wiklander 208817466cbSJens Wiklander #define HAVE_HARDCLOCK 209817466cbSJens Wiklander 210817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 211817466cbSJens Wiklander { 212817466cbSJens Wiklander LARGE_INTEGER offset; 213817466cbSJens Wiklander 214817466cbSJens Wiklander QueryPerformanceCounter( &offset ); 215817466cbSJens Wiklander 216817466cbSJens Wiklander return( (unsigned long)( offset.QuadPart ) ); 217817466cbSJens Wiklander } 218817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && _MSC_VER && !EFIX64 && !EFI32 */ 219817466cbSJens Wiklander 220817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) 221817466cbSJens Wiklander 222817466cbSJens Wiklander #define HAVE_HARDCLOCK 223817466cbSJens Wiklander 224817466cbSJens Wiklander static int hardclock_init = 0; 225817466cbSJens Wiklander static struct timeval tv_init; 226817466cbSJens Wiklander 227817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 228817466cbSJens Wiklander { 229817466cbSJens Wiklander struct timeval tv_cur; 230817466cbSJens Wiklander 231817466cbSJens Wiklander if( hardclock_init == 0 ) 232817466cbSJens Wiklander { 233817466cbSJens Wiklander gettimeofday( &tv_init, NULL ); 234817466cbSJens Wiklander hardclock_init = 1; 235817466cbSJens Wiklander } 236817466cbSJens Wiklander 237817466cbSJens Wiklander gettimeofday( &tv_cur, NULL ); 238817466cbSJens Wiklander return( ( tv_cur.tv_sec - tv_init.tv_sec ) * 1000000 239817466cbSJens Wiklander + ( tv_cur.tv_usec - tv_init.tv_usec ) ); 240817466cbSJens Wiklander } 241817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK */ 242817466cbSJens Wiklander 243817466cbSJens Wiklander volatile int mbedtls_timing_alarmed = 0; 244817466cbSJens Wiklander 245817466cbSJens Wiklander #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 246817466cbSJens Wiklander 247817466cbSJens Wiklander unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) 248817466cbSJens Wiklander { 249817466cbSJens Wiklander struct _hr_time *t = (struct _hr_time *) val; 250817466cbSJens Wiklander 251817466cbSJens Wiklander if( reset ) 252*3d3b0591SJens Wiklander { 253817466cbSJens Wiklander QueryPerformanceCounter( &t->start ); 254*3d3b0591SJens Wiklander return( 0 ); 255*3d3b0591SJens Wiklander } 256*3d3b0591SJens Wiklander else 257*3d3b0591SJens Wiklander { 258*3d3b0591SJens Wiklander unsigned long delta; 259*3d3b0591SJens Wiklander LARGE_INTEGER now, hfreq; 260*3d3b0591SJens Wiklander QueryPerformanceCounter( &now ); 261*3d3b0591SJens Wiklander QueryPerformanceFrequency( &hfreq ); 262*3d3b0591SJens Wiklander delta = (unsigned long)( ( now.QuadPart - t->start.QuadPart ) * 1000ul 263*3d3b0591SJens Wiklander / hfreq.QuadPart ); 264817466cbSJens Wiklander return( delta ); 265817466cbSJens Wiklander } 266*3d3b0591SJens Wiklander } 267817466cbSJens Wiklander 268817466cbSJens Wiklander /* It's OK to use a global because alarm() is supposed to be global anyway */ 269817466cbSJens Wiklander static DWORD alarmMs; 270817466cbSJens Wiklander 271*3d3b0591SJens Wiklander static void TimerProc( void *TimerContext ) 272817466cbSJens Wiklander { 273*3d3b0591SJens Wiklander (void) TimerContext; 274817466cbSJens Wiklander Sleep( alarmMs ); 275817466cbSJens Wiklander mbedtls_timing_alarmed = 1; 276*3d3b0591SJens Wiklander /* _endthread will be called implicitly on return 277*3d3b0591SJens Wiklander * That ensures execution of thread funcition's epilogue */ 278817466cbSJens Wiklander } 279817466cbSJens Wiklander 280817466cbSJens Wiklander void mbedtls_set_alarm( int seconds ) 281817466cbSJens Wiklander { 282*3d3b0591SJens Wiklander if( seconds == 0 ) 283*3d3b0591SJens Wiklander { 284*3d3b0591SJens Wiklander /* No need to create a thread for this simple case. 285*3d3b0591SJens Wiklander * Also, this shorcut is more reliable at least on MinGW32 */ 286*3d3b0591SJens Wiklander mbedtls_timing_alarmed = 1; 287*3d3b0591SJens Wiklander return; 288*3d3b0591SJens Wiklander } 289817466cbSJens Wiklander 290817466cbSJens Wiklander mbedtls_timing_alarmed = 0; 291817466cbSJens Wiklander alarmMs = seconds * 1000; 292*3d3b0591SJens Wiklander (void) _beginthread( TimerProc, 0, NULL ); 293817466cbSJens Wiklander } 294817466cbSJens Wiklander 295817466cbSJens Wiklander #else /* _WIN32 && !EFIX64 && !EFI32 */ 296817466cbSJens Wiklander 297817466cbSJens Wiklander unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) 298817466cbSJens Wiklander { 299817466cbSJens Wiklander struct _hr_time *t = (struct _hr_time *) val; 300817466cbSJens Wiklander 301817466cbSJens Wiklander if( reset ) 302817466cbSJens Wiklander { 303*3d3b0591SJens Wiklander gettimeofday( &t->start, NULL ); 304817466cbSJens Wiklander return( 0 ); 305817466cbSJens Wiklander } 306*3d3b0591SJens Wiklander else 307*3d3b0591SJens Wiklander { 308*3d3b0591SJens Wiklander unsigned long delta; 309*3d3b0591SJens Wiklander struct timeval now; 310*3d3b0591SJens Wiklander gettimeofday( &now, NULL ); 311*3d3b0591SJens Wiklander delta = ( now.tv_sec - t->start.tv_sec ) * 1000ul 312*3d3b0591SJens Wiklander + ( now.tv_usec - t->start.tv_usec ) / 1000; 313817466cbSJens Wiklander return( delta ); 314817466cbSJens Wiklander } 315*3d3b0591SJens Wiklander } 316817466cbSJens Wiklander 317817466cbSJens Wiklander static void sighandler( int signum ) 318817466cbSJens Wiklander { 319817466cbSJens Wiklander mbedtls_timing_alarmed = 1; 320817466cbSJens Wiklander signal( signum, sighandler ); 321817466cbSJens Wiklander } 322817466cbSJens Wiklander 323817466cbSJens Wiklander void mbedtls_set_alarm( int seconds ) 324817466cbSJens Wiklander { 325817466cbSJens Wiklander mbedtls_timing_alarmed = 0; 326817466cbSJens Wiklander signal( SIGALRM, sighandler ); 327817466cbSJens Wiklander alarm( seconds ); 328*3d3b0591SJens Wiklander if( seconds == 0 ) 329*3d3b0591SJens Wiklander { 330*3d3b0591SJens Wiklander /* alarm(0) cancelled any previous pending alarm, but the 331*3d3b0591SJens Wiklander handler won't fire, so raise the flag straight away. */ 332*3d3b0591SJens Wiklander mbedtls_timing_alarmed = 1; 333*3d3b0591SJens Wiklander } 334817466cbSJens Wiklander } 335817466cbSJens Wiklander 336817466cbSJens Wiklander #endif /* _WIN32 && !EFIX64 && !EFI32 */ 337817466cbSJens Wiklander 338817466cbSJens Wiklander /* 339817466cbSJens Wiklander * Set delays to watch 340817466cbSJens Wiklander */ 341817466cbSJens Wiklander void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms ) 342817466cbSJens Wiklander { 343817466cbSJens Wiklander mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data; 344817466cbSJens Wiklander 345817466cbSJens Wiklander ctx->int_ms = int_ms; 346817466cbSJens Wiklander ctx->fin_ms = fin_ms; 347817466cbSJens Wiklander 348817466cbSJens Wiklander if( fin_ms != 0 ) 349817466cbSJens Wiklander (void) mbedtls_timing_get_timer( &ctx->timer, 1 ); 350817466cbSJens Wiklander } 351817466cbSJens Wiklander 352817466cbSJens Wiklander /* 353817466cbSJens Wiklander * Get number of delays expired 354817466cbSJens Wiklander */ 355817466cbSJens Wiklander int mbedtls_timing_get_delay( void *data ) 356817466cbSJens Wiklander { 357817466cbSJens Wiklander mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data; 358817466cbSJens Wiklander unsigned long elapsed_ms; 359817466cbSJens Wiklander 360817466cbSJens Wiklander if( ctx->fin_ms == 0 ) 361817466cbSJens Wiklander return( -1 ); 362817466cbSJens Wiklander 363817466cbSJens Wiklander elapsed_ms = mbedtls_timing_get_timer( &ctx->timer, 0 ); 364817466cbSJens Wiklander 365817466cbSJens Wiklander if( elapsed_ms >= ctx->fin_ms ) 366817466cbSJens Wiklander return( 2 ); 367817466cbSJens Wiklander 368817466cbSJens Wiklander if( elapsed_ms >= ctx->int_ms ) 369817466cbSJens Wiklander return( 1 ); 370817466cbSJens Wiklander 371817466cbSJens Wiklander return( 0 ); 372817466cbSJens Wiklander } 373817466cbSJens Wiklander 374817466cbSJens Wiklander #endif /* !MBEDTLS_TIMING_ALT */ 375817466cbSJens Wiklander 376817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST) 377817466cbSJens Wiklander 378817466cbSJens Wiklander /* 379817466cbSJens Wiklander * Busy-waits for the given number of milliseconds. 380817466cbSJens Wiklander * Used for testing mbedtls_timing_hardclock. 381817466cbSJens Wiklander */ 382817466cbSJens Wiklander static void busy_msleep( unsigned long msec ) 383817466cbSJens Wiklander { 384817466cbSJens Wiklander struct mbedtls_timing_hr_time hires; 385817466cbSJens Wiklander unsigned long i = 0; /* for busy-waiting */ 386817466cbSJens Wiklander volatile unsigned long j; /* to prevent optimisation */ 387817466cbSJens Wiklander 388817466cbSJens Wiklander (void) mbedtls_timing_get_timer( &hires, 1 ); 389817466cbSJens Wiklander 390817466cbSJens Wiklander while( mbedtls_timing_get_timer( &hires, 0 ) < msec ) 391817466cbSJens Wiklander i++; 392817466cbSJens Wiklander 393817466cbSJens Wiklander j = i; 394817466cbSJens Wiklander (void) j; 395817466cbSJens Wiklander } 396817466cbSJens Wiklander 397817466cbSJens Wiklander #define FAIL do \ 398817466cbSJens Wiklander { \ 399817466cbSJens Wiklander if( verbose != 0 ) \ 400*3d3b0591SJens Wiklander { \ 401*3d3b0591SJens Wiklander mbedtls_printf( "failed at line %d\n", __LINE__ ); \ 402*3d3b0591SJens Wiklander mbedtls_printf( " cycles=%lu ratio=%lu millisecs=%lu secs=%lu hardfail=%d a=%lu b=%lu\n", \ 403*3d3b0591SJens Wiklander cycles, ratio, millisecs, secs, hardfail, \ 404*3d3b0591SJens Wiklander (unsigned long) a, (unsigned long) b ); \ 405*3d3b0591SJens Wiklander mbedtls_printf( " elapsed(hires)=%lu elapsed(ctx)=%lu status(ctx)=%d\n", \ 406*3d3b0591SJens Wiklander mbedtls_timing_get_timer( &hires, 0 ), \ 407*3d3b0591SJens Wiklander mbedtls_timing_get_timer( &ctx.timer, 0 ), \ 408*3d3b0591SJens Wiklander mbedtls_timing_get_delay( &ctx ) ); \ 409*3d3b0591SJens Wiklander } \ 410817466cbSJens Wiklander return( 1 ); \ 411817466cbSJens Wiklander } while( 0 ) 412817466cbSJens Wiklander 413817466cbSJens Wiklander /* 414817466cbSJens Wiklander * Checkup routine 415817466cbSJens Wiklander * 416817466cbSJens Wiklander * Warning: this is work in progress, some tests may not be reliable enough 417817466cbSJens Wiklander * yet! False positives may happen. 418817466cbSJens Wiklander */ 419817466cbSJens Wiklander int mbedtls_timing_self_test( int verbose ) 420817466cbSJens Wiklander { 421*3d3b0591SJens Wiklander unsigned long cycles = 0, ratio = 0; 422*3d3b0591SJens Wiklander unsigned long millisecs = 0, secs = 0; 423*3d3b0591SJens Wiklander int hardfail = 0; 424817466cbSJens Wiklander struct mbedtls_timing_hr_time hires; 425*3d3b0591SJens Wiklander uint32_t a = 0, b = 0; 426817466cbSJens Wiklander mbedtls_timing_delay_context ctx; 427817466cbSJens Wiklander 428817466cbSJens Wiklander if( verbose != 0 ) 429817466cbSJens Wiklander mbedtls_printf( " TIMING tests note: will take some time!\n" ); 430817466cbSJens Wiklander 431817466cbSJens Wiklander if( verbose != 0 ) 432817466cbSJens Wiklander mbedtls_printf( " TIMING test #1 (set_alarm / get_timer): " ); 433817466cbSJens Wiklander 434817466cbSJens Wiklander { 435*3d3b0591SJens Wiklander secs = 1; 436*3d3b0591SJens Wiklander 437817466cbSJens Wiklander (void) mbedtls_timing_get_timer( &hires, 1 ); 438817466cbSJens Wiklander 439817466cbSJens Wiklander mbedtls_set_alarm( (int) secs ); 440817466cbSJens Wiklander while( !mbedtls_timing_alarmed ) 441817466cbSJens Wiklander ; 442817466cbSJens Wiklander 443817466cbSJens Wiklander millisecs = mbedtls_timing_get_timer( &hires, 0 ); 444817466cbSJens Wiklander 445817466cbSJens Wiklander /* For some reason on Windows it looks like alarm has an extra delay 446817466cbSJens Wiklander * (maybe related to creating a new thread). Allow some room here. */ 447817466cbSJens Wiklander if( millisecs < 800 * secs || millisecs > 1200 * secs + 300 ) 448*3d3b0591SJens Wiklander FAIL; 449817466cbSJens Wiklander } 450817466cbSJens Wiklander 451817466cbSJens Wiklander if( verbose != 0 ) 452817466cbSJens Wiklander mbedtls_printf( "passed\n" ); 453817466cbSJens Wiklander 454817466cbSJens Wiklander if( verbose != 0 ) 455817466cbSJens Wiklander mbedtls_printf( " TIMING test #2 (set/get_delay ): " ); 456817466cbSJens Wiklander 457817466cbSJens Wiklander { 458*3d3b0591SJens Wiklander a = 800; 459*3d3b0591SJens Wiklander b = 400; 460*3d3b0591SJens Wiklander mbedtls_timing_set_delay( &ctx, a, a + b ); /* T = 0 */ 461817466cbSJens Wiklander 462*3d3b0591SJens Wiklander busy_msleep( a - a / 4 ); /* T = a - a/4 */ 463817466cbSJens Wiklander if( mbedtls_timing_get_delay( &ctx ) != 0 ) 464817466cbSJens Wiklander FAIL; 465817466cbSJens Wiklander 466*3d3b0591SJens Wiklander busy_msleep( a / 4 + b / 4 ); /* T = a + b/4 */ 467817466cbSJens Wiklander if( mbedtls_timing_get_delay( &ctx ) != 1 ) 468817466cbSJens Wiklander FAIL; 469817466cbSJens Wiklander 470*3d3b0591SJens Wiklander busy_msleep( b ); /* T = a + b + b/4 */ 471817466cbSJens Wiklander if( mbedtls_timing_get_delay( &ctx ) != 2 ) 472817466cbSJens Wiklander FAIL; 473817466cbSJens Wiklander } 474817466cbSJens Wiklander 475817466cbSJens Wiklander mbedtls_timing_set_delay( &ctx, 0, 0 ); 476817466cbSJens Wiklander busy_msleep( 200 ); 477817466cbSJens Wiklander if( mbedtls_timing_get_delay( &ctx ) != -1 ) 478817466cbSJens Wiklander FAIL; 479817466cbSJens Wiklander 480817466cbSJens Wiklander if( verbose != 0 ) 481817466cbSJens Wiklander mbedtls_printf( "passed\n" ); 482817466cbSJens Wiklander 483817466cbSJens Wiklander if( verbose != 0 ) 484817466cbSJens Wiklander mbedtls_printf( " TIMING test #3 (hardclock / get_timer): " ); 485817466cbSJens Wiklander 486817466cbSJens Wiklander /* 487817466cbSJens Wiklander * Allow one failure for possible counter wrapping. 488817466cbSJens Wiklander * On a 4Ghz 32-bit machine the cycle counter wraps about once per second; 489817466cbSJens Wiklander * since the whole test is about 10ms, it shouldn't happen twice in a row. 490817466cbSJens Wiklander */ 491817466cbSJens Wiklander 492817466cbSJens Wiklander hard_test: 493817466cbSJens Wiklander if( hardfail > 1 ) 494817466cbSJens Wiklander { 495817466cbSJens Wiklander if( verbose != 0 ) 496817466cbSJens Wiklander mbedtls_printf( "failed (ignored)\n" ); 497817466cbSJens Wiklander 498817466cbSJens Wiklander goto hard_test_done; 499817466cbSJens Wiklander } 500817466cbSJens Wiklander 501817466cbSJens Wiklander /* Get a reference ratio cycles/ms */ 502817466cbSJens Wiklander millisecs = 1; 503817466cbSJens Wiklander cycles = mbedtls_timing_hardclock(); 504817466cbSJens Wiklander busy_msleep( millisecs ); 505817466cbSJens Wiklander cycles = mbedtls_timing_hardclock() - cycles; 506817466cbSJens Wiklander ratio = cycles / millisecs; 507817466cbSJens Wiklander 508817466cbSJens Wiklander /* Check that the ratio is mostly constant */ 509817466cbSJens Wiklander for( millisecs = 2; millisecs <= 4; millisecs++ ) 510817466cbSJens Wiklander { 511817466cbSJens Wiklander cycles = mbedtls_timing_hardclock(); 512817466cbSJens Wiklander busy_msleep( millisecs ); 513817466cbSJens Wiklander cycles = mbedtls_timing_hardclock() - cycles; 514817466cbSJens Wiklander 515817466cbSJens Wiklander /* Allow variation up to 20% */ 516817466cbSJens Wiklander if( cycles / millisecs < ratio - ratio / 5 || 517817466cbSJens Wiklander cycles / millisecs > ratio + ratio / 5 ) 518817466cbSJens Wiklander { 519817466cbSJens Wiklander hardfail++; 520817466cbSJens Wiklander goto hard_test; 521817466cbSJens Wiklander } 522817466cbSJens Wiklander } 523817466cbSJens Wiklander 524817466cbSJens Wiklander if( verbose != 0 ) 525817466cbSJens Wiklander mbedtls_printf( "passed\n" ); 526817466cbSJens Wiklander 527817466cbSJens Wiklander hard_test_done: 528817466cbSJens Wiklander 529817466cbSJens Wiklander if( verbose != 0 ) 530817466cbSJens Wiklander mbedtls_printf( "\n" ); 531817466cbSJens Wiklander 532817466cbSJens Wiklander return( 0 ); 533817466cbSJens Wiklander } 534817466cbSJens Wiklander 535817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */ 536817466cbSJens Wiklander 537817466cbSJens Wiklander #endif /* MBEDTLS_TIMING_C */ 538