blob: 94b55b3715df8f36bdf2fa377c3c1d3229443ae8 [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
Manuel Pégourié-Gonnard37ff1402015-09-04 14:21:07 +02005 * 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.
Paul Bakker5121ce52009-01-03 21:22:43 +000018 */
19
Dave Rodgman0feecbd2023-03-31 16:10:18 +010020#include <string.h>
21
Gilles Peskinedb09ef62020-06-03 01:43:33 +020022#include "common.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000023
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000024#include "mbedtls/platform.h"
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +010025
Manuel Pégourié-Gonnard8903fe02015-05-12 19:30:45 +020026#if defined(MBEDTLS_TIMING_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000027
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000028#include "mbedtls/timing.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000029
Manuel Pégourié-Gonnard8903fe02015-05-12 19:30:45 +020030#if !defined(MBEDTLS_TIMING_ALT)
31
Manuel Pégourié-Gonnard325ce092016-02-22 10:33:34 +010032#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \
Augustin Cavalier60bc47d2018-04-11 20:27:32 -040033 !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \
Ørjan Malde479d8de2020-05-20 09:32:39 +000034 !defined(__HAIKU__) && !defined(__midipix__)
Manuel Pégourié-Gonnard325ce092016-02-22 10:33:34 +010035#error "This module only works on Unix and Windows, see MBEDTLS_TIMING_C in config.h"
36#endif
37
David Horstmannb6bf5f52023-01-03 11:07:09 +000038/* *INDENT-OFF* */
Manuel Pégourié-Gonnardba194322015-05-29 09:47:57 +020039#ifndef asm
40#define asm __asm
41#endif
David Horstmannb6bf5f52023-01-03 11:07:09 +000042/* *INDENT-ON* */
Manuel Pégourié-Gonnardba194322015-05-29 09:47:57 +020043
Paul Bakkerfa6a6202013-10-28 18:48:30 +010044#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
Paul Bakker5121ce52009-01-03 21:22:43 +000045
46#include <windows.h>
irwire931d0e2018-06-23 18:55:14 +030047#include <process.h>
Paul Bakker5121ce52009-01-03 21:22:43 +000048
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010049struct _hr_time {
Paul Bakker5121ce52009-01-03 21:22:43 +000050 LARGE_INTEGER start;
51};
52
53#else
54
55#include <unistd.h>
56#include <sys/types.h>
Paul Bakker5121ce52009-01-03 21:22:43 +000057#include <signal.h>
Andrzej Kurek263d8f72022-04-08 08:34:41 -040058/* time.h should be included independently of MBEDTLS_HAVE_TIME. If the
59 * platform matches the ifdefs above, it will be used. */
Paul Bakker5121ce52009-01-03 21:22:43 +000060#include <time.h>
Andrzej Kurek77daaad2022-03-04 15:10:06 -050061#include <sys/time.h>
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010062struct _hr_time {
Paul Bakker5121ce52009-01-03 21:22:43 +000063 struct timeval start;
64};
Paul Bakker9af723c2014-05-01 13:03:14 +020065#endif /* _WIN32 && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +000066
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020067#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010068 (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
Paul Bakker5121ce52009-01-03 21:22:43 +000069
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020070#define HAVE_HARDCLOCK
Paul Bakkerbb0139c2012-10-31 09:53:08 +000071
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010072unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +000073{
74 unsigned long tsc;
75 __asm rdtsc
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010076 __asm mov[tsc], eax
77 return tsc;
Paul Bakker5121ce52009-01-03 21:22:43 +000078}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020079#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +020080 ( _MSC_VER && _M_IX86 ) || __WATCOMC__ */
Paul Bakker5121ce52009-01-03 21:22:43 +000081
Manuel Pégourié-Gonnard38433532015-02-11 11:35:58 +000082/* some versions of mingw-64 have 32-bit longs even on x84_64 */
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020083#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010084 defined(__GNUC__) && (defined(__i386__) || ( \
85 (defined(__amd64__) || defined(__x86_64__)) && __SIZEOF_LONG__ == 4))
Paul Bakkerbb0139c2012-10-31 09:53:08 +000086
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020087#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +000088
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010089unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +000090{
Paul Bakkerca410102011-10-19 14:27:36 +000091 unsigned long lo, hi;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010092 asm volatile ("rdtsc" : "=a" (lo), "=d" (hi));
93 return lo;
Paul Bakker5121ce52009-01-03 21:22:43 +000094}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020095#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +020096 __GNUC__ && __i386__ */
Paul Bakker5121ce52009-01-03 21:22:43 +000097
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020098#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010099 defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__))
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000100
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200101#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000102
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100103unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000104{
105 unsigned long lo, hi;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100106 asm volatile ("rdtsc" : "=a" (lo), "=d" (hi));
107 return lo | (hi << 32);
Paul Bakker5121ce52009-01-03 21:22:43 +0000108}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200109#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200110 __GNUC__ && ( __amd64__ || __x86_64__ ) */
Paul Bakker5121ce52009-01-03 21:22:43 +0000111
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200112#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100113 defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000114
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200115#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000116
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100117unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000118{
119 unsigned long tbl, tbu0, tbu1;
120
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100121 do {
122 asm volatile ("mftbu %0" : "=r" (tbu0));
123 asm volatile ("mftb %0" : "=r" (tbl));
124 asm volatile ("mftbu %0" : "=r" (tbu1));
125 } while (tbu0 != tbu1);
Paul Bakker5121ce52009-01-03 21:22:43 +0000126
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100127 return tbl;
Paul Bakker5121ce52009-01-03 21:22:43 +0000128}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200129#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200130 __GNUC__ && ( __powerpc__ || __ppc__ ) */
Paul Bakker5121ce52009-01-03 21:22:43 +0000131
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200132#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000133 defined(__GNUC__) && defined(__sparc64__)
134
135#if defined(__OpenBSD__)
136#warning OpenBSD does not allow access to tick register using software version instead
Paul Bakker5121ce52009-01-03 21:22:43 +0000137#else
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200138#define HAVE_HARDCLOCK
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000139
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100140unsigned long mbedtls_timing_hardclock(void)
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000141{
142 unsigned long tick;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100143 asm volatile ("rdpr %%tick, %0;" : "=&r" (tick));
144 return tick;
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000145}
Paul Bakker9af723c2014-05-01 13:03:14 +0200146#endif /* __OpenBSD__ */
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200147#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200148 __GNUC__ && __sparc64__ */
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000149
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200150#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000151 defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__)
152
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200153#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000154
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100155unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000156{
157 unsigned long tick;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100158 asm volatile (".byte 0x83, 0x41, 0x00, 0x00");
159 asm volatile ("mov %%g1, %0" : "=r" (tick));
160 return tick;
Paul Bakker5121ce52009-01-03 21:22:43 +0000161}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200162#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200163 __GNUC__ && __sparc__ && !__sparc64__ */
Paul Bakker5121ce52009-01-03 21:22:43 +0000164
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200165#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000166 defined(__GNUC__) && defined(__alpha__)
167
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200168#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000169
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100170unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000171{
172 unsigned long cc;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100173 asm volatile ("rpcc %0" : "=r" (cc));
174 return cc & 0xFFFFFFFF;
Paul Bakker5121ce52009-01-03 21:22:43 +0000175}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200176#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200177 __GNUC__ && __alpha__ */
Paul Bakker5121ce52009-01-03 21:22:43 +0000178
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200179#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000180 defined(__GNUC__) && defined(__ia64__)
181
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200182#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000183
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100184unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000185{
186 unsigned long itc;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100187 asm volatile ("mov %0 = ar.itc" : "=r" (itc));
188 return itc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000189}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200190#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200191 __GNUC__ && __ia64__ */
Paul Bakker5121ce52009-01-03 21:22:43 +0000192
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200193#if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100194 !defined(EFIX64) && !defined(EFI32)
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000195
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200196#define HAVE_HARDCLOCK
Paul Bakker2eee9022011-04-24 15:28:55 +0000197
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100198unsigned long mbedtls_timing_hardclock(void)
Paul Bakker2eee9022011-04-24 15:28:55 +0000199{
200 LARGE_INTEGER offset;
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100201
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100202 QueryPerformanceCounter(&offset);
Paul Bakker2eee9022011-04-24 15:28:55 +0000203
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100204 return (unsigned long) (offset.QuadPart);
Paul Bakker2eee9022011-04-24 15:28:55 +0000205}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200206#endif /* !HAVE_HARDCLOCK && _MSC_VER && !EFIX64 && !EFI32 */
Paul Bakker2eee9022011-04-24 15:28:55 +0000207
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200208#if !defined(HAVE_HARDCLOCK)
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000209
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200210#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000211
212static int hardclock_init = 0;
213static struct timeval tv_init;
214
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100215unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000216{
217 struct timeval tv_cur;
218
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100219 if (hardclock_init == 0) {
220 gettimeofday(&tv_init, NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000221 hardclock_init = 1;
222 }
223
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100224 gettimeofday(&tv_cur, NULL);
225 return (tv_cur.tv_sec - tv_init.tv_sec) * 1000000U
226 + (tv_cur.tv_usec - tv_init.tv_usec);
Paul Bakker5121ce52009-01-03 21:22:43 +0000227}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200228#endif /* !HAVE_HARDCLOCK */
Paul Bakker5121ce52009-01-03 21:22:43 +0000229
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200230volatile int mbedtls_timing_alarmed = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000231
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100232#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
Paul Bakker5121ce52009-01-03 21:22:43 +0000233
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100234unsigned long mbedtls_timing_get_timer(struct mbedtls_timing_hr_time *val, int reset)
Paul Bakker5121ce52009-01-03 21:22:43 +0000235{
Dave Rodgmanb2e3c7a2023-03-31 16:43:40 +0100236 struct _hr_time t;
Paul Bakker5121ce52009-01-03 21:22:43 +0000237
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100238 if (reset) {
Dave Rodgmanb2e3c7a2023-03-31 16:43:40 +0100239 QueryPerformanceCounter(&t.start);
240 memcpy(val, &t, sizeof(struct _hr_time));
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100241 return 0;
242 } else {
Gilles Peskined92f0aa2017-10-16 19:33:06 +0200243 unsigned long delta;
244 LARGE_INTEGER now, hfreq;
Dave Rodgman8f109fc2023-03-31 17:07:04 +0100245 /* We can't safely cast val because it may not be aligned, so use memcpy */
246 memcpy(&t, val, sizeof(struct _hr_time));
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100247 QueryPerformanceCounter(&now);
248 QueryPerformanceFrequency(&hfreq);
Dave Rodgmanb2e3c7a2023-03-31 16:43:40 +0100249 delta = (unsigned long) ((now.QuadPart - t.start.QuadPart) * 1000ul
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100250 / hfreq.QuadPart);
251 return delta;
Gilles Peskined92f0aa2017-10-16 19:33:06 +0200252 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000253}
254
Manuel Pégourié-Gonnarddda52132015-02-11 11:36:31 +0000255/* It's OK to use a global because alarm() is supposed to be global anyway */
256static DWORD alarmMs;
257
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100258static void TimerProc(void *TimerContext)
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100259{
irwire1b82ad2018-08-30 11:57:09 +0300260 (void) TimerContext;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100261 Sleep(alarmMs);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200262 mbedtls_timing_alarmed = 1;
irwirda642d92018-08-31 15:14:54 +0300263 /* _endthread will be called implicitly on return
Tom Cosgrove49f99bc2022-12-04 16:44:21 +0000264 * That ensures execution of thread function's epilogue */
Paul Bakker5121ce52009-01-03 21:22:43 +0000265}
266
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100267void mbedtls_set_alarm(int seconds)
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100268{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100269 if (seconds == 0) {
Manuel Pégourié-Gonnard54059622018-01-29 10:16:30 +0100270 /* No need to create a thread for this simple case.
271 * Also, this shorcut is more reliable at least on MinGW32 */
272 mbedtls_timing_alarmed = 1;
273 return;
274 }
275
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200276 mbedtls_timing_alarmed = 0;
Manuel Pégourié-Gonnarddda52132015-02-11 11:36:31 +0000277 alarmMs = seconds * 1000;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100278 (void) _beginthread(TimerProc, 0, NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000279}
280
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100281#else /* _WIN32 && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +0000282
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100283unsigned long mbedtls_timing_get_timer(struct mbedtls_timing_hr_time *val, int reset)
Paul Bakker5121ce52009-01-03 21:22:43 +0000284{
Dave Rodgmanb2e3c7a2023-03-31 16:43:40 +0100285 struct _hr_time t;
Paul Bakker5121ce52009-01-03 21:22:43 +0000286
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100287 if (reset) {
Dave Rodgmanb2e3c7a2023-03-31 16:43:40 +0100288 gettimeofday(&t.start, NULL);
289 memcpy(val, &t, sizeof(struct _hr_time));
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100290 return 0;
291 } else {
Gilles Peskined92f0aa2017-10-16 19:33:06 +0200292 unsigned long delta;
293 struct timeval now;
Dave Rodgman6ab5d5c2023-03-31 17:24:10 +0100294 /* We can't safely cast val because it may not be aligned, so use memcpy */
Dave Rodgman8f109fc2023-03-31 17:07:04 +0100295 memcpy(&t, val, sizeof(struct _hr_time));
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100296 gettimeofday(&now, NULL);
Dave Rodgmanb2e3c7a2023-03-31 16:43:40 +0100297 delta = (now.tv_sec - t.start.tv_sec) * 1000ul
298 + (now.tv_usec - t.start.tv_usec) / 1000;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100299 return delta;
Gilles Peskined92f0aa2017-10-16 19:33:06 +0200300 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000301}
302
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100303static void sighandler(int signum)
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100304{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200305 mbedtls_timing_alarmed = 1;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100306 signal(signum, sighandler);
Paul Bakker5121ce52009-01-03 21:22:43 +0000307}
308
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100309void mbedtls_set_alarm(int seconds)
Paul Bakker5121ce52009-01-03 21:22:43 +0000310{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200311 mbedtls_timing_alarmed = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100312 signal(SIGALRM, sighandler);
313 alarm(seconds);
314 if (seconds == 0) {
Gilles Peskinea0af95f2017-10-10 20:10:46 +0200315 /* alarm(0) cancelled any previous pending alarm, but the
316 handler won't fire, so raise the flag straight away. */
317 mbedtls_timing_alarmed = 1;
318 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000319}
320
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100321#endif /* _WIN32 && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +0000322
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200323/*
324 * Set delays to watch
325 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100326void mbedtls_timing_set_delay(void *data, uint32_t int_ms, uint32_t fin_ms)
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200327{
328 mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data;
329
330 ctx->int_ms = int_ms;
331 ctx->fin_ms = fin_ms;
332
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100333 if (fin_ms != 0) {
334 (void) mbedtls_timing_get_timer(&ctx->timer, 1);
335 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200336}
337
338/*
339 * Get number of delays expired
340 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100341int mbedtls_timing_get_delay(void *data)
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200342{
343 mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data;
344 unsigned long elapsed_ms;
345
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100346 if (ctx->fin_ms == 0) {
347 return -1;
348 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200349
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100350 elapsed_ms = mbedtls_timing_get_timer(&ctx->timer, 0);
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200351
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100352 if (elapsed_ms >= ctx->fin_ms) {
353 return 2;
354 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200355
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100356 if (elapsed_ms >= ctx->int_ms) {
357 return 1;
358 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200359
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100360 return 0;
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200361}
362
Andrzej Kurekcf4e9992023-01-13 19:01:51 -0500363#endif /* !MBEDTLS_TIMING_ALT */
Manuel Pégourié-Gonnard8903fe02015-05-12 19:30:45 +0200364
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200365#if defined(MBEDTLS_SELF_TEST)
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100366/*
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200367 * Busy-waits for the given number of milliseconds.
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200368 * Used for testing mbedtls_timing_hardclock.
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200369 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100370static void busy_msleep(unsigned long msec)
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200371{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200372 struct mbedtls_timing_hr_time hires;
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200373 unsigned long i = 0; /* for busy-waiting */
374 volatile unsigned long j; /* to prevent optimisation */
375
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100376 (void) mbedtls_timing_get_timer(&hires, 1);
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200377
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100378 while (mbedtls_timing_get_timer(&hires, 0) < msec) {
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200379 i++;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100380 }
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200381
382 j = i;
383 (void) j;
384}
385
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200386#define FAIL do \
387 { \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100388 if (verbose != 0) \
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200389 { \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100390 mbedtls_printf("failed at line %d\n", __LINE__); \
391 mbedtls_printf(" cycles=%lu ratio=%lu millisecs=%lu secs=%lu hardfail=%d a=%lu b=%lu\n", \
392 cycles, ratio, millisecs, secs, hardfail, \
393 (unsigned long) a, (unsigned long) b); \
Andrzej Kurekcf4e9992023-01-13 19:01:51 -0500394 mbedtls_printf(" elapsed(hires)=%lu status(ctx)=%d\n", \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100395 mbedtls_timing_get_timer(&hires, 0), \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100396 mbedtls_timing_get_delay(&ctx)); \
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200397 } \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100398 return 1; \
399 } while (0)
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200400
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200401/*
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100402 * Checkup routine
Manuel Pégourié-Gonnard0f79bab2014-04-09 09:56:16 +0200403 *
404 * Warning: this is work in progress, some tests may not be reliable enough
405 * yet! False positives may happen.
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100406 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100407int mbedtls_timing_self_test(int verbose)
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100408{
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200409 unsigned long cycles = 0, ratio = 0;
410 unsigned long millisecs = 0, secs = 0;
411 int hardfail = 0;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200412 struct mbedtls_timing_hr_time hires;
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200413 uint32_t a = 0, b = 0;
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200414 mbedtls_timing_delay_context ctx;
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100415
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100416 if (verbose != 0) {
417 mbedtls_printf(" TIMING tests note: will take some time!\n");
418 }
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100419
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100420 if (verbose != 0) {
421 mbedtls_printf(" TIMING test #1 (set_alarm / get_timer): ");
422 }
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100423
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100424 {
Gilles Peskineada3ee82017-12-20 22:31:17 +0100425 secs = 1;
426
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100427 (void) mbedtls_timing_get_timer(&hires, 1);
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100428
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100429 mbedtls_set_alarm((int) secs);
430 while (!mbedtls_timing_alarmed) {
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100431 ;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100432 }
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100433
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100434 millisecs = mbedtls_timing_get_timer(&hires, 0);
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100435
Manuel Pégourié-Gonnarde578b1c2015-08-18 20:11:48 +0200436 /* For some reason on Windows it looks like alarm has an extra delay
437 * (maybe related to creating a new thread). Allow some room here. */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100438 if (millisecs < 800 * secs || millisecs > 1200 * secs + 300) {
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200439 FAIL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100440 }
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100441 }
442
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100443 if (verbose != 0) {
444 mbedtls_printf("passed\n");
445 }
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100446
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100447 if (verbose != 0) {
448 mbedtls_printf(" TIMING test #2 (set/get_delay ): ");
449 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200450
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200451 {
Gilles Peskine8873bcc2017-10-27 18:42:32 +0200452 a = 800;
453 b = 400;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100454 mbedtls_timing_set_delay(&ctx, a, a + b); /* T = 0 */
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200455
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100456 busy_msleep(a - a / 4); /* T = a - a/4 */
457 if (mbedtls_timing_get_delay(&ctx) != 0) {
Gilles Peskine8873bcc2017-10-27 18:42:32 +0200458 FAIL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100459 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200460
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100461 busy_msleep(a / 4 + b / 4); /* T = a + b/4 */
462 if (mbedtls_timing_get_delay(&ctx) != 1) {
Gilles Peskine8873bcc2017-10-27 18:42:32 +0200463 FAIL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100464 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200465
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100466 busy_msleep(b); /* T = a + b + b/4 */
467 if (mbedtls_timing_get_delay(&ctx) != 2) {
Gilles Peskine8873bcc2017-10-27 18:42:32 +0200468 FAIL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100469 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200470 }
471
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100472 mbedtls_timing_set_delay(&ctx, 0, 0);
473 busy_msleep(200);
474 if (mbedtls_timing_get_delay(&ctx) != -1) {
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200475 FAIL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100476 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200477
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100478 if (verbose != 0) {
479 mbedtls_printf("passed\n");
480 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200481
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100482 if (verbose != 0) {
483 mbedtls_printf(" TIMING test #3 (hardclock / get_timer): ");
484 }
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200485
486 /*
487 * Allow one failure for possible counter wrapping.
488 * On a 4Ghz 32-bit machine the cycle counter wraps about once per second;
489 * since the whole test is about 10ms, it shouldn't happen twice in a row.
490 */
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200491
492hard_test:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100493 if (hardfail > 1) {
494 if (verbose != 0) {
495 mbedtls_printf("failed (ignored)\n");
496 }
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200497
498 goto hard_test_done;
499 }
500
501 /* Get a reference ratio cycles/ms */
502 millisecs = 1;
503 cycles = mbedtls_timing_hardclock();
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100504 busy_msleep(millisecs);
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200505 cycles = mbedtls_timing_hardclock() - cycles;
506 ratio = cycles / millisecs;
507
508 /* Check that the ratio is mostly constant */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100509 for (millisecs = 2; millisecs <= 4; millisecs++) {
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200510 cycles = mbedtls_timing_hardclock();
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100511 busy_msleep(millisecs);
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200512 cycles = mbedtls_timing_hardclock() - cycles;
513
514 /* Allow variation up to 20% */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100515 if (cycles / millisecs < ratio - ratio / 5 ||
516 cycles / millisecs > ratio + ratio / 5) {
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200517 hardfail++;
518 goto hard_test;
519 }
520 }
521
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100522 if (verbose != 0) {
523 mbedtls_printf("passed\n");
524 }
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200525
526hard_test_done:
527
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100528 if (verbose != 0) {
529 mbedtls_printf("\n");
530 }
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200531
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100532 return 0;
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100533}
534
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200535#endif /* MBEDTLS_SELF_TEST */
Manuel Pégourié-Gonnard8903fe02015-05-12 19:30:45 +0200536#endif /* MBEDTLS_TIMING_C */