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