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