mirror of
https://github.com/stefanberger/libtpms
synced 2026-01-09 05:50:48 +00:00
Replace _plat__ClockAdjustRate with _plat__ClockRateAdjust and use its new #defines at the call sites. Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
395 lines
15 KiB
C
395 lines
15 KiB
C
/********************************************************************************/
|
|
/* */
|
|
/* Used by the simulator to mimic a hardware clock */
|
|
/* Written by Ken Goldman */
|
|
/* IBM Thomas J. Watson Research Center */
|
|
/* */
|
|
/* Licenses and Notices */
|
|
/* */
|
|
/* 1. Copyright Licenses: */
|
|
/* */
|
|
/* - Trusted Computing Group (TCG) grants to the user of the source code in */
|
|
/* this specification (the "Source Code") a worldwide, irrevocable, */
|
|
/* nonexclusive, royalty free, copyright license to reproduce, create */
|
|
/* derivative works, distribute, display and perform the Source Code and */
|
|
/* derivative works thereof, and to grant others the rights granted herein. */
|
|
/* */
|
|
/* - The TCG grants to the user of the other parts of the specification */
|
|
/* (other than the Source Code) the rights to reproduce, distribute, */
|
|
/* display, and perform the specification solely for the purpose of */
|
|
/* developing products based on such documents. */
|
|
/* */
|
|
/* 2. Source Code Distribution Conditions: */
|
|
/* */
|
|
/* - Redistributions of Source Code must retain the above copyright licenses, */
|
|
/* this list of conditions and the following disclaimers. */
|
|
/* */
|
|
/* - Redistributions in binary form must reproduce the above copyright */
|
|
/* licenses, this list of conditions and the following disclaimers in the */
|
|
/* documentation and/or other materials provided with the distribution. */
|
|
/* */
|
|
/* 3. Disclaimers: */
|
|
/* */
|
|
/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */
|
|
/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */
|
|
/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */
|
|
/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */
|
|
/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */
|
|
/* information on specification licensing rights available through TCG */
|
|
/* membership agreements. */
|
|
/* */
|
|
/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */
|
|
/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */
|
|
/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */
|
|
/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */
|
|
/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */
|
|
/* */
|
|
/* - Without limitation, TCG and its members and licensors disclaim all */
|
|
/* liability, including liability for infringement of any proprietary */
|
|
/* rights, relating to use of information in this specification and to the */
|
|
/* implementation of this specification, and TCG disclaims all liability for */
|
|
/* cost of procurement of substitute goods or services, lost profits, loss */
|
|
/* of use, loss of data or any incidental, consequential, direct, indirect, */
|
|
/* or special damages, whether under contract, tort, warranty or otherwise, */
|
|
/* arising in any way out of use or reliance upon this specification or any */
|
|
/* information herein. */
|
|
/* */
|
|
/* (c) Copyright IBM Corp. and others, 2016 - 2023 */
|
|
/* */
|
|
/********************************************************************************/
|
|
|
|
//** Description
|
|
//
|
|
// This file contains the routines that are used by the simulator to mimic
|
|
// a hardware clock on a TPM.
|
|
//
|
|
// In this implementation, all the time values are measured in millisecond.
|
|
// However, the precision of the clock functions may be implementation dependent.
|
|
|
|
//** Includes and Data Definitions
|
|
#include <assert.h>
|
|
#include "Platform.h"
|
|
|
|
// CLOCK_NOMINAL is the number of hardware ticks per ms. A value of 30000 means
|
|
// that the nominal clock rate used to drive the hardware clock is 30 MHz. The
|
|
// adjustment rates are used to determine the conversion of the hardware ticks to
|
|
// internal hardware clock value. In practice, we would expect that there would be
|
|
// a hardware register will accumulated mS. It would be incremented by the output
|
|
// of a pre-scaler. The pre-scaler would divide the ticks from the clock by some
|
|
// value that would compensate for the difference between clock time and real time.
|
|
// The code in Clock does the emulation of this function.
|
|
#define CLOCK_NOMINAL 30000
|
|
// A 1% change in rate is 300 counts
|
|
#define CLOCK_ADJUST_COARSE 300
|
|
// A 0.1% change in rate is 30 counts
|
|
#define CLOCK_ADJUST_MEDIUM 30
|
|
// A minimum change in rate is 1 count
|
|
#define CLOCK_ADJUST_FINE 1
|
|
// The clock tolerance is +/-15% (4500 counts)
|
|
// Allow some guard band (16.7%)
|
|
#define CLOCK_ADJUST_LIMIT 5000
|
|
|
|
/* libtpms added begin */
|
|
/* ClockGetTime -- get time given a specified clock type */
|
|
uint64_t
|
|
ClockGetTime(
|
|
clockid_t clk_id
|
|
)
|
|
{
|
|
uint64_t time;
|
|
#ifdef TPM_WINDOWS
|
|
#error Not supported for TPM_WINDOWS
|
|
#else
|
|
struct timespec systime;
|
|
|
|
clock_gettime(clk_id, &systime);
|
|
time = (uint64_t)systime.tv_sec * 1000 + (systime.tv_nsec / 1000000);
|
|
#endif
|
|
|
|
return time;
|
|
}
|
|
|
|
/* ClockAdjustPostResume -- adjust time parameters post resume */
|
|
#include "Tpm.h"
|
|
void
|
|
ClockAdjustPostResume(UINT64 backthen, BOOL timesAreRealtime)
|
|
{
|
|
UINT64 now = ClockGetTime(CLOCK_REALTIME);
|
|
INT64 timediff = now - backthen;
|
|
|
|
if (timesAreRealtime) {
|
|
/* g_time, s_realTimePrevious, s_tpmTime are all in real time */
|
|
s_suspendedElapsedTime = now;
|
|
s_hostMonotonicAdjustTime = -ClockGetTime(CLOCK_MONOTONIC);
|
|
|
|
/* s_lastSystemTime & s_lastReportTime need to be set as well */
|
|
s_lastSystemTime = now;
|
|
s_lastReportedTime = now;
|
|
} else if (timediff >= 0) {
|
|
s_suspendedElapsedTime += timediff;
|
|
}
|
|
}
|
|
/* libtpms added end */
|
|
|
|
//** Simulator Functions
|
|
//*** Introduction
|
|
// This set of functions is intended to be called by the simulator environment in
|
|
// order to simulate hardware events.
|
|
|
|
//***_plat__TimerReset()
|
|
// This function sets current system clock time as t0 for counting TPM time.
|
|
// This function is called at a power on event to reset the clock. When the clock
|
|
// is reset, the indication that the clock was stopped is also set.
|
|
LIB_EXPORT void _plat__TimerReset(void)
|
|
{
|
|
s_lastSystemTime = 0;
|
|
s_tpmTime = 0;
|
|
s_adjustRate = CLOCK_NOMINAL;
|
|
s_timerReset = TRUE;
|
|
s_timerStopped = TRUE;
|
|
s_hostMonotonicAdjustTime = 0; /* libtpms added */
|
|
s_suspendedElapsedTime = 0; /* libtpms added */
|
|
return;
|
|
}
|
|
|
|
//*** _plat__TimerRestart()
|
|
// This function should be called in order to simulate the restart of the timer
|
|
// should it be stopped while power is still applied.
|
|
LIB_EXPORT void _plat__TimerRestart(void)
|
|
{
|
|
s_timerStopped = TRUE;
|
|
return;
|
|
}
|
|
|
|
//** Functions Used by TPM
|
|
//*** Introduction
|
|
// These functions are called by the TPM code. They should be replaced by
|
|
// appropriated hardware functions.
|
|
|
|
#include <time.h>
|
|
clock_t debugTime;
|
|
|
|
//*** _plat__RealTime()
|
|
// This is another, probably futile, attempt to define a portable function
|
|
// that will return a 64-bit clock value that has mSec resolution.
|
|
LIB_EXPORT uint64_t _plat__RealTime(void)
|
|
{
|
|
clock64_t time;
|
|
//#ifdef _MSC_VER kgold
|
|
#ifdef TPM_WINDOWS
|
|
#include <sys/timeb.h>
|
|
struct _timeb sysTime;
|
|
//
|
|
_ftime(&sysTime); /* kgold, mingw doesn't have _ftime_s */
|
|
time = (clock64_t)(sysTime.time) * 1000 + sysTime.millitm;
|
|
// set the time back by one hour if daylight savings
|
|
if(sysTime.dstflag)
|
|
time -= 1000 * 60 * 60; // mSec/sec * sec/min * min/hour = ms/hour
|
|
#else
|
|
// hopefully, this will work with most UNIX systems
|
|
struct timespec systime;
|
|
//
|
|
clock_gettime(CLOCK_MONOTONIC, &systime);
|
|
time = (clock64_t)systime.tv_sec * 1000 + (systime.tv_nsec / 1000000);
|
|
#endif
|
|
/* libtpms added begin */
|
|
/* We have to make sure that this function returns monotonically increasing time
|
|
also when a vTPM has been suspended and the host has been rebooted.
|
|
Example:
|
|
- The vTPM is suspended at systime '5'
|
|
- The vTPM is resumed at systime '1' after a host reboot
|
|
-> we now need to add '4' to the time
|
|
Besides this we want to account for the time a vTPM was suspended.
|
|
If it was suspended for 10 time units, we need to add '10' here.
|
|
*/
|
|
time += s_hostMonotonicAdjustTime + s_suspendedElapsedTime;
|
|
/* libtpms added end */
|
|
return time;
|
|
}
|
|
|
|
//***_plat__TimerRead()
|
|
// This function provides access to the tick timer of the platform. The TPM code
|
|
// uses this value to drive the TPM Clock.
|
|
//
|
|
// The tick timer is supposed to run when power is applied to the device. This timer
|
|
// should not be reset by time events including _TPM_Init. It should only be reset
|
|
// when TPM power is re-applied.
|
|
//
|
|
// If the TPM is run in a protected environment, that environment may provide the
|
|
// tick time to the TPM as long as the time provided by the environment is not
|
|
// allowed to go backwards. If the time provided by the system can go backwards
|
|
// during a power discontinuity, then the _plat__Signal_PowerOn should call
|
|
// _plat__TimerReset().
|
|
LIB_EXPORT uint64_t _plat__TimerRead(void)
|
|
{
|
|
#ifdef HARDWARE_CLOCK
|
|
# error "need a defintion for reading the hardware clock"
|
|
return HARDWARE_CLOCK
|
|
#else
|
|
clock64_t timeDiff;
|
|
clock64_t adjustedTimeDiff;
|
|
clock64_t timeNow;
|
|
clock64_t readjustedTimeDiff;
|
|
|
|
// This produces a timeNow that is basically locked to the system clock.
|
|
timeNow = _plat__RealTime();
|
|
|
|
// if this hasn't been initialized, initialize it
|
|
if(s_lastSystemTime == 0)
|
|
{
|
|
s_lastSystemTime = timeNow;
|
|
debugTime = clock();
|
|
s_lastReportedTime = 0;
|
|
s_realTimePrevious = 0;
|
|
}
|
|
// The system time can bounce around and that's OK as long as we don't allow
|
|
// time to go backwards. When the time does appear to go backwards, set
|
|
// lastSystemTime to be the new value and then update the reported time.
|
|
if(timeNow < s_lastReportedTime)
|
|
s_lastSystemTime = timeNow;
|
|
s_lastReportedTime = s_lastReportedTime + timeNow - s_lastSystemTime;
|
|
s_lastSystemTime = timeNow;
|
|
timeNow = s_lastReportedTime;
|
|
|
|
// The code above produces a timeNow that is similar to the value returned
|
|
// by Clock(). The difference is that timeNow does not max out, and it is
|
|
// at a ms. rate rather than at a CLOCKS_PER_SEC rate. The code below
|
|
// uses that value and does the rate adjustment on the time value.
|
|
// If there is no difference in time, then skip all the computations
|
|
if(s_realTimePrevious >= timeNow)
|
|
return s_tpmTime;
|
|
// Compute the amount of time since the last update of the system clock
|
|
timeDiff = timeNow - s_realTimePrevious;
|
|
|
|
// Do the time rate adjustment and conversion from CLOCKS_PER_SEC to mSec
|
|
adjustedTimeDiff = (timeDiff * CLOCK_NOMINAL) / ((uint64_t)s_adjustRate);
|
|
|
|
// update the TPM time with the adjusted timeDiff
|
|
s_tpmTime += (clock64_t)adjustedTimeDiff;
|
|
|
|
// Might have some rounding error that would loose CLOCKS. See what is not
|
|
// being used. As mentioned above, this could result in putting back more than
|
|
// is taken out. Here, we are trying to recreate timeDiff.
|
|
readjustedTimeDiff = (adjustedTimeDiff * (uint64_t)s_adjustRate) / CLOCK_NOMINAL;
|
|
|
|
// adjusted is now converted back to being the amount we should advance the
|
|
// previous sampled time. It should always be less than or equal to timeDiff.
|
|
// That is, we could not have use more time than we started with.
|
|
s_realTimePrevious = s_realTimePrevious + readjustedTimeDiff;
|
|
|
|
# ifdef DEBUGGING_TIME
|
|
// Put this in so that TPM time will pass much faster than real time when
|
|
// doing debug.
|
|
// A value of 1000 for DEBUG_TIME_MULTIPLER will make each ms into a second
|
|
// A good value might be 100
|
|
return (s_tpmTime * DEBUG_TIME_MULTIPLIER);
|
|
# endif
|
|
return s_tpmTime;
|
|
#endif
|
|
}
|
|
|
|
//*** _plat__TimerWasReset()
|
|
// This function is used to interrogate the flag indicating if the tick timer has
|
|
// been reset.
|
|
//
|
|
// If the resetFlag parameter is SET, then the flag will be CLEAR before the
|
|
// function returns.
|
|
LIB_EXPORT int _plat__TimerWasReset(void)
|
|
{
|
|
int retVal = s_timerReset;
|
|
s_timerReset = FALSE;
|
|
return retVal;
|
|
}
|
|
|
|
//*** _plat__TimerWasStopped()
|
|
// This function is used to interrogate the flag indicating if the tick timer has
|
|
// been stopped. If so, this is typically a reason to roll the nonce.
|
|
//
|
|
// This function will CLEAR the s_timerStopped flag before returning. This provides
|
|
// functionality that is similar to status register that is cleared when read. This
|
|
// is the model used here because it is the one that has the most impact on the TPM
|
|
// code as the flag can only be accessed by one entity in the TPM. Any other
|
|
// implementation of the hardware can be made to look like a read-once register.
|
|
LIB_EXPORT int _plat__TimerWasStopped(void)
|
|
{
|
|
int retVal = s_timerStopped;
|
|
s_timerStopped = FALSE;
|
|
return retVal;
|
|
}
|
|
|
|
//***_plat__ClockAdjustRate()
|
|
// Adjust the clock rate
|
|
LIB_EXPORT void _plat__ClockRateAdjust(_plat__ClockAdjustStep adjust)
|
|
{
|
|
// We expect the caller should only use a fixed set of constant values to
|
|
// adjust the rate
|
|
switch(adjust)
|
|
{
|
|
// slower increases the divisor
|
|
case PLAT_TPM_CLOCK_ADJUST_COARSE_SLOWER:
|
|
s_adjustRate += CLOCK_ADJUST_COARSE;
|
|
break;
|
|
case PLAT_TPM_CLOCK_ADJUST_MEDIUM_SLOWER:
|
|
s_adjustRate += CLOCK_ADJUST_MEDIUM;
|
|
break;
|
|
case PLAT_TPM_CLOCK_ADJUST_FINE_SLOWER:
|
|
s_adjustRate += CLOCK_ADJUST_FINE;
|
|
break;
|
|
// faster decreases the divisor
|
|
case PLAT_TPM_CLOCK_ADJUST_FINE_FASTER:
|
|
s_adjustRate -= CLOCK_ADJUST_FINE;
|
|
break;
|
|
case PLAT_TPM_CLOCK_ADJUST_MEDIUM_FASTER:
|
|
s_adjustRate -= CLOCK_ADJUST_MEDIUM;
|
|
break;
|
|
case PLAT_TPM_CLOCK_ADJUST_COARSE_FASTER:
|
|
s_adjustRate -= CLOCK_ADJUST_COARSE;
|
|
break;
|
|
}
|
|
|
|
if(s_adjustRate > (CLOCK_NOMINAL + CLOCK_ADJUST_LIMIT))
|
|
s_adjustRate = CLOCK_NOMINAL + CLOCK_ADJUST_LIMIT;
|
|
if(s_adjustRate < (CLOCK_NOMINAL - CLOCK_ADJUST_LIMIT))
|
|
s_adjustRate = CLOCK_NOMINAL - CLOCK_ADJUST_LIMIT;
|
|
|
|
return;
|
|
}
|
|
|
|
#if 0
|
|
|
|
/* added for portability because Linux clock is 32 bits */
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
|
|
#include "TpmFail_fp.h"
|
|
|
|
LIB_EXPORT uint64_t
|
|
_plat__RealTime(
|
|
void
|
|
)
|
|
{
|
|
clock64_t time;
|
|
//#ifdef _MSC_VER kgold
|
|
#ifdef TPM_WINDOWS
|
|
#include <sys/timeb.h>
|
|
struct _timeb sysTime;
|
|
//
|
|
_ftime(&sysTime); /* kgold, mingw doesn't have _ftime_s */
|
|
time = (clock64_t)(sysTime.time) * 1000 + sysTime.millitm;
|
|
// set the time back by one hour if daylight savings
|
|
if(sysTime.dstflag)
|
|
time -= 1000 * 60 * 60; // mSec/sec * sec/min * min/hour = ms/hour
|
|
#else
|
|
// hopefully, this will work with most UNIX systems
|
|
struct timespec systime;
|
|
//
|
|
clock_gettime(CLOCK_MONOTONIC, &systime);
|
|
time = (clock64_t)systime.tv_sec * 1000 + (systime.tv_nsec / 1000000);
|
|
#endif
|
|
return time;
|
|
}
|
|
|
|
#endif
|