1 /** @file
2   Performance Library used in SMM phase.
3 
4   This library instance provides infrastructure for SMM drivers to log performance
5   data. It consumes SMM PerformanceEx or Performance Protocol published by SmmCorePerformanceLib
6   to log performance data. If both SMM PerformanceEx and Performance Protocol are not available, it does not log any
7   performance information.
8 
9   Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>
10 This program and the accompanying materials
11 are licensed and made available under the terms and conditions of the BSD License
12 which accompanies this distribution.  The full text of the license may be found at
13 http://opensource.org/licenses/bsd-license.php
14 
15 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
16 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 
18 **/
19 
20 
21 #include <Guid/Performance.h>
22 
23 #include <Library/PerformanceLib.h>
24 #include <Library/DebugLib.h>
25 #include <Library/SmmServicesTableLib.h>
26 #include <Library/PcdLib.h>
27 #include <Library/BaseMemoryLib.h>
28 
29 //
30 // The cached SMM Performance Protocol and SMM PerformanceEx Protocol interface.
31 //
32 PERFORMANCE_PROTOCOL        *mPerformance = NULL;
33 PERFORMANCE_EX_PROTOCOL     *mPerformanceEx = NULL;
34 BOOLEAN                     mPerformanceMeasurementEnabled;
35 
36 /**
37   The constructor function initializes the Performance Measurement Enable flag
38 
39   @param  ImageHandle   The firmware allocated handle for the EFI image.
40   @param  SystemTable   A pointer to the EFI System Table.
41 
42   @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
43 
44 **/
45 EFI_STATUS
46 EFIAPI
SmmPerformanceLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)47 SmmPerformanceLibConstructor (
48   IN EFI_HANDLE        ImageHandle,
49   IN EFI_SYSTEM_TABLE  *SystemTable
50   )
51 {
52 
53   mPerformanceMeasurementEnabled =  (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
54 
55   return EFI_SUCCESS;
56 }
57 
58 /**
59   The function caches the pointers to SMM PerformanceEx protocol and Performance Protocol.
60 
61   The function locates SMM PerformanceEx protocol and Performance Protocol from protocol database.
62 
63   @retval EFI_SUCCESS     SMM PerformanceEx protocol or Performance Protocol is successfully located.
64   @retval EFI_NOT_FOUND   Both SMM PerformanceEx protocol and Performance Protocol are not located to log performance.
65 
66 **/
67 EFI_STATUS
GetPerformanceProtocol(VOID)68 GetPerformanceProtocol (
69   VOID
70   )
71 {
72   EFI_STATUS                Status;
73   PERFORMANCE_PROTOCOL      *Performance;
74   PERFORMANCE_EX_PROTOCOL   *PerformanceEx;
75 
76   if (mPerformanceEx != NULL || mPerformance != NULL) {
77     return EFI_SUCCESS;
78   }
79 
80   Status = gSmst->SmmLocateProtocol (&gSmmPerformanceExProtocolGuid, NULL, (VOID **) &PerformanceEx);
81   if (!EFI_ERROR (Status)) {
82     ASSERT (PerformanceEx != NULL);
83     //
84     // Cache PerformanceEx Protocol.
85     //
86     mPerformanceEx = PerformanceEx;
87     return EFI_SUCCESS;
88   }
89 
90   Status = gSmst->SmmLocateProtocol (&gSmmPerformanceProtocolGuid, NULL, (VOID **) &Performance);
91   if (!EFI_ERROR (Status)) {
92     ASSERT (Performance != NULL);
93     //
94     // Cache performance protocol.
95     //
96     mPerformance = Performance;
97     return EFI_SUCCESS;
98   }
99 
100   return EFI_NOT_FOUND;
101 }
102 
103 /**
104   Creates a record for the beginning of a performance measurement.
105 
106   Creates a record that contains the Handle, Token, Module and Identifier.
107   If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
108   If TimeStamp is zero, then this function reads the current time stamp
109   and adds that time stamp value to the record as the start time.
110 
111   @param  Handle                  Pointer to environment specific context used
112                                   to identify the component being measured.
113   @param  Token                   Pointer to a Null-terminated ASCII string
114                                   that identifies the component being measured.
115   @param  Module                  Pointer to a Null-terminated ASCII string
116                                   that identifies the module being measured.
117   @param  TimeStamp               64-bit time stamp.
118   @param  Identifier              32-bit identifier. If the value is 0, the created record
119                                   is same as the one created by StartPerformanceMeasurement.
120 
121   @retval RETURN_SUCCESS          The start of the measurement was recorded.
122   @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
123 
124 **/
125 RETURN_STATUS
126 EFIAPI
StartPerformanceMeasurementEx(IN CONST VOID * Handle,OPTIONAL IN CONST CHAR8 * Token,OPTIONAL IN CONST CHAR8 * Module,OPTIONAL IN UINT64 TimeStamp,IN UINT32 Identifier)127 StartPerformanceMeasurementEx (
128   IN CONST VOID   *Handle,  OPTIONAL
129   IN CONST CHAR8  *Token,   OPTIONAL
130   IN CONST CHAR8  *Module,  OPTIONAL
131   IN UINT64       TimeStamp,
132   IN UINT32       Identifier
133   )
134 {
135   EFI_STATUS  Status;
136 
137   Status = GetPerformanceProtocol ();
138   if (EFI_ERROR (Status)) {
139     return RETURN_OUT_OF_RESOURCES;
140   }
141 
142   if (mPerformanceEx != NULL) {
143     Status = mPerformanceEx->StartGaugeEx (Handle, Token, Module, TimeStamp, Identifier);
144   } else if (mPerformance != NULL) {
145     Status = mPerformance->StartGauge (Handle, Token, Module, TimeStamp);
146   } else {
147     ASSERT (FALSE);
148   }
149 
150   return (RETURN_STATUS) Status;
151 }
152 
153 /**
154   Fills in the end time of a performance measurement.
155 
156   Looks up the record that matches Handle, Token, Module and Identifier.
157   If the record can not be found then return RETURN_NOT_FOUND.
158   If the record is found and TimeStamp is not zero,
159   then TimeStamp is added to the record as the end time.
160   If the record is found and TimeStamp is zero, then this function reads
161   the current time stamp and adds that time stamp value to the record as the end time.
162 
163   @param  Handle                  Pointer to environment specific context used
164                                   to identify the component being measured.
165   @param  Token                   Pointer to a Null-terminated ASCII string
166                                   that identifies the component being measured.
167   @param  Module                  Pointer to a Null-terminated ASCII string
168                                   that identifies the module being measured.
169   @param  TimeStamp               64-bit time stamp.
170   @param  Identifier              32-bit identifier. If the value is 0, the found record
171                                   is same as the one found by EndPerformanceMeasurement.
172 
173   @retval RETURN_SUCCESS          The end of  the measurement was recorded.
174   @retval RETURN_NOT_FOUND        The specified measurement record could not be found.
175 
176 **/
177 RETURN_STATUS
178 EFIAPI
EndPerformanceMeasurementEx(IN CONST VOID * Handle,OPTIONAL IN CONST CHAR8 * Token,OPTIONAL IN CONST CHAR8 * Module,OPTIONAL IN UINT64 TimeStamp,IN UINT32 Identifier)179 EndPerformanceMeasurementEx (
180   IN CONST VOID   *Handle,  OPTIONAL
181   IN CONST CHAR8  *Token,   OPTIONAL
182   IN CONST CHAR8  *Module,  OPTIONAL
183   IN UINT64       TimeStamp,
184   IN UINT32       Identifier
185   )
186 {
187   EFI_STATUS  Status;
188 
189   Status = GetPerformanceProtocol ();
190   if (EFI_ERROR (Status)) {
191     return RETURN_NOT_FOUND;
192   }
193 
194   if (mPerformanceEx != NULL) {
195     Status = mPerformanceEx->EndGaugeEx (Handle, Token, Module, TimeStamp, Identifier);
196   } else if (mPerformance != NULL) {
197     Status = mPerformance->EndGauge (Handle, Token, Module, TimeStamp);
198   } else {
199     ASSERT (FALSE);
200   }
201 
202   return (RETURN_STATUS) Status;
203 }
204 
205 /**
206   Attempts to retrieve a performance measurement log entry from the performance measurement log.
207   It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
208   and then assign the Identifier with 0.
209 
210   Attempts to retrieve the performance log entry specified by LogEntryKey.  If LogEntryKey is
211   zero on entry, then an attempt is made to retrieve the first entry from the performance log,
212   and the key for the second entry in the log is returned.  If the performance log is empty,
213   then no entry is retrieved and zero is returned.  If LogEntryKey is not zero, then the performance
214   log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
215   returned.  If LogEntryKey is the key for the last entry in the log, then the last log entry is
216   retrieved and an implementation specific non-zero key value that specifies the end of the performance
217   log is returned.  If LogEntryKey is equal this implementation specific non-zero key value, then no entry
218   is retrieved and zero is returned.  In the cases where a performance log entry can be returned,
219   the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
220   If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
221   If Handle is NULL, then ASSERT().
222   If Token is NULL, then ASSERT().
223   If Module is NULL, then ASSERT().
224   If StartTimeStamp is NULL, then ASSERT().
225   If EndTimeStamp is NULL, then ASSERT().
226   If Identifier is NULL, then ASSERT().
227 
228   @param  LogEntryKey             On entry, the key of the performance measurement log entry to retrieve.
229                                   0, then the first performance measurement log entry is retrieved.
230                                   On exit, the key of the next performance log entry.
231   @param  Handle                  Pointer to environment specific context used to identify the component
232                                   being measured.
233   @param  Token                   Pointer to a Null-terminated ASCII string that identifies the component
234                                   being measured.
235   @param  Module                  Pointer to a Null-terminated ASCII string that identifies the module
236                                   being measured.
237   @param  StartTimeStamp          Pointer to the 64-bit time stamp that was recorded when the measurement
238                                   was started.
239   @param  EndTimeStamp            Pointer to the 64-bit time stamp that was recorded when the measurement
240                                   was ended.
241   @param  Identifier              Pointer to the 32-bit identifier that was recorded.
242 
243   @return The key for the next performance log entry (in general case).
244 
245 **/
246 UINTN
247 EFIAPI
GetPerformanceMeasurementEx(IN UINTN LogEntryKey,OUT CONST VOID ** Handle,OUT CONST CHAR8 ** Token,OUT CONST CHAR8 ** Module,OUT UINT64 * StartTimeStamp,OUT UINT64 * EndTimeStamp,OUT UINT32 * Identifier)248 GetPerformanceMeasurementEx (
249   IN  UINTN       LogEntryKey,
250   OUT CONST VOID  **Handle,
251   OUT CONST CHAR8 **Token,
252   OUT CONST CHAR8 **Module,
253   OUT UINT64      *StartTimeStamp,
254   OUT UINT64      *EndTimeStamp,
255   OUT UINT32      *Identifier
256   )
257 {
258   EFI_STATUS            Status;
259   GAUGE_DATA_ENTRY_EX   *GaugeData;
260 
261   GaugeData = NULL;
262 
263   ASSERT (Handle != NULL);
264   ASSERT (Token != NULL);
265   ASSERT (Module != NULL);
266   ASSERT (StartTimeStamp != NULL);
267   ASSERT (EndTimeStamp != NULL);
268   ASSERT (Identifier != NULL);
269 
270   Status = GetPerformanceProtocol ();
271   if (EFI_ERROR (Status)) {
272     return 0;
273   }
274 
275   if (mPerformanceEx != NULL) {
276     Status = mPerformanceEx->GetGaugeEx (LogEntryKey++, &GaugeData);
277   } else if (mPerformance != NULL) {
278     Status = mPerformance->GetGauge (LogEntryKey++, (GAUGE_DATA_ENTRY **) &GaugeData);
279   } else {
280     ASSERT (FALSE);
281     return 0;
282   }
283 
284   //
285   // Make sure that LogEntryKey is a valid log entry key,
286   //
287   ASSERT (Status != EFI_INVALID_PARAMETER);
288 
289   if (EFI_ERROR (Status)) {
290     //
291     // The LogEntryKey is the last entry (equals to the total entry number).
292     //
293     return 0;
294   }
295 
296   ASSERT (GaugeData != NULL);
297 
298   *Handle         = (VOID *) (UINTN) GaugeData->Handle;
299   *Token          = GaugeData->Token;
300   *Module         = GaugeData->Module;
301   *StartTimeStamp = GaugeData->StartTimeStamp;
302   *EndTimeStamp   = GaugeData->EndTimeStamp;
303   if (mPerformanceEx != NULL) {
304     *Identifier   = GaugeData->Identifier;
305   } else {
306     *Identifier   = 0;
307   }
308 
309   return LogEntryKey;
310 }
311 
312 /**
313   Creates a record for the beginning of a performance measurement.
314 
315   Creates a record that contains the Handle, Token, and Module.
316   If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
317   If TimeStamp is zero, then this function reads the current time stamp
318   and adds that time stamp value to the record as the start time.
319 
320   @param  Handle                  Pointer to environment specific context used
321                                   to identify the component being measured.
322   @param  Token                   Pointer to a Null-terminated ASCII string
323                                   that identifies the component being measured.
324   @param  Module                  Pointer to a Null-terminated ASCII string
325                                   that identifies the module being measured.
326   @param  TimeStamp               64-bit time stamp.
327 
328   @retval RETURN_SUCCESS          The start of the measurement was recorded.
329   @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
330 
331 **/
332 RETURN_STATUS
333 EFIAPI
StartPerformanceMeasurement(IN CONST VOID * Handle,OPTIONAL IN CONST CHAR8 * Token,OPTIONAL IN CONST CHAR8 * Module,OPTIONAL IN UINT64 TimeStamp)334 StartPerformanceMeasurement (
335   IN CONST VOID   *Handle,  OPTIONAL
336   IN CONST CHAR8  *Token,   OPTIONAL
337   IN CONST CHAR8  *Module,  OPTIONAL
338   IN UINT64       TimeStamp
339   )
340 {
341   return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
342 }
343 
344 /**
345   Fills in the end time of a performance measurement.
346 
347   Looks up the record that matches Handle, Token, and Module.
348   If the record can not be found then return RETURN_NOT_FOUND.
349   If the record is found and TimeStamp is not zero,
350   then TimeStamp is added to the record as the end time.
351   If the record is found and TimeStamp is zero, then this function reads
352   the current time stamp and adds that time stamp value to the record as the end time.
353 
354   @param  Handle                  Pointer to environment specific context used
355                                   to identify the component being measured.
356   @param  Token                   Pointer to a Null-terminated ASCII string
357                                   that identifies the component being measured.
358   @param  Module                  Pointer to a Null-terminated ASCII string
359                                   that identifies the module being measured.
360   @param  TimeStamp               64-bit time stamp.
361 
362   @retval RETURN_SUCCESS          The end of  the measurement was recorded.
363   @retval RETURN_NOT_FOUND        The specified measurement record could not be found.
364 
365 **/
366 RETURN_STATUS
367 EFIAPI
EndPerformanceMeasurement(IN CONST VOID * Handle,OPTIONAL IN CONST CHAR8 * Token,OPTIONAL IN CONST CHAR8 * Module,OPTIONAL IN UINT64 TimeStamp)368 EndPerformanceMeasurement (
369   IN CONST VOID   *Handle,  OPTIONAL
370   IN CONST CHAR8  *Token,   OPTIONAL
371   IN CONST CHAR8  *Module,  OPTIONAL
372   IN UINT64       TimeStamp
373   )
374 {
375   return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
376 }
377 
378 /**
379   Attempts to retrieve a performance measurement log entry from the performance measurement log.
380   It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
381   and then eliminate the Identifier.
382 
383   Attempts to retrieve the performance log entry specified by LogEntryKey.  If LogEntryKey is
384   zero on entry, then an attempt is made to retrieve the first entry from the performance log,
385   and the key for the second entry in the log is returned.  If the performance log is empty,
386   then no entry is retrieved and zero is returned.  If LogEntryKey is not zero, then the performance
387   log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
388   returned.  If LogEntryKey is the key for the last entry in the log, then the last log entry is
389   retrieved and an implementation specific non-zero key value that specifies the end of the performance
390   log is returned.  If LogEntryKey is equal this implementation specific non-zero key value, then no entry
391   is retrieved and zero is returned.  In the cases where a performance log entry can be returned,
392   the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
393   If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
394   If Handle is NULL, then ASSERT().
395   If Token is NULL, then ASSERT().
396   If Module is NULL, then ASSERT().
397   If StartTimeStamp is NULL, then ASSERT().
398   If EndTimeStamp is NULL, then ASSERT().
399 
400   @param  LogEntryKey             On entry, the key of the performance measurement log entry to retrieve.
401                                   0, then the first performance measurement log entry is retrieved.
402                                   On exit, the key of the next performance log entry.
403   @param  Handle                  Pointer to environment specific context used to identify the component
404                                   being measured.
405   @param  Token                   Pointer to a Null-terminated ASCII string that identifies the component
406                                   being measured.
407   @param  Module                  Pointer to a Null-terminated ASCII string that identifies the module
408                                   being measured.
409   @param  StartTimeStamp          Pointer to the 64-bit time stamp that was recorded when the measurement
410                                   was started.
411   @param  EndTimeStamp            Pointer to the 64-bit time stamp that was recorded when the measurement
412                                   was ended.
413 
414   @return The key for the next performance log entry (in general case).
415 
416 **/
417 UINTN
418 EFIAPI
GetPerformanceMeasurement(IN UINTN LogEntryKey,OUT CONST VOID ** Handle,OUT CONST CHAR8 ** Token,OUT CONST CHAR8 ** Module,OUT UINT64 * StartTimeStamp,OUT UINT64 * EndTimeStamp)419 GetPerformanceMeasurement (
420   IN  UINTN       LogEntryKey,
421   OUT CONST VOID  **Handle,
422   OUT CONST CHAR8 **Token,
423   OUT CONST CHAR8 **Module,
424   OUT UINT64      *StartTimeStamp,
425   OUT UINT64      *EndTimeStamp
426   )
427 {
428   UINT32 Identifier;
429   return GetPerformanceMeasurementEx (LogEntryKey, Handle, Token, Module, StartTimeStamp, EndTimeStamp, &Identifier);
430 }
431 
432 /**
433   Returns TRUE if the performance measurement macros are enabled.
434 
435   This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
436   PcdPerformanceLibraryPropertyMask is set.  Otherwise FALSE is returned.
437 
438   @retval TRUE                    The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
439                                   PcdPerformanceLibraryPropertyMask is set.
440   @retval FALSE                   The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
441                                   PcdPerformanceLibraryPropertyMask is clear.
442 
443 **/
444 BOOLEAN
445 EFIAPI
PerformanceMeasurementEnabled(VOID)446 PerformanceMeasurementEnabled (
447   VOID
448   )
449 {
450   return mPerformanceMeasurementEnabled;
451 }
452