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