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