1 /** @file
2   This file include the file which can help to get the system
3   performance, all the function will only include if the performance
4   switch is set.
5 
6 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution.  The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11 
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 #include "InternalBm.h"
18 
19 PERF_HEADER               mBmPerfHeader;
20 PERF_DATA                 mBmPerfData;
21 EFI_PHYSICAL_ADDRESS      mBmAcpiLowMemoryBase = 0x0FFFFFFFFULL;
22 
23 /**
24   Get the short verion of PDB file name to be
25   used in performance data logging.
26 
27   @param PdbFileName     The long PDB file name.
28   @param GaugeString     The output string to be logged by performance logger.
29   @param StringSize      The buffer size of GaugeString in bytes.
30 
31 **/
32 VOID
BmGetShortPdbFileName(IN CONST CHAR8 * PdbFileName,OUT CHAR8 * GaugeString,IN UINTN StringSize)33 BmGetShortPdbFileName (
34   IN  CONST CHAR8  *PdbFileName,
35   OUT       CHAR8  *GaugeString,
36   IN        UINTN   StringSize
37   )
38 {
39   UINTN Index;
40   UINTN Index1;
41   UINTN StartIndex;
42   UINTN EndIndex;
43 
44   if (PdbFileName == NULL) {
45     AsciiStrCpyS (GaugeString, StringSize, " ");
46   } else {
47     StartIndex = 0;
48     for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)
49       ;
50 
51     for (Index = 0; PdbFileName[Index] != 0; Index++) {
52       if (PdbFileName[Index] == '\\') {
53         StartIndex = Index + 1;
54       }
55 
56       if (PdbFileName[Index] == '.') {
57         EndIndex = Index;
58       }
59     }
60 
61     Index1 = 0;
62     for (Index = StartIndex; Index < EndIndex; Index++) {
63       GaugeString[Index1] = PdbFileName[Index];
64       Index1++;
65       if (Index1 == StringSize - 1) {
66         break;
67       }
68     }
69 
70     GaugeString[Index1] = 0;
71   }
72 
73   return ;
74 }
75 
76 /**
77   Get the name from the Driver handle, which can be a handle with
78   EFI_LOADED_IMAGE_PROTOCOL or EFI_DRIVER_BINDING_PROTOCOL installed.
79   This name can be used in performance data logging.
80 
81   @param Handle          Driver handle.
82   @param GaugeString     The output string to be logged by performance logger.
83   @param StringSize      The buffer size of GaugeString in bytes.
84 
85 **/
86 VOID
BmGetNameFromHandle(IN EFI_HANDLE Handle,OUT CHAR8 * GaugeString,IN UINTN StringSize)87 BmGetNameFromHandle (
88   IN  EFI_HANDLE     Handle,
89   OUT CHAR8          *GaugeString,
90   IN  UINTN          StringSize
91   )
92 {
93   EFI_STATUS                  Status;
94   EFI_LOADED_IMAGE_PROTOCOL   *Image;
95   CHAR8                       *PdbFileName;
96   EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
97 
98   AsciiStrCpyS (GaugeString, StringSize, " ");
99 
100   //
101   // Get handle name from image protocol
102   //
103   Status = gBS->HandleProtocol (
104                   Handle,
105                   &gEfiLoadedImageProtocolGuid,
106                   (VOID **) &Image
107                   );
108 
109   if (EFI_ERROR (Status)) {
110     Status = gBS->OpenProtocol (
111                     Handle,
112                     &gEfiDriverBindingProtocolGuid,
113                     (VOID **) &DriverBinding,
114                     NULL,
115                     NULL,
116                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
117                     );
118     if (EFI_ERROR (Status)) {
119       return ;
120     }
121     //
122     // Get handle name from image protocol
123     //
124     Status = gBS->HandleProtocol (
125                     DriverBinding->ImageHandle,
126                     &gEfiLoadedImageProtocolGuid,
127                     (VOID **) &Image
128                     );
129   }
130 
131   PdbFileName = PeCoffLoaderGetPdbPointer (Image->ImageBase);
132 
133   if (PdbFileName != NULL) {
134     BmGetShortPdbFileName (PdbFileName, GaugeString, StringSize);
135   }
136 
137   return ;
138 }
139 
140 /**
141 
142   Writes performance data of booting into the allocated memory.
143   OS can process these records.
144 
145   @param  Event                 The triggered event.
146   @param  Context               Context for this event.
147 
148 **/
149 VOID
150 EFIAPI
BmWriteBootToOsPerformanceData(IN EFI_EVENT Event,IN VOID * Context)151 BmWriteBootToOsPerformanceData (
152   IN EFI_EVENT  Event,
153   IN VOID       *Context
154   )
155 {
156   EFI_STATUS                Status;
157   UINT32                    LimitCount;
158   EFI_HANDLE                *Handles;
159   UINTN                     NoHandles;
160   CHAR8                     GaugeString[PERF_TOKEN_SIZE];
161   UINT8                     *Ptr;
162   UINT32                    Index;
163   UINT64                    Ticker;
164   UINT64                    Freq;
165   UINT32                    Duration;
166   UINTN                     LogEntryKey;
167   CONST VOID                *Handle;
168   CONST CHAR8               *Token;
169   CONST CHAR8               *Module;
170   UINT64                    StartTicker;
171   UINT64                    EndTicker;
172   UINT64                    StartValue;
173   UINT64                    EndValue;
174   BOOLEAN                   CountUp;
175   UINTN                     VarSize;
176   BOOLEAN                   Found;
177 
178   //
179   // Record the performance data for End of BDS
180   //
181   PERF_END(NULL, "BDS", NULL, 0);
182 
183   //
184   // Retrieve time stamp count as early as possible
185   //
186   Ticker  = GetPerformanceCounter ();
187 
188   Freq    = GetPerformanceCounterProperties (&StartValue, &EndValue);
189 
190   Freq    = DivU64x32 (Freq, 1000);
191 
192   mBmPerfHeader.CpuFreq = Freq;
193 
194   //
195   // Record BDS raw performance data
196   //
197   if (EndValue >= StartValue) {
198     mBmPerfHeader.BDSRaw = Ticker - StartValue;
199     CountUp            = TRUE;
200   } else {
201     mBmPerfHeader.BDSRaw = StartValue - Ticker;
202     CountUp            = FALSE;
203   }
204 
205   //
206   // Reset the entry count
207   //
208   mBmPerfHeader.Count = 0;
209 
210   if (mBmAcpiLowMemoryBase == 0x0FFFFFFFF) {
211     VarSize = sizeof (EFI_PHYSICAL_ADDRESS);
212     Status = gRT->GetVariable (
213                     L"PerfDataMemAddr",
214                     &gPerformanceProtocolGuid,
215                     NULL,
216                     &VarSize,
217                     &mBmAcpiLowMemoryBase
218                     );
219     if (EFI_ERROR (Status)) {
220       //
221       // Fail to get the variable, return.
222       //
223       return;
224     }
225   }
226 
227   //
228   // Put Detailed performance data into memory
229   //
230   Handles = NULL;
231   Status = gBS->LocateHandleBuffer (
232                   AllHandles,
233                   NULL,
234                   NULL,
235                   &NoHandles,
236                   &Handles
237                   );
238   if (EFI_ERROR (Status)) {
239     return ;
240   }
241 
242   Ptr        = (UINT8 *) ((UINT32) mBmAcpiLowMemoryBase + sizeof (PERF_HEADER));
243   LimitCount = (UINT32) (PERF_DATA_MAX_LENGTH - sizeof (PERF_HEADER)) / sizeof (PERF_DATA);
244 
245   //
246   // Get performance data
247   //
248   LogEntryKey = 0;
249   while ((LogEntryKey = GetPerformanceMeasurement (
250                           LogEntryKey,
251                           &Handle,
252                           &Token,
253                           &Module,
254                           &StartTicker,
255                           &EndTicker)) != 0) {
256     if (EndTicker != 0) {
257       if (StartTicker == 1) {
258         StartTicker = StartValue;
259       }
260       if (EndTicker == 1) {
261         EndTicker = StartValue;
262       }
263       Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker);
264 
265       Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);
266       if (Duration == 0) {
267         continue;
268       }
269 
270       ZeroMem (&mBmPerfData, sizeof (PERF_DATA));
271 
272       mBmPerfData.Duration = Duration;
273 
274       //
275       // See if the Handle is in the handle buffer
276       //
277       Found = FALSE;
278       for (Index = 0; Index < NoHandles; Index++) {
279         if (Handle == Handles[Index]) {
280           BmGetNameFromHandle (Handles[Index], GaugeString, PERF_TOKEN_SIZE);
281           AsciiStrCpyS (mBmPerfData.Token, PERF_TOKEN_SIZE, GaugeString);
282           Found = TRUE;
283           break;
284         }
285       }
286 
287       if (!Found) {
288         AsciiStrnCpyS (mBmPerfData.Token, PERF_TOKEN_SIZE, Token, PERF_TOKEN_LENGTH);
289       }
290 
291       CopyMem (Ptr, &mBmPerfData, sizeof (PERF_DATA));
292       Ptr += sizeof (PERF_DATA);
293 
294       mBmPerfHeader.Count++;
295       if (mBmPerfHeader.Count == LimitCount) {
296         goto Done;
297       }
298     }
299   }
300 
301 Done:
302 
303   FreePool (Handles);
304 
305   mBmPerfHeader.Signiture = PERFORMANCE_SIGNATURE;
306 
307   //
308   // Put performance data to Reserved memory
309   //
310   CopyMem (
311     (UINTN *) (UINTN) mBmAcpiLowMemoryBase,
312     &mBmPerfHeader,
313     sizeof (PERF_HEADER)
314     );
315 
316   return ;
317 }
318