2 C Run-Time Libraries (CRT) Time Management Routines Wrapper Implementation
3 for OpenSSL-based Cryptographic Library (used in SMM).
5 Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include <Library/BaseLib.h>
17 #include <Library/IoLib.h>
18 #include <OpenSslSupport.h>
20 #define PCAT_RTC_ADDRESS_REGISTER 0x70
21 #define PCAT_RTC_DATA_REGISTER 0x71
23 #define RTC_ADDRESS_SECONDS 0 // R/W Range 0..59
24 #define RTC_ADDRESS_SECONDS_ALARM 1 // R/W Range 0..59
25 #define RTC_ADDRESS_MINUTES 2 // R/W Range 0..59
26 #define RTC_ADDRESS_MINUTES_ALARM 3 // R/W Range 0..59
27 #define RTC_ADDRESS_HOURS 4 // R/W Range 1..12 or 0..23 Bit 7 is AM/PM
28 #define RTC_ADDRESS_HOURS_ALARM 5 // R/W Range 1..12 or 0..23 Bit 7 is AM/PM
29 #define RTC_ADDRESS_DAY_OF_THE_WEEK 6 // R/W Range 1..7
30 #define RTC_ADDRESS_DAY_OF_THE_MONTH 7 // R/W Range 1..31
31 #define RTC_ADDRESS_MONTH 8 // R/W Range 1..12
32 #define RTC_ADDRESS_YEAR 9 // R/W Range 0..99
33 #define RTC_ADDRESS_REGISTER_A 10 // R/W[0..6] R0[7]
34 #define RTC_ADDRESS_REGISTER_B 11 // R/W
35 #define RTC_ADDRESS_REGISTER_C 12 // RO
36 #define RTC_ADDRESS_REGISTER_D 13 // RO
37 #define RTC_ADDRESS_CENTURY 50 // R/W Range 19..20 Bit 8 is R/W
43 UINT8 RS
: 4; // Rate Selection Bits
44 UINT8 DV
: 3; // Divisor
45 UINT8 UIP
: 1; // Update in progress
46 } RTC_REGISTER_A_BITS
;
49 RTC_REGISTER_A_BITS Bits
;
57 UINT8 DSE
: 1; // 0 - Daylight saving disabled 1 - Daylight savings enabled
58 UINT8 MIL
: 1; // 0 - 12 hour mode 1 - 24 hour mode
59 UINT8 DM
: 1; // 0 - BCD Format 1 - Binary Format
60 UINT8 SQWE
: 1; // 0 - Disable SQWE output 1 - Enable SQWE output
61 UINT8 UIE
: 1; // 0 - Update INT disabled 1 - Update INT enabled
62 UINT8 AIE
: 1; // 0 - Alarm INT disabled 1 - Alarm INT Enabled
63 UINT8 PIE
: 1; // 0 - Periodic INT disabled 1 - Periodic INT Enabled
64 UINT8 SET
: 1; // 0 - Normal operation. 1 - Updates inhibited
65 } RTC_REGISTER_B_BITS
;
68 RTC_REGISTER_B_BITS Bits
;
73 // -- Time Management Routines --
76 #define IsLeap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
77 #define SECSPERMIN (60)
78 #define SECSPERHOUR (60 * 60)
79 #define SECSPERDAY (24 * SECSPERHOUR)
82 // The arrays give the cumulative number of days up to the first of the
83 // month number used as the index (1 -> 12) for regular and leap years.
84 // The value at index 13 is for the whole year.
86 UINTN CumulativeDays
[2][14] = {
94 31 + 28 + 31 + 30 + 31,
95 31 + 28 + 31 + 30 + 31 + 30,
96 31 + 28 + 31 + 30 + 31 + 30 + 31,
97 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
98 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
99 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
100 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
101 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31
110 31 + 29 + 31 + 30 + 31,
111 31 + 29 + 31 + 30 + 31 + 30,
112 31 + 29 + 31 + 30 + 31 + 30 + 31,
113 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31,
114 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
115 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
116 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
117 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31
122 Read RTC content through its registers.
124 @param Address Address offset of RTC. It is recommended to use macros such as
127 @return The data of UINT8 type read from RTC.
134 IoWrite8 (PCAT_RTC_ADDRESS_REGISTER
, (UINT8
) (Address
| (UINT8
) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER
) & BIT7
)));
135 return IoRead8 (PCAT_RTC_DATA_REGISTER
);
138 /* Get the system time as seconds elapsed since midnight, January 1, 1970. */
142 time_t time (time_t *timer
)
151 RTC_REGISTER_A RegisterA
;
152 RTC_REGISTER_B RegisterB
;
156 RegisterA
.Data
= RtcRead (RTC_ADDRESS_REGISTER_A
);
157 while (RegisterA
.Bits
.UIP
== 1) {
159 RegisterA
.Data
= RtcRead (RTC_ADDRESS_REGISTER_A
);
162 Second
= RtcRead (RTC_ADDRESS_SECONDS
);
163 Minute
= RtcRead (RTC_ADDRESS_MINUTES
);
164 Hour
= RtcRead (RTC_ADDRESS_HOURS
);
165 Day
= RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH
);
166 Month
= RtcRead (RTC_ADDRESS_MONTH
);
167 Year
= RtcRead (RTC_ADDRESS_YEAR
);
168 Century
= RtcRead (RTC_ADDRESS_CENTURY
);
170 RegisterB
.Data
= RtcRead (RTC_ADDRESS_REGISTER_B
);
172 if ((Hour
& BIT7
) != 0) {
177 Hour
= (UINT8
) (Hour
& 0x7f);
179 if (RegisterB
.Bits
.DM
== 0) {
180 Year
= BcdToDecimal8 ((UINT8
) Year
);
181 Month
= BcdToDecimal8 (Month
);
182 Day
= BcdToDecimal8 (Day
);
183 Hour
= BcdToDecimal8 (Hour
);
184 Minute
= BcdToDecimal8 (Minute
);
185 Second
= BcdToDecimal8 (Second
);
187 Century
= BcdToDecimal8 (Century
);
189 Year
= (UINT16
) (Century
* 100 + Year
);
192 // If time is in 12 hour format, convert it to 24 hour format
194 if (RegisterB
.Bits
.MIL
== 0) {
195 if (IsPM
&& Hour
< 12) {
196 Hour
= (UINT8
) (Hour
+ 12);
198 if (!IsPM
&& Hour
== 12) {
205 // UTime should now be set to 00:00:00 on Jan 1 of the current year.
207 for (YearIndex
= 1970, *timer
= 0; YearIndex
!= Year
; YearIndex
++) {
208 *timer
= *timer
+ (time_t)(CumulativeDays
[IsLeap(YearIndex
)][13] * SECSPERDAY
);
212 // Add in number of seconds for current Month, Day, Hour, Minute, Seconds, and TimeZone adjustment
214 ASSERT (Month
<= 12);
216 (time_t)(CumulativeDays
[IsLeap(Year
)][Month
] * SECSPERDAY
) +
217 (time_t)((Day
- 1) * SECSPERDAY
) +
218 (time_t)(Hour
* SECSPERHOUR
) +
219 (time_t)(Minute
* 60) +
226 // Convert a time value from type time_t to struct tm.
228 struct tm
* gmtime (const time_t *timer
)
242 GmTime
= malloc (sizeof (struct tm
));
243 if (GmTime
== NULL
) {
247 ZeroMem ((VOID
*) GmTime
, (UINTN
) sizeof (struct tm
));
249 DayNo
= (UINT16
) (*timer
/ SECSPERDAY
);
250 DayRemainder
= (UINT16
) (*timer
% SECSPERDAY
);
252 GmTime
->tm_sec
= (int) (DayRemainder
% SECSPERMIN
);
253 GmTime
->tm_min
= (int) ((DayRemainder
% SECSPERHOUR
) / SECSPERMIN
);
254 GmTime
->tm_hour
= (int) (DayRemainder
/ SECSPERHOUR
);
255 GmTime
->tm_wday
= (int) ((DayNo
+ 4) % 7);
257 for (Year
= 1970, YearNo
= 0; DayNo
> 0; Year
++) {
258 TotalDays
= (UINT16
) (IsLeap (Year
) ? 366 : 365);
259 if (DayNo
>= TotalDays
) {
260 DayNo
= (UINT16
) (DayNo
- TotalDays
);
267 GmTime
->tm_year
= (int) (YearNo
+ (1970 - 1900));
268 GmTime
->tm_yday
= (int) DayNo
;
270 for (MonthNo
= 12; MonthNo
> 1; MonthNo
--) {
271 if (DayNo
> CumulativeDays
[IsLeap(Year
)][MonthNo
]) {
272 DayNo
= (UINT16
) (DayNo
- (UINT16
) (CumulativeDays
[IsLeap(Year
)][MonthNo
]));
277 GmTime
->tm_mon
= (int) MonthNo
;
278 GmTime
->tm_mday
= (int) DayNo
;
280 GmTime
->tm_isdst
= 0;
281 GmTime
->tm_gmtoff
= 0;
282 GmTime
->tm_zone
= NULL
;