]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.c
MdePkg/IndustryStandard: add definitions for ACPI 6.0 IORT
[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
d158ba67 8 Copyright (c) 2011 - 2016, 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
db91c620
SZ
24#include <Protocol/LockBox.h>\r
25#include <Protocol/Variable.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
d158ba67 31#include <Guid/PiSmmCommunicationRegionTable.h>\r
0284e90c
LG
32\r
33#include <Library/UefiBootServicesTableLib.h>\r
34#include <Library/UefiRuntimeServicesTableLib.h>\r
35#include <Library/BaseLib.h>\r
36#include <Library/DebugLib.h>\r
37#include <Library/TimerLib.h>\r
38#include <Library/BaseMemoryLib.h>\r
39#include <Library/MemoryAllocationLib.h>\r
40#include <Library/PcdLib.h>\r
41#include <Library/HobLib.h>\r
db91c620
SZ
42#include <Library/LockBoxLib.h>\r
43#include <Library/UefiLib.h>\r
0284e90c 44\r
1c0cc375
LG
45#define EXTENSION_RECORD_SIZE 0x10000\r
46#define SMM_BOOT_RECORD_COMM_SIZE OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + sizeof(SMM_BOOT_RECORD_COMMUNICATE)\r
0284e90c
LG
47\r
48EFI_RSC_HANDLER_PROTOCOL *mRscHandlerProtocol = NULL;\r
49\r
db91c620 50BOOLEAN mLockBoxReady = FALSE;\r
0284e90c
LG
51EFI_EVENT mReadyToBootEvent;\r
52EFI_EVENT mLegacyBootEvent;\r
53EFI_EVENT mExitBootServicesEvent;\r
54UINTN mFirmwarePerformanceTableTemplateKey = 0;\r
1c0cc375
LG
55UINT32 mBootRecordSize = 0;\r
56UINT32 mBootRecordMaxSize = 0;\r
57UINT8 *mBootRecordBuffer = NULL;\r
40a0f8cb 58BOOLEAN mDxeCoreReportStatusCodeEnable = FALSE;\r
0284e90c 59\r
0284e90c
LG
60BOOT_PERFORMANCE_TABLE *mAcpiBootPerformanceTable = NULL;\r
61S3_PERFORMANCE_TABLE *mAcpiS3PerformanceTable = NULL;\r
62\r
63FIRMWARE_PERFORMANCE_TABLE mFirmwarePerformanceTableTemplate = {\r
64 {\r
65 EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE,\r
66 sizeof (FIRMWARE_PERFORMANCE_TABLE),\r
67 EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_REVISION, // Revision\r
68 0x00, // Checksum will be updated at runtime\r
69 //\r
e84f07b5 70 // It is expected that these values will be updated at EntryPoint.\r
0284e90c 71 //\r
e84f07b5
SZ
72 {0x00}, // OEM ID is a 6 bytes long field\r
73 0x00, // OEM Table ID(8 bytes long)\r
74 0x00, // OEM Revision\r
75 0x00, // Creator ID\r
76 0x00, // Creator Revision\r
0284e90c
LG
77 },\r
78 //\r
79 // Firmware Basic Boot Performance Table Pointer Record.\r
80 //\r
81 {\r
82 {\r
83 EFI_ACPI_5_0_FPDT_RECORD_TYPE_FIRMWARE_BASIC_BOOT_POINTER , // Type\r
84 sizeof (EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_POINTER_RECORD), // Length\r
85 EFI_ACPI_5_0_FPDT_RECORD_REVISION_FIRMWARE_BASIC_BOOT_POINTER // Revision\r
86 },\r
87 0, // Reserved\r
88 0 // BootPerformanceTablePointer will be updated at runtime.\r
89 },\r
90 //\r
91 // S3 Performance Table Pointer Record.\r
92 //\r
93 {\r
94 {\r
95 EFI_ACPI_5_0_FPDT_RECORD_TYPE_S3_PERFORMANCE_TABLE_POINTER, // Type\r
96 sizeof (EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD), // Length\r
97 EFI_ACPI_5_0_FPDT_RECORD_REVISION_S3_PERFORMANCE_TABLE_POINTER // Revision\r
98 },\r
99 0, // Reserved\r
100 0 // S3PerformanceTablePointer will be updated at runtime.\r
101 }\r
102};\r
103\r
104BOOT_PERFORMANCE_TABLE mBootPerformanceTableTemplate = {\r
105 {\r
106 EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_SIGNATURE,\r
107 sizeof (BOOT_PERFORMANCE_TABLE)\r
108 },\r
109 {\r
110 {\r
111 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT, // Type\r
112 sizeof (EFI_ACPI_5_0_FPDT_FIRMWARE_BASIC_BOOT_RECORD), // Length\r
113 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_FIRMWARE_BASIC_BOOT // Revision\r
114 },\r
115 0, // Reserved\r
116 //\r
117 // These values will be updated at runtime.\r
118 //\r
119 0, // ResetEnd\r
120 0, // OsLoaderLoadImageStart\r
121 0, // OsLoaderStartImageStart\r
122 0, // ExitBootServicesEntry\r
123 0 // ExitBootServicesExit\r
124 }\r
125};\r
126\r
127S3_PERFORMANCE_TABLE mS3PerformanceTableTemplate = {\r
128 {\r
129 EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_SIGNATURE,\r
130 sizeof (S3_PERFORMANCE_TABLE)\r
131 },\r
132 {\r
133 {\r
134 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_S3_RESUME, // Type\r
135 sizeof (EFI_ACPI_5_0_FPDT_S3_RESUME_RECORD), // Length\r
136 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_S3_RESUME // Revision\r
137 },\r
138 //\r
139 // These values will be updated by Firmware Performance PEIM.\r
140 //\r
141 0, // ResumeCount\r
142 0, // FullResume\r
143 0 // AverageResume\r
144 },\r
145 {\r
146 {\r
147 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_S3_SUSPEND, // Type\r
148 sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD), // Length\r
149 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_S3_SUSPEND // Revision\r
150 },\r
151 //\r
152 // These values will be updated bye Firmware Performance SMM driver.\r
153 //\r
154 0, // SuspendStart\r
155 0 // SuspendEnd\r
156 }\r
157};\r
158\r
159/**\r
160 This function calculates and updates an UINT8 checksum.\r
161\r
162 @param[in] Buffer Pointer to buffer to checksum\r
163 @param[in] Size Number of bytes to checksum\r
164\r
165**/\r
166VOID\r
167FpdtAcpiTableChecksum (\r
168 IN UINT8 *Buffer,\r
169 IN UINTN Size\r
170 )\r
171{\r
172 UINTN ChecksumOffset;\r
173\r
174 ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum);\r
175\r
176 //\r
177 // Set checksum to 0 first.\r
178 //\r
179 Buffer[ChecksumOffset] = 0;\r
180\r
181 //\r
182 // Update checksum value.\r
183 //\r
184 Buffer[ChecksumOffset] = CalculateCheckSum8 (Buffer, Size);\r
185}\r
186\r
187/**\r
188 Allocate EfiReservedMemoryType below 4G memory address.\r
189\r
190 This function allocates EfiReservedMemoryType below 4G memory address.\r
191\r
192 @param[in] Size Size of memory to allocate.\r
193\r
194 @return Allocated address for output.\r
195\r
196**/\r
197VOID *\r
198FpdtAllocateReservedMemoryBelow4G (\r
199 IN UINTN Size\r
200 )\r
201{\r
202 UINTN Pages;\r
203 EFI_PHYSICAL_ADDRESS Address;\r
204 EFI_STATUS Status;\r
205 VOID *Buffer;\r
206\r
db91c620 207 Buffer = NULL;\r
0284e90c
LG
208 Pages = EFI_SIZE_TO_PAGES (Size);\r
209 Address = 0xffffffff;\r
210\r
211 Status = gBS->AllocatePages (\r
212 AllocateMaxAddress,\r
213 EfiReservedMemoryType,\r
214 Pages,\r
215 &Address\r
216 );\r
217 ASSERT_EFI_ERROR (Status);\r
218\r
db91c620
SZ
219 if (!EFI_ERROR (Status)) {\r
220 Buffer = (VOID *) (UINTN) Address;\r
221 ZeroMem (Buffer, Size);\r
222 }\r
0284e90c
LG
223\r
224 return Buffer;\r
225}\r
226\r
db91c620
SZ
227/**\r
228 Callback function upon VariableArchProtocol and LockBoxProtocol\r
229 to allocate S3 performance table memory and save the pointer to LockBox.\r
230\r
231 @param[in] Event Event whose notification function is being invoked.\r
232 @param[in] Context Pointer to the notification function's context.\r
233**/\r
234VOID\r
235EFIAPI\r
236FpdtAllocateS3PerformanceTableMemory (\r
237 IN EFI_EVENT Event,\r
238 IN VOID *Context\r
239 )\r
240{\r
241 EFI_STATUS Status;\r
242 VOID *Interface;\r
243 FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable;\r
244 UINTN Size;\r
245 EFI_PHYSICAL_ADDRESS S3PerformanceTablePointer;\r
246\r
247 if (mLockBoxReady && (mAcpiS3PerformanceTable != NULL)) {\r
248 //\r
249 // The memory for S3 performance table should have been ready,\r
250 // and the pointer should have been saved to LockBox, just return.\r
251 //\r
252 return;\r
253 }\r
254\r
255 if (!mLockBoxReady) {\r
256 Status = gBS->LocateProtocol (&gEfiLockBoxProtocolGuid, NULL, &Interface);\r
257 if (!EFI_ERROR (Status)) {\r
258 //\r
259 // LockBox services has been ready.\r
260 //\r
261 mLockBoxReady = TRUE;\r
262 }\r
263 }\r
264\r
265 if (mAcpiS3PerformanceTable == NULL) {\r
266 Status = gBS->LocateProtocol (&gEfiVariableArchProtocolGuid, NULL, &Interface);\r
267 if (!EFI_ERROR (Status)) {\r
268 //\r
269 // Try to allocate the same runtime buffer as last time boot.\r
270 //\r
271 ZeroMem (&PerformanceVariable, sizeof (PerformanceVariable));\r
272 Size = sizeof (PerformanceVariable);\r
273 Status = gRT->GetVariable (\r
274 EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,\r
275 &gEfiFirmwarePerformanceGuid,\r
276 NULL,\r
277 &Size,\r
278 &PerformanceVariable\r
279 );\r
280 if (!EFI_ERROR (Status)) {\r
281 Status = gBS->AllocatePages (\r
282 AllocateAddress,\r
283 EfiReservedMemoryType,\r
284 EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE)),\r
285 &PerformanceVariable.S3PerformanceTablePointer\r
286 );\r
287 if (!EFI_ERROR (Status)) {\r
288 mAcpiS3PerformanceTable = (S3_PERFORMANCE_TABLE *) (UINTN) PerformanceVariable.S3PerformanceTablePointer;\r
289 }\r
290 }\r
291 if (mAcpiS3PerformanceTable == NULL) {\r
292 //\r
293 // Fail to allocate at specified address, continue to allocate at any address.\r
294 //\r
295 mAcpiS3PerformanceTable = (S3_PERFORMANCE_TABLE *) FpdtAllocateReservedMemoryBelow4G (sizeof (S3_PERFORMANCE_TABLE));\r
296 }\r
297 DEBUG ((EFI_D_INFO, "FPDT: ACPI S3 Performance Table address = 0x%x\n", mAcpiS3PerformanceTable));\r
298 if (mAcpiS3PerformanceTable != NULL) {\r
299 CopyMem (mAcpiS3PerformanceTable, &mS3PerformanceTableTemplate, sizeof (mS3PerformanceTableTemplate));\r
300 }\r
301 }\r
302 }\r
303\r
304 if (mLockBoxReady && (mAcpiS3PerformanceTable != NULL)) {\r
305 //\r
306 // If LockBox services has been ready and memory for FPDT S3 performance table has been allocated,\r
307 // save the pointer to LockBox for use in S3 resume.\r
308 //\r
309 S3PerformanceTablePointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiS3PerformanceTable;\r
310 Status = SaveLockBox (\r
311 &gFirmwarePerformanceS3PointerGuid,\r
312 &S3PerformanceTablePointer,\r
313 sizeof (EFI_PHYSICAL_ADDRESS)\r
314 );\r
315 ASSERT_EFI_ERROR (Status);\r
316 }\r
317}\r
318\r
0284e90c
LG
319/**\r
320 Install ACPI Firmware Performance Data Table (FPDT).\r
321\r
322 @return Status code.\r
323\r
324**/\r
325EFI_STATUS\r
326InstallFirmwarePerformanceDataTable (\r
327 VOID\r
328 )\r
329{\r
330 EFI_STATUS Status;\r
331 EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;\r
0284e90c 332 UINTN Size;\r
cbcccd2c 333 UINT8 *SmmBootRecordCommBuffer;\r
1c0cc375
LG
334 EFI_SMM_COMMUNICATE_HEADER *SmmCommBufferHeader;\r
335 SMM_BOOT_RECORD_COMMUNICATE *SmmCommData;\r
336 UINTN CommSize;\r
db91c620
SZ
337 UINTN BootPerformanceDataSize;\r
338 UINT8 *BootPerformanceData; \r
1c0cc375
LG
339 EFI_SMM_COMMUNICATION_PROTOCOL *Communication;\r
340 FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable;\r
d158ba67
LG
341 EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *SmmCommRegionTable;\r
342 EFI_MEMORY_DESCRIPTOR *SmmCommMemRegion;\r
343 UINTN Index;\r
344 VOID *SmmBootRecordData;\r
345 UINTN SmmBootRecordDataSize;\r
346 UINTN ReservedMemSize;\r
0284e90c
LG
347\r
348 //\r
349 // Get AcpiTable Protocol.\r
350 //\r
351 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);\r
352 if (EFI_ERROR (Status)) {\r
353 return Status;\r
354 }\r
355\r
356 //\r
1c0cc375 357 // Collect boot records from SMM drivers.\r
0284e90c 358 //\r
9cf37b40
LG
359 SmmBootRecordCommBuffer = NULL;\r
360 SmmCommData = NULL;\r
d158ba67
LG
361 SmmBootRecordData = NULL;\r
362 SmmBootRecordDataSize = 0;\r
363 ReservedMemSize = 0;\r
1c0cc375
LG
364 Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &Communication);\r
365 if (!EFI_ERROR (Status)) {\r
366 //\r
367 // Initialize communicate buffer \r
d158ba67 368 // Get the prepared Reserved Memory Range\r
1c0cc375 369 //\r
d158ba67
LG
370 Status = EfiGetSystemConfigurationTable (\r
371 &gEdkiiPiSmmCommunicationRegionTableGuid, \r
372 (VOID **) &SmmCommRegionTable\r
373 );\r
374 if (!EFI_ERROR (Status)) {\r
375 ASSERT (SmmCommRegionTable != NULL);\r
376 SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) (SmmCommRegionTable + 1);\r
377 for (Index = 0; Index < SmmCommRegionTable->NumberOfEntries; Index ++) {\r
378 if (SmmCommMemRegion->Type == EfiConventionalMemory) {\r
379 break;\r
380 }\r
381 SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) SmmCommMemRegion + SmmCommRegionTable->DescriptorSize);\r
382 }\r
383 ASSERT (Index < SmmCommRegionTable->NumberOfEntries);\r
384 ASSERT (SmmCommMemRegion->PhysicalStart > 0);\r
385 ASSERT (SmmCommMemRegion->NumberOfPages > 0);\r
386 ReservedMemSize = (UINTN) SmmCommMemRegion->NumberOfPages * EFI_PAGE_SIZE;\r
387 \r
1c0cc375 388 //\r
d158ba67 389 // Check enough reserved memory space\r
1c0cc375 390 //\r
d158ba67
LG
391 if (ReservedMemSize > SMM_BOOT_RECORD_COMM_SIZE) {\r
392 SmmBootRecordCommBuffer = (VOID *) (UINTN) SmmCommMemRegion->PhysicalStart;\r
393 SmmCommBufferHeader = (EFI_SMM_COMMUNICATE_HEADER*)SmmBootRecordCommBuffer;\r
394 SmmCommData = (SMM_BOOT_RECORD_COMMUNICATE*)SmmCommBufferHeader->Data;\r
395 ZeroMem((UINT8*)SmmCommData, sizeof(SMM_BOOT_RECORD_COMMUNICATE));\r
396 \r
397 CopyGuid (&SmmCommBufferHeader->HeaderGuid, &gEfiFirmwarePerformanceGuid);\r
398 SmmCommBufferHeader->MessageLength = sizeof(SMM_BOOT_RECORD_COMMUNICATE);\r
399 CommSize = SMM_BOOT_RECORD_COMM_SIZE;\r
1c0cc375 400 \r
d158ba67
LG
401 //\r
402 // Get the size of boot records.\r
403 //\r
404 SmmCommData->Function = SMM_FPDT_FUNCTION_GET_BOOT_RECORD_SIZE;\r
405 SmmCommData->BootRecordData = NULL;\r
406 Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize);\r
407 ASSERT_EFI_ERROR (Status);\r
408 \r
409 if (!EFI_ERROR (SmmCommData->ReturnStatus) && SmmCommData->BootRecordSize != 0) {\r
410 //\r
411 // Get all boot records\r
412 //\r
413 SmmCommData->Function = SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA_BY_OFFSET;\r
414 SmmBootRecordDataSize = SmmCommData->BootRecordSize;\r
415 SmmBootRecordData = AllocateZeroPool(SmmBootRecordDataSize);\r
416 ASSERT (SmmBootRecordData != NULL);\r
417 SmmCommData->BootRecordOffset = 0;\r
418 SmmCommData->BootRecordData = (VOID *) ((UINTN) SmmCommMemRegion->PhysicalStart + SMM_BOOT_RECORD_COMM_SIZE);\r
419 SmmCommData->BootRecordSize = ReservedMemSize - SMM_BOOT_RECORD_COMM_SIZE;\r
420 while (SmmCommData->BootRecordOffset < SmmBootRecordDataSize) {\r
421 Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize);\r
422 ASSERT_EFI_ERROR (Status);\r
423 ASSERT_EFI_ERROR(SmmCommData->ReturnStatus);\r
424 CopyMem ((UINT8 *) SmmBootRecordData + SmmCommData->BootRecordOffset, SmmCommData->BootRecordData, SmmCommData->BootRecordSize);\r
425 SmmCommData->BootRecordOffset = SmmCommData->BootRecordOffset + SmmCommData->BootRecordSize;\r
426 }\r
427 }\r
428 }\r
1c0cc375
LG
429 }\r
430 }\r
431\r
432 //\r
db91c620 433 // Prepare memory for Boot Performance table.\r
1c0cc375
LG
434 // Boot Performance table includes BasicBoot record, and one or more appended Boot Records. \r
435 //\r
db91c620 436 BootPerformanceDataSize = sizeof (BOOT_PERFORMANCE_TABLE) + mBootRecordSize + PcdGet32 (PcdExtFpdtBootRecordPadSize);\r
1c0cc375 437 if (SmmCommData != NULL) {\r
d158ba67 438 BootPerformanceDataSize += SmmBootRecordDataSize;\r
1c0cc375
LG
439 }\r
440\r
0284e90c
LG
441 //\r
442 // Try to allocate the same runtime buffer as last time boot.\r
443 //\r
1c0cc375
LG
444 ZeroMem (&PerformanceVariable, sizeof (PerformanceVariable));\r
445 Size = sizeof (PerformanceVariable);\r
0284e90c
LG
446 Status = gRT->GetVariable (\r
447 EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,\r
448 &gEfiFirmwarePerformanceGuid,\r
449 NULL,\r
450 &Size,\r
451 &PerformanceVariable\r
452 );\r
453 if (!EFI_ERROR (Status)) {\r
0284e90c
LG
454 Status = gBS->AllocatePages (\r
455 AllocateAddress,\r
456 EfiReservedMemoryType,\r
db91c620
SZ
457 EFI_SIZE_TO_PAGES (BootPerformanceDataSize),\r
458 &PerformanceVariable.BootPerformanceTablePointer\r
0284e90c
LG
459 );\r
460 if (!EFI_ERROR (Status)) {\r
db91c620 461 mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) (UINTN) PerformanceVariable.BootPerformanceTablePointer;\r
0284e90c
LG
462 }\r
463 }\r
464\r
db91c620 465 if (mAcpiBootPerformanceTable == NULL) {\r
0284e90c
LG
466 //\r
467 // Fail to allocate at specified address, continue to allocate at any address.\r
468 //\r
db91c620 469 mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) FpdtAllocateReservedMemoryBelow4G (BootPerformanceDataSize);\r
0284e90c 470 }\r
db91c620 471 DEBUG ((EFI_D_INFO, "FPDT: ACPI Boot Performance Table address = 0x%x\n", mAcpiBootPerformanceTable));\r
0284e90c 472\r
db91c620 473 if (mAcpiBootPerformanceTable == NULL) {\r
d158ba67
LG
474 if (SmmCommData != NULL && SmmBootRecordData != NULL) {\r
475 FreePool (SmmBootRecordData);\r
9cf37b40 476 }\r
db91c620
SZ
477 if (mAcpiS3PerformanceTable != NULL) {\r
478 FreePages (mAcpiS3PerformanceTable, EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE)));\r
d158ba67 479 mAcpiS3PerformanceTable = NULL;\r
db91c620 480 }\r
0284e90c
LG
481 return EFI_OUT_OF_RESOURCES;\r
482 }\r
0284e90c 483\r
1c0cc375
LG
484 //\r
485 // Prepare Boot Performance Table.\r
486 //\r
db91c620 487 BootPerformanceData = (UINT8 *) mAcpiBootPerformanceTable;\r
1c0cc375
LG
488 //\r
489 // Fill Basic Boot record to Boot Performance Table.\r
490 //\r
db91c620
SZ
491 CopyMem (mAcpiBootPerformanceTable, &mBootPerformanceTableTemplate, sizeof (mBootPerformanceTableTemplate));\r
492 BootPerformanceData = BootPerformanceData + mAcpiBootPerformanceTable->Header.Length;\r
1c0cc375
LG
493 //\r
494 // Fill Boot records from boot drivers.\r
495 //\r
db91c620 496 CopyMem (BootPerformanceData, mBootRecordBuffer, mBootRecordSize);\r
1c0cc375 497 mAcpiBootPerformanceTable->Header.Length += mBootRecordSize;\r
db91c620 498 BootPerformanceData = BootPerformanceData + mBootRecordSize;\r
d158ba67 499 if (SmmCommData != NULL && SmmBootRecordData != NULL) {\r
1c0cc375
LG
500 //\r
501 // Fill Boot records from SMM drivers.\r
502 //\r
d158ba67
LG
503 CopyMem (BootPerformanceData, SmmBootRecordData, SmmBootRecordDataSize);\r
504 FreePool (SmmBootRecordData);\r
505 mAcpiBootPerformanceTable->Header.Length = (UINT32) (mAcpiBootPerformanceTable->Header.Length + SmmBootRecordDataSize);\r
506 BootPerformanceData = BootPerformanceData + SmmBootRecordDataSize;\r
9cf37b40
LG
507 }\r
508\r
1c0cc375 509 //\r
1c0cc375
LG
510 // Save Boot Performance Table address to Variable for use in S4 resume.\r
511 //\r
512 PerformanceVariable.BootPerformanceTablePointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiBootPerformanceTable;\r
513 //\r
514 // Update Boot Performance Table Pointer in template.\r
515 //\r
516 mFirmwarePerformanceTableTemplate.BootPointerRecord.BootPerformanceTablePointer = (UINT64) (UINTN) mAcpiBootPerformanceTable;\r
517\r
db91c620
SZ
518 //\r
519 // Save S3 Performance Table address to Variable for use in S4 resume.\r
520 //\r
521 PerformanceVariable.S3PerformanceTablePointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiS3PerformanceTable;\r
522 //\r
523 // Update S3 Performance Table Pointer in template.\r
524 //\r
525 mFirmwarePerformanceTableTemplate.S3PointerRecord.S3PerformanceTablePointer = (UINT64) (UINTN) mAcpiS3PerformanceTable;\r
0284e90c
LG
526 //\r
527 // Save Runtime Performance Table pointers to Variable.\r
fd704cbd
LG
528 // Don't check SetVariable return status. It doesn't impact FPDT table generation. \r
529 //\r
530 gRT->SetVariable (\r
531 EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,\r
532 &gEfiFirmwarePerformanceGuid,\r
533 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
534 sizeof (PerformanceVariable),\r
535 &PerformanceVariable\r
536 );\r
0284e90c
LG
537\r
538 //\r
539 // Publish Firmware Performance Data Table.\r
540 //\r
541 FpdtAcpiTableChecksum ((UINT8 *) &mFirmwarePerformanceTableTemplate, mFirmwarePerformanceTableTemplate.Header.Length);\r
542 Status = AcpiTableProtocol->InstallAcpiTable (\r
543 AcpiTableProtocol,\r
544 &mFirmwarePerformanceTableTemplate,\r
545 mFirmwarePerformanceTableTemplate.Header.Length,\r
546 &mFirmwarePerformanceTableTemplateKey\r
547 );\r
548 if (EFI_ERROR (Status)) {\r
db91c620
SZ
549 FreePages (mAcpiBootPerformanceTable, EFI_SIZE_TO_PAGES (BootPerformanceDataSize));\r
550 if (mAcpiS3PerformanceTable != NULL) {\r
551 FreePages (mAcpiS3PerformanceTable, EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE)));\r
552 }\r
0284e90c
LG
553 mAcpiBootPerformanceTable = NULL;\r
554 mAcpiS3PerformanceTable = NULL;\r
555 return Status;\r
556 }\r
1c0cc375
LG
557 \r
558 //\r
559 // Free temp Boot record, and update Boot Record to point to Basic Boot performance table.\r
560 //\r
561 if (mBootRecordBuffer != NULL) {\r
562 FreePool (mBootRecordBuffer);\r
563 }\r
564 mBootRecordBuffer = (UINT8 *) mAcpiBootPerformanceTable;\r
565 mBootRecordSize = mAcpiBootPerformanceTable->Header.Length;\r
566 mBootRecordMaxSize = mBootRecordSize + PcdGet32 (PcdExtFpdtBootRecordPadSize);\r
567 \r
0284e90c
LG
568 return EFI_SUCCESS;\r
569}\r
570\r
571/**\r
572 Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to\r
573 install the Firmware Performance Data Table.\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
581FpdtReadyToBootEventNotify (\r
582 IN EFI_EVENT Event,\r
583 IN VOID *Context\r
584 )\r
585{\r
586 if (mAcpiBootPerformanceTable == NULL) {\r
587 //\r
588 // ACPI Firmware Performance Data Table not installed yet, install it now.\r
589 //\r
590 InstallFirmwarePerformanceDataTable ();\r
591 }\r
592}\r
593\r
0284e90c
LG
594/**\r
595 Report status code listener of FPDT. This is used to collect performance data\r
596 for OsLoaderLoadImageStart and OsLoaderStartImageStart in FPDT.\r
597\r
598 @param[in] CodeType Indicates the type of status code being reported.\r
599 @param[in] Value Describes the current status of a hardware or software entity.\r
600 This included information about the class and subclass that is used to\r
601 classify the entity as well as an operation.\r
602 @param[in] Instance The enumeration of a hardware or software entity within\r
603 the system. Valid instance numbers start with 1.\r
604 @param[in] CallerId This optional parameter may be used to identify the caller.\r
605 This parameter allows the status code driver to apply different rules to\r
606 different callers.\r
607 @param[in] Data This optional parameter may be used to pass additional data.\r
608\r
609 @retval EFI_SUCCESS Status code is what we expected.\r
610 @retval EFI_UNSUPPORTED Status code not supported.\r
611\r
612**/\r
613EFI_STATUS\r
614EFIAPI\r
615FpdtStatusCodeListenerDxe (\r
616 IN EFI_STATUS_CODE_TYPE CodeType,\r
617 IN EFI_STATUS_CODE_VALUE Value,\r
618 IN UINT32 Instance,\r
619 IN EFI_GUID *CallerId,\r
620 IN EFI_STATUS_CODE_DATA *Data\r
621 )\r
622{\r
623 EFI_STATUS Status;\r
624\r
625 //\r
626 // Check whether status code is what we are interested in.\r
627 //\r
628 if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) != EFI_PROGRESS_CODE) {\r
629 return EFI_UNSUPPORTED;\r
630 }\r
40a0f8cb
LG
631 \r
632 if (Value == (EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_HANDOFF_TO_NEXT)) {\r
633 //\r
634 // DxeCore ReportStatusCode Enable so that the capability can be supported.\r
635 //\r
636 mDxeCoreReportStatusCodeEnable = TRUE;\r
637 }\r
0284e90c
LG
638\r
639 Status = EFI_SUCCESS;\r
640 if (Value == PcdGet32 (PcdProgressCodeOsLoaderLoad)) {\r
641 //\r
642 // Progress code for OS Loader LoadImage.\r
643 //\r
644 if (mAcpiBootPerformanceTable == NULL) {\r
645 return Status;\r
646 }\r
647\r
648 //\r
649 // Update OS Loader LoadImage Start for UEFI boot.\r
650 //\r
651 mAcpiBootPerformanceTable->BasicBoot.OsLoaderLoadImageStart = GetTimeInNanoSecond (GetPerformanceCounter ());\r
652 } else if (Value == PcdGet32 (PcdProgressCodeOsLoaderStart)) {\r
653 //\r
654 // Progress code for OS Loader StartImage.\r
655 //\r
656 if (mAcpiBootPerformanceTable == NULL) {\r
657 return Status;\r
658 }\r
659\r
660 //\r
661 // Update OS Loader StartImage Start for UEFI boot.\r
662 //\r
663 mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart = GetTimeInNanoSecond (GetPerformanceCounter ());\r
664 } else if (Value == (EFI_SOFTWARE_EFI_BOOT_SERVICE | EFI_SW_BS_PC_EXIT_BOOT_SERVICES)) {\r
40a0f8cb
LG
665 //\r
666 // Unregister boot time report status code listener.\r
667 //\r
668 mRscHandlerProtocol->Unregister (FpdtStatusCodeListenerDxe);\r
669\r
0284e90c
LG
670 //\r
671 // Progress code for ExitBootServices.\r
672 //\r
673 if (mAcpiBootPerformanceTable == NULL) {\r
674 return Status;\r
675 }\r
676\r
677 //\r
678 // Update ExitBootServicesExit for UEFI boot.\r
679 //\r
680 mAcpiBootPerformanceTable->BasicBoot.ExitBootServicesExit = GetTimeInNanoSecond (GetPerformanceCounter ());\r
522dfbf3
LG
681 } else if (Value == (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_LEGACY_BOOT_EVENT)) {\r
682 if (mAcpiBootPerformanceTable == NULL) {\r
683 //\r
684 // Firmware Performance Data Table not installed, do nothing.\r
685 //\r
686 return Status;\r
687 }\r
688\r
689 //\r
690 // Update Firmware Basic Boot Performance Record for legacy boot.\r
691 //\r
692 mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart = GetTimeInNanoSecond (GetPerformanceCounter ());\r
693\r
694 //\r
695 // Dump FPDT Boot Performance record.\r
696 //\r
697 DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ResetEnd = %ld\n", mAcpiBootPerformanceTable->BasicBoot.ResetEnd));\r
698 DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderLoadImageStart = 0\n"));\r
699 DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderStartImageStart = %ld\n", mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart));\r
700 DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ExitBootServicesEntry = 0\n"));\r
701 DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ExitBootServicesExit = 0\n"));\r
1c0cc375
LG
702 } else if (Data != NULL && CompareGuid (&Data->Type, &gEfiFirmwarePerformanceGuid)) {\r
703 //\r
704 // Append one or more Boot records\r
705 //\r
706 if (mAcpiBootPerformanceTable == NULL) {\r
707 //\r
708 // Append Boot records before FPDT ACPI table is installed. \r
709 //\r
710 if (mBootRecordSize + Data->Size > mBootRecordMaxSize) {\r
711 mBootRecordBuffer = ReallocatePool (mBootRecordSize, mBootRecordSize + Data->Size + EXTENSION_RECORD_SIZE, mBootRecordBuffer);\r
712 ASSERT (mBootRecordBuffer != NULL);\r
713 mBootRecordMaxSize = mBootRecordSize + Data->Size + EXTENSION_RECORD_SIZE;\r
714 }\r
715 //\r
716 // Save boot record into the temp memory space.\r
717 //\r
718 CopyMem (mBootRecordBuffer + mBootRecordSize, Data + 1, Data->Size);\r
719 mBootRecordSize += Data->Size;\r
720 } else {\r
721 //\r
722 // Append Boot records after FPDT ACPI table is installed. \r
723 //\r
724 if (mBootRecordSize + Data->Size > mBootRecordMaxSize) {\r
725 //\r
726 // No enough space to save boot record.\r
727 //\r
728 Status = EFI_OUT_OF_RESOURCES;\r
729 } else {\r
730 //\r
731 // Save boot record into BootPerformance table\r
732 //\r
733 CopyMem (mBootRecordBuffer + mBootRecordSize, Data + 1, Data->Size);\r
734 mBootRecordSize += Data->Size;\r
735 mAcpiBootPerformanceTable->Header.Length = mBootRecordSize;\r
736 }\r
737 }\r
0284e90c
LG
738 } else {\r
739 //\r
740 // Ignore else progress code.\r
741 //\r
742 Status = EFI_UNSUPPORTED;\r
743 }\r
744\r
745 return Status;\r
746}\r
747\r
40a0f8cb
LG
748\r
749/**\r
750 Notify function for event EVT_SIGNAL_EXIT_BOOT_SERVICES. This is used to record\r
751 performance data for ExitBootServicesEntry in FPDT.\r
752\r
753 @param[in] Event The Event that is being processed.\r
754 @param[in] Context The Event Context.\r
755\r
756**/\r
757VOID\r
758EFIAPI\r
759FpdtExitBootServicesEventNotify (\r
760 IN EFI_EVENT Event,\r
761 IN VOID *Context\r
762 )\r
763{\r
0b24f2cf 764 if (!mDxeCoreReportStatusCodeEnable) {\r
40a0f8cb
LG
765 //\r
766 // When DxeCore Report Status Code is disabled, \r
767 // Unregister boot time report status code listener at ExitBootService Event.\r
768 //\r
769 mRscHandlerProtocol->Unregister (FpdtStatusCodeListenerDxe);\r
770 }\r
771\r
772 if (mAcpiBootPerformanceTable == NULL) {\r
773 //\r
774 // Firmware Performance Data Table not installed, do nothing.\r
775 //\r
776 return ;\r
777 }\r
778\r
779 //\r
780 // Update Firmware Basic Boot Performance Record for UEFI boot.\r
781 //\r
782 mAcpiBootPerformanceTable->BasicBoot.ExitBootServicesEntry = GetTimeInNanoSecond (GetPerformanceCounter ());\r
783\r
784 //\r
785 // Dump FPDT Boot Performance record.\r
786 //\r
787 DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ResetEnd = %ld\n", mAcpiBootPerformanceTable->BasicBoot.ResetEnd));\r
788 DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderLoadImageStart = %ld\n", mAcpiBootPerformanceTable->BasicBoot.OsLoaderLoadImageStart));\r
789 DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderStartImageStart = %ld\n", mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart));\r
790 DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ExitBootServicesEntry = %ld\n", mAcpiBootPerformanceTable->BasicBoot.ExitBootServicesEntry));\r
791 //\r
792 // ExitBootServicesExit will be updated later, so don't dump it here.\r
793 //\r
794}\r
795\r
0284e90c
LG
796/**\r
797 The module Entry Point of the Firmware Performance Data Table DXE driver.\r
798\r
799 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
800 @param[in] SystemTable A pointer to the EFI System Table.\r
801\r
802 @retval EFI_SUCCESS The entry point is executed successfully.\r
803 @retval Other Some error occurs when executing this entry point.\r
804\r
805**/\r
806EFI_STATUS\r
807EFIAPI\r
808FirmwarePerformanceDxeEntryPoint (\r
809 IN EFI_HANDLE ImageHandle,\r
810 IN EFI_SYSTEM_TABLE *SystemTable\r
811 )\r
812{\r
813 EFI_STATUS Status;\r
814 EFI_HOB_GUID_TYPE *GuidHob;\r
815 FIRMWARE_SEC_PERFORMANCE *Performance;\r
db91c620 816 VOID *Registration;\r
e84f07b5
SZ
817 UINT64 OemTableId;\r
818\r
819 CopyMem (\r
820 mFirmwarePerformanceTableTemplate.Header.OemId,\r
821 PcdGetPtr (PcdAcpiDefaultOemId),\r
822 sizeof (mFirmwarePerformanceTableTemplate.Header.OemId)\r
823 );\r
824 OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);\r
825 CopyMem (&mFirmwarePerformanceTableTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));\r
826 mFirmwarePerformanceTableTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);\r
827 mFirmwarePerformanceTableTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);\r
828 mFirmwarePerformanceTableTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);\r
0284e90c
LG
829\r
830 //\r
831 // Get Report Status Code Handler Protocol.\r
832 //\r
833 Status = gBS->LocateProtocol (&gEfiRscHandlerProtocolGuid, NULL, (VOID **) &mRscHandlerProtocol);\r
834 ASSERT_EFI_ERROR (Status);\r
835\r
836 //\r
837 // Register report status code listener for OS Loader load and start.\r
838 //\r
839 Status = mRscHandlerProtocol->Register (FpdtStatusCodeListenerDxe, TPL_HIGH_LEVEL);\r
840 ASSERT_EFI_ERROR (Status);\r
841\r
842 //\r
843 // Register the notify function to update FPDT on ExitBootServices Event.\r
844 //\r
845 Status = gBS->CreateEventEx (\r
846 EVT_NOTIFY_SIGNAL,\r
847 TPL_NOTIFY,\r
848 FpdtExitBootServicesEventNotify,\r
849 NULL,\r
850 &gEfiEventExitBootServicesGuid,\r
851 &mExitBootServicesEvent\r
852 );\r
853 ASSERT_EFI_ERROR (Status);\r
854\r
855 //\r
856 // Create ready to boot event to install ACPI FPDT table.\r
857 //\r
858 Status = gBS->CreateEventEx (\r
859 EVT_NOTIFY_SIGNAL,\r
860 TPL_NOTIFY,\r
861 FpdtReadyToBootEventNotify,\r
862 NULL,\r
863 &gEfiEventReadyToBootGuid,\r
864 &mReadyToBootEvent\r
865 );\r
866 ASSERT_EFI_ERROR (Status);\r
867\r
0284e90c
LG
868 //\r
869 // Retrieve GUID HOB data that contains the ResetEnd.\r
870 //\r
871 GuidHob = GetFirstGuidHob (&gEfiFirmwarePerformanceGuid);\r
872 if (GuidHob != NULL) {\r
873 Performance = (FIRMWARE_SEC_PERFORMANCE *) GET_GUID_HOB_DATA (GuidHob);\r
874 mBootPerformanceTableTemplate.BasicBoot.ResetEnd = Performance->ResetEnd;\r
875 } else {\r
876 //\r
877 // SEC Performance Data Hob not found, ResetEnd in ACPI FPDT table will be 0.\r
878 //\r
879 DEBUG ((EFI_D_ERROR, "FPDT: WARNING: SEC Performance Data Hob not found, ResetEnd will be set to 0!\n"));\r
880 }\r
881\r
db91c620
SZ
882 if (FeaturePcdGet (PcdFirmwarePerformanceDataTableS3Support)) {\r
883 //\r
884 // Register callback function upon VariableArchProtocol and LockBoxProtocol\r
885 // to allocate S3 performance table memory and save the pointer to LockBox.\r
886 //\r
887 EfiCreateProtocolNotifyEvent (\r
888 &gEfiVariableArchProtocolGuid,\r
889 TPL_CALLBACK,\r
890 FpdtAllocateS3PerformanceTableMemory,\r
891 NULL,\r
892 &Registration\r
893 );\r
894 EfiCreateProtocolNotifyEvent (\r
895 &gEfiLockBoxProtocolGuid,\r
896 TPL_CALLBACK,\r
897 FpdtAllocateS3PerformanceTableMemory,\r
898 NULL,\r
899 &Registration\r
900 );\r
901 } else {\r
902 //\r
903 // Exclude S3 Performance Table Pointer from FPDT table template.\r
904 //\r
905 mFirmwarePerformanceTableTemplate.Header.Length -= sizeof (EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD);\r
906 }\r
907\r
0284e90c
LG
908 return EFI_SUCCESS;\r
909}\r