1*c6672fdcSEdison Ai // SPDX-License-Identifier: Apache-2.0 2817466cbSJens Wiklander /* 3817466cbSJens Wiklander * Portable interface to the CPU cycle counter 4817466cbSJens Wiklander * 5817466cbSJens Wiklander * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 6817466cbSJens Wiklander * 7817466cbSJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 8817466cbSJens Wiklander * not use this file except in compliance with the License. 9817466cbSJens Wiklander * You may obtain a copy of the License at 10817466cbSJens Wiklander * 11817466cbSJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 12817466cbSJens Wiklander * 13817466cbSJens Wiklander * Unless required by applicable law or agreed to in writing, software 14817466cbSJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15817466cbSJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16817466cbSJens Wiklander * See the License for the specific language governing permissions and 17817466cbSJens Wiklander * limitations under the License. 18817466cbSJens Wiklander * 19817466cbSJens Wiklander * This file is part of mbed TLS (https://tls.mbed.org) 20817466cbSJens Wiklander */ 21817466cbSJens Wiklander 22817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE) 23817466cbSJens Wiklander #include "mbedtls/config.h" 24817466cbSJens Wiklander #else 25817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE 26817466cbSJens Wiklander #endif 27817466cbSJens Wiklander 28817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_PLATFORM_C) 29817466cbSJens Wiklander #include "mbedtls/platform.h" 30817466cbSJens Wiklander #else 31817466cbSJens Wiklander #include <stdio.h> 32817466cbSJens Wiklander #define mbedtls_printf printf 33817466cbSJens Wiklander #endif 34817466cbSJens Wiklander 35817466cbSJens Wiklander #if defined(MBEDTLS_TIMING_C) 36817466cbSJens Wiklander 37817466cbSJens Wiklander #include "mbedtls/timing.h" 38817466cbSJens Wiklander 39817466cbSJens Wiklander #if !defined(MBEDTLS_TIMING_ALT) 40817466cbSJens Wiklander 41817466cbSJens Wiklander #if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ 42817466cbSJens Wiklander !defined(__APPLE__) && !defined(_WIN32) 43817466cbSJens Wiklander #error "This module only works on Unix and Windows, see MBEDTLS_TIMING_C in config.h" 44817466cbSJens Wiklander #endif 45817466cbSJens Wiklander 46817466cbSJens Wiklander #ifndef asm 47817466cbSJens Wiklander #define asm __asm 48817466cbSJens Wiklander #endif 49817466cbSJens Wiklander 50817466cbSJens Wiklander #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 51817466cbSJens Wiklander 52817466cbSJens Wiklander #include <windows.h> 53817466cbSJens Wiklander #include <winbase.h> 54817466cbSJens Wiklander 55817466cbSJens Wiklander struct _hr_time 56817466cbSJens Wiklander { 57817466cbSJens Wiklander LARGE_INTEGER start; 58817466cbSJens Wiklander }; 59817466cbSJens Wiklander 60817466cbSJens Wiklander #else 61817466cbSJens Wiklander 62817466cbSJens Wiklander #include <unistd.h> 63817466cbSJens Wiklander #include <sys/types.h> 64817466cbSJens Wiklander #include <sys/time.h> 65817466cbSJens Wiklander #include <signal.h> 66817466cbSJens Wiklander #include <time.h> 67817466cbSJens Wiklander 68817466cbSJens Wiklander struct _hr_time 69817466cbSJens Wiklander { 70817466cbSJens Wiklander struct timeval start; 71817466cbSJens Wiklander }; 72817466cbSJens Wiklander 73817466cbSJens Wiklander #endif /* _WIN32 && !EFIX64 && !EFI32 */ 74817466cbSJens Wiklander 75817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 76817466cbSJens Wiklander ( defined(_MSC_VER) && defined(_M_IX86) ) || defined(__WATCOMC__) 77817466cbSJens Wiklander 78817466cbSJens Wiklander #define HAVE_HARDCLOCK 79817466cbSJens Wiklander 80817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 81817466cbSJens Wiklander { 82817466cbSJens Wiklander unsigned long tsc; 83817466cbSJens Wiklander __asm rdtsc 84817466cbSJens Wiklander __asm mov [tsc], eax 85817466cbSJens Wiklander return( tsc ); 86817466cbSJens Wiklander } 87817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 88817466cbSJens Wiklander ( _MSC_VER && _M_IX86 ) || __WATCOMC__ */ 89817466cbSJens Wiklander 90817466cbSJens Wiklander /* some versions of mingw-64 have 32-bit longs even on x84_64 */ 91817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 92817466cbSJens Wiklander defined(__GNUC__) && ( defined(__i386__) || ( \ 93817466cbSJens Wiklander ( defined(__amd64__) || defined( __x86_64__) ) && __SIZEOF_LONG__ == 4 ) ) 94817466cbSJens Wiklander 95817466cbSJens Wiklander #define HAVE_HARDCLOCK 96817466cbSJens Wiklander 97817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 98817466cbSJens Wiklander { 99817466cbSJens Wiklander unsigned long lo, hi; 100817466cbSJens Wiklander asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); 101817466cbSJens Wiklander return( lo ); 102817466cbSJens Wiklander } 103817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 104817466cbSJens Wiklander __GNUC__ && __i386__ */ 105817466cbSJens Wiklander 106817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 107817466cbSJens Wiklander defined(__GNUC__) && ( defined(__amd64__) || defined(__x86_64__) ) 108817466cbSJens Wiklander 109817466cbSJens Wiklander #define HAVE_HARDCLOCK 110817466cbSJens Wiklander 111817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 112817466cbSJens Wiklander { 113817466cbSJens Wiklander unsigned long lo, hi; 114817466cbSJens Wiklander asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); 115817466cbSJens Wiklander return( lo | ( hi << 32 ) ); 116817466cbSJens Wiklander } 117817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 118817466cbSJens Wiklander __GNUC__ && ( __amd64__ || __x86_64__ ) */ 119817466cbSJens Wiklander 120817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 121817466cbSJens Wiklander defined(__GNUC__) && ( defined(__powerpc__) || defined(__ppc__) ) 122817466cbSJens Wiklander 123817466cbSJens Wiklander #define HAVE_HARDCLOCK 124817466cbSJens Wiklander 125817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 126817466cbSJens Wiklander { 127817466cbSJens Wiklander unsigned long tbl, tbu0, tbu1; 128817466cbSJens Wiklander 129817466cbSJens Wiklander do 130817466cbSJens Wiklander { 131817466cbSJens Wiklander asm volatile( "mftbu %0" : "=r" (tbu0) ); 132817466cbSJens Wiklander asm volatile( "mftb %0" : "=r" (tbl ) ); 133817466cbSJens Wiklander asm volatile( "mftbu %0" : "=r" (tbu1) ); 134817466cbSJens Wiklander } 135817466cbSJens Wiklander while( tbu0 != tbu1 ); 136817466cbSJens Wiklander 137817466cbSJens Wiklander return( tbl ); 138817466cbSJens Wiklander } 139817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 140817466cbSJens Wiklander __GNUC__ && ( __powerpc__ || __ppc__ ) */ 141817466cbSJens Wiklander 142817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 143817466cbSJens Wiklander defined(__GNUC__) && defined(__sparc64__) 144817466cbSJens Wiklander 145817466cbSJens Wiklander #if defined(__OpenBSD__) 146817466cbSJens Wiklander #warning OpenBSD does not allow access to tick register using software version instead 147817466cbSJens Wiklander #else 148817466cbSJens Wiklander #define HAVE_HARDCLOCK 149817466cbSJens Wiklander 150817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 151817466cbSJens Wiklander { 152817466cbSJens Wiklander unsigned long tick; 153817466cbSJens Wiklander asm volatile( "rdpr %%tick, %0;" : "=&r" (tick) ); 154817466cbSJens Wiklander return( tick ); 155817466cbSJens Wiklander } 156817466cbSJens Wiklander #endif /* __OpenBSD__ */ 157817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 158817466cbSJens Wiklander __GNUC__ && __sparc64__ */ 159817466cbSJens Wiklander 160817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 161817466cbSJens Wiklander defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__) 162817466cbSJens Wiklander 163817466cbSJens Wiklander #define HAVE_HARDCLOCK 164817466cbSJens Wiklander 165817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 166817466cbSJens Wiklander { 167817466cbSJens Wiklander unsigned long tick; 168817466cbSJens Wiklander asm volatile( ".byte 0x83, 0x41, 0x00, 0x00" ); 169817466cbSJens Wiklander asm volatile( "mov %%g1, %0" : "=r" (tick) ); 170817466cbSJens Wiklander return( tick ); 171817466cbSJens Wiklander } 172817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 173817466cbSJens Wiklander __GNUC__ && __sparc__ && !__sparc64__ */ 174817466cbSJens Wiklander 175817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 176817466cbSJens Wiklander defined(__GNUC__) && defined(__alpha__) 177817466cbSJens Wiklander 178817466cbSJens Wiklander #define HAVE_HARDCLOCK 179817466cbSJens Wiklander 180817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 181817466cbSJens Wiklander { 182817466cbSJens Wiklander unsigned long cc; 183817466cbSJens Wiklander asm volatile( "rpcc %0" : "=r" (cc) ); 184817466cbSJens Wiklander return( cc & 0xFFFFFFFF ); 185817466cbSJens Wiklander } 186817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 187817466cbSJens Wiklander __GNUC__ && __alpha__ */ 188817466cbSJens Wiklander 189817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ 190817466cbSJens Wiklander defined(__GNUC__) && defined(__ia64__) 191817466cbSJens Wiklander 192817466cbSJens Wiklander #define HAVE_HARDCLOCK 193817466cbSJens Wiklander 194817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 195817466cbSJens Wiklander { 196817466cbSJens Wiklander unsigned long itc; 197817466cbSJens Wiklander asm volatile( "mov %0 = ar.itc" : "=r" (itc) ); 198817466cbSJens Wiklander return( itc ); 199817466cbSJens Wiklander } 200817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && 201817466cbSJens Wiklander __GNUC__ && __ia64__ */ 202817466cbSJens Wiklander 203817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \ 204817466cbSJens Wiklander !defined(EFIX64) && !defined(EFI32) 205817466cbSJens Wiklander 206817466cbSJens Wiklander #define HAVE_HARDCLOCK 207817466cbSJens Wiklander 208817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 209817466cbSJens Wiklander { 210817466cbSJens Wiklander LARGE_INTEGER offset; 211817466cbSJens Wiklander 212817466cbSJens Wiklander QueryPerformanceCounter( &offset ); 213817466cbSJens Wiklander 214817466cbSJens Wiklander return( (unsigned long)( offset.QuadPart ) ); 215817466cbSJens Wiklander } 216817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK && _MSC_VER && !EFIX64 && !EFI32 */ 217817466cbSJens Wiklander 218817466cbSJens Wiklander #if !defined(HAVE_HARDCLOCK) 219817466cbSJens Wiklander 220817466cbSJens Wiklander #define HAVE_HARDCLOCK 221817466cbSJens Wiklander 222817466cbSJens Wiklander static int hardclock_init = 0; 223817466cbSJens Wiklander static struct timeval tv_init; 224817466cbSJens Wiklander 225817466cbSJens Wiklander unsigned long mbedtls_timing_hardclock( void ) 226817466cbSJens Wiklander { 227817466cbSJens Wiklander struct timeval tv_cur; 228817466cbSJens Wiklander 229817466cbSJens Wiklander if( hardclock_init == 0 ) 230817466cbSJens Wiklander { 231817466cbSJens Wiklander gettimeofday( &tv_init, NULL ); 232817466cbSJens Wiklander hardclock_init = 1; 233817466cbSJens Wiklander } 234817466cbSJens Wiklander 235817466cbSJens Wiklander gettimeofday( &tv_cur, NULL ); 236817466cbSJens Wiklander return( ( tv_cur.tv_sec - tv_init.tv_sec ) * 1000000 237817466cbSJens Wiklander + ( tv_cur.tv_usec - tv_init.tv_usec ) ); 238817466cbSJens Wiklander } 239817466cbSJens Wiklander #endif /* !HAVE_HARDCLOCK */ 240817466cbSJens Wiklander 241817466cbSJens Wiklander volatile int mbedtls_timing_alarmed = 0; 242817466cbSJens Wiklander 243817466cbSJens Wiklander #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 244817466cbSJens Wiklander 245817466cbSJens Wiklander unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) 246817466cbSJens Wiklander { 247817466cbSJens Wiklander unsigned long delta; 248817466cbSJens Wiklander LARGE_INTEGER offset, hfreq; 249817466cbSJens Wiklander struct _hr_time *t = (struct _hr_time *) val; 250817466cbSJens Wiklander 251817466cbSJens Wiklander QueryPerformanceCounter( &offset ); 252817466cbSJens Wiklander QueryPerformanceFrequency( &hfreq ); 253817466cbSJens Wiklander 254817466cbSJens Wiklander delta = (unsigned long)( ( 1000 * 255817466cbSJens Wiklander ( offset.QuadPart - t->start.QuadPart ) ) / 256817466cbSJens Wiklander hfreq.QuadPart ); 257817466cbSJens Wiklander 258817466cbSJens Wiklander if( reset ) 259817466cbSJens Wiklander QueryPerformanceCounter( &t->start ); 260817466cbSJens Wiklander 261817466cbSJens Wiklander return( delta ); 262817466cbSJens Wiklander } 263817466cbSJens Wiklander 264817466cbSJens Wiklander /* It's OK to use a global because alarm() is supposed to be global anyway */ 265817466cbSJens Wiklander static DWORD alarmMs; 266817466cbSJens Wiklander 267817466cbSJens Wiklander static DWORD WINAPI TimerProc( LPVOID TimerContext ) 268817466cbSJens Wiklander { 269817466cbSJens Wiklander ((void) TimerContext); 270817466cbSJens Wiklander Sleep( alarmMs ); 271817466cbSJens Wiklander mbedtls_timing_alarmed = 1; 272817466cbSJens Wiklander return( TRUE ); 273817466cbSJens Wiklander } 274817466cbSJens Wiklander 275817466cbSJens Wiklander void mbedtls_set_alarm( int seconds ) 276817466cbSJens Wiklander { 277817466cbSJens Wiklander DWORD ThreadId; 278817466cbSJens Wiklander 279817466cbSJens Wiklander mbedtls_timing_alarmed = 0; 280817466cbSJens Wiklander alarmMs = seconds * 1000; 281817466cbSJens Wiklander CloseHandle( CreateThread( NULL, 0, TimerProc, NULL, 0, &ThreadId ) ); 282817466cbSJens Wiklander } 283817466cbSJens Wiklander 284817466cbSJens Wiklander #else /* _WIN32 && !EFIX64 && !EFI32 */ 285817466cbSJens Wiklander 286817466cbSJens Wiklander unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) 287817466cbSJens Wiklander { 288817466cbSJens Wiklander unsigned long delta; 289817466cbSJens Wiklander struct timeval offset; 290817466cbSJens Wiklander struct _hr_time *t = (struct _hr_time *) val; 291817466cbSJens Wiklander 292817466cbSJens Wiklander gettimeofday( &offset, NULL ); 293817466cbSJens Wiklander 294817466cbSJens Wiklander if( reset ) 295817466cbSJens Wiklander { 296817466cbSJens Wiklander t->start.tv_sec = offset.tv_sec; 297817466cbSJens Wiklander t->start.tv_usec = offset.tv_usec; 298817466cbSJens Wiklander return( 0 ); 299817466cbSJens Wiklander } 300817466cbSJens Wiklander 301817466cbSJens Wiklander delta = ( offset.tv_sec - t->start.tv_sec ) * 1000 302817466cbSJens Wiklander + ( offset.tv_usec - t->start.tv_usec ) / 1000; 303817466cbSJens Wiklander 304817466cbSJens Wiklander return( delta ); 305817466cbSJens Wiklander } 306817466cbSJens Wiklander 307817466cbSJens Wiklander static void sighandler( int signum ) 308817466cbSJens Wiklander { 309817466cbSJens Wiklander mbedtls_timing_alarmed = 1; 310817466cbSJens Wiklander signal( signum, sighandler ); 311817466cbSJens Wiklander } 312817466cbSJens Wiklander 313817466cbSJens Wiklander void mbedtls_set_alarm( int seconds ) 314817466cbSJens Wiklander { 315817466cbSJens Wiklander mbedtls_timing_alarmed = 0; 316817466cbSJens Wiklander signal( SIGALRM, sighandler ); 317817466cbSJens Wiklander alarm( seconds ); 318817466cbSJens Wiklander } 319817466cbSJens Wiklander 320817466cbSJens Wiklander #endif /* _WIN32 && !EFIX64 && !EFI32 */ 321817466cbSJens Wiklander 322817466cbSJens Wiklander /* 323817466cbSJens Wiklander * Set delays to watch 324817466cbSJens Wiklander */ 325817466cbSJens Wiklander void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms ) 326817466cbSJens Wiklander { 327817466cbSJens Wiklander mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data; 328817466cbSJens Wiklander 329817466cbSJens Wiklander ctx->int_ms = int_ms; 330817466cbSJens Wiklander ctx->fin_ms = fin_ms; 331817466cbSJens Wiklander 332817466cbSJens Wiklander if( fin_ms != 0 ) 333817466cbSJens Wiklander (void) mbedtls_timing_get_timer( &ctx->timer, 1 ); 334817466cbSJens Wiklander } 335817466cbSJens Wiklander 336817466cbSJens Wiklander /* 337817466cbSJens Wiklander * Get number of delays expired 338817466cbSJens Wiklander */ 339817466cbSJens Wiklander int mbedtls_timing_get_delay( void *data ) 340817466cbSJens Wiklander { 341817466cbSJens Wiklander mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data; 342817466cbSJens Wiklander unsigned long elapsed_ms; 343817466cbSJens Wiklander 344817466cbSJens Wiklander if( ctx->fin_ms == 0 ) 345817466cbSJens Wiklander return( -1 ); 346817466cbSJens Wiklander 347817466cbSJens Wiklander elapsed_ms = mbedtls_timing_get_timer( &ctx->timer, 0 ); 348817466cbSJens Wiklander 349817466cbSJens Wiklander if( elapsed_ms >= ctx->fin_ms ) 350817466cbSJens Wiklander return( 2 ); 351817466cbSJens Wiklander 352817466cbSJens Wiklander if( elapsed_ms >= ctx->int_ms ) 353817466cbSJens Wiklander return( 1 ); 354817466cbSJens Wiklander 355817466cbSJens Wiklander return( 0 ); 356817466cbSJens Wiklander } 357817466cbSJens Wiklander 358817466cbSJens Wiklander #endif /* !MBEDTLS_TIMING_ALT */ 359817466cbSJens Wiklander 360817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST) 361817466cbSJens Wiklander 362817466cbSJens Wiklander /* 363817466cbSJens Wiklander * Busy-waits for the given number of milliseconds. 364817466cbSJens Wiklander * Used for testing mbedtls_timing_hardclock. 365817466cbSJens Wiklander */ 366817466cbSJens Wiklander static void busy_msleep( unsigned long msec ) 367817466cbSJens Wiklander { 368817466cbSJens Wiklander struct mbedtls_timing_hr_time hires; 369817466cbSJens Wiklander unsigned long i = 0; /* for busy-waiting */ 370817466cbSJens Wiklander volatile unsigned long j; /* to prevent optimisation */ 371817466cbSJens Wiklander 372817466cbSJens Wiklander (void) mbedtls_timing_get_timer( &hires, 1 ); 373817466cbSJens Wiklander 374817466cbSJens Wiklander while( mbedtls_timing_get_timer( &hires, 0 ) < msec ) 375817466cbSJens Wiklander i++; 376817466cbSJens Wiklander 377817466cbSJens Wiklander j = i; 378817466cbSJens Wiklander (void) j; 379817466cbSJens Wiklander } 380817466cbSJens Wiklander 381817466cbSJens Wiklander #define FAIL do \ 382817466cbSJens Wiklander { \ 383817466cbSJens Wiklander if( verbose != 0 ) \ 384817466cbSJens Wiklander mbedtls_printf( "failed\n" ); \ 385817466cbSJens Wiklander \ 386817466cbSJens Wiklander return( 1 ); \ 387817466cbSJens Wiklander } while( 0 ) 388817466cbSJens Wiklander 389817466cbSJens Wiklander /* 390817466cbSJens Wiklander * Checkup routine 391817466cbSJens Wiklander * 392817466cbSJens Wiklander * Warning: this is work in progress, some tests may not be reliable enough 393817466cbSJens Wiklander * yet! False positives may happen. 394817466cbSJens Wiklander */ 395817466cbSJens Wiklander int mbedtls_timing_self_test( int verbose ) 396817466cbSJens Wiklander { 397817466cbSJens Wiklander unsigned long cycles, ratio; 398817466cbSJens Wiklander unsigned long millisecs, secs; 399817466cbSJens Wiklander int hardfail; 400817466cbSJens Wiklander struct mbedtls_timing_hr_time hires; 401817466cbSJens Wiklander uint32_t a, b; 402817466cbSJens Wiklander mbedtls_timing_delay_context ctx; 403817466cbSJens Wiklander 404817466cbSJens Wiklander if( verbose != 0 ) 405817466cbSJens Wiklander mbedtls_printf( " TIMING tests note: will take some time!\n" ); 406817466cbSJens Wiklander 407817466cbSJens Wiklander 408817466cbSJens Wiklander if( verbose != 0 ) 409817466cbSJens Wiklander mbedtls_printf( " TIMING test #1 (set_alarm / get_timer): " ); 410817466cbSJens Wiklander 411817466cbSJens Wiklander for( secs = 1; secs <= 3; secs++ ) 412817466cbSJens Wiklander { 413817466cbSJens Wiklander (void) mbedtls_timing_get_timer( &hires, 1 ); 414817466cbSJens Wiklander 415817466cbSJens Wiklander mbedtls_set_alarm( (int) secs ); 416817466cbSJens Wiklander while( !mbedtls_timing_alarmed ) 417817466cbSJens Wiklander ; 418817466cbSJens Wiklander 419817466cbSJens Wiklander millisecs = mbedtls_timing_get_timer( &hires, 0 ); 420817466cbSJens Wiklander 421817466cbSJens Wiklander /* For some reason on Windows it looks like alarm has an extra delay 422817466cbSJens Wiklander * (maybe related to creating a new thread). Allow some room here. */ 423817466cbSJens Wiklander if( millisecs < 800 * secs || millisecs > 1200 * secs + 300 ) 424817466cbSJens Wiklander { 425817466cbSJens Wiklander if( verbose != 0 ) 426817466cbSJens Wiklander mbedtls_printf( "failed\n" ); 427817466cbSJens Wiklander 428817466cbSJens Wiklander return( 1 ); 429817466cbSJens Wiklander } 430817466cbSJens Wiklander } 431817466cbSJens Wiklander 432817466cbSJens Wiklander if( verbose != 0 ) 433817466cbSJens Wiklander mbedtls_printf( "passed\n" ); 434817466cbSJens Wiklander 435817466cbSJens Wiklander if( verbose != 0 ) 436817466cbSJens Wiklander mbedtls_printf( " TIMING test #2 (set/get_delay ): " ); 437817466cbSJens Wiklander 438817466cbSJens Wiklander for( a = 200; a <= 400; a += 200 ) 439817466cbSJens Wiklander { 440817466cbSJens Wiklander for( b = 200; b <= 400; b += 200 ) 441817466cbSJens Wiklander { 442817466cbSJens Wiklander mbedtls_timing_set_delay( &ctx, a, a + b ); 443817466cbSJens Wiklander 444817466cbSJens Wiklander busy_msleep( a - a / 8 ); 445817466cbSJens Wiklander if( mbedtls_timing_get_delay( &ctx ) != 0 ) 446817466cbSJens Wiklander FAIL; 447817466cbSJens Wiklander 448817466cbSJens Wiklander busy_msleep( a / 4 ); 449817466cbSJens Wiklander if( mbedtls_timing_get_delay( &ctx ) != 1 ) 450817466cbSJens Wiklander FAIL; 451817466cbSJens Wiklander 452817466cbSJens Wiklander busy_msleep( b - a / 8 - b / 8 ); 453817466cbSJens Wiklander if( mbedtls_timing_get_delay( &ctx ) != 1 ) 454817466cbSJens Wiklander FAIL; 455817466cbSJens Wiklander 456817466cbSJens Wiklander busy_msleep( b / 4 ); 457817466cbSJens Wiklander if( mbedtls_timing_get_delay( &ctx ) != 2 ) 458817466cbSJens Wiklander FAIL; 459817466cbSJens Wiklander } 460817466cbSJens Wiklander } 461817466cbSJens Wiklander 462817466cbSJens Wiklander mbedtls_timing_set_delay( &ctx, 0, 0 ); 463817466cbSJens Wiklander busy_msleep( 200 ); 464817466cbSJens Wiklander if( mbedtls_timing_get_delay( &ctx ) != -1 ) 465817466cbSJens Wiklander FAIL; 466817466cbSJens Wiklander 467817466cbSJens Wiklander if( verbose != 0 ) 468817466cbSJens Wiklander mbedtls_printf( "passed\n" ); 469817466cbSJens Wiklander 470817466cbSJens Wiklander if( verbose != 0 ) 471817466cbSJens Wiklander mbedtls_printf( " TIMING test #3 (hardclock / get_timer): " ); 472817466cbSJens Wiklander 473817466cbSJens Wiklander /* 474817466cbSJens Wiklander * Allow one failure for possible counter wrapping. 475817466cbSJens Wiklander * On a 4Ghz 32-bit machine the cycle counter wraps about once per second; 476817466cbSJens Wiklander * since the whole test is about 10ms, it shouldn't happen twice in a row. 477817466cbSJens Wiklander */ 478817466cbSJens Wiklander hardfail = 0; 479817466cbSJens Wiklander 480817466cbSJens Wiklander hard_test: 481817466cbSJens Wiklander if( hardfail > 1 ) 482817466cbSJens Wiklander { 483817466cbSJens Wiklander if( verbose != 0 ) 484817466cbSJens Wiklander mbedtls_printf( "failed (ignored)\n" ); 485817466cbSJens Wiklander 486817466cbSJens Wiklander goto hard_test_done; 487817466cbSJens Wiklander } 488817466cbSJens Wiklander 489817466cbSJens Wiklander /* Get a reference ratio cycles/ms */ 490817466cbSJens Wiklander millisecs = 1; 491817466cbSJens Wiklander cycles = mbedtls_timing_hardclock(); 492817466cbSJens Wiklander busy_msleep( millisecs ); 493817466cbSJens Wiklander cycles = mbedtls_timing_hardclock() - cycles; 494817466cbSJens Wiklander ratio = cycles / millisecs; 495817466cbSJens Wiklander 496817466cbSJens Wiklander /* Check that the ratio is mostly constant */ 497817466cbSJens Wiklander for( millisecs = 2; millisecs <= 4; millisecs++ ) 498817466cbSJens Wiklander { 499817466cbSJens Wiklander cycles = mbedtls_timing_hardclock(); 500817466cbSJens Wiklander busy_msleep( millisecs ); 501817466cbSJens Wiklander cycles = mbedtls_timing_hardclock() - cycles; 502817466cbSJens Wiklander 503817466cbSJens Wiklander /* Allow variation up to 20% */ 504817466cbSJens Wiklander if( cycles / millisecs < ratio - ratio / 5 || 505817466cbSJens Wiklander cycles / millisecs > ratio + ratio / 5 ) 506817466cbSJens Wiklander { 507817466cbSJens Wiklander hardfail++; 508817466cbSJens Wiklander goto hard_test; 509817466cbSJens Wiklander } 510817466cbSJens Wiklander } 511817466cbSJens Wiklander 512817466cbSJens Wiklander if( verbose != 0 ) 513817466cbSJens Wiklander mbedtls_printf( "passed\n" ); 514817466cbSJens Wiklander 515817466cbSJens Wiklander hard_test_done: 516817466cbSJens Wiklander 517817466cbSJens Wiklander if( verbose != 0 ) 518817466cbSJens Wiklander mbedtls_printf( "\n" ); 519817466cbSJens Wiklander 520817466cbSJens Wiklander return( 0 ); 521817466cbSJens Wiklander } 522817466cbSJens Wiklander 523817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */ 524817466cbSJens Wiklander 525817466cbSJens Wiklander #endif /* MBEDTLS_TIMING_C */ 526