Home | History | Annotate | Download | only in FirmwarePerformanceDataTableDxe
      1 /** @file
      2   This module install ACPI Firmware Performance Data Table (FPDT).
      3 
      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.
      7 
      8   Copyright (c) 2011 - 2015, 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
     13 
     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.
     16 
     17 **/
     18 
     19 #include <PiDxe.h>
     20 
     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>
     26 
     27 #include <Guid/Acpi.h>
     28 #include <Guid/FirmwarePerformance.h>
     29 #include <Guid/EventGroup.h>
     30 #include <Guid/EventLegacyBios.h>
     31 
     32 #include <Library/UefiBootServicesTableLib.h>
     33 #include <Library/UefiRuntimeServicesTableLib.h>
     34 #include <Library/BaseLib.h>
     35 #include <Library/DebugLib.h>
     36 #include <Library/TimerLib.h>
     37 #include <Library/BaseMemoryLib.h>
     38 #include <Library/MemoryAllocationLib.h>
     39 #include <Library/PcdLib.h>
     40 #include <Library/HobLib.h>
     41 #include <Library/LockBoxLib.h>
     42 #include <Library/UefiLib.h>
     43 
     44 #define EXTENSION_RECORD_SIZE     0x10000
     45 #define SMM_BOOT_RECORD_COMM_SIZE OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + sizeof(SMM_BOOT_RECORD_COMMUNICATE)
     46 
     47 EFI_RSC_HANDLER_PROTOCOL    *mRscHandlerProtocol = NULL;
     48 
     49 BOOLEAN                     mLockBoxReady = FALSE;
     50 EFI_EVENT                   mReadyToBootEvent;
     51 EFI_EVENT                   mLegacyBootEvent;
     52 EFI_EVENT                   mExitBootServicesEvent;
     53 UINTN                       mFirmwarePerformanceTableTemplateKey  = 0;
     54 UINT32                      mBootRecordSize = 0;
     55 UINT32                      mBootRecordMaxSize = 0;
     56 UINT8                       *mBootRecordBuffer = NULL;
     57 BOOLEAN                     mDxeCoreReportStatusCodeEnable = FALSE;
     58 
     59 BOOT_PERFORMANCE_TABLE                      *mAcpiBootPerformanceTable = NULL;
     60 S3_PERFORMANCE_TABLE                        *mAcpiS3PerformanceTable   = NULL;
     61 
     62 FIRMWARE_PERFORMANCE_TABLE  mFirmwarePerformanceTableTemplate = {
     63   {
     64     EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE,
     65     sizeof (FIRMWARE_PERFORMANCE_TABLE),
     66     EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_REVISION,    // Revision
     67     0x00, // Checksum will be updated at runtime
     68     //
     69     // It is expected that these values will be updated at EntryPoint.
     70     //
     71     {0x00},     // OEM ID is a 6 bytes long field
     72     0x00,       // OEM Table ID(8 bytes long)
     73     0x00,       // OEM Revision
     74     0x00,       // Creator ID
     75     0x00,       // Creator Revision
     76   },
     77   //
     78   // Firmware Basic Boot Performance Table Pointer Record.
     79   //
     80   {
     81     {
     82       EFI_ACPI_5_0_FPDT_RECORD_TYPE_FIRMWARE_BASIC_BOOT_POINTER ,       // Type
     83       sizeof (EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_POINTER_RECORD), // Length
     84       EFI_ACPI_5_0_FPDT_RECORD_REVISION_FIRMWARE_BASIC_BOOT_POINTER     // Revision
     85     },
     86     0,  // Reserved
     87     0   // BootPerformanceTablePointer will be updated at runtime.
     88   },
     89   //
     90   // S3 Performance Table Pointer Record.
     91   //
     92   {
     93     {
     94       EFI_ACPI_5_0_FPDT_RECORD_TYPE_S3_PERFORMANCE_TABLE_POINTER,     // Type
     95       sizeof (EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD), // Length
     96       EFI_ACPI_5_0_FPDT_RECORD_REVISION_S3_PERFORMANCE_TABLE_POINTER  // Revision
     97     },
     98     0,  // Reserved
     99     0   // S3PerformanceTablePointer will be updated at runtime.
    100   }
    101 };
    102 
    103 BOOT_PERFORMANCE_TABLE mBootPerformanceTableTemplate = {
    104   {
    105     EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_SIGNATURE,
    106     sizeof (BOOT_PERFORMANCE_TABLE)
    107   },
    108   {
    109     {
    110       EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT,    // Type
    111       sizeof (EFI_ACPI_5_0_FPDT_FIRMWARE_BASIC_BOOT_RECORD),        // Length
    112       EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_FIRMWARE_BASIC_BOOT // Revision
    113     },
    114     0,  // Reserved
    115     //
    116     // These values will be updated at runtime.
    117     //
    118     0,  // ResetEnd
    119     0,  // OsLoaderLoadImageStart
    120     0,  // OsLoaderStartImageStart
    121     0,  // ExitBootServicesEntry
    122     0   // ExitBootServicesExit
    123   }
    124 };
    125 
    126 S3_PERFORMANCE_TABLE        mS3PerformanceTableTemplate = {
    127   {
    128     EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_SIGNATURE,
    129     sizeof (S3_PERFORMANCE_TABLE)
    130   },
    131   {
    132     {
    133       EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_S3_RESUME,     // Type
    134       sizeof (EFI_ACPI_5_0_FPDT_S3_RESUME_RECORD),         // Length
    135       EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_S3_RESUME  // Revision
    136     },
    137     //
    138     // These values will be updated by Firmware Performance PEIM.
    139     //
    140     0,  // ResumeCount
    141     0,  // FullResume
    142     0   // AverageResume
    143   },
    144   {
    145     {
    146       EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_S3_SUSPEND,    // Type
    147       sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD),        // Length
    148       EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_S3_SUSPEND // Revision
    149     },
    150     //
    151     // These values will be updated bye Firmware Performance SMM driver.
    152     //
    153     0,  // SuspendStart
    154     0   // SuspendEnd
    155   }
    156 };
    157 
    158 /**
    159   This function calculates and updates an UINT8 checksum.
    160 
    161   @param[in]  Buffer          Pointer to buffer to checksum
    162   @param[in]  Size            Number of bytes to checksum
    163 
    164 **/
    165 VOID
    166 FpdtAcpiTableChecksum (
    167   IN UINT8      *Buffer,
    168   IN UINTN      Size
    169   )
    170 {
    171   UINTN ChecksumOffset;
    172 
    173   ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum);
    174 
    175   //
    176   // Set checksum to 0 first.
    177   //
    178   Buffer[ChecksumOffset] = 0;
    179 
    180   //
    181   // Update checksum value.
    182   //
    183   Buffer[ChecksumOffset] = CalculateCheckSum8 (Buffer, Size);
    184 }
    185 
    186 /**
    187   Allocate EfiReservedMemoryType below 4G memory address.
    188 
    189   This function allocates EfiReservedMemoryType below 4G memory address.
    190 
    191   @param[in]  Size   Size of memory to allocate.
    192 
    193   @return Allocated address for output.
    194 
    195 **/
    196 VOID *
    197 FpdtAllocateReservedMemoryBelow4G (
    198   IN UINTN       Size
    199   )
    200 {
    201   UINTN                 Pages;
    202   EFI_PHYSICAL_ADDRESS  Address;
    203   EFI_STATUS            Status;
    204   VOID                  *Buffer;
    205 
    206   Buffer  = NULL;
    207   Pages   = EFI_SIZE_TO_PAGES (Size);
    208   Address = 0xffffffff;
    209 
    210   Status = gBS->AllocatePages (
    211                   AllocateMaxAddress,
    212                   EfiReservedMemoryType,
    213                   Pages,
    214                   &Address
    215                   );
    216   ASSERT_EFI_ERROR (Status);
    217 
    218   if (!EFI_ERROR (Status)) {
    219     Buffer = (VOID *) (UINTN) Address;
    220     ZeroMem (Buffer, Size);
    221   }
    222 
    223   return Buffer;
    224 }
    225 
    226 /**
    227   Callback function upon VariableArchProtocol and LockBoxProtocol
    228   to allocate S3 performance table memory and save the pointer to LockBox.
    229 
    230   @param[in] Event    Event whose notification function is being invoked.
    231   @param[in] Context  Pointer to the notification function's context.
    232 **/
    233 VOID
    234 EFIAPI
    235 FpdtAllocateS3PerformanceTableMemory (
    236   IN  EFI_EVENT                             Event,
    237   IN  VOID                                  *Context
    238   )
    239 {
    240   EFI_STATUS                    Status;
    241   VOID                          *Interface;
    242   FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable;
    243   UINTN                         Size;
    244   EFI_PHYSICAL_ADDRESS          S3PerformanceTablePointer;
    245 
    246   if (mLockBoxReady && (mAcpiS3PerformanceTable != NULL)) {
    247     //
    248     // The memory for S3 performance table should have been ready,
    249     // and the pointer should have been saved to LockBox, just return.
    250     //
    251     return;
    252   }
    253 
    254   if (!mLockBoxReady) {
    255     Status = gBS->LocateProtocol (&gEfiLockBoxProtocolGuid, NULL, &Interface);
    256     if (!EFI_ERROR (Status)) {
    257       //
    258       // LockBox services has been ready.
    259       //
    260       mLockBoxReady = TRUE;
    261     }
    262   }
    263 
    264   if (mAcpiS3PerformanceTable == NULL) {
    265     Status = gBS->LocateProtocol (&gEfiVariableArchProtocolGuid, NULL, &Interface);
    266     if (!EFI_ERROR (Status)) {
    267       //
    268       // Try to allocate the same runtime buffer as last time boot.
    269       //
    270       ZeroMem (&PerformanceVariable, sizeof (PerformanceVariable));
    271       Size = sizeof (PerformanceVariable);
    272       Status = gRT->GetVariable (
    273                       EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,
    274                       &gEfiFirmwarePerformanceGuid,
    275                       NULL,
    276                       &Size,
    277                       &PerformanceVariable
    278                       );
    279       if (!EFI_ERROR (Status)) {
    280         Status = gBS->AllocatePages (
    281                         AllocateAddress,
    282                         EfiReservedMemoryType,
    283                         EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE)),
    284                         &PerformanceVariable.S3PerformanceTablePointer
    285                         );
    286         if (!EFI_ERROR (Status)) {
    287           mAcpiS3PerformanceTable = (S3_PERFORMANCE_TABLE *) (UINTN) PerformanceVariable.S3PerformanceTablePointer;
    288         }
    289       }
    290       if (mAcpiS3PerformanceTable == NULL) {
    291         //
    292         // Fail to allocate at specified address, continue to allocate at any address.
    293         //
    294         mAcpiS3PerformanceTable = (S3_PERFORMANCE_TABLE *) FpdtAllocateReservedMemoryBelow4G (sizeof (S3_PERFORMANCE_TABLE));
    295       }
    296       DEBUG ((EFI_D_INFO, "FPDT: ACPI S3 Performance Table address = 0x%x\n", mAcpiS3PerformanceTable));
    297       if (mAcpiS3PerformanceTable != NULL) {
    298         CopyMem (mAcpiS3PerformanceTable, &mS3PerformanceTableTemplate, sizeof (mS3PerformanceTableTemplate));
    299       }
    300     }
    301   }
    302 
    303   if (mLockBoxReady && (mAcpiS3PerformanceTable != NULL)) {
    304     //
    305     // If LockBox services has been ready and memory for FPDT S3 performance table has been allocated,
    306     // save the pointer to LockBox for use in S3 resume.
    307     //
    308     S3PerformanceTablePointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiS3PerformanceTable;
    309     Status = SaveLockBox (
    310                &gFirmwarePerformanceS3PointerGuid,
    311                &S3PerformanceTablePointer,
    312                sizeof (EFI_PHYSICAL_ADDRESS)
    313                );
    314     ASSERT_EFI_ERROR (Status);
    315   }
    316 }
    317 
    318 /**
    319   Install ACPI Firmware Performance Data Table (FPDT).
    320 
    321   @return Status code.
    322 
    323 **/
    324 EFI_STATUS
    325 InstallFirmwarePerformanceDataTable (
    326   VOID
    327   )
    328 {
    329   EFI_STATUS                    Status;
    330   EFI_ACPI_TABLE_PROTOCOL       *AcpiTableProtocol;
    331   UINTN                         Size;
    332   UINT8                         *SmmBootRecordCommBuffer;
    333   EFI_SMM_COMMUNICATE_HEADER    *SmmCommBufferHeader;
    334   SMM_BOOT_RECORD_COMMUNICATE   *SmmCommData;
    335   UINTN                         CommSize;
    336   UINTN                         BootPerformanceDataSize;
    337   UINT8                         *BootPerformanceData;
    338   EFI_SMM_COMMUNICATION_PROTOCOL  *Communication;
    339   FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable;
    340 
    341   //
    342   // Get AcpiTable Protocol.
    343   //
    344   Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);
    345   if (EFI_ERROR (Status)) {
    346     return Status;
    347   }
    348 
    349   //
    350   // Collect boot records from SMM drivers.
    351   //
    352   SmmBootRecordCommBuffer = NULL;
    353   SmmCommData             = NULL;
    354   Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &Communication);
    355   if (!EFI_ERROR (Status)) {
    356     //
    357     // Initialize communicate buffer
    358     //
    359     SmmBootRecordCommBuffer = AllocateZeroPool (SMM_BOOT_RECORD_COMM_SIZE);
    360     ASSERT (SmmBootRecordCommBuffer != NULL);
    361     SmmCommBufferHeader = (EFI_SMM_COMMUNICATE_HEADER*)SmmBootRecordCommBuffer;
    362     SmmCommData = (SMM_BOOT_RECORD_COMMUNICATE*)SmmCommBufferHeader->Data;
    363     ZeroMem((UINT8*)SmmCommData, sizeof(SMM_BOOT_RECORD_COMMUNICATE));
    364 
    365     CopyGuid (&SmmCommBufferHeader->HeaderGuid, &gEfiFirmwarePerformanceGuid);
    366     SmmCommBufferHeader->MessageLength = sizeof(SMM_BOOT_RECORD_COMMUNICATE);
    367     CommSize = SMM_BOOT_RECORD_COMM_SIZE;
    368 
    369     //
    370     // Get the size of boot records.
    371     //
    372     SmmCommData->Function       = SMM_FPDT_FUNCTION_GET_BOOT_RECORD_SIZE;
    373     SmmCommData->BootRecordData = NULL;
    374     Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize);
    375     ASSERT_EFI_ERROR (Status);
    376 
    377     if (!EFI_ERROR (SmmCommData->ReturnStatus) && SmmCommData->BootRecordSize != 0) {
    378       //
    379       // Get all boot records
    380       //
    381       SmmCommData->Function       = SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA;
    382       SmmCommData->BootRecordData = AllocateZeroPool(SmmCommData->BootRecordSize);
    383       ASSERT (SmmCommData->BootRecordData != NULL);
    384 
    385       Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize);
    386       ASSERT_EFI_ERROR (Status);
    387       ASSERT_EFI_ERROR(SmmCommData->ReturnStatus);
    388     }
    389   }
    390 
    391   //
    392   // Prepare memory for Boot Performance table.
    393   // Boot Performance table includes BasicBoot record, and one or more appended Boot Records.
    394   //
    395   BootPerformanceDataSize = sizeof (BOOT_PERFORMANCE_TABLE) + mBootRecordSize + PcdGet32 (PcdExtFpdtBootRecordPadSize);
    396   if (SmmCommData != NULL) {
    397     BootPerformanceDataSize += SmmCommData->BootRecordSize;
    398   }
    399 
    400   //
    401   // Try to allocate the same runtime buffer as last time boot.
    402   //
    403   ZeroMem (&PerformanceVariable, sizeof (PerformanceVariable));
    404   Size = sizeof (PerformanceVariable);
    405   Status = gRT->GetVariable (
    406                   EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,
    407                   &gEfiFirmwarePerformanceGuid,
    408                   NULL,
    409                   &Size,
    410                   &PerformanceVariable
    411                   );
    412   if (!EFI_ERROR (Status)) {
    413     Status = gBS->AllocatePages (
    414                     AllocateAddress,
    415                     EfiReservedMemoryType,
    416                     EFI_SIZE_TO_PAGES (BootPerformanceDataSize),
    417                     &PerformanceVariable.BootPerformanceTablePointer
    418                     );
    419     if (!EFI_ERROR (Status)) {
    420       mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) (UINTN) PerformanceVariable.BootPerformanceTablePointer;
    421     }
    422   }
    423 
    424   if (mAcpiBootPerformanceTable == NULL) {
    425     //
    426     // Fail to allocate at specified address, continue to allocate at any address.
    427     //
    428     mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) FpdtAllocateReservedMemoryBelow4G (BootPerformanceDataSize);
    429   }
    430   DEBUG ((EFI_D_INFO, "FPDT: ACPI Boot Performance Table address = 0x%x\n", mAcpiBootPerformanceTable));
    431 
    432   if (mAcpiBootPerformanceTable == NULL) {
    433     if (SmmCommData != NULL && SmmCommData->BootRecordData != NULL) {
    434       FreePool (SmmCommData->BootRecordData);
    435     }
    436     if (SmmBootRecordCommBuffer != NULL) {
    437       FreePool (SmmBootRecordCommBuffer);
    438     }
    439     if (mAcpiS3PerformanceTable != NULL) {
    440       FreePages (mAcpiS3PerformanceTable, EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE)));
    441     }
    442     return EFI_OUT_OF_RESOURCES;
    443   }
    444 
    445   //
    446   // Prepare Boot Performance Table.
    447   //
    448   BootPerformanceData = (UINT8 *) mAcpiBootPerformanceTable;
    449   //
    450   // Fill Basic Boot record to Boot Performance Table.
    451   //
    452   CopyMem (mAcpiBootPerformanceTable, &mBootPerformanceTableTemplate, sizeof (mBootPerformanceTableTemplate));
    453   BootPerformanceData = BootPerformanceData + mAcpiBootPerformanceTable->Header.Length;
    454   //
    455   // Fill Boot records from boot drivers.
    456   //
    457   CopyMem (BootPerformanceData, mBootRecordBuffer, mBootRecordSize);
    458   mAcpiBootPerformanceTable->Header.Length += mBootRecordSize;
    459   BootPerformanceData = BootPerformanceData + mBootRecordSize;
    460   if (SmmCommData != NULL && SmmCommData->BootRecordData != NULL) {
    461     //
    462     // Fill Boot records from SMM drivers.
    463     //
    464     CopyMem (BootPerformanceData, SmmCommData->BootRecordData, SmmCommData->BootRecordSize);
    465     FreePool (SmmCommData->BootRecordData);
    466     mAcpiBootPerformanceTable->Header.Length = (UINT32) (mAcpiBootPerformanceTable->Header.Length + SmmCommData->BootRecordSize);
    467     BootPerformanceData = BootPerformanceData + SmmCommData->BootRecordSize;
    468   }
    469   if (SmmBootRecordCommBuffer != NULL) {
    470     FreePool (SmmBootRecordCommBuffer);
    471   }
    472 
    473   //
    474   // Save Boot Performance Table address to Variable for use in S4 resume.
    475   //
    476   PerformanceVariable.BootPerformanceTablePointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiBootPerformanceTable;
    477   //
    478   // Update Boot Performance Table Pointer in template.
    479   //
    480   mFirmwarePerformanceTableTemplate.BootPointerRecord.BootPerformanceTablePointer = (UINT64) (UINTN) mAcpiBootPerformanceTable;
    481 
    482   //
    483   // Save S3 Performance Table address to Variable for use in S4 resume.
    484   //
    485   PerformanceVariable.S3PerformanceTablePointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiS3PerformanceTable;
    486   //
    487   // Update S3 Performance Table Pointer in template.
    488   //
    489   mFirmwarePerformanceTableTemplate.S3PointerRecord.S3PerformanceTablePointer = (UINT64) (UINTN) mAcpiS3PerformanceTable;
    490   //
    491   // Save Runtime Performance Table pointers to Variable.
    492   // Don't check SetVariable return status. It doesn't impact FPDT table generation.
    493   //
    494   gRT->SetVariable (
    495         EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,
    496         &gEfiFirmwarePerformanceGuid,
    497         EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
    498         sizeof (PerformanceVariable),
    499         &PerformanceVariable
    500         );
    501 
    502   //
    503   // Publish Firmware Performance Data Table.
    504   //
    505   FpdtAcpiTableChecksum ((UINT8 *) &mFirmwarePerformanceTableTemplate, mFirmwarePerformanceTableTemplate.Header.Length);
    506   Status = AcpiTableProtocol->InstallAcpiTable (
    507                                 AcpiTableProtocol,
    508                                 &mFirmwarePerformanceTableTemplate,
    509                                 mFirmwarePerformanceTableTemplate.Header.Length,
    510                                 &mFirmwarePerformanceTableTemplateKey
    511                                 );
    512   if (EFI_ERROR (Status)) {
    513     FreePages (mAcpiBootPerformanceTable, EFI_SIZE_TO_PAGES (BootPerformanceDataSize));
    514     if (mAcpiS3PerformanceTable != NULL) {
    515       FreePages (mAcpiS3PerformanceTable, EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE)));
    516     }
    517     mAcpiBootPerformanceTable = NULL;
    518     mAcpiS3PerformanceTable = NULL;
    519     return Status;
    520   }
    521 
    522   //
    523   // Free temp Boot record, and update Boot Record to point to Basic Boot performance table.
    524   //
    525   if (mBootRecordBuffer != NULL) {
    526     FreePool (mBootRecordBuffer);
    527   }
    528   mBootRecordBuffer  = (UINT8 *) mAcpiBootPerformanceTable;
    529   mBootRecordSize    = mAcpiBootPerformanceTable->Header.Length;
    530   mBootRecordMaxSize = mBootRecordSize + PcdGet32 (PcdExtFpdtBootRecordPadSize);
    531 
    532   return EFI_SUCCESS;
    533 }
    534 
    535 /**
    536   Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
    537   install the Firmware Performance Data Table.
    538 
    539   @param[in]  Event   The Event that is being processed.
    540   @param[in]  Context The Event Context.
    541 
    542 **/
    543 VOID
    544 EFIAPI
    545 FpdtReadyToBootEventNotify (
    546   IN EFI_EVENT        Event,
    547   IN VOID             *Context
    548   )
    549 {
    550   if (mAcpiBootPerformanceTable == NULL) {
    551     //
    552     // ACPI Firmware Performance Data Table not installed yet, install it now.
    553     //
    554     InstallFirmwarePerformanceDataTable ();
    555   }
    556 }
    557 
    558 /**
    559   Report status code listener of FPDT. This is used to collect performance data
    560   for OsLoaderLoadImageStart and OsLoaderStartImageStart in FPDT.
    561 
    562   @param[in]  CodeType            Indicates the type of status code being reported.
    563   @param[in]  Value               Describes the current status of a hardware or software entity.
    564                                   This included information about the class and subclass that is used to
    565                                   classify the entity as well as an operation.
    566   @param[in]  Instance            The enumeration of a hardware or software entity within
    567                                   the system. Valid instance numbers start with 1.
    568   @param[in]  CallerId            This optional parameter may be used to identify the caller.
    569                                   This parameter allows the status code driver to apply different rules to
    570                                   different callers.
    571   @param[in]  Data                This optional parameter may be used to pass additional data.
    572 
    573   @retval EFI_SUCCESS             Status code is what we expected.
    574   @retval EFI_UNSUPPORTED         Status code not supported.
    575 
    576 **/
    577 EFI_STATUS
    578 EFIAPI
    579 FpdtStatusCodeListenerDxe (
    580   IN EFI_STATUS_CODE_TYPE     CodeType,
    581   IN EFI_STATUS_CODE_VALUE    Value,
    582   IN UINT32                   Instance,
    583   IN EFI_GUID                 *CallerId,
    584   IN EFI_STATUS_CODE_DATA     *Data
    585   )
    586 {
    587   EFI_STATUS  Status;
    588 
    589   //
    590   // Check whether status code is what we are interested in.
    591   //
    592   if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) != EFI_PROGRESS_CODE) {
    593     return EFI_UNSUPPORTED;
    594   }
    595 
    596   if (Value == (EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_HANDOFF_TO_NEXT)) {
    597     //
    598     // DxeCore ReportStatusCode Enable so that the capability can be supported.
    599     //
    600     mDxeCoreReportStatusCodeEnable = TRUE;
    601   }
    602 
    603   Status = EFI_SUCCESS;
    604   if (Value == PcdGet32 (PcdProgressCodeOsLoaderLoad)) {
    605     //
    606     // Progress code for OS Loader LoadImage.
    607     //
    608     if (mAcpiBootPerformanceTable == NULL) {
    609       return Status;
    610     }
    611 
    612     //
    613     // Update OS Loader LoadImage Start for UEFI boot.
    614     //
    615     mAcpiBootPerformanceTable->BasicBoot.OsLoaderLoadImageStart = GetTimeInNanoSecond (GetPerformanceCounter ());
    616   } else if (Value == PcdGet32 (PcdProgressCodeOsLoaderStart)) {
    617     //
    618     // Progress code for OS Loader StartImage.
    619     //
    620     if (mAcpiBootPerformanceTable == NULL) {
    621       return Status;
    622     }
    623 
    624     //
    625     // Update OS Loader StartImage Start for UEFI boot.
    626     //
    627     mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart = GetTimeInNanoSecond (GetPerformanceCounter ());
    628   } else if (Value == (EFI_SOFTWARE_EFI_BOOT_SERVICE | EFI_SW_BS_PC_EXIT_BOOT_SERVICES)) {
    629     //
    630     // Unregister boot time report status code listener.
    631     //
    632     mRscHandlerProtocol->Unregister (FpdtStatusCodeListenerDxe);
    633 
    634     //
    635     // Progress code for ExitBootServices.
    636     //
    637     if (mAcpiBootPerformanceTable == NULL) {
    638       return Status;
    639     }
    640 
    641     //
    642     // Update ExitBootServicesExit for UEFI boot.
    643     //
    644     mAcpiBootPerformanceTable->BasicBoot.ExitBootServicesExit = GetTimeInNanoSecond (GetPerformanceCounter ());
    645   } else if (Value == (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_LEGACY_BOOT_EVENT)) {
    646     if (mAcpiBootPerformanceTable == NULL) {
    647       //
    648       // Firmware Performance Data Table not installed, do nothing.
    649       //
    650       return Status;
    651     }
    652 
    653     //
    654     // Update Firmware Basic Boot Performance Record for legacy boot.
    655     //
    656     mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart = GetTimeInNanoSecond (GetPerformanceCounter ());
    657 
    658     //
    659     // Dump FPDT Boot Performance record.
    660     //
    661     DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ResetEnd                = %ld\n", mAcpiBootPerformanceTable->BasicBoot.ResetEnd));
    662     DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderLoadImageStart  = 0\n"));
    663     DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderStartImageStart = %ld\n", mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart));
    664     DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ExitBootServicesEntry   = 0\n"));
    665     DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ExitBootServicesExit    = 0\n"));
    666   } else if (Data != NULL && CompareGuid (&Data->Type, &gEfiFirmwarePerformanceGuid)) {
    667     //
    668     // Append one or more Boot records
    669     //
    670     if (mAcpiBootPerformanceTable == NULL) {
    671       //
    672       // Append Boot records before FPDT ACPI table is installed.
    673       //
    674       if (mBootRecordSize + Data->Size > mBootRecordMaxSize) {
    675         mBootRecordBuffer = ReallocatePool (mBootRecordSize, mBootRecordSize + Data->Size + EXTENSION_RECORD_SIZE, mBootRecordBuffer);
    676         ASSERT (mBootRecordBuffer != NULL);
    677         mBootRecordMaxSize = mBootRecordSize + Data->Size + EXTENSION_RECORD_SIZE;
    678       }
    679       //
    680       // Save boot record into the temp memory space.
    681       //
    682       CopyMem (mBootRecordBuffer + mBootRecordSize, Data + 1, Data->Size);
    683       mBootRecordSize += Data->Size;
    684     } else {
    685       //
    686       // Append Boot records after FPDT ACPI table is installed.
    687       //
    688       if (mBootRecordSize + Data->Size > mBootRecordMaxSize) {
    689         //
    690         // No enough space to save boot record.
    691         //
    692         Status = EFI_OUT_OF_RESOURCES;
    693       } else {
    694         //
    695         // Save boot record into BootPerformance table
    696         //
    697         CopyMem (mBootRecordBuffer + mBootRecordSize, Data + 1, Data->Size);
    698         mBootRecordSize += Data->Size;
    699         mAcpiBootPerformanceTable->Header.Length = mBootRecordSize;
    700       }
    701     }
    702   } else {
    703     //
    704     // Ignore else progress code.
    705     //
    706     Status = EFI_UNSUPPORTED;
    707   }
    708 
    709   return Status;
    710 }
    711 
    712 
    713 /**
    714   Notify function for event EVT_SIGNAL_EXIT_BOOT_SERVICES. This is used to record
    715   performance data for ExitBootServicesEntry in FPDT.
    716 
    717   @param[in]  Event   The Event that is being processed.
    718   @param[in]  Context The Event Context.
    719 
    720 **/
    721 VOID
    722 EFIAPI
    723 FpdtExitBootServicesEventNotify (
    724   IN EFI_EVENT        Event,
    725   IN VOID             *Context
    726   )
    727 {
    728   if (!mDxeCoreReportStatusCodeEnable) {
    729     //
    730     // When DxeCore Report Status Code is disabled,
    731     // Unregister boot time report status code listener at ExitBootService Event.
    732     //
    733     mRscHandlerProtocol->Unregister (FpdtStatusCodeListenerDxe);
    734   }
    735 
    736   if (mAcpiBootPerformanceTable == NULL) {
    737     //
    738     // Firmware Performance Data Table not installed, do nothing.
    739     //
    740     return ;
    741   }
    742 
    743   //
    744   // Update Firmware Basic Boot Performance Record for UEFI boot.
    745   //
    746   mAcpiBootPerformanceTable->BasicBoot.ExitBootServicesEntry = GetTimeInNanoSecond (GetPerformanceCounter ());
    747 
    748   //
    749   // Dump FPDT Boot Performance record.
    750   //
    751   DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ResetEnd                = %ld\n", mAcpiBootPerformanceTable->BasicBoot.ResetEnd));
    752   DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderLoadImageStart  = %ld\n", mAcpiBootPerformanceTable->BasicBoot.OsLoaderLoadImageStart));
    753   DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderStartImageStart = %ld\n", mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart));
    754   DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ExitBootServicesEntry   = %ld\n", mAcpiBootPerformanceTable->BasicBoot.ExitBootServicesEntry));
    755   //
    756   // ExitBootServicesExit will be updated later, so don't dump it here.
    757   //
    758 }
    759 
    760 /**
    761   The module Entry Point of the Firmware Performance Data Table DXE driver.
    762 
    763   @param[in]  ImageHandle    The firmware allocated handle for the EFI image.
    764   @param[in]  SystemTable    A pointer to the EFI System Table.
    765 
    766   @retval EFI_SUCCESS    The entry point is executed successfully.
    767   @retval Other          Some error occurs when executing this entry point.
    768 
    769 **/
    770 EFI_STATUS
    771 EFIAPI
    772 FirmwarePerformanceDxeEntryPoint (
    773   IN EFI_HANDLE          ImageHandle,
    774   IN EFI_SYSTEM_TABLE    *SystemTable
    775   )
    776 {
    777   EFI_STATUS               Status;
    778   EFI_HOB_GUID_TYPE        *GuidHob;
    779   FIRMWARE_SEC_PERFORMANCE *Performance;
    780   VOID                     *Registration;
    781   UINT64                   OemTableId;
    782 
    783   CopyMem (
    784     mFirmwarePerformanceTableTemplate.Header.OemId,
    785     PcdGetPtr (PcdAcpiDefaultOemId),
    786     sizeof (mFirmwarePerformanceTableTemplate.Header.OemId)
    787     );
    788   OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
    789   CopyMem (&mFirmwarePerformanceTableTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
    790   mFirmwarePerformanceTableTemplate.Header.OemRevision      = PcdGet32 (PcdAcpiDefaultOemRevision);
    791   mFirmwarePerformanceTableTemplate.Header.CreatorId        = PcdGet32 (PcdAcpiDefaultCreatorId);
    792   mFirmwarePerformanceTableTemplate.Header.CreatorRevision  = PcdGet32 (PcdAcpiDefaultCreatorRevision);
    793 
    794   //
    795   // Get Report Status Code Handler Protocol.
    796   //
    797   Status = gBS->LocateProtocol (&gEfiRscHandlerProtocolGuid, NULL, (VOID **) &mRscHandlerProtocol);
    798   ASSERT_EFI_ERROR (Status);
    799 
    800   //
    801   // Register report status code listener for OS Loader load and start.
    802   //
    803   Status = mRscHandlerProtocol->Register (FpdtStatusCodeListenerDxe, TPL_HIGH_LEVEL);
    804   ASSERT_EFI_ERROR (Status);
    805 
    806   //
    807   // Register the notify function to update FPDT on ExitBootServices Event.
    808   //
    809   Status = gBS->CreateEventEx (
    810                   EVT_NOTIFY_SIGNAL,
    811                   TPL_NOTIFY,
    812                   FpdtExitBootServicesEventNotify,
    813                   NULL,
    814                   &gEfiEventExitBootServicesGuid,
    815                   &mExitBootServicesEvent
    816                   );
    817   ASSERT_EFI_ERROR (Status);
    818 
    819   //
    820   // Create ready to boot event to install ACPI FPDT table.
    821   //
    822   Status = gBS->CreateEventEx (
    823                   EVT_NOTIFY_SIGNAL,
    824                   TPL_NOTIFY,
    825                   FpdtReadyToBootEventNotify,
    826                   NULL,
    827                   &gEfiEventReadyToBootGuid,
    828                   &mReadyToBootEvent
    829                   );
    830   ASSERT_EFI_ERROR (Status);
    831 
    832   //
    833   // Retrieve GUID HOB data that contains the ResetEnd.
    834   //
    835   GuidHob = GetFirstGuidHob (&gEfiFirmwarePerformanceGuid);
    836   if (GuidHob != NULL) {
    837     Performance = (FIRMWARE_SEC_PERFORMANCE *) GET_GUID_HOB_DATA (GuidHob);
    838     mBootPerformanceTableTemplate.BasicBoot.ResetEnd = Performance->ResetEnd;
    839   } else {
    840     //
    841     // SEC Performance Data Hob not found, ResetEnd in ACPI FPDT table will be 0.
    842     //
    843     DEBUG ((EFI_D_ERROR, "FPDT: WARNING: SEC Performance Data Hob not found, ResetEnd will be set to 0!\n"));
    844   }
    845 
    846   if (FeaturePcdGet (PcdFirmwarePerformanceDataTableS3Support)) {
    847     //
    848     // Register callback function upon VariableArchProtocol and LockBoxProtocol
    849     // to allocate S3 performance table memory and save the pointer to LockBox.
    850     //
    851     EfiCreateProtocolNotifyEvent (
    852       &gEfiVariableArchProtocolGuid,
    853       TPL_CALLBACK,
    854       FpdtAllocateS3PerformanceTableMemory,
    855       NULL,
    856       &Registration
    857       );
    858     EfiCreateProtocolNotifyEvent (
    859       &gEfiLockBoxProtocolGuid,
    860       TPL_CALLBACK,
    861       FpdtAllocateS3PerformanceTableMemory,
    862       NULL,
    863       &Registration
    864       );
    865   } else {
    866     //
    867     // Exclude S3 Performance Table Pointer from FPDT table template.
    868     //
    869     mFirmwarePerformanceTableTemplate.Header.Length -= sizeof (EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD);
    870   }
    871 
    872   return EFI_SUCCESS;
    873 }
    874