2 This module install ACPI Firmware Performance Data Table (FPDT).
4 This module register report status code listener to collect performance data
5 for Firmware Basic Boot Performance Record and install FPDT to ACPI table.
7 Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 #include <IndustryStandard/Acpi50.h>
22 #include <Protocol/ReportStatusCodeHandler.h>
23 #include <Protocol/AcpiTable.h>
25 #include <Guid/Acpi.h>
26 #include <Guid/FirmwarePerformance.h>
27 #include <Guid/EventGroup.h>
28 #include <Guid/EventLegacyBios.h>
30 #include <Library/UefiBootServicesTableLib.h>
31 #include <Library/UefiRuntimeServicesTableLib.h>
32 #include <Library/BaseLib.h>
33 #include <Library/DebugLib.h>
34 #include <Library/TimerLib.h>
35 #include <Library/BaseMemoryLib.h>
36 #include <Library/MemoryAllocationLib.h>
37 #include <Library/PcdLib.h>
38 #include <Library/HobLib.h>
39 #include <Library/PcdLib.h>
42 // ACPI table information used to initialize tables.
44 #define EFI_ACPI_OEM_ID "INTEL"
45 #define EFI_ACPI_OEM_TABLE_ID 0x2020204F4E414954ULL // "TIANO "
46 #define EFI_ACPI_OEM_REVISION 0x00000001
47 #define EFI_ACPI_CREATOR_ID 0x5446534D // TBD "MSFT"
48 #define EFI_ACPI_CREATOR_REVISION 0x01000013 // TBD
50 EFI_RSC_HANDLER_PROTOCOL
*mRscHandlerProtocol
= NULL
;
52 EFI_EVENT mReadyToBootEvent
;
53 EFI_EVENT mLegacyBootEvent
;
54 EFI_EVENT mExitBootServicesEvent
;
55 UINTN mFirmwarePerformanceTableTemplateKey
= 0;
57 FIRMWARE_PERFORMANCE_RUNTIME_DATA
*mPerformanceRuntimeData
= NULL
;
58 BOOT_PERFORMANCE_TABLE
*mAcpiBootPerformanceTable
= NULL
;
59 S3_PERFORMANCE_TABLE
*mAcpiS3PerformanceTable
= NULL
;
61 FIRMWARE_PERFORMANCE_TABLE mFirmwarePerformanceTableTemplate
= {
63 EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE
,
64 sizeof (FIRMWARE_PERFORMANCE_TABLE
),
65 EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_REVISION
, // Revision
66 0x00, // Checksum will be updated at runtime
68 // It is expected that these values will be updated at runtime.
70 EFI_ACPI_OEM_ID
, // OEMID is a 6 bytes long field
71 EFI_ACPI_OEM_TABLE_ID
, // OEM table identification(8 bytes long)
72 EFI_ACPI_OEM_REVISION
, // OEM revision number
73 EFI_ACPI_CREATOR_ID
, // ASL compiler vendor ID
74 EFI_ACPI_CREATOR_REVISION
, // ASL compiler revision number
77 // Firmware Basic Boot Performance Table Pointer Record.
81 EFI_ACPI_5_0_FPDT_RECORD_TYPE_FIRMWARE_BASIC_BOOT_POINTER
, // Type
82 sizeof (EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_POINTER_RECORD
), // Length
83 EFI_ACPI_5_0_FPDT_RECORD_REVISION_FIRMWARE_BASIC_BOOT_POINTER
// Revision
86 0 // BootPerformanceTablePointer will be updated at runtime.
89 // S3 Performance Table Pointer Record.
93 EFI_ACPI_5_0_FPDT_RECORD_TYPE_S3_PERFORMANCE_TABLE_POINTER
, // Type
94 sizeof (EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD
), // Length
95 EFI_ACPI_5_0_FPDT_RECORD_REVISION_S3_PERFORMANCE_TABLE_POINTER
// Revision
98 0 // S3PerformanceTablePointer will be updated at runtime.
102 BOOT_PERFORMANCE_TABLE mBootPerformanceTableTemplate
= {
104 EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_SIGNATURE
,
105 sizeof (BOOT_PERFORMANCE_TABLE
)
109 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT
, // Type
110 sizeof (EFI_ACPI_5_0_FPDT_FIRMWARE_BASIC_BOOT_RECORD
), // Length
111 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_FIRMWARE_BASIC_BOOT
// Revision
115 // These values will be updated at runtime.
118 0, // OsLoaderLoadImageStart
119 0, // OsLoaderStartImageStart
120 0, // ExitBootServicesEntry
121 0 // ExitBootServicesExit
125 S3_PERFORMANCE_TABLE mS3PerformanceTableTemplate
= {
127 EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_SIGNATURE
,
128 sizeof (S3_PERFORMANCE_TABLE
)
132 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_S3_RESUME
, // Type
133 sizeof (EFI_ACPI_5_0_FPDT_S3_RESUME_RECORD
), // Length
134 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_S3_RESUME
// Revision
137 // These values will be updated by Firmware Performance PEIM.
145 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_S3_SUSPEND
, // Type
146 sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD
), // Length
147 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_S3_SUSPEND
// Revision
150 // These values will be updated bye Firmware Performance SMM driver.
158 This function calculates and updates an UINT8 checksum.
160 @param[in] Buffer Pointer to buffer to checksum
161 @param[in] Size Number of bytes to checksum
165 FpdtAcpiTableChecksum (
170 UINTN ChecksumOffset
;
172 ChecksumOffset
= OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER
, Checksum
);
175 // Set checksum to 0 first.
177 Buffer
[ChecksumOffset
] = 0;
180 // Update checksum value.
182 Buffer
[ChecksumOffset
] = CalculateCheckSum8 (Buffer
, Size
);
186 Allocate EfiReservedMemoryType below 4G memory address.
188 This function allocates EfiReservedMemoryType below 4G memory address.
190 @param[in] Size Size of memory to allocate.
192 @return Allocated address for output.
196 FpdtAllocateReservedMemoryBelow4G (
201 EFI_PHYSICAL_ADDRESS Address
;
205 Pages
= EFI_SIZE_TO_PAGES (Size
);
206 Address
= 0xffffffff;
208 Status
= gBS
->AllocatePages (
210 EfiReservedMemoryType
,
214 ASSERT_EFI_ERROR (Status
);
216 Buffer
= (VOID
*) (UINTN
) Address
;
217 ZeroMem (Buffer
, Size
);
223 Install ACPI Firmware Performance Data Table (FPDT).
229 InstallFirmwarePerformanceDataTable (
234 EFI_ACPI_TABLE_PROTOCOL
*AcpiTableProtocol
;
235 FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable
;
236 EFI_PHYSICAL_ADDRESS Address
;
240 // Get AcpiTable Protocol.
242 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**) &AcpiTableProtocol
);
243 if (EFI_ERROR (Status
)) {
248 // Prepare memory for runtime Performance Record.
250 mPerformanceRuntimeData
= NULL
;
251 ZeroMem (&PerformanceVariable
, sizeof (PerformanceVariable
));
253 // Try to allocate the same runtime buffer as last time boot.
255 Size
= sizeof (FIRMWARE_PERFORMANCE_VARIABLE
);
256 Status
= gRT
->GetVariable (
257 EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME
,
258 &gEfiFirmwarePerformanceGuid
,
263 if (!EFI_ERROR (Status
)) {
264 Address
= PerformanceVariable
.BootPerformanceTablePointer
;
265 Status
= gBS
->AllocatePages (
267 EfiReservedMemoryType
,
268 EFI_SIZE_TO_PAGES (sizeof (FIRMWARE_PERFORMANCE_RUNTIME_DATA
)),
271 if (!EFI_ERROR (Status
)) {
272 mPerformanceRuntimeData
= (FIRMWARE_PERFORMANCE_RUNTIME_DATA
*) (UINTN
) Address
;
276 if (mPerformanceRuntimeData
== NULL
) {
278 // Fail to allocate at specified address, continue to allocate at any address.
280 mPerformanceRuntimeData
= FpdtAllocateReservedMemoryBelow4G (sizeof (FIRMWARE_PERFORMANCE_RUNTIME_DATA
));
282 DEBUG ((EFI_D_INFO
, "FPDT: Performance Runtime Data address = 0x%x\n", mPerformanceRuntimeData
));
284 if (mPerformanceRuntimeData
== NULL
) {
285 return EFI_OUT_OF_RESOURCES
;
289 // Prepare Boot Performance Table.
291 mAcpiBootPerformanceTable
= &mPerformanceRuntimeData
->BootPerformance
;
292 CopyMem (mAcpiBootPerformanceTable
, &mBootPerformanceTableTemplate
, sizeof (mBootPerformanceTableTemplate
));
293 DEBUG ((EFI_D_INFO
, "FPDT: ACPI Boot Performance Table address = 0x%x\n", mAcpiBootPerformanceTable
));
295 // Save Boot Performance Table address to Variable for use in S4 resume.
297 PerformanceVariable
.BootPerformanceTablePointer
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) mAcpiBootPerformanceTable
;
299 // Update Boot Performance Table Pointer in template.
301 mFirmwarePerformanceTableTemplate
.BootPointerRecord
.BootPerformanceTablePointer
= (UINT64
) (UINTN
) mAcpiBootPerformanceTable
;
303 if (FeaturePcdGet (PcdFirmwarePerformanceDataTableS3Support
)) {
305 // Prepare S3 Performance Table.
307 mAcpiS3PerformanceTable
= &mPerformanceRuntimeData
->S3Performance
;
308 CopyMem (mAcpiS3PerformanceTable
, &mS3PerformanceTableTemplate
, sizeof (mS3PerformanceTableTemplate
));
309 DEBUG ((EFI_D_INFO
, "FPDT: ACPI S3 Performance Table address = 0x%x\n", mAcpiS3PerformanceTable
));
312 // Save S3 Performance Table address to Variable for use in Firmware Performance PEIM.
314 PerformanceVariable
.S3PerformanceTablePointer
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) mAcpiS3PerformanceTable
;
317 // Update S3 Performance Table Pointer in template.
319 mFirmwarePerformanceTableTemplate
.S3PointerRecord
.S3PerformanceTablePointer
= (UINT64
) PerformanceVariable
.S3PerformanceTablePointer
;
322 // Exclude S3 Performance Table Pointer from FPDT table template.
324 mFirmwarePerformanceTableTemplate
.Header
.Length
-= sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD
);
328 // Save Runtime Performance Table pointers to Variable.
330 Status
= gRT
->SetVariable (
331 EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME
,
332 &gEfiFirmwarePerformanceGuid
,
333 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
334 sizeof (FIRMWARE_PERFORMANCE_VARIABLE
),
337 ASSERT_EFI_ERROR (Status
);
340 // Publish Firmware Performance Data Table.
342 FpdtAcpiTableChecksum ((UINT8
*) &mFirmwarePerformanceTableTemplate
, mFirmwarePerformanceTableTemplate
.Header
.Length
);
343 Status
= AcpiTableProtocol
->InstallAcpiTable (
345 &mFirmwarePerformanceTableTemplate
,
346 mFirmwarePerformanceTableTemplate
.Header
.Length
,
347 &mFirmwarePerformanceTableTemplateKey
349 if (EFI_ERROR (Status
)) {
350 FreePool (mPerformanceRuntimeData
);
351 mAcpiBootPerformanceTable
= NULL
;
352 mAcpiS3PerformanceTable
= NULL
;
360 Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
361 install the Firmware Performance Data Table.
363 @param[in] Event The Event that is being processed.
364 @param[in] Context The Event Context.
369 FpdtReadyToBootEventNotify (
374 if (mAcpiBootPerformanceTable
== NULL
) {
376 // ACPI Firmware Performance Data Table not installed yet, install it now.
378 InstallFirmwarePerformanceDataTable ();
383 Notify function for event group EFI_EVENT_LEGACY_BOOT_GUID. This is used to
384 record performance data for OsLoaderLoadImageStart in FPDT for legacy boot.
386 @param[in] Event The Event that is being processed.
387 @param[in] Context The Event Context.
392 FpdtLegacyBootEventNotify (
397 if (mAcpiBootPerformanceTable
== NULL
) {
399 // Firmware Performance Data Table not installed, do nothing.
405 // Update Firmware Basic Boot Performance Record for legacy boot.
407 mAcpiBootPerformanceTable
->BasicBoot
.OsLoaderLoadImageStart
= 0;
408 mAcpiBootPerformanceTable
->BasicBoot
.OsLoaderStartImageStart
= GetTimeInNanoSecond (GetPerformanceCounter ());
409 mAcpiBootPerformanceTable
->BasicBoot
.ExitBootServicesEntry
= 0;
410 mAcpiBootPerformanceTable
->BasicBoot
.ExitBootServicesExit
= 0;
413 // Dump FPDT Boot Performance record.
415 DEBUG ((EFI_D_INFO
, "FPDT: Boot Performance - ResetEnd = %ld\n", mAcpiBootPerformanceTable
->BasicBoot
.ResetEnd
));
416 DEBUG ((EFI_D_INFO
, "FPDT: Boot Performance - OsLoaderLoadImageStart = 0\n"));
417 DEBUG ((EFI_D_INFO
, "FPDT: Boot Performance - OsLoaderStartImageStart = %ld\n", mAcpiBootPerformanceTable
->BasicBoot
.OsLoaderStartImageStart
));
418 DEBUG ((EFI_D_INFO
, "FPDT: Boot Performance - ExitBootServicesEntry = 0\n"));
419 DEBUG ((EFI_D_INFO
, "FPDT: Boot Performance - ExitBootServicesExit = 0\n"));
423 Notify function for event EVT_SIGNAL_EXIT_BOOT_SERVICES. This is used to record
424 performance data for ExitBootServicesEntry in FPDT.
426 @param[in] Event The Event that is being processed.
427 @param[in] Context The Event Context.
432 FpdtExitBootServicesEventNotify (
437 if (mAcpiBootPerformanceTable
== NULL
) {
439 // Firmware Performance Data Table not installed, do nothing.
445 // Update Firmware Basic Boot Performance Record for UEFI boot.
447 mAcpiBootPerformanceTable
->BasicBoot
.ExitBootServicesEntry
= GetTimeInNanoSecond (GetPerformanceCounter ());
450 // Dump FPDT Boot Performance record.
452 DEBUG ((EFI_D_INFO
, "FPDT: Boot Performance - ResetEnd = %ld\n", mAcpiBootPerformanceTable
->BasicBoot
.ResetEnd
));
453 DEBUG ((EFI_D_INFO
, "FPDT: Boot Performance - OsLoaderLoadImageStart = %ld\n", mAcpiBootPerformanceTable
->BasicBoot
.OsLoaderLoadImageStart
));
454 DEBUG ((EFI_D_INFO
, "FPDT: Boot Performance - OsLoaderStartImageStart = %ld\n", mAcpiBootPerformanceTable
->BasicBoot
.OsLoaderStartImageStart
));
455 DEBUG ((EFI_D_INFO
, "FPDT: Boot Performance - ExitBootServicesEntry = %ld\n", mAcpiBootPerformanceTable
->BasicBoot
.ExitBootServicesEntry
));
457 // ExitBootServicesExit will be updated later, so don't dump it here.
462 Report status code listener of FPDT. This is used to collect performance data
463 for OsLoaderLoadImageStart and OsLoaderStartImageStart in FPDT.
465 @param[in] CodeType Indicates the type of status code being reported.
466 @param[in] Value Describes the current status of a hardware or software entity.
467 This included information about the class and subclass that is used to
468 classify the entity as well as an operation.
469 @param[in] Instance The enumeration of a hardware or software entity within
470 the system. Valid instance numbers start with 1.
471 @param[in] CallerId This optional parameter may be used to identify the caller.
472 This parameter allows the status code driver to apply different rules to
474 @param[in] Data This optional parameter may be used to pass additional data.
476 @retval EFI_SUCCESS Status code is what we expected.
477 @retval EFI_UNSUPPORTED Status code not supported.
482 FpdtStatusCodeListenerDxe (
483 IN EFI_STATUS_CODE_TYPE CodeType
,
484 IN EFI_STATUS_CODE_VALUE Value
,
486 IN EFI_GUID
*CallerId
,
487 IN EFI_STATUS_CODE_DATA
*Data
493 // Check whether status code is what we are interested in.
495 if ((CodeType
& EFI_STATUS_CODE_TYPE_MASK
) != EFI_PROGRESS_CODE
) {
496 return EFI_UNSUPPORTED
;
499 Status
= EFI_SUCCESS
;
500 if (Value
== PcdGet32 (PcdProgressCodeOsLoaderLoad
)) {
502 // Progress code for OS Loader LoadImage.
504 if (mAcpiBootPerformanceTable
== NULL
) {
509 // Update OS Loader LoadImage Start for UEFI boot.
511 mAcpiBootPerformanceTable
->BasicBoot
.OsLoaderLoadImageStart
= GetTimeInNanoSecond (GetPerformanceCounter ());
512 } else if (Value
== PcdGet32 (PcdProgressCodeOsLoaderStart
)) {
514 // Progress code for OS Loader StartImage.
516 if (mAcpiBootPerformanceTable
== NULL
) {
521 // Update OS Loader StartImage Start for UEFI boot.
523 mAcpiBootPerformanceTable
->BasicBoot
.OsLoaderStartImageStart
= GetTimeInNanoSecond (GetPerformanceCounter ());
524 } else if (Value
== (EFI_SOFTWARE_EFI_BOOT_SERVICE
| EFI_SW_BS_PC_EXIT_BOOT_SERVICES
)) {
526 // Progress code for ExitBootServices.
528 if (mAcpiBootPerformanceTable
== NULL
) {
533 // Update ExitBootServicesExit for UEFI boot.
535 mAcpiBootPerformanceTable
->BasicBoot
.ExitBootServicesExit
= GetTimeInNanoSecond (GetPerformanceCounter ());
538 // Unregister boot time report status code listener.
540 mRscHandlerProtocol
->Unregister (FpdtStatusCodeListenerDxe
);
543 // Ignore else progress code.
545 Status
= EFI_UNSUPPORTED
;
552 The module Entry Point of the Firmware Performance Data Table DXE driver.
554 @param[in] ImageHandle The firmware allocated handle for the EFI image.
555 @param[in] SystemTable A pointer to the EFI System Table.
557 @retval EFI_SUCCESS The entry point is executed successfully.
558 @retval Other Some error occurs when executing this entry point.
563 FirmwarePerformanceDxeEntryPoint (
564 IN EFI_HANDLE ImageHandle
,
565 IN EFI_SYSTEM_TABLE
*SystemTable
569 EFI_HOB_GUID_TYPE
*GuidHob
;
570 FIRMWARE_SEC_PERFORMANCE
*Performance
;
573 // Get Report Status Code Handler Protocol.
575 Status
= gBS
->LocateProtocol (&gEfiRscHandlerProtocolGuid
, NULL
, (VOID
**) &mRscHandlerProtocol
);
576 ASSERT_EFI_ERROR (Status
);
579 // Register report status code listener for OS Loader load and start.
581 Status
= mRscHandlerProtocol
->Register (FpdtStatusCodeListenerDxe
, TPL_HIGH_LEVEL
);
582 ASSERT_EFI_ERROR (Status
);
585 // Register the notify function to update FPDT on ExitBootServices Event.
587 Status
= gBS
->CreateEventEx (
590 FpdtExitBootServicesEventNotify
,
592 &gEfiEventExitBootServicesGuid
,
593 &mExitBootServicesEvent
595 ASSERT_EFI_ERROR (Status
);
598 // Create ready to boot event to install ACPI FPDT table.
600 Status
= gBS
->CreateEventEx (
603 FpdtReadyToBootEventNotify
,
605 &gEfiEventReadyToBootGuid
,
608 ASSERT_EFI_ERROR (Status
);
611 // Create legacy boot event to log OsLoaderStartImageStart for legacy boot.
613 Status
= gBS
->CreateEventEx (
616 FpdtLegacyBootEventNotify
,
618 &gEfiEventLegacyBootGuid
,
621 ASSERT_EFI_ERROR (Status
);
624 // Retrieve GUID HOB data that contains the ResetEnd.
626 GuidHob
= GetFirstGuidHob (&gEfiFirmwarePerformanceGuid
);
627 if (GuidHob
!= NULL
) {
628 Performance
= (FIRMWARE_SEC_PERFORMANCE
*) GET_GUID_HOB_DATA (GuidHob
);
629 mBootPerformanceTableTemplate
.BasicBoot
.ResetEnd
= Performance
->ResetEnd
;
632 // SEC Performance Data Hob not found, ResetEnd in ACPI FPDT table will be 0.
634 DEBUG ((EFI_D_ERROR
, "FPDT: WARNING: SEC Performance Data Hob not found, ResetEnd will be set to 0!\n"));