This Trac instance is not used for development anymore!

We migrated our development workflow to git and Gitea.
To test the future redirection, replace trac by ariadne in the page URL.

source: ps/trunk/build/premake/premake5/contrib/mbedtls/library/timing.c

Last change on this file was 20366, checked in by Itms, 7 years ago

Alpha 12 version of Premake 5, including prebuilt binary for Windows.
Directly taken from https://premake.github.io/.

Refs #3729.

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