1/*
2 *  Portable interface to the CPU cycle counter
3 *
4 *  Based on XySSL: Copyright (C) 2006-2008  Christophe Devine
5 *
6 *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
7 *
8 *  All rights reserved.
9 *
10 *  Redistribution and use in source and binary forms, with or without
11 *  modification, are permitted provided that the following conditions
12 *  are met:
13 *
14 *    * Redistributions of source code must retain the above copyright
15 *      notice, this list of conditions and the following disclaimer.
16 *    * Redistributions in binary form must reproduce the above copyright
17 *      notice, this list of conditions and the following disclaimer in the
18 *      documentation and/or other materials provided with the distribution.
19 *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
20 *      may be used to endorse or promote products derived from this software
21 *      without specific prior written permission.
22 *
23 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 *  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36#include "polarssl/config.h"
37
38#if defined(POLARSSL_TIMING_C)
39
40#include "polarssl/timing.h"
41
42#if defined(WIN32)
43
44#include <windows.h>
45#include <winbase.h>
46
47struct _hr_time
48{
49    LARGE_INTEGER start;
50};
51
52#else
53
54#include <unistd.h>
55#include <sys/types.h>
56#include <sys/time.h>
57#include <signal.h>
58#include <time.h>
59
60struct _hr_time
61{
62    struct timeval start;
63};
64
65#endif
66
67#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
68
69unsigned long hardclock( void )
70{
71    unsigned long tsc;
72    __asm   rdtsc
73    __asm   mov  [tsc], eax
74    return( tsc );
75}
76
77#else
78#if defined(__GNUC__) && defined(__i386__)
79
80unsigned long hardclock( void )
81{
82    unsigned long tsc;
83    asm( "rdtsc" : "=a" (tsc) );
84    return( tsc );
85}
86
87#else
88#if defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__))
89
90unsigned long hardclock( void )
91{
92    unsigned long lo, hi;
93    asm( "rdtsc" : "=a" (lo), "=d" (hi) );
94    return( lo | (hi << 32) );
95}
96
97#else
98#if defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
99
100unsigned long hardclock( void )
101{
102    unsigned long tbl, tbu0, tbu1;
103
104    do
105    {
106        asm( "mftbu %0" : "=r" (tbu0) );
107        asm( "mftb  %0" : "=r" (tbl ) );
108        asm( "mftbu %0" : "=r" (tbu1) );
109    }
110    while( tbu0 != tbu1 );
111
112    return( tbl );
113}
114
115#else
116#if defined(__GNUC__) && defined(__sparc__)
117
118unsigned long hardclock( void )
119{
120    unsigned long tick;
121    asm( ".byte 0x83, 0x41, 0x00, 0x00" );
122    asm( "mov   %%g1, %0" : "=r" (tick) );
123    return( tick );
124}
125
126#else
127#if defined(__GNUC__) && defined(__alpha__)
128
129unsigned long hardclock( void )
130{
131    unsigned long cc;
132    asm( "rpcc %0" : "=r" (cc) );
133    return( cc & 0xFFFFFFFF );
134}
135
136#else
137#if defined(__GNUC__) && defined(__ia64__)
138
139unsigned long hardclock( void )
140{
141    unsigned long itc;
142    asm( "mov %0 = ar.itc" : "=r" (itc) );
143    return( itc );
144}
145
146#else
147
148static int hardclock_init = 0;
149static struct timeval tv_init;
150
151unsigned long hardclock( void )
152{
153    struct timeval tv_cur;
154
155    if( hardclock_init == 0 )
156    {
157        gettimeofday( &tv_init, NULL );
158        hardclock_init = 1;
159    }
160
161    gettimeofday( &tv_cur, NULL );
162    return( ( tv_cur.tv_sec  - tv_init.tv_sec  ) * 1000000
163          + ( tv_cur.tv_usec - tv_init.tv_usec ) );
164}
165
166#endif /* generic */
167#endif /* IA-64   */
168#endif /* Alpha   */
169#endif /* SPARC8  */
170#endif /* PowerPC */
171#endif /* AMD64   */
172#endif /* i586+   */
173
174int alarmed = 0;
175
176#if defined(WIN32)
177
178unsigned long get_timer( struct hr_time *val, int reset )
179{
180    unsigned long delta;
181    LARGE_INTEGER offset, hfreq;
182    struct _hr_time *t = (struct _hr_time *) val;
183
184    QueryPerformanceCounter(  &offset );
185    QueryPerformanceFrequency( &hfreq );
186
187    delta = (unsigned long)( ( 1000 *
188        ( offset.QuadPart - t->start.QuadPart ) ) /
189           hfreq.QuadPart );
190
191    if( reset )
192        QueryPerformanceCounter( &t->start );
193
194    return( delta );
195}
196
197DWORD WINAPI TimerProc( LPVOID uElapse )
198{
199    Sleep( (DWORD) uElapse );
200    alarmed = 1;
201    return( TRUE );
202}
203
204void set_alarm( int seconds )
205{
206    DWORD ThreadId;
207
208    alarmed = 0;
209    CloseHandle( CreateThread( NULL, 0, TimerProc,
210        (LPVOID) ( seconds * 1000 ), 0, &ThreadId ) );
211}
212
213void m_sleep( int milliseconds )
214{
215    Sleep( milliseconds );
216}
217
218#else
219
220unsigned long get_timer( struct hr_time *val, int reset )
221{
222    unsigned long delta;
223    struct timeval offset;
224    struct _hr_time *t = (struct _hr_time *) val;
225
226    gettimeofday( &offset, NULL );
227
228    delta = ( offset.tv_sec  - t->start.tv_sec  ) * 1000
229          + ( offset.tv_usec - t->start.tv_usec ) / 1000;
230
231    if( reset )
232    {
233        t->start.tv_sec  = offset.tv_sec;
234        t->start.tv_usec = offset.tv_usec;
235    }
236
237    return( delta );
238}
239
240static void sighandler( int signum )
241{
242    alarmed = 1;
243    signal( signum, sighandler );
244}
245
246void set_alarm( int seconds )
247{
248    alarmed = 0;
249    signal( SIGALRM, sighandler );
250    alarm( seconds );
251}
252
253void m_sleep( int milliseconds )
254{
255    struct timeval tv;
256
257    tv.tv_sec  = milliseconds / 1000;
258    tv.tv_usec = milliseconds * 1000;
259
260    select( 0, NULL, NULL, NULL, &tv );
261}
262
263#endif
264
265#endif
266