Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbedtls by
timing.c
00001 /* 00002 * Portable interface to the CPU cycle counter 00003 * 00004 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 00005 * SPDX-License-Identifier: Apache-2.0 00006 * 00007 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00008 * not use this file except in compliance with the License. 00009 * You may obtain a copy of the License at 00010 * 00011 * http://www.apache.org/licenses/LICENSE-2.0 00012 * 00013 * Unless required by applicable law or agreed to in writing, software 00014 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00015 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00016 * See the License for the specific language governing permissions and 00017 * limitations under the License. 00018 * 00019 * This file is part of mbed TLS (https://tls.mbed.org) 00020 */ 00021 00022 #if !defined(MBEDTLS_CONFIG_FILE) 00023 #include "mbedtls/config.h" 00024 #else 00025 #include MBEDTLS_CONFIG_FILE 00026 #endif 00027 00028 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_PLATFORM_C) 00029 #include "mbedtls/platform.h" 00030 #else 00031 #include <stdio.h> 00032 #define mbedtls_printf printf 00033 #endif 00034 00035 #if defined(MBEDTLS_TIMING_C) 00036 00037 #include "mbedtls/timing.h" 00038 00039 #if !defined(MBEDTLS_TIMING_ALT) 00040 00041 #ifndef asm 00042 #define asm __asm 00043 #endif 00044 00045 #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 00046 00047 #include <windows.h> 00048 #include <winbase.h> 00049 00050 struct _hr_time 00051 { 00052 LARGE_INTEGER start; 00053 }; 00054 00055 #else 00056 00057 #include <unistd.h> 00058 #include <sys/types.h> 00059 #include <sys/time.h> 00060 #include <signal.h> 00061 #include <time.h> 00062 00063 struct _hr_time 00064 { 00065 struct timeval start; 00066 }; 00067 00068 #endif /* _WIN32 && !EFIX64 && !EFI32 */ 00069 00070 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 00071 ( defined(_MSC_VER) && defined(_M_IX86) ) || defined(__WATCOMC__) 00072 00073 #define HAVE_HARDCLOCK 00074 00075 unsigned long mbedtls_timing_hardclock( void ) 00076 { 00077 unsigned long tsc; 00078 __asm rdtsc 00079 __asm mov [tsc], eax 00080 return( tsc ); 00081 } 00082 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 00083 ( _MSC_VER && _M_IX86 ) || __WATCOMC__ */ 00084 00085 /* some versions of mingw-64 have 32-bit longs even on x84_64 */ 00086 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 00087 defined(__GNUC__) && ( defined(__i386__) || ( \ 00088 ( defined(__amd64__) || defined( __x86_64__) ) && __SIZEOF_LONG__ == 4 ) ) 00089 00090 #define HAVE_HARDCLOCK 00091 00092 unsigned long mbedtls_timing_hardclock( void ) 00093 { 00094 unsigned long lo, hi; 00095 asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); 00096 return( lo ); 00097 } 00098 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 00099 __GNUC__ && __i386__ */ 00100 00101 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 00102 defined(__GNUC__) && ( defined(__amd64__) || defined(__x86_64__) ) 00103 00104 #define HAVE_HARDCLOCK 00105 00106 unsigned long mbedtls_timing_hardclock( void ) 00107 { 00108 unsigned long lo, hi; 00109 asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); 00110 return( lo | ( hi << 32 ) ); 00111 } 00112 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 00113 __GNUC__ && ( __amd64__ || __x86_64__ ) */ 00114 00115 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 00116 defined(__GNUC__) && ( defined(__powerpc__) || defined(__ppc__) ) 00117 00118 #define HAVE_HARDCLOCK 00119 00120 unsigned long mbedtls_timing_hardclock( void ) 00121 { 00122 unsigned long tbl, tbu0, tbu1; 00123 00124 do 00125 { 00126 asm volatile( "mftbu %0" : "=r" (tbu0) ); 00127 asm volatile( "mftb %0" : "=r" (tbl ) ); 00128 asm volatile( "mftbu %0" : "=r" (tbu1) ); 00129 } 00130 while( tbu0 != tbu1 ); 00131 00132 return( tbl ); 00133 } 00134 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 00135 __GNUC__ && ( __powerpc__ || __ppc__ ) */ 00136 00137 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 00138 defined(__GNUC__) && defined(__sparc64__) 00139 00140 #if defined(__OpenBSD__) 00141 #warning OpenBSD does not allow access to tick register using software version instead 00142 #else 00143 #define HAVE_HARDCLOCK 00144 00145 unsigned long mbedtls_timing_hardclock( void ) 00146 { 00147 unsigned long tick; 00148 asm volatile( "rdpr %%tick, %0;" : "=&r" (tick) ); 00149 return( tick ); 00150 } 00151 #endif /* __OpenBSD__ */ 00152 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 00153 __GNUC__ && __sparc64__ */ 00154 00155 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 00156 defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__) 00157 00158 #define HAVE_HARDCLOCK 00159 00160 unsigned long mbedtls_timing_hardclock( void ) 00161 { 00162 unsigned long tick; 00163 asm volatile( ".byte 0x83, 0x41, 0x00, 0x00" ); 00164 asm volatile( "mov %%g1, %0" : "=r" (tick) ); 00165 return( tick ); 00166 } 00167 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 00168 __GNUC__ && __sparc__ && !__sparc64__ */ 00169 00170 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 00171 defined(__GNUC__) && defined(__alpha__) 00172 00173 #define HAVE_HARDCLOCK 00174 00175 unsigned long mbedtls_timing_hardclock( void ) 00176 { 00177 unsigned long cc; 00178 asm volatile( "rpcc %0" : "=r" (cc) ); 00179 return( cc & 0xFFFFFFFF ); 00180 } 00181 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 00182 __GNUC__ && __alpha__ */ 00183 00184 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 00185 defined(__GNUC__) && defined(__ia64__) 00186 00187 #define HAVE_HARDCLOCK 00188 00189 unsigned long mbedtls_timing_hardclock( void ) 00190 { 00191 unsigned long itc; 00192 asm volatile( "mov %0 = ar.itc" : "=r" (itc) ); 00193 return( itc ); 00194 } 00195 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 00196 __GNUC__ && __ia64__ */ 00197 00198 #if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \ 00199 !defined(EFIX64) && !defined(EFI32) 00200 00201 #define HAVE_HARDCLOCK 00202 00203 unsigned long mbedtls_timing_hardclock( void ) 00204 { 00205 LARGE_INTEGER offset; 00206 00207 QueryPerformanceCounter( &offset ); 00208 00209 return( (unsigned long)( offset.QuadPart ) ); 00210 } 00211 #endif /* !HAVE_HARDCLOCK && _MSC_VER && !EFIX64 && !EFI32 */ 00212 00213 #if !defined(HAVE_HARDCLOCK) 00214 00215 #define HAVE_HARDCLOCK 00216 00217 static int hardclock_init = 0; 00218 static struct timeval tv_init; 00219 00220 unsigned long mbedtls_timing_hardclock( void ) 00221 { 00222 struct timeval tv_cur; 00223 00224 if( hardclock_init == 0 ) 00225 { 00226 gettimeofday( &tv_init, NULL ); 00227 hardclock_init = 1; 00228 } 00229 00230 gettimeofday( &tv_cur, NULL ); 00231 return( ( tv_cur.tv_sec - tv_init.tv_sec ) * 1000000 00232 + ( tv_cur.tv_usec - tv_init.tv_usec ) ); 00233 } 00234 #endif /* !HAVE_HARDCLOCK */ 00235 00236 volatile int mbedtls_timing_alarmed = 0; 00237 00238 #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 00239 00240 unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) 00241 { 00242 unsigned long delta; 00243 LARGE_INTEGER offset, hfreq; 00244 struct _hr_time *t = (struct _hr_time *) val; 00245 00246 QueryPerformanceCounter( &offset ); 00247 QueryPerformanceFrequency( &hfreq ); 00248 00249 delta = (unsigned long)( ( 1000 * 00250 ( offset.QuadPart - t->start.QuadPart ) ) / 00251 hfreq.QuadPart ); 00252 00253 if( reset ) 00254 QueryPerformanceCounter( &t->start ); 00255 00256 return( delta ); 00257 } 00258 00259 /* It's OK to use a global because alarm() is supposed to be global anyway */ 00260 static DWORD alarmMs; 00261 00262 static DWORD WINAPI TimerProc( LPVOID TimerContext ) 00263 { 00264 ((void) TimerContext); 00265 Sleep( alarmMs ); 00266 mbedtls_timing_alarmed = 1; 00267 return( TRUE ); 00268 } 00269 00270 void mbedtls_set_alarm( int seconds ) 00271 { 00272 DWORD ThreadId; 00273 00274 mbedtls_timing_alarmed = 0; 00275 alarmMs = seconds * 1000; 00276 CloseHandle( CreateThread( NULL, 0, TimerProc, NULL, 0, &ThreadId ) ); 00277 } 00278 00279 #else /* _WIN32 && !EFIX64 && !EFI32 */ 00280 00281 unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) 00282 { 00283 unsigned long delta; 00284 struct timeval offset; 00285 struct _hr_time *t = (struct _hr_time *) val; 00286 00287 gettimeofday( &offset, NULL ); 00288 00289 if( reset ) 00290 { 00291 t->start.tv_sec = offset.tv_sec; 00292 t->start.tv_usec = offset.tv_usec; 00293 return( 0 ); 00294 } 00295 00296 delta = ( offset.tv_sec - t->start.tv_sec ) * 1000 00297 + ( offset.tv_usec - t->start.tv_usec ) / 1000; 00298 00299 return( delta ); 00300 } 00301 00302 static void sighandler( int signum ) 00303 { 00304 mbedtls_timing_alarmed = 1; 00305 signal( signum, sighandler ); 00306 } 00307 00308 void mbedtls_set_alarm( int seconds ) 00309 { 00310 mbedtls_timing_alarmed = 0; 00311 signal( SIGALRM, sighandler ); 00312 alarm( seconds ); 00313 } 00314 00315 #endif /* _WIN32 && !EFIX64 && !EFI32 */ 00316 00317 /* 00318 * Set delays to watch 00319 */ 00320 void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms ) 00321 { 00322 mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data; 00323 00324 ctx->int_ms = int_ms; 00325 ctx->fin_ms = fin_ms; 00326 00327 if( fin_ms != 0 ) 00328 (void) mbedtls_timing_get_timer( &ctx->timer, 1 ); 00329 } 00330 00331 /* 00332 * Get number of delays expired 00333 */ 00334 int mbedtls_timing_get_delay( void *data ) 00335 { 00336 mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data; 00337 unsigned long elapsed_ms; 00338 00339 if( ctx->fin_ms == 0 ) 00340 return( -1 ); 00341 00342 elapsed_ms = mbedtls_timing_get_timer( &ctx->timer, 0 ); 00343 00344 if( elapsed_ms >= ctx->fin_ms ) 00345 return( 2 ); 00346 00347 if( elapsed_ms >= ctx->int_ms ) 00348 return( 1 ); 00349 00350 return( 0 ); 00351 } 00352 00353 #endif /* !MBEDTLS_TIMING_ALT */ 00354 00355 #if defined(MBEDTLS_SELF_TEST) 00356 00357 /* 00358 * Busy-waits for the given number of milliseconds. 00359 * Used for testing mbedtls_timing_hardclock. 00360 */ 00361 static void busy_msleep( unsigned long msec ) 00362 { 00363 struct mbedtls_timing_hr_time hires; 00364 unsigned long i = 0; /* for busy-waiting */ 00365 volatile unsigned long j; /* to prevent optimisation */ 00366 00367 (void) mbedtls_timing_get_timer( &hires, 1 ); 00368 00369 while( mbedtls_timing_get_timer( &hires, 0 ) < msec ) 00370 i++; 00371 00372 j = i; 00373 (void) j; 00374 } 00375 00376 #define FAIL do \ 00377 { \ 00378 if( verbose != 0 ) \ 00379 mbedtls_printf( "failed\n" ); \ 00380 \ 00381 return( 1 ); \ 00382 } while( 0 ) 00383 00384 /* 00385 * Checkup routine 00386 * 00387 * Warning: this is work in progress, some tests may not be reliable enough 00388 * yet! False positives may happen. 00389 */ 00390 int mbedtls_timing_self_test( int verbose ) 00391 { 00392 unsigned long cycles, ratio; 00393 unsigned long millisecs, secs; 00394 int hardfail; 00395 struct mbedtls_timing_hr_time hires; 00396 uint32_t a, b; 00397 mbedtls_timing_delay_context ctx; 00398 00399 if( verbose != 0 ) 00400 mbedtls_printf( " TIMING tests note: will take some time!\n" ); 00401 00402 00403 if( verbose != 0 ) 00404 mbedtls_printf( " TIMING test #1 (set_alarm / get_timer): " ); 00405 00406 for( secs = 1; secs <= 3; secs++ ) 00407 { 00408 (void) mbedtls_timing_get_timer( &hires, 1 ); 00409 00410 mbedtls_set_alarm( (int) secs ); 00411 while( !mbedtls_timing_alarmed ) 00412 ; 00413 00414 millisecs = mbedtls_timing_get_timer( &hires, 0 ); 00415 00416 /* For some reason on Windows it looks like alarm has an extra delay 00417 * (maybe related to creating a new thread). Allow some room here. */ 00418 if( millisecs < 800 * secs || millisecs > 1200 * secs + 300 ) 00419 { 00420 if( verbose != 0 ) 00421 mbedtls_printf( "failed\n" ); 00422 00423 return( 1 ); 00424 } 00425 } 00426 00427 if( verbose != 0 ) 00428 mbedtls_printf( "passed\n" ); 00429 00430 if( verbose != 0 ) 00431 mbedtls_printf( " TIMING test #2 (set/get_delay ): " ); 00432 00433 for( a = 200; a <= 400; a += 200 ) 00434 { 00435 for( b = 200; b <= 400; b += 200 ) 00436 { 00437 mbedtls_timing_set_delay( &ctx, a, a + b ); 00438 00439 busy_msleep( a - a / 8 ); 00440 if( mbedtls_timing_get_delay( &ctx ) != 0 ) 00441 FAIL; 00442 00443 busy_msleep( a / 4 ); 00444 if( mbedtls_timing_get_delay( &ctx ) != 1 ) 00445 FAIL; 00446 00447 busy_msleep( b - a / 8 - b / 8 ); 00448 if( mbedtls_timing_get_delay( &ctx ) != 1 ) 00449 FAIL; 00450 00451 busy_msleep( b / 4 ); 00452 if( mbedtls_timing_get_delay( &ctx ) != 2 ) 00453 FAIL; 00454 } 00455 } 00456 00457 mbedtls_timing_set_delay( &ctx, 0, 0 ); 00458 busy_msleep( 200 ); 00459 if( mbedtls_timing_get_delay( &ctx ) != -1 ) 00460 FAIL; 00461 00462 if( verbose != 0 ) 00463 mbedtls_printf( "passed\n" ); 00464 00465 if( verbose != 0 ) 00466 mbedtls_printf( " TIMING test #3 (hardclock / get_timer): " ); 00467 00468 /* 00469 * Allow one failure for possible counter wrapping. 00470 * On a 4Ghz 32-bit machine the cycle counter wraps about once per second; 00471 * since the whole test is about 10ms, it shouldn't happen twice in a row. 00472 */ 00473 hardfail = 0; 00474 00475 hard_test: 00476 if( hardfail > 1 ) 00477 { 00478 if( verbose != 0 ) 00479 mbedtls_printf( "failed (ignored)\n" ); 00480 00481 goto hard_test_done; 00482 } 00483 00484 /* Get a reference ratio cycles/ms */ 00485 millisecs = 1; 00486 cycles = mbedtls_timing_hardclock(); 00487 busy_msleep( millisecs ); 00488 cycles = mbedtls_timing_hardclock() - cycles; 00489 ratio = cycles / millisecs; 00490 00491 /* Check that the ratio is mostly constant */ 00492 for( millisecs = 2; millisecs <= 4; millisecs++ ) 00493 { 00494 cycles = mbedtls_timing_hardclock(); 00495 busy_msleep( millisecs ); 00496 cycles = mbedtls_timing_hardclock() - cycles; 00497 00498 /* Allow variation up to 20% */ 00499 if( cycles / millisecs < ratio - ratio / 5 || 00500 cycles / millisecs > ratio + ratio / 5 ) 00501 { 00502 hardfail++; 00503 goto hard_test; 00504 } 00505 } 00506 00507 if( verbose != 0 ) 00508 mbedtls_printf( "passed\n" ); 00509 00510 hard_test_done: 00511 00512 if( verbose != 0 ) 00513 mbedtls_printf( "\n" ); 00514 00515 return( 0 ); 00516 } 00517 00518 #endif /* MBEDTLS_SELF_TEST */ 00519 00520 #endif /* MBEDTLS_TIMING_C */
Generated on Tue Jul 12 2022 12:52:49 by
