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 //
16 void
TimePowerOn(void)17 TimePowerOn(
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 //
45 void
TimeStartup(STARTUP_TYPE type)46 TimeStartup(
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 //
101 void
TimeUpdateToCurrent(void)102 TimeUpdateToCurrent(
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 //
143 void
TimeSetAdjustRate(TPM_CLOCK_ADJUST adjust)144 TimeSetAdjustRate(
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 //
187 TPM_RC
TimeGetRange(UINT16 offset,UINT16 size,TIME_INFO * dataBuffer)188 TimeGetRange(
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 //
218 void
TimeFillInfo(TPMS_CLOCK_INFO * clockInfo)219 TimeFillInfo(
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