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