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