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