\r
**/\r
\r
-#include <Uefi.h>\r
#include <PiDxe.h>\r
+\r
+#include <Guid/EventGroup.h>\r
+#include <Guid/GlobalVariable.h>\r
+\r
#include <Library/BaseLib.h>\r
#include <Library/DebugLib.h>\r
-#include <Library/UefiLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
#include <Library/IoLib.h>\r
-#include <Library/RealTimeClockLib.h>\r
#include <Library/MemoryAllocationLib.h>\r
#include <Library/PcdLib.h>\r
-#include <Library/ArmPlatformSysConfigLib.h>\r
-#include <Library/DxeServicesTableLib.h>\r
+#include <Library/RealTimeClockLib.h>\r
+#include <Library/TimeBaseLib.h>\r
#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
#include <Library/UefiRuntimeServicesTableLib.h>\r
#include <Library/UefiRuntimeLib.h>\r
\r
#include <Protocol/RealTimeClock.h>\r
\r
-#include <Guid/GlobalVariable.h>\r
-#include <Guid/EventGroup.h>\r
+#include "PL031RealTimeClock.h"\r
\r
-#include <Drivers/PL031RealTimeClock.h>\r
-\r
-#include <Library/TimeBaseLib.h>\r
-\r
-#include <ArmPlatform.h>\r
-\r
-STATIC CONST CHAR16 mTimeZoneVariableName[] = L"PL031RtcTimeZone";\r
-STATIC CONST CHAR16 mDaylightVariableName[] = L"PL031RtcDaylight";\r
STATIC BOOLEAN mPL031Initialized = FALSE;\r
STATIC EFI_EVENT mRtcVirtualAddrChangeEvent;\r
STATIC UINTN mPL031RtcBase;\r
{\r
EFI_STATUS Status = EFI_SUCCESS;\r
UINT32 EpochSeconds;\r
- INT16 TimeZone;\r
- UINT8 Daylight;\r
- UINTN Size;\r
-\r
- // Initialize the hardware if not already done\r
- if (!mPL031Initialized) {\r
- Status = InitializePL031 ();\r
- if (EFI_ERROR (Status)) {\r
- goto EXIT;\r
- }\r
- }\r
-\r
- // Snapshot the time as early in the function call as possible\r
- // On some platforms we may have access to a battery backed up hardware clock.\r
- // If such RTC exists try to use it first.\r
- Status = ArmPlatformSysConfigGet (SYS_CFG_RTC, &EpochSeconds);\r
- if (Status == EFI_UNSUPPORTED) {\r
- // Battery backed up hardware RTC does not exist, revert to PL031\r
- EpochSeconds = MmioRead32 (mPL031RtcBase + PL031_RTC_DR_DATA_REGISTER);\r
- Status = EFI_SUCCESS;\r
- } else if (EFI_ERROR (Status)) {\r
- // Battery backed up hardware RTC exists but could not be read due to error. Abort.\r
- goto EXIT;\r
- } else {\r
- // Battery backed up hardware RTC exists and we read the time correctly from it.\r
- // Now sync the PL031 to the new time.\r
- MmioWrite32 (mPL031RtcBase + PL031_RTC_LR_LOAD_REGISTER, EpochSeconds);\r
- }\r
\r
// Ensure Time is a valid pointer\r
if (Time == NULL) {\r
- Status = EFI_INVALID_PARAMETER;\r
- goto EXIT;\r
+ return EFI_INVALID_PARAMETER;\r
}\r
\r
- // Get the current time zone information from non-volatile storage\r
- Size = sizeof (TimeZone);\r
- Status = EfiGetVariable (\r
- (CHAR16 *)mTimeZoneVariableName,\r
- &gEfiCallerIdGuid,\r
- NULL,\r
- &Size,\r
- (VOID *)&TimeZone\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- ASSERT(Status != EFI_INVALID_PARAMETER);\r
- ASSERT(Status != EFI_BUFFER_TOO_SMALL);\r
-\r
- if (Status != EFI_NOT_FOUND)\r
- goto EXIT;\r
-\r
- // The time zone variable does not exist in non-volatile storage, so create it.\r
- Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
- // Store it\r
- Status = EfiSetVariable (\r
- (CHAR16 *)mTimeZoneVariableName,\r
- &gEfiCallerIdGuid,\r
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
- Size,\r
- (VOID *)&(Time->TimeZone)\r
- );\r
+ // Initialize the hardware if not already done\r
+ if (!mPL031Initialized) {\r
+ Status = InitializePL031 ();\r
if (EFI_ERROR (Status)) {\r
- DEBUG ((\r
- EFI_D_ERROR,\r
- "LibGetTime: Failed to save %s variable to non-volatile storage, Status = %r\n",\r
- mTimeZoneVariableName,\r
- Status\r
- ));\r
- goto EXIT;\r
- }\r
- } else {\r
- // Got the time zone\r
- Time->TimeZone = TimeZone;\r
-\r
- // Check TimeZone bounds: -1440 to 1440 or 2047\r
- if (((Time->TimeZone < -1440) || (Time->TimeZone > 1440))\r
- && (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE)) {\r
- Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
- }\r
-\r
- // Adjust for the correct time zone\r
- if (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE) {\r
- EpochSeconds += Time->TimeZone * SEC_PER_MIN;\r
+ return Status;\r
}\r
}\r
\r
- // Get the current daylight information from non-volatile storage\r
- Size = sizeof (Daylight);\r
- Status = EfiGetVariable (\r
- (CHAR16 *)mDaylightVariableName,\r
- &gEfiCallerIdGuid,\r
- NULL,\r
- &Size,\r
- (VOID *)&Daylight\r
- );\r
+ EpochSeconds = MmioRead32 (mPL031RtcBase + PL031_RTC_DR_DATA_REGISTER);\r
\r
- if (EFI_ERROR (Status)) {\r
- ASSERT(Status != EFI_INVALID_PARAMETER);\r
- ASSERT(Status != EFI_BUFFER_TOO_SMALL);\r
-\r
- if (Status != EFI_NOT_FOUND)\r
- goto EXIT;\r
-\r
- // The daylight variable does not exist in non-volatile storage, so create it.\r
- Time->Daylight = 0;\r
- // Store it\r
- Status = EfiSetVariable (\r
- (CHAR16 *)mDaylightVariableName,\r
- &gEfiCallerIdGuid,\r
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
- Size,\r
- (VOID *)&(Time->Daylight)\r
- );\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((\r
- EFI_D_ERROR,\r
- "LibGetTime: Failed to save %s variable to non-volatile storage, Status = %r\n",\r
- mDaylightVariableName,\r
- Status\r
- ));\r
- goto EXIT;\r
- }\r
- } else {\r
- // Got the daylight information\r
- Time->Daylight = Daylight;\r
-\r
- // Adjust for the correct period\r
- if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) {\r
- // Convert to adjusted time, i.e. spring forwards one hour\r
- EpochSeconds += SEC_PER_HOUR;\r
- }\r
+ // Adjust for the correct time zone\r
+ // The timezone setting also reflects the DST setting of the clock\r
+ if (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE) {\r
+ EpochSeconds += Time->TimeZone * SEC_PER_MIN;\r
+ } else if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) {\r
+ // Convert to adjusted time, i.e. spring forwards one hour\r
+ EpochSeconds += SEC_PER_HOUR;\r
}\r
\r
// Convert from internal 32-bit time to UEFI time\r
Capabilities->SetsToZero = FALSE;\r
}\r
\r
- EXIT:\r
- return Status;\r
+ return EFI_SUCCESS;\r
}\r
\r
\r
EFI_STATUS Status;\r
UINTN EpochSeconds;\r
\r
- // Check the input parameters are within the range specified by UEFI\r
- if ((Time->Year < 1900) ||\r
- (Time->Year > 9999) ||\r
- (Time->Month < 1 ) ||\r
- (Time->Month > 12 ) ||\r
- (!IsDayValid (Time) ) ||\r
- (Time->Hour > 23 ) ||\r
- (Time->Minute > 59 ) ||\r
- (Time->Second > 59 ) ||\r
- (Time->Nanosecond > 999999999) ||\r
- (!((Time->TimeZone == EFI_UNSPECIFIED_TIMEZONE) || ((Time->TimeZone >= -1440) && (Time->TimeZone <= 1440)))) ||\r
- (Time->Daylight & (~(EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT)))\r
- ) {\r
- Status = EFI_INVALID_PARAMETER;\r
- goto EXIT;\r
- }\r
-\r
// Because the PL031 is a 32-bit counter counting seconds,\r
// the maximum time span is just over 136 years.\r
// Time is stored in Unix Epoch format, so it starts in 1970,\r
// Therefore it can not exceed the year 2106.\r
if ((Time->Year < 1970) || (Time->Year >= 2106)) {\r
- Status = EFI_UNSUPPORTED;\r
- goto EXIT;\r
+ return EFI_UNSUPPORTED;\r
}\r
\r
// Initialize the hardware if not already done\r
if (!mPL031Initialized) {\r
Status = InitializePL031 ();\r
if (EFI_ERROR (Status)) {\r
- goto EXIT;\r
+ return Status;\r
}\r
}\r
\r
EpochSeconds = EfiTimeToEpoch (Time);\r
\r
// Adjust for the correct time zone, i.e. convert to UTC time zone\r
+ // The timezone setting also reflects the DST setting of the clock\r
if (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE) {\r
EpochSeconds -= Time->TimeZone * SEC_PER_MIN;\r
- }\r
-\r
- // TODO: Automatic Daylight activation\r
-\r
- // Adjust for the correct period\r
- if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) {\r
+ } else if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) {\r
// Convert to un-adjusted time, i.e. fall back one hour\r
EpochSeconds -= SEC_PER_HOUR;\r
}\r
\r
- // On some platforms we may have access to a battery backed up hardware clock.\r
- //\r
- // If such RTC exists then it must be updated first, before the PL031,\r
- // to minimise any time drift. This is important because the battery backed-up\r
- // RTC maintains the master time for the platform across reboots.\r
- //\r
- // If such RTC does not exist then the following function returns UNSUPPORTED.\r
- Status = ArmPlatformSysConfigSet (SYS_CFG_RTC, EpochSeconds);\r
- if ((EFI_ERROR (Status)) && (Status != EFI_UNSUPPORTED)){\r
- // Any status message except SUCCESS and UNSUPPORTED indicates a hardware failure.\r
- goto EXIT;\r
- }\r
-\r
-\r
// Set the PL031\r
MmioWrite32 (mPL031RtcBase + PL031_RTC_LR_LOAD_REGISTER, EpochSeconds);\r
\r
- // The accesses to Variable Services can be very slow, because we may be writing to Flash.\r
- // Do this after having set the RTC.\r
-\r
- // Save the current time zone information into non-volatile storage\r
- Status = EfiSetVariable (\r
- (CHAR16 *)mTimeZoneVariableName,\r
- &gEfiCallerIdGuid,\r
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
- sizeof (Time->TimeZone),\r
- (VOID *)&(Time->TimeZone)\r
- );\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((\r
- EFI_D_ERROR,\r
- "LibSetTime: Failed to save %s variable to non-volatile storage, Status = %r\n",\r
- mTimeZoneVariableName,\r
- Status\r
- ));\r
- goto EXIT;\r
- }\r
-\r
- // Save the current daylight information into non-volatile storage\r
- Status = EfiSetVariable (\r
- (CHAR16 *)mDaylightVariableName,\r
- &gEfiCallerIdGuid,\r
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
- sizeof(Time->Daylight),\r
- (VOID *)&(Time->Daylight)\r
- );\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((\r
- EFI_D_ERROR,\r
- "LibSetTime: Failed to save %s variable to non-volatile storage, Status = %r\n",\r
- mDaylightVariableName,\r
- Status\r
- ));\r
- goto EXIT;\r
- }\r
-\r
- EXIT:\r
- return Status;\r
+ return EFI_SUCCESS;\r
}\r
\r
\r