]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.c
Separate memory allocation for FPDT S3 performance table and boot performance table...
[mirror_edk2.git] / MdeModulePkg / Universal / Acpi / FirmwarePerformanceDataTableDxe / FirmwarePerformanceDxe.c
index dae12a4869004a63e2f55f5159fc850a5bc1ea56..8996fe2b6ba6028522909d883c1d657bb9196d85 100644 (file)
@@ -21,6 +21,8 @@
 #include <Protocol/ReportStatusCodeHandler.h>\r
 #include <Protocol/AcpiTable.h>\r
 #include <Protocol/SmmCommunication.h>\r
+#include <Protocol/LockBox.h>\r
+#include <Protocol/Variable.h>\r
 \r
 #include <Guid/Acpi.h>\r
 #include <Guid/FirmwarePerformance.h>\r
@@ -36,7 +38,8 @@
 #include <Library/MemoryAllocationLib.h>\r
 #include <Library/PcdLib.h>\r
 #include <Library/HobLib.h>\r
-#include <Library/PcdLib.h>\r
+#include <Library/LockBoxLib.h>\r
+#include <Library/UefiLib.h>\r
 \r
 //\r
 // ACPI table information used to initialize tables.\r
@@ -51,6 +54,7 @@
 \r
 EFI_RSC_HANDLER_PROTOCOL    *mRscHandlerProtocol = NULL;\r
 \r
+BOOLEAN                     mLockBoxReady = FALSE;\r
 EFI_EVENT                   mReadyToBootEvent;\r
 EFI_EVENT                   mLegacyBootEvent;\r
 EFI_EVENT                   mExitBootServicesEvent;\r
@@ -206,6 +210,7 @@ FpdtAllocateReservedMemoryBelow4G (
   EFI_STATUS            Status;\r
   VOID                  *Buffer;\r
 \r
+  Buffer  = NULL;\r
   Pages   = EFI_SIZE_TO_PAGES (Size);\r
   Address = 0xffffffff;\r
 \r
@@ -217,12 +222,106 @@ FpdtAllocateReservedMemoryBelow4G (
                   );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-  Buffer = (VOID *) (UINTN) Address;\r
-  ZeroMem (Buffer, Size);\r
+  if (!EFI_ERROR (Status)) {\r
+    Buffer = (VOID *) (UINTN) Address;\r
+    ZeroMem (Buffer, Size);\r
+  }\r
 \r
   return Buffer;\r
 }\r
 \r
