aboutsummaryrefslogtreecommitdiff
path: root/Time.c
blob: 87c5ce290235da26273ad148e607bc314b21b127 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
// 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;
}