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 other boot performance records,
6 and install FPDT to ACPI table.
8 Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>
9 This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 #include <Protocol/ReportStatusCodeHandler.h>
22 #include <Protocol/AcpiTable.h>
23 #include <Protocol/SmmCommunication.h>
24 #include <Protocol/LockBox.h>
25 #include <Protocol/Variable.h>
27 #include <Guid/Acpi.h>
28 #include <Guid/FirmwarePerformance.h>
29 #include <Guid/EventGroup.h>
30 #include <Guid/EventLegacyBios.h>
31 #include <Guid/PiSmmCommunicationRegionTable.h>
33 #include <Library/UefiBootServicesTableLib.h>
34 #include <Library/UefiRuntimeServicesTableLib.h>
35 #include <Library/BaseLib.h>
36 #include <Library/DebugLib.h>
37 #include <Library/TimerLib.h>
38 #include <Library/BaseMemoryLib.h>
39 #include <Library/MemoryAllocationLib.h>
40 #include <Library/PcdLib.h>
41 #include <Library/HobLib.h>
42 #include <Library/LockBoxLib.h>
43 #include <Library/UefiLib.h>
45 #define EXTENSION_RECORD_SIZE 0x10000
46 #define SMM_BOOT_RECORD_COMM_SIZE OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + sizeof(SMM_BOOT_RECORD_COMMUNICATE)
48 EFI_RSC_HANDLER_PROTOCOL
*mRscHandlerProtocol
= NULL
;
50 BOOLEAN mLockBoxReady
= FALSE
;
51 EFI_EVENT mReadyToBootEvent
;
52 EFI_EVENT mLegacyBootEvent
;
53 EFI_EVENT mExitBootServicesEvent
;
54 UINTN mFirmwarePerformanceTableTemplateKey
= 0;
55 UINT32 mBootRecordSize
= 0;
56 UINT32 mBootRecordMaxSize
= 0;
57 UINT8
*mBootRecordBuffer
= NULL
;
58 BOOLEAN mDxeCoreReportStatusCodeEnable
= FALSE
;
60 BOOT_PERFORMANCE_TABLE
*mAcpiBootPerformanceTable
= NULL
;
61 S3_PERFORMANCE_TABLE
*mAcpiS3PerformanceTable
= NULL
;
63 FIRMWARE_PERFORMANCE_TABLE mFirmwarePerformanceTableTemplate
= {
65 EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE
,
66 sizeof (FIRMWARE_PERFORMANCE_TABLE
),
67 EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_REVISION
, // Revision
68 0x00, // Checksum will be updated at runtime
70 // It is expected that these values will be updated at EntryPoint.
72 {0x00}, // OEM ID is a 6 bytes long field
73 0x00, // OEM Table ID(8 bytes long)
76 0x00, // Creator Revision
79 // Firmware Basic Boot Performance Table Pointer Record.
83 EFI_ACPI_5_0_FPDT_RECORD_TYPE_FIRMWARE_BASIC_BOOT_POINTER
, // Type
84 sizeof (EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_POINTER_RECORD
), // Length
85 EFI_ACPI_5_0_FPDT_RECORD_REVISION_FIRMWARE_BASIC_BOOT_POINTER
// Revision
88 0 // BootPerformanceTablePointer will be updated at runtime.
91 // S3 Performance Table Pointer Record.
95 EFI_ACPI_5_0_FPDT_RECORD_TYPE_S3_PERFORMANCE_TABLE_POINTER
, // Type
96 sizeof (EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD
), // Length
97 EFI_ACPI_5_0_FPDT_RECORD_REVISION_S3_PERFORMANCE_TABLE_POINTER
// Revision
100 0 // S3PerformanceTablePointer will be updated at runtime.
104 BOOT_PERFORMANCE_TABLE mBootPerformanceTableTemplate
= {
106 EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_SIGNATURE
,
107 sizeof (BOOT_PERFORMANCE_TABLE
)
111 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT
, // Type
112 sizeof (EFI_ACPI_5_0_FPDT_FIRMWARE_BASIC_BOOT_RECORD
), // Length
113 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_FIRMWARE_BASIC_BOOT
// Revision
117 // These values will be updated at runtime.
120 0, // OsLoaderLoadImageStart
121 0, // OsLoaderStartImageStart
122 0, // ExitBootServicesEntry
123 0 // ExitBootServicesExit
127 S3_PERFORMANCE_TABLE mS3PerformanceTableTemplate
= {
129 EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_SIGNATURE
,
130 sizeof (S3_PERFORMANCE_TABLE
)
134 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_S3_RESUME
, // Type
135 sizeof (EFI_ACPI_5_0_FPDT_S3_RESUME_RECORD
), // Length
136 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_S3_RESUME
// Revision
139 // These values will be updated by Firmware Performance PEIM.
147 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_S3_SUSPEND
, // Type
148 sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD
), // Length
149 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_S3_SUSPEND
// Revision
152 // These values will be updated bye Firmware Performance SMM driver.
160 This function calculates and updates an UINT8 checksum.
162 @param[in] Buffer Pointer to buffer to checksum
163 @param[in] Size Number of bytes to checksum
167 FpdtAcpiTableChecksum (
172 UINTN ChecksumOffset
;
174 ChecksumOffset
= OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER
, Checksum
);
177 // Set checksum to 0 first.
179 Buffer
[ChecksumOffset
] = 0;
182 // Update checksum value.
184 Buffer
[ChecksumOffset
] = CalculateCheckSum8 (Buffer
, Size
);
188 Allocate EfiReservedMemoryType below 4G memory address.
190 This function allocates EfiReservedMemoryType below 4G memory address.
192 @param[in] Size Size of memory to allocate.
194 @return Allocated address for output.
198 FpdtAllocateReservedMemoryBelow4G (
203 EFI_PHYSICAL_ADDRESS Address
;
208 Pages
= EFI_SIZE_TO_PAGES (Size
);
209 Address
= 0xffffffff;
211 Status
= gBS
->AllocatePages (
213 EfiReservedMemoryType
,
217 ASSERT_EFI_ERROR (Status
);
219 if (!EFI_ERROR (Status
)) {
220 Buffer
= (VOID
*) (UINTN
) Address
;
221 ZeroMem (Buffer
, Size
);
228 Callback function upon VariableArchProtocol and LockBoxProtocol
229 to allocate S3 performance table memory and save the pointer to LockBox.
231 @param[in] Event Event whose notification function is being invoked.
232 @param[in] Context Pointer to the notification function's context.
236 FpdtAllocateS3PerformanceTableMemory (
243 FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable
;
245 EFI_PHYSICAL_ADDRESS S3PerformanceTablePointer
;
247 if (mLockBoxReady
&& (mAcpiS3PerformanceTable
!= NULL
)) {
249 // The memory for S3 performance table should have been ready,
250 // and the pointer should have been saved to LockBox, just return.
255 if (!mLockBoxReady
) {
256 Status
= gBS
->LocateProtocol (&gEfiLockBoxProtocolGuid
, NULL
, &Interface
);
257 if (!EFI_ERROR (Status
)) {
259 // LockBox services has been ready.
261 mLockBoxReady
= TRUE
;
265 if (mAcpiS3PerformanceTable
== NULL
) {
266 Status
= gBS
->LocateProtocol (&gEfiVariableArchProtocolGuid
, NULL
, &Interface
);
267 if (!EFI_ERROR (Status
)) {
269 // Try to allocate the same runtime buffer as last time boot.
271 ZeroMem (&PerformanceVariable
, sizeof (PerformanceVariable
));
272 Size
= sizeof (PerformanceVariable
);
273 Status
= gRT
->GetVariable (
274 EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME
,
275 &gEfiFirmwarePerformanceGuid
,
280 if (!EFI_ERROR (Status
)) {
281 Status
= gBS
->AllocatePages (
283 EfiReservedMemoryType
,
284 EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE
)),
285 &PerformanceVariable
.S3PerformanceTablePointer
287 if (!EFI_ERROR (Status
)) {
288 mAcpiS3PerformanceTable
= (S3_PERFORMANCE_TABLE
*) (UINTN
) PerformanceVariable
.S3PerformanceTablePointer
;
291 if (mAcpiS3PerformanceTable
== NULL
) {
293 // Fail to allocate at specified address, continue to allocate at any address.
295 mAcpiS3PerformanceTable
= (S3_PERFORMANCE_TABLE
*) FpdtAllocateReservedMemoryBelow4G (sizeof (S3_PERFORMANCE_TABLE
));
297 DEBUG ((EFI_D_INFO
, "FPDT: ACPI S3 Performance Table address = 0x%x\n", mAcpiS3PerformanceTable
));
298 if (mAcpiS3PerformanceTable
!= NULL
) {
299 CopyMem (mAcpiS3PerformanceTable
, &mS3PerformanceTableTemplate
, sizeof (mS3PerformanceTableTemplate
));
304 if (mLockBoxReady
&& (mAcpiS3PerformanceTable
!= NULL
)) {
306 // If LockBox services has been ready and memory for FPDT S3 performance table has been allocated,
307 // save the pointer to LockBox for use in S3 resume.
309 S3PerformanceTablePointer
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) mAcpiS3PerformanceTable
;
310 Status
= SaveLockBox (
311 &gFirmwarePerformanceS3PointerGuid
,
312 &S3PerformanceTablePointer
,
313 sizeof (EFI_PHYSICAL_ADDRESS
)
315 ASSERT_EFI_ERROR (Status
);
320 Install ACPI Firmware Performance Data Table (FPDT).
326 InstallFirmwarePerformanceDataTable (
331 EFI_ACPI_TABLE_PROTOCOL
*AcpiTableProtocol
;
333 UINT8
*SmmBootRecordCommBuffer
;
334 EFI_SMM_COMMUNICATE_HEADER
*SmmCommBufferHeader
;
335 SMM_BOOT_RECORD_COMMUNICATE
*SmmCommData
;
337 UINTN BootPerformanceDataSize
;
338 UINT8
*BootPerformanceData
;
339 EFI_SMM_COMMUNICATION_PROTOCOL
*Communication
;
340 FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable
;
341 EDKII_PI_SMM_COMMUNICATION_REGION_TABLE
*SmmCommRegionTable
;
342 EFI_MEMORY_DESCRIPTOR
*SmmCommMemRegion
;
344 VOID
*SmmBootRecordData
;
345 UINTN SmmBootRecordDataSize
;
346 UINTN ReservedMemSize
;
349 // Get AcpiTable Protocol.
351 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**) &AcpiTableProtocol
);
352 if (EFI_ERROR (Status
)) {
357 // Collect boot records from SMM drivers.
359 SmmBootRecordCommBuffer
= NULL
;
361 SmmBootRecordData
= NULL
;
362 SmmBootRecordDataSize
= 0;
364 Status
= gBS
->LocateProtocol (&gEfiSmmCommunicationProtocolGuid
, NULL
, (VOID
**) &Communication
);
365 if (!EFI_ERROR (Status
)) {
367 // Initialize communicate buffer
368 // Get the prepared Reserved Memory Range
370 Status
= EfiGetSystemConfigurationTable (
371 &gEdkiiPiSmmCommunicationRegionTableGuid
,
372 (VOID
**) &SmmCommRegionTable
374 if (!EFI_ERROR (Status
)) {
375 ASSERT (SmmCommRegionTable
!= NULL
);
376 SmmCommMemRegion
= (EFI_MEMORY_DESCRIPTOR
*) (SmmCommRegionTable
+ 1);
377 for (Index
= 0; Index
< SmmCommRegionTable
->NumberOfEntries
; Index
++) {
378 if (SmmCommMemRegion
->Type
== EfiConventionalMemory
) {
381 SmmCommMemRegion
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) SmmCommMemRegion
+ SmmCommRegionTable
->DescriptorSize
);
383 ASSERT (Index
< SmmCommRegionTable
->NumberOfEntries
);
384 ASSERT (SmmCommMemRegion
->PhysicalStart
> 0);
385 ASSERT (SmmCommMemRegion
->NumberOfPages
> 0);
386 ReservedMemSize
= (UINTN
) SmmCommMemRegion
->NumberOfPages
* EFI_PAGE_SIZE
;
389 // Check enough reserved memory space
391 if (ReservedMemSize
> SMM_BOOT_RECORD_COMM_SIZE
) {
392 SmmBootRecordCommBuffer
= (VOID
*) (UINTN
) SmmCommMemRegion
->PhysicalStart
;
393 SmmCommBufferHeader
= (EFI_SMM_COMMUNICATE_HEADER
*)SmmBootRecordCommBuffer
;
394 SmmCommData
= (SMM_BOOT_RECORD_COMMUNICATE
*)SmmCommBufferHeader
->Data
;
395 ZeroMem((UINT8
*)SmmCommData
, sizeof(SMM_BOOT_RECORD_COMMUNICATE
));
397 CopyGuid (&SmmCommBufferHeader
->HeaderGuid
, &gEfiFirmwarePerformanceGuid
);
398 SmmCommBufferHeader
->MessageLength
= sizeof(SMM_BOOT_RECORD_COMMUNICATE
);
399 CommSize
= SMM_BOOT_RECORD_COMM_SIZE
;
402 // Get the size of boot records.
404 SmmCommData
->Function
= SMM_FPDT_FUNCTION_GET_BOOT_RECORD_SIZE
;
405 SmmCommData
->BootRecordData
= NULL
;
406 Status
= Communication
->Communicate (Communication
, SmmBootRecordCommBuffer
, &CommSize
);
407 ASSERT_EFI_ERROR (Status
);
409 if (!EFI_ERROR (SmmCommData
->ReturnStatus
) && SmmCommData
->BootRecordSize
!= 0) {
411 // Get all boot records
413 SmmCommData
->Function
= SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA_BY_OFFSET
;
414 SmmBootRecordDataSize
= SmmCommData
->BootRecordSize
;
415 SmmBootRecordData
= AllocateZeroPool(SmmBootRecordDataSize
);
416 ASSERT (SmmBootRecordData
!= NULL
);
417 SmmCommData
->BootRecordOffset
= 0;
418 SmmCommData
->BootRecordData
= (VOID
*) ((UINTN
) SmmCommMemRegion
->PhysicalStart
+ SMM_BOOT_RECORD_COMM_SIZE
);
419 SmmCommData
->BootRecordSize
= ReservedMemSize
- SMM_BOOT_RECORD_COMM_SIZE
;
420 while (SmmCommData
->BootRecordOffset
< SmmBootRecordDataSize
) {
421 Status
= Communication
->Communicate (Communication
, SmmBootRecordCommBuffer
, &CommSize
);
422 ASSERT_EFI_ERROR (Status
);
423 ASSERT_EFI_ERROR(SmmCommData
->ReturnStatus
);
424 CopyMem ((UINT8
*) SmmBootRecordData
+ SmmCommData
->BootRecordOffset
, SmmCommData
->BootRecordData
, SmmCommData
->BootRecordSize
);
425 SmmCommData
->BootRecordOffset
= SmmCommData
->BootRecordOffset
+ SmmCommData
->BootRecordSize
;
433 // Prepare memory for Boot Performance table.
434 // Boot Performance table includes BasicBoot record, and one or more appended Boot Records.
436 BootPerformanceDataSize
= sizeof (BOOT_PERFORMANCE_TABLE
) + mBootRecordSize
+ PcdGet32 (PcdExtFpdtBootRecordPadSize
);
437 if (SmmCommData
!= NULL
) {
438 BootPerformanceDataSize
+= SmmBootRecordDataSize
;
442 // Try to allocate the same runtime buffer as last time boot.
444 ZeroMem (&PerformanceVariable
, sizeof (PerformanceVariable
));
445 Size
= sizeof (PerformanceVariable
);
446 Status
= gRT
->GetVariable (
447 EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME
,
448 &gEfiFirmwarePerformanceGuid
,
453 if (!EFI_ERROR (Status
)) {
454 Status
= gBS
->AllocatePages (
456 EfiReservedMemoryType
,
457 EFI_SIZE_TO_PAGES (BootPerformanceDataSize
),
458 &PerformanceVariable
.BootPerformanceTablePointer
460 if (!EFI_ERROR (Status
)) {
461 mAcpiBootPerformanceTable
= (BOOT_PERFORMANCE_TABLE
*) (UINTN
) PerformanceVariable
.BootPerformanceTablePointer
;
465 if (mAcpiBootPerformanceTable
== NULL
) {
467 // Fail to allocate at specified address, continue to allocate at any address.
469 mAcpiBootPerformanceTable
= (BOOT_PERFORMANCE_TABLE
*) FpdtAllocateReservedMemoryBelow4G (BootPerformanceDataSize
);
471 DEBUG ((EFI_D_INFO
, "FPDT: ACPI Boot Performance Table address = 0x%x\n", mAcpiBootPerformanceTable
));
473 if (mAcpiBootPerformanceTable
== NULL
) {
474 if (SmmCommData
!= NULL
&& SmmBootRecordData
!= NULL
) {
475 FreePool (SmmBootRecordData
);
477 if (mAcpiS3PerformanceTable
!= NULL
) {
478 FreePages (mAcpiS3PerformanceTable
, EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE
)));
479 mAcpiS3PerformanceTable
= NULL
;
481 return EFI_OUT_OF_RESOURCES
;
485 // Prepare Boot Performance Table.
487 BootPerformanceData
= (UINT8
*) mAcpiBootPerformanceTable
;
489 // Fill Basic Boot record to Boot Performance Table.
491 CopyMem (mAcpiBootPerformanceTable
, &mBootPerformanceTableTemplate
, sizeof (mBootPerformanceTableTemplate
));
492 BootPerformanceData
= BootPerformanceData
+ mAcpiBootPerformanceTable
->Header
.Length
;
494 // Fill Boot records from boot drivers.
496 CopyMem (BootPerformanceData
, mBootRecordBuffer
, mBootRecordSize
);
497 mAcpiBootPerformanceTable
->Header
.Length
+= mBootRecordSize
;
498 BootPerformanceData
= BootPerformanceData
+ mBootRecordSize
;
499 if (SmmCommData
!= NULL
&& SmmBootRecordData
!= NULL
) {
501 // Fill Boot records from SMM drivers.
503 CopyMem (BootPerformanceData
, SmmBootRecordData
, SmmBootRecordDataSize
);
504 FreePool (SmmBootRecordData
);
505 mAcpiBootPerformanceTable
->Header
.Length
= (UINT32
) (mAcpiBootPerformanceTable
->Header
.Length
+ SmmBootRecordDataSize
);
506 BootPerformanceData
= BootPerformanceData
+ SmmBootRecordDataSize
;
510 // Save Boot Performance Table address to Variable for use in S4 resume.
512 PerformanceVariable
.BootPerformanceTablePointer
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) mAcpiBootPerformanceTable
;
514 // Update Boot Performance Table Pointer in template.
516 mFirmwarePerformanceTableTemplate
.BootPointerRecord
.BootPerformanceTablePointer
= (UINT64
) (UINTN
) mAcpiBootPerformanceTable
;
519 // Save S3 Performance Table address to Variable for use in S4 resume.
521 PerformanceVariable
.S3PerformanceTablePointer
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) mAcpiS3PerformanceTable
;
523 // Update S3 Performance Table Pointer in template.
525 mFirmwarePerformanceTableTemplate
.S3PointerRecord
.S3PerformanceTablePointer
= (UINT64
) (UINTN
) mAcpiS3PerformanceTable
;
527 // Save Runtime Performance Table pointers to Variable.
528 // Don't check SetVariable return status. It doesn't impact FPDT table generation.
531 EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME
,
532 &gEfiFirmwarePerformanceGuid
,
533 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
534 sizeof (PerformanceVariable
),
539 // Publish Firmware Performance Data Table.
541 FpdtAcpiTableChecksum ((UINT8
*) &mFirmwarePerformanceTableTemplate
, mFirmwarePerformanceTableTemplate
.Header
.Length
);
542 Status
= AcpiTableProtocol
->InstallAcpiTable (
544 &mFirmwarePerformanceTableTemplate
,
545 mFirmwarePerformanceTableTemplate
.Header
.Length
,
546 &mFirmwarePerformanceTableTemplateKey
548 if (EFI_ERROR (Status
)) {
549 FreePages (mAcpiBootPerformanceTable
, EFI_SIZE_TO_PAGES (BootPerformanceDataSize
));
550 if (mAcpiS3PerformanceTable
!= NULL
) {
551 FreePages (mAcpiS3PerformanceTable
, EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE
)));
553 mAcpiBootPerformanceTable
= NULL
;
554 mAcpiS3PerformanceTable
= NULL
;
559 // Free temp Boot record, and update Boot Record to point to Basic Boot performance table.
561 if (mBootRecordBuffer
!= NULL
) {
562 FreePool (mBootRecordBuffer
);
564 mBootRecordBuffer
= (UINT8
*) mAcpiBootPerformanceTable
;
565 mBootRecordSize
= mAcpiBootPerformanceTable
->Header
.Length
;
566 mBootRecordMaxSize
= mBootRecordSize
+ PcdGet32 (PcdExtFpdtBootRecordPadSize
);
572 Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
573 install the Firmware Performance Data Table.
575 @param[in] Event The Event that is being processed.
576 @param[in] Context The Event Context.
581 FpdtReadyToBootEventNotify (
586 if (mAcpiBootPerformanceTable
== NULL
) {
588 // ACPI Firmware Performance Data Table not installed yet, install it now.
590 InstallFirmwarePerformanceDataTable ();
595 Report status code listener of FPDT. This is used to collect performance data
596 for OsLoaderLoadImageStart and OsLoaderStartImageStart in FPDT.
598 @param[in] CodeType Indicates the type of status code being reported.
599 @param[in] Value Describes the current status of a hardware or software entity.
600 This included information about the class and subclass that is used to
601 classify the entity as well as an operation.
602 @param[in] Instance The enumeration of a hardware or software entity within
603 the system. Valid instance numbers start with 1.
604 @param[in] CallerId This optional parameter may be used to identify the caller.
605 This parameter allows the status code driver to apply different rules to
607 @param[in] Data This optional parameter may be used to pass additional data.
609 @retval EFI_SUCCESS Status code is what we expected.
610 @retval EFI_UNSUPPORTED Status code not supported.
615 FpdtStatusCodeListenerDxe (
616 IN EFI_STATUS_CODE_TYPE CodeType
,
617 IN EFI_STATUS_CODE_VALUE Value
,
619 IN EFI_GUID
*CallerId
,
620 IN EFI_STATUS_CODE_DATA
*Data
626 // Check whether status code is what we are interested in.
628 if ((CodeType
& EFI_STATUS_CODE_TYPE_MASK
) != EFI_PROGRESS_CODE
) {
629 return EFI_UNSUPPORTED
;
632 if (Value
== (EFI_SOFTWARE_DXE_CORE
| EFI_SW_DXE_CORE_PC_HANDOFF_TO_NEXT
)) {
634 // DxeCore ReportStatusCode Enable so that the capability can be supported.
636 mDxeCoreReportStatusCodeEnable
= TRUE
;
639 Status
= EFI_SUCCESS
;
640 if (Value
== PcdGet32 (PcdProgressCodeOsLoaderLoad
)) {
642 // Progress code for OS Loader LoadImage.
644 if (mAcpiBootPerformanceTable
== NULL
) {
649 // Update OS Loader LoadImage Start for UEFI boot.
651 mAcpiBootPerformanceTable
->BasicBoot
.OsLoaderLoadImageStart
= GetTimeInNanoSecond (GetPerformanceCounter ());
652 } else if (Value
== PcdGet32 (PcdProgressCodeOsLoaderStart
)) {
654 // Progress code for OS Loader StartImage.
656 if (mAcpiBootPerformanceTable
== NULL
) {
661 // Update OS Loader StartImage Start for UEFI boot.
663 mAcpiBootPerformanceTable
->BasicBoot
.OsLoaderStartImageStart
= GetTimeInNanoSecond (GetPerformanceCounter ());
664 } else if (Value
== (EFI_SOFTWARE_EFI_BOOT_SERVICE
| EFI_SW_BS_PC_EXIT_BOOT_SERVICES
)) {
666 // Unregister boot time report status code listener.
668 mRscHandlerProtocol
->Unregister (FpdtStatusCodeListenerDxe
);
671 // Progress code for ExitBootServices.
673 if (mAcpiBootPerformanceTable
== NULL
) {
678 // Update ExitBootServicesExit for UEFI boot.
680 mAcpiBootPerformanceTable
->BasicBoot
.ExitBootServicesExit
= GetTimeInNanoSecond (GetPerformanceCounter ());
681 } else if (Value
== (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_LEGACY_BOOT_EVENT
)) {
682 if (mAcpiBootPerformanceTable
== NULL
) {
684 // Firmware Performance Data Table not installed, do nothing.
690 // Update Firmware Basic Boot Performance Record for legacy boot.
692 mAcpiBootPerformanceTable
->BasicBoot
.OsLoaderStartImageStart
= GetTimeInNanoSecond (GetPerformanceCounter ());
695 // Dump FPDT Boot Performance record.
697 DEBUG ((EFI_D_INFO
, "FPDT: Boot Performance - ResetEnd = %ld\n", mAcpiBootPerformanceTable
->BasicBoot
.ResetEnd
));
698 DEBUG ((EFI_D_INFO
, "FPDT: Boot Performance - OsLoaderLoadImageStart = 0\n"));
699 DEBUG ((EFI_D_INFO
, "FPDT: Boot Performance - OsLoaderStartImageStart = %ld\n", mAcpiBootPerformanceTable
->BasicBoot
.OsLoaderStartImageStart
));
700 DEBUG ((EFI_D_INFO
, "FPDT: Boot Performance - ExitBootServicesEntry = 0\n"));
701 DEBUG ((EFI_D_INFO
, "FPDT: Boot Performance - ExitBootServicesExit = 0\n"));
702 } else if (Data
!= NULL
&& CompareGuid (&Data
->Type
, &gEfiFirmwarePerformanceGuid
)) {
704 // Append one or more Boot records
706 if (mAcpiBootPerformanceTable
== NULL
) {
708 // Append Boot records before FPDT ACPI table is installed.
710 if (mBootRecordSize
+ Data
->Size
> mBootRecordMaxSize
) {
711 mBootRecordBuffer
= ReallocatePool (mBootRecordSize
, mBootRecordSize
+ Data
->Size
+ EXTENSION_RECORD_SIZE
, mBootRecordBuffer
);
712 ASSERT (mBootRecordBuffer
!= NULL
);
713 mBootRecordMaxSize
= mBootRecordSize
+ Data
->Size
+ EXTENSION_RECORD_SIZE
;
716 // Save boot record into the temp memory space.
718 CopyMem (mBootRecordBuffer
+ mBootRecordSize
, Data
+ 1, Data
->Size
);
719 mBootRecordSize
+= Data
->Size
;
722 // Append Boot records after FPDT ACPI table is installed.
724 if (mBootRecordSize
+ Data
->Size
> mBootRecordMaxSize
) {
726 // No enough space to save boot record.
728 Status
= EFI_OUT_OF_RESOURCES
;
731 // Save boot record into BootPerformance table
733 CopyMem (mBootRecordBuffer
+ mBootRecordSize
, Data
+ 1, Data
->Size
);
734 mBootRecordSize
+= Data
->Size
;
735 mAcpiBootPerformanceTable
->Header
.Length
= mBootRecordSize
;
740 // Ignore else progress code.
742 Status
= EFI_UNSUPPORTED
;
750 Notify function for event EVT_SIGNAL_EXIT_BOOT_SERVICES. This is used to record
751 performance data for ExitBootServicesEntry in FPDT.
753 @param[in] Event The Event that is being processed.
754 @param[in] Context The Event Context.
759 FpdtExitBootServicesEventNotify (
764 if (!mDxeCoreReportStatusCodeEnable
) {
766 // When DxeCore Report Status Code is disabled,
767 // Unregister boot time report status code listener at ExitBootService Event.
769 mRscHandlerProtocol
->Unregister (FpdtStatusCodeListenerDxe
);
772 if (mAcpiBootPerformanceTable
== NULL
) {
774 // Firmware Performance Data Table not installed, do nothing.
780 // Update Firmware Basic Boot Performance Record for UEFI boot.
782 mAcpiBootPerformanceTable
->BasicBoot
.ExitBootServicesEntry
= GetTimeInNanoSecond (GetPerformanceCounter ());
785 // Dump FPDT Boot Performance record.
787 DEBUG ((EFI_D_INFO
, "FPDT: Boot Performance - ResetEnd = %ld\n", mAcpiBootPerformanceTable
->BasicBoot
.ResetEnd
));
788 DEBUG ((EFI_D_INFO
, "FPDT: Boot Performance - OsLoaderLoadImageStart = %ld\n", mAcpiBootPerformanceTable
->BasicBoot
.OsLoaderLoadImageStart
));
789 DEBUG ((EFI_D_INFO
, "FPDT: Boot Performance - OsLoaderStartImageStart = %ld\n", mAcpiBootPerformanceTable
->BasicBoot
.OsLoaderStartImageStart
));
790 DEBUG ((EFI_D_INFO
, "FPDT: Boot Performance - ExitBootServicesEntry = %ld\n", mAcpiBootPerformanceTable
->BasicBoot
.ExitBootServicesEntry
));
792 // ExitBootServicesExit will be updated later, so don't dump it here.
797 The module Entry Point of the Firmware Performance Data Table DXE driver.
799 @param[in] ImageHandle The firmware allocated handle for the EFI image.
800 @param[in] SystemTable A pointer to the EFI System Table.
802 @retval EFI_SUCCESS The entry point is executed successfully.
803 @retval Other Some error occurs when executing this entry point.
808 FirmwarePerformanceDxeEntryPoint (
809 IN EFI_HANDLE ImageHandle
,
810 IN EFI_SYSTEM_TABLE
*SystemTable
814 EFI_HOB_GUID_TYPE
*GuidHob
;
815 FIRMWARE_SEC_PERFORMANCE
*Performance
;
820 mFirmwarePerformanceTableTemplate
.Header
.OemId
,
821 PcdGetPtr (PcdAcpiDefaultOemId
),
822 sizeof (mFirmwarePerformanceTableTemplate
.Header
.OemId
)
824 OemTableId
= PcdGet64 (PcdAcpiDefaultOemTableId
);
825 CopyMem (&mFirmwarePerformanceTableTemplate
.Header
.OemTableId
, &OemTableId
, sizeof (UINT64
));
826 mFirmwarePerformanceTableTemplate
.Header
.OemRevision
= PcdGet32 (PcdAcpiDefaultOemRevision
);
827 mFirmwarePerformanceTableTemplate
.Header
.CreatorId
= PcdGet32 (PcdAcpiDefaultCreatorId
);
828 mFirmwarePerformanceTableTemplate
.Header
.CreatorRevision
= PcdGet32 (PcdAcpiDefaultCreatorRevision
);
831 // Get Report Status Code Handler Protocol.
833 Status
= gBS
->LocateProtocol (&gEfiRscHandlerProtocolGuid
, NULL
, (VOID
**) &mRscHandlerProtocol
);
834 ASSERT_EFI_ERROR (Status
);
837 // Register report status code listener for OS Loader load and start.
839 Status
= mRscHandlerProtocol
->Register (FpdtStatusCodeListenerDxe
, TPL_HIGH_LEVEL
);
840 ASSERT_EFI_ERROR (Status
);
843 // Register the notify function to update FPDT on ExitBootServices Event.
845 Status
= gBS
->CreateEventEx (
848 FpdtExitBootServicesEventNotify
,
850 &gEfiEventExitBootServicesGuid
,
851 &mExitBootServicesEvent
853 ASSERT_EFI_ERROR (Status
);
856 // Create ready to boot event to install ACPI FPDT table.
858 Status
= gBS
->CreateEventEx (
861 FpdtReadyToBootEventNotify
,
863 &gEfiEventReadyToBootGuid
,
866 ASSERT_EFI_ERROR (Status
);
869 // Retrieve GUID HOB data that contains the ResetEnd.
871 GuidHob
= GetFirstGuidHob (&gEfiFirmwarePerformanceGuid
);
872 if (GuidHob
!= NULL
) {
873 Performance
= (FIRMWARE_SEC_PERFORMANCE
*) GET_GUID_HOB_DATA (GuidHob
);
874 mBootPerformanceTableTemplate
.BasicBoot
.ResetEnd
= Performance
->ResetEnd
;
877 // SEC Performance Data Hob not found, ResetEnd in ACPI FPDT table will be 0.
879 DEBUG ((DEBUG_WARN
, "FPDT: WARNING: SEC Performance Data Hob not found, ResetEnd will be set to 0!\n"));
882 if (FeaturePcdGet (PcdFirmwarePerformanceDataTableS3Support
)) {
884 // Register callback function upon VariableArchProtocol and LockBoxProtocol
885 // to allocate S3 performance table memory and save the pointer to LockBox.
887 EfiCreateProtocolNotifyEvent (
888 &gEfiVariableArchProtocolGuid
,
890 FpdtAllocateS3PerformanceTableMemory
,
894 EfiCreateProtocolNotifyEvent (
895 &gEfiLockBoxProtocolGuid
,
897 FpdtAllocateS3PerformanceTableMemory
,
903 // Exclude S3 Performance Table Pointer from FPDT table template.
905 mFirmwarePerformanceTableTemplate
.Header
.Length
-= sizeof (EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD
);