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