]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / EmbeddedPkg / Library / TimeBaseLib / TimeBaseLib.c
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 }