summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.c')
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.c289
1 files changed, 289 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.c
new file mode 100644
index 00000000..2a3962c4
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.c
@@ -0,0 +1,289 @@
+/** @file
+*
+* Copyright (c) 2016, Hisilicon Limited. All rights reserved.
+* Copyright (c) 2016-2019, Linaro Limited. All rights reserved.
+* Copyright (c) 2021, Ampere Computing LLC. All rights reserved.
+*
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#include <Uefi/UefiBaseType.h>
+#include <Uefi/UefiSpec.h>
+#include <Library/DebugLib.h>
+#include <Library/TimeBaseLib.h>
+
+/**
+ Converts Epoch seconds (elapsed since 1970 JANUARY 01, 00:00:00 UTC) to EFI_TIME.
+
+ @param EpochSeconds Epoch seconds.
+ @param Time The time converted to UEFI format.
+
+**/
+VOID
+EFIAPI
+EpochToEfiTime (
+ IN UINTN EpochSeconds,
+ OUT EFI_TIME *Time
+ )
+{
+ UINTN a;
+ UINTN b;
+ UINTN c;
+ UINTN d;
+ UINTN g;
+ UINTN j;
+ UINTN m;
+ UINTN y;
+ UINTN da;
+ UINTN db;
+ UINTN dc;
+ UINTN dg;
+ UINTN hh;
+ UINTN mm;
+ UINTN ss;
+ UINTN J;
+
+ J = (EpochSeconds / 86400) + 2440588;
+ j = J + 32044;
+ g = j / 146097;
+ dg = j % 146097;
+ c = (((dg / 36524) + 1) * 3) / 4;
+ dc = dg - (c * 36524);
+ b = dc / 1461;
+ db = dc % 1461;
+ a = (((db / 365) + 1) * 3) / 4;
+ da = db - (a * 365);
+ y = (g * 400) + (c * 100) + (b * 4) + a;
+ m = (((da * 5) + 308) / 153) - 2;
+ d = da - (((m + 4) * 153) / 5) + 122;
+
+ Time->Year = (UINT16)(y - 4800 + ((m + 2) / 12));
+ Time->Month = ((m + 2) % 12) + 1;
+ Time->Day = (UINT8)(d + 1);
+
+ ss = EpochSeconds % 60;
+ a = (EpochSeconds - ss) / 60;
+ mm = a % 60;
+ b = (a - mm) / 60;
+ hh = b % 24;
+
+ Time->Hour = (UINT8)hh;
+ Time->Minute = (UINT8)mm;
+ Time->Second = (UINT8)ss;
+ Time->Nanosecond = 0;
+
+}
+
+/**
+ Calculate Epoch days.
+
+ @param Time The UEFI time to be calculated.
+
+ @return Number of days.
+
+**/
+UINTN
+EFIAPI
+EfiGetEpochDays (
+ IN EFI_TIME *Time
+ )
+{
+ UINTN a;
+ UINTN y;
+ UINTN m;
+ UINTN JulianDate; // Absolute Julian Date representation of the supplied Time
+ UINTN EpochDays; // Number of days elapsed since EPOCH_JULIAN_DAY
+
+ a = (14 - Time->Month) / 12 ;
+ y = Time->Year + 4800 - a;
+ m = Time->Month + (12*a) - 3;
+
+ JulianDate = Time->Day + ((153*m + 2)/5) + (365*y) + (y/4) - (y/100) + (y/400) - 32045;
+
+ ASSERT (JulianDate >= EPOCH_JULIAN_DATE);
+ EpochDays = JulianDate - EPOCH_JULIAN_DATE;
+
+ return EpochDays;
+}
+
+/**
+ Converts EFI_TIME to Epoch seconds (elapsed since 1970 JANUARY 01, 00:00:00 UTC).
+
+ @param Time The UEFI time to be converted.
+
+ @return Number of seconds.
+
+**/
+UINTN
+EFIAPI
+EfiTimeToEpoch (
+ IN EFI_TIME *Time
+ )
+{
+ UINTN EpochDays; // Number of days elapsed since EPOCH_JULIAN_DAY
+ UINTN EpochSeconds;
+
+ EpochDays = EfiGetEpochDays (Time);
+
+ EpochSeconds = (EpochDays * SEC_PER_DAY) + ((UINTN)Time->Hour * SEC_PER_HOUR) + (Time->Minute * SEC_PER_MIN) + Time->Second;
+
+ return EpochSeconds;
+}
+
+/**
+ Get the day of the week from the UEFI time.
+
+ @param Time The UEFI time to be calculated.
+
+ @return The day of the week: Sunday=0, Monday=1, ... Saturday=6
+
+**/
+UINTN
+EfiTimeToWday (
+ IN EFI_TIME *Time
+ )
+{
+ UINTN EpochDays; // Number of days elapsed since EPOCH_JULIAN_DAY
+
+ EpochDays = EfiGetEpochDays (Time);
+
+ // 4=1/1/1970 was a Thursday
+
+ return (EpochDays + 4) % 7;
+}
+
+/**
+ Check if it is a leap year.
+
+ @param Time The UEFI time to be checked.
+
+ @retval TRUE It is a leap year.
+ @retval FALSE It is NOT a leap year.
+
+**/
+BOOLEAN
+EFIAPI
+IsLeapYear (
+ IN EFI_TIME *Time
+ )
+{
+ if (Time->Year % 4 == 0) {
+ if (Time->Year % 100 == 0) {
+ if (Time->Year % 400 == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else {
+ return TRUE;
+ }
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Check if the day in the UEFI time is valid.
+
+ @param Time The UEFI time to be checked.
+
+ @retval TRUE Valid.
+ @retval FALSE Invalid.
+
+**/
+BOOLEAN
+EFIAPI
+IsDayValid (
+ IN EFI_TIME *Time
+ )
+{
+ STATIC CONST INTN DayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+ if (Time->Day < 1 ||
+ Time->Day > DayOfMonth[Time->Month - 1] ||
+ (Time->Month == 2 && (!IsLeapYear (Time) && Time->Day > 28))
+ ) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Check if the time zone is valid.
+ Valid values are between -1440 and 1440 or 2047 (EFI_UNSPECIFIED_TIMEZONE).
+
+ @param TimeZone The time zone to be checked.
+
+ @retval TRUE Valid.
+ @retval FALSE Invalid.
+
+**/
+BOOLEAN
+EFIAPI
+IsValidTimeZone (
+ IN INT16 TimeZone
+ )
+{
+ return TimeZone == EFI_UNSPECIFIED_TIMEZONE ||
+ (TimeZone >= -1440 && TimeZone <= 1440);
+}
+
+/**
+ Check if the daylight is valid.
+ Valid values are:
+ 0 : Time is not affected.
+ 1 : Time is affected, and has not been adjusted for daylight savings.
+ 3 : Time is affected, and has been adjusted for daylight savings.
+ All other values are invalid.
+
+ @param Daylight The daylight to be checked.
+
+ @retval TRUE Valid.
+ @retval FALSE Invalid.
+
+**/
+BOOLEAN
+EFIAPI
+IsValidDaylight (
+ IN INT8 Daylight
+ )
+{
+ return Daylight == 0 ||
+ Daylight == EFI_TIME_ADJUST_DAYLIGHT ||
+ Daylight == (EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT);
+}
+
+/**
+ Check if the UEFI time is valid.
+
+ @param Time The UEFI time to be checked.
+
+ @retval TRUE Valid.
+ @retval FALSE Invalid.
+
+**/
+BOOLEAN
+EFIAPI
+IsTimeValid (
+ IN EFI_TIME *Time
+ )
+{
+ // Check the input parameters are within the range specified by UEFI
+ if ((Time->Year < 2000) ||
+ (Time->Year > 2099) ||
+ (Time->Month < 1 ) ||
+ (Time->Month > 12 ) ||
+ (!IsDayValid (Time) ) ||
+ (Time->Hour > 23 ) ||
+ (Time->Minute > 59 ) ||
+ (Time->Second > 59 ) ||
+ (Time->Nanosecond > 999999999) ||
+ (!IsValidTimeZone(Time->TimeZone)) ||
+ (!IsValidDaylight(Time->Daylight))) {
+ return FALSE;
+ }
+
+ return TRUE;
+}