1// This file was extracted from the TCG Published 2// Trusted Platform Module Library 3// Part 4: Supporting Routines 4// Family "2.0" 5// Level 00 Revision 01.16 6// October 30, 2014 7 8#include "InternalRoutines.h" 9#include "Platform.h" 10// Functions 11// 12// TimePowerOn() 13// 14// This function initialize time info at _TPM_Init(). 15// 16void 17TimePowerOn( 18 void 19 ) 20{ 21 TPM_SU orderlyShutDown; 22 // Read orderly data info from NV memory 23 NvReadReserved(NV_ORDERLY_DATA, &go); 24 // Read orderly shut down state flag 25 NvReadReserved(NV_ORDERLY, &orderlyShutDown); 26 // If the previous cycle is orderly shut down, the value of the safe bit 27 // the same as previously saved. Otherwise, it is not safe. 28 if(orderlyShutDown == SHUTDOWN_NONE) 29 go.clockSafe= NO; 30 else 31 go.clockSafe = YES; 32 // Set the initial state of the DRBG 33 CryptDrbgGetPutState(PUT_STATE); 34 // Clear time since TPM power on 35 g_time = 0; 36 return; 37} 38// 39// 40// TimeStartup() 41// 42// This function updates the resetCount and restartCount components of TPMS_CLOCK_INFO structure at 43// TPM2_Startup(). 44// 45void 46TimeStartup( 47 STARTUP_TYPE type // IN: start up type 48 ) 49{ 50 if(type == SU_RESUME) 51 { 52 // Resume sequence 53 gr.restartCount++; 54 } 55 else 56 { 57 if(type == SU_RESTART) 58 { 59 // Hibernate sequence 60 gr.clearCount++; 61 gr.restartCount++; 62 } 63 else 64 { 65 // Reset sequence 66 // Increase resetCount 67 gp.resetCount++; 68 // Write resetCount to NV 69 NvWriteReserved(NV_RESET_COUNT, &gp.resetCount); 70 gp.totalResetCount++; 71 // We do not expect the total reset counter overflow during the life 72 // time of TPM. if it ever happens, TPM will be put to failure mode 73 // and there is no way to recover it. 74 // The reason that there is no recovery is that we don't increment 75 // the NV totalResetCount when incrementing would make it 0. When the 76 // TPM starts up again, the old value of totalResetCount will be read 77 // and we will get right back to here with the increment failing. 78 if(gp.totalResetCount == 0) 79 FAIL(FATAL_ERROR_INTERNAL); 80 // Write total reset counter to NV 81 NvWriteReserved(NV_TOTAL_RESET_COUNT, &gp.totalResetCount); 82 // Reset restartCount 83 gr.restartCount = 0; 84 } 85 } 86 return; 87} 88// 89// 90// TimeUpdateToCurrent() 91// 92// This function updates the Time and Clock in the global TPMS_TIME_INFO structure. 93// In this implementation, Time and Clock are updated at the beginning of each command and the values 94// are unchanged for the duration of the command. 95// Because Clock updates may require a write to NV memory, Time and Clock are not allowed to advance if 96// NV is not available. When clock is not advancing, any function that uses Clock will fail and return 97// TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE. 98// This implementations does not do rate limiting. If the implementation does do rate limiting, then the Clock 99// update should not be inhibited even when doing rather limiting. 100// 101void 102TimeUpdateToCurrent( 103 void 104 ) 105{ 106 UINT64 oldClock; 107 UINT64 elapsed; 108#define CLOCK_UPDATE_MASK ((1ULL << NV_CLOCK_UPDATE_INTERVAL)- 1) 109 // Can't update time during the dark interval or when rate limiting. 110 if(NvIsAvailable() != TPM_RC_SUCCESS) 111 return; 112 // Save the old clock value 113 oldClock = go.clock; 114 // Update the time info to current 115 elapsed = _plat__ClockTimeElapsed(); 116 go.clock += elapsed; 117 g_time += elapsed; 118 // Check to see if the update has caused a need for an nvClock update 119 // CLOCK_UPDATE_MASK is measured by second, while the value in go.clock is 120 // recorded by millisecond. Align the clock value to second before the bit 121// 122 // operations 123 if( ((go.clock/1000) | CLOCK_UPDATE_MASK) 124 > ((oldClock/1000) | CLOCK_UPDATE_MASK)) 125 { 126 // Going to update the time state so the safe flag 127 // should be set 128 go.clockSafe = YES; 129 // Get the DRBG state before updating orderly data 130 CryptDrbgGetPutState(GET_STATE); 131 NvWriteReserved(NV_ORDERLY_DATA, &go); 132 } 133 // Call self healing logic for dictionary attack parameters 134 DASelfHeal(); 135 return; 136} 137// 138// 139// TimeSetAdjustRate() 140// 141// This function is used to perform rate adjustment on Time and Clock. 142// 143void 144TimeSetAdjustRate( 145 TPM_CLOCK_ADJUST adjust // IN: adjust constant 146 ) 147{ 148 switch(adjust) 149 { 150 case TPM_CLOCK_COARSE_SLOWER: 151 _plat__ClockAdjustRate(CLOCK_ADJUST_COARSE); 152 break; 153 case TPM_CLOCK_COARSE_FASTER: 154 _plat__ClockAdjustRate(-CLOCK_ADJUST_COARSE); 155 break; 156 case TPM_CLOCK_MEDIUM_SLOWER: 157 _plat__ClockAdjustRate(CLOCK_ADJUST_MEDIUM); 158 break; 159 case TPM_CLOCK_MEDIUM_FASTER: 160 _plat__ClockAdjustRate(-CLOCK_ADJUST_MEDIUM); 161 break; 162 case TPM_CLOCK_FINE_SLOWER: 163 _plat__ClockAdjustRate(CLOCK_ADJUST_FINE); 164 break; 165 case TPM_CLOCK_FINE_FASTER: 166 _plat__ClockAdjustRate(-CLOCK_ADJUST_FINE); 167 break; 168 case TPM_CLOCK_NO_CHANGE: 169 break; 170 default: 171 pAssert(FALSE); 172 break; 173 } 174 return; 175} 176// 177// 178// TimeGetRange() 179// 180// This function is used to access TPMS_TIME_INFO. The TPMS_TIME_INFO structure is treaded as an 181// array of bytes, and a byte offset and length determine what bytes are returned. 182// 183// Error Returns Meaning 184// 185// TPM_RC_RANGE invalid data range 186// 187TPM_RC 188TimeGetRange( 189 UINT16 offset, // IN: offset in TPMS_TIME_INFO 190 UINT16 size, // IN: size of data 191 TIME_INFO *dataBuffer // OUT: result buffer 192 ) 193{ 194 TPMS_TIME_INFO timeInfo; 195 UINT16 infoSize; 196 BYTE infoData[sizeof(TPMS_TIME_INFO)]; 197 BYTE *buffer; 198 INT32 bufferSize; 199 // Fill TPMS_TIME_INFO structure 200 timeInfo.time = g_time; 201 TimeFillInfo(&timeInfo.clockInfo); 202 // Marshal TPMS_TIME_INFO to canonical form 203 buffer = infoData; 204 bufferSize = sizeof(TPMS_TIME_INFO); 205 infoSize = TPMS_TIME_INFO_Marshal(&timeInfo, &buffer, &bufferSize); 206 // Check if the input range is valid 207 if(offset + size > infoSize) return TPM_RC_RANGE; 208 // Copy info data to output buffer 209 MemoryCopy(dataBuffer, infoData + offset, size, sizeof(TIME_INFO)); 210 return TPM_RC_SUCCESS; 211} 212// 213// 214// TimeFillInfo 215// 216// This function gathers information to fill in a TPMS_CLOCK_INFO structure. 217// 218void 219TimeFillInfo( 220 TPMS_CLOCK_INFO *clockInfo 221 ) 222{ 223 clockInfo->clock = go.clock; 224 clockInfo->resetCount = gp.resetCount; 225 clockInfo->restartCount = gr.restartCount; 226 // If NV is not available, clock stopped advancing and the value reported is 227 // not "safe". 228 if(NvIsAvailable() == TPM_RC_SUCCESS) 229 clockInfo->safe = go.clockSafe; 230 else 231 clockInfo->safe = NO; 232 return; 233} 234