]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c
Optimize the log entry search algorithm to save boot performance.
[mirror_edk2.git] / MdeModulePkg / Library / SmmCorePerformanceLib / SmmCorePerformanceLib.c
1 /** @file
2 Performance library instance used by SMM Core.
3
4 This library provides the performance measurement interfaces and initializes performance
5 logging for the SMM phase.
6 It initializes SMM phase performance logging by publishing the SMM Performance and PerformanceEx Protocol,
7 which is consumed by SmmPerformanceLib to logging performance data in SMM phase.
8
9 This library is mainly used by SMM Core to start performance logging to ensure that
10 SMM Performance and PerformanceEx Protocol are installed at the very beginning of SMM phase.
11
12 Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>
13 This program and the accompanying materials
14 are licensed and made available under the terms and conditions of the BSD License
15 which accompanies this distribution. The full text of the license may be found at
16 http://opensource.org/licenses/bsd-license.php
17
18 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
19 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20
21 **/
22
23
24 #include "SmmCorePerformanceLibInternal.h"
25
26 //
27 // The data structure to hold global performance data.
28 //
29 GAUGE_DATA_HEADER *mGaugeData;
30
31 //
32 // The current maximum number of logging entries. If current number of
33 // entries exceeds this value, it will re-allocate a larger array and
34 // migration the old data to the larger array.
35 //
36 UINT32 mMaxGaugeRecords;
37
38 //
39 // The handle to install Performance Protocol instance.
40 //
41 EFI_HANDLE mHandle = NULL;
42
43 BOOLEAN mPerformanceMeasurementEnabled;
44
45 SPIN_LOCK mSmmPerfLock;
46
47 EFI_SMRAM_DESCRIPTOR *mSmramRanges;
48 UINTN mSmramRangeCount;
49
50 //
51 // Interfaces for SMM Performance Protocol.
52 //
53 PERFORMANCE_PROTOCOL mPerformanceInterface = {
54 StartGauge,
55 EndGauge,
56 GetGauge
57 };
58
59 //
60 // Interfaces for SMM PerformanceEx Protocol.
61 //
62 PERFORMANCE_EX_PROTOCOL mPerformanceExInterface = {
63 StartGaugeEx,
64 EndGaugeEx,
65 GetGaugeEx
66 };
67
68 /**
69 Searches in the gauge array with keyword Handle, Token, Module and Identfier.
70
71 This internal function searches for the gauge entry in the gauge array.
72 If there is an entry that exactly matches the given keywords
73 and its end time stamp is zero, then the index of that gauge entry is returned;
74 otherwise, the the number of gauge entries in the array is returned.
75
76 @param Handle Pointer to environment specific context used
77 to identify the component being measured.
78 @param Token Pointer to a Null-terminated ASCII string
79 that identifies the component being measured.
80 @param Module Pointer to a Null-terminated ASCII string
81 that identifies the module being measured.
82 @param Identifier 32-bit identifier.
83
84 @retval The index of gauge entry in the array.
85
86 **/
87 UINT32
88 SmmSearchForGaugeEntry (
89 IN CONST VOID *Handle, OPTIONAL
90 IN CONST CHAR8 *Token, OPTIONAL
91 IN CONST CHAR8 *Module, OPTIONAL
92 IN CONST UINT32 Identifier
93 )
94 {
95 UINT32 Index;
96 UINT32 Index2;
97 UINT32 NumberOfEntries;
98 GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
99
100 if (Token == NULL) {
101 Token = "";
102 }
103 if (Module == NULL) {
104 Module = "";
105 }
106
107 NumberOfEntries = mGaugeData->NumberOfEntries;
108 GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
109
110 Index2 = 0;
111
112 for (Index = 0; Index < NumberOfEntries; Index++) {
113 Index2 = NumberOfEntries - 1 - Index;
114 if (GaugeEntryExArray[Index2].EndTimeStamp == 0 &&
115 (GaugeEntryExArray[Index2].Handle == (EFI_PHYSICAL_ADDRESS) (UINTN) Handle) &&
116 AsciiStrnCmp (GaugeEntryExArray[Index2].Token, Token, SMM_PERFORMANCE_STRING_LENGTH) == 0 &&
117 AsciiStrnCmp (GaugeEntryExArray[Index2].Module, Module, SMM_PERFORMANCE_STRING_LENGTH) == 0 &&
118 (GaugeEntryExArray[Index2].Identifier == Identifier)) {
119 Index = Index2;
120 break;
121 }
122 }
123
124 return Index;
125 }
126
127 /**
128 Adds a record at the end of the performance measurement log
129 that records the start time of a performance measurement.
130
131 Adds a record to the end of the performance measurement log
132 that contains the Handle, Token, Module and Identifier.
133 The end time of the new record must be set to zero.
134 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
135 If TimeStamp is zero, the start time in the record is filled in with the value
136 read from the current time stamp.
137
138 @param Handle Pointer to environment specific context used
139 to identify the component being measured.
140 @param Token Pointer to a Null-terminated ASCII string
141 that identifies the component being measured.
142 @param Module Pointer to a Null-terminated ASCII string
143 that identifies the module being measured.
144 @param TimeStamp 64-bit time stamp.
145 @param Identifier 32-bit identifier. If the value is 0, the created record
146 is same as the one created by StartGauge of PERFORMANCE_PROTOCOL.
147
148 @retval EFI_SUCCESS The data was read correctly from the device.
149 @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement.
150
151 **/
152 EFI_STATUS
153 EFIAPI
154 StartGaugeEx (
155 IN CONST VOID *Handle, OPTIONAL
156 IN CONST CHAR8 *Token, OPTIONAL
157 IN CONST CHAR8 *Module, OPTIONAL
158 IN UINT64 TimeStamp,
159 IN UINT32 Identifier
160 )
161 {
162 GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
163 UINTN GaugeDataSize;
164 GAUGE_DATA_HEADER *NewGaugeData;
165 UINTN OldGaugeDataSize;
166 GAUGE_DATA_HEADER *OldGaugeData;
167 UINT32 Index;
168
169 AcquireSpinLock (&mSmmPerfLock);
170
171 Index = mGaugeData->NumberOfEntries;
172 if (Index >= mMaxGaugeRecords) {
173 //
174 // Try to enlarge the scale of gauge array.
175 //
176 OldGaugeData = mGaugeData;
177 OldGaugeDataSize = sizeof (GAUGE_DATA_HEADER) + sizeof (GAUGE_DATA_ENTRY_EX) * mMaxGaugeRecords;
178
179 GaugeDataSize = sizeof (GAUGE_DATA_HEADER) + sizeof (GAUGE_DATA_ENTRY_EX) * mMaxGaugeRecords * 2;
180
181 NewGaugeData = AllocateZeroPool (GaugeDataSize);
182 if (NewGaugeData == NULL) {
183 ReleaseSpinLock (&mSmmPerfLock);
184 return EFI_OUT_OF_RESOURCES;
185 }
186
187 mGaugeData = NewGaugeData;
188 mMaxGaugeRecords *= 2;
189
190 //
191 // Initialize new data array and migrate old data one.
192 //
193 mGaugeData = CopyMem (mGaugeData, OldGaugeData, OldGaugeDataSize);
194
195 FreePool (OldGaugeData);
196 }
197
198 GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
199 GaugeEntryExArray[Index].Handle = (EFI_PHYSICAL_ADDRESS) (UINTN) Handle;
200
201 if (Token != NULL) {
202 AsciiStrnCpy (GaugeEntryExArray[Index].Token, Token, SMM_PERFORMANCE_STRING_LENGTH);
203 }
204 if (Module != NULL) {
205 AsciiStrnCpy (GaugeEntryExArray[Index].Module, Module, SMM_PERFORMANCE_STRING_LENGTH);
206 }
207
208 GaugeEntryExArray[Index].EndTimeStamp = 0;
209 GaugeEntryExArray[Index].Identifier = Identifier;
210
211 if (TimeStamp == 0) {
212 TimeStamp = GetPerformanceCounter ();
213 }
214 GaugeEntryExArray[Index].StartTimeStamp = TimeStamp;
215
216 mGaugeData->NumberOfEntries++;
217
218 ReleaseSpinLock (&mSmmPerfLock);
219
220 return EFI_SUCCESS;
221 }
222
223 /**
224 Searches the performance measurement log from the beginning of the log
225 for the first matching record that contains a zero end time and fills in a valid end time.
226
227 Searches the performance measurement log from the beginning of the log
228 for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.
229 If the record can not be found then return EFI_NOT_FOUND.
230 If the record is found and TimeStamp is not zero,
231 then the end time in the record is filled in with the value specified by TimeStamp.
232 If the record is found and TimeStamp is zero, then the end time in the matching record
233 is filled in with the current time stamp value.
234
235 @param Handle Pointer to environment specific context used
236 to identify the component being measured.
237 @param Token Pointer to a Null-terminated ASCII string
238 that identifies the component being measured.
239 @param Module Pointer to a Null-terminated ASCII string
240 that identifies the module being measured.
241 @param TimeStamp 64-bit time stamp.
242 @param Identifier 32-bit identifier. If the value is 0, the found record
243 is same as the one found by EndGauge of PERFORMANCE_PROTOCOL.
244
245 @retval EFI_SUCCESS The end of the measurement was recorded.
246 @retval EFI_NOT_FOUND The specified measurement record could not be found.
247
248 **/
249 EFI_STATUS
250 EFIAPI
251 EndGaugeEx (
252 IN CONST VOID *Handle, OPTIONAL
253 IN CONST CHAR8 *Token, OPTIONAL
254 IN CONST CHAR8 *Module, OPTIONAL
255 IN UINT64 TimeStamp,
256 IN UINT32 Identifier
257 )
258 {
259 GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
260 UINT32 Index;
261
262 AcquireSpinLock (&mSmmPerfLock);
263
264 if (TimeStamp == 0) {
265 TimeStamp = GetPerformanceCounter ();
266 }
267
268 Index = SmmSearchForGaugeEntry (Handle, Token, Module, Identifier);
269 if (Index >= mGaugeData->NumberOfEntries) {
270 ReleaseSpinLock (&mSmmPerfLock);
271 return EFI_NOT_FOUND;
272 }
273 GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
274 GaugeEntryExArray[Index].EndTimeStamp = TimeStamp;
275
276 ReleaseSpinLock (&mSmmPerfLock);
277
278 return EFI_SUCCESS;
279 }
280
281 /**
282 Retrieves a previously logged performance measurement.
283 It can also retrieve the log created by StartGauge and EndGauge of PERFORMANCE_PROTOCOL,
284 and then assign the Identifier with 0.
285
286 Retrieves the performance log entry from the performance log specified by LogEntryKey.
287 If it stands for a valid entry, then EFI_SUCCESS is returned and
288 GaugeDataEntryEx stores the pointer to that entry.
289
290 @param LogEntryKey The key for the previous performance measurement log entry.
291 If 0, then the first performance measurement log entry is retrieved.
292 @param GaugeDataEntryEx The indirect pointer to the extended gauge data entry specified by LogEntryKey
293 if the retrieval is successful.
294
295 @retval EFI_SUCCESS The GuageDataEntryEx is successfully found based on LogEntryKey.
296 @retval EFI_NOT_FOUND The LogEntryKey is the last entry (equals to the total entry number).
297 @retval EFI_INVALIDE_PARAMETER The LogEntryKey is not a valid entry (greater than the total entry number).
298 @retval EFI_INVALIDE_PARAMETER GaugeDataEntryEx is NULL.
299
300 **/
301 EFI_STATUS
302 EFIAPI
303 GetGaugeEx (
304 IN UINTN LogEntryKey,
305 OUT GAUGE_DATA_ENTRY_EX **GaugeDataEntryEx
306 )
307 {
308 UINTN NumberOfEntries;
309 GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
310
311 NumberOfEntries = (UINTN) (mGaugeData->NumberOfEntries);
312 if (LogEntryKey > NumberOfEntries) {
313 return EFI_INVALID_PARAMETER;
314 }
315 if (LogEntryKey == NumberOfEntries) {
316 return EFI_NOT_FOUND;
317 }
318
319 GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
320
321 if (GaugeDataEntryEx == NULL) {
322 return EFI_INVALID_PARAMETER;
323 }
324 *GaugeDataEntryEx = &GaugeEntryExArray[LogEntryKey];
325
326 return EFI_SUCCESS;
327 }
328
329 /**
330 Adds a record at the end of the performance measurement log
331 that records the start time of a performance measurement.
332
333 Adds a record to the end of the performance measurement log
334 that contains the Handle, Token, and Module.
335 The end time of the new record must be set to zero.
336 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
337 If TimeStamp is zero, the start time in the record is filled in with the value
338 read from the current time stamp.
339
340 @param Handle Pointer to environment specific context used
341 to identify the component being measured.
342 @param Token Pointer to a Null-terminated ASCII string
343 that identifies the component being measured.
344 @param Module Pointer to a Null-terminated ASCII string
345 that identifies the module being measured.
346 @param TimeStamp 64-bit time stamp.
347
348 @retval EFI_SUCCESS The data was read correctly from the device.
349 @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement.
350
351 **/
352 EFI_STATUS
353 EFIAPI
354 StartGauge (
355 IN CONST VOID *Handle, OPTIONAL
356 IN CONST CHAR8 *Token, OPTIONAL
357 IN CONST CHAR8 *Module, OPTIONAL
358 IN UINT64 TimeStamp
359 )
360 {
361 return StartGaugeEx (Handle, Token, Module, TimeStamp, 0);
362 }
363
364 /**
365 Searches the performance measurement log from the beginning of the log
366 for the first matching record that contains a zero end time and fills in a valid end time.
367
368 Searches the performance measurement log from the beginning of the log
369 for the first record that matches Handle, Token, and Module and has an end time value of zero.
370 If the record can not be found then return EFI_NOT_FOUND.
371 If the record is found and TimeStamp is not zero,
372 then the end time in the record is filled in with the value specified by TimeStamp.
373 If the record is found and TimeStamp is zero, then the end time in the matching record
374 is filled in with the current time stamp value.
375
376 @param Handle Pointer to environment specific context used
377 to identify the component being measured.
378 @param Token Pointer to a Null-terminated ASCII string
379 that identifies the component being measured.
380 @param Module Pointer to a Null-terminated ASCII string
381 that identifies the module being measured.
382 @param TimeStamp 64-bit time stamp.
383
384 @retval EFI_SUCCESS The end of the measurement was recorded.
385 @retval EFI_NOT_FOUND The specified measurement record could not be found.
386
387 **/
388 EFI_STATUS
389 EFIAPI
390 EndGauge (
391 IN CONST VOID *Handle, OPTIONAL
392 IN CONST CHAR8 *Token, OPTIONAL
393 IN CONST CHAR8 *Module, OPTIONAL
394 IN UINT64 TimeStamp
395 )
396 {
397 return EndGaugeEx (Handle, Token, Module, TimeStamp, 0);
398 }
399
400 /**
401 Retrieves a previously logged performance measurement.
402 It can also retrieve the log created by StartGaugeEx and EndGaugeEx of PERFORMANCE_EX_PROTOCOL,
403 and then eliminate the Identifier.
404
405 Retrieves the performance log entry from the performance log specified by LogEntryKey.
406 If it stands for a valid entry, then EFI_SUCCESS is returned and
407 GaugeDataEntry stores the pointer to that entry.
408
409 @param LogEntryKey The key for the previous performance measurement log entry.
410 If 0, then the first performance measurement log entry is retrieved.
411 @param GaugeDataEntry The indirect pointer to the gauge data entry specified by LogEntryKey
412 if the retrieval is successful.
413
414 @retval EFI_SUCCESS The GuageDataEntry is successfully found based on LogEntryKey.
415 @retval EFI_NOT_FOUND The LogEntryKey is the last entry (equals to the total entry number).
416 @retval EFI_INVALIDE_PARAMETER The LogEntryKey is not a valid entry (greater than the total entry number).
417 @retval EFI_INVALIDE_PARAMETER GaugeDataEntry is NULL.
418
419 **/
420 EFI_STATUS
421 EFIAPI
422 GetGauge (
423 IN UINTN LogEntryKey,
424 OUT GAUGE_DATA_ENTRY **GaugeDataEntry
425 )
426 {
427 EFI_STATUS Status;
428 GAUGE_DATA_ENTRY_EX *GaugeEntryEx;
429
430 GaugeEntryEx = NULL;
431
432 Status = GetGaugeEx (LogEntryKey, &GaugeEntryEx);
433 if (EFI_ERROR (Status)) {
434 return Status;
435 }
436
437 if (GaugeDataEntry == NULL) {
438 return EFI_INVALID_PARAMETER;
439 }
440
441 *GaugeDataEntry = (GAUGE_DATA_ENTRY *) GaugeEntryEx;
442
443 return EFI_SUCCESS;
444 }
445
446 /**
447 This function check if the address is in SMRAM.
448
449 @param Buffer the buffer address to be checked.
450 @param Length the buffer length to be checked.
451
452 @retval TRUE this address is in SMRAM.
453 @retval FALSE this address is NOT in SMRAM.
454 **/
455 BOOLEAN
456 IsAddressInSmram (
457 IN EFI_PHYSICAL_ADDRESS Buffer,
458 IN UINT64 Length
459 )
460 {
461 UINTN Index;
462
463 for (Index = 0; Index < mSmramRangeCount; Index ++) {
464 if (((Buffer >= mSmramRanges[Index].CpuStart) && (Buffer < mSmramRanges[Index].CpuStart + mSmramRanges[Index].PhysicalSize)) ||
465 ((mSmramRanges[Index].CpuStart >= Buffer) && (mSmramRanges[Index].CpuStart < Buffer + Length))) {
466 return TRUE;
467 }
468 }
469
470 return FALSE;
471 }
472
473 /**
474 Communication service SMI Handler entry.
475
476 This SMI handler provides services for the performance wrapper driver.
477
478 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
479 @param[in] RegisterContext Points to an optional handler context which was specified when the
480 handler was registered.
481 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
482 be conveyed from a non-SMM environment into an SMM environment.
483 @param[in, out] CommBufferSize The size of the CommBuffer.
484
485 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
486 should still be called.
487 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
488 still be called.
489 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
490 be called.
491 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
492 **/
493 EFI_STATUS
494 EFIAPI
495 SmmPerformanceHandlerEx (
496 IN EFI_HANDLE DispatchHandle,
497 IN CONST VOID *RegisterContext,
498 IN OUT VOID *CommBuffer,
499 IN OUT UINTN *CommBufferSize
500 )
501 {
502 EFI_STATUS Status;
503 SMM_PERF_COMMUNICATE_EX *SmmPerfCommData;
504 GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
505 UINTN DataSize;
506
507 GaugeEntryExArray = NULL;
508
509 ASSERT (CommBuffer != NULL);
510
511 SmmPerfCommData = (SMM_PERF_COMMUNICATE_EX *)CommBuffer;
512
513 switch (SmmPerfCommData->Function) {
514 case SMM_PERF_FUNCTION_GET_GAUGE_ENTRY_NUMBER :
515 SmmPerfCommData->NumberOfEntries = mGaugeData->NumberOfEntries;
516 Status = EFI_SUCCESS;
517 break;
518
519 case SMM_PERF_FUNCTION_GET_GAUGE_DATA :
520 if ( SmmPerfCommData->GaugeDataEx == NULL || SmmPerfCommData->NumberOfEntries == 0 ||
521 (SmmPerfCommData->LogEntryKey + SmmPerfCommData->NumberOfEntries) > mGaugeData->NumberOfEntries) {
522 Status = EFI_INVALID_PARAMETER;
523 break;
524 }
525
526 //
527 // Sanity check
528 //
529 DataSize = SmmPerfCommData->NumberOfEntries * sizeof(GAUGE_DATA_ENTRY_EX);
530 if (IsAddressInSmram ((EFI_PHYSICAL_ADDRESS)(UINTN)SmmPerfCommData->GaugeDataEx, DataSize)) {
531 DEBUG ((EFI_D_ERROR, "Smm Performance Data buffer is in SMRAM!\n"));
532 Status = EFI_ACCESS_DENIED;
533 break ;
534 }
535
536 GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
537 CopyMem(
538 (UINT8 *) (SmmPerfCommData->GaugeDataEx),
539 (UINT8 *) &GaugeEntryExArray[SmmPerfCommData->LogEntryKey],
540 DataSize
541 );
542 Status = EFI_SUCCESS;
543 break;
544
545 default:
546 ASSERT (FALSE);
547 Status = EFI_UNSUPPORTED;
548 }
549
550 SmmPerfCommData->ReturnStatus = Status;
551 return EFI_SUCCESS;
552 }
553
554 /**
555 Communication service SMI Handler entry.
556
557 This SMI handler provides services for the performance wrapper driver.
558
559 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
560 @param[in] RegisterContext Points to an optional handler context which was specified when the
561 handler was registered.
562 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
563 be conveyed from a non-SMM environment into an SMM environment.
564 @param[in, out] CommBufferSize The size of the CommBuffer.
565
566 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
567 should still be called.
568 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
569 still be called.
570 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
571 be called.
572 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
573 **/
574 EFI_STATUS
575 EFIAPI
576 SmmPerformanceHandler (
577 IN EFI_HANDLE DispatchHandle,
578 IN CONST VOID *RegisterContext,
579 IN OUT VOID *CommBuffer,
580 IN OUT UINTN *CommBufferSize
581 )
582 {
583 EFI_STATUS Status;
584 SMM_PERF_COMMUNICATE *SmmPerfCommData;
585 GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
586 UINTN DataSize;
587 UINTN Index;
588 UINTN LogEntryKey;
589
590 GaugeEntryExArray = NULL;
591
592 ASSERT (CommBuffer != NULL);
593
594 SmmPerfCommData = (SMM_PERF_COMMUNICATE *)CommBuffer;
595
596 switch (SmmPerfCommData->Function) {
597 case SMM_PERF_FUNCTION_GET_GAUGE_ENTRY_NUMBER :
598 SmmPerfCommData->NumberOfEntries = mGaugeData->NumberOfEntries;
599 Status = EFI_SUCCESS;
600 break;
601
602 case SMM_PERF_FUNCTION_GET_GAUGE_DATA :
603 if ( SmmPerfCommData->GaugeData == NULL || SmmPerfCommData->NumberOfEntries == 0 ||
604 (SmmPerfCommData->LogEntryKey + SmmPerfCommData->NumberOfEntries) > mGaugeData->NumberOfEntries) {
605 Status = EFI_INVALID_PARAMETER;
606 break;
607 }
608
609 //
610 // Sanity check
611 //
612 DataSize = SmmPerfCommData->NumberOfEntries * sizeof(GAUGE_DATA_ENTRY);
613 if (IsAddressInSmram ((EFI_PHYSICAL_ADDRESS)(UINTN)SmmPerfCommData->GaugeData, DataSize)) {
614 DEBUG ((EFI_D_ERROR, "Smm Performance Data buffer is in SMRAM!\n"));
615 Status = EFI_ACCESS_DENIED;
616 break ;
617 }
618
619 GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
620
621 LogEntryKey = SmmPerfCommData->LogEntryKey;
622 for (Index = 0; Index < SmmPerfCommData->NumberOfEntries; Index++) {
623 CopyMem(
624 (UINT8 *) &(SmmPerfCommData->GaugeData[Index]),
625 (UINT8 *) &GaugeEntryExArray[LogEntryKey++],
626 sizeof (GAUGE_DATA_ENTRY)
627 );
628 }
629 Status = EFI_SUCCESS;
630 break;
631
632 default:
633 ASSERT (FALSE);
634 Status = EFI_UNSUPPORTED;
635 }
636
637 SmmPerfCommData->ReturnStatus = Status;
638 return EFI_SUCCESS;
639 }
640
641 /**
642 SmmBase2 protocol notify callback function, when SMST and SMM memory service get initialized
643 this function is callbacked to initialize the Smm Performance Lib
644
645 @param Event The event of notify protocol.
646 @param Context Notify event context.
647
648 **/
649 VOID
650 EFIAPI
651 InitializeSmmCorePerformanceLib (
652 IN EFI_EVENT Event,
653 IN VOID *Context
654 )
655 {
656 EFI_STATUS Status;
657 EFI_HANDLE Handle;
658 EFI_SMM_ACCESS2_PROTOCOL *SmmAccess;
659 UINTN Size;
660
661
662 //
663 // Initialize spin lock
664 //
665 InitializeSpinLock (&mSmmPerfLock);
666
667 mMaxGaugeRecords = INIT_SMM_GAUGE_DATA_ENTRIES;
668
669 mGaugeData = AllocateZeroPool (sizeof (GAUGE_DATA_HEADER) + (sizeof (GAUGE_DATA_ENTRY_EX) * mMaxGaugeRecords));
670 ASSERT (mGaugeData != NULL);
671
672 //
673 // Get SMRAM information
674 //
675 Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess);
676 ASSERT_EFI_ERROR (Status);
677
678 Size = 0;
679 Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL);
680 ASSERT (Status == EFI_BUFFER_TOO_SMALL);
681
682 Status = gSmst->SmmAllocatePool (
683 EfiRuntimeServicesData,
684 Size,
685 (VOID **)&mSmramRanges
686 );
687 ASSERT_EFI_ERROR (Status);
688
689 Status = SmmAccess->GetCapabilities (SmmAccess, &Size, mSmramRanges);
690 ASSERT_EFI_ERROR (Status);
691
692 mSmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
693
694 //
695 // Install the protocol interfaces.
696 //
697 Status = gSmst->SmmInstallProtocolInterface (
698 &mHandle,
699 &gSmmPerformanceProtocolGuid,
700 EFI_NATIVE_INTERFACE,
701 &mPerformanceInterface
702 );
703 ASSERT_EFI_ERROR (Status);
704
705 Status = gSmst->SmmInstallProtocolInterface (
706 &mHandle,
707 &gSmmPerformanceExProtocolGuid,
708 EFI_NATIVE_INTERFACE,
709 &mPerformanceExInterface
710 );
711 ASSERT_EFI_ERROR (Status);
712
713 ///
714 /// Register SMM Performance SMI handler
715 ///
716 Handle = NULL;
717 Status = gSmst->SmiHandlerRegister (SmmPerformanceHandler, &gSmmPerformanceProtocolGuid, &Handle);
718 ASSERT_EFI_ERROR (Status);
719 Status = gSmst->SmiHandlerRegister (SmmPerformanceHandlerEx, &gSmmPerformanceExProtocolGuid, &Handle);
720 ASSERT_EFI_ERROR (Status);
721 }
722
723 /**
724 The constructor function initializes the Performance Measurement Enable flag and
725 registers SmmBase2 protocol notify callback.
726 It will ASSERT() if one of these operations fails and it will always return EFI_SUCCESS.
727
728 @param ImageHandle The firmware allocated handle for the EFI image.
729 @param SystemTable A pointer to the EFI System Table.
730
731 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
732
733 **/
734 EFI_STATUS
735 EFIAPI
736 SmmCorePerformanceLibConstructor (
737 IN EFI_HANDLE ImageHandle,
738 IN EFI_SYSTEM_TABLE *SystemTable
739 )
740 {
741 EFI_STATUS Status;
742 EFI_EVENT Event;
743 VOID *Registration;
744
745 mPerformanceMeasurementEnabled = (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
746 if (!mPerformanceMeasurementEnabled) {
747 //
748 // Do not initialize performance infrastructure if not required.
749 //
750 return EFI_SUCCESS;
751 }
752
753 //
754 // Create the events to do the library init.
755 //
756 Status = gBS->CreateEvent (
757 EVT_NOTIFY_SIGNAL,
758 TPL_CALLBACK,
759 InitializeSmmCorePerformanceLib,
760 NULL,
761 &Event
762 );
763 ASSERT_EFI_ERROR (Status);
764
765 //
766 // Register for protocol notifications on this event
767 //
768 Status = gBS->RegisterProtocolNotify (
769 &gEfiSmmBase2ProtocolGuid,
770 Event,
771 &Registration
772 );
773
774 ASSERT_EFI_ERROR (Status);
775
776 return EFI_SUCCESS;
777 }
778
779 /**
780 Adds a record at the end of the performance measurement log
781 that records the start time of a performance measurement.
782
783 Adds a record to the end of the performance measurement log
784 that contains the Handle, Token, Module and Identifier.
785 The end time of the new record must be set to zero.
786 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
787 If TimeStamp is zero, the start time in the record is filled in with the value
788 read from the current time stamp.
789
790 @param Handle Pointer to environment specific context used
791 to identify the component being measured.
792 @param Token Pointer to a Null-terminated ASCII string
793 that identifies the component being measured.
794 @param Module Pointer to a Null-terminated ASCII string
795 that identifies the module being measured.
796 @param TimeStamp 64-bit time stamp.
797 @param Identifier 32-bit identifier. If the value is 0, the created record
798 is same as the one created by StartPerformanceMeasurement.
799
800 @retval RETURN_SUCCESS The start of the measurement was recorded.
801 @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
802
803 **/
804 RETURN_STATUS
805 EFIAPI
806 StartPerformanceMeasurementEx (
807 IN CONST VOID *Handle, OPTIONAL
808 IN CONST CHAR8 *Token, OPTIONAL
809 IN CONST CHAR8 *Module, OPTIONAL
810 IN UINT64 TimeStamp,
811 IN UINT32 Identifier
812 )
813 {
814 return (RETURN_STATUS) StartGaugeEx (Handle, Token, Module, TimeStamp, Identifier);
815 }
816
817 /**
818 Searches the performance measurement log from the beginning of the log
819 for the first matching record that contains a zero end time and fills in a valid end time.
820
821 Searches the performance measurement log from the beginning of the log
822 for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.
823 If the record can not be found then return RETURN_NOT_FOUND.
824 If the record is found and TimeStamp is not zero,
825 then the end time in the record is filled in with the value specified by TimeStamp.
826 If the record is found and TimeStamp is zero, then the end time in the matching record
827 is filled in with the current time stamp value.
828
829 @param Handle Pointer to environment specific context used
830 to identify the component being measured.
831 @param Token Pointer to a Null-terminated ASCII string
832 that identifies the component being measured.
833 @param Module Pointer to a Null-terminated ASCII string
834 that identifies the module being measured.
835 @param TimeStamp 64-bit time stamp.
836 @param Identifier 32-bit identifier. If the value is 0, the found record
837 is same as the one found by EndPerformanceMeasurement.
838
839 @retval RETURN_SUCCESS The end of the measurement was recorded.
840 @retval RETURN_NOT_FOUND The specified measurement record could not be found.
841
842 **/
843 RETURN_STATUS
844 EFIAPI
845 EndPerformanceMeasurementEx (
846 IN CONST VOID *Handle, OPTIONAL
847 IN CONST CHAR8 *Token, OPTIONAL
848 IN CONST CHAR8 *Module, OPTIONAL
849 IN UINT64 TimeStamp,
850 IN UINT32 Identifier
851 )
852 {
853 return (RETURN_STATUS) EndGaugeEx (Handle, Token, Module, TimeStamp, Identifier);
854 }
855
856 /**
857 Attempts to retrieve a performance measurement log entry from the performance measurement log.
858 It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
859 and then assign the Identifier with 0.
860
861 Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
862 zero on entry, then an attempt is made to retrieve the first entry from the performance log,
863 and the key for the second entry in the log is returned. If the performance log is empty,
864 then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
865 log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
866 returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
867 retrieved and an implementation specific non-zero key value that specifies the end of the performance
868 log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
869 is retrieved and zero is returned. In the cases where a performance log entry can be returned,
870 the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
871 If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
872 If Handle is NULL, then ASSERT().
873 If Token is NULL, then ASSERT().
874 If Module is NULL, then ASSERT().
875 If StartTimeStamp is NULL, then ASSERT().
876 If EndTimeStamp is NULL, then ASSERT().
877 If Identifier is NULL, then ASSERT().
878
879 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
880 0, then the first performance measurement log entry is retrieved.
881 On exit, the key of the next performance log entry.
882 @param Handle Pointer to environment specific context used to identify the component
883 being measured.
884 @param Token Pointer to a Null-terminated ASCII string that identifies the component
885 being measured.
886 @param Module Pointer to a Null-terminated ASCII string that identifies the module
887 being measured.
888 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
889 was started.
890 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
891 was ended.
892 @param Identifier Pointer to the 32-bit identifier that was recorded.
893
894 @return The key for the next performance log entry (in general case).
895
896 **/
897 UINTN
898 EFIAPI
899 GetPerformanceMeasurementEx (
900 IN UINTN LogEntryKey,
901 OUT CONST VOID **Handle,
902 OUT CONST CHAR8 **Token,
903 OUT CONST CHAR8 **Module,
904 OUT UINT64 *StartTimeStamp,
905 OUT UINT64 *EndTimeStamp,
906 OUT UINT32 *Identifier
907 )
908 {
909 EFI_STATUS Status;
910 GAUGE_DATA_ENTRY_EX *GaugeData;
911
912 GaugeData = NULL;
913
914 ASSERT (Handle != NULL);
915 ASSERT (Token != NULL);
916 ASSERT (Module != NULL);
917 ASSERT (StartTimeStamp != NULL);
918 ASSERT (EndTimeStamp != NULL);
919 ASSERT (Identifier != NULL);
920
921 Status = GetGaugeEx (LogEntryKey++, &GaugeData);
922
923 //
924 // Make sure that LogEntryKey is a valid log entry key,
925 //
926 ASSERT (Status != EFI_INVALID_PARAMETER);
927
928 if (EFI_ERROR (Status)) {
929 //
930 // The LogEntryKey is the last entry (equals to the total entry number).
931 //
932 return 0;
933 }
934
935 ASSERT (GaugeData != NULL);
936
937 *Handle = (VOID *) (UINTN) GaugeData->Handle;
938 *Token = GaugeData->Token;
939 *Module = GaugeData->Module;
940 *StartTimeStamp = GaugeData->StartTimeStamp;
941 *EndTimeStamp = GaugeData->EndTimeStamp;
942 *Identifier = GaugeData->Identifier;
943
944 return LogEntryKey;
945 }
946
947 /**
948 Adds a record at the end of the performance measurement log
949 that records the start time of a performance measurement.
950
951 Adds a record to the end of the performance measurement log
952 that contains the Handle, Token, and Module.
953 The end time of the new record must be set to zero.
954 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
955 If TimeStamp is zero, the start time in the record is filled in with the value
956 read from the current time stamp.
957
958 @param Handle Pointer to environment specific context used
959 to identify the component being measured.
960 @param Token Pointer to a Null-terminated ASCII string
961 that identifies the component being measured.
962 @param Module Pointer to a Null-terminated ASCII string
963 that identifies the module being measured.
964 @param TimeStamp 64-bit time stamp.
965
966 @retval RETURN_SUCCESS The start of the measurement was recorded.
967 @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
968
969 **/
970 RETURN_STATUS
971 EFIAPI
972 StartPerformanceMeasurement (
973 IN CONST VOID *Handle, OPTIONAL
974 IN CONST CHAR8 *Token, OPTIONAL
975 IN CONST CHAR8 *Module, OPTIONAL
976 IN UINT64 TimeStamp
977 )
978 {
979 return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
980 }
981
982 /**
983 Searches the performance measurement log from the beginning of the log
984 for the first matching record that contains a zero end time and fills in a valid end time.
985
986 Searches the performance measurement log from the beginning of the log
987 for the first record that matches Handle, Token, and Module and has an end time value of zero.
988 If the record can not be found then return RETURN_NOT_FOUND.
989 If the record is found and TimeStamp is not zero,
990 then the end time in the record is filled in with the value specified by TimeStamp.
991 If the record is found and TimeStamp is zero, then the end time in the matching record
992 is filled in with the current time stamp value.
993
994 @param Handle Pointer to environment specific context used
995 to identify the component being measured.
996 @param Token Pointer to a Null-terminated ASCII string
997 that identifies the component being measured.
998 @param Module Pointer to a Null-terminated ASCII string
999 that identifies the module being measured.
1000 @param TimeStamp 64-bit time stamp.
1001
1002 @retval RETURN_SUCCESS The end of the measurement was recorded.
1003 @retval RETURN_NOT_FOUND The specified measurement record could not be found.
1004
1005 **/
1006 RETURN_STATUS
1007 EFIAPI
1008 EndPerformanceMeasurement (
1009 IN CONST VOID *Handle, OPTIONAL
1010 IN CONST CHAR8 *Token, OPTIONAL
1011 IN CONST CHAR8 *Module, OPTIONAL
1012 IN UINT64 TimeStamp
1013 )
1014 {
1015 return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
1016 }
1017
1018 /**
1019 Attempts to retrieve a performance measurement log entry from the performance measurement log.
1020 It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
1021 and then eliminate the Identifier.
1022
1023 Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
1024 zero on entry, then an attempt is made to retrieve the first entry from the performance log,
1025 and the key for the second entry in the log is returned. If the performance log is empty,
1026 then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
1027 log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
1028 returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
1029 retrieved and an implementation specific non-zero key value that specifies the end of the performance
1030 log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
1031 is retrieved and zero is returned. In the cases where a performance log entry can be returned,
1032 the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
1033 If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
1034 If Handle is NULL, then ASSERT().
1035 If Token is NULL, then ASSERT().
1036 If Module is NULL, then ASSERT().
1037 If StartTimeStamp is NULL, then ASSERT().
1038 If EndTimeStamp is NULL, then ASSERT().
1039
1040 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
1041 0, then the first performance measurement log entry is retrieved.
1042 On exit, the key of the next performance log entry.
1043 @param Handle Pointer to environment specific context used to identify the component
1044 being measured.
1045 @param Token Pointer to a Null-terminated ASCII string that identifies the component
1046 being measured.
1047 @param Module Pointer to a Null-terminated ASCII string that identifies the module
1048 being measured.
1049 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
1050 was started.
1051 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
1052 was ended.
1053
1054 @return The key for the next performance log entry (in general case).
1055
1056 **/
1057 UINTN
1058 EFIAPI
1059 GetPerformanceMeasurement (
1060 IN UINTN LogEntryKey,
1061 OUT CONST VOID **Handle,
1062 OUT CONST CHAR8 **Token,
1063 OUT CONST CHAR8 **Module,
1064 OUT UINT64 *StartTimeStamp,
1065 OUT UINT64 *EndTimeStamp
1066 )
1067 {
1068 UINT32 Identifier;
1069 return GetPerformanceMeasurementEx (LogEntryKey, Handle, Token, Module, StartTimeStamp, EndTimeStamp, &Identifier);
1070 }
1071
1072 /**
1073 Returns TRUE if the performance measurement macros are enabled.
1074
1075 This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
1076 PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
1077
1078 @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
1079 PcdPerformanceLibraryPropertyMask is set.
1080 @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
1081 PcdPerformanceLibraryPropertyMask is clear.
1082
1083 **/
1084 BOOLEAN
1085 EFIAPI
1086 PerformanceMeasurementEnabled (
1087 VOID
1088 )
1089 {
1090 return mPerformanceMeasurementEnabled;
1091 }