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