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
594 InitializePerformanceInfrastructure (
595 IN EFI_HANDLE ImageHandle
,
596 IN EFI_SYSTEM_TABLE
*SystemTable
,
603 Install gEfiPerformanceProtocolGuid protocol and transfer PEI performance to gauge data nodes.
607 ImageHandle - Standard driver entry point parameter
608 SystemTable - Standard driver entry point parameter
609 Ticker - End tick for PEI performance
613 EFI_OUT_OF_RESOURCES - No enough buffer to allocate
614 EFI_SUCCESS - Protocol installed.
619 EFI_PERFORMANCE_INSTANCE
*PerfInstance
;
622 // Allocate a new image structure
624 PerfInstance
= EfiLibAllocateZeroPool (sizeof (EFI_PERFORMANCE_INSTANCE
));
625 if (PerfInstance
== NULL
) {
626 return EFI_OUT_OF_RESOURCES
;
629 PerfInstance
->Signature
= EFI_PERFORMANCE_SIGNATURE
;
630 PerfInstance
->Perf
.StartGauge
= StartGauge
;
631 PerfInstance
->Perf
.EndGauge
= EndGauge
;
632 PerfInstance
->Perf
.GetGauge
= GetGauge
;
635 // Install the protocol interfaces
637 Status
= gBS
->InstallProtocolInterface (
638 &PerfInstance
->Handle
,
639 &gEfiPerformanceProtocolGuid
,
640 EFI_NATIVE_INTERFACE
,
644 if (!EFI_ERROR (Status
)) {
645 GetPeiPerformance (ImageHandle
, SystemTable
, Ticker
);
664 Start to gauge on a specified handle, token and host, with Ticker as start tick.
668 Handle - Handle to measure
669 Token - Token to measure
670 Host - Host to measure
671 Ticker - Ticker as start tick
680 EFI_PERFORMANCE_PROTOCOL
*Perf
;
682 Status
= gBS
->LocateProtocol (&gEfiPerformanceProtocolGuid
, NULL
, (VOID
**) &Perf
);
683 if (EFI_ERROR (Status
)) {
687 return Perf
->StartGauge (Perf
, Handle
, Token
, Host
, Ticker
);
704 End gauging on a specified handle, token and host, with Ticker as end tick.
708 Handle - Handle to stop
709 Token - Token to stop
711 Ticker - Ticker as end tick
720 EFI_PERFORMANCE_PROTOCOL
*Perf
;
722 Status
= gBS
->LocateProtocol (&gEfiPerformanceProtocolGuid
, NULL
, (VOID
**) &Perf
);
723 if (Status
!= EFI_SUCCESS
) {
727 return (Perf
->EndGauge( Perf
, Handle
, Token
, Host
, Ticker
)) ;
737 EFI_HANDLE HandleNew
,
747 Handle - A pointer of an efi handle.
748 Token - A pointer to the token.
749 Host - A pointer to the host.
750 HandleNew - A pointer of an new efi handle.
751 TokenNew - A pointer to the new token.
752 HostNew - A pointer to the new host.
757 EFI_NOT_FOUND - The speicified gauge data node not found.
759 EFI_SUCCESS - Update successfully.
764 EFI_GAUGE_DATA
*GaugeData
;
765 EFI_PERFORMANCE_PROTOCOL
*Perf
;
767 Status
= gBS
->LocateProtocol (&gEfiPerformanceProtocolGuid
, NULL
, (VOID
**) &Perf
);
768 if (EFI_ERROR (Status
)) {
772 GaugeData
= Perf
->GetGauge (Perf
, Handle
, Token
, Host
, NULL
);
774 return EFI_NOT_FOUND
;
777 GaugeData
->Handle
= HandleNew
;
778 if (HostNew
!= NULL
) {
779 EfiStrCpy (GaugeData
->Host
, HostNew
);
781 EfiStrCpy (GaugeData
->Host
, L
"");
784 if (TokenNew
!= NULL
) {
785 EfiStrCpy (GaugeData
->Token
, TokenNew
);
787 EfiStrCpy (GaugeData
->Token
, L
"");
796 IN EFI_HANDLE ImageHandle
,
797 IN EFI_SYSTEM_TABLE
*SystemTable
,
804 Transfer PEI performance data to gauge data node.
808 ImageHandle - Standard entry point parameter
809 SystemTable - Standard entry point parameter
814 EFI_OUT_OF_RESOURCES - No enough resource to create data node.
815 EFI_SUCCESS - Transfer done successfully.
821 EFI_HOB_GUID_DATA_PERFORMANCE_LOG
*LogHob
;
822 PEI_PERFORMANCE_MEASURE_LOG_ENTRY
*LogEntry
;
824 EFI_PERF_DATA_LIST
*Node
;
827 Node
= CreateDataNode (0, PEI_TOK
, NULL
);
829 return EFI_OUT_OF_RESOURCES
;
833 // Initialize 'LogHob' to NULL before usage.
840 GetTimerValue (&TimerValue
);
842 (Node
->GaugeData
).EndTick
= TimerValue
;
844 InsertTailList (&mPerfDataHead
, &(Node
->Link
));
846 EfiLibGetSystemConfigurationTable (&gEfiHobListGuid
, &HobList
);
848 Status
= GetNextGuidHob (&HobList
, &gEfiPeiPerformanceHobGuid
, (VOID
**) &LogHob
, NULL
);
849 if (EFI_ERROR (Status
) || (LogHob
== NULL
)) {
851 // Failed to get HOB for ProtocolGuid.
856 for (Index
= 0; Index
< LogHob
->NumberOfEntries
; Index
++) {
857 LogEntry
= &(LogHob
->Log
[Index
]);
858 Node
= CreateDataNode (0, LogEntry
->DescriptionString
, NULL
);
860 return EFI_OUT_OF_RESOURCES
;
862 (Node
->GaugeData
).StartTick
= LogEntry
->StartTimeCount
;
864 EfiCopyMem (&(Node
->GaugeData
.GuidName
), &LogEntry
->Name
, sizeof (EFI_GUID
));
866 InsertTailList (&mPerfDataHead
, &(Node
->Link
));
868 (Node
->GaugeData
).EndTick
= LogEntry
->StopTimeCount
;
870 } while (!EFI_ERROR (Status
));