+/**\r
+ This function scan ACPI table in RSDT.\r
+\r
+ @param Rsdt ACPI RSDT\r
+ @param Signature ACPI table signature\r
+\r
+ @return ACPI table\r
+**/\r
+VOID *\r
+ScanTableInRSDT (\r
+ IN RSDT_TABLE *Rsdt,\r
+ IN UINT32 Signature\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINT32 EntryCount;\r
+ UINT32 *EntryPtr;\r
+ EFI_ACPI_DESCRIPTION_HEADER *Table;\r
+\r
+ EntryCount = (Rsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32);\r
+\r
+ EntryPtr = &Rsdt->Entry;\r
+ for (Index = 0; Index < EntryCount; Index ++, EntryPtr ++) {\r
+ Table = (EFI_ACPI_DESCRIPTION_HEADER*)((UINTN)(*EntryPtr));\r
+ if (Table->Signature == Signature) {\r
+ return Table;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ This function scan ACPI table in XSDT.\r
+\r
+ @param Xsdt ACPI XSDT\r
+ @param Signature ACPI table signature\r
+\r
+ @return ACPI table\r
+**/\r
+VOID *\r
+ScanTableInXSDT (\r
+ IN XSDT_TABLE *Xsdt,\r
+ IN UINT32 Signature\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINT32 EntryCount;\r
+ UINT64 EntryPtr;\r
+ UINTN BasePtr;\r
+ EFI_ACPI_DESCRIPTION_HEADER *Table;\r
+\r
+ EntryCount = (Xsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);\r
+\r
+ BasePtr = (UINTN)(&(Xsdt->Entry));\r
+ for (Index = 0; Index < EntryCount; Index ++) {\r
+ CopyMem (&EntryPtr, (VOID *)(BasePtr + Index * sizeof(UINT64)), sizeof(UINT64));\r
+ Table = (EFI_ACPI_DESCRIPTION_HEADER*)((UINTN)(EntryPtr));\r
+ if (Table->Signature == Signature) {\r
+ return Table;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ This function scan ACPI table in RSDP.\r
+\r
+ @param Rsdp ACPI RSDP\r
+ @param Signature ACPI table signature\r
+\r
+ @return ACPI table\r
+**/\r
+VOID *\r
+FindAcpiPtr (\r
+ IN EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp,\r
+ IN UINT32 Signature\r
+ )\r
+{\r
+ EFI_ACPI_DESCRIPTION_HEADER *AcpiTable;\r
+ RSDT_TABLE *Rsdt;\r
+ XSDT_TABLE *Xsdt;\r
+\r
+ AcpiTable = NULL;\r
+\r
+ //\r
+ // Check ACPI2.0 table\r
+ //\r
+ Rsdt = (RSDT_TABLE *)(UINTN)Rsdp->RsdtAddress;\r
+ Xsdt = NULL;\r
+ if ((Rsdp->Revision >= 2) && (Rsdp->XsdtAddress < (UINT64)(UINTN)-1)) {\r
+ Xsdt = (XSDT_TABLE *)(UINTN)Rsdp->XsdtAddress;\r
+ }\r
+ //\r
+ // Check Xsdt\r
+ //\r
+ if (Xsdt != NULL) {\r
+ AcpiTable = ScanTableInXSDT (Xsdt, Signature);\r
+ }\r
+ //\r
+ // Check Rsdt\r
+ //\r
+ if ((AcpiTable == NULL) && (Rsdt != NULL)) {\r
+ AcpiTable = ScanTableInRSDT (Rsdt, Signature);\r
+ }\r
+\r
+ return AcpiTable;\r
+}\r
+\r
+/**\r
+ Get Boot performance table form Acpi table.\r
+\r
+**/\r
+EFI_STATUS\r
+GetBootPerformanceTable (\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *AcpiTable;\r
+ FIRMWARE_PERFORMANCE_TABLE *FirmwarePerformanceTable;\r
+\r
+ AcpiTable = NULL;\r
+\r
+ Status = EfiGetSystemConfigurationTable (\r
+ &gEfiAcpi20TableGuid,\r
+ &AcpiTable\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EfiGetSystemConfigurationTable (\r
+ &gEfiAcpi10TableGuid,\r
+ &AcpiTable\r
+ );\r
+ }\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ FirmwarePerformanceTable = FindAcpiPtr (\r
+ (EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)AcpiTable,\r
+ EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE\r
+ );\r
+ if (FirmwarePerformanceTable == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ mBootPerformanceTable = (UINT8*) (UINTN)FirmwarePerformanceTable->BootPointerRecord.BootPerformanceTablePointer;\r
+ mBootPerformanceTableSize = ((BOOT_PERFORMANCE_TABLE *) mBootPerformanceTable)->Header.Length;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get Handle form Module Guid.\r
+\r
+ @param ModuleGuid Module Guid.\r
+ @param Handle The handle to be returned.\r
+\r
+**/\r
+VOID\r
+GetHandleFormModuleGuid (\r
+ IN EFI_GUID *ModuleGuid,\r
+ IN OUT EFI_HANDLE *Handle\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ if (IsZeroGuid (ModuleGuid)) {\r
+ *Handle = NULL;\r
+ }\r
+ //\r
+ // Try to get the Handle form the caached array.\r
+ //\r
+ for (Index = 0; Index < mCachePairCount; Index++) {\r
+ if (CompareGuid (ModuleGuid, &mCacheHandleGuidTable[Index].ModuleGuid)) {\r
+ *Handle = mCacheHandleGuidTable[Index].Handle;\r
+ break;\r
+ }\r
+ }\r
+ if (Index >= mCachePairCount) {\r
+ *Handle = NULL;\r
+ }\r
+}\r
+\r
+/**\r
+Cache the GUID and handle mapping pairs. In order to save time for searching.\r
+\r
+**/\r
+EFI_STATUS\r
+BuildCachedGuidHandleTable (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE *HandleBuffer;\r
+ UINTN HandleCount;\r
+ UINTN Index;\r
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;\r
+ EFI_GUID *TempGuid;\r
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath;\r
+\r
+ Status = gBS->LocateHandleBuffer (AllHandles, NULL, NULL, &HandleCount, &HandleBuffer);\r
+ if (EFI_ERROR (Status)) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLES_ERROR), mDpHiiHandle, Status);\r
+ return Status;\r
+ }\r
+\r
+ mCacheHandleGuidTable = AllocateZeroPool (HandleCount * sizeof (HANDLE_GUID_MAP));\r
+ if (mCacheHandleGuidTable == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ //\r
+ // Try Handle as ImageHandle.\r
+ //\r
+ Status = gBS->HandleProtocol (\r
+ HandleBuffer[Index],\r
+ &gEfiLoadedImageProtocolGuid,\r
+ (VOID**) &LoadedImage\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Try Handle as Controller Handle\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ HandleBuffer[Index],\r
+ &gEfiDriverBindingProtocolGuid,\r
+ (VOID **) &DriverBinding,\r
+ NULL,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Get Image protocol from ImageHandle\r
+ //\r
+ Status = gBS->HandleProtocol (\r
+ DriverBinding->ImageHandle,\r
+ &gEfiLoadedImageProtocolGuid,\r
+ (VOID**) &LoadedImage\r
+ );\r
+ }\r
+ }\r
+\r
+ if (!EFI_ERROR (Status) && LoadedImage != NULL) {\r
+ //\r
+ // Get Module Guid from DevicePath.\r
+ //\r
+ if (LoadedImage->FilePath != NULL &&\r
+ LoadedImage->FilePath->Type == MEDIA_DEVICE_PATH &&\r
+ LoadedImage->FilePath->SubType == MEDIA_PIWG_FW_FILE_DP\r
+ ) {\r
+ FvFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LoadedImage->FilePath;\r
+ TempGuid = &FvFilePath->FvFileName;\r
+\r
+ mCacheHandleGuidTable[mCachePairCount].Handle = HandleBuffer[Index];\r
+ CopyGuid (&mCacheHandleGuidTable[mCachePairCount].ModuleGuid, TempGuid);\r
+ mCachePairCount ++;\r
+ }\r
+ }\r
+ }\r
+ if (HandleBuffer != NULL) {\r
+ FreePool (HandleBuffer);\r
+ HandleBuffer = NULL;\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get Measurement form Fpdt records.\r
+\r
+ @param RecordHeader Pointer to the start record.\r
+ @param IsStart Is start record or End record.\r
+ @param Measurement Pointer to the measurement which need to be filled.\r
+\r
+**/\r
+VOID\r
+GetMeasurementInfo (\r
+ IN EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *RecordHeader,\r
+ IN BOOLEAN IsStart,\r
+ IN OUT MEASUREMENT_RECORD *Measurement\r
+ )\r
+{\r
+ VOID *ModuleGuid;\r
+ EFI_HANDLE StartHandle;\r
+\r
+ switch (RecordHeader->Type) {\r
+ case FPDT_GUID_EVENT_TYPE:\r
+ ModuleGuid = &(((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Guid);\r
+ Measurement->Identifier = ((UINT32)((FPDT_GUID_EVENT_RECORD *)RecordHeader)->ProgressID);\r
+ if (IsStart) {\r
+ Measurement->StartTimeStamp = ((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Timestamp;\r
+ } else {\r
+ Measurement->EndTimeStamp = ((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Timestamp;\r
+ }\r
+ switch (Measurement->Identifier) {\r
+ case MODULE_START_ID:\r
+ case MODULE_END_ID:\r
+ if (mPeiPhase) {\r
+ Measurement->Token = ALit_PEIM;\r
+ Measurement->Module = ALit_PEIM;\r
+ } else if (mDxePhase) {\r
+ Measurement->Token = ALit_START_IMAGE;\r
+ Measurement->Module = ALit_START_IMAGE;\r
+ }\r
+ break;\r
+ default:\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ if (AsciiStrCmp (Measurement->Token, ALit_PEIM) == 0) {\r
+ Measurement->Handle = &(((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Guid);\r
+ } else {\r
+ GetHandleFormModuleGuid(ModuleGuid, &StartHandle);\r
+ Measurement->Handle = StartHandle;\r
+ }\r
+ break;\r
+\r
+ case FPDT_DYNAMIC_STRING_EVENT_TYPE:\r
+ ModuleGuid = &(((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Guid);\r
+ Measurement->Identifier = ((UINT32)((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->ProgressID);\r
+ if (IsStart) {\r
+ Measurement->StartTimeStamp = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Timestamp;\r
+ } else {\r
+ Measurement->EndTimeStamp = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Timestamp;\r
+ }\r
+ switch (Measurement->Identifier) {\r
+ case MODULE_START_ID:\r
+ case MODULE_END_ID:\r
+ if (mPeiPhase) {\r
+ Measurement->Token = ALit_PEIM;\r
+ } else if (mDxePhase) {\r
+ Measurement->Token = ALit_START_IMAGE;\r
+ }\r
+ break;\r
+\r
+ case MODULE_LOADIMAGE_START_ID:\r
+ case MODULE_LOADIMAGE_END_ID:\r
+ Measurement->Token = ALit_LOAD_IMAGE;\r
+ break;\r
+\r
+ case MODULE_DB_START_ID:\r
+ case MODULE_DB_END_ID:\r
+ Measurement->Token = ALit_DB_START;\r
+ break;\r
+\r
+ case MODULE_DB_SUPPORT_START_ID:\r
+ case MODULE_DB_SUPPORT_END_ID:\r
+ Measurement->Token = ALit_DB_SUPPORT;\r
+ break;\r
+\r
+ case MODULE_DB_STOP_START_ID:\r
+ case MODULE_DB_STOP_END_ID:\r
+ Measurement->Token = ALit_DB_STOP;\r
+ break;\r
+\r
+ default:\r
+ Measurement->Token = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->String;\r
+ break;\r
+ }\r
+\r
+ Measurement->Module = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->String;\r
+\r
+ if (AsciiStrCmp (Measurement->Token, ALit_PEIM) == 0) {\r
+ Measurement->Handle = &(((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Guid);\r
+ } else {\r
+ GetHandleFormModuleGuid(ModuleGuid, &StartHandle);\r
+ Measurement->Handle = StartHandle;\r
+ }\r
+ break;\r
+\r
+ case FPDT_GUID_QWORD_EVENT_TYPE:\r
+ ModuleGuid = &(((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->Guid);\r
+ Measurement->Identifier = ((UINT32)((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->ProgressID);\r
+ if (IsStart) {\r
+ Measurement->StartTimeStamp = ((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->Timestamp;\r
+ } else {\r
+ Measurement->EndTimeStamp = ((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->Timestamp;\r
+ }\r
+ switch (Measurement->Identifier) {\r
+ case MODULE_DB_START_ID:\r
+ Measurement->Token = ALit_DB_START;\r
+ Measurement->Module = ALit_DB_START;\r
+ break;\r
+\r
+ case MODULE_DB_SUPPORT_START_ID:\r
+ case MODULE_DB_SUPPORT_END_ID:\r
+ Measurement->Token = ALit_DB_SUPPORT;\r
+ Measurement->Module = ALit_DB_SUPPORT;\r
+ break;\r
+\r
+ case MODULE_DB_STOP_START_ID:\r
+ case MODULE_DB_STOP_END_ID:\r
+ Measurement->Token = ALit_DB_STOP;\r
+ Measurement->Module = ALit_DB_STOP;\r
+ break;\r
+\r
+ case MODULE_LOADIMAGE_START_ID:\r
+ case MODULE_LOADIMAGE_END_ID:\r
+ Measurement->Token = ALit_LOAD_IMAGE;\r
+ Measurement->Module = ALit_LOAD_IMAGE;\r
+ break;\r
+\r
+ default:\r
+ ASSERT(FALSE);\r
+ }\r
+ GetHandleFormModuleGuid(ModuleGuid, &StartHandle);\r
+ Measurement->Handle = StartHandle;\r
+ break;\r
+\r
+ case FPDT_GUID_QWORD_STRING_EVENT_TYPE:\r
+ ModuleGuid = &(((FPDT_GUID_QWORD_STRING_EVENT_RECORD *)RecordHeader)->Guid);\r
+ Measurement->Identifier = ((UINT32)((FPDT_GUID_QWORD_STRING_EVENT_RECORD *)RecordHeader)->ProgressID);\r
+ if (IsStart) {\r
+ Measurement->StartTimeStamp = ((FPDT_GUID_QWORD_STRING_EVENT_RECORD*)RecordHeader)->Timestamp;\r
+ } else {\r
+ Measurement->EndTimeStamp = ((FPDT_GUID_QWORD_STRING_EVENT_RECORD *)RecordHeader)->Timestamp;\r
+ }\r
+ //\r
+ // Currently only "DB:Start:" end record with FPDT_GUID_QWORD_STRING_EVENT_TYPE.\r
+ //\r
+ switch (Measurement->Identifier) {\r
+ case MODULE_DB_END_ID:\r
+ Measurement->Token = ALit_DB_START;\r
+ Measurement->Module = ALit_DB_START;\r
+ break;\r
+ default:\r
+ ASSERT(FALSE);\r
+ }\r
+ GetHandleFormModuleGuid(ModuleGuid, &StartHandle);\r
+ Measurement->Handle = StartHandle;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+}\r
+\r
+/**\r
+ Search the start measurement in the mMeasurementList for the end measurement.\r
+\r
+ @param EndMeasureMent Measurement for end record.\r
+\r
+**/\r
+VOID\r
+SearchMeasurement (\r
+ IN MEASUREMENT_RECORD *EndMeasureMent\r
+ )\r
+{\r
+ INTN Index;\r
+\r
+ for (Index = mMeasurementNum - 1; Index >= 0; Index--) {\r
+ if (AsciiStrCmp (EndMeasureMent->Token, ALit_PEIM) == 0) {\r
+ if (mMeasurementList[Index].EndTimeStamp == 0 && EndMeasureMent->Handle!= NULL && mMeasurementList[Index].Handle != NULL&&\r
+ CompareGuid(mMeasurementList[Index].Handle, EndMeasureMent->Handle) &&\r
+ (AsciiStrCmp (mMeasurementList[Index].Token, EndMeasureMent->Token) == 0) &&\r
+ (AsciiStrCmp (mMeasurementList[Index].Module, EndMeasureMent->Module) == 0)) {\r
+ mMeasurementList[Index].EndTimeStamp = EndMeasureMent->EndTimeStamp;\r
+ break;\r
+ }\r
+ } else {\r
+ if (mMeasurementList[Index].EndTimeStamp == 0 && mMeasurementList[Index].Handle == EndMeasureMent->Handle &&\r
+ (AsciiStrCmp (mMeasurementList[Index].Token, EndMeasureMent->Token) == 0) &&\r
+ (AsciiStrCmp (mMeasurementList[Index].Module, EndMeasureMent->Module) == 0)) {\r
+ mMeasurementList[Index].EndTimeStamp = EndMeasureMent->EndTimeStamp;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Generate the measure record array.\r
+\r
+**/\r
+EFI_STATUS\r
+BuildMeasurementList (\r
+ )\r
+{\r
+ EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *RecordHeader;\r
+ UINT8 *PerformanceTablePtr;\r
+ UINT16 StartProgressId;\r
+ UINTN TableLength;\r
+ UINT8 *StartRecordEvent;\r
+ MEASUREMENT_RECORD MeasureMent;\r
+\r
+ mMeasurementList = AllocateZeroPool (mBootPerformanceTableSize);\r
+ if (mMeasurementList == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ TableLength = sizeof (BOOT_PERFORMANCE_TABLE);\r
+ PerformanceTablePtr = (mBootPerformanceTable + TableLength);\r
+\r
+ while (TableLength < mBootPerformanceTableSize) {\r
+ RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER*) PerformanceTablePtr;\r
+ StartRecordEvent = (UINT8 *)RecordHeader;\r
+ StartProgressId = ((FPDT_GUID_EVENT_RECORD *)StartRecordEvent)->ProgressID;\r
+\r
+ //\r
+ // If the record is the start record, fill the info to the measurement in the mMeasurementList.\r
+ // If the record is the end record, find the related start measurement in the mMeasurementList and fill the EndTimeStamp.\r
+ //\r
+ if (((StartProgressId >= PERF_EVENTSIGNAL_START_ID && ((StartProgressId & 0x000F) == 0)) ||\r
+ (StartProgressId < PERF_EVENTSIGNAL_START_ID && ((StartProgressId & 0x0001) != 0)))) {\r
+ //\r
+ // Since PEIM and StartImage has same Type and ID when PCD PcdEdkiiFpdtStringRecordEnableOnly = FALSE\r
+ // So we need to identify these two kinds of record through different phase.\r
+ //\r
+ if (AsciiStrCmp (((FPDT_DYNAMIC_STRING_EVENT_RECORD *)StartRecordEvent)->String, ALit_PEI) == 0) {\r
+ mPeiPhase = TRUE;\r
+ } else if (AsciiStrCmp (((FPDT_DYNAMIC_STRING_EVENT_RECORD *)StartRecordEvent)->String, ALit_DXE) == 0) {\r
+ mDxePhase = TRUE;\r
+ mPeiPhase = FALSE;\r
+ }\r
+ // Get measurement info form the start record to the mMeasurementList.\r
+ GetMeasurementInfo (RecordHeader, TRUE, &(mMeasurementList[mMeasurementNum]));\r
+ mMeasurementNum ++;\r
+ } else {\r
+ GetMeasurementInfo (RecordHeader, FALSE, &MeasureMent);\r
+ SearchMeasurement (&MeasureMent);\r
+ }\r
+ TableLength += RecordHeader->Length;\r
+ PerformanceTablePtr += RecordHeader->Length;\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r