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: mbed Socket lwip-eth lwip-sys lwip
Fork of 6_songs-from-the-cloud 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:47:51 by
1.7.2
