3 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Support for Performance primatives.
23 #include "EfiDriverLib.h"
24 #include EFI_PROTOCOL_DEFINITION (Performance)
25 #include EFI_PROTOCOL_DEFINITION (LoadedImage)
26 #include EFI_GUID_DEFINITION (Hob)
27 #include EFI_GUID_DEFINITION (PeiPerformanceHob)
28 #include "LinkedList.h"
29 #include "EfiHobLib.h"
34 OUT UINT64
*TimerValue
39 IN EFI_HANDLE ImageHandle
,
40 IN EFI_SYSTEM_TABLE
*SystemTable
,
44 #define EFI_PERFORMANCE_DATA_SIGNATURE EFI_SIGNATURE_32 ('P', 'E', 'D', 'A')
49 EFI_GAUGE_DATA GaugeData
;
52 #define GAUGE_DATA_FROM_LINK(_link) \
53 CR(_link, EFI_PERF_DATA_LIST, Link, EFI_PERFORMANCE_DATA_SIGNATURE)
55 #define GAUGE_DATA_FROM_GAUGE(_GaugeData) \
56 CR(_GaugeData, EFI_PERF_DATA_LIST, GaugeData, EFI_PERFORMANCE_DATA_SIGNATURE)
58 #define EFI_PERFORMANCE_SIGNATURE EFI_SIGNATURE_32 ('P', 'E', 'R', 'F')
61 // Performance protocol instance data structure
66 EFI_PERFORMANCE_PROTOCOL Perf
;
68 } EFI_PERFORMANCE_INSTANCE
;
71 // Performace protocol instance containing record macro
74 #define EFI_PERFORMANCE_FROM_THIS(a) \
75 CR(a, EFI_PERFORMANCE_INSTANCE, Perf, EFI_PERFORMANCE_SIGNATURE)
77 EFI_LIST_ENTRY mPerfDataHead
= INITIALIZE_LIST_HEAD_VARIABLE(mPerfDataHead
);
100 if (PdbFileName
== NULL
) {
101 EfiAsciiStrCpy (GaugeString
, (CHAR8
*)" ");
104 for (EndIndex
= 0; PdbFileName
[EndIndex
] != 0; EndIndex
++)
107 for (Index
= 0; PdbFileName
[Index
] != 0; Index
++) {
108 if (PdbFileName
[Index
] == '\\') {
109 StartIndex
= Index
+ 1;
112 if (PdbFileName
[Index
] == '.') {
118 for (Index
= StartIndex
; Index
< EndIndex
; Index
++) {
119 GaugeString
[Index1
] = PdbFileName
[Index
];
121 if (Index1
== EFI_PERF_PDBFILENAME_LENGTH
- 1) {
126 GaugeString
[Index1
] = 0;
141 Located PDB path name in PE image
145 ImageBase - base of PE to search
149 Pointer into image at offset of PDB file name if PDB file name is found,
150 Otherwise a pointer to an empty string.
156 EFI_IMAGE_DOS_HEADER
*DosHdr
;
157 EFI_IMAGE_NT_HEADERS
*NtHdr
;
159 EFI_IMAGE_OPTIONAL_HEADER32
*OptionalHdr32
;
160 EFI_IMAGE_OPTIONAL_HEADER64
*OptionalHdr64
;
161 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
162 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
163 VOID
*CodeViewEntryPointer
;
165 CodeViewEntryPointer
= NULL
;
168 if (DosHdr
&& DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
169 NtHdr
= (EFI_IMAGE_NT_HEADERS
*) ((UINT8
*) DosHdr
+ DosHdr
->e_lfanew
);
171 // NOTE: We use Machine to identify PE32/PE32+, instead of Magic.
172 // It is for backward-compatibility consideration, because
173 // some system will generate PE32+ image with PE32 Magic.
175 if (NtHdr
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA32
) {
176 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
177 } else if (NtHdr
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA64
) {
178 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
179 } else if (NtHdr
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_X64
) {
180 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
182 Magic
= NtHdr
->OptionalHeader
.Magic
;
184 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
185 OptionalHdr32
= (VOID
*) &NtHdr
->OptionalHeader
;
186 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionalHdr32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
188 OptionalHdr64
= (VOID
*) &NtHdr
->OptionalHeader
;
189 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionalHdr64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
192 if (DirectoryEntry
->VirtualAddress
!= 0) {
194 (DirCount
< DirectoryEntry
->Size
/ sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) && CodeViewEntryPointer
== NULL
;
197 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*) (DirectoryEntry
->VirtualAddress
+ (UINTN
) ImageBase
+ DirCount
* sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
));
198 if (DebugEntry
->Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
199 CodeViewEntryPointer
= (VOID
*) ((UINTN
) DebugEntry
->RVA
+ (UINTN
) ImageBase
);
200 switch (*(UINT32
*) CodeViewEntryPointer
) {
201 case CODEVIEW_SIGNATURE_NB10
:
202 PdbPath
= (CHAR8
*) CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
205 case CODEVIEW_SIGNATURE_RSDS
:
206 PdbPath
= (CHAR8
*) CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
223 IN EFI_HANDLE Handle
,
224 OUT CHAR8
*GaugeString
228 EFI_LOADED_IMAGE_PROTOCOL
*Image
;
230 EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
;
232 EfiAsciiStrCpy (GaugeString
, (CHAR8
*)" ");
235 // Get handle name from image protocol
237 Status
= gBS
->HandleProtocol (
239 &gEfiLoadedImageProtocolGuid
,
243 if (EFI_ERROR (Status
)) {
244 Status
= gBS
->OpenProtocol (
246 &gEfiDriverBindingProtocolGuid
,
247 (VOID
**) &DriverBinding
,
250 EFI_OPEN_PROTOCOL_GET_PROTOCOL
252 if (EFI_ERROR (Status
)) {
256 // Get handle name from image protocol
258 Status
= gBS
->HandleProtocol (
259 DriverBinding
->ImageHandle
,
260 &gEfiLoadedImageProtocolGuid
,
265 PdbFileName
= GetPdbPath (Image
->ImageBase
);
267 if (PdbFileName
!= NULL
) {
268 GetShortPdbFileName (PdbFileName
, GaugeString
);
276 IN EFI_HANDLE Handle
,
284 Create a EFI_PERF_DATA_LIST data node.
288 Handle - Handle of gauge data
289 Token - Token of gauge data
290 Host - Host of gauge data
294 Pointer to a data node created.
298 EFI_PERF_DATA_LIST
*Node
;
301 // Al\ a new image structure
303 Node
= EfiLibAllocateZeroPool (sizeof (EFI_PERF_DATA_LIST
));
306 Node
->Signature
= EFI_PERFORMANCE_DATA_SIGNATURE
;
308 Node
->GaugeData
.Handle
= Handle
;
311 EfiStrCpy ((Node
->GaugeData
).Token
, Token
);
315 EfiStrCpy ((Node
->GaugeData
).Host
, Host
);
318 if (Handle
!= NULL
) {
319 GetNameFromHandle (Handle
, Node
->GaugeData
.PdbFileName
);
329 IN EFI_HANDLE Handle
,
332 IN EFI_GUID
*GuidName
,
333 IN EFI_GAUGE_DATA
*PrevGauge
339 Search gauge node list to find one node with matched handle, token, host and Guid name.
343 Handle - Handle to match
344 Token - Token to match
346 GuidName - Guid name to match
347 PrevGauge - Start node, start from list head if NULL
351 Return pointer to the node found, NULL if not found.
355 EFI_PERF_DATA_LIST
*Node
;
356 EFI_PERF_DATA_LIST
*Temp
;
357 EFI_PERF_DATA_LIST
*Temp2
;
358 EFI_LIST_ENTRY
*CurrentLink
;
359 EFI_GUID NullGuid
= EFI_NULL_GUID
;
365 if (PrevGauge
== NULL
) {
366 CurrentLink
= mPerfDataHead
.ForwardLink
;
368 Temp2
= GAUGE_DATA_FROM_GAUGE (PrevGauge
);
369 CurrentLink
= (Temp2
->Link
).ForwardLink
;
372 while (CurrentLink
&& CurrentLink
!= &mPerfDataHead
) {
373 Node
= GAUGE_DATA_FROM_LINK (CurrentLink
);
375 if (Handle
== 0 && Token
== NULL
&& Host
== NULL
&& GuidName
== NULL
) {
379 if (Handle
!= (Node
->GaugeData
).Handle
) {
380 CurrentLink
= CurrentLink
->ForwardLink
;
384 if (GuidName
== NULL
&& !EfiCompareGuid (&((Node
->GaugeData
).GuidName
), &NullGuid
)) {
385 CurrentLink
= CurrentLink
->ForwardLink
;
389 if (GuidName
&& !EfiCompareGuid (&((Node
->GaugeData
).GuidName
), GuidName
)) {
390 CurrentLink
= CurrentLink
->ForwardLink
;
394 if (Token
== NULL
&& EfiStrCmp (Node
->GaugeData
.Token
, L
"")) {
395 CurrentLink
= CurrentLink
->ForwardLink
;
399 if (Token
&& EfiStrCmp (Node
->GaugeData
.Token
, Token
)) {
400 CurrentLink
= CurrentLink
->ForwardLink
;
404 if (Host
== NULL
&& EfiStrCmp (Node
->GaugeData
.Host
, L
"")) {
405 CurrentLink
= CurrentLink
->ForwardLink
;
409 if (Host
&& EfiStrCmp (Node
->GaugeData
.Host
, Host
)) {
410 CurrentLink
= CurrentLink
->ForwardLink
;
425 IN EFI_PERFORMANCE_PROTOCOL
*This
,
426 IN EFI_HANDLE Handle
,
435 Create a guage data node and initialized it.
439 This - Calling context
440 Handle - Handle of gauge data
441 Token - Token of gauge data
442 Host - Host of gauge data
443 Ticker - Set gauge data's StartTick. If 0, StartTick is current timer.
447 EFI_SUCCESS - Successfully create and initialized a guage data node.
448 EFI_OUT_OF_RESOURCES - No enough resource to create a guage data node.
452 EFI_PERFORMANCE_INSTANCE
*PerfInstance
;
453 EFI_PERF_DATA_LIST
*Node
;
457 PerfInstance
= EFI_PERFORMANCE_FROM_THIS (This
);
459 Node
= CreateDataNode (Handle
, Token
, Host
);
461 return EFI_OUT_OF_RESOURCES
;
467 GetTimerValue (&TimerValue
);
470 Node
->GaugeData
.StartTick
= TimerValue
;
472 if (!EfiStrCmp (Token
, DXE_TOK
)) {
473 PerfInstance
->Phase
= DXE_PHASE
;
476 if (!EfiStrCmp (Token
, SHELL_TOK
)) {
477 PerfInstance
->Phase
= SHELL_PHASE
;
480 Node
->GaugeData
.Phase
= PerfInstance
->Phase
;
482 InsertTailList (&mPerfDataHead
, &(Node
->Link
));
491 IN EFI_PERFORMANCE_PROTOCOL
*This
,
492 IN EFI_HANDLE Handle
,
501 End all unfinished gauge data node that match specified handle, token and host.
505 This - Calling context
506 Handle - Handle to stop
507 Token - Token to stop
509 Ticker - End tick, if 0 then get current timer
513 EFI_NOT_FOUND - Node not found
514 EFI_SUCCESS - Gauge data node successfully ended.
518 EFI_PERFORMANCE_INSTANCE
*PerfInstance
;
519 EFI_PERF_DATA_LIST
*Node
;
523 PerfInstance
= EFI_PERFORMANCE_FROM_THIS (This
);
525 Node
= GetDataNode (Handle
, Token
, Host
, NULL
, NULL
);
527 return EFI_NOT_FOUND
;
530 while (Node
->GaugeData
.EndTick
!= 0) {
531 Node
= GetDataNode (Handle
, Token
, Host
, NULL
, &(Node
->GaugeData
));
533 return EFI_NOT_FOUND
;
540 GetTimerValue (&TimerValue
);
543 Node
->GaugeData
.EndTick
= TimerValue
;
552 IN EFI_PERFORMANCE_PROTOCOL
*This
,
553 IN EFI_HANDLE Handle
,
556 IN EFI_GAUGE_DATA
*PrevGauge
564 This - A pointer to the EFI_PERFORMANCE_PROTOCOL.
565 Handle - A pointer of a efi handle.
566 Token - A pointer to the token.
567 Host - A pointer to the host.
568 PrevGauge - A pointer to the EFI_GAUGE_DATA structure.
576 EFI_PERFORMANCE_INSTANCE
*PerfInstance
;
577 EFI_PERF_DATA_LIST
*Node
;
579 PerfInstance
= EFI_PERFORMANCE_FROM_THIS (This
);
581 Node
= GetDataNode (Handle
, Token
, Host
, NULL
, PrevGauge
);
583 return &(Node
->GaugeData
);
590 // Driver entry point
593 InitializePerformanceInfrastructure (
594 IN EFI_HANDLE ImageHandle
,
595 IN EFI_SYSTEM_TABLE
*SystemTable
,
602 Install gEfiPerformanceProtocolGuid protocol and transfer PEI performance to gauge data nodes.
606 ImageHandle - Standard driver entry point parameter
607 SystemTable - Standard driver entry point parameter
608 Ticker - End tick for PEI performance
612 EFI_OUT_OF_RESOURCES - No enough buffer to allocate
613 EFI_SUCCESS - Protocol installed.
618 EFI_PERFORMANCE_INSTANCE
*PerfInstance
;
621 // Allocate a new image structure
623 PerfInstance
= EfiLibAllocateZeroPool (sizeof (EFI_PERFORMANCE_INSTANCE
));
624 if (PerfInstance
== NULL
) {
625 return EFI_OUT_OF_RESOURCES
;
628 PerfInstance
->Signature
= EFI_PERFORMANCE_SIGNATURE
;
629 PerfInstance
->Perf
.StartGauge
= StartGauge
;
630 PerfInstance
->Perf
.EndGauge
= EndGauge
;
631 PerfInstance
->Perf
.GetGauge
= GetGauge
;
634 // Install the protocol interfaces
636 Status
= gBS
->InstallProtocolInterface (
637 &PerfInstance
->Handle
,
638 &gEfiPerformanceProtocolGuid
,
639 EFI_NATIVE_INTERFACE
,
643 if (!EFI_ERROR (Status
)) {
644 GetPeiPerformance (ImageHandle
, SystemTable
, Ticker
);
662 Start to gauge on a specified handle, token and host, with Ticker as start tick.
666 Handle - Handle to measure
667 Token - Token to measure
668 Host - Host to measure
669 Ticker - Ticker as start tick
678 EFI_PERFORMANCE_PROTOCOL
*Perf
;
680 Status
= gBS
->LocateProtocol (&gEfiPerformanceProtocolGuid
, NULL
, (VOID
**) &Perf
);
681 if (EFI_ERROR (Status
)) {
685 return Perf
->StartGauge (Perf
, Handle
, Token
, Host
, Ticker
);
701 End gauging on a specified handle, token and host, with Ticker as end tick.
705 Handle - Handle to stop
706 Token - Token to stop
708 Ticker - Ticker as end tick
717 EFI_PERFORMANCE_PROTOCOL
*Perf
;
719 Status
= gBS
->LocateProtocol (&gEfiPerformanceProtocolGuid
, NULL
, (VOID
**) &Perf
);
720 if (Status
!= EFI_SUCCESS
) {
724 return (Perf
->EndGauge( Perf
, Handle
, Token
, Host
, Ticker
)) ;
733 EFI_HANDLE HandleNew
,
743 Handle - A pointer of an efi handle.
744 Token - A pointer to the token.
745 Host - A pointer to the host.
746 HandleNew - A pointer of an new efi handle.
747 TokenNew - A pointer to the new token.
748 HostNew - A pointer to the new host.
753 EFI_NOT_FOUND - The speicified gauge data node not found.
755 EFI_SUCCESS - Update successfully.
760 EFI_GAUGE_DATA
*GaugeData
;
761 EFI_PERFORMANCE_PROTOCOL
*Perf
;
763 Status
= gBS
->LocateProtocol (&gEfiPerformanceProtocolGuid
, NULL
, (VOID
**) &Perf
);
764 if (EFI_ERROR (Status
)) {
768 GaugeData
= Perf
->GetGauge (Perf
, Handle
, Token
, Host
, NULL
);
770 return EFI_NOT_FOUND
;
773 GaugeData
->Handle
= HandleNew
;
774 if (HostNew
!= NULL
) {
775 EfiStrCpy (GaugeData
->Host
, HostNew
);
777 EfiStrCpy (GaugeData
->Host
, L
"");
780 if (TokenNew
!= NULL
) {
781 EfiStrCpy (GaugeData
->Token
, TokenNew
);
783 EfiStrCpy (GaugeData
->Token
, L
"");
792 IN EFI_HANDLE ImageHandle
,
793 IN EFI_SYSTEM_TABLE
*SystemTable
,
800 Transfer PEI performance data to gauge data node.
804 ImageHandle - Standard entry point parameter
805 SystemTable - Standard entry point parameter
810 EFI_OUT_OF_RESOURCES - No enough resource to create data node.
811 EFI_SUCCESS - Transfer done successfully.
817 EFI_HOB_GUID_DATA_PERFORMANCE_LOG
*LogHob
;
818 PEI_PERFORMANCE_MEASURE_LOG_ENTRY
*LogEntry
;
820 EFI_PERF_DATA_LIST
*Node
;
823 Node
= CreateDataNode (0, PEI_TOK
, NULL
);
825 return EFI_OUT_OF_RESOURCES
;
829 // Initialize 'LogHob' to NULL before usage.
836 GetTimerValue (&TimerValue
);
838 (Node
->GaugeData
).EndTick
= TimerValue
;
840 InsertTailList (&mPerfDataHead
, &(Node
->Link
));
842 EfiLibGetSystemConfigurationTable (&gEfiHobListGuid
, &HobList
);
844 Status
= GetNextGuidHob (&HobList
, &gEfiPeiPerformanceHobGuid
, (VOID
**) &LogHob
, NULL
);
845 if (EFI_ERROR (Status
) || (LogHob
== NULL
)) {
847 // Failed to get HOB for ProtocolGuid.
852 for (Index
= 0; Index
< LogHob
->NumberOfEntries
; Index
++) {
853 LogEntry
= &(LogHob
->Log
[Index
]);
854 Node
= CreateDataNode (0, LogEntry
->DescriptionString
, NULL
);
856 return EFI_OUT_OF_RESOURCES
;
858 (Node
->GaugeData
).StartTick
= LogEntry
->StartTimeCount
;
860 EfiCopyMem (&(Node
->GaugeData
.GuidName
), &LogEntry
->Name
, sizeof (EFI_GUID
));
862 InsertTailList (&mPerfDataHead
, &(Node
->Link
));
864 (Node
->GaugeData
).EndTick
= LogEntry
->StopTimeCount
;
866 } while (!EFI_ERROR (Status
));