233 lines
7.3 KiB
C
233 lines
7.3 KiB
C
// This file was extracted from the TCG Published
|
|
// Trusted Platform Module Library
|
|
// Part 4: Supporting Routines
|
|
// Family "2.0"
|
|
// Level 00 Revision 01.16
|
|
// October 30, 2014
|
|
|
|
#include "InternalRoutines.h"
|
|
#include "Platform.h"
|
|
// Functions
|
|
//
|
|
// TimePowerOn()
|
|
//
|
|
// This function initialize time info at _TPM_Init().
|
|
//
|
|
void
|
|
TimePowerOn(
|
|
void
|
|
)
|
|
{
|
|
TPM_SU orderlyShutDown;
|
|
// Read orderly data info from NV memory
|
|
NvReadReserved(NV_ORDERLY_DATA, &go);
|
|
// Read orderly shut down state flag
|
|
NvReadReserved(NV_ORDERLY, &orderlyShutDown);
|
|
// If the previous cycle is orderly shut down, the value of the safe bit
|
|
// the same as previously saved. Otherwise, it is not safe.
|
|
if(orderlyShutDown == SHUTDOWN_NONE)
|
|
go.clockSafe= NO;
|
|
else
|
|
go.clockSafe = YES;
|
|
// Set the initial state of the DRBG
|
|
CryptDrbgGetPutState(PUT_STATE);
|
|
// Clear time since TPM power on
|
|
g_time = 0;
|
|
return;
|
|
}
|
|
//
|
|
//
|
|
// TimeStartup()
|
|
//
|
|
// This function updates the resetCount and restartCount components of TPMS_CLOCK_INFO structure at
|
|
// TPM2_Startup().
|
|
//
|
|
void
|
|
TimeStartup(
|
|
STARTUP_TYPE type // IN: start up type
|
|
)
|
|
{
|
|
if(type == SU_RESUME)
|
|
{
|
|
// Resume sequence
|
|
gr.restartCount++;
|
|
}
|
|
else
|
|
{
|
|
if(type == SU_RESTART)
|
|
{
|
|
// Hibernate sequence
|
|
gr.clearCount++;
|
|
gr.restartCount++;
|
|
}
|
|
else
|
|
{
|
|
// Reset sequence
|
|
// Increase resetCount
|
|
gp.resetCount++;
|
|
// Write resetCount to NV
|
|
NvWriteReserved(NV_RESET_COUNT, &gp.resetCount);
|
|
gp.totalResetCount++;
|
|
// We do not expect the total reset counter overflow during the life
|
|
// time of TPM. if it ever happens, TPM will be put to failure mode
|
|
// and there is no way to recover it.
|
|
// The reason that there is no recovery is that we don't increment
|
|
// the NV totalResetCount when incrementing would make it 0. When the
|
|
// TPM starts up again, the old value of totalResetCount will be read
|
|
// and we will get right back to here with the increment failing.
|
|
if(gp.totalResetCount == 0)
|
|
FAIL(FATAL_ERROR_INTERNAL);
|
|
// Write total reset counter to NV
|
|
NvWriteReserved(NV_TOTAL_RESET_COUNT, &gp.totalResetCount);
|
|
// Reset restartCount
|
|
gr.restartCount = 0;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
//
|
|
//
|
|
// TimeUpdateToCurrent()
|
|
//
|
|
// This function updates the Time and Clock in the global TPMS_TIME_INFO structure.
|
|
// In this implementation, Time and Clock are updated at the beginning of each command and the values
|
|
// are unchanged for the duration of the command.
|
|
// Because Clock updates may require a write to NV memory, Time and Clock are not allowed to advance if
|
|
// NV is not available. When clock is not advancing, any function that uses Clock will fail and return
|
|
// TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE.
|
|
// This implementations does not do rate limiting. If the implementation does do rate limiting, then the Clock
|
|
// update should not be inhibited even when doing rather limiting.
|
|
//
|
|
void
|
|
TimeUpdateToCurrent(
|
|
void
|
|
)
|
|
{
|
|
UINT64 oldClock;
|
|
UINT64 elapsed;
|
|
#define CLOCK_UPDATE_MASK ((1ULL << NV_CLOCK_UPDATE_INTERVAL)- 1)
|
|
// Can't update time during the dark interval or when rate limiting.
|
|
if(NvIsAvailable() != TPM_RC_SUCCESS)
|
|
return;
|
|
// Save the old clock value
|
|
oldClock = go.clock;
|
|
// Update the time info to current
|
|
elapsed = _plat__ClockTimeElapsed();
|
|
go.clock += elapsed;
|
|
g_time += elapsed;
|
|
// Check to see if the update has caused a need for an nvClock update
|
|
// CLOCK_UPDATE_MASK is measured by second, while the value in go.clock is
|
|
// recorded by millisecond. Align the clock value to second before the bit
|
|
//
|
|
// operations
|
|
if( ((go.clock/1000) | CLOCK_UPDATE_MASK)
|
|
> ((oldClock/1000) | CLOCK_UPDATE_MASK))
|
|
{
|
|
// Going to update the time state so the safe flag
|
|
// should be set
|
|
go.clockSafe = YES;
|
|
// Get the DRBG state before updating orderly data
|
|
CryptDrbgGetPutState(GET_STATE);
|
|
NvWriteReserved(NV_ORDERLY_DATA, &go);
|
|
}
|
|
// Call self healing logic for dictionary attack parameters
|
|
DASelfHeal();
|
|
return;
|
|
}
|
|
//
|
|
//
|
|
// TimeSetAdjustRate()
|
|
//
|
|
// This function is used to perform rate adjustment on Time and Clock.
|
|
//
|
|
void
|
|
TimeSetAdjustRate(
|
|
TPM_CLOCK_ADJUST adjust // IN: adjust constant
|
|
)
|
|
{
|
|
switch(adjust)
|
|
{
|
|
case TPM_CLOCK_COARSE_SLOWER:
|
|
_plat__ClockAdjustRate(CLOCK_ADJUST_COARSE);
|
|
break;
|
|
case TPM_CLOCK_COARSE_FASTER:
|
|
_plat__ClockAdjustRate(-CLOCK_ADJUST_COARSE);
|
|
break;
|
|
case TPM_CLOCK_MEDIUM_SLOWER:
|
|
_plat__ClockAdjustRate(CLOCK_ADJUST_MEDIUM);
|
|
break;
|
|
case TPM_CLOCK_MEDIUM_FASTER:
|
|
_plat__ClockAdjustRate(-CLOCK_ADJUST_MEDIUM);
|
|
break;
|
|
case TPM_CLOCK_FINE_SLOWER:
|
|
_plat__ClockAdjustRate(CLOCK_ADJUST_FINE);
|
|
break;
|
|
case TPM_CLOCK_FINE_FASTER:
|
|
_plat__ClockAdjustRate(-CLOCK_ADJUST_FINE);
|
|
break;
|
|
case TPM_CLOCK_NO_CHANGE:
|
|
break;
|
|
default:
|
|
pAssert(FALSE);
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
//
|
|
//
|
|
// TimeGetRange()
|
|
//
|
|
// This function is used to access TPMS_TIME_INFO. The TPMS_TIME_INFO structure is treaded as an
|
|
// array of bytes, and a byte offset and length determine what bytes are returned.
|
|
//
|
|
// Error Returns Meaning
|
|
//
|
|
// TPM_RC_RANGE invalid data range
|
|
//
|
|
TPM_RC
|
|
TimeGetRange(
|
|
UINT16 offset, // IN: offset in TPMS_TIME_INFO
|
|
UINT16 size, // IN: size of data
|
|
TIME_INFO *dataBuffer // OUT: result buffer
|
|
)
|
|
{
|
|
TPMS_TIME_INFO timeInfo;
|
|
UINT16 infoSize;
|
|
BYTE infoData[sizeof(TPMS_TIME_INFO)];
|
|
BYTE *buffer;
|
|
INT32 bufferSize;
|
|
// Fill TPMS_TIME_INFO structure
|
|
timeInfo.time = g_time;
|
|
TimeFillInfo(&timeInfo.clockInfo);
|
|
// Marshal TPMS_TIME_INFO to canonical form
|
|
buffer = infoData;
|
|
bufferSize = sizeof(TPMS_TIME_INFO);
|
|
infoSize = TPMS_TIME_INFO_Marshal(&timeInfo, &buffer, &bufferSize);
|
|
// Check if the input range is valid
|
|
if(offset + size > infoSize) return TPM_RC_RANGE;
|
|
// Copy info data to output buffer
|
|
MemoryCopy(dataBuffer, infoData + offset, size, sizeof(TIME_INFO));
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
//
|
|
//
|
|
// TimeFillInfo
|
|
//
|
|
// This function gathers information to fill in a TPMS_CLOCK_INFO structure.
|
|
//
|
|
void
|
|
TimeFillInfo(
|
|
TPMS_CLOCK_INFO *clockInfo
|
|
)
|
|
{
|
|
clockInfo->clock = go.clock;
|
|
clockInfo->resetCount = gp.resetCount;
|
|
clockInfo->restartCount = gr.restartCount;
|
|
// If NV is not available, clock stopped advancing and the value reported is
|
|
// not "safe".
|
|
if(NvIsAvailable() == TPM_RC_SUCCESS)
|
|
clockInfo->safe = go.clockSafe;
|
|
else
|
|
clockInfo->safe = NO;
|
|
return;
|
|
}
|