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