+/**\r
+  Callback function upon VariableArchProtocol and LockBoxProtocol\r
+  to allocate S3 performance table memory and save the pointer to LockBox.\r
+\r
+  @param[in] Event    Event whose notification function is being invoked.\r
+  @param[in] Context  Pointer to the notification function's context.\r
+**/\r
+VOID\r
+EFIAPI\r
+FpdtAllocateS3PerformanceTableMemory (\r
+  IN  EFI_EVENT                             Event,\r
+  IN  VOID                                  *Context\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  VOID                          *Interface;\r
+  FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable;\r
+  UINTN                         Size;\r
+  EFI_PHYSICAL_ADDRESS          S3PerformanceTablePointer;\r
+\r
+  if (mLockBoxReady && (mAcpiS3PerformanceTable != NULL)) {\r
+    //\r
+    // The memory for S3 performance table should have been ready,\r
+    // and the pointer should have been saved to LockBox, just return.\r
+    //\r
+    return;\r
+  }\r
+\r
+  if (!mLockBoxReady) {\r
+    Status = gBS->LocateProtocol (&gEfiLockBoxProtocolGuid, NULL, &Interface);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // LockBox services has been ready.\r
+      //\r
+      mLockBoxReady = TRUE;\r
+    }\r
+  }\r
+\r
+  if (mAcpiS3PerformanceTable == NULL) {\r
+    Status = gBS->LocateProtocol (&gEfiVariableArchProtocolGuid, NULL, &Interface);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Try to allocate the same runtime buffer as last time boot.\r
+      //\r
+      ZeroMem (&PerformanceVariable, sizeof (PerformanceVariable));\r
+      Size = sizeof (PerformanceVariable);\r
+      Status = gRT->GetVariable (\r
+                      EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,\r
+                      &gEfiFirmwarePerformanceGuid,\r
+                      NULL,\r
+                      &Size,\r
+                      &PerformanceVariable\r
+                      );\r
+      if (!EFI_ERROR (Status)) {\r
+        Status = gBS->AllocatePages (\r
+                        AllocateAddress,\r
+                        EfiReservedMemoryType,\r
+                        EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE)),\r
+                        &PerformanceVariable.S3PerformanceTablePointer\r
+                        );\r
+        if (!EFI_ERROR (Status)) {\r
+          mAcpiS3PerformanceTable = (S3_PERFORMANCE_TABLE *) (UINTN) PerformanceVariable.S3PerformanceTablePointer;\r
+        }\r
+      }\r
+      if (mAcpiS3PerformanceTable == NULL) {\r
+        //\r
+        // Fail to allocate at specified address, continue to allocate at any address.\r
+        //\r
+        mAcpiS3PerformanceTable = (S3_PERFORMANCE_TABLE *) FpdtAllocateReservedMemoryBelow4G (sizeof (S3_PERFORMANCE_TABLE));\r
+      }\r
+      DEBUG ((EFI_D_INFO, "FPDT: ACPI S3 Performance Table address = 0x%x\n", mAcpiS3PerformanceTable));\r
+      if (mAcpiS3PerformanceTable != NULL) {\r
+        CopyMem (mAcpiS3PerformanceTable, &mS3PerformanceTableTemplate, sizeof (mS3PerformanceTableTemplate));\r
+      }\r
+    }\r
+  }\r
+\r
+  if (mLockBoxReady && (mAcpiS3PerformanceTable != NULL)) {\r
+    //\r
+    // If LockBox services has been ready and memory for FPDT S3 performance table has been allocated,\r
+    // save the pointer to LockBox for use in S3 resume.\r
+    //\r
+    S3PerformanceTablePointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiS3PerformanceTable;\r
+    Status = SaveLockBox (\r
+               &gFirmwarePerformanceS3PointerGuid,\r
+               &S3PerformanceTablePointer,\r
+               sizeof (EFI_PHYSICAL_ADDRESS)\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+}\r
+\r
 /**\r
   Install ACPI Firmware Performance Data Table (FPDT).\r
 \r
@@ -236,15 +335,13 @@ InstallFirmwarePerformanceDataTable (
 {\r
   EFI_STATUS                    Status;\r
   EFI_ACPI_TABLE_PROTOCOL       *AcpiTableProtocol;\r
-  EFI_PHYSICAL_ADDRESS          Address;\r
   UINTN                         Size;\r
   UINT8                         *SmmBootRecordCommBuffer;\r
   EFI_SMM_COMMUNICATE_HEADER    *SmmCommBufferHeader;\r
   SMM_BOOT_RECORD_COMMUNICATE   *SmmCommData;\r
   UINTN                         CommSize;\r
-  UINTN                         PerformanceRuntimeDataSize;\r
-  UINT8                         *PerformanceRuntimeData; \r
-  UINT8                         *PerformanceRuntimeDataHead; \r
+  UINTN                         BootPerformanceDataSize;\r
+  UINT8                         *BootPerformanceData; \r
   EFI_SMM_COMMUNICATION_PROTOCOL  *Communication;\r
   FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable;\r
 \r
@@ -299,15 +396,12 @@ InstallFirmwarePerformanceDataTable (
   FreePool (SmmBootRecordCommBuffer);\r
 \r
   //\r
-  // Prepare memory for runtime Performance Record. \r
-  // Runtime performance records includes two tables S3 performance table and Boot performance table. \r
-  // S3 Performance table includes S3Resume and S3Suspend records. \r
+  // Prepare memory for Boot Performance table.\r
   // Boot Performance table includes BasicBoot record, and one or more appended Boot Records. \r
   //\r
-  PerformanceRuntimeData = NULL;\r
-  PerformanceRuntimeDataSize = sizeof (S3_PERFORMANCE_TABLE) + sizeof (BOOT_PERFORMANCE_TABLE) + mBootRecordSize + PcdGet32 (PcdExtFpdtBootRecordPadSize);\r
+  BootPerformanceDataSize = sizeof (BOOT_PERFORMANCE_TABLE) + mBootRecordSize + PcdGet32 (PcdExtFpdtBootRecordPadSize);\r
   if (SmmCommData != NULL) {\r
-    PerformanceRuntimeDataSize += SmmCommData->BootRecordSize;\r
+    BootPerformanceDataSize += SmmCommData->BootRecordSize;\r
   }\r
 \r
   //\r
@@ -323,88 +417,60 @@ InstallFirmwarePerformanceDataTable (
                   &PerformanceVariable\r
                   );\r
   if (!EFI_ERROR (Status)) {\r
-    Address = PerformanceVariable.S3PerformanceTablePointer;\r
     Status = gBS->AllocatePages (\r
                     AllocateAddress,\r
                     EfiReservedMemoryType,\r
-                    EFI_SIZE_TO_PAGES (PerformanceRuntimeDataSize),\r
-                    &Address\r
+                    EFI_SIZE_TO_PAGES (BootPerformanceDataSize),\r
+                    &PerformanceVariable.BootPerformanceTablePointer\r
                     );\r
     if (!EFI_ERROR (Status)) {\r
-      PerformanceRuntimeData = (UINT8 *) (UINTN) Address;\r
+      mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) (UINTN) PerformanceVariable.BootPerformanceTablePointer;\r
     }\r
   }\r
 \r
-  if (PerformanceRuntimeData == NULL) {\r
+  if (mAcpiBootPerformanceTable == NULL) {\r
     //\r
     // Fail to allocate at specified address, continue to allocate at any address.\r
     //\r
-    PerformanceRuntimeData = FpdtAllocateReservedMemoryBelow4G (PerformanceRuntimeDataSize);\r
+    mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) FpdtAllocateReservedMemoryBelow4G (BootPerformanceDataSize);\r
   }\r
-  DEBUG ((EFI_D_INFO, "FPDT: Performance Runtime Data address = 0x%x\n", PerformanceRuntimeData));\r
+  DEBUG ((EFI_D_INFO, "FPDT: ACPI Boot Performance Table address = 0x%x\n", mAcpiBootPerformanceTable));\r
 \r
-  if (PerformanceRuntimeData == NULL) {\r
+  if (mAcpiBootPerformanceTable == NULL) {\r
     if (SmmCommData != NULL && SmmCommData->BootRecordData != NULL) {\r
       FreePool (SmmCommData->BootRecordData);\r
     }\r
+    if (mAcpiS3PerformanceTable != NULL) {\r
+      FreePages (mAcpiS3PerformanceTable, EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE)));\r
+    }\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
-  \r
-  PerformanceRuntimeDataHead = PerformanceRuntimeData;\r
-\r
-  if (FeaturePcdGet (PcdFirmwarePerformanceDataTableS3Support)) {\r
-    //\r
-    // Prepare S3 Performance Table.\r
-    //\r
-    mAcpiS3PerformanceTable = (S3_PERFORMANCE_TABLE *) PerformanceRuntimeData;\r
-    CopyMem (mAcpiS3PerformanceTable, &mS3PerformanceTableTemplate, sizeof (mS3PerformanceTableTemplate));\r
-    PerformanceRuntimeData  = PerformanceRuntimeData + mAcpiS3PerformanceTable->Header.Length;\r
-    DEBUG ((EFI_D_INFO, "FPDT: ACPI S3 Performance Table address = 0x%x\n", mAcpiS3PerformanceTable));\r
-    //\r
-    // Save S3 Performance Table address to Variable for use in Firmware Performance PEIM.\r
-    //\r
-    PerformanceVariable.S3PerformanceTablePointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiS3PerformanceTable;\r
-    //\r
-    // Update S3 Performance Table Pointer in template.\r
-    //\r
-    mFirmwarePerformanceTableTemplate.S3PointerRecord.S3PerformanceTablePointer = (UINT64) PerformanceVariable.S3PerformanceTablePointer;\r
-  } else {\r
-    //\r
-    // Exclude S3 Performance Table Pointer from FPDT table template.\r
-    //\r
-    mFirmwarePerformanceTableTemplate.Header.Length -= sizeof (EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD);\r
-  }\r
 \r
   //\r
   // Prepare Boot Performance Table.\r
   //\r
-  mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) PerformanceRuntimeData;\r
+  BootPerformanceData = (UINT8 *) mAcpiBootPerformanceTable;\r
   //\r
   // Fill Basic Boot record to Boot Performance Table.\r
   //\r
-  CopyMem (PerformanceRuntimeData, &mBootPerformanceTableTemplate, sizeof (mBootPerformanceTableTemplate));\r
-  PerformanceRuntimeData = PerformanceRuntimeData + mAcpiBootPerformanceTable->Header.Length;\r
+  CopyMem (mAcpiBootPerformanceTable, &mBootPerformanceTableTemplate, sizeof (mBootPerformanceTableTemplate));\r
+  BootPerformanceData = BootPerformanceData + mAcpiBootPerformanceTable->Header.Length;\r
   //\r
   // Fill Boot records from boot drivers.\r
   //\r
-  CopyMem (PerformanceRuntimeData, mBootRecordBuffer, mBootRecordSize);\r
+  CopyMem (BootPerformanceData, mBootRecordBuffer, mBootRecordSize);\r
   mAcpiBootPerformanceTable->Header.Length += mBootRecordSize;\r
-  PerformanceRuntimeData = PerformanceRuntimeData + mBootRecordSize;\r
+  BootPerformanceData = BootPerformanceData + mBootRecordSize;\r
   if (SmmCommData != NULL && SmmCommData->BootRecordData != NULL) {\r
     //\r
     // Fill Boot records from SMM drivers.\r
     //\r
-    CopyMem (PerformanceRuntimeData, SmmCommData->BootRecordData, SmmCommData->BootRecordSize);\r
+    CopyMem (BootPerformanceData, SmmCommData->BootRecordData, SmmCommData->BootRecordSize);\r
     FreePool (SmmCommData->BootRecordData);\r
     mAcpiBootPerformanceTable->Header.Length = (UINT32) (mAcpiBootPerformanceTable->Header.Length + SmmCommData->BootRecordSize);\r
-    PerformanceRuntimeData = PerformanceRuntimeData + SmmCommData->BootRecordSize;\r
+    BootPerformanceData = BootPerformanceData + SmmCommData->BootRecordSize;\r
   }\r
   //\r
-  // Reserve space for boot records after ReadyToBoot.\r
-  //\r
-  PerformanceRuntimeData = PerformanceRuntimeData + PcdGet32 (PcdExtFpdtBootRecordPadSize);\r
-  DEBUG ((EFI_D_INFO, "FPDT: ACPI Boot Performance Table address = 0x%x\n", mAcpiBootPerformanceTable));\r
-  //\r
   // Save Boot Performance Table address to Variable for use in S4 resume.\r
   //\r
   PerformanceVariable.BootPerformanceTablePointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiBootPerformanceTable;\r
@@ -413,13 +479,21 @@ InstallFirmwarePerformanceDataTable (
   //\r
   mFirmwarePerformanceTableTemplate.BootPointerRecord.BootPerformanceTablePointer = (UINT64) (UINTN) mAcpiBootPerformanceTable;\r
 \r
+  //\r
+  // Save S3 Performance Table address to Variable for use in S4 resume.\r
+  //\r
+  PerformanceVariable.S3PerformanceTablePointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiS3PerformanceTable;\r
+  //\r
+  // Update S3 Performance Table Pointer in template.\r
+  //\r
+  mFirmwarePerformanceTableTemplate.S3PointerRecord.S3PerformanceTablePointer = (UINT64) (UINTN) mAcpiS3PerformanceTable;\r
   //\r
   // Save Runtime Performance Table pointers to Variable.\r
   //\r
   Status = gRT->SetVariable (\r
                   EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,\r
                   &gEfiFirmwarePerformanceGuid,\r
-                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
                   sizeof (PerformanceVariable),\r
                   &PerformanceVariable\r
                   );\r
@@ -436,7 +510,10 @@ InstallFirmwarePerformanceDataTable (
                                 &mFirmwarePerformanceTableTemplateKey\r
                                 );\r
   if (EFI_ERROR (Status)) {\r
-    FreePool (PerformanceRuntimeDataHead);\r
+    FreePages (mAcpiBootPerformanceTable, EFI_SIZE_TO_PAGES (BootPerformanceDataSize));\r
+    if (mAcpiS3PerformanceTable != NULL) {\r
+      FreePages (mAcpiS3PerformanceTable, EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE)));\r
+    }\r
     mAcpiBootPerformanceTable = NULL;\r
     mAcpiS3PerformanceTable = NULL;\r
     return Status;\r
@@ -703,6 +780,7 @@ FirmwarePerformanceDxeEntryPoint (
   EFI_STATUS               Status;\r
   EFI_HOB_GUID_TYPE        *GuidHob;\r
   FIRMWARE_SEC_PERFORMANCE *Performance;\r
+  VOID                     *Registration;\r
 \r
   //\r
   // Get Report Status Code Handler Protocol.\r
@@ -769,5 +847,31 @@ FirmwarePerformanceDxeEntryPoint (
     DEBUG ((EFI_D_ERROR, "FPDT: WARNING: SEC Performance Data Hob not found, ResetEnd will be set to 0!\n"));\r
   }\r
 \r
+  if (FeaturePcdGet (PcdFirmwarePerformanceDataTableS3Support)) {\r
+    //\r
+    // Register callback function upon VariableArchProtocol and LockBoxProtocol\r
+    // to allocate S3 performance table memory and save the pointer to LockBox.\r
+    //\r
+    EfiCreateProtocolNotifyEvent (\r
+      &gEfiVariableArchProtocolGuid,\r
+      TPL_CALLBACK,\r
+      FpdtAllocateS3PerformanceTableMemory,\r
+      NULL,\r
+      &Registration\r
+      );\r
+    EfiCreateProtocolNotifyEvent (\r
+      &gEfiLockBoxProtocolGuid,\r
+      TPL_CALLBACK,\r
+      FpdtAllocateS3PerformanceTableMemory,\r
+      NULL,\r
+      &Registration\r
+      );\r
+  } else {\r
+    //\r
+    // Exclude S3 Performance Table Pointer from FPDT table template.\r
+    //\r
+    mFirmwarePerformanceTableTemplate.Header.Length -= sizeof (EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD);\r
+  }\r
+\r
   return EFI_SUCCESS;\r
 }\r