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