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