]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeSmmPerformanceLib/DxeSmmPerformanceLib.c
MdeModulePkg-FPDT(4): Use fixed buffer for SMM_PERF_COMMUNICATE in PerfLib.
[mirror_edk2.git] / MdeModulePkg / Library / DxeSmmPerformanceLib / DxeSmmPerformanceLib.c
1 /** @file
2 Performance library instance used in DXE phase to dump both PEI/DXE and SMM performance data.
3
4 This library instance allows a DXE driver or UEFI application to dump both PEI/DXE and SMM performance data.
5 StartPerformanceMeasurement(), EndPerformanceMeasurement(), StartPerformanceMeasurementEx()
6 and EndPerformanceMeasurementEx() are not implemented.
7
8 Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
9 This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
13
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16
17 **/
18
19
20 #include <PiDxe.h>
21
22 #include <Guid/Performance.h>
23
24 #include <Library/PerformanceLib.h>
25 #include <Library/DebugLib.h>
26 #include <Library/UefiBootServicesTableLib.h>
27 #include <Library/UefiRuntimeServicesTableLib.h>
28 #include <Library/PcdLib.h>
29 #include <Library/BaseMemoryLib.h>
30 #include <Library/BaseLib.h>
31 #include <Library/MemoryAllocationLib.h>
32
33 #include <Protocol/SmmCommunication.h>
34
35 #include <Guid/PiSmmCommunicationRegionTable.h>
36 #include <Library/UefiLib.h>
37
38 #define SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + sizeof (SMM_PERF_COMMUNICATE))
39
40 EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;
41 UINT8 *mSmmPerformanceBuffer;
42 GAUGE_DATA_ENTRY *mGaugeData = NULL;
43 UINTN mGaugeNumberOfEntries = 0;
44 GAUGE_DATA_ENTRY_EX *mGaugeDataEx = NULL;
45 UINTN mGaugeNumberOfEntriesEx = 0;
46
47 BOOLEAN mNoSmmPerfHandler = FALSE;
48 BOOLEAN mNoSmmPerfExHandler = FALSE;
49
50 //
51 // The cached Performance Protocol and PerformanceEx Protocol interface.
52 //
53 PERFORMANCE_PROTOCOL *mPerformance = NULL;
54 PERFORMANCE_EX_PROTOCOL *mPerformanceEx = NULL;
55
56 /**
57 The function caches the pointer to SMM Communication protocol.
58
59 The function locates SMM Communication protocol from protocol database.
60
61 @retval EFI_SUCCESS SMM Communication protocol is successfully located.
62 @retval Other SMM Communication protocol is not located to log performance.
63
64 **/
65 EFI_STATUS
66 GetCommunicationProtocol (
67 VOID
68 )
69 {
70 EFI_STATUS Status;
71 EFI_SMM_COMMUNICATION_PROTOCOL *Communication;
72
73 if (mSmmCommunication != NULL) {
74 return EFI_SUCCESS;
75 }
76
77 Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &Communication);
78 if (!EFI_ERROR (Status)) {
79 ASSERT (Communication != NULL);
80 //
81 // Cache SMM Communication protocol.
82 //
83 mSmmCommunication = Communication;
84 }
85
86 return Status;
87 }
88
89 /**
90 The function caches the pointers to PerformanceEx protocol and Performance Protocol.
91
92 The function locates PerformanceEx protocol and Performance Protocol from protocol database.
93
94 @retval EFI_SUCCESS PerformanceEx protocol or Performance Protocol is successfully located.
95 @retval EFI_NOT_FOUND Both PerformanceEx protocol and Performance Protocol are not located to log performance.
96
97 **/
98 EFI_STATUS
99 GetPerformanceProtocol (
100 VOID
101 )
102 {
103 EFI_STATUS Status;
104 PERFORMANCE_PROTOCOL *Performance;
105 PERFORMANCE_EX_PROTOCOL *PerformanceEx;
106
107 if (mPerformanceEx != NULL || mPerformance != NULL) {
108 return EFI_SUCCESS;
109 }
110
111 Status = gBS->LocateProtocol (&gPerformanceExProtocolGuid, NULL, (VOID **) &PerformanceEx);
112 if (!EFI_ERROR (Status)) {
113 ASSERT (PerformanceEx != NULL);
114 //
115 // Cache PerformanceEx Protocol.
116 //
117 mPerformanceEx = PerformanceEx;
118 return EFI_SUCCESS;
119 }
120
121 Status = gBS->LocateProtocol (&gPerformanceProtocolGuid, NULL, (VOID **) &Performance);
122 if (!EFI_ERROR (Status)) {
123 ASSERT (Performance != NULL);
124 //
125 // Cache performance protocol.
126 //
127 mPerformance = Performance;
128 return EFI_SUCCESS;
129 }
130
131 return EFI_NOT_FOUND;
132 }
133
134 /**
135 Creates a record for the beginning of a performance measurement.
136
137 Creates a record that contains the Handle, Token, Module and Identifier.
138 If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
139 If TimeStamp is zero, then this function reads the current time stamp
140 and adds that time stamp value to the record as the start time.
141
142 @param Handle Pointer to environment specific context used
143 to identify the component being measured.
144 @param Token Pointer to a Null-terminated ASCII string
145 that identifies the component being measured.
146 @param Module Pointer to a Null-terminated ASCII string
147 that identifies the module being measured.
148 @param TimeStamp 64-bit time stamp.
149 @param Identifier 32-bit identifier. If the value is 0, the created record
150 is same as the one created by StartPerformanceMeasurement.
151
152 @retval RETURN_SUCCESS The start of the measurement was recorded.
153 @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
154
155 **/
156 RETURN_STATUS
157 EFIAPI
158 StartPerformanceMeasurementEx (
159 IN CONST VOID *Handle, OPTIONAL
160 IN CONST CHAR8 *Token, OPTIONAL
161 IN CONST CHAR8 *Module, OPTIONAL
162 IN UINT64 TimeStamp,
163 IN UINT32 Identifier
164 )
165 {
166 return RETURN_SUCCESS;
167 }
168
169 /**
170 Fills in the end time of a performance measurement.
171
172 Looks up the record that matches Handle, Token and Module.
173 If the record can not be found then return RETURN_NOT_FOUND.
174 If the record is found and TimeStamp is not zero,
175 then TimeStamp is added to the record as the end time.
176 If the record is found and TimeStamp is zero, then this function reads
177 the current time stamp and adds that time stamp value to the record as the end time.
178
179 @param Handle Pointer to environment specific context used
180 to identify the component being measured.
181 @param Token Pointer to a Null-terminated ASCII string
182 that identifies the component being measured.
183 @param Module Pointer to a Null-terminated ASCII string
184 that identifies the module being measured.
185 @param TimeStamp 64-bit time stamp.
186 @param Identifier 32-bit identifier. If the value is 0, the found record
187 is same as the one found by EndPerformanceMeasurement.
188
189 @retval RETURN_SUCCESS The end of the measurement was recorded.
190 @retval RETURN_NOT_FOUND The specified measurement record could not be found.
191
192 **/
193 RETURN_STATUS
194 EFIAPI
195 EndPerformanceMeasurementEx (
196 IN CONST VOID *Handle, OPTIONAL
197 IN CONST CHAR8 *Token, OPTIONAL
198 IN CONST CHAR8 *Module, OPTIONAL
199 IN UINT64 TimeStamp,
200 IN UINT32 Identifier
201 )
202 {
203 return RETURN_SUCCESS;
204 }
205
206 /**
207 Creates a record for the beginning of a performance measurement.
208
209 Creates a record that contains the Handle, Token, and Module.
210 If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
211 If TimeStamp is zero, then this function reads the current time stamp
212 and adds that time stamp value to the record as the start time.
213
214 @param Handle Pointer to environment specific context used
215 to identify the component being measured.
216 @param Token Pointer to a Null-terminated ASCII string
217 that identifies the component being measured.
218 @param Module Pointer to a Null-terminated ASCII string
219 that identifies the module being measured.
220 @param TimeStamp 64-bit time stamp.
221
222 @retval RETURN_SUCCESS The start of the measurement was recorded.
223 @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
224
225 **/
226 RETURN_STATUS
227 EFIAPI
228 StartPerformanceMeasurement (
229 IN CONST VOID *Handle, OPTIONAL
230 IN CONST CHAR8 *Token, OPTIONAL
231 IN CONST CHAR8 *Module, OPTIONAL
232 IN UINT64 TimeStamp
233 )
234 {
235 return RETURN_SUCCESS;
236 }
237
238 /**
239 Fills in the end time of a performance measurement.
240
241 Looks up the record that matches Handle, Token, and Module.
242 If the record can not be found then return RETURN_NOT_FOUND.
243 If the record is found and TimeStamp is not zero,
244 then TimeStamp is added to the record as the end time.
245 If the record is found and TimeStamp is zero, then this function reads
246 the current time stamp and adds that time stamp value to the record as the end time.
247
248 @param Handle Pointer to environment specific context used
249 to identify the component being measured.
250 @param Token Pointer to a Null-terminated ASCII string
251 that identifies the component being measured.
252 @param Module Pointer to a Null-terminated ASCII string
253 that identifies the module being measured.
254 @param TimeStamp 64-bit time stamp.
255
256 @retval RETURN_SUCCESS The end of the measurement was recorded.
257 @retval RETURN_NOT_FOUND The specified measurement record could not be found.
258
259 **/
260 RETURN_STATUS
261 EFIAPI
262 EndPerformanceMeasurement (
263 IN CONST VOID *Handle, OPTIONAL
264 IN CONST CHAR8 *Token, OPTIONAL
265 IN CONST CHAR8 *Module, OPTIONAL
266 IN UINT64 TimeStamp
267 )
268 {
269 return RETURN_SUCCESS;
270 }
271
272 /**
273 Attempts to retrieve a performance measurement log entry from the performance measurement log.
274 It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
275 and then assign the Identifier with 0.
276
277 Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
278 zero on entry, then an attempt is made to retrieve the first entry from the performance log,
279 and the key for the second entry in the log is returned. If the performance log is empty,
280 then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
281 log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
282 returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
283 retrieved and an implementation specific non-zero key value that specifies the end of the performance
284 log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
285 is retrieved and zero is returned. In the cases where a performance log entry can be returned,
286 the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
287 If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
288 If Handle is NULL, then ASSERT().
289 If Token is NULL, then ASSERT().
290 If Module is NULL, then ASSERT().
291 If StartTimeStamp is NULL, then ASSERT().
292 If EndTimeStamp is NULL, then ASSERT().
293 If Identifier is NULL, then ASSERT().
294
295 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
296 0, then the first performance measurement log entry is retrieved.
297 On exit, the key of the next performance log entry.
298 @param Handle Pointer to environment specific context used to identify the component
299 being measured.
300 @param Token Pointer to a Null-terminated ASCII string that identifies the component
301 being measured.
302 @param Module Pointer to a Null-terminated ASCII string that identifies the module
303 being measured.
304 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
305 was started.
306 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
307 was ended.
308 @param Identifier Pointer to the 32-bit identifier that was recorded.
309
310 @return The key for the next performance log entry (in general case).
311
312 **/
313 UINTN
314 EFIAPI
315 GetByPerformanceProtocol (
316 IN UINTN LogEntryKey,
317 OUT CONST VOID **Handle,
318 OUT CONST CHAR8 **Token,
319 OUT CONST CHAR8 **Module,
320 OUT UINT64 *StartTimeStamp,
321 OUT UINT64 *EndTimeStamp,
322 OUT UINT32 *Identifier
323 )
324 {
325 EFI_STATUS Status;
326 GAUGE_DATA_ENTRY_EX *GaugeData;
327
328 Status = GetPerformanceProtocol ();
329 if (EFI_ERROR (Status)) {
330 return 0;
331 }
332
333 if (mPerformanceEx != NULL) {
334 Status = mPerformanceEx->GetGaugeEx (LogEntryKey++, &GaugeData);
335 } else if (mPerformance != NULL) {
336 Status = mPerformance->GetGauge (LogEntryKey++, (GAUGE_DATA_ENTRY **) &GaugeData);
337 } else {
338 ASSERT (FALSE);
339 return 0;
340 }
341
342 //
343 // Make sure that LogEntryKey is a valid log entry key,
344 //
345 ASSERT (Status != EFI_INVALID_PARAMETER);
346
347 if (EFI_ERROR (Status)) {
348 //
349 // The LogEntryKey is the last entry (equals to the total entry number).
350 //
351 return 0;
352 }
353
354 ASSERT (GaugeData != NULL);
355
356 *Handle = (VOID *) (UINTN) GaugeData->Handle;
357 *Token = GaugeData->Token;
358 *Module = GaugeData->Module;
359 *StartTimeStamp = GaugeData->StartTimeStamp;
360 *EndTimeStamp = GaugeData->EndTimeStamp;
361 if (mPerformanceEx != NULL) {
362 *Identifier = GaugeData->Identifier;
363 } else {
364 *Identifier = 0;
365 }
366
367 return LogEntryKey;
368 }
369
370
371 /**
372 Retrieves all previous logged performance measurement.
373 Function will use SMM communicate protocol to get all previous SMM performance measurement data.
374 If success, data buffer will be returned. If fail function will return NULL.
375
376 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
377 0, then the first performance measurement log entry is retrieved.
378 On exit, the key of the next performance log entry.
379
380 @retval !NULL Get all gauge data success.
381 @retval NULL Get all gauge data failed.
382 **/
383 GAUGE_DATA_ENTRY *
384 EFIAPI
385 GetAllSmmGaugeData (
386 IN UINTN LogEntryKey
387 )
388 {
389 EFI_STATUS Status;
390 EFI_SMM_COMMUNICATE_HEADER *SmmCommBufferHeader;
391 SMM_PERF_COMMUNICATE *SmmPerfCommData;
392 UINTN CommSize;
393 UINTN DataSize;
394 EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable;
395 UINT32 Index;
396 EFI_MEMORY_DESCRIPTOR *Entry;
397 UINT8 *Buffer;
398 UINTN Size;
399 UINTN NumberOfEntries;
400 UINTN EntriesGot;
401
402 if (mNoSmmPerfHandler) {
403 //
404 // Not try to get the SMM gauge data again
405 // if no SMM Performance handler found.
406 //
407 return NULL;
408 }
409
410 if (LogEntryKey != 0) {
411 if (mGaugeData != NULL) {
412 return mGaugeData;
413 }
414 } else {
415 //
416 // Reget the SMM gauge data at the first entry get.
417 //
418 if (mGaugeData != NULL) {
419 FreePool (mGaugeData);
420 mGaugeData = NULL;
421 mGaugeNumberOfEntries = 0;
422 }
423 }
424
425 Status = GetCommunicationProtocol ();
426 if (EFI_ERROR (Status)) {
427 return NULL;
428 }
429
430 Status = EfiGetSystemConfigurationTable (
431 &gEdkiiPiSmmCommunicationRegionTableGuid,
432 (VOID **) &PiSmmCommunicationRegionTable
433 );
434 if (EFI_ERROR (Status)) {
435 return NULL;
436 }
437 ASSERT (PiSmmCommunicationRegionTable != NULL);
438 Entry = (EFI_MEMORY_DESCRIPTOR *) (PiSmmCommunicationRegionTable + 1);
439 Size = 0;
440 for (Index = 0; Index < PiSmmCommunicationRegionTable->NumberOfEntries; Index++) {
441 if (Entry->Type == EfiConventionalMemory) {
442 Size = EFI_PAGES_TO_SIZE ((UINTN) Entry->NumberOfPages);
443 if (Size >= (SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE + sizeof (GAUGE_DATA_ENTRY))) {
444 break;
445 }
446 }
447 Entry = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) Entry + PiSmmCommunicationRegionTable->DescriptorSize);
448 }
449 ASSERT (Index < PiSmmCommunicationRegionTable->NumberOfEntries);
450 mSmmPerformanceBuffer = (UINT8 *) (UINTN) Entry->PhysicalStart;
451
452 //
453 // Initialize communicate buffer
454 //
455 SmmCommBufferHeader = (EFI_SMM_COMMUNICATE_HEADER *)mSmmPerformanceBuffer;
456 SmmPerfCommData = (SMM_PERF_COMMUNICATE *)SmmCommBufferHeader->Data;
457 ZeroMem((UINT8*)SmmPerfCommData, sizeof(SMM_PERF_COMMUNICATE));
458
459 CopyGuid (&SmmCommBufferHeader->HeaderGuid, &gSmmPerformanceProtocolGuid);
460 SmmCommBufferHeader->MessageLength = sizeof(SMM_PERF_COMMUNICATE);
461 CommSize = SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE;
462
463 //
464 // Get total number of SMM gauge entries
465 //
466 SmmPerfCommData->Function = SMM_PERF_FUNCTION_GET_GAUGE_ENTRY_NUMBER;
467 Status = mSmmCommunication->Communicate (mSmmCommunication, mSmmPerformanceBuffer, &CommSize);
468 if (Status == EFI_NOT_FOUND) {
469 mNoSmmPerfHandler = TRUE;
470 }
471 if (EFI_ERROR (Status) || EFI_ERROR (SmmPerfCommData->ReturnStatus) || SmmPerfCommData->NumberOfEntries == 0) {
472 return NULL;
473 }
474
475 mGaugeNumberOfEntries = SmmPerfCommData->NumberOfEntries;
476
477 Buffer = mSmmPerformanceBuffer + SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE;
478 NumberOfEntries = (Size - SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE) / sizeof (GAUGE_DATA_ENTRY);
479 DataSize = mGaugeNumberOfEntries * sizeof(GAUGE_DATA_ENTRY);
480 mGaugeData = AllocateZeroPool(DataSize);
481 ASSERT (mGaugeData != NULL);
482
483 //
484 // Get all SMM gauge data
485 //
486 SmmPerfCommData->Function = SMM_PERF_FUNCTION_GET_GAUGE_DATA;
487 SmmPerfCommData->GaugeData = (GAUGE_DATA_ENTRY *) Buffer;
488 EntriesGot = 0;
489 do {
490 SmmPerfCommData->LogEntryKey = EntriesGot;
491 if ((mGaugeNumberOfEntries - EntriesGot) >= NumberOfEntries) {
492 SmmPerfCommData->NumberOfEntries = NumberOfEntries;
493 } else {
494 SmmPerfCommData->NumberOfEntries = mGaugeNumberOfEntries - EntriesGot;
495 }
496 Status = mSmmCommunication->Communicate (mSmmCommunication, mSmmPerformanceBuffer, &CommSize);
497 if (EFI_ERROR (Status) || EFI_ERROR (SmmPerfCommData->ReturnStatus)) {
498 FreePool (mGaugeData);
499 mGaugeData = NULL;
500 mGaugeNumberOfEntries = 0;
501 return NULL;
502 } else {
503 CopyMem (&mGaugeData[EntriesGot], Buffer, SmmPerfCommData->NumberOfEntries * sizeof (GAUGE_DATA_ENTRY));
504 }
505 EntriesGot += SmmPerfCommData->NumberOfEntries;
506 } while (EntriesGot < mGaugeNumberOfEntries);
507
508 return mGaugeData;
509 }
510
511 /**
512 Retrieves all previous logged performance measurement.
513 Function will use SMM communicate protocol to get all previous SMM performance measurement data.
514 If success, data buffer will be returned. If fail function will return NULL.
515
516 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
517 0, then the first performance measurement log entry is retrieved.
518 On exit, the key of the next performance log entry.
519
520 @retval !NULL Get all gauge data success.
521 @retval NULL Get all gauge data failed.
522 **/
523 GAUGE_DATA_ENTRY_EX *
524 EFIAPI
525 GetAllSmmGaugeDataEx (
526 IN UINTN LogEntryKey
527 )
528 {
529 EFI_STATUS Status;
530 EFI_SMM_COMMUNICATE_HEADER *SmmCommBufferHeader;
531 SMM_PERF_COMMUNICATE_EX *SmmPerfCommData;
532 UINTN CommSize;
533 UINTN DataSize;
534 EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable;
535 UINT32 Index;
536 EFI_MEMORY_DESCRIPTOR *Entry;
537 UINT8 *Buffer;
538 UINTN Size;
539 UINTN NumberOfEntries;
540 UINTN EntriesGot;
541
542 if (mNoSmmPerfExHandler) {
543 //
544 // Not try to get the SMM gauge data again
545 // if no SMM PerformanceEx handler found.
546 //
547 return NULL;
548 }
549
550 if (LogEntryKey != 0) {
551 if (mGaugeDataEx != NULL) {
552 return mGaugeDataEx;
553 }
554 } else {
555 //
556 // Reget the SMM gauge data at the first entry get.
557 //
558 if (mGaugeDataEx != NULL) {
559 FreePool (mGaugeDataEx);
560 mGaugeDataEx = NULL;
561 mGaugeNumberOfEntriesEx = 0;
562 }
563 }
564
565 Status = GetCommunicationProtocol ();
566 if (EFI_ERROR (Status)) {
567 return NULL;
568 }
569
570 Status = EfiGetSystemConfigurationTable (
571 &gEdkiiPiSmmCommunicationRegionTableGuid,
572 (VOID **) &PiSmmCommunicationRegionTable
573 );
574 if (EFI_ERROR (Status)) {
575 return NULL;
576 }
577 ASSERT (PiSmmCommunicationRegionTable != NULL);
578 Entry = (EFI_MEMORY_DESCRIPTOR *) (PiSmmCommunicationRegionTable + 1);
579 Size = 0;
580 for (Index = 0; Index < PiSmmCommunicationRegionTable->NumberOfEntries; Index++) {
581 if (Entry->Type == EfiConventionalMemory) {
582 Size = EFI_PAGES_TO_SIZE ((UINTN) Entry->NumberOfPages);
583 if (Size >= (SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE + sizeof (GAUGE_DATA_ENTRY_EX))) {
584 break;
585 }
586 }
587 Entry = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) Entry + PiSmmCommunicationRegionTable->DescriptorSize);
588 }
589 ASSERT (Index < PiSmmCommunicationRegionTable->NumberOfEntries);
590 mSmmPerformanceBuffer = (UINT8 *) (UINTN) Entry->PhysicalStart;
591 //
592 // Initialize communicate buffer
593 //
594 SmmCommBufferHeader = (EFI_SMM_COMMUNICATE_HEADER *)mSmmPerformanceBuffer;
595 SmmPerfCommData = (SMM_PERF_COMMUNICATE_EX *)SmmCommBufferHeader->Data;
596 ZeroMem((UINT8*)SmmPerfCommData, sizeof(SMM_PERF_COMMUNICATE_EX));
597
598 CopyGuid (&SmmCommBufferHeader->HeaderGuid, &gSmmPerformanceExProtocolGuid);
599 SmmCommBufferHeader->MessageLength = sizeof(SMM_PERF_COMMUNICATE_EX);
600 CommSize = SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE;
601
602 //
603 // Get total number of SMM gauge entries
604 //
605 SmmPerfCommData->Function = SMM_PERF_FUNCTION_GET_GAUGE_ENTRY_NUMBER;
606 Status = mSmmCommunication->Communicate (mSmmCommunication, mSmmPerformanceBuffer, &CommSize);
607 if (Status == EFI_NOT_FOUND) {
608 mNoSmmPerfExHandler = TRUE;
609 }
610 if (EFI_ERROR (Status) || EFI_ERROR (SmmPerfCommData->ReturnStatus) || SmmPerfCommData->NumberOfEntries == 0) {
611 return NULL;
612 }
613
614 mGaugeNumberOfEntriesEx = SmmPerfCommData->NumberOfEntries;
615
616 Buffer = mSmmPerformanceBuffer + SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE;
617 NumberOfEntries = (Size - SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE) / sizeof (GAUGE_DATA_ENTRY_EX);
618 DataSize = mGaugeNumberOfEntriesEx * sizeof(GAUGE_DATA_ENTRY_EX);
619 mGaugeDataEx = AllocateZeroPool(DataSize);
620 ASSERT (mGaugeDataEx != NULL);
621
622 //
623 // Get all SMM gauge data
624 //
625 SmmPerfCommData->Function = SMM_PERF_FUNCTION_GET_GAUGE_DATA;
626 SmmPerfCommData->GaugeDataEx = (GAUGE_DATA_ENTRY_EX *) Buffer;
627 EntriesGot = 0;
628 do {
629 SmmPerfCommData->LogEntryKey = EntriesGot;
630 if ((mGaugeNumberOfEntriesEx - EntriesGot) >= NumberOfEntries) {
631 SmmPerfCommData->NumberOfEntries = NumberOfEntries;
632 } else {
633 SmmPerfCommData->NumberOfEntries = mGaugeNumberOfEntriesEx - EntriesGot;
634 }
635 Status = mSmmCommunication->Communicate (mSmmCommunication, mSmmPerformanceBuffer, &CommSize);
636 if (EFI_ERROR (Status) || EFI_ERROR (SmmPerfCommData->ReturnStatus)) {
637 FreePool (mGaugeDataEx);
638 mGaugeDataEx = NULL;
639 mGaugeNumberOfEntriesEx = 0;
640 return NULL;
641 } else {
642 CopyMem (&mGaugeDataEx[EntriesGot], Buffer, SmmPerfCommData->NumberOfEntries * sizeof (GAUGE_DATA_ENTRY_EX));
643 }
644 EntriesGot += SmmPerfCommData->NumberOfEntries;
645 } while (EntriesGot < mGaugeNumberOfEntriesEx);
646
647 return mGaugeDataEx;
648 }
649
650 /**
651 Attempts to retrieve a performance measurement log entry from the performance measurement log.
652 It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
653 and then assign the Identifier with 0.
654
655 Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
656 zero on entry, then an attempt is made to retrieve the first entry from the performance log,
657 and the key for the second entry in the log is returned. If the performance log is empty,
658 then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
659 log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
660 returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
661 retrieved and an implementation specific non-zero key value that specifies the end of the performance
662 log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
663 is retrieved and zero is returned. In the cases where a performance log entry can be returned,
664 the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
665 If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
666 If Handle is NULL, then ASSERT().
667 If Token is NULL, then ASSERT().
668 If Module is NULL, then ASSERT().
669 If StartTimeStamp is NULL, then ASSERT().
670 If EndTimeStamp is NULL, then ASSERT().
671 If Identifier is NULL, then ASSERT().
672
673 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
674 0, then the first performance measurement log entry is retrieved.
675 On exit, the key of the next performance log entry.
676 @param Handle Pointer to environment specific context used to identify the component
677 being measured.
678 @param Token Pointer to a Null-terminated ASCII string that identifies the component
679 being measured.
680 @param Module Pointer to a Null-terminated ASCII string that identifies the module
681 being measured.
682 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
683 was started.
684 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
685 was ended.
686 @param Identifier Pointer to the 32-bit identifier that was recorded.
687
688 @return The key for the next performance log entry (in general case).
689
690 **/
691 UINTN
692 EFIAPI
693 GetPerformanceMeasurementEx (
694 IN UINTN LogEntryKey,
695 OUT CONST VOID **Handle,
696 OUT CONST CHAR8 **Token,
697 OUT CONST CHAR8 **Module,
698 OUT UINT64 *StartTimeStamp,
699 OUT UINT64 *EndTimeStamp,
700 OUT UINT32 *Identifier
701 )
702 {
703 GAUGE_DATA_ENTRY_EX *GaugeData;
704
705 GaugeData = NULL;
706
707 ASSERT (Handle != NULL);
708 ASSERT (Token != NULL);
709 ASSERT (Module != NULL);
710 ASSERT (StartTimeStamp != NULL);
711 ASSERT (EndTimeStamp != NULL);
712 ASSERT (Identifier != NULL);
713
714 mGaugeDataEx = GetAllSmmGaugeDataEx (LogEntryKey);
715 if (mGaugeDataEx != NULL) {
716 if (LogEntryKey >= mGaugeNumberOfEntriesEx) {
717 //
718 // Try to get the data by Performance Protocol.
719 //
720 LogEntryKey = LogEntryKey - mGaugeNumberOfEntriesEx;
721 LogEntryKey = GetByPerformanceProtocol (
722 LogEntryKey,
723 Handle,
724 Token,
725 Module,
726 StartTimeStamp,
727 EndTimeStamp,
728 Identifier
729 );
730 if (LogEntryKey == 0) {
731 //
732 // Last entry.
733 //
734 return LogEntryKey;
735 } else {
736 return (LogEntryKey + mGaugeNumberOfEntriesEx);
737 }
738 }
739
740 GaugeData = &mGaugeDataEx[LogEntryKey++];
741 *Identifier = GaugeData->Identifier;
742 } else {
743 mGaugeData = GetAllSmmGaugeData (LogEntryKey);
744 if (mGaugeData != NULL) {
745 if (LogEntryKey >= mGaugeNumberOfEntries) {
746 //
747 // Try to get the data by Performance Protocol.
748 //
749 LogEntryKey = LogEntryKey - mGaugeNumberOfEntries;
750 LogEntryKey = GetByPerformanceProtocol (
751 LogEntryKey,
752 Handle,
753 Token,
754 Module,
755 StartTimeStamp,
756 EndTimeStamp,
757 Identifier
758 );
759 if (LogEntryKey == 0) {
760 //
761 // Last entry.
762 //
763 return LogEntryKey;
764 } else {
765 return (LogEntryKey + mGaugeNumberOfEntries);
766 }
767 }
768
769 GaugeData = (GAUGE_DATA_ENTRY_EX *) &mGaugeData[LogEntryKey++];
770 *Identifier = 0;
771 } else {
772 return GetByPerformanceProtocol (
773 LogEntryKey,
774 Handle,
775 Token,
776 Module,
777 StartTimeStamp,
778 EndTimeStamp,
779 Identifier
780 );
781 }
782 }
783
784 *Handle = (VOID *) (UINTN) GaugeData->Handle;
785 *Token = GaugeData->Token;
786 *Module = GaugeData->Module;
787 *StartTimeStamp = GaugeData->StartTimeStamp;
788 *EndTimeStamp = GaugeData->EndTimeStamp;
789
790 return LogEntryKey;
791 }
792
793 /**
794 Attempts to retrieve a performance measurement log entry from the performance measurement log.
795 It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
796 and then eliminate the Identifier.
797
798 Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
799 zero on entry, then an attempt is made to retrieve the first entry from the performance log,
800 and the key for the second entry in the log is returned. If the performance log is empty,
801 then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
802 log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
803 returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
804 retrieved and an implementation specific non-zero key value that specifies the end of the performance
805 log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
806 is retrieved and zero is returned. In the cases where a performance log entry can be returned,
807 the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
808 If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
809 If Handle is NULL, then ASSERT().
810 If Token is NULL, then ASSERT().
811 If Module is NULL, then ASSERT().
812 If StartTimeStamp is NULL, then ASSERT().
813 If EndTimeStamp is NULL, then ASSERT().
814
815 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
816 0, then the first performance measurement log entry is retrieved.
817 On exit, the key of the next performance log entry.
818 @param Handle Pointer to environment specific context used to identify the component
819 being measured.
820 @param Token Pointer to a Null-terminated ASCII string that identifies the component
821 being measured.
822 @param Module Pointer to a Null-terminated ASCII string that identifies the module
823 being measured.
824 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
825 was started.
826 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
827 was ended.
828
829 @return The key for the next performance log entry (in general case).
830
831 **/
832 UINTN
833 EFIAPI
834 GetPerformanceMeasurement (
835 IN UINTN LogEntryKey,
836 OUT CONST VOID **Handle,
837 OUT CONST CHAR8 **Token,
838 OUT CONST CHAR8 **Module,
839 OUT UINT64 *StartTimeStamp,
840 OUT UINT64 *EndTimeStamp
841 )
842 {
843 UINT32 Identifier;
844 return GetPerformanceMeasurementEx (LogEntryKey, Handle, Token, Module, StartTimeStamp, EndTimeStamp, &Identifier);
845 }
846
847 /**
848 Returns TRUE if the performance measurement macros are enabled.
849
850 This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
851 PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
852
853 @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
854 PcdPerformanceLibraryPropertyMask is set.
855 @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
856 PcdPerformanceLibraryPropertyMask is clear.
857
858 **/
859 BOOLEAN
860 EFIAPI
861 PerformanceMeasurementEnabled (
862 VOID
863 )
864 {
865 return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
866 }