/********************************************************************************/ /* */ /* 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 #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 //** 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; 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 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 struct _timeb sysTime; // _ftime_s(&sysTime); 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; } //***_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 #include #include #include "TpmFail_fp.h" LIB_EXPORT uint64_t _plat__RealTime( void ) { clock64_t time; //#ifdef _MSC_VER kgold #ifdef TPM_WINDOWS #include 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