]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Universal / Acpi / FirmwarePerformanceDataTableDxe / FirmwarePerformanceDxe.c
CommitLineData
0284e90c
LG
1/** @file\r
2 This module install ACPI Firmware Performance Data Table (FPDT).\r
3\r
4 This module register report status code listener to collect performance data\r
d1102dba 5 for Firmware Basic Boot Performance Record and other boot performance records,\r
1c0cc375 6 and install FPDT to ACPI table.\r
0284e90c 7\r
9e62c230 8 Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 9 SPDX-License-Identifier: BSD-2-Clause-Patent\r
0284e90c
LG
10\r
11**/\r
12\r
13#include <PiDxe.h>\r
14\r
0284e90c
LG
15#include <Protocol/ReportStatusCodeHandler.h>\r
16#include <Protocol/AcpiTable.h>\r
db91c620
SZ
17#include <Protocol/LockBox.h>\r
18#include <Protocol/Variable.h>\r
0284e90c
LG
19\r
20#include <Guid/Acpi.h>\r
21#include <Guid/FirmwarePerformance.h>\r
0284e90c
LG
22\r
23#include <Library/UefiBootServicesTableLib.h>\r
24#include <Library/UefiRuntimeServicesTableLib.h>\r
25#include <Library/BaseLib.h>\r
26#include <Library/DebugLib.h>\r
65e984cd 27#include <Library/DxeServicesLib.h>\r
0284e90c
LG
28#include <Library/TimerLib.h>\r
29#include <Library/BaseMemoryLib.h>\r
30#include <Library/MemoryAllocationLib.h>\r
31#include <Library/PcdLib.h>\r
32#include <Library/HobLib.h>\r
db91c620
SZ
33#include <Library/LockBoxLib.h>\r
34#include <Library/UefiLib.h>\r
0284e90c 35\r
9e62c230 36#define SMM_BOOT_RECORD_COMM_SIZE (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + sizeof(SMM_BOOT_RECORD_COMMUNICATE))\r
0284e90c
LG
37\r
38EFI_RSC_HANDLER_PROTOCOL *mRscHandlerProtocol = NULL;\r
39\r
db91c620 40BOOLEAN mLockBoxReady = FALSE;\r
0284e90c
LG
41EFI_EVENT mReadyToBootEvent;\r
42EFI_EVENT mLegacyBootEvent;\r
43EFI_EVENT mExitBootServicesEvent;\r
44UINTN mFirmwarePerformanceTableTemplateKey = 0;\r
40a0f8cb 45BOOLEAN mDxeCoreReportStatusCodeEnable = FALSE;\r
0284e90c 46\r
0284e90c 47BOOT_PERFORMANCE_TABLE *mAcpiBootPerformanceTable = NULL;\r
9e62c230 48BOOT_PERFORMANCE_TABLE *mReceivedAcpiBootPerformanceTable = NULL;\r
0284e90c
LG
49S3_PERFORMANCE_TABLE *mAcpiS3PerformanceTable = NULL;\r
50\r
51FIRMWARE_PERFORMANCE_TABLE mFirmwarePerformanceTableTemplate = {\r
52 {\r
53 EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE,\r
54 sizeof (FIRMWARE_PERFORMANCE_TABLE),\r
55 EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_REVISION, // Revision\r
56 0x00, // Checksum will be updated at runtime\r
57 //\r
e84f07b5 58 // It is expected that these values will be updated at EntryPoint.\r
0284e90c 59 //\r
e84f07b5
SZ
60 {0x00}, // OEM ID is a 6 bytes long field\r
61 0x00, // OEM Table ID(8 bytes long)\r
62 0x00, // OEM Revision\r
63 0x00, // Creator ID\r
64 0x00, // Creator Revision\r
0284e90c
LG
65 },\r
66 //\r
67 // Firmware Basic Boot Performance Table Pointer Record.\r
68 //\r
69 {\r
70 {\r
71 EFI_ACPI_5_0_FPDT_RECORD_TYPE_FIRMWARE_BASIC_BOOT_POINTER , // Type\r
72 sizeof (EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_POINTER_RECORD), // Length\r
73 EFI_ACPI_5_0_FPDT_RECORD_REVISION_FIRMWARE_BASIC_BOOT_POINTER // Revision\r
74 },\r
75 0, // Reserved\r
76 0 // BootPerformanceTablePointer will be updated at runtime.\r
77 },\r
78 //\r
79 // S3 Performance Table Pointer Record.\r
80 //\r
81 {\r
82 {\r
83 EFI_ACPI_5_0_FPDT_RECORD_TYPE_S3_PERFORMANCE_TABLE_POINTER, // Type\r
84 sizeof (EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD), // Length\r
85 EFI_ACPI_5_0_FPDT_RECORD_REVISION_S3_PERFORMANCE_TABLE_POINTER // Revision\r
86 },\r
87 0, // Reserved\r
88 0 // S3PerformanceTablePointer will be updated at runtime.\r
89 }\r
90};\r
91\r
92BOOT_PERFORMANCE_TABLE mBootPerformanceTableTemplate = {\r
93 {\r
94 EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_SIGNATURE,\r
95 sizeof (BOOT_PERFORMANCE_TABLE)\r
96 },\r
97 {\r
98 {\r
99 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT, // Type\r
100 sizeof (EFI_ACPI_5_0_FPDT_FIRMWARE_BASIC_BOOT_RECORD), // Length\r
101 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_FIRMWARE_BASIC_BOOT // Revision\r
102 },\r
103 0, // Reserved\r
104 //\r
105 // These values will be updated at runtime.\r
106 //\r
107 0, // ResetEnd\r
108 0, // OsLoaderLoadImageStart\r
109 0, // OsLoaderStartImageStart\r
110 0, // ExitBootServicesEntry\r
111 0 // ExitBootServicesExit\r
112 }\r
113};\r
114\r
115S3_PERFORMANCE_TABLE mS3PerformanceTableTemplate = {\r
116 {\r
117 EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_SIGNATURE,\r
118 sizeof (S3_PERFORMANCE_TABLE)\r
119 },\r
120 {\r
121 {\r
122 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_S3_RESUME, // Type\r
123 sizeof (EFI_ACPI_5_0_FPDT_S3_RESUME_RECORD), // Length\r
124 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_S3_RESUME // Revision\r
125 },\r
126 //\r
127 // These values will be updated by Firmware Performance PEIM.\r
128 //\r
129 0, // ResumeCount\r
130 0, // FullResume\r
131 0 // AverageResume\r
132 },\r
133 {\r
134 {\r
135 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_S3_SUSPEND, // Type\r
136 sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD), // Length\r
137 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_S3_SUSPEND // Revision\r
138 },\r
139 //\r
140 // These values will be updated bye Firmware Performance SMM driver.\r
141 //\r
142 0, // SuspendStart\r
143 0 // SuspendEnd\r
144 }\r
145};\r
146\r
147/**\r
148 This function calculates and updates an UINT8 checksum.\r
149\r
150 @param[in] Buffer Pointer to buffer to checksum\r
151 @param[in] Size Number of bytes to checksum\r
152\r
153**/\r
154VOID\r
155FpdtAcpiTableChecksum (\r
156 IN UINT8 *Buffer,\r
157 IN UINTN Size\r
158 )\r
159{\r
160 UINTN ChecksumOffset;\r
161\r
162 ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum);\r
163\r
164 //\r
165 // Set checksum to 0 first.\r
166 //\r
167 Buffer[ChecksumOffset] = 0;\r
168\r
169 //\r
170 // Update checksum value.\r
171 //\r
172 Buffer[ChecksumOffset] = CalculateCheckSum8 (Buffer, Size);\r
173}\r
174\r
db91c620
SZ
175/**\r
176 Callback function upon VariableArchProtocol and LockBoxProtocol\r
177 to allocate S3 performance table memory and save the pointer to LockBox.\r
178\r
179 @param[in] Event Event whose notification function is being invoked.\r
180 @param[in] Context Pointer to the notification function's context.\r
181**/\r
182VOID\r
183EFIAPI\r
184FpdtAllocateS3PerformanceTableMemory (\r
185 IN EFI_EVENT Event,\r
186 IN VOID *Context\r
187 )\r
188{\r
189 EFI_STATUS Status;\r
190 VOID *Interface;\r
191 FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable;\r
192 UINTN Size;\r
193 EFI_PHYSICAL_ADDRESS S3PerformanceTablePointer;\r
194\r
195 if (mLockBoxReady && (mAcpiS3PerformanceTable != NULL)) {\r
196 //\r
197 // The memory for S3 performance table should have been ready,\r
198 // and the pointer should have been saved to LockBox, just return.\r
199 //\r
200 return;\r
201 }\r
202\r
203 if (!mLockBoxReady) {\r
204 Status = gBS->LocateProtocol (&gEfiLockBoxProtocolGuid, NULL, &Interface);\r
205 if (!EFI_ERROR (Status)) {\r
206 //\r
207 // LockBox services has been ready.\r
208 //\r
209 mLockBoxReady = TRUE;\r
210 }\r
211 }\r
212\r
213 if (mAcpiS3PerformanceTable == NULL) {\r
214 Status = gBS->LocateProtocol (&gEfiVariableArchProtocolGuid, NULL, &Interface);\r
215 if (!EFI_ERROR (Status)) {\r
216 //\r
217 // Try to allocate the same runtime buffer as last time boot.\r
218 //\r
219 ZeroMem (&PerformanceVariable, sizeof (PerformanceVariable));\r
220 Size = sizeof (PerformanceVariable);\r
221 Status = gRT->GetVariable (\r
222 EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,\r
223 &gEfiFirmwarePerformanceGuid,\r
224 NULL,\r
225 &Size,\r
226 &PerformanceVariable\r
227 );\r
228 if (!EFI_ERROR (Status)) {\r
229 Status = gBS->AllocatePages (\r
230 AllocateAddress,\r
231 EfiReservedMemoryType,\r
232 EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE)),\r
233 &PerformanceVariable.S3PerformanceTablePointer\r
234 );\r
235 if (!EFI_ERROR (Status)) {\r
236 mAcpiS3PerformanceTable = (S3_PERFORMANCE_TABLE *) (UINTN) PerformanceVariable.S3PerformanceTablePointer;\r
237 }\r
238 }\r
239 if (mAcpiS3PerformanceTable == NULL) {\r
240 //\r
241 // Fail to allocate at specified address, continue to allocate at any address.\r
242 //\r
65e984cd
AB
243 mAcpiS3PerformanceTable = (S3_PERFORMANCE_TABLE *) AllocatePeiAccessiblePages (\r
244 EfiReservedMemoryType,\r
245 EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE))\r
246 );\r
db91c620
SZ
247 }\r
248 DEBUG ((EFI_D_INFO, "FPDT: ACPI S3 Performance Table address = 0x%x\n", mAcpiS3PerformanceTable));\r
249 if (mAcpiS3PerformanceTable != NULL) {\r
250 CopyMem (mAcpiS3PerformanceTable, &mS3PerformanceTableTemplate, sizeof (mS3PerformanceTableTemplate));\r
251 }\r
252 }\r
253 }\r
254\r
255 if (mLockBoxReady && (mAcpiS3PerformanceTable != NULL)) {\r
256 //\r
257 // If LockBox services has been ready and memory for FPDT S3 performance table has been allocated,\r
258 // save the pointer to LockBox for use in S3 resume.\r
259 //\r
260 S3PerformanceTablePointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiS3PerformanceTable;\r
261 Status = SaveLockBox (\r
262 &gFirmwarePerformanceS3PointerGuid,\r
263 &S3PerformanceTablePointer,\r
264 sizeof (EFI_PHYSICAL_ADDRESS)\r
265 );\r
266 ASSERT_EFI_ERROR (Status);\r
267 }\r
268}\r
269\r
0284e90c
LG
270/**\r
271 Install ACPI Firmware Performance Data Table (FPDT).\r
272\r
273 @return Status code.\r
274\r
275**/\r
276EFI_STATUS\r
277InstallFirmwarePerformanceDataTable (\r
278 VOID\r
279 )\r
280{\r
281 EFI_STATUS Status;\r
282 EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;\r
db91c620 283 UINTN BootPerformanceDataSize;\r
1c0cc375 284 FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable;\r
9e62c230 285 UINTN Size;\r
0284e90c
LG
286\r
287 //\r
288 // Get AcpiTable Protocol.\r
289 //\r
290 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);\r
291 if (EFI_ERROR (Status)) {\r
292 return Status;\r
293 }\r
294\r
9e62c230
DB
295 if (mReceivedAcpiBootPerformanceTable != NULL) {\r
296 mAcpiBootPerformanceTable = mReceivedAcpiBootPerformanceTable;\r
297 mAcpiBootPerformanceTable->BasicBoot.ResetEnd = mBootPerformanceTableTemplate.BasicBoot.ResetEnd;\r
298 } else {\r
1c0cc375 299 //\r
9e62c230
DB
300 // Try to allocate the same runtime buffer as last time boot.\r
301 //\r
302 BootPerformanceDataSize = sizeof (BOOT_PERFORMANCE_TABLE);\r
303 ZeroMem (&PerformanceVariable, sizeof (PerformanceVariable));\r
304 Size = sizeof (PerformanceVariable);\r
305 Status = gRT->GetVariable (\r
306 EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,\r
307 &gEfiFirmwarePerformanceGuid,\r
308 NULL,\r
309 &Size,\r
310 &PerformanceVariable\r
311 );\r
d158ba67 312 if (!EFI_ERROR (Status)) {\r
9e62c230
DB
313 Status = gBS->AllocatePages (\r
314 AllocateAddress,\r
315 EfiReservedMemoryType,\r
316 EFI_SIZE_TO_PAGES (BootPerformanceDataSize),\r
317 &PerformanceVariable.BootPerformanceTablePointer\r
318 );\r
319 if (!EFI_ERROR (Status)) {\r
320 mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) (UINTN) PerformanceVariable.BootPerformanceTablePointer;\r
d158ba67 321 }\r
9e62c230
DB
322 }\r
323 if (mAcpiBootPerformanceTable == NULL) {\r
1c0cc375 324 //\r
9e62c230 325 // Fail to allocate at specified address, continue to allocate at any address.\r
1c0cc375 326 //\r
65e984cd
AB
327 mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) AllocatePeiAccessiblePages (\r
328 EfiReservedMemoryType,\r
329 EFI_SIZE_TO_PAGES (BootPerformanceDataSize)\r
330 );\r
1c0cc375 331 }\r
9e62c230
DB
332 DEBUG ((DEBUG_INFO, "FPDT: ACPI Boot Performance Table address = 0x%x\n", mAcpiBootPerformanceTable));\r
333 if (mAcpiBootPerformanceTable == NULL) {\r
334 return EFI_OUT_OF_RESOURCES;\r
db91c620 335 }\r
1c0cc375 336 //\r
9e62c230 337 // Fill Basic Boot record to Boot Performance Table.\r
1c0cc375 338 //\r
9e62c230 339 CopyMem (mAcpiBootPerformanceTable, &mBootPerformanceTableTemplate, sizeof (mBootPerformanceTableTemplate));\r
9cf37b40 340 }\r
9e62c230 341 BootPerformanceDataSize = mAcpiBootPerformanceTable->Header.Length;\r
9cf37b40 342\r
1c0cc375 343 //\r
1c0cc375
LG
344 // Save Boot Performance Table address to Variable for use in S4 resume.\r
345 //\r
346 PerformanceVariable.BootPerformanceTablePointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiBootPerformanceTable;\r
347 //\r
348 // Update Boot Performance Table Pointer in template.\r
349 //\r
350 mFirmwarePerformanceTableTemplate.BootPointerRecord.BootPerformanceTablePointer = (UINT64) (UINTN) mAcpiBootPerformanceTable;\r
351\r
db91c620
SZ
352 //\r
353 // Save S3 Performance Table address to Variable for use in S4 resume.\r
354 //\r
355 PerformanceVariable.S3PerformanceTablePointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiS3PerformanceTable;\r
356 //\r
357 // Update S3 Performance Table Pointer in template.\r
358 //\r
359 mFirmwarePerformanceTableTemplate.S3PointerRecord.S3PerformanceTablePointer = (UINT64) (UINTN) mAcpiS3PerformanceTable;\r
0284e90c
LG
360 //\r
361 // Save Runtime Performance Table pointers to Variable.\r
9e62c230 362 // Don't check SetVariable return status. It doesn't impact FPDT table generation.\r
fd704cbd
LG
363 //\r
364 gRT->SetVariable (\r
365 EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,\r
366 &gEfiFirmwarePerformanceGuid,\r
367 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
368 sizeof (PerformanceVariable),\r
369 &PerformanceVariable\r
370 );\r
0284e90c
LG
371\r
372 //\r
373 // Publish Firmware Performance Data Table.\r
374 //\r
375 FpdtAcpiTableChecksum ((UINT8 *) &mFirmwarePerformanceTableTemplate, mFirmwarePerformanceTableTemplate.Header.Length);\r
376 Status = AcpiTableProtocol->InstallAcpiTable (\r
377 AcpiTableProtocol,\r
378 &mFirmwarePerformanceTableTemplate,\r
379 mFirmwarePerformanceTableTemplate.Header.Length,\r
380 &mFirmwarePerformanceTableTemplateKey\r
381 );\r
382 if (EFI_ERROR (Status)) {\r
9e62c230
DB
383 if (mAcpiBootPerformanceTable != NULL) {\r
384 FreePages (mAcpiBootPerformanceTable, EFI_SIZE_TO_PAGES (BootPerformanceDataSize));\r
385 }\r
db91c620
SZ
386 if (mAcpiS3PerformanceTable != NULL) {\r
387 FreePages (mAcpiS3PerformanceTable, EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE)));\r
388 }\r
0284e90c
LG
389 mAcpiBootPerformanceTable = NULL;\r
390 mAcpiS3PerformanceTable = NULL;\r
391 return Status;\r
392 }\r
0284e90c
LG
393 return EFI_SUCCESS;\r
394}\r
395\r
0284e90c
LG
396/**\r
397 Report status code listener of FPDT. This is used to collect performance data\r
398 for OsLoaderLoadImageStart and OsLoaderStartImageStart in FPDT.\r
399\r
400 @param[in] CodeType Indicates the type of status code being reported.\r
401 @param[in] Value Describes the current status of a hardware or software entity.\r
402 This included information about the class and subclass that is used to\r
403 classify the entity as well as an operation.\r
404 @param[in] Instance The enumeration of a hardware or software entity within\r
405 the system. Valid instance numbers start with 1.\r
406 @param[in] CallerId This optional parameter may be used to identify the caller.\r
407 This parameter allows the status code driver to apply different rules to\r
408 different callers.\r
409 @param[in] Data This optional parameter may be used to pass additional data.\r
410\r
411 @retval EFI_SUCCESS Status code is what we expected.\r
412 @retval EFI_UNSUPPORTED Status code not supported.\r
413\r
414**/\r
415EFI_STATUS\r
416EFIAPI\r
417FpdtStatusCodeListenerDxe (\r
418 IN EFI_STATUS_CODE_TYPE CodeType,\r
419 IN EFI_STATUS_CODE_VALUE Value,\r
420 IN UINT32 Instance,\r
421 IN EFI_GUID *CallerId,\r
422 IN EFI_STATUS_CODE_DATA *Data\r
423 )\r
424{\r
425 EFI_STATUS Status;\r
426\r
427 //\r
428 // Check whether status code is what we are interested in.\r
429 //\r
430 if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) != EFI_PROGRESS_CODE) {\r
431 return EFI_UNSUPPORTED;\r
432 }\r
d1102dba 433\r
40a0f8cb
LG
434 if (Value == (EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_HANDOFF_TO_NEXT)) {\r
435 //\r
436 // DxeCore ReportStatusCode Enable so that the capability can be supported.\r
437 //\r
438 mDxeCoreReportStatusCodeEnable = TRUE;\r
439 }\r
0284e90c
LG
440\r
441 Status = EFI_SUCCESS;\r
442 if (Value == PcdGet32 (PcdProgressCodeOsLoaderLoad)) {\r
443 //\r
444 // Progress code for OS Loader LoadImage.\r
445 //\r
446 if (mAcpiBootPerformanceTable == NULL) {\r
447 return Status;\r
448 }\r
449\r
450 //\r
451 // Update OS Loader LoadImage Start for UEFI boot.\r
452 //\r
453 mAcpiBootPerformanceTable->BasicBoot.OsLoaderLoadImageStart = GetTimeInNanoSecond (GetPerformanceCounter ());\r
454 } else if (Value == PcdGet32 (PcdProgressCodeOsLoaderStart)) {\r
455 //\r
456 // Progress code for OS Loader StartImage.\r
457 //\r
458 if (mAcpiBootPerformanceTable == NULL) {\r
459 return Status;\r
460 }\r
461\r
462 //\r
463 // Update OS Loader StartImage Start for UEFI boot.\r
464 //\r
465 mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart = GetTimeInNanoSecond (GetPerformanceCounter ());\r
466 } else if (Value == (EFI_SOFTWARE_EFI_BOOT_SERVICE | EFI_SW_BS_PC_EXIT_BOOT_SERVICES)) {\r
40a0f8cb
LG
467 //\r
468 // Unregister boot time report status code listener.\r
469 //\r
470 mRscHandlerProtocol->Unregister (FpdtStatusCodeListenerDxe);\r
471\r
0284e90c
LG
472 //\r
473 // Progress code for ExitBootServices.\r
474 //\r
475 if (mAcpiBootPerformanceTable == NULL) {\r
476 return Status;\r
477 }\r
478\r
479 //\r
480 // Update ExitBootServicesExit for UEFI boot.\r
481 //\r
482 mAcpiBootPerformanceTable->BasicBoot.ExitBootServicesExit = GetTimeInNanoSecond (GetPerformanceCounter ());\r
522dfbf3
LG
483 } else if (Value == (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_LEGACY_BOOT_EVENT)) {\r
484 if (mAcpiBootPerformanceTable == NULL) {\r
485 //\r
486 // Firmware Performance Data Table not installed, do nothing.\r
487 //\r
488 return Status;\r
489 }\r
490\r
491 //\r
492 // Update Firmware Basic Boot Performance Record for legacy boot.\r
493 //\r
494 mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart = GetTimeInNanoSecond (GetPerformanceCounter ());\r
495\r
496 //\r
497 // Dump FPDT Boot Performance record.\r
498 //\r
499 DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ResetEnd = %ld\n", mAcpiBootPerformanceTable->BasicBoot.ResetEnd));\r
500 DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderLoadImageStart = 0\n"));\r
501 DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderStartImageStart = %ld\n", mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart));\r
502 DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ExitBootServicesEntry = 0\n"));\r
503 DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ExitBootServicesExit = 0\n"));\r
9e62c230 504 } else if (Value == (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT)) {\r
1c0cc375
LG
505 if (mAcpiBootPerformanceTable == NULL) {\r
506 //\r
9e62c230 507 // ACPI Firmware Performance Data Table not installed yet, install it now.\r
1c0cc375 508 //\r
9e62c230 509 InstallFirmwarePerformanceDataTable ();\r
1c0cc375 510 }\r
9e62c230
DB
511 } else if (Data != NULL && CompareGuid (&Data->Type, &gEdkiiFpdtExtendedFirmwarePerformanceGuid)) {\r
512 //\r
513 // Get the Boot performance table and then install it to ACPI table.\r
514 //\r
515 CopyMem (&mReceivedAcpiBootPerformanceTable, Data + 1, Data->Size);\r
d4ee449d
DB
516 } else if (Data != NULL && CompareGuid (&Data->Type, &gEfiFirmwarePerformanceGuid)) {\r
517 DEBUG ((DEBUG_ERROR, "FpdtStatusCodeListenerDxe: Performance data reported through gEfiFirmwarePerformanceGuid will not be collected by FirmwarePerformanceDataTableDxe\n"));\r
518 Status = EFI_UNSUPPORTED;\r
0284e90c
LG
519 } else {\r
520 //\r
521 // Ignore else progress code.\r
522 //\r
523 Status = EFI_UNSUPPORTED;\r
524 }\r
525\r
526 return Status;\r
527}\r
528\r
40a0f8cb
LG
529\r
530/**\r
531 Notify function for event EVT_SIGNAL_EXIT_BOOT_SERVICES. This is used to record\r
532 performance data for ExitBootServicesEntry in FPDT.\r
533\r
534 @param[in] Event The Event that is being processed.\r
535 @param[in] Context The Event Context.\r
536\r
537**/\r
538VOID\r
539EFIAPI\r
540FpdtExitBootServicesEventNotify (\r
541 IN EFI_EVENT Event,\r
542 IN VOID *Context\r
543 )\r
544{\r
0b24f2cf 545 if (!mDxeCoreReportStatusCodeEnable) {\r
40a0f8cb 546 //\r
d1102dba 547 // When DxeCore Report Status Code is disabled,\r
40a0f8cb
LG
548 // Unregister boot time report status code listener at ExitBootService Event.\r
549 //\r
550 mRscHandlerProtocol->Unregister (FpdtStatusCodeListenerDxe);\r
551 }\r
552\r
553 if (mAcpiBootPerformanceTable == NULL) {\r
554 //\r
555 // Firmware Performance Data Table not installed, do nothing.\r
556 //\r
557 return ;\r
558 }\r
559\r
560 //\r
561 // Update Firmware Basic Boot Performance Record for UEFI boot.\r
562 //\r
563 mAcpiBootPerformanceTable->BasicBoot.ExitBootServicesEntry = GetTimeInNanoSecond (GetPerformanceCounter ());\r
564\r
565 //\r
566 // Dump FPDT Boot Performance record.\r
567 //\r
568 DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ResetEnd = %ld\n", mAcpiBootPerformanceTable->BasicBoot.ResetEnd));\r
569 DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderLoadImageStart = %ld\n", mAcpiBootPerformanceTable->BasicBoot.OsLoaderLoadImageStart));\r
570 DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderStartImageStart = %ld\n", mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart));\r
571 DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ExitBootServicesEntry = %ld\n", mAcpiBootPerformanceTable->BasicBoot.ExitBootServicesEntry));\r
572 //\r
573 // ExitBootServicesExit will be updated later, so don't dump it here.\r
574 //\r
575}\r
576\r
0284e90c
LG
577/**\r
578 The module Entry Point of the Firmware Performance Data Table DXE driver.\r
579\r
580 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
581 @param[in] SystemTable A pointer to the EFI System Table.\r
582\r
583 @retval EFI_SUCCESS The entry point is executed successfully.\r
584 @retval Other Some error occurs when executing this entry point.\r
585\r
586**/\r
587EFI_STATUS\r
588EFIAPI\r
589FirmwarePerformanceDxeEntryPoint (\r
590 IN EFI_HANDLE ImageHandle,\r
591 IN EFI_SYSTEM_TABLE *SystemTable\r
592 )\r
593{\r
594 EFI_STATUS Status;\r
595 EFI_HOB_GUID_TYPE *GuidHob;\r
596 FIRMWARE_SEC_PERFORMANCE *Performance;\r
db91c620 597 VOID *Registration;\r
e84f07b5
SZ
598 UINT64 OemTableId;\r
599\r
600 CopyMem (\r
601 mFirmwarePerformanceTableTemplate.Header.OemId,\r
602 PcdGetPtr (PcdAcpiDefaultOemId),\r
603 sizeof (mFirmwarePerformanceTableTemplate.Header.OemId)\r
604 );\r
605 OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);\r
606 CopyMem (&mFirmwarePerformanceTableTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));\r
607 mFirmwarePerformanceTableTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);\r
608 mFirmwarePerformanceTableTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);\r
609 mFirmwarePerformanceTableTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);\r
0284e90c
LG
610\r
611 //\r
612 // Get Report Status Code Handler Protocol.\r
613 //\r
614 Status = gBS->LocateProtocol (&gEfiRscHandlerProtocolGuid, NULL, (VOID **) &mRscHandlerProtocol);\r
615 ASSERT_EFI_ERROR (Status);\r
616\r
617 //\r
618 // Register report status code listener for OS Loader load and start.\r
619 //\r
620 Status = mRscHandlerProtocol->Register (FpdtStatusCodeListenerDxe, TPL_HIGH_LEVEL);\r
621 ASSERT_EFI_ERROR (Status);\r
622\r
623 //\r
624 // Register the notify function to update FPDT on ExitBootServices Event.\r
625 //\r
626 Status = gBS->CreateEventEx (\r
627 EVT_NOTIFY_SIGNAL,\r
628 TPL_NOTIFY,\r
629 FpdtExitBootServicesEventNotify,\r
630 NULL,\r
631 &gEfiEventExitBootServicesGuid,\r
632 &mExitBootServicesEvent\r
633 );\r
634 ASSERT_EFI_ERROR (Status);\r
635\r
0284e90c
LG
636 //\r
637 // Retrieve GUID HOB data that contains the ResetEnd.\r
638 //\r
639 GuidHob = GetFirstGuidHob (&gEfiFirmwarePerformanceGuid);\r
640 if (GuidHob != NULL) {\r
641 Performance = (FIRMWARE_SEC_PERFORMANCE *) GET_GUID_HOB_DATA (GuidHob);\r
642 mBootPerformanceTableTemplate.BasicBoot.ResetEnd = Performance->ResetEnd;\r
643 } else {\r
644 //\r
645 // SEC Performance Data Hob not found, ResetEnd in ACPI FPDT table will be 0.\r
646 //\r
d3d562b9 647 DEBUG ((DEBUG_WARN, "FPDT: WARNING: SEC Performance Data Hob not found, ResetEnd will be set to 0!\n"));\r
0284e90c
LG
648 }\r
649\r
db91c620
SZ
650 if (FeaturePcdGet (PcdFirmwarePerformanceDataTableS3Support)) {\r
651 //\r
652 // Register callback function upon VariableArchProtocol and LockBoxProtocol\r
653 // to allocate S3 performance table memory and save the pointer to LockBox.\r
654 //\r
655 EfiCreateProtocolNotifyEvent (\r
656 &gEfiVariableArchProtocolGuid,\r
657 TPL_CALLBACK,\r
658 FpdtAllocateS3PerformanceTableMemory,\r
659 NULL,\r
660 &Registration\r
661 );\r
662 EfiCreateProtocolNotifyEvent (\r
663 &gEfiLockBoxProtocolGuid,\r
664 TPL_CALLBACK,\r
665 FpdtAllocateS3PerformanceTableMemory,\r
666 NULL,\r
667 &Registration\r
668 );\r
669 } else {\r
670 //\r
671 // Exclude S3 Performance Table Pointer from FPDT table template.\r
672 //\r
673 mFirmwarePerformanceTableTemplate.Header.Length -= sizeof (EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD);\r
674 }\r
675\r
0284e90c
LG
676 return EFI_SUCCESS;\r
677}\r