xref: /aosp_15_r20/external/ms-tpm-20-ref/TPMCmd/Platform/src/Clock.c (revision 5c591343844d1f9da7da26467c4bf7efc8a7a413)
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