+ EFI_STATUS Status = EFI_SUCCESS;\r
+ UINTN EpochSeconds;\r
+ INT16 *TimeZone = 0;\r
+ UINTN *Daylight = 0;\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( 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( 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
+ }\r
+\r
+ // Get the current time zone information from non-volatile storage\r
+ TimeZone = (INT16 *)GetVariable(mTimeZoneVariableName, &gEfiGlobalVariableGuid);\r
+\r
+ if( TimeZone == NULL ) {\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 = gRT->SetVariable (\r
+ mTimeZoneVariableName,\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ sizeof(Time->TimeZone),\r
+ &(Time->TimeZone)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR,"LibGetTime: ERROR: TimeZone\n"));\r
+ goto EXIT;\r
+ }\r
+ } else {\r
+ // Got the time zone\r
+ Time->TimeZone = *TimeZone;\r
+ FreePool(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
+ }\r
+ }\r
+\r
+ // Get the current daylight information from non-volatile storage\r
+ Daylight = (UINTN *)GetVariable(mDaylightVariableName, &gEfiGlobalVariableGuid);\r
+\r
+ if( Daylight == NULL ) {\r
+ // The daylight variable does not exist in non-volatile storage, so create it.\r
+ Time->Daylight = 0;\r
+ // Store it\r
+ Status = gRT->SetVariable (\r
+ mDaylightVariableName,\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ sizeof(Time->Daylight),\r
+ &(Time->Daylight)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR,"LibGetTime: ERROR: Daylight\n"));\r
+ goto EXIT;\r
+ }\r
+ } else {\r
+ // Got the daylight information\r
+ Time->Daylight = *Daylight;\r
+ FreePool(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
+ }\r
+\r
+ // Convert from internal 32-bit time to UEFI time\r
+ EpochToEfiTime( EpochSeconds, Time );\r
+\r
+ // Update the Capabilities info\r
+ if( Capabilities != NULL ) {\r
+ Capabilities->Resolution = PL031_COUNTS_PER_SECOND; /* PL031 runs at frequency 1Hz */\r
+ Capabilities->Accuracy = PL031_PPM_ACCURACY; /* Accuracy in ppm multiplied by 1,000,000, e.g. for 50ppm set 50,000,000 */\r
+ Capabilities->SetsToZero = FALSE; /* FALSE: Setting the time does not clear the values below the resolution level */\r
+ }\r
+\r
+ EXIT:\r
+ return Status;\r