blob: 87c5ce290235da26273ad148e607bc314b21b127 [file] [log] [blame]
Vadim Bendebury56797522015-05-20 10:32:25 -07001// 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;
Jocelyn Bohr32be4042015-07-29 15:14:01 -0700198 INT32 bufferSize;
Vadim Bendebury56797522015-05-20 10:32:25 -0700199 // 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;
Jocelyn Bohr32be4042015-07-29 15:14:01 -0700204 bufferSize = sizeof(TPMS_TIME_INFO);
205 infoSize = TPMS_TIME_INFO_Marshal(&timeInfo, &buffer, &bufferSize);
Vadim Bendebury56797522015-05-20 10:32:25 -0700206 // 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}