/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c
https://github.com/tianocore/edk2 · C · 422 lines · 272 code · 37 blank · 113 comment · 45 complexity · 2b0798d3c9a7af1ea723d7287dd4ce6e MD5 · raw file
- /** @file
- *
- * Implement virtual EFI RealTimeClock runtime services.
- *
- * Coypright (c) 2019, Pete Batard <pete@akeo.ie>
- * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
- * Copyright (c) 2011-2021, ARM Ltd. All rights reserved.
- * Copyright (c) 2008-2010, Apple Inc. All rights reserved.
- * Copyright (c) Microsoft Corporation. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-2-Clause-Patent
- *
- * 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;
- INT16 TimeZone;
- UINT8 Daylight;
- UINT64 Freq;
- UINT64 Counter;
- UINT64 Remainder;
- UINTN EpochSeconds;
- 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);
- EpochSeconds = 0;
- Status = EfiGetVariable (
- (CHAR16 *)mEpochVariableName,
- &gEfiCallerIdGuid,
- NULL,
- &Size,
- (VOID *)&EpochSeconds
- );
- // 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.
- //
- EpochSeconds = BUILD_EPOCH;
- DEBUG ((
- DEBUG_INFO,
- "LibGetTime: %s non volatile variable was not found - Using compilation time epoch.\n",
- mEpochVariableName
- ));
-
- EfiSetVariable (
- (CHAR16 *)mEpochVariableName,
- &gEfiCallerIdGuid,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
- sizeof (EpochSeconds),
- &EpochSeconds
- );
- }
-
- Counter = GetPerformanceCounter ();
- EpochSeconds += 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 (EpochSeconds, 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 = (UINT32)(MultU64x64 (Remainder, 1000000000U) / Freq);
- } else {
- DEBUG ((DEBUG_WARN, "LibGetTime: Nanosecond value not set (64-bit overflow).\n"));
- }
-
- if (Capabilities) {
- Capabilities->Accuracy = 0;
- Capabilities->Resolution = 1;
- 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;
- UINT64 Freq;
- UINT64 Counter;
- UINT64 Remainder;
- 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))
- {
- EpochSeconds -= Time->TimeZone * SEC_PER_MIN;
- }
-
- // Adjust for the correct period
- if ( ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT)
- && (EpochSeconds > SEC_PER_HOUR))
- {
- // Convert to un-adjusted time, i.e. fall back one hour
- EpochSeconds -= SEC_PER_HOUR;
- }
-
- // Use the performance counter to subtract the number of seconds
- // since platform reset. Without this, setting time from the shell
- // and immediately reading it back would result in a forward time
- // offset, of the duration during which the platform has been up.
- Freq = GetPerformanceCounterProperties (NULL, NULL);
- if (Freq != 0) {
- Counter = GetPerformanceCounter ();
- if (EpochSeconds > DivU64x64Remainder (Counter, Freq, &Remainder)) {
- EpochSeconds -= DivU64x64Remainder (Counter, Freq, &Remainder);
- }
- }
-
- // 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",
- mEpochVariableName,
- 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;
- }