/* Microsoft Reference Implementation for TPM 2.0 | |
* | |
* The copyright in this software is being made available under the BSD License, | |
* included below. This software may be subject to other third party and | |
* contributor rights, including patent rights, and no such rights are granted | |
* under this license. | |
* | |
* Copyright (c) Microsoft Corporation | |
* | |
* All rights reserved. | |
* | |
* BSD License | |
* | |
* Redistribution and use in source and binary forms, with or without modification, | |
* are permitted provided that the following conditions are met: | |
* | |
* Redistributions of source code must retain the above copyright notice, this list | |
* of conditions and the following disclaimer. | |
* | |
* Redistributions in binary form must reproduce the above copyright notice, this | |
* list of conditions and the following disclaimer in the documentation and/or | |
* other materials provided with the distribution. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" | |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | |
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
//** 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" | |
#include "TpmFail_fp.h" | |
//** 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 <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 | |
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__ClockAdjustRate( | |
int adjust // IN: the adjust number. It could be positive | |
// or negative | |
) | |
{ | |
// We expect the caller should only use a fixed set of constant values to | |
// adjust the rate | |
switch(adjust) | |
{ | |
case CLOCK_ADJUST_COARSE: | |
s_adjustRate += CLOCK_ADJUST_COARSE; | |
break; | |
case -CLOCK_ADJUST_COARSE: | |
s_adjustRate -= CLOCK_ADJUST_COARSE; | |
break; | |
case CLOCK_ADJUST_MEDIUM: | |
s_adjustRate += CLOCK_ADJUST_MEDIUM; | |
break; | |
case -CLOCK_ADJUST_MEDIUM: | |
s_adjustRate -= CLOCK_ADJUST_MEDIUM; | |
break; | |
case CLOCK_ADJUST_FINE: | |
s_adjustRate += CLOCK_ADJUST_FINE; | |
break; | |
case -CLOCK_ADJUST_FINE: | |
s_adjustRate -= CLOCK_ADJUST_FINE; | |
break; | |
default: | |
// ignore any other values; | |
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; | |
} | |