blob: d4f9554ee359d2c0490b8558c9243b62f572bfb8 [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
Gilles Peskinedb09ef62020-06-03 01:43:33 +020020#include "common.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000021
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000022#include "mbedtls/platform.h"
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +010023
Manuel Pégourié-Gonnard8903fe02015-05-12 19:30:45 +020024#if defined(MBEDTLS_TIMING_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000025
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000026#include "mbedtls/timing.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000027
Manuel Pégourié-Gonnard8903fe02015-05-12 19:30:45 +020028#if !defined(MBEDTLS_TIMING_ALT)
29
Manuel Pégourié-Gonnard325ce092016-02-22 10:33:34 +010030#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \
Augustin Cavalier60bc47d2018-04-11 20:27:32 -040031 !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \
Ørjan Malde479d8de2020-05-20 09:32:39 +000032 !defined(__HAIKU__) && !defined(__midipix__)
Manuel Pégourié-Gonnard325ce092016-02-22 10:33:34 +010033#error "This module only works on Unix and Windows, see MBEDTLS_TIMING_C in config.h"
34#endif
35
David Horstmannb6bf5f52023-01-03 11:07:09 +000036/* *INDENT-OFF* */
Manuel Pégourié-Gonnardba194322015-05-29 09:47:57 +020037#ifndef asm
38#define asm __asm
39#endif
David Horstmannb6bf5f52023-01-03 11:07:09 +000040/* *INDENT-ON* */
Manuel Pégourié-Gonnardba194322015-05-29 09:47:57 +020041
Paul Bakkerfa6a6202013-10-28 18:48:30 +010042#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
Paul Bakker5121ce52009-01-03 21:22:43 +000043
44#include <windows.h>
irwire931d0e2018-06-23 18:55:14 +030045#include <process.h>
Paul Bakker5121ce52009-01-03 21:22:43 +000046
David Horstmannceeaeb92023-01-05 15:44:23 +000047struct _hr_time {
Paul Bakker5121ce52009-01-03 21:22:43 +000048 LARGE_INTEGER start;
49};
50
51#else
52
53#include <unistd.h>
54#include <sys/types.h>
Paul Bakker5121ce52009-01-03 21:22:43 +000055#include <signal.h>
Andrzej Kurek263d8f72022-04-08 08:34:41 -040056/* time.h should be included independently of MBEDTLS_HAVE_TIME. If the
57 * platform matches the ifdefs above, it will be used. */
Paul Bakker5121ce52009-01-03 21:22:43 +000058#include <time.h>
Andrzej Kurek77daaad2022-03-04 15:10:06 -050059#include <sys/time.h>
David Horstmannceeaeb92023-01-05 15:44:23 +000060struct _hr_time {
Paul Bakker5121ce52009-01-03 21:22:43 +000061 struct timeval start;
62};
Paul Bakker9af723c2014-05-01 13:03:14 +020063#endif /* _WIN32 && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +000064
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020065#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
David Horstmannceeaeb92023-01-05 15:44:23 +000066 (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
Paul Bakker5121ce52009-01-03 21:22:43 +000067
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020068#define HAVE_HARDCLOCK
Paul Bakkerbb0139c2012-10-31 09:53:08 +000069
David Horstmannceeaeb92023-01-05 15:44:23 +000070unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +000071{
72 unsigned long tsc;
73 __asm rdtsc
David Horstmannceeaeb92023-01-05 15:44:23 +000074 __asm mov[tsc], eax
75 return tsc;
Paul Bakker5121ce52009-01-03 21:22:43 +000076}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020077#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +020078 ( _MSC_VER && _M_IX86 ) || __WATCOMC__ */
Paul Bakker5121ce52009-01-03 21:22:43 +000079
Manuel Pégourié-Gonnard38433532015-02-11 11:35:58 +000080/* some versions of mingw-64 have 32-bit longs even on x84_64 */
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020081#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
David Horstmannceeaeb92023-01-05 15:44:23 +000082 defined(__GNUC__) && (defined(__i386__) || ( \
83 (defined(__amd64__) || defined(__x86_64__)) && __SIZEOF_LONG__ == 4))
Paul Bakkerbb0139c2012-10-31 09:53:08 +000084
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020085#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +000086
David Horstmannceeaeb92023-01-05 15:44:23 +000087unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +000088{
Paul Bakkerca410102011-10-19 14:27:36 +000089 unsigned long lo, hi;
David Horstmannceeaeb92023-01-05 15:44:23 +000090 asm volatile ("rdtsc" : "=a" (lo), "=d" (hi));
91 return lo;
Paul Bakker5121ce52009-01-03 21:22:43 +000092}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020093#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +020094 __GNUC__ && __i386__ */
Paul Bakker5121ce52009-01-03 21:22:43 +000095
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020096#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
David Horstmannceeaeb92023-01-05 15:44:23 +000097 defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__))
Paul Bakkerbb0139c2012-10-31 09:53:08 +000098
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020099#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000100
David Horstmannceeaeb92023-01-05 15:44:23 +0000101unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000102{
103 unsigned long lo, hi;
David Horstmannceeaeb92023-01-05 15:44:23 +0000104 asm volatile ("rdtsc" : "=a" (lo), "=d" (hi));
105 return lo | (hi << 32);
Paul Bakker5121ce52009-01-03 21:22:43 +0000106}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200107#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200108 __GNUC__ && ( __amd64__ || __x86_64__ ) */
Paul Bakker5121ce52009-01-03 21:22:43 +0000109
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200110#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
David Horstmannceeaeb92023-01-05 15:44:23 +0000111 defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000112
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200113#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000114
David Horstmannceeaeb92023-01-05 15:44:23 +0000115unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000116{
117 unsigned long tbl, tbu0, tbu1;
118
David Horstmannceeaeb92023-01-05 15:44:23 +0000119 do {
120 asm volatile ("mftbu %0" : "=r" (tbu0));
121 asm volatile ("mftb %0" : "=r" (tbl));
122 asm volatile ("mftbu %0" : "=r" (tbu1));
123 } while (tbu0 != tbu1);
Paul Bakker5121ce52009-01-03 21:22:43 +0000124
David Horstmannceeaeb92023-01-05 15:44:23 +0000125 return tbl;
Paul Bakker5121ce52009-01-03 21:22:43 +0000126}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200127#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200128 __GNUC__ && ( __powerpc__ || __ppc__ ) */
Paul Bakker5121ce52009-01-03 21:22:43 +0000129
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200130#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000131 defined(__GNUC__) && defined(__sparc64__)
132
133#if defined(__OpenBSD__)
134#warning OpenBSD does not allow access to tick register using software version instead
Paul Bakker5121ce52009-01-03 21:22:43 +0000135#else
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200136#define HAVE_HARDCLOCK
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000137
David Horstmannceeaeb92023-01-05 15:44:23 +0000138unsigned long mbedtls_timing_hardclock(void)
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000139{
140 unsigned long tick;
David Horstmannceeaeb92023-01-05 15:44:23 +0000141 asm volatile ("rdpr %%tick, %0;" : "=&r" (tick));
142 return tick;
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000143}
Paul Bakker9af723c2014-05-01 13:03:14 +0200144#endif /* __OpenBSD__ */
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200145#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200146 __GNUC__ && __sparc64__ */
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000147
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200148#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000149 defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__)
150
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200151#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000152
David Horstmannceeaeb92023-01-05 15:44:23 +0000153unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000154{
155 unsigned long tick;
David Horstmannceeaeb92023-01-05 15:44:23 +0000156 asm volatile (".byte 0x83, 0x41, 0x00, 0x00");
157 asm volatile ("mov %%g1, %0" : "=r" (tick));
158 return tick;
Paul Bakker5121ce52009-01-03 21:22:43 +0000159}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200160#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200161 __GNUC__ && __sparc__ && !__sparc64__ */
Paul Bakker5121ce52009-01-03 21:22:43 +0000162
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200163#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000164 defined(__GNUC__) && defined(__alpha__)
165
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200166#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000167
David Horstmannceeaeb92023-01-05 15:44:23 +0000168unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000169{
170 unsigned long cc;
David Horstmannceeaeb92023-01-05 15:44:23 +0000171 asm volatile ("rpcc %0" : "=r" (cc));
172 return cc & 0xFFFFFFFF;
Paul Bakker5121ce52009-01-03 21:22:43 +0000173}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200174#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200175 __GNUC__ && __alpha__ */
Paul Bakker5121ce52009-01-03 21:22:43 +0000176
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200177#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000178 defined(__GNUC__) && defined(__ia64__)
179
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200180#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000181
David Horstmannceeaeb92023-01-05 15:44:23 +0000182unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000183{
184 unsigned long itc;
David Horstmannceeaeb92023-01-05 15:44:23 +0000185 asm volatile ("mov %0 = ar.itc" : "=r" (itc));
186 return itc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000187}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200188#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200189 __GNUC__ && __ia64__ */
Paul Bakker5121ce52009-01-03 21:22:43 +0000190
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200191#if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100192 !defined(EFIX64) && !defined(EFI32)
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000193
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200194#define HAVE_HARDCLOCK
Paul Bakker2eee9022011-04-24 15:28:55 +0000195
David Horstmannceeaeb92023-01-05 15:44:23 +0000196unsigned long mbedtls_timing_hardclock(void)
Paul Bakker2eee9022011-04-24 15:28:55 +0000197{
198 LARGE_INTEGER offset;
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100199
David Horstmannceeaeb92023-01-05 15:44:23 +0000200 QueryPerformanceCounter(&offset);
Paul Bakker2eee9022011-04-24 15:28:55 +0000201
David Horstmannceeaeb92023-01-05 15:44:23 +0000202 return (unsigned long) (offset.QuadPart);
Paul Bakker2eee9022011-04-24 15:28:55 +0000203}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200204#endif /* !HAVE_HARDCLOCK && _MSC_VER && !EFIX64 && !EFI32 */
Paul Bakker2eee9022011-04-24 15:28:55 +0000205
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200206#if !defined(HAVE_HARDCLOCK)
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000207
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200208#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000209
210static int hardclock_init = 0;
211static struct timeval tv_init;
212
David Horstmannceeaeb92023-01-05 15:44:23 +0000213unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000214{
215 struct timeval tv_cur;
216
David Horstmannceeaeb92023-01-05 15:44:23 +0000217 if (hardclock_init == 0) {
218 gettimeofday(&tv_init, NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000219 hardclock_init = 1;
220 }
221
David Horstmannceeaeb92023-01-05 15:44:23 +0000222 gettimeofday(&tv_cur, NULL);
223 return (tv_cur.tv_sec - tv_init.tv_sec) * 1000000U
224 + (tv_cur.tv_usec - tv_init.tv_usec);
Paul Bakker5121ce52009-01-03 21:22:43 +0000225}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200226#endif /* !HAVE_HARDCLOCK */
Paul Bakker5121ce52009-01-03 21:22:43 +0000227
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200228volatile int mbedtls_timing_alarmed = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000229
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100230#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
Paul Bakker5121ce52009-01-03 21:22:43 +0000231
David Horstmannceeaeb92023-01-05 15:44:23 +0000232unsigned long mbedtls_timing_get_timer(struct mbedtls_timing_hr_time *val, int reset)
Paul Bakker5121ce52009-01-03 21:22:43 +0000233{
Paul Bakker5121ce52009-01-03 21:22:43 +0000234 struct _hr_time *t = (struct _hr_time *) val;
235
David Horstmannceeaeb92023-01-05 15:44:23 +0000236 if (reset) {
237 QueryPerformanceCounter(&t->start);
238 return 0;
239 } else {
Gilles Peskined92f0aa2017-10-16 19:33:06 +0200240 unsigned long delta;
241 LARGE_INTEGER now, hfreq;
David Horstmannceeaeb92023-01-05 15:44:23 +0000242 QueryPerformanceCounter(&now);
243 QueryPerformanceFrequency(&hfreq);
244 delta = (unsigned long) ((now.QuadPart - t->start.QuadPart) * 1000ul
245 / hfreq.QuadPart);
246 return delta;
Gilles Peskined92f0aa2017-10-16 19:33:06 +0200247 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000248}
249
Manuel Pégourié-Gonnarddda52132015-02-11 11:36:31 +0000250/* It's OK to use a global because alarm() is supposed to be global anyway */
251static DWORD alarmMs;
252
David Horstmannceeaeb92023-01-05 15:44:23 +0000253static void TimerProc(void *TimerContext)
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100254{
irwire1b82ad2018-08-30 11:57:09 +0300255 (void) TimerContext;
David Horstmannceeaeb92023-01-05 15:44:23 +0000256 Sleep(alarmMs);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200257 mbedtls_timing_alarmed = 1;
irwirda642d92018-08-31 15:14:54 +0300258 /* _endthread will be called implicitly on return
Tom Cosgrove49f99bc2022-12-04 16:44:21 +0000259 * That ensures execution of thread function's epilogue */
Paul Bakker5121ce52009-01-03 21:22:43 +0000260}
261
David Horstmannceeaeb92023-01-05 15:44:23 +0000262void mbedtls_set_alarm(int seconds)
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100263{
David Horstmannceeaeb92023-01-05 15:44:23 +0000264 if (seconds == 0) {
Manuel Pégourié-Gonnard54059622018-01-29 10:16:30 +0100265 /* No need to create a thread for this simple case.
266 * Also, this shorcut is more reliable at least on MinGW32 */
267 mbedtls_timing_alarmed = 1;
268 return;
269 }
270
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200271 mbedtls_timing_alarmed = 0;
Manuel Pégourié-Gonnarddda52132015-02-11 11:36:31 +0000272 alarmMs = seconds * 1000;
David Horstmannceeaeb92023-01-05 15:44:23 +0000273 (void) _beginthread(TimerProc, 0, NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000274}
275
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100276#else /* _WIN32 && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +0000277
David Horstmannceeaeb92023-01-05 15:44:23 +0000278unsigned long mbedtls_timing_get_timer(struct mbedtls_timing_hr_time *val, int reset)
Paul Bakker5121ce52009-01-03 21:22:43 +0000279{
Paul Bakker5121ce52009-01-03 21:22:43 +0000280 struct _hr_time *t = (struct _hr_time *) val;
281
David Horstmannceeaeb92023-01-05 15:44:23 +0000282 if (reset) {
283 gettimeofday(&t->start, NULL);
284 return 0;
285 } else {
Gilles Peskined92f0aa2017-10-16 19:33:06 +0200286 unsigned long delta;
287 struct timeval now;
David Horstmannceeaeb92023-01-05 15:44:23 +0000288 gettimeofday(&now, NULL);
289 delta = (now.tv_sec - t->start.tv_sec) * 1000ul
290 + (now.tv_usec - t->start.tv_usec) / 1000;
291 return delta;
Gilles Peskined92f0aa2017-10-16 19:33:06 +0200292 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000293}
294
David Horstmannceeaeb92023-01-05 15:44:23 +0000295static void sighandler(int signum)
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100296{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200297 mbedtls_timing_alarmed = 1;
David Horstmannceeaeb92023-01-05 15:44:23 +0000298 signal(signum, sighandler);
Paul Bakker5121ce52009-01-03 21:22:43 +0000299}
300
David Horstmannceeaeb92023-01-05 15:44:23 +0000301void mbedtls_set_alarm(int seconds)
Paul Bakker5121ce52009-01-03 21:22:43 +0000302{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200303 mbedtls_timing_alarmed = 0;
David Horstmannceeaeb92023-01-05 15:44:23 +0000304 signal(SIGALRM, sighandler);
305 alarm(seconds);
306 if (seconds == 0) {
Gilles Peskinea0af95f2017-10-10 20:10:46 +0200307 /* alarm(0) cancelled any previous pending alarm, but the
308 handler won't fire, so raise the flag straight away. */
309 mbedtls_timing_alarmed = 1;
310 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000311}
312
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100313#endif /* _WIN32 && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +0000314
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200315/*
316 * Set delays to watch
317 */
David Horstmannceeaeb92023-01-05 15:44:23 +0000318void mbedtls_timing_set_delay(void *data, uint32_t int_ms, uint32_t fin_ms)
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200319{
320 mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data;
321
322 ctx->int_ms = int_ms;
323 ctx->fin_ms = fin_ms;
324
David Horstmannceeaeb92023-01-05 15:44:23 +0000325 if (fin_ms != 0) {
326 (void) mbedtls_timing_get_timer(&ctx->timer, 1);
327 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200328}
329
330/*
331 * Get number of delays expired
332 */
David Horstmannceeaeb92023-01-05 15:44:23 +0000333int mbedtls_timing_get_delay(void *data)
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200334{
335 mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data;
336 unsigned long elapsed_ms;
337
David Horstmannceeaeb92023-01-05 15:44:23 +0000338 if (ctx->fin_ms == 0) {
339 return -1;
340 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200341
David Horstmannceeaeb92023-01-05 15:44:23 +0000342 elapsed_ms = mbedtls_timing_get_timer(&ctx->timer, 0);
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200343
David Horstmannceeaeb92023-01-05 15:44:23 +0000344 if (elapsed_ms >= ctx->fin_ms) {
345 return 2;
346 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200347
David Horstmannceeaeb92023-01-05 15:44:23 +0000348 if (elapsed_ms >= ctx->int_ms) {
349 return 1;
350 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200351
David Horstmannceeaeb92023-01-05 15:44:23 +0000352 return 0;
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200353}
354
Manuel Pégourié-Gonnard8903fe02015-05-12 19:30:45 +0200355
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200356#if defined(MBEDTLS_SELF_TEST)
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100357
358/*
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200359 * Busy-waits for the given number of milliseconds.
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200360 * Used for testing mbedtls_timing_hardclock.
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200361 */
David Horstmannceeaeb92023-01-05 15:44:23 +0000362static void busy_msleep(unsigned long msec)
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200363{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200364 struct mbedtls_timing_hr_time hires;
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200365 unsigned long i = 0; /* for busy-waiting */
366 volatile unsigned long j; /* to prevent optimisation */
367
David Horstmannceeaeb92023-01-05 15:44:23 +0000368 (void) mbedtls_timing_get_timer(&hires, 1);
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200369
David Horstmannceeaeb92023-01-05 15:44:23 +0000370 while (mbedtls_timing_get_timer(&hires, 0) < msec) {
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200371 i++;
David Horstmannceeaeb92023-01-05 15:44:23 +0000372 }
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200373
374 j = i;
375 (void) j;
376}
377
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200378#define FAIL do \
379 { \
David Horstmannceeaeb92023-01-05 15:44:23 +0000380 if (verbose != 0) \
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200381 { \
David Horstmannceeaeb92023-01-05 15:44:23 +0000382 mbedtls_printf("failed at line %d\n", __LINE__); \
383 mbedtls_printf(" cycles=%lu ratio=%lu millisecs=%lu secs=%lu hardfail=%d a=%lu b=%lu\n", \
384 cycles, ratio, millisecs, secs, hardfail, \
385 (unsigned long) a, (unsigned long) b); \
386 mbedtls_printf(" elapsed(hires)=%lu elapsed(ctx)=%lu status(ctx)=%d\n", \
387 mbedtls_timing_get_timer(&hires, 0), \
388 mbedtls_timing_get_timer(&ctx.timer, 0), \
389 mbedtls_timing_get_delay(&ctx)); \
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200390 } \
David Horstmannceeaeb92023-01-05 15:44:23 +0000391 return 1; \
392 } while (0)
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200393
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200394/*
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100395 * Checkup routine
Manuel Pégourié-Gonnard0f79bab2014-04-09 09:56:16 +0200396 *
397 * Warning: this is work in progress, some tests may not be reliable enough
398 * yet! False positives may happen.
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100399 */
David Horstmannceeaeb92023-01-05 15:44:23 +0000400int mbedtls_timing_self_test(int verbose)
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100401{
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200402 unsigned long cycles = 0, ratio = 0;
403 unsigned long millisecs = 0, secs = 0;
404 int hardfail = 0;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200405 struct mbedtls_timing_hr_time hires;
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200406 uint32_t a = 0, b = 0;
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200407 mbedtls_timing_delay_context ctx;
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100408
David Horstmannceeaeb92023-01-05 15:44:23 +0000409 if (verbose != 0) {
410 mbedtls_printf(" TIMING tests note: will take some time!\n");
411 }
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100412
David Horstmannceeaeb92023-01-05 15:44:23 +0000413 if (verbose != 0) {
414 mbedtls_printf(" TIMING test #1 (set_alarm / get_timer): ");
415 }
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100416
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100417 {
Gilles Peskineada3ee82017-12-20 22:31:17 +0100418 secs = 1;
419
David Horstmannceeaeb92023-01-05 15:44:23 +0000420 (void) mbedtls_timing_get_timer(&hires, 1);
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100421
David Horstmannceeaeb92023-01-05 15:44:23 +0000422 mbedtls_set_alarm((int) secs);
423 while (!mbedtls_timing_alarmed) {
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100424 ;
David Horstmannceeaeb92023-01-05 15:44:23 +0000425 }
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100426
David Horstmannceeaeb92023-01-05 15:44:23 +0000427 millisecs = mbedtls_timing_get_timer(&hires, 0);
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100428
Manuel Pégourié-Gonnarde578b1c2015-08-18 20:11:48 +0200429 /* For some reason on Windows it looks like alarm has an extra delay
430 * (maybe related to creating a new thread). Allow some room here. */
David Horstmannceeaeb92023-01-05 15:44:23 +0000431 if (millisecs < 800 * secs || millisecs > 1200 * secs + 300) {
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200432 FAIL;
David Horstmannceeaeb92023-01-05 15:44:23 +0000433 }
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100434 }
435
David Horstmannceeaeb92023-01-05 15:44:23 +0000436 if (verbose != 0) {
437 mbedtls_printf("passed\n");
438 }
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100439
David Horstmannceeaeb92023-01-05 15:44:23 +0000440 if (verbose != 0) {
441 mbedtls_printf(" TIMING test #2 (set/get_delay ): ");
442 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200443
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200444 {
Gilles Peskine8873bcc2017-10-27 18:42:32 +0200445 a = 800;
446 b = 400;
David Horstmannceeaeb92023-01-05 15:44:23 +0000447 mbedtls_timing_set_delay(&ctx, a, a + b); /* T = 0 */
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200448
David Horstmannceeaeb92023-01-05 15:44:23 +0000449 busy_msleep(a - a / 4); /* T = a - a/4 */
450 if (mbedtls_timing_get_delay(&ctx) != 0) {
Gilles Peskine8873bcc2017-10-27 18:42:32 +0200451 FAIL;
David Horstmannceeaeb92023-01-05 15:44:23 +0000452 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200453
David Horstmannceeaeb92023-01-05 15:44:23 +0000454 busy_msleep(a / 4 + b / 4); /* T = a + b/4 */
455 if (mbedtls_timing_get_delay(&ctx) != 1) {
Gilles Peskine8873bcc2017-10-27 18:42:32 +0200456 FAIL;
David Horstmannceeaeb92023-01-05 15:44:23 +0000457 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200458
David Horstmannceeaeb92023-01-05 15:44:23 +0000459 busy_msleep(b); /* T = a + b + b/4 */
460 if (mbedtls_timing_get_delay(&ctx) != 2) {
Gilles Peskine8873bcc2017-10-27 18:42:32 +0200461 FAIL;
David Horstmannceeaeb92023-01-05 15:44:23 +0000462 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200463 }
464
David Horstmannceeaeb92023-01-05 15:44:23 +0000465 mbedtls_timing_set_delay(&ctx, 0, 0);
466 busy_msleep(200);
467 if (mbedtls_timing_get_delay(&ctx) != -1) {
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200468 FAIL;
David Horstmannceeaeb92023-01-05 15:44:23 +0000469 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200470
David Horstmannceeaeb92023-01-05 15:44:23 +0000471 if (verbose != 0) {
472 mbedtls_printf("passed\n");
473 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200474
David Horstmannceeaeb92023-01-05 15:44:23 +0000475 if (verbose != 0) {
476 mbedtls_printf(" TIMING test #3 (hardclock / get_timer): ");
477 }
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200478
479 /*
480 * Allow one failure for possible counter wrapping.
481 * On a 4Ghz 32-bit machine the cycle counter wraps about once per second;
482 * since the whole test is about 10ms, it shouldn't happen twice in a row.
483 */
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200484
485hard_test:
David Horstmannceeaeb92023-01-05 15:44:23 +0000486 if (hardfail > 1) {
487 if (verbose != 0) {
488 mbedtls_printf("failed (ignored)\n");
489 }
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200490
491 goto hard_test_done;
492 }
493
494 /* Get a reference ratio cycles/ms */
495 millisecs = 1;
496 cycles = mbedtls_timing_hardclock();
David Horstmannceeaeb92023-01-05 15:44:23 +0000497 busy_msleep(millisecs);
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200498 cycles = mbedtls_timing_hardclock() - cycles;
499 ratio = cycles / millisecs;
500
501 /* Check that the ratio is mostly constant */
David Horstmannceeaeb92023-01-05 15:44:23 +0000502 for (millisecs = 2; millisecs <= 4; millisecs++) {
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200503 cycles = mbedtls_timing_hardclock();
David Horstmannceeaeb92023-01-05 15:44:23 +0000504 busy_msleep(millisecs);
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200505 cycles = mbedtls_timing_hardclock() - cycles;
506
507 /* Allow variation up to 20% */
David Horstmannceeaeb92023-01-05 15:44:23 +0000508 if (cycles / millisecs < ratio - ratio / 5 ||
509 cycles / millisecs > ratio + ratio / 5) {
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200510 hardfail++;
511 goto hard_test;
512 }
513 }
514
David Horstmannceeaeb92023-01-05 15:44:23 +0000515 if (verbose != 0) {
516 mbedtls_printf("passed\n");
517 }
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200518
519hard_test_done:
520
David Horstmannceeaeb92023-01-05 15:44:23 +0000521 if (verbose != 0) {
522 mbedtls_printf("\n");
523 }
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200524
David Horstmannceeaeb92023-01-05 15:44:23 +0000525 return 0;
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100526}
527
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200528#endif /* MBEDTLS_SELF_TEST */
Andrzej Kurek77daaad2022-03-04 15:10:06 -0500529#endif /* !MBEDTLS_TIMING_ALT */
Manuel Pégourié-Gonnard8903fe02015-05-12 19:30:45 +0200530#endif /* MBEDTLS_TIMING_C */