blob: b1f72fe1bae8081bc0e1882e7b2a37fb74e7fd8b [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * Portable interface to the CPU cycle counter
3 *
Bence Szépkúti1e148272020-08-07 13:07:28 +02004 * Copyright The Mbed TLS Contributors
Dave Rodgman7ff79652023-11-03 12:04:52 +00005 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
Paul Bakker5121ce52009-01-03 21:22:43 +00006 */
7
Dave Rodgman0feecbd2023-03-31 16:10:18 +01008#include <string.h>
9
Gilles Peskinedb09ef62020-06-03 01:43:33 +020010#include "common.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000011
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000012#include "mbedtls/platform.h"
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +010013
Manuel Pégourié-Gonnard8903fe02015-05-12 19:30:45 +020014#if defined(MBEDTLS_TIMING_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000015
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000016#include "mbedtls/timing.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000017
Manuel Pégourié-Gonnard8903fe02015-05-12 19:30:45 +020018#if !defined(MBEDTLS_TIMING_ALT)
19
Manuel Pégourié-Gonnard325ce092016-02-22 10:33:34 +010020#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \
Augustin Cavalier60bc47d2018-04-11 20:27:32 -040021 !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \
Ørjan Malde479d8de2020-05-20 09:32:39 +000022 !defined(__HAIKU__) && !defined(__midipix__)
Manuel Pégourié-Gonnard325ce092016-02-22 10:33:34 +010023#error "This module only works on Unix and Windows, see MBEDTLS_TIMING_C in config.h"
24#endif
25
David Horstmannb6bf5f52023-01-03 11:07:09 +000026/* *INDENT-OFF* */
Manuel Pégourié-Gonnardba194322015-05-29 09:47:57 +020027#ifndef asm
28#define asm __asm
29#endif
David Horstmannb6bf5f52023-01-03 11:07:09 +000030/* *INDENT-ON* */
Manuel Pégourié-Gonnardba194322015-05-29 09:47:57 +020031
Paul Bakkerfa6a6202013-10-28 18:48:30 +010032#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
Paul Bakker5121ce52009-01-03 21:22:43 +000033
34#include <windows.h>
irwire931d0e2018-06-23 18:55:14 +030035#include <process.h>
Paul Bakker5121ce52009-01-03 21:22:43 +000036
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010037struct _hr_time {
Paul Bakker5121ce52009-01-03 21:22:43 +000038 LARGE_INTEGER start;
39};
40
41#else
42
43#include <unistd.h>
44#include <sys/types.h>
Paul Bakker5121ce52009-01-03 21:22:43 +000045#include <signal.h>
Andrzej Kurek263d8f72022-04-08 08:34:41 -040046/* time.h should be included independently of MBEDTLS_HAVE_TIME. If the
47 * platform matches the ifdefs above, it will be used. */
Paul Bakker5121ce52009-01-03 21:22:43 +000048#include <time.h>
Andrzej Kurek77daaad2022-03-04 15:10:06 -050049#include <sys/time.h>
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010050struct _hr_time {
Paul Bakker5121ce52009-01-03 21:22:43 +000051 struct timeval start;
52};
Paul Bakker9af723c2014-05-01 13:03:14 +020053#endif /* _WIN32 && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +000054
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020055#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010056 (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
Paul Bakker5121ce52009-01-03 21:22:43 +000057
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020058#define HAVE_HARDCLOCK
Paul Bakkerbb0139c2012-10-31 09:53:08 +000059
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010060unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +000061{
62 unsigned long tsc;
63 __asm rdtsc
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010064 __asm mov[tsc], eax
65 return tsc;
Paul Bakker5121ce52009-01-03 21:22:43 +000066}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020067#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +020068 ( _MSC_VER && _M_IX86 ) || __WATCOMC__ */
Paul Bakker5121ce52009-01-03 21:22:43 +000069
Manuel Pégourié-Gonnard38433532015-02-11 11:35:58 +000070/* some versions of mingw-64 have 32-bit longs even on x84_64 */
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020071#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010072 defined(__GNUC__) && (defined(__i386__) || ( \
73 (defined(__amd64__) || defined(__x86_64__)) && __SIZEOF_LONG__ == 4))
Paul Bakkerbb0139c2012-10-31 09:53:08 +000074
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020075#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +000076
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010077unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +000078{
Paul Bakkerca410102011-10-19 14:27:36 +000079 unsigned long lo, hi;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010080 asm volatile ("rdtsc" : "=a" (lo), "=d" (hi));
81 return lo;
Paul Bakker5121ce52009-01-03 21:22:43 +000082}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020083#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +020084 __GNUC__ && __i386__ */
Paul Bakker5121ce52009-01-03 21:22:43 +000085
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020086#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010087 defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__))
Paul Bakkerbb0139c2012-10-31 09:53:08 +000088
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020089#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +000090
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010091unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +000092{
93 unsigned long lo, hi;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010094 asm volatile ("rdtsc" : "=a" (lo), "=d" (hi));
95 return lo | (hi << 32);
Paul Bakker5121ce52009-01-03 21:22:43 +000096}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020097#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +020098 __GNUC__ && ( __amd64__ || __x86_64__ ) */
Paul Bakker5121ce52009-01-03 21:22:43 +000099
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200100#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100101 defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000102
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200103#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000104
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100105unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000106{
107 unsigned long tbl, tbu0, tbu1;
108
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100109 do {
110 asm volatile ("mftbu %0" : "=r" (tbu0));
111 asm volatile ("mftb %0" : "=r" (tbl));
112 asm volatile ("mftbu %0" : "=r" (tbu1));
113 } while (tbu0 != tbu1);
Paul Bakker5121ce52009-01-03 21:22:43 +0000114
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100115 return tbl;
Paul Bakker5121ce52009-01-03 21:22:43 +0000116}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200117#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200118 __GNUC__ && ( __powerpc__ || __ppc__ ) */
Paul Bakker5121ce52009-01-03 21:22:43 +0000119
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200120#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000121 defined(__GNUC__) && defined(__sparc64__)
122
123#if defined(__OpenBSD__)
124#warning OpenBSD does not allow access to tick register using software version instead
Paul Bakker5121ce52009-01-03 21:22:43 +0000125#else
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200126#define HAVE_HARDCLOCK
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000127
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100128unsigned long mbedtls_timing_hardclock(void)
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000129{
130 unsigned long tick;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100131 asm volatile ("rdpr %%tick, %0;" : "=&r" (tick));
132 return tick;
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000133}
Paul Bakker9af723c2014-05-01 13:03:14 +0200134#endif /* __OpenBSD__ */
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200135#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200136 __GNUC__ && __sparc64__ */
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000137
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200138#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000139 defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__)
140
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200141#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000142
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100143unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000144{
145 unsigned long tick;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100146 asm volatile (".byte 0x83, 0x41, 0x00, 0x00");
147 asm volatile ("mov %%g1, %0" : "=r" (tick));
148 return tick;
Paul Bakker5121ce52009-01-03 21:22:43 +0000149}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200150#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200151 __GNUC__ && __sparc__ && !__sparc64__ */
Paul Bakker5121ce52009-01-03 21:22:43 +0000152
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200153#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000154 defined(__GNUC__) && defined(__alpha__)
155
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200156#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000157
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100158unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000159{
160 unsigned long cc;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100161 asm volatile ("rpcc %0" : "=r" (cc));
162 return cc & 0xFFFFFFFF;
Paul Bakker5121ce52009-01-03 21:22:43 +0000163}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200164#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200165 __GNUC__ && __alpha__ */
Paul Bakker5121ce52009-01-03 21:22:43 +0000166
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200167#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000168 defined(__GNUC__) && defined(__ia64__)
169
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200170#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000171
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100172unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000173{
174 unsigned long itc;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100175 asm volatile ("mov %0 = ar.itc" : "=r" (itc));
176 return itc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000177}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200178#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200179 __GNUC__ && __ia64__ */
Paul Bakker5121ce52009-01-03 21:22:43 +0000180
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200181#if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100182 !defined(EFIX64) && !defined(EFI32)
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000183
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200184#define HAVE_HARDCLOCK
Paul Bakker2eee9022011-04-24 15:28:55 +0000185
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100186unsigned long mbedtls_timing_hardclock(void)
Paul Bakker2eee9022011-04-24 15:28:55 +0000187{
188 LARGE_INTEGER offset;
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100189
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100190 QueryPerformanceCounter(&offset);
Paul Bakker2eee9022011-04-24 15:28:55 +0000191
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100192 return (unsigned long) (offset.QuadPart);
Paul Bakker2eee9022011-04-24 15:28:55 +0000193}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200194#endif /* !HAVE_HARDCLOCK && _MSC_VER && !EFIX64 && !EFI32 */
Paul Bakker2eee9022011-04-24 15:28:55 +0000195
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200196#if !defined(HAVE_HARDCLOCK)
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000197
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200198#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000199
200static int hardclock_init = 0;
201static struct timeval tv_init;
202
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100203unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000204{
205 struct timeval tv_cur;
206
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100207 if (hardclock_init == 0) {
208 gettimeofday(&tv_init, NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000209 hardclock_init = 1;
210 }
211
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100212 gettimeofday(&tv_cur, NULL);
213 return (tv_cur.tv_sec - tv_init.tv_sec) * 1000000U
214 + (tv_cur.tv_usec - tv_init.tv_usec);
Paul Bakker5121ce52009-01-03 21:22:43 +0000215}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200216#endif /* !HAVE_HARDCLOCK */
Paul Bakker5121ce52009-01-03 21:22:43 +0000217
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200218volatile int mbedtls_timing_alarmed = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000219
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100220#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
Paul Bakker5121ce52009-01-03 21:22:43 +0000221
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100222unsigned long mbedtls_timing_get_timer(struct mbedtls_timing_hr_time *val, int reset)
Paul Bakker5121ce52009-01-03 21:22:43 +0000223{
Dave Rodgmanb2e3c7a2023-03-31 16:43:40 +0100224 struct _hr_time t;
Paul Bakker5121ce52009-01-03 21:22:43 +0000225
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100226 if (reset) {
Dave Rodgmanb2e3c7a2023-03-31 16:43:40 +0100227 QueryPerformanceCounter(&t.start);
228 memcpy(val, &t, sizeof(struct _hr_time));
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100229 return 0;
230 } else {
Gilles Peskined92f0aa2017-10-16 19:33:06 +0200231 unsigned long delta;
232 LARGE_INTEGER now, hfreq;
Dave Rodgman8f109fc2023-03-31 17:07:04 +0100233 /* We can't safely cast val because it may not be aligned, so use memcpy */
234 memcpy(&t, val, sizeof(struct _hr_time));
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100235 QueryPerformanceCounter(&now);
236 QueryPerformanceFrequency(&hfreq);
Dave Rodgmanb2e3c7a2023-03-31 16:43:40 +0100237 delta = (unsigned long) ((now.QuadPart - t.start.QuadPart) * 1000ul
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100238 / hfreq.QuadPart);
239 return delta;
Gilles Peskined92f0aa2017-10-16 19:33:06 +0200240 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000241}
242
Manuel Pégourié-Gonnarddda52132015-02-11 11:36:31 +0000243/* It's OK to use a global because alarm() is supposed to be global anyway */
244static DWORD alarmMs;
245
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100246static void TimerProc(void *TimerContext)
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100247{
irwire1b82ad2018-08-30 11:57:09 +0300248 (void) TimerContext;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100249 Sleep(alarmMs);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200250 mbedtls_timing_alarmed = 1;
irwirda642d92018-08-31 15:14:54 +0300251 /* _endthread will be called implicitly on return
Tom Cosgrove49f99bc2022-12-04 16:44:21 +0000252 * That ensures execution of thread function's epilogue */
Paul Bakker5121ce52009-01-03 21:22:43 +0000253}
254
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100255void mbedtls_set_alarm(int seconds)
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100256{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100257 if (seconds == 0) {
Manuel Pégourié-Gonnard54059622018-01-29 10:16:30 +0100258 /* No need to create a thread for this simple case.
259 * Also, this shorcut is more reliable at least on MinGW32 */
260 mbedtls_timing_alarmed = 1;
261 return;
262 }
263
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200264 mbedtls_timing_alarmed = 0;
Manuel Pégourié-Gonnarddda52132015-02-11 11:36:31 +0000265 alarmMs = seconds * 1000;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100266 (void) _beginthread(TimerProc, 0, NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000267}
268
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100269#else /* _WIN32 && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +0000270
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100271unsigned long mbedtls_timing_get_timer(struct mbedtls_timing_hr_time *val, int reset)
Paul Bakker5121ce52009-01-03 21:22:43 +0000272{
Dave Rodgmanb2e3c7a2023-03-31 16:43:40 +0100273 struct _hr_time t;
Paul Bakker5121ce52009-01-03 21:22:43 +0000274
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100275 if (reset) {
Dave Rodgmanb2e3c7a2023-03-31 16:43:40 +0100276 gettimeofday(&t.start, NULL);
277 memcpy(val, &t, sizeof(struct _hr_time));
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100278 return 0;
279 } else {
Gilles Peskined92f0aa2017-10-16 19:33:06 +0200280 unsigned long delta;
281 struct timeval now;
Dave Rodgman6ab5d5c2023-03-31 17:24:10 +0100282 /* We can't safely cast val because it may not be aligned, so use memcpy */
Dave Rodgman8f109fc2023-03-31 17:07:04 +0100283 memcpy(&t, val, sizeof(struct _hr_time));
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100284 gettimeofday(&now, NULL);
Dave Rodgmanb2e3c7a2023-03-31 16:43:40 +0100285 delta = (now.tv_sec - t.start.tv_sec) * 1000ul
286 + (now.tv_usec - t.start.tv_usec) / 1000;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100287 return delta;
Gilles Peskined92f0aa2017-10-16 19:33:06 +0200288 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000289}
290
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100291static void sighandler(int signum)
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100292{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200293 mbedtls_timing_alarmed = 1;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100294 signal(signum, sighandler);
Paul Bakker5121ce52009-01-03 21:22:43 +0000295}
296
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100297void mbedtls_set_alarm(int seconds)
Paul Bakker5121ce52009-01-03 21:22:43 +0000298{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200299 mbedtls_timing_alarmed = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100300 signal(SIGALRM, sighandler);
301 alarm(seconds);
302 if (seconds == 0) {
Gilles Peskinea0af95f2017-10-10 20:10:46 +0200303 /* alarm(0) cancelled any previous pending alarm, but the
304 handler won't fire, so raise the flag straight away. */
305 mbedtls_timing_alarmed = 1;
306 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000307}
308
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100309#endif /* _WIN32 && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +0000310
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200311/*
312 * Set delays to watch
313 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100314void mbedtls_timing_set_delay(void *data, uint32_t int_ms, uint32_t fin_ms)
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200315{
316 mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data;
317
318 ctx->int_ms = int_ms;
319 ctx->fin_ms = fin_ms;
320
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100321 if (fin_ms != 0) {
322 (void) mbedtls_timing_get_timer(&ctx->timer, 1);
323 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200324}
325
326/*
327 * Get number of delays expired
328 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100329int mbedtls_timing_get_delay(void *data)
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200330{
331 mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data;
332 unsigned long elapsed_ms;
333
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100334 if (ctx->fin_ms == 0) {
335 return -1;
336 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200337
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100338 elapsed_ms = mbedtls_timing_get_timer(&ctx->timer, 0);
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200339
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100340 if (elapsed_ms >= ctx->fin_ms) {
341 return 2;
342 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200343
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100344 if (elapsed_ms >= ctx->int_ms) {
345 return 1;
346 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200347
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100348 return 0;
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200349}
350
Andrzej Kurekcf4e9992023-01-13 19:01:51 -0500351#endif /* !MBEDTLS_TIMING_ALT */
Manuel Pégourié-Gonnard8903fe02015-05-12 19:30:45 +0200352
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200353#if defined(MBEDTLS_SELF_TEST)
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100354/*
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200355 * Busy-waits for the given number of milliseconds.
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200356 * Used for testing mbedtls_timing_hardclock.
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200357 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100358static void busy_msleep(unsigned long msec)
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200359{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200360 struct mbedtls_timing_hr_time hires;
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200361 unsigned long i = 0; /* for busy-waiting */
362 volatile unsigned long j; /* to prevent optimisation */
363
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100364 (void) mbedtls_timing_get_timer(&hires, 1);
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200365
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100366 while (mbedtls_timing_get_timer(&hires, 0) < msec) {
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200367 i++;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100368 }
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200369
370 j = i;
371 (void) j;
372}
373
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200374#define FAIL do \
375 { \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100376 if (verbose != 0) \
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200377 { \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100378 mbedtls_printf("failed at line %d\n", __LINE__); \
379 mbedtls_printf(" cycles=%lu ratio=%lu millisecs=%lu secs=%lu hardfail=%d a=%lu b=%lu\n", \
380 cycles, ratio, millisecs, secs, hardfail, \
381 (unsigned long) a, (unsigned long) b); \
Andrzej Kurekcf4e9992023-01-13 19:01:51 -0500382 mbedtls_printf(" elapsed(hires)=%lu status(ctx)=%d\n", \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100383 mbedtls_timing_get_timer(&hires, 0), \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100384 mbedtls_timing_get_delay(&ctx)); \
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200385 } \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100386 return 1; \
387 } while (0)
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200388
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200389/*
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100390 * Checkup routine
Manuel Pégourié-Gonnard0f79bab2014-04-09 09:56:16 +0200391 *
392 * Warning: this is work in progress, some tests may not be reliable enough
393 * yet! False positives may happen.
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100394 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100395int mbedtls_timing_self_test(int verbose)
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100396{
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200397 unsigned long cycles = 0, ratio = 0;
398 unsigned long millisecs = 0, secs = 0;
399 int hardfail = 0;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200400 struct mbedtls_timing_hr_time hires;
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200401 uint32_t a = 0, b = 0;
Gianfranco Costamagnaf88dd842024-01-03 01:41:32 +0100402 mbedtls_timing_delay_context ctx;
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100403
Gianfranco Costamagnad7768232024-01-18 12:08:21 +0100404 memset(&ctx, 0, sizeof(ctx));
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100405 if (verbose != 0) {
406 mbedtls_printf(" TIMING tests note: will take some time!\n");
407 }
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100408
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100409 if (verbose != 0) {
410 mbedtls_printf(" TIMING test #1 (set_alarm / get_timer): ");
411 }
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100412
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100413 {
Gilles Peskineada3ee82017-12-20 22:31:17 +0100414 secs = 1;
415
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100416 (void) mbedtls_timing_get_timer(&hires, 1);
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100417
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100418 mbedtls_set_alarm((int) secs);
419 while (!mbedtls_timing_alarmed) {
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100420 ;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100421 }
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100422
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100423 millisecs = mbedtls_timing_get_timer(&hires, 0);
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100424
Manuel Pégourié-Gonnarde578b1c2015-08-18 20:11:48 +0200425 /* For some reason on Windows it looks like alarm has an extra delay
426 * (maybe related to creating a new thread). Allow some room here. */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100427 if (millisecs < 800 * secs || millisecs > 1200 * secs + 300) {
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200428 FAIL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100429 }
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100430 }
431
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100432 if (verbose != 0) {
433 mbedtls_printf("passed\n");
434 }
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100435
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100436 if (verbose != 0) {
437 mbedtls_printf(" TIMING test #2 (set/get_delay ): ");
438 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200439
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200440 {
Gilles Peskine8873bcc2017-10-27 18:42:32 +0200441 a = 800;
442 b = 400;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100443 mbedtls_timing_set_delay(&ctx, a, a + b); /* T = 0 */
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200444
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100445 busy_msleep(a - a / 4); /* T = a - a/4 */
446 if (mbedtls_timing_get_delay(&ctx) != 0) {
Gilles Peskine8873bcc2017-10-27 18:42:32 +0200447 FAIL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100448 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200449
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100450 busy_msleep(a / 4 + b / 4); /* T = a + b/4 */
451 if (mbedtls_timing_get_delay(&ctx) != 1) {
Gilles Peskine8873bcc2017-10-27 18:42:32 +0200452 FAIL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100453 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200454
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100455 busy_msleep(b); /* T = a + b + b/4 */
456 if (mbedtls_timing_get_delay(&ctx) != 2) {
Gilles Peskine8873bcc2017-10-27 18:42:32 +0200457 FAIL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100458 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200459 }
460
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100461 mbedtls_timing_set_delay(&ctx, 0, 0);
462 busy_msleep(200);
463 if (mbedtls_timing_get_delay(&ctx) != -1) {
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200464 FAIL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100465 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200466
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100467 if (verbose != 0) {
468 mbedtls_printf("passed\n");
469 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200470
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100471 if (verbose != 0) {
472 mbedtls_printf(" TIMING test #3 (hardclock / get_timer): ");
473 }
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200474
475 /*
476 * Allow one failure for possible counter wrapping.
477 * On a 4Ghz 32-bit machine the cycle counter wraps about once per second;
478 * since the whole test is about 10ms, it shouldn't happen twice in a row.
479 */
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200480
481hard_test:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100482 if (hardfail > 1) {
483 if (verbose != 0) {
484 mbedtls_printf("failed (ignored)\n");
485 }
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200486
487 goto hard_test_done;
488 }
489
490 /* Get a reference ratio cycles/ms */
491 millisecs = 1;
492 cycles = mbedtls_timing_hardclock();
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100493 busy_msleep(millisecs);
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200494 cycles = mbedtls_timing_hardclock() - cycles;
495 ratio = cycles / millisecs;
496
497 /* Check that the ratio is mostly constant */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100498 for (millisecs = 2; millisecs <= 4; millisecs++) {
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200499 cycles = mbedtls_timing_hardclock();
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100500 busy_msleep(millisecs);
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200501 cycles = mbedtls_timing_hardclock() - cycles;
502
503 /* Allow variation up to 20% */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100504 if (cycles / millisecs < ratio - ratio / 5 ||
505 cycles / millisecs > ratio + ratio / 5) {
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200506 hardfail++;
507 goto hard_test;
508 }
509 }
510
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100511 if (verbose != 0) {
512 mbedtls_printf("passed\n");
513 }
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200514
515hard_test_done:
516
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100517 if (verbose != 0) {
518 mbedtls_printf("\n");
519 }
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200520
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100521 return 0;
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100522}
523
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200524#endif /* MBEDTLS_SELF_TEST */
Manuel Pégourié-Gonnard8903fe02015-05-12 19:30:45 +0200525#endif /* MBEDTLS_TIMING_C */