1 /* Microsoft Reference Implementation for TPM 2.0
2 *
3 * The copyright in this software is being made available under the BSD License,
4 * included below. This software may be subject to other third party and
5 * contributor rights, including patent rights, and no such rights are granted
6 * under this license.
7 *
8 * Copyright (c) Microsoft Corporation
9 *
10 * All rights reserved.
11 *
12 * BSD License
13 *
14 * Redistribution and use in source and binary forms, with or without modification,
15 * are permitted provided that the following conditions are met:
16 *
17 * Redistributions of source code must retain the above copyright notice, this list
18 * of conditions and the following disclaimer.
19 *
20 * Redistributions in binary form must reproduce the above copyright notice, this
21 * list of conditions and the following disclaimer in the documentation and/or
22 * other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35 //** Description
36 //
37 // This file contains the routines that are used by the simulator to mimic
38 // a hardware clock on a TPM.
39 //
40 // In this implementation, all the time values are measured in millisecond.
41 // However, the precision of the clock functions may be implementation dependent.
42
43 //** Includes and Data Definitions
44 #include "PlatformData.h"
45 #include "Platform_fp.h"
46 #include "TpmFail_fp.h"
47 #include <assert.h>
48 #include <tee_internal_api.h>
49
50 //** Simulator Functions
51 //*** Introduction
52 // This set of functions is intended to be called by the simulator environment in
53 // order to simulate hardware events.
54
55 //***_plat__TimerReset()
56 // This function sets current system clock time as t0 for counting TPM time.
57 // This function is called at a power on event to reset the clock. When the clock
58 // is reset, the indication that the clock was stopped is also set.
59 LIB_EXPORT void
_plat__TimerReset(void)60 _plat__TimerReset(
61 void
62 )
63 {
64 TEE_Result Result;
65 TEE_Time Time = { 0 };
66
67 // Reset our TA persistent time, this affects all instances.
68 Result = TEE_SetTAPersistentTime(&Time);
69
70 // Nothing we can do on failure here.
71 assert(Result == TEE_SUCCESS);
72
73 s_adjustRate = 0;
74 s_lastSystemTime = 0;
75 s_tpmTime = 0;
76 s_adjustRate = CLOCK_NOMINAL;
77 s_timerReset = TRUE;
78 s_timerStopped = TRUE;
79
80 return;
81 }
82
83 //*** _plat__TimerRestart()
84 // This function should be called in order to simulate the restart of the timer
85 // should it be stopped while power is still applied.
86 LIB_EXPORT void
_plat__TimerRestart(void)87 _plat__TimerRestart(
88 void
89 )
90 {
91 s_timerStopped = TRUE;
92 return;
93 }
94
95 //** Functions Used by TPM
96 //*** Introduction
97 // These functions are called by the TPM code. They should be replaced by
98 // appropriated hardware functions.
99
100 #include <time.h>
101 TEE_Time debugTime;
102
103 //*** _plat__RealTime()
104 // This is another, probably futile, attempt to define a portable function
105 // that will return a 64-bit clock value that has mSec resolution.
106 uint64_t
_plat__RealTime(void)107 _plat__RealTime(
108 void
109 )
110 {
111 TEE_Result Result;
112 TEE_Time Time;
113 uint64_t Elapsed, Temp;
114
115 Result = TEE_GetTAPersistentTime(&Time);
116
117 // Error conditions from GetTime may be resolved with a clock reset
118 if ((Result == TEE_ERROR_TIME_NOT_SET) ||
119 (Result == TEE_ERROR_TIME_NEEDS_RESET)) {
120 //
121 // REVISIT: Since error conditions from get time may be resolved
122 // by resetting time. Determine if, when this happens, we see
123 // an issue with timing in the reference implementaiton.
124 //
125 _plat__TimerReset();
126
127 Result = TEE_GetTAPersistentTime(&Time);
128 // If the reset didn't resolve the error condision, give up.
129 assert(Result == TEE_SUCCESS);
130 }
131 assert(Result == TEE_SUCCESS);
132
133 Elapsed = ((Time.seconds * 1000) + (Time.millis));
134
135 return Elapsed;
136 }
137
138 //***_plat__TimerRead()
139 // This function provides access to the tick timer of the platform. The TPM code
140 // uses this value to drive the TPM Clock.
141 //
142 // The tick timer is supposed to run when power is applied to the device. This timer
143 // should not be reset by time events including _TPM_Init. It should only be reset
144 // when TPM power is re-applied.
145 //
146 // If the TPM is run in a protected environment, that environment may provide the
147 // tick time to the TPM as long as the time provided by the environment is not
148 // allowed to go backwards. If the time provided by the system can go backwards
149 // during a power discontinuity, then the _plat__Signal_PowerOn should call
150 // _plat__TimerReset().
151 LIB_EXPORT uint64_t
_plat__TimerRead(void)152 _plat__TimerRead(
153 void
154 )
155 {
156 #ifdef HARDWARE_CLOCK
157 #error "need a defintion for reading the hardware clock"
158 return HARDWARE_CLOCK
159 #else
160 clock64_t timeDiff;
161 clock64_t adjustedTimeDiff;
162 clock64_t timeNow;
163 clock64_t readjustedTimeDiff;
164
165 // This produces a timeNow that is basically locked to the system clock.
166 timeNow = _plat__RealTime();
167
168 // if this hasn't been initialized, initialize it
169 if(s_lastSystemTime == 0)
170 {
171 s_lastSystemTime = timeNow;
172 TEE_GetSystemTime(&debugTime);
173 s_lastReportedTime = 0;
174 s_realTimePrevious = 0;
175 }
176 // The system time can bounce around and that's OK as long as we don't allow
177 // time to go backwards. When the time does appear to go backwards, set
178 // lastSystemTime to be the new value and then update the reported time.
179 if(timeNow < s_lastReportedTime)
180 s_lastSystemTime = timeNow;
181 s_lastReportedTime = s_lastReportedTime + timeNow - s_lastSystemTime;
182 s_lastSystemTime = timeNow;
183 timeNow = s_lastReportedTime;
184
185 // The code above produces a timeNow that is similar to the value returned
186 // by Clock(). The difference is that timeNow does not max out, and it is
187 // at a ms. rate rather than at a CLOCKS_PER_SEC rate. The code below
188 // uses that value and does the rate adjustment on the time value.
189 // If there is no difference in time, then skip all the computations
190 if(s_realTimePrevious >= timeNow)
191 return s_tpmTime;
192 // Compute the amount of time since the last update of the system clock
193 timeDiff = timeNow - s_realTimePrevious;
194
195 // Do the time rate adjustment and conversion from CLOCKS_PER_SEC to mSec
196 adjustedTimeDiff = (timeDiff * CLOCK_NOMINAL) / ((uint64_t)s_adjustRate);
197
198 // update the TPM time with the adjusted timeDiff
199 s_tpmTime += (clock64_t)adjustedTimeDiff;
200
201 // Might have some rounding error that would loose CLOCKS. See what is not
202 // being used. As mentioned above, this could result in putting back more than
203 // is taken out. Here, we are trying to recreate timeDiff.
204 readjustedTimeDiff = (adjustedTimeDiff * (uint64_t)s_adjustRate )
205 / CLOCK_NOMINAL;
206
207 // adjusted is now converted back to being the amount we should advance the
208 // previous sampled time. It should always be less than or equal to timeDiff.
209 // That is, we could not have use more time than we started with.
210 s_realTimePrevious = s_realTimePrevious + readjustedTimeDiff;
211
212 #ifdef DEBUGGING_TIME
213 // Put this in so that TPM time will pass much faster than real time when
214 // doing debug.
215 // A value of 1000 for DEBUG_TIME_MULTIPLER will make each ms into a second
216 // A good value might be 100
217 return (s_tpmTime * DEBUG_TIME_MULTIPLIER);
218 #endif
219 return s_tpmTime;
220 #endif
221 }
222
223
224
225 //*** _plat__TimerWasReset()
226 // This function is used to interrogate the flag indicating if the tick timer has
227 // been reset.
228 //
229 // If the resetFlag parameter is SET, then the flag will be CLEAR before the
230 // function returns.
231 LIB_EXPORT BOOL
232 _plat__TimerWasReset(
233 void
234 )
235 {
236 BOOL retVal = s_timerReset;
237 s_timerReset = FALSE;
238 return retVal;
239 }
240
241 //*** _plat__TimerWasStopped()
242 // This function is used to interrogate the flag indicating if the tick timer has
243 // been stopped. If so, this is typically a reason to roll the nonce.
244 //
245 // This function will CLEAR the s_timerStopped flag before returning. This provides
246 // functionality that is similar to status register that is cleared when read. This
247 // is the model used here because it is the one that has the most impact on the TPM
248 // code as the flag can only be accessed by one entity in the TPM. Any other
249 // implementation of the hardware can be made to look like a read-once register.
250 LIB_EXPORT BOOL
251 _plat__TimerWasStopped(
252 void
253 )
254 {
255 BOOL retVal = s_timerStopped;
256 s_timerStopped = FALSE;
257 return retVal;
258 }
259
260 //***_plat__ClockAdjustRate()
261 // Adjust the clock rate
262 LIB_EXPORT void
263 _plat__ClockAdjustRate(
264 int adjust // IN: the adjust number. It could be positive
265 // or negative
266 )
267 {
268 // We expect the caller should only use a fixed set of constant values to
269 // adjust the rate
270 switch(adjust)
271 {
272 case CLOCK_ADJUST_COARSE:
273 s_adjustRate += CLOCK_ADJUST_COARSE;
274 break;
275 case -CLOCK_ADJUST_COARSE:
276 s_adjustRate -= CLOCK_ADJUST_COARSE;
277 break;
278 case CLOCK_ADJUST_MEDIUM:
279 s_adjustRate += CLOCK_ADJUST_MEDIUM;
280 break;
281 case -CLOCK_ADJUST_MEDIUM:
282 s_adjustRate -= CLOCK_ADJUST_MEDIUM;
283 break;
284 case CLOCK_ADJUST_FINE:
285 s_adjustRate += CLOCK_ADJUST_FINE;
286 break;
287 case -CLOCK_ADJUST_FINE:
288 s_adjustRate -= CLOCK_ADJUST_FINE;
289 break;
290 default:
291 // ignore any other values;
292 break;
293 }
294
295 if(s_adjustRate > (CLOCK_NOMINAL + CLOCK_ADJUST_LIMIT))
296 s_adjustRate = CLOCK_NOMINAL + CLOCK_ADJUST_LIMIT;
297 if(s_adjustRate < (CLOCK_NOMINAL - CLOCK_ADJUST_LIMIT))
298 s_adjustRate = CLOCK_NOMINAL - CLOCK_ADJUST_LIMIT;
299
300 return;
301 }
302
303