]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPlatformPkg/Library/PL031RealTimeClockLib/PL031RealTimeClockLib.c
ArmPlatformPkg: fix undefined reference to memcpy
[mirror_edk2.git] / ArmPlatformPkg / Library / PL031RealTimeClockLib / PL031RealTimeClockLib.c
index 9bccd2f14f89fe27767056832bdaf90afc814fd2..52ba48992b83e599731efc89bd108532fe3a64ca 100644 (file)
@@ -1,9 +1,8 @@
 /** @file\r
   Implement EFI RealTimeClock runtime services via RTC Lib.\r
 \r
-  Currently this driver does not support runtime virtual calling.\r
-\r
   Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
+  Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>\r
 \r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
@@ -15,7 +14,6 @@
 \r
 **/\r
 \r
-#include <Base.h>\r
 #include <Uefi.h>\r
 #include <PiDxe.h>\r
 #include <Library/BaseLib.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/UefiBootServicesTableLib.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 <ArmPlatform.h>\r
+#include <Guid/EventGroup.h>\r
+\r
 #include <Drivers/PL031RealTimeClock.h>\r
 \r
-CHAR16        mTimeZoneVariableName[] = L"PL031_TimeZone";\r
-CHAR16        mDaylightVariableName[] = L"PL031_Daylight";\r
-BOOLEAN       mPL031Initialized = FALSE;\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
+STATIC EFI_RUNTIME_SERVICES   *mRT;\r
 \r
 EFI_STATUS\r
 IdentifyPL031 (\r
@@ -44,19 +53,19 @@ IdentifyPL031 (
   EFI_STATUS    Status;\r
 \r
   // Check if this is a PrimeCell Peripheral\r
-  if(    ( MmioRead8( PL031_RTC_PCELL_ID0 ) != 0x0D )\r
-      || ( MmioRead8( PL031_RTC_PCELL_ID1 ) != 0xF0 )\r
-      || ( MmioRead8( PL031_RTC_PCELL_ID2 ) != 0x05 )\r
-      || ( MmioRead8( PL031_RTC_PCELL_ID3 ) != 0xB1 ) ) {\r
+  if (  (MmioRead8 (mPL031RtcBase + PL031_RTC_PCELL_ID0) != 0x0D)\r
+      || (MmioRead8 (mPL031RtcBase + PL031_RTC_PCELL_ID1) != 0xF0)\r
+      || (MmioRead8 (mPL031RtcBase + PL031_RTC_PCELL_ID2) != 0x05)\r
+      || (MmioRead8 (mPL031RtcBase + PL031_RTC_PCELL_ID3) != 0xB1)) {\r
     Status = EFI_NOT_FOUND;\r
     goto EXIT;\r
   }\r
 \r
-  // Check if this PrimeCell Peripheral is the SP805 Watchdog Timer\r
-  if(    ( MmioRead8( PL031_RTC_PERIPH_ID0 ) != 0x31 )\r
-      || ( MmioRead8( PL031_RTC_PERIPH_ID1 ) != 0x10 )\r
-      || (( MmioRead8( PL031_RTC_PERIPH_ID2 ) & 0xF) != 0x04 )\r
-      || ( MmioRead8( PL031_RTC_PERIPH_ID3 ) != 0x00 ) ) {\r
+  // Check if this PrimeCell Peripheral is the PL031 Real Time Clock\r
+  if (  (MmioRead8 (mPL031RtcBase + PL031_RTC_PERIPH_ID0) != 0x31)\r
+      || (MmioRead8 (mPL031RtcBase + PL031_RTC_PERIPH_ID1) != 0x10)\r
+      || ((MmioRead8 (mPL031RtcBase + PL031_RTC_PERIPH_ID2) & 0xF) != 0x04)\r
+      || (MmioRead8 (mPL031RtcBase + PL031_RTC_PERIPH_ID3) != 0x00)) {\r
     Status = EFI_NOT_FOUND;\r
     goto EXIT;\r
   }\r
@@ -81,18 +90,18 @@ InitializePL031 (
   }\r
 \r
   // Ensure interrupts are masked. We do not want RTC interrupts in UEFI\r
-  if ( (MmioRead32( PL031_RTC_IMSC_IRQ_MASK_SET_CLEAR_REGISTER ) & PL031_SET_IRQ_MASK) != PL031_SET_IRQ_MASK ) {\r
-    MmioOr32( PL031_RTC_IMSC_IRQ_MASK_SET_CLEAR_REGISTER, PL031_SET_IRQ_MASK);\r
+  if ((MmioRead32 (mPL031RtcBase + PL031_RTC_IMSC_IRQ_MASK_SET_CLEAR_REGISTER) & PL031_SET_IRQ_MASK) != PL031_SET_IRQ_MASK) {\r
+    MmioOr32 (mPL031RtcBase + PL031_RTC_IMSC_IRQ_MASK_SET_CLEAR_REGISTER, PL031_SET_IRQ_MASK);\r
   }\r
 \r
   // Clear any existing interrupts\r
-  if ( (MmioRead32( PL031_RTC_RIS_RAW_IRQ_STATUS_REGISTER ) & PL031_IRQ_TRIGGERED) == PL031_IRQ_TRIGGERED ) {\r
-    MmioOr32( PL031_RTC_ICR_IRQ_CLEAR_REGISTER, PL031_CLEAR_IRQ);\r
+  if ((MmioRead32 (mPL031RtcBase + PL031_RTC_RIS_RAW_IRQ_STATUS_REGISTER) & PL031_IRQ_TRIGGERED) == PL031_IRQ_TRIGGERED) {\r
+    MmioOr32 (mPL031RtcBase + PL031_RTC_ICR_IRQ_CLEAR_REGISTER, PL031_CLEAR_IRQ);\r
   }\r
 \r
   // Start the clock counter\r
-  if ( (MmioRead32( PL031_RTC_CR_CONTROL_REGISTER ) & PL031_RTC_ENABLED) != PL031_RTC_ENABLED ) {\r
-    MmioOr32( PL031_RTC_CR_CONTROL_REGISTER, PL031_RTC_ENABLED);\r
+  if ((MmioRead32 (mPL031RtcBase + PL031_RTC_CR_CONTROL_REGISTER) & PL031_RTC_ENABLED) != PL031_RTC_ENABLED) {\r
+    MmioOr32 (mPL031RtcBase + PL031_RTC_CR_CONTROL_REGISTER, PL031_RTC_ENABLED);\r
   }\r
 \r
   mPL031Initialized = TRUE;\r
@@ -127,10 +136,6 @@ EpochToEfiTime (
   UINTN         ss;\r
   UINTN         J;\r
 \r
-  if( Time->Daylight == TRUE) {\r
-\r
-  }\r
-\r
   J  = (EpochSeconds / 86400) + 2440588;\r
   j  = J + 32044;\r
   g  = j / 146097;\r
@@ -183,7 +188,7 @@ EfiTimeToEpoch (
 \r
   JulianDate = Time->Day + ((153*m + 2)/5) + (365*y) + (y/4) - (y/100) + (y/400) - 32045;\r
 \r
-  ASSERT( JulianDate > EPOCH_JULIAN_DATE );\r
+  ASSERT (JulianDate >= EPOCH_JULIAN_DATE);\r
   EpochDays = JulianDate - EPOCH_JULIAN_DATE;\r
 \r
   EpochSeconds = (EpochDays * SEC_PER_DAY) + ((UINTN)Time->Hour * SEC_PER_HOUR) + (Time->Minute * SEC_PER_MIN) + Time->Second;\r
@@ -216,12 +221,12 @@ DayValid (
   IN  EFI_TIME  *Time\r
   )\r
 {\r
-  INTN  DayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\r
+  STATIC CONST INTN DayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\r
 \r
   if (Time->Day < 1 ||\r
       Time->Day > DayOfMonth[Time->Month - 1] ||\r
       (Time->Month == 2 && (!IsLeapYear (Time) && Time->Day > 28))\r
-      ) {\r
+     ) {\r
     return FALSE;\r
   }\r
 \r
@@ -232,13 +237,14 @@ DayValid (
   Returns the current time and date information, and the time-keeping capabilities\r
   of the hardware platform.\r
 \r
-  @param  Time                  A pointer to storage to receive a snapshot of the current time.\r
-  @param  Capabilities          An optional pointer to a buffer to receive the real time clock\r
-                                device's capabilities.\r
+  @param  Time                   A pointer to storage to receive a snapshot of the current time.\r
+  @param  Capabilities           An optional pointer to a buffer to receive the real time clock\r
+                                 device's capabilities.\r
 \r
-  @retval EFI_SUCCESS           The operation completed successfully.\r
-  @retval EFI_INVALID_PARAMETER Time is NULL.\r
-  @retval EFI_DEVICE_ERROR      The time could not be retrieved due to hardware error.\r
+  @retval EFI_SUCCESS            The operation completed successfully.\r
+  @retval EFI_INVALID_PARAMETER  Time is NULL.\r
+  @retval EFI_DEVICE_ERROR       The time could not be retrieved due to hardware error.\r
+  @retval EFI_SECURITY_VIOLATION The time could not be retrieved due to an authentication failure.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -249,13 +255,14 @@ LibGetTime (
   )\r
 {\r
   EFI_STATUS  Status = EFI_SUCCESS;\r
-  UINTN       EpochSeconds;\r
-  INT16       *TimeZone = 0;\r
-  UINTN       *Daylight = 0;\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 (!mPL031Initialized) {\r
+    Status = InitializePL031 ();\r
     if (EFI_ERROR (Status)) {\r
       goto EXIT;\r
     }\r
@@ -267,7 +274,7 @@ LibGetTime (
   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
+    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
@@ -275,88 +282,125 @@ LibGetTime (
   } 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
+    MmioWrite32 (mPL031RtcBase + PL031_RTC_LR_LOAD_REGISTER, EpochSeconds);\r
   }\r
 \r
   // Ensure Time is a valid pointer\r
-  if( Time == NULL ) {\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
+  Size = sizeof (TimeZone);\r
+  Status = mRT->GetVariable (\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
-  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
+    Status = mRT->SetVariable (\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
     if (EFI_ERROR (Status)) {\r
-      DEBUG((EFI_D_ERROR,"LibGetTime: ERROR: TimeZone\n"));\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
-    FreePool(TimeZone);\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
+    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
+    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
+  Size = sizeof (Daylight);\r
+  Status = mRT->GetVariable (\r
+                  (CHAR16 *)mDaylightVariableName,\r
+                  &gEfiCallerIdGuid,\r
+                  NULL,\r
+                  &Size,\r
+                  (VOID *)&Daylight\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
-  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
+    Status = mRT->SetVariable (\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((EFI_D_ERROR,"LibGetTime: ERROR: Daylight\n"));\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
-    FreePool(Daylight);\r
+    Time->Daylight = Daylight;\r
 \r
     // Adjust for the correct period\r
-    if( (Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT ) {\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
+  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
+  if (Capabilities != NULL) {\r
+    // PL031 runs at frequency 1Hz\r
+    Capabilities->Resolution  = PL031_COUNTS_PER_SECOND;\r
+    // Accuracy in ppm multiplied by 1,000,000, e.g. for 50ppm set 50,000,000\r
+    Capabilities->Accuracy    = (UINT32)PcdGet32 (PcdPL031RtcPpmAccuracy);\r
+    // FALSE: Setting the time does not clear the values below the resolution level\r
+    Capabilities->SetsToZero  = FALSE;\r
   }\r
 \r
   EXIT:\r
@@ -383,49 +427,51 @@ LibSetTime (
   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
+       (!DayValid (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
-  // This is not a problem for UEFI, as the current spec limits the years\r
-  // to the range 1998 .. 2011\r
-\r
-  // Check the input parameters' range.\r
-  if ( ( Time->Year   < 1998 ) ||\r
-       ( Time->Year   > 2099 ) ||\r
-       ( Time->Month  < 1    ) ||\r
-       ( Time->Month  > 12   ) ||\r
-       (!DayValid (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
+  if ((Time->Year < 1970) || (Time->Year >= 2106)) {\r
+    Status = EFI_UNSUPPORTED;\r
     goto EXIT;\r
   }\r
 \r
   // Initialize the hardware if not already done\r
-  if( !mPL031Initialized ) {\r
-    Status = InitializePL031();\r
+  if (!mPL031Initialized) {\r
+    Status = InitializePL031 ();\r
     if (EFI_ERROR (Status)) {\r
       goto EXIT;\r
     }\r
   }\r
 \r
-  EpochSeconds = EfiTimeToEpoch( Time );\r
+  EpochSeconds = EfiTimeToEpoch (Time);\r
 \r
   // Adjust for the correct time zone, i.e. convert to UTC time zone\r
-  if( Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE ) {\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
+  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
@@ -445,34 +491,44 @@ LibSetTime (
 \r
 \r
   // Set the PL031\r
-  MmioWrite32( PL031_RTC_LR_LOAD_REGISTER, EpochSeconds);\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 = 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
+  Status = mRT->SetVariable (\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((EFI_D_ERROR,"LibSetTime: ERROR: TimeZone\n"));\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 = 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
+  Status = mRT->SetVariable (\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((EFI_D_ERROR,"LibSetTime: ERROR: Daylight\n"));\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
@@ -530,7 +586,31 @@ LibSetWakeupTime (
   return EFI_UNSUPPORTED;\r
 }\r
 \r
+/**\r
+  Fixup internal data so that EFI can be call in virtual mode.\r
+  Call the passed in Child Notify event and convert any pointers in\r
+  lib to virtual mode.\r
 \r
+  @param[in]    Event   The Event that is being processed\r
+  @param[in]    Context Event Context\r
+**/\r
+VOID\r
+EFIAPI\r
+LibRtcVirtualNotifyEvent (\r
+  IN EFI_EVENT        Event,\r
+  IN VOID             *Context\r
+  )\r
+{\r
+  //\r
+  // Only needed if you are going to support the OS calling RTC functions in virtual mode.\r
+  // You will need to call EfiConvertPointer (). To convert any stored physical addresses\r
+  // to virtual address. After the OS transitions to calling in virtual mode, all future\r
+  // runtime calls will be made in virtual mode.\r
+  //\r
+  EfiConvertPointer (0x0, (VOID**)&mPL031RtcBase);\r
+  EfiConvertPointer (0x0, (VOID**)&mRT);\r
+  return;\r
+}\r
 \r
 /**\r
   This is the declaration of an EFI image entry point. This can be the entry point to an application\r
@@ -552,44 +632,53 @@ LibRtcInitialize (
   EFI_STATUS    Status;\r
   EFI_HANDLE    Handle;\r
 \r
+  // Initialize RTC Base Address\r
+  mPL031RtcBase = PcdGet32 (PcdPL031RtcBase);\r
+\r
+  // Declare the controller as EFI_MEMORY_RUNTIME\r
+  Status = gDS->AddMemorySpace (\r
+                  EfiGcdMemoryTypeMemoryMappedIo,\r
+                  mPL031RtcBase, SIZE_4KB,\r
+                  EFI_MEMORY_UC | EFI_MEMORY_RUNTIME\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gDS->SetMemorySpaceAttributes (mPL031RtcBase, SIZE_4KB, EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
   // Setup the setters and getters\r
   gRT->GetTime       = LibGetTime;\r
   gRT->SetTime       = LibSetTime;\r
   gRT->GetWakeupTime = LibGetWakeupTime;\r
   gRT->SetWakeupTime = LibSetWakeupTime;\r
 \r
+  mRT = gRT;\r
+\r
   // Install the protocol\r
   Handle = NULL;\r
   Status = gBS->InstallMultipleProtocolInterfaces (\r
                   &Handle,\r
                   &gEfiRealTimeClockArchProtocolGuid,  NULL,\r
                   NULL\r
-                  );\r
+                 );\r
+  ASSERT_EFI_ERROR (Status);\r
 \r
-  return Status;\r
-}\r
-\r
-\r
-/**\r
-  Fixup internal data so that EFI can be call in virtual mode.\r
-  Call the passed in Child Notify event and convert any pointers in\r
-  lib to virtual mode.\r
-\r
-  @param[in]    Event   The Event that is being processed\r
-  @param[in]    Context Event Context\r
-**/\r
-VOID\r
-EFIAPI\r
-LibRtcVirtualNotifyEvent (\r
-  IN EFI_EVENT        Event,\r
-  IN VOID             *Context\r
-  )\r
-{\r
   //\r
-  // Only needed if you are going to support the OS calling RTC functions in virtual mode.\r
-  // You will need to call EfiConvertPointer (). To convert any stored physical addresses\r
-  // to virtual address. After the OS transitions to calling in virtual mode, all future\r
-  // runtime calls will be made in virtual mode.\r
+  // Register for the virtual address change event\r
   //\r
-  return;\r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  LibRtcVirtualNotifyEvent,\r
+                  NULL,\r
+                  &gEfiEventVirtualAddressChangeGuid,\r
+                  &mRtcVirtualAddrChangeEvent\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
 }\r