+/**\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