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