mirror of https://github.com/wolfSSL/wolfTPM.git
Bound TIS wait loops by real time where a monotonic clock exists
parent
4fe76e2ad9
commit
192c59ee5d
115
src/tpm2_tis.c
115
src/tpm2_tis.c
|
|
@ -417,22 +417,115 @@ int TPM2_TIS_Status(TPM2_CTX* ctx, byte* status)
|
|||
sizeof(*status));
|
||||
}
|
||||
|
||||
/* Budget for the wait loops below. An iteration count makes the real timeout
|
||||
* depend on host speed, so a >20 s RSA key generation times out intermittently.
|
||||
* Use TPM_TIMEOUT_MS of real time where a monotonic clock exists; elsewhere
|
||||
* keep counting exactly as before so no port gains a requirement. */
|
||||
typedef struct TPM2_TIS_TIMEOUT {
|
||||
#ifdef WOLFTPM_HAVE_MONOTONIC_MS
|
||||
word32 start;
|
||||
int haveStart;
|
||||
#endif
|
||||
#if defined(DEBUG_WOLFTPM) && !defined(WOLFTPM_NO_STD_HEADERS) && \
|
||||
defined(WOLFTPM_HAVE_MONOTONIC_MS)
|
||||
#define WOLFTPM_TIS_PROGRESS
|
||||
word32 secs; /* whole seconds already marked with a dot */
|
||||
#endif
|
||||
int tries;
|
||||
} TPM2_TIS_TIMEOUT;
|
||||
|
||||
static void TPM2_TIS_TimeoutStart(TPM2_TIS_TIMEOUT* to)
|
||||
{
|
||||
XMEMSET(to, 0, sizeof(*to));
|
||||
to->tries = TPM_TIMEOUT_TRIES;
|
||||
#ifdef WOLFTPM_HAVE_MONOTONIC_MS
|
||||
to->start = XTPM_GET_TIMEMS();
|
||||
/* zero tick means the clock could not be read; count instead */
|
||||
to->haveStart = (to->start != 0) ? 1 : 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Returns 1 once the budget is spent, 0 while there is still time. */
|
||||
static int TPM2_TIS_TimeoutExpired(TPM2_TIS_TIMEOUT* to)
|
||||
{
|
||||
#ifdef WOLFTPM_HAVE_MONOTONIC_MS
|
||||
word32 elapsed;
|
||||
#endif
|
||||
|
||||
if (to->tries > 0) {
|
||||
to->tries--;
|
||||
}
|
||||
#ifdef WOLFTPM_HAVE_MONOTONIC_MS
|
||||
if (to->haveStart) {
|
||||
/* unsigned subtraction stays correct across the word32 wrap */
|
||||
elapsed = (word32)(XTPM_GET_TIMEMS() - to->start);
|
||||
if (elapsed >= TPM_TIMEOUT_MS) {
|
||||
return 1;
|
||||
}
|
||||
#ifdef WOLFTPM_TIS_PROGRESS
|
||||
/* Waits of a minute or more are normal for key generation, so show a
|
||||
* dot per second rather than let a slow command look like a hang. */
|
||||
if (elapsed / 1000u > to->secs) {
|
||||
to->secs = elapsed / 1000u;
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif
|
||||
/* A clock stuck at one value would never expire, so keep the
|
||||
* iteration cap as a backstop for that case only. */
|
||||
return (to->tries <= 0 && elapsed == 0) ? 1 : 0;
|
||||
}
|
||||
#endif
|
||||
return (to->tries <= 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
#ifdef WOLFTPM_TIS_PROGRESS
|
||||
/* End the dot line, if any were printed. */
|
||||
static void TPM2_TIS_TimeoutDone(TPM2_TIS_TIMEOUT* to)
|
||||
{
|
||||
if (to->secs > 0) {
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define TPM2_TIS_TimeoutDone(to) (void)(to)
|
||||
#endif
|
||||
|
||||
#ifdef WOLFTPM_DEBUG_TIMEOUT
|
||||
/* Elapsed ms where a clock exists, else polls taken. */
|
||||
static word32 TPM2_TIS_TimeoutSpent(TPM2_TIS_TIMEOUT* to)
|
||||
{
|
||||
#ifdef WOLFTPM_HAVE_MONOTONIC_MS
|
||||
if (to->haveStart) {
|
||||
return (word32)(XTPM_GET_TIMEMS() - to->start);
|
||||
}
|
||||
#endif
|
||||
return (word32)(TPM_TIMEOUT_TRIES - to->tries);
|
||||
}
|
||||
#endif
|
||||
|
||||
int TPM2_TIS_WaitForStatus(TPM2_CTX* ctx, byte status, byte status_mask)
|
||||
{
|
||||
int rc;
|
||||
int timeout = TPM_TIMEOUT_TRIES;
|
||||
int expired = 0;
|
||||
TPM2_TIS_TIMEOUT to;
|
||||
byte reg = 0;
|
||||
|
||||
TPM2_TIS_TimeoutStart(&to);
|
||||
do {
|
||||
rc = TPM2_TIS_Status(ctx, ®);
|
||||
if (rc == TPM_RC_SUCCESS && (reg & status) == status_mask)
|
||||
break;
|
||||
XTPM_WAIT();
|
||||
} while (rc == TPM_RC_SUCCESS && --timeout > 0);
|
||||
expired = TPM2_TIS_TimeoutExpired(&to);
|
||||
} while (rc == TPM_RC_SUCCESS && !expired);
|
||||
TPM2_TIS_TimeoutDone(&to);
|
||||
#ifdef WOLFTPM_DEBUG_TIMEOUT
|
||||
printf("TIS_WaitForStatus: Timeout %d\n", TPM_TIMEOUT_TRIES - timeout);
|
||||
printf("TIS_WaitForStatus: spent %u\n",
|
||||
(unsigned int)TPM2_TIS_TimeoutSpent(&to));
|
||||
#endif
|
||||
if (timeout <= 0)
|
||||
if (expired)
|
||||
return TPM_RC_TIMEOUT;
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -458,7 +551,10 @@ int TPM2_TIS_GetBurstCount(TPM2_CTX* ctx, word16* burstCount)
|
|||
#endif
|
||||
|
||||
{
|
||||
int timeout = TPM_TIMEOUT_TRIES;
|
||||
int expired = 0;
|
||||
TPM2_TIS_TIMEOUT to;
|
||||
|
||||
TPM2_TIS_TimeoutStart(&to);
|
||||
*burstCount = 0;
|
||||
do {
|
||||
rc = TPM2_TIS_Read(ctx, TPM_BURST_COUNT(ctx->locality),
|
||||
|
|
@ -469,16 +565,19 @@ int TPM2_TIS_GetBurstCount(TPM2_CTX* ctx, word16* burstCount)
|
|||
if (rc == TPM_RC_SUCCESS && *burstCount > 0)
|
||||
break;
|
||||
XTPM_WAIT();
|
||||
} while (rc == TPM_RC_SUCCESS && --timeout > 0);
|
||||
expired = TPM2_TIS_TimeoutExpired(&to);
|
||||
} while (rc == TPM_RC_SUCCESS && !expired);
|
||||
TPM2_TIS_TimeoutDone(&to);
|
||||
|
||||
#ifdef WOLFTPM_DEBUG_TIMEOUT
|
||||
printf("TIS_GetBurstCount: Timeout %d\n", TPM_TIMEOUT_TRIES - timeout);
|
||||
printf("TIS_GetBurstCount: spent %u\n",
|
||||
(unsigned int)TPM2_TIS_TimeoutSpent(&to));
|
||||
#endif
|
||||
|
||||
if (*burstCount > MAX_SPI_FRAMESIZE)
|
||||
*burstCount = MAX_SPI_FRAMESIZE;
|
||||
|
||||
if (timeout <= 0)
|
||||
if (expired)
|
||||
return TPM_RC_TIMEOUT;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -716,6 +716,56 @@ typedef int64_t INT64;
|
|||
#endif
|
||||
#endif
|
||||
|
||||
/* Monotonic ms tick for the TIS wait loops. Wraps ~49 days, so compare with
|
||||
* unsigned subtraction. WOLFTPM_HAVE_MONOTONIC_MS is set only where a clock
|
||||
* exists, port-supplied included; otherwise the iteration counter is kept.
|
||||
* WOLFTPM_NO_MONOTONIC_MS forces the counter. */
|
||||
#ifndef WOLFTPM_NO_MONOTONIC_MS
|
||||
|
||||
/* Without this a port-supplied hook would be silently ignored. */
|
||||
#ifdef XTPM_GET_TIMEMS
|
||||
#define WOLFTPM_HAVE_MONOTONIC_MS
|
||||
#elif !defined(WOLFTPM_NO_STD_HEADERS)
|
||||
#if defined(WOLFTPM_ZEPHYR)
|
||||
#include <zephyr/kernel.h>
|
||||
#define XTPM_GET_TIMEMS() ((word32)k_uptime_get())
|
||||
#define WOLFTPM_HAVE_MONOTONIC_MS
|
||||
#elif defined(WOLFSSL_ESPIDF) || defined(FREERTOS)
|
||||
#define XTPM_GET_TIMEMS() \
|
||||
((word32)xTaskGetTickCount() * (word32)portTICK_PERIOD_MS)
|
||||
#define WOLFTPM_HAVE_MONOTONIC_MS
|
||||
#elif defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#define XTPM_GET_TIMEMS() ((word32)GetTickCount64())
|
||||
#define WOLFTPM_HAVE_MONOTONIC_MS
|
||||
#else
|
||||
/* Include first, then feature-test: strict C99 may not expose
|
||||
* CLOCK_MONOTONIC, and __linux__ alone would fail to compile. */
|
||||
#include <time.h>
|
||||
#if defined(CLOCK_MONOTONIC) && \
|
||||
(!defined(_POSIX_TIMERS) || _POSIX_TIMERS > 0)
|
||||
static inline word32 XTPM_GET_TIMEMS(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
|
||||
return 0;
|
||||
}
|
||||
return (word32)((word32)ts.tv_sec * 1000u +
|
||||
(word32)(ts.tv_nsec / 1000000L));
|
||||
}
|
||||
#define WOLFTPM_HAVE_MONOTONIC_MS
|
||||
#endif
|
||||
#endif
|
||||
#endif /* XTPM_GET_TIMEMS */
|
||||
|
||||
#endif /* !WOLFTPM_NO_MONOTONIC_MS */
|
||||
|
||||
/* Must cover the slowest single command. RSA-2048 key generation has been
|
||||
* measured at 89 s on a current part, so this leaves roughly 2x headroom. */
|
||||
#ifndef TPM_TIMEOUT_MS
|
||||
#define TPM_TIMEOUT_MS 180000
|
||||
#endif
|
||||
|
||||
#ifndef BUFFER_ALIGNMENT
|
||||
#define BUFFER_ALIGNMENT 4
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue