2 C Run-Time Libraries (CRT) Time Management Routines Wrapper Implementation
3 for OpenSSL-based Cryptographic Library (used in SMM).
5 Copyright (c) 2010, 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 SECSPERHOUR (60 * 60)
78 #define SECSPERDAY (24 * SECSPERHOUR)
81 // The arrays give the cumulative number of days up to the first of the
82 // month number used as the index (1 -> 12) for regular and leap years.
83 // The value at index 13 is for the whole year.
85 UINTN CumulativeDays
[2][14] = {
93 31 + 28 + 31 + 30 + 31,
94 31 + 28 + 31 + 30 + 31 + 30,
95 31 + 28 + 31 + 30 + 31 + 30 + 31,
96 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
97 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
98 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
99 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
100 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31
109 31 + 29 + 31 + 30 + 31,
110 31 + 29 + 31 + 30 + 31 + 30,
111 31 + 29 + 31 + 30 + 31 + 30 + 31,
112 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31,
113 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
114 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
115 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
116 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31
121 Read RTC content through its registers.
123 @param Address Address offset of RTC. It is recommended to use macros such as
126 @return The data of UINT8 type read from RTC.
133 IoWrite8 (PCAT_RTC_ADDRESS_REGISTER
, (UINT8
) (Address
| (UINT8
) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER
) & BIT7
)));
134 return IoRead8 (PCAT_RTC_DATA_REGISTER
);
137 /* Get the system time as seconds elapsed since midnight, January 1, 1970. */
141 time_t time (time_t *timer
)
150 RTC_REGISTER_A RegisterA
;
151 RTC_REGISTER_B RegisterB
;
155 RegisterA
.Data
= RtcRead (RTC_ADDRESS_REGISTER_A
);
156 while (RegisterA
.Bits
.UIP
== 1) {
158 RegisterA
.Data
= RtcRead (RTC_ADDRESS_REGISTER_A
);
161 Second
= RtcRead (RTC_ADDRESS_SECONDS
);
162 Minute
= RtcRead (RTC_ADDRESS_MINUTES
);
163 Hour
= RtcRead (RTC_ADDRESS_HOURS
);
164 Day
= RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH
);
165 Month
= RtcRead (RTC_ADDRESS_MONTH
);
166 Year
= RtcRead (RTC_ADDRESS_YEAR
);
167 Century
= RtcRead (RTC_ADDRESS_CENTURY
);
169 RegisterB
.Data
= RtcRead (RTC_ADDRESS_REGISTER_B
);
171 if ((Hour
& BIT7
) != 0) {
176 Hour
= (UINT8
) (Hour
& 0x7f);
178 if (RegisterB
.Bits
.DM
== 0) {
179 Year
= BcdToDecimal8 ((UINT8
) Year
);
180 Month
= BcdToDecimal8 (Month
);
181 Day
= BcdToDecimal8 (Day
);
182 Hour
= BcdToDecimal8 (Hour
);
183 Minute
= BcdToDecimal8 (Minute
);
184 Second
= BcdToDecimal8 (Second
);
186 Century
= BcdToDecimal8 (Century
);
188 Year
= (UINT16
) (Century
* 100 + Year
);
191 // If time is in 12 hour format, convert it to 24 hour format
193 if (RegisterB
.Bits
.MIL
== 0) {
194 if (IsPM
&& Hour
< 12) {
195 Hour
= (UINT8
) (Hour
+ 12);
197 if (!IsPM
&& Hour
== 12) {
204 // UTime should now be set to 00:00:00 on Jan 1 of the current year.
206 for (YearIndex
= 1970, *timer
= 0; YearIndex
!= Year
; YearIndex
++) {
207 *timer
= *timer
+ (time_t)(CumulativeDays
[IsLeap(YearIndex
)][13] * SECSPERDAY
);
211 // Add in number of seconds for current Month, Day, Hour, Minute, Seconds, and TimeZone adjustment
213 ASSERT (Month
<= 12);
215 (time_t)(CumulativeDays
[IsLeap(Year
)][Month
] * SECSPERDAY
) +
216 (time_t)((Day
- 1) * SECSPERDAY
) +
217 (time_t)(Hour
* SECSPERHOUR
) +
218 (time_t)(Minute
* 60) +