]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c
MdeModulePkg-MemoryProfile(2): Add SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA_BY_OFFSET...
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / SmramProfileRecord.c
1 /** @file
2 Support routines for SMRAM profile.
3
4 Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "PiSmmCore.h"
16
17 #define IS_SMRAM_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT1) != 0)
18
19 typedef struct {
20 UINT32 Signature;
21 MEMORY_PROFILE_CONTEXT Context;
22 LIST_ENTRY *DriverInfoList;
23 } MEMORY_PROFILE_CONTEXT_DATA;
24
25 typedef struct {
26 UINT32 Signature;
27 MEMORY_PROFILE_DRIVER_INFO DriverInfo;
28 LIST_ENTRY *AllocInfoList;
29 LIST_ENTRY Link;
30 } MEMORY_PROFILE_DRIVER_INFO_DATA;
31
32 typedef struct {
33 UINT32 Signature;
34 MEMORY_PROFILE_ALLOC_INFO AllocInfo;
35 LIST_ENTRY Link;
36 } MEMORY_PROFILE_ALLOC_INFO_DATA;
37
38 //
39 // When free memory less than 4 pages, dump it.
40 //
41 #define SMRAM_INFO_DUMP_PAGE_THRESHOLD 4
42
43 GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_FREE_MEMORY mSmramFreeMemory = {
44 {
45 MEMORY_PROFILE_FREE_MEMORY_SIGNATURE,
46 sizeof (MEMORY_PROFILE_FREE_MEMORY),
47 MEMORY_PROFILE_FREE_MEMORY_REVISION
48 },
49 0,
50 0
51 };
52
53 GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mImageQueue = INITIALIZE_LIST_HEAD_VARIABLE (mImageQueue);
54 GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA mSmramProfileContext = {
55 MEMORY_PROFILE_CONTEXT_SIGNATURE,
56 {
57 {
58 MEMORY_PROFILE_CONTEXT_SIGNATURE,
59 sizeof (MEMORY_PROFILE_CONTEXT),
60 MEMORY_PROFILE_CONTEXT_REVISION
61 },
62 0,
63 0,
64 {0},
65 {0},
66 0,
67 0,
68 0
69 },
70 &mImageQueue,
71 };
72 GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA *mSmramProfileContextPtr = NULL;
73
74 BOOLEAN mSmramReadyToLock;
75 BOOLEAN mSmramProfileRecordingStatus = FALSE;
76
77 /**
78 Dump SMRAM infromation.
79
80 **/
81 VOID
82 DumpSmramInfo (
83 VOID
84 );
85
86 /**
87 Return SMRAM profile context.
88
89 @return SMRAM profile context.
90
91 **/
92 MEMORY_PROFILE_CONTEXT_DATA *
93 GetSmramProfileContext (
94 VOID
95 )
96 {
97 return mSmramProfileContextPtr;
98 }
99
100 /**
101 Retrieves the magic value from the PE/COFF header.
102
103 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
104
105 @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32
106 @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+
107
108 **/
109 UINT16
110 InternalPeCoffGetPeHeaderMagicValue (
111 IN EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
112 )
113 {
114 //
115 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
116 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
117 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
118 // then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
119 //
120 if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
121 return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
122 }
123 //
124 // Return the magic value from the PC/COFF Optional Header
125 //
126 return Hdr.Pe32->OptionalHeader.Magic;
127 }
128
129 /**
130 Retrieves and returns the Subsystem of a PE/COFF image that has been loaded into system memory.
131 If Pe32Data is NULL, then ASSERT().
132
133 @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.
134
135 @return The Subsystem of the PE/COFF image.
136
137 **/
138 UINT16
139 InternalPeCoffGetSubsystem (
140 IN VOID *Pe32Data
141 )
142 {
143 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
144 EFI_IMAGE_DOS_HEADER *DosHdr;
145 UINT16 Magic;
146
147 ASSERT (Pe32Data != NULL);
148
149 DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;
150 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
151 //
152 // DOS image header is present, so read the PE header after the DOS image header.
153 //
154 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
155 } else {
156 //
157 // DOS image header is not present, so PE header is at the image base.
158 //
159 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;
160 }
161
162 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
163 return Hdr.Te->Subsystem;
164 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
165 Magic = InternalPeCoffGetPeHeaderMagicValue (Hdr);
166 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
167 return Hdr.Pe32->OptionalHeader.Subsystem;
168 } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
169 return Hdr.Pe32Plus->OptionalHeader.Subsystem;
170 }
171 }
172
173 return 0x0000;
174 }
175
176 /**
177 Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded
178 into system memory with the PE/COFF Loader Library functions.
179
180 Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry
181 point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then
182 return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS.
183 If Pe32Data is NULL, then ASSERT().
184 If EntryPoint is NULL, then ASSERT().
185
186 @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.
187 @param EntryPoint The pointer to entry point to the PE/COFF image to return.
188
189 @retval RETURN_SUCCESS EntryPoint was returned.
190 @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image.
191
192 **/
193 RETURN_STATUS
194 InternalPeCoffGetEntryPoint (
195 IN VOID *Pe32Data,
196 OUT VOID **EntryPoint
197 )
198 {
199 EFI_IMAGE_DOS_HEADER *DosHdr;
200 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
201
202 ASSERT (Pe32Data != NULL);
203 ASSERT (EntryPoint != NULL);
204
205 DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;
206 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
207 //
208 // DOS image header is present, so read the PE header after the DOS image header.
209 //
210 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
211 } else {
212 //
213 // DOS image header is not present, so PE header is at the image base.
214 //
215 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;
216 }
217
218 //
219 // Calculate the entry point relative to the start of the image.
220 // AddressOfEntryPoint is common for PE32 & PE32+
221 //
222 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
223 *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);
224 return RETURN_SUCCESS;
225 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
226 *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff));
227 return RETURN_SUCCESS;
228 }
229
230 return RETURN_UNSUPPORTED;
231 }
232
233 /**
234 Build driver info.
235
236 @param ContextData Memory profile context.
237 @param FileName File name of the image.
238 @param ImageBase Image base address.
239 @param ImageSize Image size.
240 @param EntryPoint Entry point of the image.
241 @param ImageSubsystem Image subsystem of the image.
242
243 @param FileType File type of the image.
244
245 @return Pointer to memory profile driver info.
246
247 **/
248 MEMORY_PROFILE_DRIVER_INFO_DATA *
249 BuildDriverInfo (
250 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
251 IN EFI_GUID *FileName,
252 IN PHYSICAL_ADDRESS ImageBase,
253 IN UINT64 ImageSize,
254 IN PHYSICAL_ADDRESS EntryPoint,
255 IN UINT16 ImageSubsystem,
256 IN EFI_FV_FILETYPE FileType
257 )
258 {
259 EFI_STATUS Status;
260 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
261 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
262 VOID *EntryPointInImage;
263
264 //
265 // Use SmmInternalAllocatePool() that will not update profile for this AllocatePool action.
266 //
267 Status = SmmInternalAllocatePool (
268 EfiRuntimeServicesData,
269 sizeof (*DriverInfoData) + sizeof (LIST_ENTRY),
270 (VOID **) &DriverInfoData
271 );
272 if (EFI_ERROR (Status)) {
273 return NULL;
274 }
275
276 ZeroMem (DriverInfoData, sizeof (*DriverInfoData));
277
278 DriverInfo = &DriverInfoData->DriverInfo;
279 DriverInfoData->Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
280 DriverInfo->Header.Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
281 DriverInfo->Header.Length = sizeof (MEMORY_PROFILE_DRIVER_INFO);
282 DriverInfo->Header.Revision = MEMORY_PROFILE_DRIVER_INFO_REVISION;
283 if (FileName != NULL) {
284 CopyMem (&DriverInfo->FileName, FileName, sizeof (EFI_GUID));
285 }
286 DriverInfo->ImageBase = ImageBase;
287 DriverInfo->ImageSize = ImageSize;
288 DriverInfo->EntryPoint = EntryPoint;
289 DriverInfo->ImageSubsystem = ImageSubsystem;
290 if ((EntryPoint != 0) && ((EntryPoint < ImageBase) || (EntryPoint >= (ImageBase + ImageSize)))) {
291 //
292 // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
293 // So patch ImageBuffer here to align the EntryPoint.
294 //
295 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);
296 ASSERT_EFI_ERROR (Status);
297 DriverInfo->ImageBase = ImageBase + EntryPoint - (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
298 }
299 DriverInfo->FileType = FileType;
300 DriverInfoData->AllocInfoList = (LIST_ENTRY *) (DriverInfoData + 1);
301 InitializeListHead (DriverInfoData->AllocInfoList);
302 DriverInfo->CurrentUsage = 0;
303 DriverInfo->PeakUsage = 0;
304 DriverInfo->AllocRecordCount = 0;
305
306 InsertTailList (ContextData->DriverInfoList, &DriverInfoData->Link);
307 ContextData->Context.ImageCount ++;
308 ContextData->Context.TotalImageSize += DriverInfo->ImageSize;
309
310 return DriverInfoData;
311 }
312
313 /**
314 Register image to DXE.
315
316 @param FileName File name of the image.
317 @param ImageBase Image base address.
318 @param ImageSize Image size.
319 @param FileType File type of the image.
320
321 **/
322 VOID
323 RegisterImageToDxe (
324 IN EFI_GUID *FileName,
325 IN PHYSICAL_ADDRESS ImageBase,
326 IN UINT64 ImageSize,
327 IN EFI_FV_FILETYPE FileType
328 )
329 {
330 EFI_STATUS Status;
331 EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol;
332 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
333 UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];
334
335 if (IS_SMRAM_PROFILE_ENABLED) {
336
337 FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;
338 Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID **) &ProfileProtocol);
339 if (!EFI_ERROR (Status)) {
340 EfiInitializeFwVolDevicepathNode (FilePath, FileName);
341 SetDevicePathEndNode (FilePath + 1);
342
343 Status = ProfileProtocol->RegisterImage (
344 ProfileProtocol,
345 (EFI_DEVICE_PATH_PROTOCOL *) FilePath,
346 ImageBase,
347 ImageSize,
348 FileType
349 );
350 }
351 }
352 }
353
354 /**
355 Unregister image from DXE.
356
357 @param FileName File name of the image.
358 @param ImageBase Image base address.
359 @param ImageSize Image size.
360
361 **/
362 VOID
363 UnregisterImageFromDxe (
364 IN EFI_GUID *FileName,
365 IN PHYSICAL_ADDRESS ImageBase,
366 IN UINT64 ImageSize
367 )
368 {
369 EFI_STATUS Status;
370 EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol;
371 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
372 UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];
373
374 if (IS_SMRAM_PROFILE_ENABLED) {
375
376 FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;
377 Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID *) &ProfileProtocol);
378 if (!EFI_ERROR (Status)) {
379 EfiInitializeFwVolDevicepathNode (FilePath, FileName);
380 SetDevicePathEndNode (FilePath + 1);
381
382 Status = ProfileProtocol->UnregisterImage (
383 ProfileProtocol,
384 (EFI_DEVICE_PATH_PROTOCOL *) FilePath,
385 ImageBase,
386 ImageSize
387 );
388 }
389 }
390 }
391
392 /**
393 Register SMM Core to SMRAM profile.
394
395 @param ContextData SMRAM profile context.
396
397 @retval TRUE Register success.
398 @retval FALSE Register fail.
399
400 **/
401 BOOLEAN
402 RegisterSmmCore (
403 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData
404 )
405 {
406 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
407 PHYSICAL_ADDRESS ImageBase;
408
409 ASSERT (ContextData != NULL);
410
411 RegisterImageToDxe (
412 &gEfiCallerIdGuid,
413 gSmmCorePrivate->PiSmmCoreImageBase,
414 gSmmCorePrivate->PiSmmCoreImageSize,
415 EFI_FV_FILETYPE_SMM_CORE
416 );
417
418 ImageBase = gSmmCorePrivate->PiSmmCoreImageBase;
419 DriverInfoData = BuildDriverInfo (
420 ContextData,
421 &gEfiCallerIdGuid,
422 ImageBase,
423 gSmmCorePrivate->PiSmmCoreImageSize,
424 gSmmCorePrivate->PiSmmCoreEntryPoint,
425 InternalPeCoffGetSubsystem ((VOID *) (UINTN) ImageBase),
426 EFI_FV_FILETYPE_SMM_CORE
427 );
428 if (DriverInfoData == NULL) {
429 return FALSE;
430 }
431
432 return TRUE;
433 }
434
435 /**
436 Initialize SMRAM profile.
437
438 **/
439 VOID
440 SmramProfileInit (
441 VOID
442 )
443 {
444 MEMORY_PROFILE_CONTEXT_DATA *SmramProfileContext;
445
446 if (!IS_SMRAM_PROFILE_ENABLED) {
447 return;
448 }
449
450 SmramProfileContext = GetSmramProfileContext ();
451 if (SmramProfileContext != NULL) {
452 return;
453 }
454
455 mSmramProfileRecordingStatus = TRUE;
456 mSmramProfileContextPtr = &mSmramProfileContext;
457
458 RegisterSmmCore (&mSmramProfileContext);
459
460 DEBUG ((EFI_D_INFO, "SmramProfileInit SmramProfileContext - 0x%x\n", &mSmramProfileContext));
461 }
462
463 /**
464 Register SMM image to SMRAM profile.
465
466 @param DriverEntry SMM image info.
467 @param RegisterToDxe Register image to DXE.
468
469 @retval TRUE Register success.
470 @retval FALSE Register fail.
471
472 **/
473 BOOLEAN
474 RegisterSmramProfileImage (
475 IN EFI_SMM_DRIVER_ENTRY *DriverEntry,
476 IN BOOLEAN RegisterToDxe
477 )
478 {
479 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
480 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
481
482 if (!IS_SMRAM_PROFILE_ENABLED) {
483 return FALSE;
484 }
485
486 if (RegisterToDxe) {
487 RegisterImageToDxe (
488 &DriverEntry->FileName,
489 DriverEntry->ImageBuffer,
490 EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage),
491 EFI_FV_FILETYPE_SMM
492 );
493 }
494
495 ContextData = GetSmramProfileContext ();
496 if (ContextData == NULL) {
497 return FALSE;
498 }
499
500 DriverInfoData = BuildDriverInfo (
501 ContextData,
502 &DriverEntry->FileName,
503 DriverEntry->ImageBuffer,
504 EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage),
505 DriverEntry->ImageEntryPoint,
506 InternalPeCoffGetSubsystem ((VOID *) (UINTN) DriverEntry->ImageBuffer),
507 EFI_FV_FILETYPE_SMM
508 );
509 if (DriverInfoData == NULL) {
510 return FALSE;
511 }
512
513 return TRUE;
514 }
515
516 /**
517 Search image from memory profile.
518
519 @param ContextData Memory profile context.
520 @param FileName Image file name.
521 @param Address Image Address.
522
523 @return Pointer to memory profile driver info.
524
525 **/
526 MEMORY_PROFILE_DRIVER_INFO_DATA *
527 GetMemoryProfileDriverInfoByFileNameAndAddress (
528 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
529 IN EFI_GUID *FileName,
530 IN PHYSICAL_ADDRESS Address
531 )
532 {
533 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
534 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
535 LIST_ENTRY *DriverLink;
536 LIST_ENTRY *DriverInfoList;
537
538 DriverInfoList = ContextData->DriverInfoList;
539
540 for (DriverLink = DriverInfoList->ForwardLink;
541 DriverLink != DriverInfoList;
542 DriverLink = DriverLink->ForwardLink) {
543 DriverInfoData = CR (
544 DriverLink,
545 MEMORY_PROFILE_DRIVER_INFO_DATA,
546 Link,
547 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
548 );
549 DriverInfo = &DriverInfoData->DriverInfo;
550 if ((CompareGuid (&DriverInfo->FileName, FileName)) &&
551 (Address >= DriverInfo->ImageBase) &&
552 (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {
553 return DriverInfoData;
554 }
555 }
556
557 return NULL;
558 }
559
560 /**
561 Search dummy image from SMRAM profile.
562
563 @param ContextData Memory profile context.
564
565 @return Pointer to memory profile driver info.
566
567 **/
568 MEMORY_PROFILE_DRIVER_INFO_DATA *
569 FindDummyImage (
570 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData
571 )
572 {
573 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
574 LIST_ENTRY *DriverLink;
575 LIST_ENTRY *DriverInfoList;
576
577 DriverInfoList = ContextData->DriverInfoList;
578
579 for (DriverLink = DriverInfoList->ForwardLink;
580 DriverLink != DriverInfoList;
581 DriverLink = DriverLink->ForwardLink) {
582 DriverInfoData = CR (
583 DriverLink,
584 MEMORY_PROFILE_DRIVER_INFO_DATA,
585 Link,
586 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
587 );
588 if (CompareGuid (&gZeroGuid, &DriverInfoData->DriverInfo.FileName)) {
589 return DriverInfoData;
590 }
591 }
592
593 return BuildDriverInfo (ContextData, &gZeroGuid, 0, 0, 0, 0, 0);
594 }
595
596 /**
597 Search image from memory profile.
598 It will return image, if (Address >= ImageBuffer) AND (Address < ImageBuffer + ImageSize)
599
600 @param ContextData Memory profile context.
601 @param Address Image or Function address.
602
603 @return Pointer to memory profile driver info.
604
605 **/
606 MEMORY_PROFILE_DRIVER_INFO_DATA *
607 GetMemoryProfileDriverInfoFromAddress (
608 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
609 IN PHYSICAL_ADDRESS Address
610 )
611 {
612 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
613 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
614 LIST_ENTRY *DriverLink;
615 LIST_ENTRY *DriverInfoList;
616
617 DriverInfoList = ContextData->DriverInfoList;
618
619 for (DriverLink = DriverInfoList->ForwardLink;
620 DriverLink != DriverInfoList;
621 DriverLink = DriverLink->ForwardLink) {
622 DriverInfoData = CR (
623 DriverLink,
624 MEMORY_PROFILE_DRIVER_INFO_DATA,
625 Link,
626 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
627 );
628 DriverInfo = &DriverInfoData->DriverInfo;
629 if ((Address >= DriverInfo->ImageBase) &&
630 (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {
631 return DriverInfoData;
632 }
633 }
634
635 //
636 // Should never come here.
637 //
638 return FindDummyImage (ContextData);
639 }
640
641 /**
642 Unregister image from SMRAM profile.
643
644 @param DriverEntry SMM image info.
645 @param UnregisterFromDxe Unregister image from DXE.
646
647 @retval TRUE Unregister success.
648 @retval FALSE Unregister fail.
649
650 **/
651 BOOLEAN
652 UnregisterSmramProfileImage (
653 IN EFI_SMM_DRIVER_ENTRY *DriverEntry,
654 IN BOOLEAN UnregisterFromDxe
655 )
656 {
657 EFI_STATUS Status;
658 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
659 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
660 EFI_GUID *FileName;
661 PHYSICAL_ADDRESS ImageAddress;
662 VOID *EntryPointInImage;
663
664 if (!IS_SMRAM_PROFILE_ENABLED) {
665 return FALSE;
666 }
667
668 if (UnregisterFromDxe) {
669 UnregisterImageFromDxe (
670 &DriverEntry->FileName,
671 DriverEntry->ImageBuffer,
672 EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage)
673 );
674 }
675
676 ContextData = GetSmramProfileContext ();
677 if (ContextData == NULL) {
678 return FALSE;
679 }
680
681 DriverInfoData = NULL;
682 FileName = &DriverEntry->FileName;
683 ImageAddress = DriverEntry->ImageBuffer;
684 if ((DriverEntry->ImageEntryPoint < ImageAddress) || (DriverEntry->ImageEntryPoint >= (ImageAddress + EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage)))) {
685 //
686 // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
687 // So patch ImageAddress here to align the EntryPoint.
688 //
689 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageAddress, &EntryPointInImage);
690 ASSERT_EFI_ERROR (Status);
691 ImageAddress = ImageAddress + (UINTN) DriverEntry->ImageEntryPoint - (UINTN) EntryPointInImage;
692 }
693 if (FileName != NULL) {
694 DriverInfoData = GetMemoryProfileDriverInfoByFileNameAndAddress (ContextData, FileName, ImageAddress);
695 }
696 if (DriverInfoData == NULL) {
697 DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, ImageAddress);
698 }
699 if (DriverInfoData == NULL) {
700 return FALSE;
701 }
702
703 ContextData->Context.TotalImageSize -= DriverInfoData->DriverInfo.ImageSize;
704
705 DriverInfoData->DriverInfo.ImageBase = 0;
706 DriverInfoData->DriverInfo.ImageSize = 0;
707
708 if (DriverInfoData->DriverInfo.PeakUsage == 0) {
709 ContextData->Context.ImageCount --;
710 RemoveEntryList (&DriverInfoData->Link);
711 //
712 // Use SmmInternalFreePool() that will not update profile for this FreePool action.
713 //
714 SmmInternalFreePool (DriverInfoData);
715 }
716
717 return TRUE;
718 }
719
720 /**
721 Return if this memory type needs to be recorded into memory profile.
722 Only need to record EfiRuntimeServicesCode and EfiRuntimeServicesData for SMRAM profile.
723
724 @param MemoryType Memory type.
725
726 @retval TRUE This memory type need to be recorded.
727 @retval FALSE This memory type need not to be recorded.
728
729 **/
730 BOOLEAN
731 SmmCoreNeedRecordProfile (
732 IN EFI_MEMORY_TYPE MemoryType
733 )
734 {
735 UINT64 TestBit;
736
737 if (MemoryType != EfiRuntimeServicesCode &&
738 MemoryType != EfiRuntimeServicesData) {
739 return FALSE;
740 }
741
742 TestBit = LShiftU64 (1, MemoryType);
743
744 if ((PcdGet64 (PcdMemoryProfileMemoryType) & TestBit) != 0) {
745 return TRUE;
746 } else {
747 return FALSE;
748 }
749 }
750
751 /**
752 Convert EFI memory type to profile memory index. The rule is:
753 If BIOS memory type (0 ~ EfiMaxMemoryType - 1), ProfileMemoryIndex = MemoryType.
754 As SMRAM profile is only to record EfiRuntimeServicesCode and EfiRuntimeServicesData,
755 so return input memory type directly.
756
757 @param MemoryType Memory type.
758
759 @return EFI memory type as profile memory index.
760
761 **/
762 EFI_MEMORY_TYPE
763 GetProfileMemoryIndex (
764 IN EFI_MEMORY_TYPE MemoryType
765 )
766 {
767 return MemoryType;
768 }
769
770 /**
771 Update SMRAM profile FreeMemoryPages information
772
773 @param ContextData Memory profile context.
774
775 **/
776 VOID
777 SmramProfileUpdateFreePages (
778 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData
779 )
780 {
781 LIST_ENTRY *Node;
782 FREE_PAGE_LIST *Pages;
783 LIST_ENTRY *FreePageList;
784 UINTN NumberOfPages;
785
786 NumberOfPages = 0;
787 FreePageList = &mSmmMemoryMap;
788 for (Node = FreePageList->BackLink;
789 Node != FreePageList;
790 Node = Node->BackLink) {
791 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
792 NumberOfPages += Pages->NumberOfPages;
793 }
794
795 mSmramFreeMemory.TotalFreeMemoryPages = NumberOfPages;
796
797 if (NumberOfPages <= SMRAM_INFO_DUMP_PAGE_THRESHOLD) {
798 DumpSmramInfo ();
799 }
800 }
801
802 /**
803 Update SMRAM profile Allocate information.
804
805 @param CallerAddress Address of caller who call Allocate.
806 @param Action This Allocate action.
807 @param MemoryType Memory type.
808 @param Size Buffer size.
809 @param Buffer Buffer address.
810
811 @retval TRUE Profile udpate success.
812 @retval FALSE Profile update fail.
813
814 **/
815 BOOLEAN
816 SmmCoreUpdateProfileAllocate (
817 IN PHYSICAL_ADDRESS CallerAddress,
818 IN MEMORY_PROFILE_ACTION Action,
819 IN EFI_MEMORY_TYPE MemoryType,
820 IN UINTN Size,
821 IN VOID *Buffer
822 )
823 {
824 EFI_STATUS Status;
825 MEMORY_PROFILE_CONTEXT *Context;
826 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
827 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
828 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
829 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
830 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
831 EFI_MEMORY_TYPE ProfileMemoryIndex;
832
833 AllocInfoData = NULL;
834
835 ContextData = GetSmramProfileContext ();
836 if (ContextData == NULL) {
837 return FALSE;
838 }
839
840 DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
841 ASSERT (DriverInfoData != NULL);
842
843 //
844 // Use SmmInternalAllocatePool() that will not update profile for this AllocatePool action.
845 //
846 Status = SmmInternalAllocatePool (
847 EfiRuntimeServicesData,
848 sizeof (*AllocInfoData),
849 (VOID **) &AllocInfoData
850 );
851 if (EFI_ERROR (Status)) {
852 return FALSE;
853 }
854 AllocInfo = &AllocInfoData->AllocInfo;
855 AllocInfoData->Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
856 AllocInfo->Header.Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
857 AllocInfo->Header.Length = sizeof (MEMORY_PROFILE_ALLOC_INFO);
858 AllocInfo->Header.Revision = MEMORY_PROFILE_ALLOC_INFO_REVISION;
859 AllocInfo->CallerAddress = CallerAddress;
860 AllocInfo->SequenceId = ContextData->Context.SequenceCount;
861 AllocInfo->Action = Action;
862 AllocInfo->MemoryType = MemoryType;
863 AllocInfo->Buffer = (PHYSICAL_ADDRESS) (UINTN) Buffer;
864 AllocInfo->Size = Size;
865
866 InsertTailList (DriverInfoData->AllocInfoList, &AllocInfoData->Link);
867
868 ProfileMemoryIndex = GetProfileMemoryIndex (MemoryType);
869
870 DriverInfo = &DriverInfoData->DriverInfo;
871 DriverInfo->CurrentUsage += Size;
872 if (DriverInfo->PeakUsage < DriverInfo->CurrentUsage) {
873 DriverInfo->PeakUsage = DriverInfo->CurrentUsage;
874 }
875 DriverInfo->CurrentUsageByType[ProfileMemoryIndex] += Size;
876 if (DriverInfo->PeakUsageByType[ProfileMemoryIndex] < DriverInfo->CurrentUsageByType[ProfileMemoryIndex]) {
877 DriverInfo->PeakUsageByType[ProfileMemoryIndex] = DriverInfo->CurrentUsageByType[ProfileMemoryIndex];
878 }
879 DriverInfo->AllocRecordCount ++;
880
881 Context = &ContextData->Context;
882 Context->CurrentTotalUsage += Size;
883 if (Context->PeakTotalUsage < Context->CurrentTotalUsage) {
884 Context->PeakTotalUsage = Context->CurrentTotalUsage;
885 }
886 Context->CurrentTotalUsageByType[ProfileMemoryIndex] += Size;
887 if (Context->PeakTotalUsageByType[ProfileMemoryIndex] < Context->CurrentTotalUsageByType[ProfileMemoryIndex]) {
888 Context->PeakTotalUsageByType[ProfileMemoryIndex] = Context->CurrentTotalUsageByType[ProfileMemoryIndex];
889 }
890 Context->SequenceCount ++;
891
892 SmramProfileUpdateFreePages (ContextData);
893 return TRUE;
894 }
895
896 /**
897 Get memory profile alloc info from memory profile
898
899 @param DriverInfoData Driver info
900 @param Action This Free action
901 @param Size Buffer size
902 @param Buffer Buffer address
903
904 @return Pointer to memory profile alloc info.
905 **/
906 MEMORY_PROFILE_ALLOC_INFO_DATA *
907 GetMemoryProfileAllocInfoFromAddress (
908 IN MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData,
909 IN MEMORY_PROFILE_ACTION Action,
910 IN UINTN Size,
911 IN VOID *Buffer
912 )
913 {
914 LIST_ENTRY *AllocInfoList;
915 LIST_ENTRY *AllocLink;
916 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
917 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
918
919 AllocInfoList = DriverInfoData->AllocInfoList;
920
921 for (AllocLink = AllocInfoList->ForwardLink;
922 AllocLink != AllocInfoList;
923 AllocLink = AllocLink->ForwardLink) {
924 AllocInfoData = CR (
925 AllocLink,
926 MEMORY_PROFILE_ALLOC_INFO_DATA,
927 Link,
928 MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
929 );
930 AllocInfo = &AllocInfoData->AllocInfo;
931 if (AllocInfo->Action != Action) {
932 continue;
933 }
934 switch (Action) {
935 case MemoryProfileActionAllocatePages:
936 if ((AllocInfo->Buffer <= (PHYSICAL_ADDRESS) (UINTN) Buffer) &&
937 ((AllocInfo->Buffer + AllocInfo->Size) >= ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size))) {
938 return AllocInfoData;
939 }
940 break;
941 case MemoryProfileActionAllocatePool:
942 if (AllocInfo->Buffer == (PHYSICAL_ADDRESS) (UINTN) Buffer) {
943 return AllocInfoData;
944 }
945 break;
946 default:
947 ASSERT (FALSE);
948 break;
949 }
950 }
951
952 return NULL;
953 }
954
955 /**
956 Update SMRAM profile Free information.
957
958 @param CallerAddress Address of caller who call Free.
959 @param Action This Free action.
960 @param Size Buffer size.
961 @param Buffer Buffer address.
962
963 @retval TRUE Profile udpate success.
964 @retval FALSE Profile update fail.
965
966 **/
967 BOOLEAN
968 SmmCoreUpdateProfileFree (
969 IN PHYSICAL_ADDRESS CallerAddress,
970 IN MEMORY_PROFILE_ACTION Action,
971 IN UINTN Size,
972 IN VOID *Buffer
973 )
974 {
975 MEMORY_PROFILE_CONTEXT *Context;
976 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
977 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
978 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
979 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
980 LIST_ENTRY *DriverLink;
981 LIST_ENTRY *DriverInfoList;
982 MEMORY_PROFILE_DRIVER_INFO_DATA *ThisDriverInfoData;
983 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
984 EFI_MEMORY_TYPE ProfileMemoryIndex;
985
986 ContextData = GetSmramProfileContext ();
987 if (ContextData == NULL) {
988 return FALSE;
989 }
990
991 DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
992 ASSERT (DriverInfoData != NULL);
993
994 switch (Action) {
995 case MemoryProfileActionFreePages:
996 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
997 break;
998 case MemoryProfileActionFreePool:
999 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
1000 break;
1001 default:
1002 ASSERT (FALSE);
1003 AllocInfoData = NULL;
1004 break;
1005 }
1006 if (AllocInfoData == NULL) {
1007 //
1008 // Legal case, because driver A might free memory allocated by driver B, by some protocol.
1009 //
1010 DriverInfoList = ContextData->DriverInfoList;
1011
1012 for (DriverLink = DriverInfoList->ForwardLink;
1013 DriverLink != DriverInfoList;
1014 DriverLink = DriverLink->ForwardLink) {
1015 ThisDriverInfoData = CR (
1016 DriverLink,
1017 MEMORY_PROFILE_DRIVER_INFO_DATA,
1018 Link,
1019 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
1020 );
1021 switch (Action) {
1022 case MemoryProfileActionFreePages:
1023 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
1024 break;
1025 case MemoryProfileActionFreePool:
1026 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
1027 break;
1028 default:
1029 ASSERT (FALSE);
1030 AllocInfoData = NULL;
1031 break;
1032 }
1033 if (AllocInfoData != NULL) {
1034 DriverInfoData = ThisDriverInfoData;
1035 break;
1036 }
1037 }
1038
1039 if (AllocInfoData == NULL) {
1040 //
1041 // No matched allocate operation is found for this free operation.
1042 // It is because the specified memory type allocate operation has been
1043 // filtered by CoreNeedRecordProfile(), but free operations have no
1044 // memory type information, they can not be filtered by CoreNeedRecordProfile().
1045 // Then, they will be filtered here.
1046 //
1047 return FALSE;
1048 }
1049 }
1050
1051 Context = &ContextData->Context;
1052 DriverInfo = &DriverInfoData->DriverInfo;
1053 AllocInfo = &AllocInfoData->AllocInfo;
1054
1055 ProfileMemoryIndex = GetProfileMemoryIndex (AllocInfo->MemoryType);
1056
1057 Context->CurrentTotalUsage -= AllocInfo->Size;
1058 Context->CurrentTotalUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
1059
1060 DriverInfo->CurrentUsage -= AllocInfo->Size;
1061 DriverInfo->CurrentUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
1062 DriverInfo->AllocRecordCount --;
1063
1064 RemoveEntryList (&AllocInfoData->Link);
1065
1066 if (Action == MemoryProfileActionFreePages) {
1067 if (AllocInfo->Buffer != (PHYSICAL_ADDRESS) (UINTN) Buffer) {
1068 SmmCoreUpdateProfileAllocate (
1069 AllocInfo->CallerAddress,
1070 MemoryProfileActionAllocatePages,
1071 AllocInfo->MemoryType,
1072 (UINTN) ((PHYSICAL_ADDRESS) (UINTN) Buffer - AllocInfo->Buffer),
1073 (VOID *) (UINTN) AllocInfo->Buffer
1074 );
1075 }
1076 if (AllocInfo->Buffer + AllocInfo->Size != ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)) {
1077 SmmCoreUpdateProfileAllocate (
1078 AllocInfo->CallerAddress,
1079 MemoryProfileActionAllocatePages,
1080 AllocInfo->MemoryType,
1081 (UINTN) ((AllocInfo->Buffer + AllocInfo->Size) - ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)),
1082 (VOID *) ((UINTN) Buffer + Size)
1083 );
1084 }
1085 }
1086
1087 //
1088 // Use SmmInternalFreePool() that will not update profile for this FreePool action.
1089 //
1090 SmmInternalFreePool (AllocInfoData);
1091
1092 return TRUE;
1093 }
1094
1095 /**
1096 Update SMRAM profile information.
1097
1098 @param CallerAddress Address of caller who call Allocate or Free.
1099 @param Action This Allocate or Free action.
1100 @param MemoryType Memory type.
1101 @param Size Buffer size.
1102 @param Buffer Buffer address.
1103
1104 @retval TRUE Profile udpate success.
1105 @retval FALSE Profile update fail.
1106
1107 **/
1108 BOOLEAN
1109 SmmCoreUpdateProfile (
1110 IN PHYSICAL_ADDRESS CallerAddress,
1111 IN MEMORY_PROFILE_ACTION Action,
1112 IN EFI_MEMORY_TYPE MemoryType, // Valid for AllocatePages/AllocatePool
1113 IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool
1114 IN VOID *Buffer
1115 )
1116 {
1117 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
1118
1119 if (!IS_SMRAM_PROFILE_ENABLED) {
1120 return FALSE;
1121 }
1122
1123 if (!mSmramProfileRecordingStatus) {
1124 return FALSE;
1125 }
1126
1127 //
1128 // Free operations have no memory type information, so skip the check.
1129 //
1130 if ((Action == MemoryProfileActionAllocatePages) || (Action == MemoryProfileActionAllocatePool)) {
1131 //
1132 // Only record limited MemoryType.
1133 //
1134 if (!SmmCoreNeedRecordProfile (MemoryType)) {
1135 return FALSE;
1136 }
1137 }
1138
1139 ContextData = GetSmramProfileContext ();
1140 if (ContextData == NULL) {
1141 return FALSE;
1142 }
1143
1144 switch (Action) {
1145 case MemoryProfileActionAllocatePages:
1146 SmmCoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer);
1147 break;
1148 case MemoryProfileActionFreePages:
1149 SmmCoreUpdateProfileFree (CallerAddress, Action, Size, Buffer);
1150 break;
1151 case MemoryProfileActionAllocatePool:
1152 SmmCoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer);
1153 break;
1154 case MemoryProfileActionFreePool:
1155 SmmCoreUpdateProfileFree (CallerAddress, Action, 0, Buffer);
1156 break;
1157 default:
1158 ASSERT (FALSE);
1159 break;
1160 }
1161
1162 return TRUE;
1163 }
1164
1165 /**
1166 SMRAM profile ready to lock callback function.
1167
1168 **/
1169 VOID
1170 SmramProfileReadyToLock (
1171 VOID
1172 )
1173 {
1174 if (!IS_SMRAM_PROFILE_ENABLED) {
1175 return;
1176 }
1177
1178 DEBUG ((EFI_D_INFO, "SmramProfileReadyToLock\n"));
1179 mSmramReadyToLock = TRUE;
1180 }
1181
1182 ////////////////////
1183
1184 /**
1185 Get SMRAM profile data size.
1186
1187 @return SMRAM profile data size.
1188
1189 **/
1190 UINTN
1191 SmramProfileGetDataSize (
1192 VOID
1193 )
1194 {
1195 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
1196 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
1197 LIST_ENTRY *DriverInfoList;
1198 LIST_ENTRY *DriverLink;
1199 UINTN TotalSize;
1200 LIST_ENTRY *Node;
1201 LIST_ENTRY *FreePageList;
1202 LIST_ENTRY *FreePoolList;
1203 FREE_POOL_HEADER *Pool;
1204 UINTN PoolListIndex;
1205 UINTN Index;
1206
1207 ContextData = GetSmramProfileContext ();
1208 if (ContextData == NULL) {
1209 return 0;
1210 }
1211
1212 TotalSize = sizeof (MEMORY_PROFILE_CONTEXT);
1213 TotalSize += sizeof (MEMORY_PROFILE_DRIVER_INFO) * (UINTN) ContextData->Context.ImageCount;
1214
1215 DriverInfoList = ContextData->DriverInfoList;
1216 for (DriverLink = DriverInfoList->ForwardLink;
1217 DriverLink != DriverInfoList;
1218 DriverLink = DriverLink->ForwardLink) {
1219 DriverInfoData = CR (
1220 DriverLink,
1221 MEMORY_PROFILE_DRIVER_INFO_DATA,
1222 Link,
1223 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
1224 );
1225 TotalSize += sizeof (MEMORY_PROFILE_ALLOC_INFO) * (UINTN) DriverInfoData->DriverInfo.AllocRecordCount;
1226 }
1227
1228
1229 Index = 0;
1230 FreePageList = &mSmmMemoryMap;
1231 for (Node = FreePageList->BackLink;
1232 Node != FreePageList;
1233 Node = Node->BackLink) {
1234 Index++;
1235 }
1236 for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
1237 FreePoolList = &mSmmPoolLists[PoolListIndex];
1238 for (Node = FreePoolList->BackLink;
1239 Node != FreePoolList;
1240 Node = Node->BackLink) {
1241 Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
1242 if (Pool->Header.Available) {
1243 Index++;
1244 }
1245 }
1246 }
1247
1248
1249 TotalSize += (sizeof (MEMORY_PROFILE_FREE_MEMORY) + Index * sizeof (MEMORY_PROFILE_DESCRIPTOR));
1250 TotalSize += (sizeof (MEMORY_PROFILE_MEMORY_RANGE) + mFullSmramRangeCount * sizeof (MEMORY_PROFILE_DESCRIPTOR));
1251
1252 return TotalSize;
1253 }
1254
1255 /**
1256 Copy SMRAM profile data.
1257
1258 @param ProfileBuffer The buffer to hold SMRAM profile data.
1259 @param ProfileSize On input, profile buffer size.
1260 On output, actual profile data size copied.
1261 @param ProfileOffset On input, profile buffer offset to copy.
1262 On output, next time profile buffer offset to copy.
1263
1264 **/
1265 VOID
1266 SmramProfileCopyData (
1267 OUT VOID *ProfileBuffer,
1268 IN OUT UINT64 *ProfileSize,
1269 IN OUT UINT64 *ProfileOffset
1270 )
1271 {
1272 MEMORY_PROFILE_CONTEXT *Context;
1273 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
1274 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
1275 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
1276 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
1277 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
1278 LIST_ENTRY *DriverInfoList;
1279 LIST_ENTRY *DriverLink;
1280 LIST_ENTRY *AllocInfoList;
1281 LIST_ENTRY *AllocLink;
1282 LIST_ENTRY *Node;
1283 FREE_PAGE_LIST *Pages;
1284 LIST_ENTRY *FreePageList;
1285 LIST_ENTRY *FreePoolList;
1286 FREE_POOL_HEADER *Pool;
1287 UINTN PoolListIndex;
1288 UINT32 Index;
1289 MEMORY_PROFILE_FREE_MEMORY *FreeMemory;
1290 MEMORY_PROFILE_MEMORY_RANGE *MemoryRange;
1291 MEMORY_PROFILE_DESCRIPTOR *MemoryProfileDescriptor;
1292 UINT64 Offset;
1293 UINT64 RemainingSize;
1294
1295 ContextData = GetSmramProfileContext ();
1296 if (ContextData == NULL) {
1297 return ;
1298 }
1299
1300 RemainingSize = *ProfileSize;
1301 Offset = 0;
1302
1303 if (*ProfileOffset < sizeof (MEMORY_PROFILE_CONTEXT)) {
1304 if (RemainingSize >= sizeof (MEMORY_PROFILE_CONTEXT)) {
1305 Context = ProfileBuffer;
1306 CopyMem (Context, &ContextData->Context, sizeof (MEMORY_PROFILE_CONTEXT));
1307 RemainingSize -= sizeof (MEMORY_PROFILE_CONTEXT);
1308 ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_CONTEXT);
1309 } else {
1310 goto Done;
1311 }
1312 }
1313 Offset += sizeof (MEMORY_PROFILE_CONTEXT);
1314
1315 DriverInfoList = ContextData->DriverInfoList;
1316 for (DriverLink = DriverInfoList->ForwardLink;
1317 DriverLink != DriverInfoList;
1318 DriverLink = DriverLink->ForwardLink) {
1319 DriverInfoData = CR (
1320 DriverLink,
1321 MEMORY_PROFILE_DRIVER_INFO_DATA,
1322 Link,
1323 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
1324 );
1325 if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_DRIVER_INFO))) {
1326 if (RemainingSize >= sizeof (MEMORY_PROFILE_DRIVER_INFO)) {
1327 DriverInfo = ProfileBuffer;
1328 CopyMem (DriverInfo, &DriverInfoData->DriverInfo, sizeof (MEMORY_PROFILE_DRIVER_INFO));
1329 RemainingSize -= sizeof (MEMORY_PROFILE_DRIVER_INFO);
1330 ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_DRIVER_INFO);
1331 } else {
1332 goto Done;
1333 }
1334 }
1335 Offset += sizeof (MEMORY_PROFILE_DRIVER_INFO);
1336
1337 AllocInfoList = DriverInfoData->AllocInfoList;
1338 for (AllocLink = AllocInfoList->ForwardLink;
1339 AllocLink != AllocInfoList;
1340 AllocLink = AllocLink->ForwardLink) {
1341 AllocInfoData = CR (
1342 AllocLink,
1343 MEMORY_PROFILE_ALLOC_INFO_DATA,
1344 Link,
1345 MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
1346 );
1347 if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_ALLOC_INFO))) {
1348 if (RemainingSize >= sizeof (MEMORY_PROFILE_ALLOC_INFO)) {
1349 AllocInfo = ProfileBuffer;
1350 CopyMem (AllocInfo, &AllocInfoData->AllocInfo, sizeof (MEMORY_PROFILE_ALLOC_INFO));
1351 RemainingSize -= sizeof (MEMORY_PROFILE_ALLOC_INFO);
1352 ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_ALLOC_INFO);
1353 } else {
1354 goto Done;
1355 }
1356 }
1357 Offset += sizeof (MEMORY_PROFILE_ALLOC_INFO);
1358 }
1359 }
1360
1361
1362 if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_FREE_MEMORY))) {
1363 if (RemainingSize >= sizeof (MEMORY_PROFILE_FREE_MEMORY)) {
1364 FreeMemory = ProfileBuffer;
1365 CopyMem (FreeMemory, &mSmramFreeMemory, sizeof (MEMORY_PROFILE_FREE_MEMORY));
1366 Index = 0;
1367 FreePageList = &mSmmMemoryMap;
1368 for (Node = FreePageList->BackLink;
1369 Node != FreePageList;
1370 Node = Node->BackLink) {
1371 Index++;
1372 }
1373 for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
1374 FreePoolList = &mSmmPoolLists[MAX_POOL_INDEX - PoolListIndex - 1];
1375 for (Node = FreePoolList->BackLink;
1376 Node != FreePoolList;
1377 Node = Node->BackLink) {
1378 Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
1379 if (Pool->Header.Available) {
1380 Index++;
1381 }
1382 }
1383 }
1384 FreeMemory->FreeMemoryEntryCount = Index;
1385
1386 RemainingSize -= sizeof (MEMORY_PROFILE_FREE_MEMORY);
1387 ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_FREE_MEMORY);
1388 } else {
1389 goto Done;
1390 }
1391 }
1392 Offset += sizeof (MEMORY_PROFILE_FREE_MEMORY);
1393 FreePageList = &mSmmMemoryMap;
1394 for (Node = FreePageList->BackLink;
1395 Node != FreePageList;
1396 Node = Node->BackLink) {
1397 if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_DESCRIPTOR))) {
1398 if (RemainingSize >= sizeof (MEMORY_PROFILE_DESCRIPTOR)) {
1399 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
1400 MemoryProfileDescriptor = ProfileBuffer;
1401 MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;
1402 MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);
1403 MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;
1404 MemoryProfileDescriptor->Address = (PHYSICAL_ADDRESS) (UINTN) Pages;
1405 MemoryProfileDescriptor->Size = EFI_PAGES_TO_SIZE (Pages->NumberOfPages);
1406
1407 RemainingSize -= sizeof (MEMORY_PROFILE_DESCRIPTOR);
1408 ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_DESCRIPTOR);
1409 } else {
1410 goto Done;
1411 }
1412 }
1413 Offset += sizeof (MEMORY_PROFILE_DESCRIPTOR);
1414 }
1415 for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
1416 FreePoolList = &mSmmPoolLists[MAX_POOL_INDEX - PoolListIndex - 1];
1417 for (Node = FreePoolList->BackLink;
1418 Node != FreePoolList;
1419 Node = Node->BackLink) {
1420 Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
1421 if (Pool->Header.Available) {
1422 if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_DESCRIPTOR))) {
1423 if (RemainingSize >= sizeof (MEMORY_PROFILE_DESCRIPTOR)) {
1424 MemoryProfileDescriptor = ProfileBuffer;
1425 MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;
1426 MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);
1427 MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;
1428 MemoryProfileDescriptor->Address = (PHYSICAL_ADDRESS) (UINTN) Pool;
1429 MemoryProfileDescriptor->Size = Pool->Header.Size;
1430
1431 RemainingSize -= sizeof (MEMORY_PROFILE_DESCRIPTOR);
1432 ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_DESCRIPTOR);
1433 } else {
1434 goto Done;
1435 }
1436 }
1437 Offset += sizeof (MEMORY_PROFILE_DESCRIPTOR);
1438 }
1439 }
1440 }
1441
1442 if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_MEMORY_RANGE))) {
1443 if (RemainingSize >= sizeof (MEMORY_PROFILE_MEMORY_RANGE)) {
1444 MemoryRange = ProfileBuffer;
1445 MemoryRange->Header.Signature = MEMORY_PROFILE_MEMORY_RANGE_SIGNATURE;
1446 MemoryRange->Header.Length = sizeof (MEMORY_PROFILE_MEMORY_RANGE);
1447 MemoryRange->Header.Revision = MEMORY_PROFILE_MEMORY_RANGE_REVISION;
1448 MemoryRange->MemoryRangeCount = (UINT32) mFullSmramRangeCount;
1449
1450 RemainingSize -= sizeof (MEMORY_PROFILE_MEMORY_RANGE);
1451 ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_MEMORY_RANGE);
1452 } else {
1453 goto Done;
1454 }
1455 }
1456 Offset += sizeof (MEMORY_PROFILE_MEMORY_RANGE);
1457 for (Index = 0; Index < mFullSmramRangeCount; Index++) {
1458 if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_DESCRIPTOR))) {
1459 if (RemainingSize >= sizeof (MEMORY_PROFILE_DESCRIPTOR)) {
1460 MemoryProfileDescriptor = ProfileBuffer;
1461 MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;
1462 MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);
1463 MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;
1464 MemoryProfileDescriptor->Address = mFullSmramRanges[Index].PhysicalStart;
1465 MemoryProfileDescriptor->Size = mFullSmramRanges[Index].PhysicalSize;
1466
1467 RemainingSize -= sizeof (MEMORY_PROFILE_DESCRIPTOR);
1468 ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_DESCRIPTOR);
1469 } else {
1470 goto Done;
1471 }
1472 }
1473 Offset += sizeof (MEMORY_PROFILE_DESCRIPTOR);
1474 }
1475
1476 Done:
1477 //
1478 // On output, actual profile data size copied.
1479 //
1480 *ProfileSize -= RemainingSize;
1481 //
1482 // On output, next time profile buffer offset to copy.
1483 //
1484 *ProfileOffset = Offset;
1485 }
1486
1487 /**
1488 SMRAM profile handler to get profile info.
1489
1490 @param SmramProfileParameterGetInfo The parameter of SMM profile get size.
1491
1492 **/
1493 VOID
1494 SmramProfileHandlerGetInfo (
1495 IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *SmramProfileParameterGetInfo
1496 )
1497 {
1498 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
1499 BOOLEAN SmramProfileRecordingStatus;
1500
1501 ContextData = GetSmramProfileContext ();
1502 if (ContextData == NULL) {
1503 return ;
1504 }
1505
1506 SmramProfileRecordingStatus = mSmramProfileRecordingStatus;
1507 mSmramProfileRecordingStatus = FALSE;
1508
1509 SmramProfileParameterGetInfo->ProfileSize = SmramProfileGetDataSize();
1510 SmramProfileParameterGetInfo->Header.ReturnStatus = 0;
1511
1512 mSmramProfileRecordingStatus = SmramProfileRecordingStatus;
1513 }
1514
1515 /**
1516 SMRAM profile handler to get profile data.
1517
1518 @param SmramProfileParameterGetData The parameter of SMM profile get data.
1519
1520 **/
1521 VOID
1522 SmramProfileHandlerGetData (
1523 IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA *SmramProfileParameterGetData
1524 )
1525 {
1526 UINT64 ProfileSize;
1527 UINT64 ProfileOffset;
1528 SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA SmramProfileGetData;
1529 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
1530 BOOLEAN SmramProfileRecordingStatus;
1531
1532 ContextData = GetSmramProfileContext ();
1533 if (ContextData == NULL) {
1534 return ;
1535 }
1536
1537 SmramProfileRecordingStatus = mSmramProfileRecordingStatus;
1538 mSmramProfileRecordingStatus = FALSE;
1539
1540
1541 CopyMem (&SmramProfileGetData, SmramProfileParameterGetData, sizeof (SmramProfileGetData));
1542
1543 ProfileSize = SmramProfileGetDataSize();
1544
1545 //
1546 // Sanity check
1547 //
1548 if (!SmmIsBufferOutsideSmmValid ((UINTN) SmramProfileGetData.ProfileBuffer, (UINTN) ProfileSize)) {
1549 DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetData: SMM ProfileBuffer in SMRAM or overflow!\n"));
1550 SmramProfileParameterGetData->ProfileSize = ProfileSize;
1551 SmramProfileParameterGetData->Header.ReturnStatus = (UINT64) (INT64) (INTN) EFI_ACCESS_DENIED;
1552 goto Done;
1553 }
1554
1555 if (SmramProfileGetData.ProfileSize < ProfileSize) {
1556 SmramProfileParameterGetData->ProfileSize = ProfileSize;
1557 SmramProfileParameterGetData->Header.ReturnStatus = (UINT64) (INT64) (INTN) EFI_BUFFER_TOO_SMALL;
1558 goto Done;
1559 }
1560
1561 ProfileOffset = 0;
1562 SmramProfileCopyData ((VOID *) (UINTN) SmramProfileGetData.ProfileBuffer, &ProfileSize, &ProfileOffset);
1563 SmramProfileParameterGetData->ProfileSize = ProfileSize;
1564 SmramProfileParameterGetData->Header.ReturnStatus = 0;
1565
1566 Done:
1567 mSmramProfileRecordingStatus = SmramProfileRecordingStatus;
1568 }
1569
1570 /**
1571 SMRAM profile handler to get profile data by offset.
1572
1573 @param SmramProfileParameterGetDataByOffset The parameter of SMM profile get data by offset.
1574
1575 **/
1576 VOID
1577 SmramProfileHandlerGetDataByOffset (
1578 IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET *SmramProfileParameterGetDataByOffset
1579 )
1580 {
1581 SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET SmramProfileGetDataByOffset;
1582 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
1583 BOOLEAN SmramProfileRecordingStatus;
1584
1585 ContextData = GetSmramProfileContext ();
1586 if (ContextData == NULL) {
1587 return ;
1588 }
1589
1590 SmramProfileRecordingStatus = mSmramProfileRecordingStatus;
1591 mSmramProfileRecordingStatus = FALSE;
1592
1593
1594 CopyMem (&SmramProfileGetDataByOffset, SmramProfileParameterGetDataByOffset, sizeof (SmramProfileGetDataByOffset));
1595
1596 //
1597 // Sanity check
1598 //
1599 if (!SmmIsBufferOutsideSmmValid ((UINTN) SmramProfileGetDataByOffset.ProfileBuffer, (UINTN) SmramProfileGetDataByOffset.ProfileSize)) {
1600 DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetDataByOffset: SMM ProfileBuffer in SMRAM or overflow!\n"));
1601 SmramProfileParameterGetDataByOffset->Header.ReturnStatus = (UINT64) (INT64) (INTN) EFI_ACCESS_DENIED;
1602 goto Done;
1603 }
1604
1605 SmramProfileCopyData ((VOID *) (UINTN) SmramProfileGetDataByOffset.ProfileBuffer, &SmramProfileGetDataByOffset.ProfileSize, &SmramProfileGetDataByOffset.ProfileOffset);
1606 CopyMem (SmramProfileParameterGetDataByOffset, &SmramProfileGetDataByOffset, sizeof (SmramProfileGetDataByOffset));
1607 SmramProfileParameterGetDataByOffset->Header.ReturnStatus = 0;
1608
1609 Done:
1610 mSmramProfileRecordingStatus = SmramProfileRecordingStatus;
1611 }
1612
1613 /**
1614 SMRAM profile handler to register SMM image.
1615
1616 @param SmramProfileParameterRegisterImage The parameter of SMM profile register image.
1617
1618 **/
1619 VOID
1620 SmramProfileHandlerRegisterImage (
1621 IN SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE *SmramProfileParameterRegisterImage
1622 )
1623 {
1624 EFI_STATUS Status;
1625 EFI_SMM_DRIVER_ENTRY DriverEntry;
1626 VOID *EntryPointInImage;
1627 BOOLEAN Ret;
1628
1629 ZeroMem (&DriverEntry, sizeof (DriverEntry));
1630 CopyMem (&DriverEntry.FileName, &SmramProfileParameterRegisterImage->FileName, sizeof(EFI_GUID));
1631 DriverEntry.ImageBuffer = SmramProfileParameterRegisterImage->ImageBuffer;
1632 DriverEntry.NumberOfPage = (UINTN) SmramProfileParameterRegisterImage->NumberOfPage;
1633 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) DriverEntry.ImageBuffer, &EntryPointInImage);
1634 ASSERT_EFI_ERROR (Status);
1635 DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
1636
1637 Ret = RegisterSmramProfileImage (&DriverEntry, FALSE);
1638 if (Ret) {
1639 SmramProfileParameterRegisterImage->Header.ReturnStatus = 0;
1640 }
1641 }
1642
1643 /**
1644 SMRAM profile handler to unregister SMM image.
1645
1646 @param SmramProfileParameterUnregisterImage The parameter of SMM profile unregister image.
1647
1648 **/
1649 VOID
1650 SmramProfileHandlerUnregisterImage (
1651 IN SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE *SmramProfileParameterUnregisterImage
1652 )
1653 {
1654 EFI_STATUS Status;
1655 EFI_SMM_DRIVER_ENTRY DriverEntry;
1656 VOID *EntryPointInImage;
1657 BOOLEAN Ret;
1658
1659 ZeroMem (&DriverEntry, sizeof (DriverEntry));
1660 CopyMem (&DriverEntry.FileName, &SmramProfileParameterUnregisterImage->FileName, sizeof (EFI_GUID));
1661 DriverEntry.ImageBuffer = SmramProfileParameterUnregisterImage->ImageBuffer;
1662 DriverEntry.NumberOfPage = (UINTN) SmramProfileParameterUnregisterImage->NumberOfPage;
1663 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) DriverEntry.ImageBuffer, &EntryPointInImage);
1664 ASSERT_EFI_ERROR (Status);
1665 DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
1666
1667 Ret = UnregisterSmramProfileImage (&DriverEntry, FALSE);
1668 if (Ret) {
1669 SmramProfileParameterUnregisterImage->Header.ReturnStatus = 0;
1670 }
1671 }
1672
1673 /**
1674 Dispatch function for a Software SMI handler.
1675
1676 Caution: This function may receive untrusted input.
1677 Communicate buffer and buffer size are external input, so this function will do basic validation.
1678
1679 @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
1680 @param Context Points to an optional handler context which was specified when the
1681 handler was registered.
1682 @param CommBuffer A pointer to a collection of data in memory that will
1683 be conveyed from a non-SMM environment into an SMM environment.
1684 @param CommBufferSize The size of the CommBuffer.
1685
1686 @retval EFI_SUCCESS Command is handled successfully.
1687
1688 **/
1689 EFI_STATUS
1690 EFIAPI
1691 SmramProfileHandler (
1692 IN EFI_HANDLE DispatchHandle,
1693 IN CONST VOID *Context OPTIONAL,
1694 IN OUT VOID *CommBuffer OPTIONAL,
1695 IN OUT UINTN *CommBufferSize OPTIONAL
1696 )
1697 {
1698 SMRAM_PROFILE_PARAMETER_HEADER *SmramProfileParameterHeader;
1699 UINTN TempCommBufferSize;
1700
1701 DEBUG ((EFI_D_ERROR, "SmramProfileHandler Enter\n"));
1702
1703 //
1704 // If input is invalid, stop processing this SMI
1705 //
1706 if (CommBuffer == NULL || CommBufferSize == NULL) {
1707 return EFI_SUCCESS;
1708 }
1709
1710 TempCommBufferSize = *CommBufferSize;
1711
1712 if (TempCommBufferSize < sizeof (SMRAM_PROFILE_PARAMETER_HEADER)) {
1713 DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
1714 return EFI_SUCCESS;
1715 }
1716
1717 if (mSmramReadyToLock && !SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
1718 DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer in SMRAM or overflow!\n"));
1719 return EFI_SUCCESS;
1720 }
1721
1722 SmramProfileParameterHeader = (SMRAM_PROFILE_PARAMETER_HEADER *) ((UINTN) CommBuffer);
1723
1724 SmramProfileParameterHeader->ReturnStatus = (UINT64)-1;
1725
1726 if (GetSmramProfileContext () == NULL) {
1727 SmramProfileParameterHeader->ReturnStatus = (UINT64) (INT64) (INTN) EFI_UNSUPPORTED;
1728 return EFI_SUCCESS;
1729 }
1730
1731 switch (SmramProfileParameterHeader->Command) {
1732 case SMRAM_PROFILE_COMMAND_GET_PROFILE_INFO:
1733 DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetInfo\n"));
1734 if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO)) {
1735 DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
1736 return EFI_SUCCESS;
1737 }
1738 SmramProfileHandlerGetInfo ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *) (UINTN) CommBuffer);
1739 break;
1740 case SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA:
1741 DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetData\n"));
1742 if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA)) {
1743 DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
1744 return EFI_SUCCESS;
1745 }
1746 SmramProfileHandlerGetData ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA *) (UINTN) CommBuffer);
1747 break;
1748 case SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA_BY_OFFSET:
1749 DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetDataByOffset\n"));
1750 if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET)) {
1751 DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
1752 return EFI_SUCCESS;
1753 }
1754 SmramProfileHandlerGetDataByOffset ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET *) (UINTN) CommBuffer);
1755 break;
1756 case SMRAM_PROFILE_COMMAND_REGISTER_IMAGE:
1757 DEBUG ((EFI_D_ERROR, "SmramProfileHandlerRegisterImage\n"));
1758 if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE)) {
1759 DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
1760 return EFI_SUCCESS;
1761 }
1762 if (mSmramReadyToLock) {
1763 return EFI_SUCCESS;
1764 }
1765 SmramProfileHandlerRegisterImage ((SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE *) (UINTN) CommBuffer);
1766 break;
1767 case SMRAM_PROFILE_COMMAND_UNREGISTER_IMAGE:
1768 DEBUG ((EFI_D_ERROR, "SmramProfileHandlerUnregisterImage\n"));
1769 if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE)) {
1770 DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
1771 return EFI_SUCCESS;
1772 }
1773 if (mSmramReadyToLock) {
1774 return EFI_SUCCESS;
1775 }
1776 SmramProfileHandlerUnregisterImage ((SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE *) (UINTN) CommBuffer);
1777 break;
1778 default:
1779 break;
1780 }
1781
1782 DEBUG ((EFI_D_ERROR, "SmramProfileHandler Exit\n"));
1783
1784 return EFI_SUCCESS;
1785 }
1786
1787 /**
1788 Register SMRAM profile handler.
1789
1790 **/
1791 VOID
1792 RegisterSmramProfileHandler (
1793 VOID
1794 )
1795 {
1796 EFI_STATUS Status;
1797 EFI_HANDLE DispatchHandle;
1798
1799 if (!IS_SMRAM_PROFILE_ENABLED) {
1800 return;
1801 }
1802
1803 Status = SmiHandlerRegister (
1804 SmramProfileHandler,
1805 &gEdkiiMemoryProfileGuid,
1806 &DispatchHandle
1807 );
1808 ASSERT_EFI_ERROR (Status);
1809 }
1810
1811 ////////////////////
1812
1813 /**
1814 Dump SMRAM range.
1815
1816 **/
1817 VOID
1818 DumpSmramRange (
1819 VOID
1820 )
1821 {
1822 UINTN Index;
1823 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
1824 BOOLEAN SmramProfileRecordingStatus;
1825
1826 ContextData = GetSmramProfileContext ();
1827 if (ContextData == NULL) {
1828 return ;
1829 }
1830
1831 SmramProfileRecordingStatus = mSmramProfileRecordingStatus;
1832 mSmramProfileRecordingStatus = FALSE;
1833
1834 DEBUG ((EFI_D_INFO, "FullSmramRange address - 0x%08x\n", mFullSmramRanges));
1835
1836 DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));
1837
1838 DEBUG ((EFI_D_INFO, "FullSmramRange:\n"));
1839 for (Index = 0; Index < mFullSmramRangeCount; Index++) {
1840 DEBUG ((EFI_D_INFO, " FullSmramRange (0x%x)\n", Index));
1841 DEBUG ((EFI_D_INFO, " PhysicalStart - 0x%016lx\n", mFullSmramRanges[Index].PhysicalStart));
1842 DEBUG ((EFI_D_INFO, " CpuStart - 0x%016lx\n", mFullSmramRanges[Index].CpuStart));
1843 DEBUG ((EFI_D_INFO, " PhysicalSize - 0x%016lx\n", mFullSmramRanges[Index].PhysicalSize));
1844 DEBUG ((EFI_D_INFO, " RegionState - 0x%016lx\n", mFullSmramRanges[Index].RegionState));
1845 }
1846
1847 DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));
1848
1849 mSmramProfileRecordingStatus = SmramProfileRecordingStatus;
1850 }
1851
1852 /**
1853 Dump SMRAM free page list.
1854
1855 **/
1856 VOID
1857 DumpFreePagesList (
1858 VOID
1859 )
1860 {
1861 LIST_ENTRY *FreePageList;
1862 LIST_ENTRY *Node;
1863 FREE_PAGE_LIST *Pages;
1864 UINTN Index;
1865 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
1866 BOOLEAN SmramProfileRecordingStatus;
1867
1868 ContextData = GetSmramProfileContext ();
1869 if (ContextData == NULL) {
1870 return ;
1871 }
1872
1873 SmramProfileRecordingStatus = mSmramProfileRecordingStatus;
1874 mSmramProfileRecordingStatus = FALSE;
1875
1876 DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));
1877
1878 DEBUG ((EFI_D_INFO, "FreePagesList:\n"));
1879 FreePageList = &mSmmMemoryMap;
1880 for (Node = FreePageList->BackLink, Index = 0;
1881 Node != FreePageList;
1882 Node = Node->BackLink, Index++) {
1883 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
1884 DEBUG ((EFI_D_INFO, " Index - 0x%x\n", Index));
1885 DEBUG ((EFI_D_INFO, " PhysicalStart - 0x%016lx\n", (PHYSICAL_ADDRESS) (UINTN) Pages));
1886 DEBUG ((EFI_D_INFO, " NumberOfPages - 0x%08x\n", Pages->NumberOfPages));
1887 }
1888
1889 DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));
1890
1891 mSmramProfileRecordingStatus = SmramProfileRecordingStatus;
1892 }
1893
1894 /**
1895 Dump SMRAM free pool list.
1896
1897 **/
1898 VOID
1899 DumpFreePoolList (
1900 VOID
1901 )
1902 {
1903 LIST_ENTRY *FreePoolList;
1904 LIST_ENTRY *Node;
1905 FREE_POOL_HEADER *Pool;
1906 UINTN Index;
1907 UINTN PoolListIndex;
1908 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
1909 BOOLEAN SmramProfileRecordingStatus;
1910
1911 ContextData = GetSmramProfileContext ();
1912 if (ContextData == NULL) {
1913 return ;
1914 }
1915
1916 SmramProfileRecordingStatus = mSmramProfileRecordingStatus;
1917 mSmramProfileRecordingStatus = FALSE;
1918
1919 DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));
1920
1921 for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
1922 DEBUG ((EFI_D_INFO, "FreePoolList (%d):\n", PoolListIndex));
1923 FreePoolList = &mSmmPoolLists[PoolListIndex];
1924 for (Node = FreePoolList->BackLink, Index = 0;
1925 Node != FreePoolList;
1926 Node = Node->BackLink, Index++) {
1927 Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
1928 DEBUG ((EFI_D_INFO, " Index - 0x%x\n", Index));
1929 DEBUG ((EFI_D_INFO, " PhysicalStart - 0x%016lx\n", (PHYSICAL_ADDRESS) (UINTN) Pool));
1930 DEBUG ((EFI_D_INFO, " Size - 0x%08x\n", Pool->Header.Size));
1931 DEBUG ((EFI_D_INFO, " Available - 0x%02x\n", Pool->Header.Available));
1932 }
1933 }
1934
1935 DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));
1936
1937 mSmramProfileRecordingStatus = SmramProfileRecordingStatus;
1938 }
1939
1940 GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mActionString[] = {
1941 L"Unknown",
1942 L"AllocatePages",
1943 L"FreePages",
1944 L"AllocatePool",
1945 L"FreePool",
1946 };
1947
1948 typedef struct {
1949 EFI_MEMORY_TYPE MemoryType;
1950 CHAR16 *MemoryTypeStr;
1951 } PROFILE_MEMORY_TYPE_STRING;
1952
1953 GLOBAL_REMOVE_IF_UNREFERENCED PROFILE_MEMORY_TYPE_STRING mMemoryTypeString[] = {
1954 {EfiRuntimeServicesCode, L"EfiRuntimeServicesCode"},
1955 {EfiRuntimeServicesData, L"EfiRuntimeServicesData"}
1956 };
1957
1958 /**
1959 Memory type to string.
1960
1961 @param[in] MemoryType Memory type.
1962
1963 @return Pointer to string.
1964
1965 **/
1966 CHAR16 *
1967 ProfileMemoryTypeToStr (
1968 IN EFI_MEMORY_TYPE MemoryType
1969 )
1970 {
1971 UINTN Index;
1972 for (Index = 0; Index < sizeof (mMemoryTypeString) / sizeof (mMemoryTypeString[0]); Index++) {
1973 if (mMemoryTypeString[Index].MemoryType == MemoryType) {
1974 return mMemoryTypeString[Index].MemoryTypeStr;
1975 }
1976 }
1977
1978 return L"UnexpectedMemoryType";
1979 }
1980
1981 /**
1982 Dump SMRAM profile.
1983
1984 **/
1985 VOID
1986 DumpSmramProfile (
1987 VOID
1988 )
1989 {
1990 MEMORY_PROFILE_CONTEXT *Context;
1991 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
1992 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
1993 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
1994 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
1995 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
1996 LIST_ENTRY *SmramDriverInfoList;
1997 UINTN DriverIndex;
1998 LIST_ENTRY *DriverLink;
1999 LIST_ENTRY *AllocInfoList;
2000 UINTN AllocIndex;
2001 LIST_ENTRY *AllocLink;
2002 BOOLEAN SmramProfileRecordingStatus;
2003 UINTN TypeIndex;
2004
2005 ContextData = GetSmramProfileContext ();
2006 if (ContextData == NULL) {
2007 return ;
2008 }
2009
2010 SmramProfileRecordingStatus = mSmramProfileRecordingStatus;
2011 mSmramProfileRecordingStatus = FALSE;
2012
2013 Context = &ContextData->Context;
2014 DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));
2015 DEBUG ((EFI_D_INFO, "MEMORY_PROFILE_CONTEXT\n"));
2016
2017 DEBUG ((EFI_D_INFO, " CurrentTotalUsage - 0x%016lx\n", Context->CurrentTotalUsage));
2018 DEBUG ((EFI_D_INFO, " PeakTotalUsage - 0x%016lx\n", Context->PeakTotalUsage));
2019 for (TypeIndex = 0; TypeIndex < sizeof (Context->CurrentTotalUsageByType) / sizeof (Context->CurrentTotalUsageByType[0]); TypeIndex++) {
2020 if ((Context->CurrentTotalUsageByType[TypeIndex] != 0) ||
2021 (Context->PeakTotalUsageByType[TypeIndex] != 0)) {
2022 DEBUG ((EFI_D_INFO, " CurrentTotalUsage[0x%02x] - 0x%016lx (%s)\n", TypeIndex, Context->CurrentTotalUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
2023 DEBUG ((EFI_D_INFO, " PeakTotalUsage[0x%02x] - 0x%016lx (%s)\n", TypeIndex, Context->PeakTotalUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
2024 }
2025 }
2026 DEBUG ((EFI_D_INFO, " TotalImageSize - 0x%016lx\n", Context->TotalImageSize));
2027 DEBUG ((EFI_D_INFO, " ImageCount - 0x%08x\n", Context->ImageCount));
2028 DEBUG ((EFI_D_INFO, " SequenceCount - 0x%08x\n", Context->SequenceCount));
2029
2030 SmramDriverInfoList = ContextData->DriverInfoList;
2031 for (DriverLink = SmramDriverInfoList->ForwardLink, DriverIndex = 0;
2032 DriverLink != SmramDriverInfoList;
2033 DriverLink = DriverLink->ForwardLink, DriverIndex++) {
2034 DriverInfoData = CR (
2035 DriverLink,
2036 MEMORY_PROFILE_DRIVER_INFO_DATA,
2037 Link,
2038 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
2039 );
2040 DriverInfo = &DriverInfoData->DriverInfo;
2041 DEBUG ((EFI_D_INFO, " MEMORY_PROFILE_DRIVER_INFO (0x%x)\n", DriverIndex));
2042 DEBUG ((EFI_D_INFO, " FileName - %g\n", &DriverInfo->FileName));
2043 DEBUG ((EFI_D_INFO, " ImageBase - 0x%016lx\n", DriverInfo->ImageBase));
2044 DEBUG ((EFI_D_INFO, " ImageSize - 0x%016lx\n", DriverInfo->ImageSize));
2045 DEBUG ((EFI_D_INFO, " EntryPoint - 0x%016lx\n", DriverInfo->EntryPoint));
2046 DEBUG ((EFI_D_INFO, " ImageSubsystem - 0x%04x\n", DriverInfo->ImageSubsystem));
2047 DEBUG ((EFI_D_INFO, " FileType - 0x%02x\n", DriverInfo->FileType));
2048 DEBUG ((EFI_D_INFO, " CurrentUsage - 0x%016lx\n", DriverInfo->CurrentUsage));
2049 DEBUG ((EFI_D_INFO, " PeakUsage - 0x%016lx\n", DriverInfo->PeakUsage));
2050 for (TypeIndex = 0; TypeIndex < sizeof (DriverInfo->CurrentUsageByType) / sizeof (DriverInfo->CurrentUsageByType[0]); TypeIndex++) {
2051 if ((DriverInfo->CurrentUsageByType[TypeIndex] != 0) ||
2052 (DriverInfo->PeakUsageByType[TypeIndex] != 0)) {
2053 DEBUG ((EFI_D_INFO, " CurrentUsage[0x%02x] - 0x%016lx (%s)\n", TypeIndex, DriverInfo->CurrentUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
2054 DEBUG ((EFI_D_INFO, " PeakUsage[0x%02x] - 0x%016lx (%s)\n", TypeIndex, DriverInfo->PeakUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
2055 }
2056 }
2057 DEBUG ((EFI_D_INFO, " AllocRecordCount - 0x%08x\n", DriverInfo->AllocRecordCount));
2058
2059 AllocInfoList = DriverInfoData->AllocInfoList;
2060 for (AllocLink = AllocInfoList->ForwardLink, AllocIndex = 0;
2061 AllocLink != AllocInfoList;
2062 AllocLink = AllocLink->ForwardLink, AllocIndex++) {
2063 AllocInfoData = CR (
2064 AllocLink,
2065 MEMORY_PROFILE_ALLOC_INFO_DATA,
2066 Link,
2067 MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
2068 );
2069 AllocInfo = &AllocInfoData->AllocInfo;
2070 DEBUG ((EFI_D_INFO, " MEMORY_PROFILE_ALLOC_INFO (0x%x)\n", AllocIndex));
2071 DEBUG ((EFI_D_INFO, " CallerAddress - 0x%016lx (Offset: 0x%08x)\n", AllocInfo->CallerAddress, AllocInfo->CallerAddress - DriverInfo->ImageBase));
2072 DEBUG ((EFI_D_INFO, " SequenceId - 0x%08x\n", AllocInfo->SequenceId));
2073 DEBUG ((EFI_D_INFO, " Action - 0x%08x (%s)\n", AllocInfo->Action, mActionString[(AllocInfo->Action < sizeof(mActionString)/sizeof(mActionString[0])) ? AllocInfo->Action : 0]));
2074 DEBUG ((EFI_D_INFO, " MemoryType - 0x%08x\n", AllocInfo->MemoryType));
2075 DEBUG ((EFI_D_INFO, " Buffer - 0x%016lx\n", AllocInfo->Buffer));
2076 DEBUG ((EFI_D_INFO, " Size - 0x%016lx\n", AllocInfo->Size));
2077 }
2078 }
2079
2080 DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));
2081
2082 mSmramProfileRecordingStatus = SmramProfileRecordingStatus;
2083 }
2084
2085 /**
2086 Dump SMRAM infromation.
2087
2088 **/
2089 VOID
2090 DumpSmramInfo (
2091 VOID
2092 )
2093 {
2094 DEBUG_CODE (
2095 if (IS_SMRAM_PROFILE_ENABLED) {
2096 DumpSmramProfile ();
2097 DumpFreePagesList ();
2098 DumpFreePoolList ();
2099 DumpSmramRange ();
2100 }
2101 );
2102 }
2103