+/**\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
+ Get the century RTC address from the ACPI FADT table.\r
+\r
+ @return The century RTC address or 0 if not found.\r
+**/\r
+UINT8\r
+GetCenturyRtcAddress (\r
+ VOID\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
+\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 0;\r
+ }\r
+\r
+ ASSERT (Rsdp != NULL);\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
+ ) {\r
+ return Fadt->Century;\r
+ } else {\r
+ return 0;\r
+ }\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_TIME Time;\r
+ UINT8 CenturyRtcAddress;\r
+ UINT8 Century;\r
+\r
+ CenturyRtcAddress = GetCenturyRtcAddress ();\r
+ if ((CenturyRtcAddress != 0) && (mModuleGlobal.CenturyRtcAddress != CenturyRtcAddress)) {\r
+ mModuleGlobal.CenturyRtcAddress = CenturyRtcAddress;\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