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.
Dependencies: nRF51_Vdd TextLCD BME280
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 #if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ 00042 !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \ 00043 !defined(__HAIKU__) 00044 #error "This module only works on Unix and Windows, see MBEDTLS_TIMING_C in config.h" 00045 #endif 00046 00047 #ifndef asm 00048 #define asm __asm 00049 #endif 00050 00051 #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 00052 00053 #include <windows.h> 00054 #include <winbase.h> 00055 00056 struct _hr_time 00057 { 00058 LARGE_INTEGER start; 00059 }; 00060 00061 #else 00062 00063 #include <unistd.h> 00064 #include <sys/types.h> 00065 #include <sys/time.h> 00066 #include <signal.h> 00067 #include <time.h> 00068 00069 struct _hr_time 00070 { 00071 struct timeval start; 00072 }; 00073 00074 #endif /* _WIN32 && !EFIX64 && !EFI32 */ 00075 00076 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 00077 ( defined(_MSC_VER) && defined(_M_IX86) ) || defined(__WATCOMC__) 00078 00079 #define HAVE_HARDCLOCK 00080 00081 unsigned long mbedtls_timing_hardclock( void ) 00082 { 00083 unsigned long tsc; 00084 __asm rdtsc 00085 __asm mov [tsc], eax 00086 return( tsc ); 00087 } 00088 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 00089 ( _MSC_VER && _M_IX86 ) || __WATCOMC__ */ 00090 00091 /* some versions of mingw-64 have 32-bit longs even on x84_64 */ 00092 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 00093 defined(__GNUC__) && ( defined(__i386__) || ( \ 00094 ( defined(__amd64__) || defined( __x86_64__) ) && __SIZEOF_LONG__ == 4 ) ) 00095 00096 #define HAVE_HARDCLOCK 00097 00098 unsigned long mbedtls_timing_hardclock( void ) 00099 { 00100 unsigned long lo, hi; 00101 asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); 00102 return( lo ); 00103 } 00104 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 00105 __GNUC__ && __i386__ */ 00106 00107 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 00108 defined(__GNUC__) && ( defined(__amd64__) || defined(__x86_64__) ) 00109 00110 #define HAVE_HARDCLOCK 00111 00112 unsigned long mbedtls_timing_hardclock( void ) 00113 { 00114 unsigned long lo, hi; 00115 asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); 00116 return( lo | ( hi << 32 ) ); 00117 } 00118 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 00119 __GNUC__ && ( __amd64__ || __x86_64__ ) */ 00120 00121 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 00122 defined(__GNUC__) && ( defined(__powerpc__) || defined(__ppc__) ) 00123 00124 #define HAVE_HARDCLOCK 00125 00126 unsigned long mbedtls_timing_hardclock( void ) 00127 { 00128 unsigned long tbl, tbu0, tbu1; 00129 00130 do 00131 { 00132 asm volatile( "mftbu %0" : "=r" (tbu0) ); 00133 asm volatile( "mftb %0" : "=r" (tbl ) ); 00134 asm volatile( "mftbu %0" : "=r" (tbu1) ); 00135 } 00136 while( tbu0 != tbu1 ); 00137 00138 return( tbl ); 00139 } 00140 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 00141 __GNUC__ && ( __powerpc__ || __ppc__ ) */ 00142 00143 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 00144 defined(__GNUC__) && defined(__sparc64__) 00145 00146 #if defined(__OpenBSD__) 00147 #warning OpenBSD does not allow access to tick register using software version instead 00148 #else 00149 #define HAVE_HARDCLOCK 00150 00151 unsigned long mbedtls_timing_hardclock( void ) 00152 { 00153 unsigned long tick; 00154 asm volatile( "rdpr %%tick, %0;" : "=&r" (tick) ); 00155 return( tick ); 00156 } 00157 #endif /* __OpenBSD__ */ 00158 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 00159 __GNUC__ && __sparc64__ */ 00160 00161 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 00162 defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__) 00163 00164 #define HAVE_HARDCLOCK 00165 00166 unsigned long mbedtls_timing_hardclock( void ) 00167 { 00168 unsigned long tick; 00169 asm volatile( ".byte 0x83, 0x41, 0x00, 0x00" ); 00170 asm volatile( "mov %%g1, %0" : "=r" (tick) ); 00171 return( tick ); 00172 } 00173 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 00174 __GNUC__ && __sparc__ && !__sparc64__ */ 00175 00176 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 00177 defined(__GNUC__) && defined(__alpha__) 00178 00179 #define HAVE_HARDCLOCK 00180 00181 unsigned long mbedtls_timing_hardclock( void ) 00182 { 00183 unsigned long cc; 00184 asm volatile( "rpcc %0" : "=r" (cc) ); 00185 return( cc & 0xFFFFFFFF ); 00186 } 00187 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 00188 __GNUC__ && __alpha__ */ 00189 00190 #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 00191 defined(__GNUC__) && defined(__ia64__) 00192 00193 #define HAVE_HARDCLOCK 00194 00195 unsigned long mbedtls_timing_hardclock( void ) 00196 { 00197 unsigned long itc; 00198 asm volatile( "mov %0 = ar.itc" : "=r" (itc) ); 00199 return( itc ); 00200 } 00201 #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 00202 __GNUC__ && __ia64__ */ 00203 00204 #if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \ 00205 !defined(EFIX64) && !defined(EFI32) 00206 00207 #define HAVE_HARDCLOCK 00208 00209 unsigned long mbedtls_timing_hardclock( void ) 00210 { 00211 LARGE_INTEGER offset; 00212 00213 QueryPerformanceCounter( &offset ); 00214 00215 return( (unsigned long)( offset.QuadPart ) ); 00216 } 00217 #endif /* !HAVE_HARDCLOCK && _MSC_VER && !EFIX64 && !EFI32 */ 00218 00219 #if !defined(HAVE_HARDCLOCK) 00220 00221 #define HAVE_HARDCLOCK 00222 00223 static int hardclock_init = 0; 00224 static struct timeval tv_init; 00225 00226 unsigned long mbedtls_timing_hardclock( void ) 00227 { 00228 struct timeval tv_cur; 00229 00230 if( hardclock_init == 0 ) 00231 { 00232 gettimeofday( &tv_init, NULL ); 00233 hardclock_init = 1; 00234 } 00235 00236 gettimeofday( &tv_cur, NULL ); 00237 return( ( tv_cur.tv_sec - tv_init.tv_sec ) * 1000000 00238 + ( tv_cur.tv_usec - tv_init.tv_usec ) ); 00239 } 00240 #endif /* !HAVE_HARDCLOCK */ 00241 00242 volatile int mbedtls_timing_alarmed = 0; 00243 00244 #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 00245 00246 unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) 00247 { 00248 struct _hr_time *t = (struct _hr_time *) val; 00249 00250 if( reset ) 00251 { 00252 QueryPerformanceCounter( &t->start ); 00253 return( 0 ); 00254 } 00255 else 00256 { 00257 unsigned long delta; 00258 LARGE_INTEGER now, hfreq; 00259 QueryPerformanceCounter( &now ); 00260 QueryPerformanceFrequency( &hfreq ); 00261 delta = (unsigned long)( ( now.QuadPart - t->start.QuadPart ) * 1000ul 00262 / hfreq.QuadPart ); 00263 return( delta ); 00264 } 00265 } 00266 00267 /* It's OK to use a global because alarm() is supposed to be global anyway */ 00268 static DWORD alarmMs; 00269 00270 static DWORD WINAPI TimerProc( LPVOID TimerContext ) 00271 { 00272 ((void) TimerContext); 00273 Sleep( alarmMs ); 00274 mbedtls_timing_alarmed = 1; 00275 return( TRUE ); 00276 } 00277 00278 void mbedtls_set_alarm( int seconds ) 00279 { 00280 DWORD ThreadId; 00281 00282 if( seconds == 0 ) 00283 { 00284 /* No need to create a thread for this simple case. 00285 * Also, this shorcut is more reliable at least on MinGW32 */ 00286 mbedtls_timing_alarmed = 1; 00287 return; 00288 } 00289 00290 mbedtls_timing_alarmed = 0; 00291 alarmMs = seconds * 1000; 00292 CloseHandle( CreateThread( NULL, 0, TimerProc, NULL, 0, &ThreadId ) ); 00293 } 00294 00295 #else /* _WIN32 && !EFIX64 && !EFI32 */ 00296 00297 unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) 00298 { 00299 struct _hr_time *t = (struct _hr_time *) val; 00300 00301 if( reset ) 00302 { 00303 gettimeofday( &t->start, NULL ); 00304 return( 0 ); 00305 } 00306 else 00307 { 00308 unsigned long delta; 00309 struct timeval now; 00310 gettimeofday( &now, NULL ); 00311 delta = ( now.tv_sec - t->start.tv_sec ) * 1000ul 00312 + ( now.tv_usec - t->start.tv_usec ) / 1000; 00313 return( delta ); 00314 } 00315 } 00316 00317 static void sighandler( int signum ) 00318 { 00319 mbedtls_timing_alarmed = 1; 00320 signal( signum, sighandler ); 00321 } 00322 00323 void mbedtls_set_alarm( int seconds ) 00324 { 00325 mbedtls_timing_alarmed = 0; 00326 signal( SIGALRM, sighandler ); 00327 alarm( seconds ); 00328 if( seconds == 0 ) 00329 { 00330 /* alarm(0) cancelled any previous pending alarm, but the 00331 handler won't fire, so raise the flag straight away. */ 00332 mbedtls_timing_alarmed = 1; 00333 } 00334 } 00335 00336 #endif /* _WIN32 && !EFIX64 && !EFI32 */ 00337 00338 /* 00339 * Set delays to watch 00340 */ 00341 void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms ) 00342 { 00343 mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data; 00344 00345 ctx->int_ms = int_ms; 00346 ctx->fin_ms = fin_ms; 00347 00348 if( fin_ms != 0 ) 00349 (void) mbedtls_timing_get_timer( &ctx->timer, 1 ); 00350 } 00351 00352 /* 00353 * Get number of delays expired 00354 */ 00355 int mbedtls_timing_get_delay( void *data ) 00356 { 00357 mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data; 00358 unsigned long elapsed_ms; 00359 00360 if( ctx->fin_ms == 0 ) 00361 return( -1 ); 00362 00363 elapsed_ms = mbedtls_timing_get_timer( &ctx->timer, 0 ); 00364 00365 if( elapsed_ms >= ctx->fin_ms ) 00366 return( 2 ); 00367 00368 if( elapsed_ms >= ctx->int_ms ) 00369 return( 1 ); 00370 00371 return( 0 ); 00372 } 00373 00374 #endif /* !MBEDTLS_TIMING_ALT */ 00375 00376 #if defined(MBEDTLS_SELF_TEST) 00377 00378 /* 00379 * Busy-waits for the given number of milliseconds. 00380 * Used for testing mbedtls_timing_hardclock. 00381 */ 00382 static void busy_msleep( unsigned long msec ) 00383 { 00384 struct mbedtls_timing_hr_time hires; 00385 unsigned long i = 0; /* for busy-waiting */ 00386 volatile unsigned long j; /* to prevent optimisation */ 00387 00388 (void) mbedtls_timing_get_timer( &hires, 1 ); 00389 00390 while( mbedtls_timing_get_timer( &hires, 0 ) < msec ) 00391 i++; 00392 00393 j = i; 00394 (void) j; 00395 } 00396 00397 #define FAIL do \ 00398 { \ 00399 if( verbose != 0 ) \ 00400 { \ 00401 mbedtls_printf( "failed at line %d\n", __LINE__ ); \ 00402 mbedtls_printf( " cycles=%lu ratio=%lu millisecs=%lu secs=%lu hardfail=%d a=%lu b=%lu\n", \ 00403 cycles, ratio, millisecs, secs, hardfail, \ 00404 (unsigned long) a, (unsigned long) b ); \ 00405 mbedtls_printf( " elapsed(hires)=%lu elapsed(ctx)=%lu status(ctx)=%d\n", \ 00406 mbedtls_timing_get_timer( &hires, 0 ), \ 00407 mbedtls_timing_get_timer( &ctx.timer, 0 ), \ 00408 mbedtls_timing_get_delay( &ctx ) ); \ 00409 } \ 00410 return( 1 ); \ 00411 } while( 0 ) 00412 00413 /* 00414 * Checkup routine 00415 * 00416 * Warning: this is work in progress, some tests may not be reliable enough 00417 * yet! False positives may happen. 00418 */ 00419 int mbedtls_timing_self_test( int verbose ) 00420 { 00421 unsigned long cycles = 0, ratio = 0; 00422 unsigned long millisecs = 0, secs = 0; 00423 int hardfail = 0; 00424 struct mbedtls_timing_hr_time hires; 00425 uint32_t a = 0, b = 0; 00426 mbedtls_timing_delay_context ctx; 00427 00428 if( verbose != 0 ) 00429 mbedtls_printf( " TIMING tests note: will take some time!\n" ); 00430 00431 if( verbose != 0 ) 00432 mbedtls_printf( " TIMING test #1 (set_alarm / get_timer): " ); 00433 00434 { 00435 secs = 1; 00436 00437 (void) mbedtls_timing_get_timer( &hires, 1 ); 00438 00439 mbedtls_set_alarm( (int) secs ); 00440 while( !mbedtls_timing_alarmed ) 00441 ; 00442 00443 millisecs = mbedtls_timing_get_timer( &hires, 0 ); 00444 00445 /* For some reason on Windows it looks like alarm has an extra delay 00446 * (maybe related to creating a new thread). Allow some room here. */ 00447 if( millisecs < 800 * secs || millisecs > 1200 * secs + 300 ) 00448 FAIL; 00449 } 00450 00451 if( verbose != 0 ) 00452 mbedtls_printf( "passed\n" ); 00453 00454 if( verbose != 0 ) 00455 mbedtls_printf( " TIMING test #2 (set/get_delay ): " ); 00456 00457 { 00458 a = 800; 00459 b = 400; 00460 mbedtls_timing_set_delay( &ctx, a, a + b ); /* T = 0 */ 00461 00462 busy_msleep( a - a / 4 ); /* T = a - a/4 */ 00463 if( mbedtls_timing_get_delay( &ctx ) != 0 ) 00464 FAIL; 00465 00466 busy_msleep( a / 4 + b / 4 ); /* T = a + b/4 */ 00467 if( mbedtls_timing_get_delay( &ctx ) != 1 ) 00468 FAIL; 00469 00470 busy_msleep( b ); /* T = a + b + b/4 */ 00471 if( mbedtls_timing_get_delay( &ctx ) != 2 ) 00472 FAIL; 00473 } 00474 00475 mbedtls_timing_set_delay( &ctx, 0, 0 ); 00476 busy_msleep( 200 ); 00477 if( mbedtls_timing_get_delay( &ctx ) != -1 ) 00478 FAIL; 00479 00480 if( verbose != 0 ) 00481 mbedtls_printf( "passed\n" ); 00482 00483 if( verbose != 0 ) 00484 mbedtls_printf( " TIMING test #3 (hardclock / get_timer): " ); 00485 00486 /* 00487 * Allow one failure for possible counter wrapping. 00488 * On a 4Ghz 32-bit machine the cycle counter wraps about once per second; 00489 * since the whole test is about 10ms, it shouldn't happen twice in a row. 00490 */ 00491 00492 hard_test: 00493 if( hardfail > 1 ) 00494 { 00495 if( verbose != 0 ) 00496 mbedtls_printf( "failed (ignored)\n" ); 00497 00498 goto hard_test_done; 00499 } 00500 00501 /* Get a reference ratio cycles/ms */ 00502 millisecs = 1; 00503 cycles = mbedtls_timing_hardclock(); 00504 busy_msleep( millisecs ); 00505 cycles = mbedtls_timing_hardclock() - cycles; 00506 ratio = cycles / millisecs; 00507 00508 /* Check that the ratio is mostly constant */ 00509 for( millisecs = 2; millisecs <= 4; millisecs++ ) 00510 { 00511 cycles = mbedtls_timing_hardclock(); 00512 busy_msleep( millisecs ); 00513 cycles = mbedtls_timing_hardclock() - cycles; 00514 00515 /* Allow variation up to 20% */ 00516 if( cycles / millisecs < ratio - ratio / 5 || 00517 cycles / millisecs > ratio + ratio / 5 ) 00518 { 00519 hardfail++; 00520 goto hard_test; 00521 } 00522 } 00523 00524 if( verbose != 0 ) 00525 mbedtls_printf( "passed\n" ); 00526 00527 hard_test_done: 00528 00529 if( verbose != 0 ) 00530 mbedtls_printf( "\n" ); 00531 00532 return( 0 ); 00533 } 00534 00535 #endif /* MBEDTLS_SELF_TEST */ 00536 00537 #endif /* MBEDTLS_TIMING_C */
Generated on Tue Jul 12 2022 15:16:02 by
