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; }