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 <assert.h>
45 #include "Platform.h"
46 #include "TpmFail_fp.h"
47
48
49 //** Simulator Functions
50 //*** Introduction
51 // This set of functions is intended to be called by the simulator environment in
52 // order to simulate hardware events.
53
54 //***_plat__TimerReset()
55 // This function sets current system clock time as t0 for counting TPM time.
56 // This function is called at a power on event to reset the clock. When the clock
57 // is reset, the indication that the clock was stopped is also set.
58 LIB_EXPORT void
_plat__TimerReset(void)59 _plat__TimerReset(
60 void
61 )
62 {
63 s_lastSystemTime = 0;
64 s_tpmTime = 0;
65 s_adjustRate = CLOCK_NOMINAL;
66 s_timerReset = TRUE;
67 s_timerStopped = TRUE;
68 return;
69 }
70
71 //*** _plat__TimerRestart()
72 // This function should be called in order to simulate the restart of the timer
73 // should it be stopped while power is still applied.
74 LIB_EXPORT void
_plat__TimerRestart(void)75 _plat__TimerRestart(
76 void
77 )
78 {
79 s_timerStopped = TRUE;
80 return;
81 }
82
83 //** Functions Used by TPM
84 //*** Introduction
85 // These functions are called by the TPM code. They should be replaced by
86 // appropriated hardware functions.
87
88 #include <time.h>
89 clock_t debugTime;
90
91 //*** _plat__RealTime()
92 // This is another, probably futile, attempt to define a portable function
93 // that will return a 64-bit clock value that has mSec resolution.
94 LIB_EXPORT uint64_t
_plat__RealTime(void)95 _plat__RealTime(
96 void
97 )
98 {
99 clock64_t time;
100 #ifdef _MSC_VER
101 struct _timeb sysTime;
102 //
103 _ftime_s(&sysTime);
104 time = (clock64_t)(sysTime.time) * 1000 + sysTime.millitm;
105 // set the time back by one hour if daylight savings
106 if(sysTime.dstflag)
107 time -= 1000 * 60 * 60; // mSec/sec * sec/min * min/hour = ms/hour
108 #else
109 // hopefully, this will work with most UNIX systems
110 struct timespec systime;
111 //
112 clock_gettime(CLOCK_MONOTONIC, &systime);
113 time = (clock64_t)systime.tv_sec * 1000 + (systime.tv_nsec / 1000000);
114 #endif
115 return time;
116 }
117
118 //***_plat__TimerRead()
119 // This function provides access to the tick timer of the platform. The TPM code
120 // uses this value to drive the TPM Clock.
121 //
122 // The tick timer is supposed to run when power is applied to the device. This timer
123 // should not be reset by time events including _TPM_Init. It should only be reset
124 // when TPM power is re-applied.
125 //
126 // If the TPM is run in a protected environment, that environment may provide the
127 // tick time to the TPM as long as the time provided by the environment is not
128 // allowed to go backwards. If the time provided by the system can go backwards
129 // during a power discontinuity, then the _plat__Signal_PowerOn should call
130 // _plat__TimerReset().
131 LIB_EXPORT uint64_t
_plat__TimerRead(void)132 _plat__TimerRead(
133 void
134 )
135 {
136 #ifdef HARDWARE_CLOCK
137 #error "need a defintion for reading the hardware clock"
138 return HARDWARE_CLOCK
139 #else
140 clock64_t timeDiff;
141 clock64_t adjustedTimeDiff;
142 clock64_t timeNow;
143 clock64_t readjustedTimeDiff;
144
145 // This produces a timeNow that is basically locked to the system clock.
146 timeNow = _plat__RealTime();
147
148 // if this hasn't been initialized, initialize it
149 if(s_lastSystemTime == 0)
150 {
151 s_lastSystemTime = timeNow;
152 debugTime = clock();
153 s_lastReportedTime = 0;
154 s_realTimePrevious = 0;
155 }
156 // The system time can bounce around and that's OK as long as we don't allow
157 // time to go backwards. When the time does appear to go backwards, set
158 // lastSystemTime to be the new value and then update the reported time.
159 if(timeNow < s_lastReportedTime)
160 s_lastSystemTime = timeNow;
161 s_lastReportedTime = s_lastReportedTime + timeNow - s_lastSystemTime;
162 s_lastSystemTime = timeNow;
163 timeNow = s_lastReportedTime;
164
165 // The code above produces a timeNow that is similar to the value returned
166 // by Clock(). The difference is that timeNow does not max out, and it is
167 // at a ms. rate rather than at a CLOCKS_PER_SEC rate. The code below
168 // uses that value and does the rate adjustment on the time value.
169 // If there is no difference in time, then skip all the computations
170 if(s_realTimePrevious >= timeNow)
171 return s_tpmTime;
172 // Compute the amount of time since the last update of the system clock
173 timeDiff = timeNow - s_realTimePrevious;
174
175 // Do the time rate adjustment and conversion from CLOCKS_PER_SEC to mSec
176 adjustedTimeDiff = (timeDiff * CLOCK_NOMINAL) / ((uint64_t)s_adjustRate);
177
178 // update the TPM time with the adjusted timeDiff
179 s_tpmTime += (clock64_t)adjustedTimeDiff;
180
181 // Might have some rounding error that would loose CLOCKS. See what is not
182 // being used. As mentioned above, this could result in putting back more than
183 // is taken out. Here, we are trying to recreate timeDiff.
184 readjustedTimeDiff = (adjustedTimeDiff * (uint64_t)s_adjustRate )
185 / CLOCK_NOMINAL;
186
187 // adjusted is now converted back to being the amount we should advance the
188 // previous sampled time. It should always be less than or equal to timeDiff.
189 // That is, we could not have use more time than we started with.
190 s_realTimePrevious = s_realTimePrevious + readjustedTimeDiff;
191
192 #ifdef DEBUGGING_TIME
193 // Put this in so that TPM time will pass much faster than real time when
194 // doing debug.
195 // A value of 1000 for DEBUG_TIME_MULTIPLER will make each ms into a second
196 // A good value might be 100
197 return (s_tpmTime * DEBUG_TIME_MULTIPLIER);
198 #endif
199 return s_tpmTime;
200 #endif
201 }
202
203
204
205 //*** _plat__TimerWasReset()
206 // This function is used to interrogate the flag indicating if the tick timer has
207 // been reset.
208 //
209 // If the resetFlag parameter is SET, then the flag will be CLEAR before the
210 // function returns.
211 LIB_EXPORT int
212 _plat__TimerWasReset(
213 void
214 )
215 {
216 int retVal = s_timerReset;
217 s_timerReset = FALSE;
218 return retVal;
219 }
220
221 //*** _plat__TimerWasStopped()
222 // This function is used to interrogate the flag indicating if the tick timer has
223 // been stopped. If so, this is typically a reason to roll the nonce.
224 //
225 // This function will CLEAR the s_timerStopped flag before returning. This provides
226 // functionality that is similar to status register that is cleared when read. This
227 // is the model used here because it is the one that has the most impact on the TPM
228 // code as the flag can only be accessed by one entity in the TPM. Any other
229 // implementation of the hardware can be made to look like a read-once register.
230 LIB_EXPORT int
231 _plat__TimerWasStopped(
232 void
233 )
234 {
235 int retVal = s_timerStopped;
236 s_timerStopped = FALSE;
237 return retVal;
238 }
239
240 //***_plat__ClockAdjustRate()
241 // Adjust the clock rate
242 LIB_EXPORT void
243 _plat__ClockAdjustRate(
244 int adjust // IN: the adjust number. It could be positive
245 // or negative
246 )
247 {
248 // We expect the caller should only use a fixed set of constant values to
249 // adjust the rate
250 switch(adjust)
251 {
252 case CLOCK_ADJUST_COARSE:
253 s_adjustRate += CLOCK_ADJUST_COARSE;
254 break;
255 case -CLOCK_ADJUST_COARSE:
256 s_adjustRate -= CLOCK_ADJUST_COARSE;
257 break;
258 case CLOCK_ADJUST_MEDIUM:
259 s_adjustRate += CLOCK_ADJUST_MEDIUM;
260 break;
261 case -CLOCK_ADJUST_MEDIUM:
262 s_adjustRate -= CLOCK_ADJUST_MEDIUM;
263 break;
264 case CLOCK_ADJUST_FINE:
265 s_adjustRate += CLOCK_ADJUST_FINE;
266 break;
267 case -CLOCK_ADJUST_FINE:
268 s_adjustRate -= CLOCK_ADJUST_FINE;
269 break;
270 default:
271 // ignore any other values;
272 break;
273 }
274
275 if(s_adjustRate > (CLOCK_NOMINAL + CLOCK_ADJUST_LIMIT))
276 s_adjustRate = CLOCK_NOMINAL + CLOCK_ADJUST_LIMIT;
277 if(s_adjustRate < (CLOCK_NOMINAL - CLOCK_ADJUST_LIMIT))
278 s_adjustRate = CLOCK_NOMINAL - CLOCK_ADJUST_LIMIT;
279
280 return;
281 }
282
283