]> git.proxmox.com Git - mirror_edk2.git/blame - 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
CommitLineData
a8c44645 1/** @file\r
2 C Run-Time Libraries (CRT) Time Management Routines Wrapper Implementation\r
3 for OpenSSL-based Cryptographic Library (used in SMM).\r
4\r
b7d320f8 5Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>\r
a8c44645 6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include <Library/BaseLib.h>\r
17#include <Library/IoLib.h>\r
18#include <OpenSslSupport.h>\r
19\r
20#define PCAT_RTC_ADDRESS_REGISTER 0x70\r
21#define PCAT_RTC_DATA_REGISTER 0x71\r
22\r
23#define RTC_ADDRESS_SECONDS 0 // R/W Range 0..59\r
24#define RTC_ADDRESS_SECONDS_ALARM 1 // R/W Range 0..59\r
25#define RTC_ADDRESS_MINUTES 2 // R/W Range 0..59\r
26#define RTC_ADDRESS_MINUTES_ALARM 3 // R/W Range 0..59\r
27#define RTC_ADDRESS_HOURS 4 // R/W Range 1..12 or 0..23 Bit 7 is AM/PM\r
28#define RTC_ADDRESS_HOURS_ALARM 5 // R/W Range 1..12 or 0..23 Bit 7 is AM/PM\r
29#define RTC_ADDRESS_DAY_OF_THE_WEEK 6 // R/W Range 1..7\r
30#define RTC_ADDRESS_DAY_OF_THE_MONTH 7 // R/W Range 1..31\r
31#define RTC_ADDRESS_MONTH 8 // R/W Range 1..12\r
32#define RTC_ADDRESS_YEAR 9 // R/W Range 0..99\r
33#define RTC_ADDRESS_REGISTER_A 10 // R/W[0..6] R0[7]\r
34#define RTC_ADDRESS_REGISTER_B 11 // R/W\r
35#define RTC_ADDRESS_REGISTER_C 12 // RO\r
36#define RTC_ADDRESS_REGISTER_D 13 // RO\r
37#define RTC_ADDRESS_CENTURY 50 // R/W Range 19..20 Bit 8 is R/W\r
38\r
39//\r
40// Register A\r
41//\r
42typedef struct {\r
43 UINT8 RS : 4; // Rate Selection Bits\r
44 UINT8 DV : 3; // Divisor\r
45 UINT8 UIP : 1; // Update in progress\r
46} RTC_REGISTER_A_BITS;\r
47\r
48typedef union {\r
49 RTC_REGISTER_A_BITS Bits;\r
50 UINT8 Data;\r
51} RTC_REGISTER_A;\r
52\r
53//\r
54// Register B\r
55//\r
56typedef struct {\r
57 UINT8 DSE : 1; // 0 - Daylight saving disabled 1 - Daylight savings enabled\r
58 UINT8 MIL : 1; // 0 - 12 hour mode 1 - 24 hour mode\r
59 UINT8 DM : 1; // 0 - BCD Format 1 - Binary Format\r
60 UINT8 SQWE : 1; // 0 - Disable SQWE output 1 - Enable SQWE output\r
61 UINT8 UIE : 1; // 0 - Update INT disabled 1 - Update INT enabled\r
62 UINT8 AIE : 1; // 0 - Alarm INT disabled 1 - Alarm INT Enabled\r
63 UINT8 PIE : 1; // 0 - Periodic INT disabled 1 - Periodic INT Enabled\r
64 UINT8 SET : 1; // 0 - Normal operation. 1 - Updates inhibited\r
65} RTC_REGISTER_B_BITS;\r
66\r
67typedef union {\r
68 RTC_REGISTER_B_BITS Bits;\r
69 UINT8 Data;\r
70} RTC_REGISTER_B;\r
71\r
72//\r
73// -- Time Management Routines --\r
74//\r
75\r
76#define IsLeap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))\r
b7d320f8 77#define SECSPERMIN (60)\r
a8c44645 78#define SECSPERHOUR (60 * 60)\r
79#define SECSPERDAY (24 * SECSPERHOUR)\r
80\r
81//\r
82// The arrays give the cumulative number of days up to the first of the\r
83// month number used as the index (1 -> 12) for regular and leap years.\r
84// The value at index 13 is for the whole year.\r
85//\r
86UINTN CumulativeDays[2][14] = {\r
87 {\r
88 0,\r
89 0,\r
90 31,\r
91 31 + 28,\r
92 31 + 28 + 31,\r
93 31 + 28 + 31 + 30,\r
94 31 + 28 + 31 + 30 + 31,\r
95 31 + 28 + 31 + 30 + 31 + 30,\r
96 31 + 28 + 31 + 30 + 31 + 30 + 31,\r
97 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,\r
98 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,\r
99 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,\r
100 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,\r
101 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31\r
102 },\r
103 {\r
104 0,\r
105 0,\r
106 31,\r
107 31 + 29,\r
108 31 + 29 + 31,\r
109 31 + 29 + 31 + 30,\r
110 31 + 29 + 31 + 30 + 31,\r
111 31 + 29 + 31 + 30 + 31 + 30,\r
112 31 + 29 + 31 + 30 + 31 + 30 + 31,\r
113 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31,\r
114 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30,\r
115 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,\r
116 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,\r
117 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 \r
118 }\r
119};\r
120\r
121/**\r
122 Read RTC content through its registers.\r
123\r
124 @param Address Address offset of RTC. It is recommended to use macros such as\r
125 RTC_ADDRESS_SECONDS.\r
126\r
127 @return The data of UINT8 type read from RTC.\r
128**/\r
129UINT8\r
130RtcRead (\r
131 IN UINT8 Address\r
132 )\r
133{\r
134 IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8) (Address | (UINT8) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & BIT7)));\r
135 return IoRead8 (PCAT_RTC_DATA_REGISTER);\r
136}\r
137\r
138/* Get the system time as seconds elapsed since midnight, January 1, 1970. */\r
139//INTN time(\r
140// INTN *timer\r
141// )\r
142time_t time (time_t *timer)\r
143{\r
144 UINT16 Year;\r
145 UINT8 Month;\r
146 UINT8 Day;\r
147 UINT8 Hour;\r
148 UINT8 Minute;\r
149 UINT8 Second;\r
150 UINT8 Century;\r
151 RTC_REGISTER_A RegisterA;\r
152 RTC_REGISTER_B RegisterB;\r
153 BOOLEAN IsPM;\r
154 UINT16 YearIndex;\r
155\r
156 RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A);\r
157 while (RegisterA.Bits.UIP == 1) {\r
158 CpuPause();\r
159 RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A);\r
160 }\r
161\r
162 Second = RtcRead (RTC_ADDRESS_SECONDS);\r
163 Minute = RtcRead (RTC_ADDRESS_MINUTES);\r
164 Hour = RtcRead (RTC_ADDRESS_HOURS);\r
165 Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);\r
166 Month = RtcRead (RTC_ADDRESS_MONTH);\r
167 Year = RtcRead (RTC_ADDRESS_YEAR);\r
168 Century = RtcRead (RTC_ADDRESS_CENTURY);\r
169\r
170 RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);\r
171\r
172 if ((Hour & BIT7) != 0) {\r
173 IsPM = TRUE;\r
174 } else {\r
175 IsPM = FALSE;\r
176 }\r
177 Hour = (UINT8) (Hour & 0x7f);\r
178\r
179 if (RegisterB.Bits.DM == 0) {\r
180 Year = BcdToDecimal8 ((UINT8) Year);\r
181 Month = BcdToDecimal8 (Month);\r
182 Day = BcdToDecimal8 (Day);\r
183 Hour = BcdToDecimal8 (Hour);\r
184 Minute = BcdToDecimal8 (Minute);\r
185 Second = BcdToDecimal8 (Second);\r
186 }\r
187 Century = BcdToDecimal8 (Century);\r
188\r
189 Year = (UINT16) (Century * 100 + Year);\r
190\r
191 //\r
192 // If time is in 12 hour format, convert it to 24 hour format\r
193 //\r
194 if (RegisterB.Bits.MIL == 0) {\r
195 if (IsPM && Hour < 12) {\r
196 Hour = (UINT8) (Hour + 12);\r
197 }\r
198 if (!IsPM && Hour == 12) {\r
199 Hour = 0;\r
200 }\r
201 }\r
202\r
203 //\r
204 // Years Handling\r
205 // UTime should now be set to 00:00:00 on Jan 1 of the current year.\r
206 //\r
207 for (YearIndex = 1970, *timer = 0; YearIndex != Year; YearIndex++) {\r
208 *timer = *timer + (time_t)(CumulativeDays[IsLeap(YearIndex)][13] * SECSPERDAY);\r
209 }\r
210\r
211 //\r
212 // Add in number of seconds for current Month, Day, Hour, Minute, Seconds, and TimeZone adjustment\r
213 //\r
214 ASSERT (Month <= 12);\r
215 *timer = *timer + \r
216 (time_t)(CumulativeDays[IsLeap(Year)][Month] * SECSPERDAY) + \r
217 (time_t)((Day - 1) * SECSPERDAY) + \r
218 (time_t)(Hour * SECSPERHOUR) + \r
219 (time_t)(Minute * 60) + \r
220 (time_t)Second;\r
221\r
222 return *timer;\r
223}\r
b7d320f8 224\r
225//\r
226// Convert a time value from type time_t to struct tm.\r
227//\r
228struct tm * gmtime (const time_t *timer)\r
229{\r
230 struct tm *GmTime;\r
231 UINT16 DayNo;\r
232 UINT16 DayRemainder;\r
233 time_t Year;\r
234 time_t YearNo;\r
235 UINT16 TotalDays;\r
236 UINT16 MonthNo;\r
237\r
238 if (timer == NULL) {\r
239 return NULL;\r
240 }\r
241\r
242 GmTime = malloc (sizeof (struct tm));\r
243 if (GmTime == NULL) {\r
244 return NULL;\r
245 }\r
246\r
247 ZeroMem ((VOID *) GmTime, (UINTN) sizeof (struct tm));\r
248\r
249 DayNo = (UINT16) (*timer / SECSPERDAY);\r
250 DayRemainder = (UINT16) (*timer % SECSPERDAY);\r
251\r
252 GmTime->tm_sec = (int) (DayRemainder % SECSPERMIN);\r
253 GmTime->tm_min = (int) ((DayRemainder % SECSPERHOUR) / SECSPERMIN);\r
254 GmTime->tm_hour = (int) (DayRemainder / SECSPERHOUR);\r
255 GmTime->tm_wday = (int) ((DayNo + 4) % 7);\r
256\r
257 for (Year = 1970, YearNo = 0; DayNo > 0; Year++) { \r
258 TotalDays = (UINT16) (IsLeap (Year) ? 366 : 365);\r
259 if (DayNo >= TotalDays) {\r
260 DayNo = (UINT16) (DayNo - TotalDays);\r
261 YearNo++;\r
262 } else {\r
263 break;\r
264 }\r
265 }\r
266\r
267 GmTime->tm_year = (int) (YearNo + (1970 - 1900));\r
268 GmTime->tm_yday = (int) DayNo;\r
269\r
270 for (MonthNo = 12; MonthNo > 1; MonthNo--) {\r
271 if (DayNo > CumulativeDays[IsLeap(Year)][MonthNo]) {\r
272 DayNo = (UINT16) (DayNo - (UINT16) (CumulativeDays[IsLeap(Year)][MonthNo]));\r
273 break;\r
274 }\r
275 }\r
276\r
277 GmTime->tm_mon = (int) MonthNo;\r
278 GmTime->tm_mday = (int) DayNo;\r
279\r
280 GmTime->tm_isdst = 0;\r
281 GmTime->tm_gmtoff = 0;\r
282 GmTime->tm_zone = NULL;\r
283\r
284 return GmTime;\r
285}\r
286\r