X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=ArmPlatformPkg%2FLibrary%2FPL031RealTimeClockLib%2FPL031RealTimeClockLib.c;h=52ba48992b83e599731efc89bd108532fe3a64ca;hp=44a1eee7a44c33c44632e521ab36c9ba67457be8;hb=a23eb77b45f4940b04a49cbd6d40ce46f8c677f6;hpb=d5cd447b1f48dad6cc4e3569e5f3ba516acef13e
diff --git a/ArmPlatformPkg/Library/PL031RealTimeClockLib/PL031RealTimeClockLib.c b/ArmPlatformPkg/Library/PL031RealTimeClockLib/PL031RealTimeClockLib.c
index 44a1eee7a4..52ba48992b 100644
--- a/ArmPlatformPkg/Library/PL031RealTimeClockLib/PL031RealTimeClockLib.c
+++ b/ArmPlatformPkg/Library/PL031RealTimeClockLib/PL031RealTimeClockLib.c
@@ -1,10 +1,8 @@
/** @file
Implement EFI RealTimeClock runtime services via RTC Lib.
- Currently this driver does not support runtime virtual calling.
-
Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
- Copyright (c) 2011-2013, ARM Ltd. All rights reserved.
+ Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
@@ -26,17 +24,26 @@
#include
#include
#include
+#include
#include
#include
+#include
+
#include
+
#include
+#include
+
#include
#include
-CHAR16 mTimeZoneVariableName[] = L"PL031_TimeZone";
-CHAR16 mDaylightVariableName[] = L"PL031_Daylight";
-BOOLEAN mPL031Initialized = FALSE;
+STATIC CONST CHAR16 mTimeZoneVariableName[] = L"PL031RtcTimeZone";
+STATIC CONST CHAR16 mDaylightVariableName[] = L"PL031RtcDaylight";
+STATIC BOOLEAN mPL031Initialized = FALSE;
+STATIC EFI_EVENT mRtcVirtualAddrChangeEvent;
+STATIC UINTN mPL031RtcBase;
+STATIC EFI_RUNTIME_SERVICES *mRT;
EFI_STATUS
IdentifyPL031 (
@@ -46,19 +53,19 @@ IdentifyPL031 (
EFI_STATUS Status;
// Check if this is a PrimeCell Peripheral
- if ( (MmioRead8 (PL031_RTC_PCELL_ID0) != 0x0D)
- || (MmioRead8 (PL031_RTC_PCELL_ID1) != 0xF0)
- || (MmioRead8 (PL031_RTC_PCELL_ID2) != 0x05)
- || (MmioRead8 (PL031_RTC_PCELL_ID3) != 0xB1)) {
+ if ( (MmioRead8 (mPL031RtcBase + PL031_RTC_PCELL_ID0) != 0x0D)
+ || (MmioRead8 (mPL031RtcBase + PL031_RTC_PCELL_ID1) != 0xF0)
+ || (MmioRead8 (mPL031RtcBase + PL031_RTC_PCELL_ID2) != 0x05)
+ || (MmioRead8 (mPL031RtcBase + PL031_RTC_PCELL_ID3) != 0xB1)) {
Status = EFI_NOT_FOUND;
goto EXIT;
}
// Check if this PrimeCell Peripheral is the PL031 Real Time Clock
- if ( (MmioRead8 (PL031_RTC_PERIPH_ID0) != 0x31)
- || (MmioRead8 (PL031_RTC_PERIPH_ID1) != 0x10)
- || ((MmioRead8 (PL031_RTC_PERIPH_ID2) & 0xF) != 0x04)
- || (MmioRead8 (PL031_RTC_PERIPH_ID3) != 0x00)) {
+ if ( (MmioRead8 (mPL031RtcBase + PL031_RTC_PERIPH_ID0) != 0x31)
+ || (MmioRead8 (mPL031RtcBase + PL031_RTC_PERIPH_ID1) != 0x10)
+ || ((MmioRead8 (mPL031RtcBase + PL031_RTC_PERIPH_ID2) & 0xF) != 0x04)
+ || (MmioRead8 (mPL031RtcBase + PL031_RTC_PERIPH_ID3) != 0x00)) {
Status = EFI_NOT_FOUND;
goto EXIT;
}
@@ -83,18 +90,18 @@ InitializePL031 (
}
// Ensure interrupts are masked. We do not want RTC interrupts in UEFI
- if ((MmioRead32 (PL031_RTC_IMSC_IRQ_MASK_SET_CLEAR_REGISTER) & PL031_SET_IRQ_MASK) != PL031_SET_IRQ_MASK) {
- MmioOr32 (PL031_RTC_IMSC_IRQ_MASK_SET_CLEAR_REGISTER, PL031_SET_IRQ_MASK);
+ if ((MmioRead32 (mPL031RtcBase + PL031_RTC_IMSC_IRQ_MASK_SET_CLEAR_REGISTER) & PL031_SET_IRQ_MASK) != PL031_SET_IRQ_MASK) {
+ MmioOr32 (mPL031RtcBase + PL031_RTC_IMSC_IRQ_MASK_SET_CLEAR_REGISTER, PL031_SET_IRQ_MASK);
}
// Clear any existing interrupts
- if ((MmioRead32 (PL031_RTC_RIS_RAW_IRQ_STATUS_REGISTER) & PL031_IRQ_TRIGGERED) == PL031_IRQ_TRIGGERED) {
- MmioOr32 (PL031_RTC_ICR_IRQ_CLEAR_REGISTER, PL031_CLEAR_IRQ);
+ if ((MmioRead32 (mPL031RtcBase + PL031_RTC_RIS_RAW_IRQ_STATUS_REGISTER) & PL031_IRQ_TRIGGERED) == PL031_IRQ_TRIGGERED) {
+ MmioOr32 (mPL031RtcBase + PL031_RTC_ICR_IRQ_CLEAR_REGISTER, PL031_CLEAR_IRQ);
}
// Start the clock counter
- if ((MmioRead32 (PL031_RTC_CR_CONTROL_REGISTER) & PL031_RTC_ENABLED) != PL031_RTC_ENABLED) {
- MmioOr32 (PL031_RTC_CR_CONTROL_REGISTER, PL031_RTC_ENABLED);
+ if ((MmioRead32 (mPL031RtcBase + PL031_RTC_CR_CONTROL_REGISTER) & PL031_RTC_ENABLED) != PL031_RTC_ENABLED) {
+ MmioOr32 (mPL031RtcBase + PL031_RTC_CR_CONTROL_REGISTER, PL031_RTC_ENABLED);
}
mPL031Initialized = TRUE;
@@ -129,10 +136,6 @@ EpochToEfiTime (
UINTN ss;
UINTN J;
- if (Time->Daylight == TRUE) {
-
- }
-
J = (EpochSeconds / 86400) + 2440588;
j = J + 32044;
g = j / 146097;
@@ -185,7 +188,7 @@ EfiTimeToEpoch (
JulianDate = Time->Day + ((153*m + 2)/5) + (365*y) + (y/4) - (y/100) + (y/400) - 32045;
- ASSERT(JulianDate > EPOCH_JULIAN_DATE);
+ ASSERT (JulianDate >= EPOCH_JULIAN_DATE);
EpochDays = JulianDate - EPOCH_JULIAN_DATE;
EpochSeconds = (EpochDays * SEC_PER_DAY) + ((UINTN)Time->Hour * SEC_PER_HOUR) + (Time->Minute * SEC_PER_MIN) + Time->Second;
@@ -218,7 +221,7 @@ DayValid (
IN EFI_TIME *Time
)
{
- INTN DayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ STATIC CONST INTN DayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if (Time->Day < 1 ||
Time->Day > DayOfMonth[Time->Month - 1] ||
@@ -234,13 +237,14 @@ DayValid (
Returns the current time and date information, and the time-keeping capabilities
of the hardware platform.
- @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.
+ @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.
+ @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.
+ @retval EFI_SECURITY_VIOLATION The time could not be retrieved due to an authentication failure.
**/
EFI_STATUS
@@ -252,8 +256,9 @@ LibGetTime (
{
EFI_STATUS Status = EFI_SUCCESS;
UINT32 EpochSeconds;
- INT16 *TimeZone = 0;
- UINTN *Daylight = 0;
+ INT16 TimeZone;
+ UINT8 Daylight;
+ UINTN Size;
// Initialize the hardware if not already done
if (!mPL031Initialized) {
@@ -269,7 +274,7 @@ LibGetTime (
Status = ArmPlatformSysConfigGet (SYS_CFG_RTC, &EpochSeconds);
if (Status == EFI_UNSUPPORTED) {
// Battery backed up hardware RTC does not exist, revert to PL031
- EpochSeconds = MmioRead32 (PL031_RTC_DR_DATA_REGISTER);
+ EpochSeconds = MmioRead32 (mPL031RtcBase + PL031_RTC_DR_DATA_REGISTER);
Status = EFI_SUCCESS;
} else if (EFI_ERROR (Status)) {
// Battery backed up hardware RTC exists but could not be read due to error. Abort.
@@ -277,7 +282,7 @@ LibGetTime (
} else {
// Battery backed up hardware RTC exists and we read the time correctly from it.
// Now sync the PL031 to the new time.
- MmioWrite32 (PL031_RTC_LR_LOAD_REGISTER, EpochSeconds);
+ MmioWrite32 (mPL031RtcBase + PL031_RTC_LR_LOAD_REGISTER, EpochSeconds);
}
// Ensure Time is a valid pointer
@@ -287,27 +292,44 @@ LibGetTime (
}
// Get the current time zone information from non-volatile storage
- TimeZone = (INT16 *)GetVariable(mTimeZoneVariableName, &gEfiGlobalVariableGuid);
+ Size = sizeof (TimeZone);
+ Status = mRT->GetVariable (
+ (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)
+ goto EXIT;
- if (TimeZone == NULL) {
// The time zone variable does not exist in non-volatile storage, so create it.
Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;
// Store it
- Status = gRT->SetVariable (
- mTimeZoneVariableName,
- &gEfiGlobalVariableGuid,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
- sizeof(Time->TimeZone),
- &(Time->TimeZone)
- );
+ Status = mRT->SetVariable (
+ (CHAR16 *)mTimeZoneVariableName,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ Size,
+ (VOID *)&(Time->TimeZone)
+ );
if (EFI_ERROR (Status)) {
- DEBUG((EFI_D_ERROR,"LibGetTime: ERROR: TimeZone\n"));
+ DEBUG ((
+ EFI_D_ERROR,
+ "LibGetTime: Failed to save %s variable to non-volatile storage, Status = %r\n",
+ mTimeZoneVariableName,
+ Status
+ ));
goto EXIT;
}
} else {
// Got the time zone
- Time->TimeZone = *TimeZone;
- FreePool(TimeZone);
+ Time->TimeZone = TimeZone;
// Check TimeZone bounds: -1440 to 1440 or 2047
if (((Time->TimeZone < -1440) || (Time->TimeZone > 1440))
@@ -322,27 +344,44 @@ LibGetTime (
}
// Get the current daylight information from non-volatile storage
- Daylight = (UINTN *)GetVariable(mDaylightVariableName, &gEfiGlobalVariableGuid);
+ Size = sizeof (Daylight);
+ Status = mRT->GetVariable (
+ (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)
+ goto EXIT;
- if (Daylight == NULL) {
// The daylight variable does not exist in non-volatile storage, so create it.
Time->Daylight = 0;
// Store it
- Status = gRT->SetVariable (
- mDaylightVariableName,
- &gEfiGlobalVariableGuid,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
- sizeof(Time->Daylight),
- &(Time->Daylight)
- );
+ Status = mRT->SetVariable (
+ (CHAR16 *)mDaylightVariableName,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ Size,
+ (VOID *)&(Time->Daylight)
+ );
if (EFI_ERROR (Status)) {
- DEBUG((EFI_D_ERROR,"LibGetTime: ERROR: Daylight\n"));
+ DEBUG ((
+ EFI_D_ERROR,
+ "LibGetTime: Failed to save %s variable to non-volatile storage, Status = %r\n",
+ mDaylightVariableName,
+ Status
+ ));
goto EXIT;
}
} else {
// Got the daylight information
- Time->Daylight = *Daylight;
- FreePool(Daylight);
+ Time->Daylight = Daylight;
// Adjust for the correct period
if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) {
@@ -388,16 +427,9 @@ LibSetTime (
EFI_STATUS Status;
UINTN EpochSeconds;
- // Because the PL031 is a 32-bit counter counting seconds,
- // the maximum time span is just over 136 years.
- // Time is stored in Unix Epoch format, so it starts in 1970,
- // Therefore it can not exceed the year 2106.
- // This is not a problem for UEFI, as the current spec limits the years
- // to the range 1998 .. 2011
-
- // Check the input parameters' range.
- if ((Time->Year < 1998) ||
- (Time->Year > 2099) ||
+ // Check the input parameters are within the range specified by UEFI
+ if ((Time->Year < 1900) ||
+ (Time->Year > 9999) ||
(Time->Month < 1 ) ||
(Time->Month > 12 ) ||
(!DayValid (Time) ) ||
@@ -412,6 +444,15 @@ LibSetTime (
goto EXIT;
}
+ // Because the PL031 is a 32-bit counter counting seconds,
+ // the maximum time span is just over 136 years.
+ // Time is stored in Unix Epoch format, so it starts in 1970,
+ // Therefore it can not exceed the year 2106.
+ if ((Time->Year < 1970) || (Time->Year >= 2106)) {
+ Status = EFI_UNSUPPORTED;
+ goto EXIT;
+ }
+
// Initialize the hardware if not already done
if (!mPL031Initialized) {
Status = InitializePL031 ();
@@ -450,34 +491,44 @@ LibSetTime (
// Set the PL031
- MmioWrite32 (PL031_RTC_LR_LOAD_REGISTER, EpochSeconds);
+ MmioWrite32 (mPL031RtcBase + PL031_RTC_LR_LOAD_REGISTER, EpochSeconds);
// The accesses to Variable Services can be very slow, because we may be writing to Flash.
// Do this after having set the RTC.
// Save the current time zone information into non-volatile storage
- Status = gRT->SetVariable (
- mTimeZoneVariableName,
- &gEfiGlobalVariableGuid,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
- sizeof(Time->TimeZone),
- &(Time->TimeZone)
- );
+ Status = mRT->SetVariable (
+ (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((EFI_D_ERROR,"LibSetTime: ERROR: TimeZone\n"));
+ DEBUG ((
+ EFI_D_ERROR,
+ "LibSetTime: Failed to save %s variable to non-volatile storage, Status = %r\n",
+ mTimeZoneVariableName,
+ Status
+ ));
goto EXIT;
}
// Save the current daylight information into non-volatile storage
- Status = gRT->SetVariable (
- mDaylightVariableName,
- &gEfiGlobalVariableGuid,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
- sizeof(Time->Daylight),
- &(Time->Daylight)
- );
+ Status = mRT->SetVariable (
+ (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((EFI_D_ERROR,"LibSetTime: ERROR: Daylight\n"));
+ DEBUG ((
+ EFI_D_ERROR,
+ "LibSetTime: Failed to save %s variable to non-volatile storage, Status = %r\n",
+ mDaylightVariableName,
+ Status
+ ));
goto EXIT;
}
@@ -535,7 +586,31 @@ LibSetWakeupTime (
return EFI_UNSUPPORTED;
}
+/**
+ 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
+ )
+{
+ //
+ // Only needed if you are going to support the OS calling RTC functions in virtual mode.
+ // You will need to call EfiConvertPointer (). To convert any stored physical addresses
+ // to virtual address. After the OS transitions to calling in virtual mode, all future
+ // runtime calls will be made in virtual mode.
+ //
+ EfiConvertPointer (0x0, (VOID**)&mPL031RtcBase);
+ EfiConvertPointer (0x0, (VOID**)&mRT);
+ return;
+}
/**
This is the declaration of an EFI image entry point. This can be the entry point to an application
@@ -557,12 +632,32 @@ LibRtcInitialize (
EFI_STATUS Status;
EFI_HANDLE Handle;
+ // Initialize RTC Base Address
+ mPL031RtcBase = PcdGet32 (PcdPL031RtcBase);
+
+ // Declare the controller as EFI_MEMORY_RUNTIME
+ Status = gDS->AddMemorySpace (
+ EfiGcdMemoryTypeMemoryMappedIo,
+ mPL031RtcBase, SIZE_4KB,
+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gDS->SetMemorySpaceAttributes (mPL031RtcBase, SIZE_4KB, EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
// Setup the setters and getters
gRT->GetTime = LibGetTime;
gRT->SetTime = LibSetTime;
gRT->GetWakeupTime = LibGetWakeupTime;
gRT->SetWakeupTime = LibSetWakeupTime;
+ mRT = gRT;
+
// Install the protocol
Handle = NULL;
Status = gBS->InstallMultipleProtocolInterfaces (
@@ -570,31 +665,20 @@ LibRtcInitialize (
&gEfiRealTimeClockArchProtocolGuid, NULL,
NULL
);
+ ASSERT_EFI_ERROR (Status);
- return Status;
-}
-
-
-/**
- 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
- )
-{
//
- // Only needed if you are going to support the OS calling RTC functions in virtual mode.
- // You will need to call EfiConvertPointer (). To convert any stored physical addresses
- // to virtual address. After the OS transitions to calling in virtual mode, all future
- // runtime calls will be made in virtual mode.
+ // Register for the virtual address change event
//
- return;
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ LibRtcVirtualNotifyEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mRtcVirtualAddrChangeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
}