]> git.proxmox.com Git - mirror_edk2.git/blob - CryptoPkg/Library/BaseCryptLib/SysCall/RealTimeClock.c
Add new interfaces to support PKCS7#7 signed data and authenticode signature. Update...
[mirror_edk2.git] / CryptoPkg / Library / BaseCryptLib / SysCall / RealTimeClock.c
1 /** @file
2 C Run-Time Libraries (CRT) Time Management Routines Wrapper Implementation
3 for OpenSSL-based Cryptographic Library (used in SMM).
4
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
10
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.
13
14 **/
15
16 #include <Library/BaseLib.h>
17 #include <Library/IoLib.h>
18 #include <OpenSslSupport.h>
19
20 #define PCAT_RTC_ADDRESS_REGISTER 0x70
21 #define PCAT_RTC_DATA_REGISTER 0x71
22
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
38
39 //
40 // Register A
41 //
42 typedef struct {
43 UINT8 RS : 4; // Rate Selection Bits
44 UINT8 DV : 3; // Divisor
45 UINT8 UIP : 1; // Update in progress
46 } RTC_REGISTER_A_BITS;
47
48 typedef union {
49 RTC_REGISTER_A_BITS Bits;
50 UINT8 Data;
51 } RTC_REGISTER_A;
52
53 //
54 // Register B
55 //
56 typedef struct {
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;
66
67 typedef union {
68 RTC_REGISTER_B_BITS Bits;
69 UINT8 Data;
70 } RTC_REGISTER_B;
71
72 //
73 // -- Time Management Routines --
74 //
75
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)
80
81 //
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.
85 //
86 UINTN CumulativeDays[2][14] = {
87 {
88 0,
89 0,
90 31,
91 31 + 28,
92 31 + 28 + 31,
93 31 + 28 + 31 + 30,
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
102 },
103 {
104 0,
105 0,
106 31,
107 31 + 29,
108 31 + 29 + 31,
109 31 + 29 + 31 + 30,
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
118 }
119 };
120
121 /**
122 Read RTC content through its registers.
123
124 @param Address Address offset of RTC. It is recommended to use macros such as
125 RTC_ADDRESS_SECONDS.
126
127 @return The data of UINT8 type read from RTC.
128 **/
129 UINT8
130 RtcRead (
131 IN UINT8 Address
132 )
133 {
134 IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8) (Address | (UINT8) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & BIT7)));
135 return IoRead8 (PCAT_RTC_DATA_REGISTER);
136 }
137
138 /* Get the system time as seconds elapsed since midnight, January 1, 1970. */
139 //INTN time(
140 // INTN *timer
141 // )
142 time_t time (time_t *timer)
143 {
144 UINT16 Year;
145 UINT8 Month;
146 UINT8 Day;
147 UINT8 Hour;
148 UINT8 Minute;
149 UINT8 Second;
150 UINT8 Century;
151 RTC_REGISTER_A RegisterA;
152 RTC_REGISTER_B RegisterB;
153 BOOLEAN IsPM;
154 UINT16 YearIndex;
155
156 RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A);
157 while (RegisterA.Bits.UIP == 1) {
158 CpuPause();
159 RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A);
160 }
161
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);
169
170 RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
171
172 if ((Hour & BIT7) != 0) {
173 IsPM = TRUE;
174 } else {
175 IsPM = FALSE;
176 }
177 Hour = (UINT8) (Hour & 0x7f);
178
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);
186 }
187 Century = BcdToDecimal8 (Century);
188
189 Year = (UINT16) (Century * 100 + Year);
190
191 //
192 // If time is in 12 hour format, convert it to 24 hour format
193 //
194 if (RegisterB.Bits.MIL == 0) {
195 if (IsPM && Hour < 12) {
196 Hour = (UINT8) (Hour + 12);
197 }
198 if (!IsPM && Hour == 12) {
199 Hour = 0;
200 }
201 }
202
203 //
204 // Years Handling
205 // UTime should now be set to 00:00:00 on Jan 1 of the current year.
206 //
207 for (YearIndex = 1970, *timer = 0; YearIndex != Year; YearIndex++) {
208 *timer = *timer + (time_t)(CumulativeDays[IsLeap(YearIndex)][13] * SECSPERDAY);
209 }
210
211 //
212 // Add in number of seconds for current Month, Day, Hour, Minute, Seconds, and TimeZone adjustment
213 //
214 ASSERT (Month <= 12);
215 *timer = *timer +
216 (time_t)(CumulativeDays[IsLeap(Year)][Month] * SECSPERDAY) +
217 (time_t)((Day - 1) * SECSPERDAY) +
218 (time_t)(Hour * SECSPERHOUR) +
219 (time_t)(Minute * 60) +
220 (time_t)Second;
221
222 return *timer;
223 }
224
225 //
226 // Convert a time value from type time_t to struct tm.
227 //
228 struct tm * gmtime (const time_t *timer)
229 {
230 struct tm *GmTime;
231 UINT16 DayNo;
232 UINT16 DayRemainder;
233 time_t Year;
234 time_t YearNo;
235 UINT16 TotalDays;
236 UINT16 MonthNo;
237
238 if (timer == NULL) {
239 return NULL;
240 }
241
242 GmTime = malloc (sizeof (struct tm));
243 if (GmTime == NULL) {
244 return NULL;
245 }
246
247 ZeroMem ((VOID *) GmTime, (UINTN) sizeof (struct tm));
248
249 DayNo = (UINT16) (*timer / SECSPERDAY);
250 DayRemainder = (UINT16) (*timer % SECSPERDAY);
251
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);
256
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);
261 YearNo++;
262 } else {
263 break;
264 }
265 }
266
267 GmTime->tm_year = (int) (YearNo + (1970 - 1900));
268 GmTime->tm_yday = (int) DayNo;
269
270 for (MonthNo = 12; MonthNo > 1; MonthNo--) {
271 if (DayNo > CumulativeDays[IsLeap(Year)][MonthNo]) {
272 DayNo = (UINT16) (DayNo - (UINT16) (CumulativeDays[IsLeap(Year)][MonthNo]));
273 break;
274 }
275 }
276
277 GmTime->tm_mon = (int) MonthNo;
278 GmTime->tm_mday = (int) DayNo;
279
280 GmTime->tm_isdst = 0;
281 GmTime->tm_gmtoff = 0;
282 GmTime->tm_zone = NULL;
283
284 return GmTime;
285 }
286