blob: 9a6129bf800d7b96a3aa12b4e0f13df741fa3230 [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * Portable interface to the CPU cycle counter
3 *
Paul Bakkerf2561b32014-02-06 15:11:55 +01004 * Copyright (C) 2006-2014, Brainspark B.V.
Paul Bakkerb96f1542010-07-18 20:36:00 +00005 *
6 * This file is part of PolarSSL (http://www.polarssl.org)
Paul Bakker84f12b72010-07-18 10:13:04 +00007 * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
Paul Bakkerb96f1542010-07-18 20:36:00 +00008 *
Paul Bakker77b385e2009-07-28 17:23:11 +00009 * All rights reserved.
Paul Bakkere0ccd0a2009-01-04 16:27:10 +000010 *
Paul Bakker5121ce52009-01-03 21:22:43 +000011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25
Paul Bakker40e46942009-01-03 21:51:57 +000026#include "polarssl/config.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000027
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +010028#if defined(POLARSSL_SELF_TEST) && defined(POLARSSL_PLATFORM_C)
29#include "polarssl/platform.h"
30#else
31#include <stdio.h>
32#define polarssl_printf printf
33#endif
34
Paul Bakkerf2561b32014-02-06 15:11:55 +010035#if defined(POLARSSL_TIMING_C) && !defined(POLARSSL_TIMING_ALT)
Paul Bakker5121ce52009-01-03 21:22:43 +000036
Paul Bakker40e46942009-01-03 21:51:57 +000037#include "polarssl/timing.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000038
Paul Bakkerfa6a6202013-10-28 18:48:30 +010039#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
Paul Bakker5121ce52009-01-03 21:22:43 +000040
41#include <windows.h>
42#include <winbase.h>
43
44struct _hr_time
45{
46 LARGE_INTEGER start;
47};
48
49#else
50
51#include <unistd.h>
52#include <sys/types.h>
53#include <sys/time.h>
54#include <signal.h>
55#include <time.h>
56
57struct _hr_time
58{
59 struct timeval start;
60};
61
62#endif
63
Paul Bakkerbb0139c2012-10-31 09:53:08 +000064#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +010065 (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
Paul Bakker5121ce52009-01-03 21:22:43 +000066
Paul Bakkerbb0139c2012-10-31 09:53:08 +000067#define POLARSSL_HAVE_HARDCLOCK
68
Paul Bakker5121ce52009-01-03 21:22:43 +000069unsigned long hardclock( void )
70{
71 unsigned long tsc;
72 __asm rdtsc
73 __asm mov [tsc], eax
74 return( tsc );
75}
Paul Bakkerbb0139c2012-10-31 09:53:08 +000076#endif
Paul Bakker5121ce52009-01-03 21:22:43 +000077
Paul Bakkerbb0139c2012-10-31 09:53:08 +000078#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \
79 defined(__GNUC__) && defined(__i386__)
80
81#define POLARSSL_HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +000082
83unsigned long hardclock( void )
84{
Paul Bakkerca410102011-10-19 14:27:36 +000085 unsigned long lo, hi;
Manuel Pégourié-Gonnardd6aebe12014-03-27 21:15:40 +010086 asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) );
Paul Bakkerca410102011-10-19 14:27:36 +000087 return( lo );
Paul Bakker5121ce52009-01-03 21:22:43 +000088}
Paul Bakkerbb0139c2012-10-31 09:53:08 +000089#endif
Paul Bakker5121ce52009-01-03 21:22:43 +000090
Paul Bakkerbb0139c2012-10-31 09:53:08 +000091#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \
92 defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__))
93
94#define POLARSSL_HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +000095
96unsigned long hardclock( void )
97{
98 unsigned long lo, hi;
Manuel Pégourié-Gonnardd6aebe12014-03-27 21:15:40 +010099 asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000100 return( lo | (hi << 32) );
101}
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000102#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000103
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000104#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \
105 defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
106
107#define POLARSSL_HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000108
109unsigned long hardclock( void )
110{
111 unsigned long tbl, tbu0, tbu1;
112
113 do
114 {
Manuel Pégourié-Gonnardd6aebe12014-03-27 21:15:40 +0100115 asm volatile( "mftbu %0" : "=r" (tbu0) );
116 asm volatile( "mftb %0" : "=r" (tbl ) );
117 asm volatile( "mftbu %0" : "=r" (tbu1) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000118 }
119 while( tbu0 != tbu1 );
120
121 return( tbl );
122}
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000123#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000124
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000125#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \
126 defined(__GNUC__) && defined(__sparc64__)
127
128#if defined(__OpenBSD__)
129#warning OpenBSD does not allow access to tick register using software version instead
Paul Bakker5121ce52009-01-03 21:22:43 +0000130#else
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000131#define POLARSSL_HAVE_HARDCLOCK
132
133unsigned long hardclock( void )
134{
135 unsigned long tick;
Manuel Pégourié-Gonnardd6aebe12014-03-27 21:15:40 +0100136 asm volatile( "rdpr %%tick, %0;" : "=&r" (tick) );
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000137 return( tick );
138}
139#endif
140#endif
141
142#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \
143 defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__)
144
145#define POLARSSL_HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000146
147unsigned long hardclock( void )
148{
149 unsigned long tick;
Manuel Pégourié-Gonnardd6aebe12014-03-27 21:15:40 +0100150 asm volatile( ".byte 0x83, 0x41, 0x00, 0x00" );
151 asm volatile( "mov %%g1, %0" : "=r" (tick) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000152 return( tick );
153}
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000154#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000155
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000156#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \
157 defined(__GNUC__) && defined(__alpha__)
158
159#define POLARSSL_HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000160
161unsigned long hardclock( void )
162{
163 unsigned long cc;
Manuel Pégourié-Gonnardd6aebe12014-03-27 21:15:40 +0100164 asm volatile( "rpcc %0" : "=r" (cc) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000165 return( cc & 0xFFFFFFFF );
166}
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000167#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000168
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000169#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \
170 defined(__GNUC__) && defined(__ia64__)
171
172#define POLARSSL_HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000173
174unsigned long hardclock( void )
175{
176 unsigned long itc;
Manuel Pégourié-Gonnardd6aebe12014-03-27 21:15:40 +0100177 asm volatile( "mov %0 = ar.itc" : "=r" (itc) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000178 return( itc );
179}
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000180#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000181
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100182#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(_MSC_VER) && \
183 !defined(EFIX64) && !defined(EFI32)
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000184
185#define POLARSSL_HAVE_HARDCLOCK
Paul Bakker2eee9022011-04-24 15:28:55 +0000186
187unsigned long hardclock( void )
188{
189 LARGE_INTEGER offset;
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100190
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100191 QueryPerformanceCounter( &offset );
Paul Bakker2eee9022011-04-24 15:28:55 +0000192
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100193 return (unsigned long)( offset.QuadPart );
Paul Bakker2eee9022011-04-24 15:28:55 +0000194}
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000195#endif
Paul Bakker2eee9022011-04-24 15:28:55 +0000196
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000197#if !defined(POLARSSL_HAVE_HARDCLOCK)
198
199#define POLARSSL_HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000200
201static int hardclock_init = 0;
202static struct timeval tv_init;
203
204unsigned long hardclock( void )
205{
206 struct timeval tv_cur;
207
208 if( hardclock_init == 0 )
209 {
210 gettimeofday( &tv_init, NULL );
211 hardclock_init = 1;
212 }
213
214 gettimeofday( &tv_cur, NULL );
215 return( ( tv_cur.tv_sec - tv_init.tv_sec ) * 1000000
216 + ( tv_cur.tv_usec - tv_init.tv_usec ) );
217}
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000218#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000219
Paul Bakker2eee9022011-04-24 15:28:55 +0000220volatile int alarmed = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000221
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100222#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
Paul Bakker5121ce52009-01-03 21:22:43 +0000223
224unsigned long get_timer( struct hr_time *val, int reset )
225{
226 unsigned long delta;
227 LARGE_INTEGER offset, hfreq;
228 struct _hr_time *t = (struct _hr_time *) val;
229
230 QueryPerformanceCounter( &offset );
231 QueryPerformanceFrequency( &hfreq );
232
233 delta = (unsigned long)( ( 1000 *
234 ( offset.QuadPart - t->start.QuadPart ) ) /
235 hfreq.QuadPart );
236
237 if( reset )
238 QueryPerformanceCounter( &t->start );
239
240 return( delta );
241}
242
243DWORD WINAPI TimerProc( LPVOID uElapse )
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100244{
Paul Bakker5121ce52009-01-03 21:22:43 +0000245 Sleep( (DWORD) uElapse );
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100246 alarmed = 1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000247 return( TRUE );
248}
249
250void set_alarm( int seconds )
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100251{
Paul Bakker5121ce52009-01-03 21:22:43 +0000252 DWORD ThreadId;
253
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100254 alarmed = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000255 CloseHandle( CreateThread( NULL, 0, TimerProc,
256 (LPVOID) ( seconds * 1000 ), 0, &ThreadId ) );
257}
258
259void m_sleep( int milliseconds )
260{
261 Sleep( milliseconds );
262}
263
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100264#else /* _WIN32 && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +0000265
266unsigned long get_timer( struct hr_time *val, int reset )
267{
268 unsigned long delta;
269 struct timeval offset;
270 struct _hr_time *t = (struct _hr_time *) val;
271
272 gettimeofday( &offset, NULL );
273
274 delta = ( offset.tv_sec - t->start.tv_sec ) * 1000
275 + ( offset.tv_usec - t->start.tv_usec ) / 1000;
276
277 if( reset )
278 {
279 t->start.tv_sec = offset.tv_sec;
280 t->start.tv_usec = offset.tv_usec;
281 }
282
283 return( delta );
284}
285
Paul Bakker49d75672012-09-26 15:22:07 +0000286#if defined(INTEGRITY)
287void m_sleep( int milliseconds )
288{
289 usleep( milliseconds * 1000 );
290}
291
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100292#else /* INTEGRITY */
Paul Bakker49d75672012-09-26 15:22:07 +0000293
Paul Bakker5121ce52009-01-03 21:22:43 +0000294static void sighandler( int signum )
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100295{
Paul Bakker5121ce52009-01-03 21:22:43 +0000296 alarmed = 1;
297 signal( signum, sighandler );
298}
299
300void set_alarm( int seconds )
301{
302 alarmed = 0;
303 signal( SIGALRM, sighandler );
304 alarm( seconds );
305}
306
307void m_sleep( int milliseconds )
308{
309 struct timeval tv;
310
311 tv.tv_sec = milliseconds / 1000;
Manuel Pégourié-Gonnarddfbf9c72014-02-20 22:16:43 +0100312 tv.tv_usec = ( milliseconds % 1000 ) * 1000;
Paul Bakker5121ce52009-01-03 21:22:43 +0000313
314 select( 0, NULL, NULL, NULL, &tv );
315}
Paul Bakker49d75672012-09-26 15:22:07 +0000316#endif /* INTEGRITY */
Paul Bakker5121ce52009-01-03 21:22:43 +0000317
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100318#endif /* _WIN32 && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +0000319
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100320#if defined(POLARSSL_SELF_TEST)
321
322/*
323 * Checkup routine
324 */
325int timing_self_test( int verbose )
326{
327 unsigned long cycles, ratio;
328 unsigned long millisecs, secs;
329 int hardfail;
330 struct hr_time hires;
331
332 if( verbose != 0)
333 polarssl_printf( " TIMING tests warning: will take some time!\n" );
334
335 if( verbose != 0 )
336 polarssl_printf( " TIMING test #1 (m_sleep / get_timer): " );
337
338 for( secs = 1; secs <= 3; secs++ )
339 {
340 (void) get_timer( &hires, 1 );
341
342 m_sleep( 1000 * secs );
343
344 millisecs = get_timer( &hires, 0 );
345
346 if( millisecs < 900 * secs || millisecs > 1100 * secs )
347 {
348 if( verbose != 0 )
349 polarssl_printf( "failed\n" );
350
351 return( 1 );
352 }
353 }
354
355 if( verbose != 0 )
356 polarssl_printf( "passed\n" );
357
358 if( verbose != 0 )
359 polarssl_printf( " TIMING test #2 (set_alarm / get_timer): " );
360
361 for( secs = 1; secs <= 3; secs++ )
362 {
363 (void) get_timer( &hires, 1 );
364
365 set_alarm( secs );
366 while( !alarmed )
367 ;
368
369 millisecs = get_timer( &hires, 0 );
370
371 if( millisecs < 900 * secs || millisecs > 1100 * secs )
372 {
373 if( verbose != 0 )
374 polarssl_printf( "failed\n" );
375
376 return( 1 );
377 }
378 }
379
380 if( verbose != 0 )
381 polarssl_printf( "passed\n" );
382
383 if( verbose != 0 )
384 polarssl_printf( " TIMING test #3 (hardclock / m_sleep ): " );
385
386 /*
387 * Allow one failure for possible counter wrapping.
388 * On a 4Ghz 32-bit machine the cycle counter wraps about once per second;
389 * since the whole test is about 10ms, it shouldn't happen twice in a row.
390 */
391 hardfail = 0;
392
393hard_test:
394 if( hardfail > 1 )
395 {
396 if( verbose != 0 )
397 polarssl_printf( "failed\n" );
398
399 return( 1 );
400 }
401
402 /* Get a reference ratio cycles/ms */
403 cycles = hardclock();
404 m_sleep( 1 );
405 cycles = hardclock() - cycles;
406 ratio = cycles / 1;
407
408 for( millisecs = 2; millisecs <= 4; millisecs++ )
409 {
410 cycles = hardclock();
411 m_sleep( millisecs );
412 cycles = hardclock() - cycles;
413
414 /* Allow variation up to 20% */
415 if( cycles / millisecs < ratio - ratio / 5 ||
416 cycles / millisecs > ratio + ratio / 5 )
417 {
418 hardfail++;
419 goto hard_test;
420 }
421 }
422
423 if( verbose != 0 )
424 polarssl_printf( "passed\n" );
425
426 if( verbose != 0 )
427 polarssl_printf( "\n" );
428
429 return( 0 );
430}
431
432#endif /* POLARSSL_SELF_TEST */
433
434#endif /* POLARSSL_TIMING_C && !POLARSSL_TIMING_ALT */