---
EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c | 400
++++++++++++++++++++
EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf | 43
+++
2 files changed, 443 insertions(+)
diff --git
a/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c
b/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c
new file mode 100644
index 000000000000..4c354730d02b
--- /dev/null
+++ b/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c
@@ -0,0 +1,400 @@
+/** @file
+ *
+ * Implement virtual EFI RealTimeClock runtime services.
+ *
+ * Coypright (c) 2019, Pete Batard <p...@akeo.ie>
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warken...@gmail.com>
+ * Copyright (c) 2011-2014, ARM Ltd. All rights reserved.
+ * Copyright (c) 2008-2010, Apple Inc. All rights reserved.
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ *
+ * This program and the accompanying materials
+ * are licensed and made available under the terms and conditions of the BSD
License
+ * which accompanies this distribution. The full text of the license may be
found at
+ * http://opensource.org/licenses/bsd-license.php
+ *
+ * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR
IMPLIED.
+ *
+ * Based on
ArmPlatformPkg/Library/PL031RealTimeClockLib/PL031RealTimeClockLib.inf
+ *
+ **/
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/RealTimeClockLib.h>
+#include <Library/TimerLib.h>
+#include <Library/TimeBaseLib.h>
+#include <Library/UefiRuntimeLib.h>
+
+STATIC CONST CHAR16 mEpochVariableName[] = L"RtcEpochSeconds";
+STATIC CONST CHAR16 mTimeZoneVariableName[] = L"RtcTimeZone";
+STATIC CONST CHAR16 mDaylightVariableName[] = L"RtcDaylight";
+
+/**
+ Returns the current time and date information, and the time-keeping
capabilities
+ of the virtual RTC.
+
+ @param Time A pointer to storage to receive a snapshot of
the current time.
+ @param Capabilities An optional pointer to a buffer to receive
the real time clock
+ device's capabilities.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER Time is NULL.
+ @retval EFI_DEVICE_ERROR The time could not be retrieved due to
hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibGetTime (
+ OUT EFI_TIME *Time,
+ OUT EFI_TIME_CAPABILITIES *Capabilities
+ )
+{
+ EFI_STATUS Status;
+ UINT32 EpochSeconds;
+ INT16 TimeZone;
+ UINT8 Daylight;
+ UINT64 Freq;
+ UINT64 Counter;
+ UINT64 Remainder;
+ UINTN ElapsedSeconds;
+ UINTN Size;
+
+ if (Time == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Get the counter frequency
+ Freq = GetPerformanceCounterProperties (NULL, NULL);
+ if (Freq == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ // Get the epoch time from non-volatile storage
+ Size = sizeof (UINTN);
+ ElapsedSeconds = 0;
+ Status = EfiGetVariable (
+ (CHAR16 *)mEpochVariableName,
+ &gEfiCallerIdGuid,
+ NULL,
+ &Size,
+ (VOID *)&ElapsedSeconds
+ );
+ // Fall back to compilation-time epoch if not set
+ if (EFI_ERROR (Status)) {
+ ASSERT(Status != EFI_INVALID_PARAMETER);
+ ASSERT(Status != EFI_BUFFER_TOO_SMALL);
+ //
+ // The following is intended to produce a compilation error on build
+ // environments where BUILD_EPOCH can not be set from inline shell.
+ // If you are attempting to use this library on such an environment, please
+ // contact the edk2 mailing list, so we can try to add support for it.
+ //
+ ElapsedSeconds = BUILD_EPOCH;
+ DEBUG ((
+ DEBUG_INFO,
+ "LibGetTime: %s non volatile variable was not found - Using compilation time
epoch.\n",
+ mEpochVariableName
+ ));
+ }
+ Counter = GetPerformanceCounter ();
+ ElapsedSeconds += DivU64x64Remainder (Counter, Freq, &Remainder);
+
+ // Get the current time zone information from non-volatile storage
+ Size = sizeof (TimeZone);
+ Status = EfiGetVariable (
+ (CHAR16 *)mTimeZoneVariableName,
+ &gEfiCallerIdGuid,
+ NULL,
+ &Size,
+ (VOID *)&TimeZone
+ );
+
+ if (EFI_ERROR (Status)) {
+ ASSERT(Status != EFI_INVALID_PARAMETER);
+ ASSERT(Status != EFI_BUFFER_TOO_SMALL);
+
+ if (Status != EFI_NOT_FOUND) {
+ return Status;
+ }
+
+ // The time zone variable does not exist in non-volatile storage, so
create it.
+ Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;
+ // Store it
+ Status = EfiSetVariable (
+ (CHAR16 *)mTimeZoneVariableName,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS,
+ Size,
+ (VOID *)&(Time->TimeZone)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "LibGetTime: Failed to save %s variable to non-volatile storage, Status =
%r\n",
+ mTimeZoneVariableName,
+ Status
+ ));
+ return Status;
+ }
+ } else {
+ // Got the time zone
+ Time->TimeZone = TimeZone;
+
+ // Check TimeZone bounds: -1440 to 1440 or 2047
+ if (((Time->TimeZone < -1440) || (Time->TimeZone > 1440))
+ && (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE)) {
+ Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;
+ }
+
+ // Adjust for the correct time zone
+ if (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE) {
+ EpochSeconds += Time->TimeZone * SEC_PER_MIN;
+ }
+ }
+
+ // Get the current daylight information from non-volatile storage
+ Size = sizeof (Daylight);
+ Status = EfiGetVariable (
+ (CHAR16 *)mDaylightVariableName,
+ &gEfiCallerIdGuid,
+ NULL,
+ &Size,
+ (VOID *)&Daylight
+ );
+
+ if (EFI_ERROR (Status)) {
+ ASSERT(Status != EFI_INVALID_PARAMETER);
+ ASSERT(Status != EFI_BUFFER_TOO_SMALL);
+
+ if (Status != EFI_NOT_FOUND) {
+ return Status;
+ }
+
+ // The daylight variable does not exist in non-volatile storage, so create
it.
+ Time->Daylight = 0;
+ // Store it
+ Status = EfiSetVariable (
+ (CHAR16 *)mDaylightVariableName,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS,
+ Size,
+ (VOID *)&(Time->Daylight)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "LibGetTime: Failed to save %s variable to non-volatile storage, Status =
%r\n",
+ mDaylightVariableName,
+ Status
+ ));
+ return Status;
+ }
+ } else {
+ // Got the daylight information
+ Time->Daylight = Daylight;
+
+ // Adjust for the correct period
+ if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) {
+ // Convert to adjusted time, i.e. spring forwards one hour
+ EpochSeconds += SEC_PER_HOUR;
+ }
+ }
+
+ EpochToEfiTime (ElapsedSeconds, Time);
+
+ // Because we use the performance counter, we can fill the Nanosecond
attribute
+ // provided that the remainder doesn't overflow 64-bit during multiplication.
+ if (Remainder <= 18446744073U) {
+ Time->Nanosecond = MultU64x64 (Remainder, 1000000000U) / Freq;
+ } else {
+ DEBUG ((DEBUG_WARN, "LibGetTime: Nanosecond value not set (64-bit
overflow).\n"));
+ }
+
+ if (Capabilities) {
+ Capabilities->Accuracy = 0;
+ Capabilities->Resolution = Freq;
+ Capabilities->SetsToZero = FALSE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets the current local time and date information.
+
+ @param Time A pointer to the current time.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER A time field is out of range.
+ @retval EFI_DEVICE_ERROR The time could not be set due due to hardware
error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibSetTime (
+ IN EFI_TIME *Time
+ )
+{
+ EFI_STATUS Status;
+ UINTN EpochSeconds;
+
+ if (!IsTimeValid (Time)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EpochSeconds = EfiTimeToEpoch (Time);
+
+ // Adjust for the correct time zone, i.e. convert to UTC time zone
+ if (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE) {
+ EpochSeconds -= Time->TimeZone * SEC_PER_MIN;
+ }
+
+ // Adjust for the correct period
+ if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) {
+ // Convert to un-adjusted time, i.e. fall back one hour
+ EpochSeconds -= SEC_PER_HOUR;
+ }
+
+ // Save the current time zone information into non-volatile storage
+ Status = EfiSetVariable (
+ (CHAR16 *)mTimeZoneVariableName,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (Time->TimeZone),
+ (VOID *)&(Time->TimeZone)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "LibSetTime: Failed to save %s variable to non-volatile storage, Status =
%r\n",
+ mTimeZoneVariableName,
+ Status
+ ));
+ return Status;
+ }
+
+ // Save the current daylight information into non-volatile storage
+ Status = EfiSetVariable (
+ (CHAR16 *)mDaylightVariableName,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof(Time->Daylight),
+ (VOID *)&(Time->Daylight)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "LibSetTime: Failed to save %s variable to non-volatile storage, Status =
%r\n",
+ mDaylightVariableName,
+ Status
+ ));
+ return Status;
+ }
+
+ Status = EfiSetVariable (
+ (CHAR16 *)mEpochVariableName,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (EpochSeconds),
+ &EpochSeconds
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "LibSetTime: Failed to save %s variable to non-volatile storage, Status =
%r\n",
+ mDaylightVariableName,
+ Status
+ ));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Returns the current wakeup alarm clock setting.
+
+ @param Enabled Indicates if the alarm is currently enabled
or disabled.
+ @param Pending Indicates if the alarm signal is pending and
requires acknowledgement.
+ @param Time The current alarm setting.
+
+ @retval EFI_SUCCESS The alarm settings were returned.
+ @retval EFI_INVALID_PARAMETER Any parameter is NULL.
+ @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to
a hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibGetWakeupTime (
+ OUT BOOLEAN *Enabled,
+ OUT BOOLEAN *Pending,
+ OUT EFI_TIME *Time
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Sets the system wakeup alarm clock time.
+
+ @param Enabled Enable or disable the wakeup alarm.
+ @param Time If Enable is TRUE, the time to set the wakeup
alarm for.
+
+ @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was
enabled. If
+ Enable is FALSE, then the wakeup alarm was disabled.
+ @retval EFI_INVALID_PARAMETER A time field is out of range.
+ @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a
hardware error.
+ @retval EFI_UNSUPPORTED A wakeup timer is not supported on this
platform.
+
+**/
+EFI_STATUS
+EFIAPI
+LibSetWakeupTime (
+ IN BOOLEAN Enabled,
+ OUT EFI_TIME *Time
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ This is the declaration of an EFI image entry point. This can be the entry
point to an application
+ written to this specification, an EFI boot service driver, or an EFI
runtime driver.
+
+ @param ImageHandle Handle that identifies the loaded image.
+ @param SystemTable System Table for this image.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+LibRtcInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Fixup internal data so that EFI can be call in virtual mode.
+ Call the passed in Child Notify event and convert any pointers in
+ lib to virtual mode.
+
+ @param[in] Event The Event that is being processed
+ @param[in] Context Event Context
+**/
+VOID
+EFIAPI
+LibRtcVirtualNotifyEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ return;
+}
diff --git
a/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf
b/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf
new file mode 100644
index 000000000000..ed69faad4205
--- /dev/null
+++ b/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf
@@ -0,0 +1,43 @@
+#/** @file
+#
+# Implement virtual EFI RealTimeClock runtime services.
+#
+# Copyright (c) 2019, Pete Batard <p...@akeo.ie>
+# Copyright (c) 2018, Andrei Warkentin <andrey.warken...@gmail.com>
+# Copyright (c) Microsoft Corporation. All rights reserved.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD
License
+# which accompanies this distribution. The full text of the license may be
found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR
IMPLIED.
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x0001001A
+ BASE_NAME = VirtualRealTimeClockLib
+ FILE_GUID = 1E27D461-78F3-4F7D-B1C2-F72384F13A6E
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = RealTimeClockLib
+
+[Sources.common]
+ VirtualRealTimeClockLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+
+[LibraryClasses]
+ IoLib
+ DebugLib
+ TimerLib
+ TimeBaseLib
+ UefiRuntimeLib
+
+# Current usage of this library expects GCC in a UNIX-like shell environment
with the date command
+[BuildOptions]
+ GCC:*_*_*_CC_FLAGS = -DBUILD_EPOCH=`date +%s`
--
2.17.0.windows.1