123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422 |
- /** @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;
- }
|