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 - 2016, 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 and Module.
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