1 | /** @file
|
---|
2 | *
|
---|
3 | * Copyright (c) 2016, Hisilicon Limited. All rights reserved.
|
---|
4 | * Copyright (c) 2016-2019, Linaro Limited. All rights reserved.
|
---|
5 | * Copyright (c) 2021, Ampere Computing LLC. All rights reserved.
|
---|
6 | *
|
---|
7 | * SPDX-License-Identifier: BSD-2-Clause-Patent
|
---|
8 | *
|
---|
9 | **/
|
---|
10 |
|
---|
11 | #include <Uefi/UefiBaseType.h>
|
---|
12 | #include <Uefi/UefiSpec.h>
|
---|
13 | #include <Library/DebugLib.h>
|
---|
14 | #include <Library/TimeBaseLib.h>
|
---|
15 |
|
---|
16 | /**
|
---|
17 | Converts Epoch seconds (elapsed since 1970 JANUARY 01, 00:00:00 UTC) to EFI_TIME.
|
---|
18 |
|
---|
19 | @param EpochSeconds Epoch seconds.
|
---|
20 | @param Time The time converted to UEFI format.
|
---|
21 |
|
---|
22 | **/
|
---|
23 | VOID
|
---|
24 | EFIAPI
|
---|
25 | EpochToEfiTime (
|
---|
26 | IN UINTN EpochSeconds,
|
---|
27 | OUT EFI_TIME *Time
|
---|
28 | )
|
---|
29 | {
|
---|
30 | UINTN a;
|
---|
31 | UINTN b;
|
---|
32 | UINTN c;
|
---|
33 | UINTN d;
|
---|
34 | UINTN g;
|
---|
35 | UINTN j;
|
---|
36 | UINTN m;
|
---|
37 | UINTN y;
|
---|
38 | UINTN da;
|
---|
39 | UINTN db;
|
---|
40 | UINTN dc;
|
---|
41 | UINTN dg;
|
---|
42 | UINTN hh;
|
---|
43 | UINTN mm;
|
---|
44 | UINTN ss;
|
---|
45 | UINTN J;
|
---|
46 |
|
---|
47 | J = (EpochSeconds / 86400) + 2440588;
|
---|
48 | j = J + 32044;
|
---|
49 | g = j / 146097;
|
---|
50 | dg = j % 146097;
|
---|
51 | c = (((dg / 36524) + 1) * 3) / 4;
|
---|
52 | dc = dg - (c * 36524);
|
---|
53 | b = dc / 1461;
|
---|
54 | db = dc % 1461;
|
---|
55 | a = (((db / 365) + 1) * 3) / 4;
|
---|
56 | da = db - (a * 365);
|
---|
57 | y = (g * 400) + (c * 100) + (b * 4) + a;
|
---|
58 | m = (((da * 5) + 308) / 153) - 2;
|
---|
59 | d = da - (((m + 4) * 153) / 5) + 122;
|
---|
60 |
|
---|
61 | Time->Year = (UINT16)(y - 4800 + ((m + 2) / 12));
|
---|
62 | Time->Month = ((m + 2) % 12) + 1;
|
---|
63 | Time->Day = (UINT8)(d + 1);
|
---|
64 |
|
---|
65 | ss = EpochSeconds % 60;
|
---|
66 | a = (EpochSeconds - ss) / 60;
|
---|
67 | mm = a % 60;
|
---|
68 | b = (a - mm) / 60;
|
---|
69 | hh = b % 24;
|
---|
70 |
|
---|
71 | Time->Hour = (UINT8)hh;
|
---|
72 | Time->Minute = (UINT8)mm;
|
---|
73 | Time->Second = (UINT8)ss;
|
---|
74 | Time->Nanosecond = 0;
|
---|
75 | }
|
---|
76 |
|
---|
77 | /**
|
---|
78 | Calculate Epoch days.
|
---|
79 |
|
---|
80 | @param Time The UEFI time to be calculated.
|
---|
81 |
|
---|
82 | @return Number of days.
|
---|
83 |
|
---|
84 | **/
|
---|
85 | UINTN
|
---|
86 | EFIAPI
|
---|
87 | EfiGetEpochDays (
|
---|
88 | IN EFI_TIME *Time
|
---|
89 | )
|
---|
90 | {
|
---|
91 | UINTN a;
|
---|
92 | UINTN y;
|
---|
93 | UINTN m;
|
---|
94 | UINTN JulianDate; // Absolute Julian Date representation of the supplied Time
|
---|
95 | UINTN EpochDays; // Number of days elapsed since EPOCH_JULIAN_DAY
|
---|
96 |
|
---|
97 | a = (14 - Time->Month) / 12;
|
---|
98 | y = Time->Year + 4800 - a;
|
---|
99 | m = Time->Month + (12*a) - 3;
|
---|
100 |
|
---|
101 | JulianDate = Time->Day + ((153*m + 2)/5) + (365*y) + (y/4) - (y/100) + (y/400) - 32045;
|
---|
102 |
|
---|
103 | ASSERT (JulianDate >= EPOCH_JULIAN_DATE);
|
---|
104 | EpochDays = JulianDate - EPOCH_JULIAN_DATE;
|
---|
105 |
|
---|
106 | return EpochDays;
|
---|
107 | }
|
---|
108 |
|
---|
109 | /**
|
---|
110 | Converts EFI_TIME to Epoch seconds (elapsed since 1970 JANUARY 01, 00:00:00 UTC).
|
---|
111 |
|
---|
112 | @param Time The UEFI time to be converted.
|
---|
113 |
|
---|
114 | @return Number of seconds.
|
---|
115 |
|
---|
116 | **/
|
---|
117 | UINTN
|
---|
118 | EFIAPI
|
---|
119 | EfiTimeToEpoch (
|
---|
120 | IN EFI_TIME *Time
|
---|
121 | )
|
---|
122 | {
|
---|
123 | UINTN EpochDays; // Number of days elapsed since EPOCH_JULIAN_DAY
|
---|
124 | UINTN EpochSeconds;
|
---|
125 |
|
---|
126 | EpochDays = EfiGetEpochDays (Time);
|
---|
127 |
|
---|
128 | EpochSeconds = (EpochDays * SEC_PER_DAY) + ((UINTN)Time->Hour * SEC_PER_HOUR) + (Time->Minute * SEC_PER_MIN) + Time->Second;
|
---|
129 |
|
---|
130 | return EpochSeconds;
|
---|
131 | }
|
---|
132 |
|
---|
133 | /**
|
---|
134 | Get the day of the week from the UEFI time.
|
---|
135 |
|
---|
136 | @param Time The UEFI time to be calculated.
|
---|
137 |
|
---|
138 | @return The day of the week: Sunday=0, Monday=1, ... Saturday=6
|
---|
139 |
|
---|
140 | **/
|
---|
141 | UINTN
|
---|
142 | EfiTimeToWday (
|
---|
143 | IN EFI_TIME *Time
|
---|
144 | )
|
---|
145 | {
|
---|
146 | UINTN EpochDays; // Number of days elapsed since EPOCH_JULIAN_DAY
|
---|
147 |
|
---|
148 | EpochDays = EfiGetEpochDays (Time);
|
---|
149 |
|
---|
150 | // 4=1/1/1970 was a Thursday
|
---|
151 |
|
---|
152 | return (EpochDays + 4) % 7;
|
---|
153 | }
|
---|
154 |
|
---|
155 | /**
|
---|
156 | Check if it is a leap year.
|
---|
157 |
|
---|
158 | @param Time The UEFI time to be checked.
|
---|
159 |
|
---|
160 | @retval TRUE It is a leap year.
|
---|
161 | @retval FALSE It is NOT a leap year.
|
---|
162 |
|
---|
163 | **/
|
---|
164 | BOOLEAN
|
---|
165 | EFIAPI
|
---|
166 | IsLeapYear (
|
---|
167 | IN EFI_TIME *Time
|
---|
168 | )
|
---|
169 | {
|
---|
170 | if (Time->Year % 4 == 0) {
|
---|
171 | if (Time->Year % 100 == 0) {
|
---|
172 | if (Time->Year % 400 == 0) {
|
---|
173 | return TRUE;
|
---|
174 | } else {
|
---|
175 | return FALSE;
|
---|
176 | }
|
---|
177 | } else {
|
---|
178 | return TRUE;
|
---|
179 | }
|
---|
180 | } else {
|
---|
181 | return FALSE;
|
---|
182 | }
|
---|
183 | }
|
---|
184 |
|
---|
185 | /**
|
---|
186 | Check if the day in the UEFI time is valid.
|
---|
187 |
|
---|
188 | @param Time The UEFI time to be checked.
|
---|
189 |
|
---|
190 | @retval TRUE Valid.
|
---|
191 | @retval FALSE Invalid.
|
---|
192 |
|
---|
193 | **/
|
---|
194 | BOOLEAN
|
---|
195 | EFIAPI
|
---|
196 | IsDayValid (
|
---|
197 | IN EFI_TIME *Time
|
---|
198 | )
|
---|
199 | {
|
---|
200 | STATIC CONST INTN DayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
---|
201 |
|
---|
202 | if ((Time->Day < 1) ||
|
---|
203 | (Time->Day > DayOfMonth[Time->Month - 1]) ||
|
---|
204 | ((Time->Month == 2) && (!IsLeapYear (Time) && (Time->Day > 28)))
|
---|
205 | )
|
---|
206 | {
|
---|
207 | return FALSE;
|
---|
208 | }
|
---|
209 |
|
---|
210 | return TRUE;
|
---|
211 | }
|
---|
212 |
|
---|
213 | /**
|
---|
214 | Check if the time zone is valid.
|
---|
215 | Valid values are between -1440 and 1440 or 2047 (EFI_UNSPECIFIED_TIMEZONE).
|
---|
216 |
|
---|
217 | @param TimeZone The time zone to be checked.
|
---|
218 |
|
---|
219 | @retval TRUE Valid.
|
---|
220 | @retval FALSE Invalid.
|
---|
221 |
|
---|
222 | **/
|
---|
223 | BOOLEAN
|
---|
224 | EFIAPI
|
---|
225 | IsValidTimeZone (
|
---|
226 | IN INT16 TimeZone
|
---|
227 | )
|
---|
228 | {
|
---|
229 | return TimeZone == EFI_UNSPECIFIED_TIMEZONE ||
|
---|
230 | (TimeZone >= -1440 && TimeZone <= 1440);
|
---|
231 | }
|
---|
232 |
|
---|
233 | /**
|
---|
234 | Check if the daylight is valid.
|
---|
235 | Valid values are:
|
---|
236 | 0 : Time is not affected.
|
---|
237 | 1 : Time is affected, and has not been adjusted for daylight savings.
|
---|
238 | 3 : Time is affected, and has been adjusted for daylight savings.
|
---|
239 | All other values are invalid.
|
---|
240 |
|
---|
241 | @param Daylight The daylight to be checked.
|
---|
242 |
|
---|
243 | @retval TRUE Valid.
|
---|
244 | @retval FALSE Invalid.
|
---|
245 |
|
---|
246 | **/
|
---|
247 | BOOLEAN
|
---|
248 | EFIAPI
|
---|
249 | IsValidDaylight (
|
---|
250 | IN INT8 Daylight
|
---|
251 | )
|
---|
252 | {
|
---|
253 | return Daylight == 0 ||
|
---|
254 | Daylight == EFI_TIME_ADJUST_DAYLIGHT ||
|
---|
255 | Daylight == (EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT);
|
---|
256 | }
|
---|
257 |
|
---|
258 | /**
|
---|
259 | Check if the UEFI time is valid.
|
---|
260 |
|
---|
261 | @param Time The UEFI time to be checked.
|
---|
262 |
|
---|
263 | @retval TRUE Valid.
|
---|
264 | @retval FALSE Invalid.
|
---|
265 |
|
---|
266 | **/
|
---|
267 | BOOLEAN
|
---|
268 | EFIAPI
|
---|
269 | IsTimeValid (
|
---|
270 | IN EFI_TIME *Time
|
---|
271 | )
|
---|
272 | {
|
---|
273 | // Check the input parameters are within the range specified by UEFI
|
---|
274 | if ((Time->Year < 2000) ||
|
---|
275 | (Time->Year > 2099) ||
|
---|
276 | (Time->Month < 1) ||
|
---|
277 | (Time->Month > 12) ||
|
---|
278 | (!IsDayValid (Time)) ||
|
---|
279 | (Time->Hour > 23) ||
|
---|
280 | (Time->Minute > 59) ||
|
---|
281 | (Time->Second > 59) ||
|
---|
282 | (Time->Nanosecond > 999999999) ||
|
---|
283 | (!IsValidTimeZone (Time->TimeZone)) ||
|
---|
284 | (!IsValidDaylight (Time->Daylight)))
|
---|
285 | {
|
---|
286 | return FALSE;
|
---|
287 | }
|
---|
288 |
|
---|
289 | return TRUE;
|
---|
290 | }
|
---|