| // 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; |
| } |