]> git.proxmox.com Git - mirror_edk2.git/blobdiff - PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c
PcAtChipsetPkg/Rtc: Fix a UEFI Win7 boot hang issue
[mirror_edk2.git] / PcAtChipsetPkg / PcatRealTimeClockRuntimeDxe / PcRtc.c
index 5abb71c032b4d949f8ea467239db699360e5f73c..e122ae16990a51324e13935441de6b9a5d5efb32 100644 (file)
@@ -500,6 +500,13 @@ PcRtcSetTime (
   RegisterB.Bits.Set  = 1;\r
   RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
 \r
+  //\r
+  // Store the century value to RTC before converting to BCD format.\r
+  //\r
+  if (Global->CenturyRtcAddress != 0) {\r
+    RtcWrite (Global->CenturyRtcAddress, DecimalToBcd8 ((UINT8) (RtcTime.Year / 100)));\r
+  }\r
+\r
   ConvertEfiTimeToRtcTime (&RtcTime, RegisterB);\r
 \r
   RtcWrite (RTC_ADDRESS_SECONDS, RtcTime.Second);\r
@@ -1198,3 +1205,106 @@ IsWithinOneDay (
   return Adjacent;\r
 }\r
 \r
+/**\r
+  This function find ACPI table with the specified signature in RSDT or XSDT.\r
+\r
+  @param Sdt              ACPI RSDT or XSDT.\r
+  @param Signature        ACPI table signature.\r
+  @param TablePointerSize Size of table pointer: 4 or 8.\r
+\r
+  @return ACPI table or NULL if not found.\r
+**/\r
+VOID *\r
+ScanTableInSDT (\r
+  IN EFI_ACPI_DESCRIPTION_HEADER    *Sdt,\r
+  IN UINT32                         Signature,\r
+  IN UINTN                          TablePointerSize\r
+  )\r
+{\r
+  UINTN                          Index;\r
+  UINTN                          EntryCount;\r
+  UINTN                          EntryBase;\r
+  EFI_ACPI_DESCRIPTION_HEADER    *Table;\r
+\r
+  EntryCount = (Sdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / TablePointerSize;\r
+\r
+  EntryBase = (UINTN) (Sdt + 1);\r
+  for (Index = 0; Index < EntryCount; Index++) {\r
+    //\r
+    // When TablePointerSize is 4 while sizeof (VOID *) is 8, make sure the upper 4 bytes are zero.\r
+    //\r
+    Table = 0;\r
+    CopyMem (&Table, (VOID *) (EntryBase + Index * TablePointerSize), TablePointerSize);\r
+    if (Table->Signature == Signature) {\r
+      return Table;\r
+    }\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Notification function of ACPI Table change.\r
+\r
+  This is a notification function registered on ACPI Table change event.\r
+  It saves the Century address stored in ACPI FADT table.\r
+\r
+  @param  Event        Event whose notification function is being invoked.\r
+  @param  Context      Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PcRtcAcpiTableChangeCallback (\r
+  IN EFI_EVENT        Event,\r
+  IN VOID             *Context\r
+  )\r
+{\r
+  EFI_STATUS                                    Status;\r
+  EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER  *Rsdp;\r
+  EFI_ACPI_DESCRIPTION_HEADER                   *Rsdt;\r
+  EFI_ACPI_DESCRIPTION_HEADER                   *Xsdt;\r
+  EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE     *Fadt;\r
+  EFI_TIME                                      Time;\r
+  UINT8                                         Century;\r
+\r
+  Status = EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid, (VOID **) &Rsdp);\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EfiGetSystemConfigurationTable (&gEfiAcpi10TableGuid, (VOID **) &Rsdp);\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Find FADT in XSDT\r
+  //\r
+  Fadt = NULL;\r
+  if (Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION) {\r
+    Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->XsdtAddress;\r
+    Fadt = ScanTableInSDT (Xsdt, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, sizeof (UINT64));\r
+  }\r
+\r
+  if (Fadt == NULL) {\r
+    //\r
+    // Find FADT in RSDT\r
+    //\r
+    Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->RsdtAddress;\r
+    Fadt = ScanTableInSDT (Rsdt, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, sizeof (UINT32));\r
+  }\r
+\r
+  if ((Fadt != NULL) &&\r
+      (Fadt->Century > RTC_ADDRESS_REGISTER_D) && (Fadt->Century < 0x80) &&\r
+      (mModuleGlobal.CenturyRtcAddress != Fadt->Century)\r
+      ) {\r
+    mModuleGlobal.CenturyRtcAddress = Fadt->Century;\r
+    Status = PcRtcGetTime (&Time, NULL, &mModuleGlobal);\r
+    if (!EFI_ERROR (Status)) {\r
+      Century = (UINT8) (Time.Year / 100);\r
+      Century = DecimalToBcd8 (Century);\r
+      DEBUG ((EFI_D_INFO, "PcRtc: Write 0x%x to CMOS location 0x%x\n", Century, mModuleGlobal.CenturyRtcAddress));\r
+      RtcWrite (mModuleGlobal.CenturyRtcAddress, Century);\r
+    }\r
+  }\r
+}\r