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