From: Ruiyu Ni Date: Tue, 22 Dec 2015 13:52:47 +0000 (+0000) Subject: PcAtChipsetPkg/Rtc: Fix a UEFI Win7 boot hang issue X-Git-Tag: edk2-stable201903~8189 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=41628cbc7cb267f35db4ba2efca833aa39198cba PcAtChipsetPkg/Rtc: Fix a UEFI Win7 boot hang issue The patch updates the Century value in CMOS location specified by FADT.Century to avoid UEFI Win7 hang during booting. Per the ACPI spec if the FADT.Century is zero, it's not needed to store the century value in CMOS. But UEFI Win7 treats the Century storage is optional only when FADT.Century is 0x80. While Linux strictly follows the ACPI spec and treats Century storage is optional when FADT.Century is 0. So if a platform wants to support both UEFI Win7 and Linux, it needs to report FADT.Century to a traditional value which doesn't equal to 0 or 0x80 (0x32 mostly). And RTC driver is enhanced to save the century value to the location specified by FADT.Century. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Star Zeng git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19442 6f19259b-4bc3-4df7-8a09-765794883524 --- diff --git a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c index 5abb71c032..e122ae1699 100644 --- a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c +++ b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c @@ -500,6 +500,13 @@ PcRtcSetTime ( RegisterB.Bits.Set = 1; RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data); + // + // Store the century value to RTC before converting to BCD format. + // + if (Global->CenturyRtcAddress != 0) { + RtcWrite (Global->CenturyRtcAddress, DecimalToBcd8 ((UINT8) (RtcTime.Year / 100))); + } + ConvertEfiTimeToRtcTime (&RtcTime, RegisterB); RtcWrite (RTC_ADDRESS_SECONDS, RtcTime.Second); @@ -1198,3 +1205,106 @@ IsWithinOneDay ( return Adjacent; } +/** + This function find ACPI table with the specified signature in RSDT or XSDT. + + @param Sdt ACPI RSDT or XSDT. + @param Signature ACPI table signature. + @param TablePointerSize Size of table pointer: 4 or 8. + + @return ACPI table or NULL if not found. +**/ +VOID * +ScanTableInSDT ( + IN EFI_ACPI_DESCRIPTION_HEADER *Sdt, + IN UINT32 Signature, + IN UINTN TablePointerSize + ) +{ + UINTN Index; + UINTN EntryCount; + UINTN EntryBase; + EFI_ACPI_DESCRIPTION_HEADER *Table; + + EntryCount = (Sdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / TablePointerSize; + + EntryBase = (UINTN) (Sdt + 1); + for (Index = 0; Index < EntryCount; Index++) { + // + // When TablePointerSize is 4 while sizeof (VOID *) is 8, make sure the upper 4 bytes are zero. + // + Table = 0; + CopyMem (&Table, (VOID *) (EntryBase + Index * TablePointerSize), TablePointerSize); + if (Table->Signature == Signature) { + return Table; + } + } + + return NULL; +} + +/** + Notification function of ACPI Table change. + + This is a notification function registered on ACPI Table change event. + It saves the Century address stored in ACPI FADT table. + + @param Event Event whose notification function is being invoked. + @param Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +PcRtcAcpiTableChangeCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp; + EFI_ACPI_DESCRIPTION_HEADER *Rsdt; + EFI_ACPI_DESCRIPTION_HEADER *Xsdt; + EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt; + EFI_TIME Time; + UINT8 Century; + + Status = EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid, (VOID **) &Rsdp); + if (EFI_ERROR (Status)) { + Status = EfiGetSystemConfigurationTable (&gEfiAcpi10TableGuid, (VOID **) &Rsdp); + } + + if (EFI_ERROR (Status)) { + return; + } + + // + // Find FADT in XSDT + // + Fadt = NULL; + if (Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION) { + Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->XsdtAddress; + Fadt = ScanTableInSDT (Xsdt, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, sizeof (UINT64)); + } + + if (Fadt == NULL) { + // + // Find FADT in RSDT + // + Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->RsdtAddress; + Fadt = ScanTableInSDT (Rsdt, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, sizeof (UINT32)); + } + + if ((Fadt != NULL) && + (Fadt->Century > RTC_ADDRESS_REGISTER_D) && (Fadt->Century < 0x80) && + (mModuleGlobal.CenturyRtcAddress != Fadt->Century) + ) { + mModuleGlobal.CenturyRtcAddress = Fadt->Century; + Status = PcRtcGetTime (&Time, NULL, &mModuleGlobal); + if (!EFI_ERROR (Status)) { + Century = (UINT8) (Time.Year / 100); + Century = DecimalToBcd8 (Century); + DEBUG ((EFI_D_INFO, "PcRtc: Write 0x%x to CMOS location 0x%x\n", Century, mModuleGlobal.CenturyRtcAddress)); + RtcWrite (mModuleGlobal.CenturyRtcAddress, Century); + } + } +} diff --git a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h index 026c1086b2..7fc19f9043 100644 --- a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h +++ b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h @@ -19,6 +19,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include +#include + #include #include @@ -34,13 +36,15 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include - typedef struct { EFI_LOCK RtcLock; INT16 SavedTimeZone; UINT8 Daylight; + UINT8 CenturyRtcAddress; } PC_RTC_MODULE_GLOBALS; +extern PC_RTC_MODULE_GLOBALS mModuleGlobal; + #define PCAT_RTC_ADDRESS_REGISTER 0x70 #define PCAT_RTC_DATA_REGISTER 0x71 @@ -355,4 +359,20 @@ IsLeapYear ( IN EFI_TIME *Time ); +/** + Notification function of ACPI Table change. + + This is a notification function registered on ACPI Table change event. + It saves the Century address stored in ACPI FADT table. + + @param Event Event whose notification function is being invoked. + @param Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +PcRtcAcpiTableChangeCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ); #endif diff --git a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c index 9cf3988705..6f2a987f22 100644 --- a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c +++ b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c @@ -1,7 +1,7 @@ /** @file Provides Set/Get time operations. -Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -14,11 +14,10 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "PcRtc.h" -PC_RTC_MODULE_GLOBALS mModuleGlobal; +PC_RTC_MODULE_GLOBALS mModuleGlobal = { 0 }; EFI_HANDLE mHandle = NULL; - /** Returns the current time and date information, and the time-keeping capabilities of the hardware platform. @@ -133,11 +132,32 @@ InitializePcRtc ( ) { EFI_STATUS Status; + EFI_EVENT Event; EfiInitializeLock (&mModuleGlobal.RtcLock, TPL_CALLBACK); Status = PcRtcInit (&mModuleGlobal); ASSERT_EFI_ERROR (Status); + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + PcRtcAcpiTableChangeCallback, + NULL, + &gEfiAcpi10TableGuid, + &Event + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + PcRtcAcpiTableChangeCallback, + NULL, + &gEfiAcpiTableGuid, + &Event + ); + ASSERT_EFI_ERROR (Status); gRT->GetTime = PcRtcEfiGetTime; gRT->SetTime = PcRtcEfiSetTime; diff --git a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf index 9e5faf75d6..94596cef78 100644 --- a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf +++ b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf @@ -57,6 +57,10 @@ [Protocols] gEfiRealTimeClockArchProtocolGuid ## PRODUCES +[Guids] + gEfiAcpi10TableGuid ## CONSUMES + gEfiAcpiTableGuid ## CONSUMES + [Depex] gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid