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