• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define IS_UEFI_MEMORY_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT0) != 0)
19 
20 #define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
21   ((ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)))
22 
23 typedef struct {
24   UINT32                        Signature;
25   MEMORY_PROFILE_CONTEXT        Context;
26   LIST_ENTRY                    *DriverInfoList;
27 } MEMORY_PROFILE_CONTEXT_DATA;
28 
29 typedef struct {
30   UINT32                        Signature;
31   MEMORY_PROFILE_DRIVER_INFO    DriverInfo;
32   LIST_ENTRY                    *AllocInfoList;
33   CHAR8                         *PdbString;
34   LIST_ENTRY                    Link;
35 } MEMORY_PROFILE_DRIVER_INFO_DATA;
36 
37 typedef struct {
38   UINT32                        Signature;
39   MEMORY_PROFILE_ALLOC_INFO     AllocInfo;
40   CHAR8                         *ActionString;
41   LIST_ENTRY                    Link;
42 } MEMORY_PROFILE_ALLOC_INFO_DATA;
43 
44 //
45 // When free memory less than 4 pages, dump it.
46 //
47 #define SMRAM_INFO_DUMP_PAGE_THRESHOLD  4
48 
49 GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_FREE_MEMORY mSmramFreeMemory = {
50   {
51     MEMORY_PROFILE_FREE_MEMORY_SIGNATURE,
52     sizeof (MEMORY_PROFILE_FREE_MEMORY),
53     MEMORY_PROFILE_FREE_MEMORY_REVISION
54   },
55   0,
56   0
57 };
58 
59 GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY  mImageQueue = INITIALIZE_LIST_HEAD_VARIABLE (mImageQueue);
60 GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA mSmramProfileContext = {
61   MEMORY_PROFILE_CONTEXT_SIGNATURE,
62   {
63     {
64       MEMORY_PROFILE_CONTEXT_SIGNATURE,
65       sizeof (MEMORY_PROFILE_CONTEXT),
66       MEMORY_PROFILE_CONTEXT_REVISION
67     },
68     0,
69     0,
70     {0},
71     {0},
72     0,
73     0,
74     0
75   },
76   &mImageQueue,
77 };
78 GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA *mSmramProfileContextPtr = NULL;
79 
80 BOOLEAN mSmramReadyToLock;
81 BOOLEAN mSmramProfileGettingStatus = FALSE;
82 BOOLEAN mSmramProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
83 EFI_DEVICE_PATH_PROTOCOL *mSmramProfileDriverPath;
84 UINTN                    mSmramProfileDriverPathSize;
85 
86 /**
87   Dump SMRAM infromation.
88 
89 **/
90 VOID
91 DumpSmramInfo (
92   VOID
93   );
94 
95 /**
96   Get memory profile data.
97 
98   @param[in]      This              The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
99   @param[in, out] ProfileSize       On entry, points to the size in bytes of the ProfileBuffer.
100                                     On return, points to the size of the data returned in ProfileBuffer.
101   @param[out]     ProfileBuffer     Profile buffer.
102 
103   @return EFI_SUCCESS               Get the memory profile data successfully.
104   @return EFI_UNSUPPORTED           Memory profile is unsupported.
105   @return EFI_BUFFER_TO_SMALL       The ProfileSize is too small for the resulting data.
106                                     ProfileSize is updated with the size required.
107 
108 **/
109 EFI_STATUS
110 EFIAPI
111 SmramProfileProtocolGetData (
112   IN     EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
113   IN OUT UINT64                             *ProfileSize,
114      OUT VOID                               *ProfileBuffer
115   );
116 
117 /**
118   Register image to memory profile.
119 
120   @param[in] This               The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
121   @param[in] FilePath           File path of the image.
122   @param[in] ImageBase          Image base address.
123   @param[in] ImageSize          Image size.
124   @param[in] FileType           File type of the image.
125 
126   @return EFI_SUCCESS           Register successfully.
127   @return EFI_UNSUPPORTED       Memory profile is unsupported,
128                                 or memory profile for the image is not required.
129   @return EFI_OUT_OF_RESOURCE   No enough resource for this register.
130 
131 **/
132 EFI_STATUS
133 EFIAPI
134 SmramProfileProtocolRegisterImage (
135   IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
136   IN EFI_DEVICE_PATH_PROTOCOL           *FilePath,
137   IN PHYSICAL_ADDRESS                   ImageBase,
138   IN UINT64                             ImageSize,
139   IN EFI_FV_FILETYPE                    FileType
140   );
141 
142 /**
143   Unregister image from memory profile.
144 
145   @param[in] This               The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
146   @param[in] FilePath           File path of the image.
147   @param[in] ImageBase          Image base address.
148   @param[in] ImageSize          Image size.
149 
150   @return EFI_SUCCESS           Unregister successfully.
151   @return EFI_UNSUPPORTED       Memory profile is unsupported,
152                                 or memory profile for the image is not required.
153   @return EFI_NOT_FOUND         The image is not found.
154 
155 **/
156 EFI_STATUS
157 EFIAPI
158 SmramProfileProtocolUnregisterImage (
159   IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
160   IN EFI_DEVICE_PATH_PROTOCOL           *FilePath,
161   IN PHYSICAL_ADDRESS                   ImageBase,
162   IN UINT64                             ImageSize
163   );
164 
165 /**
166   Get memory profile recording state.
167 
168   @param[in]  This              The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
169   @param[out] RecordingState    Recording state.
170 
171   @return EFI_SUCCESS           Memory profile recording state is returned.
172   @return EFI_UNSUPPORTED       Memory profile is unsupported.
173   @return EFI_INVALID_PARAMETER RecordingState is NULL.
174 
175 **/
176 EFI_STATUS
177 EFIAPI
178 SmramProfileProtocolGetRecordingState (
179   IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
180   OUT BOOLEAN                           *RecordingState
181   );
182 
183 /**
184   Set memory profile recording state.
185 
186   @param[in] This               The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
187   @param[in] RecordingState     Recording state.
188 
189   @return EFI_SUCCESS           Set memory profile recording state successfully.
190   @return EFI_UNSUPPORTED       Memory profile is unsupported.
191 
192 **/
193 EFI_STATUS
194 EFIAPI
195 SmramProfileProtocolSetRecordingState (
196   IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
197   IN BOOLEAN                            RecordingState
198   );
199 
200 /**
201   Record memory profile of multilevel caller.
202 
203   @param[in] This               The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
204   @param[in] CallerAddress      Address of caller.
205   @param[in] Action             Memory profile action.
206   @param[in] MemoryType         Memory type.
207                                 EfiMaxMemoryType means the MemoryType is unknown.
208   @param[in] Buffer             Buffer address.
209   @param[in] Size               Buffer size.
210   @param[in] ActionString       String for memory profile action.
211                                 Only needed for user defined allocate action.
212 
213   @return EFI_SUCCESS           Memory profile is updated.
214   @return EFI_UNSUPPORTED       Memory profile is unsupported,
215                                 or memory profile for the image is not required,
216                                 or memory profile for the memory type is not required.
217   @return EFI_ACCESS_DENIED     It is during memory profile data getting.
218   @return EFI_ABORTED           Memory profile recording is not enabled.
219   @return EFI_OUT_OF_RESOURCES  No enough resource to update memory profile for allocate action.
220   @return EFI_NOT_FOUND         No matched allocate info found for free action.
221 
222 **/
223 EFI_STATUS
224 EFIAPI
225 SmramProfileProtocolRecord (
226   IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
227   IN PHYSICAL_ADDRESS                   CallerAddress,
228   IN MEMORY_PROFILE_ACTION              Action,
229   IN EFI_MEMORY_TYPE                    MemoryType,
230   IN VOID                               *Buffer,
231   IN UINTN                              Size,
232   IN CHAR8                              *ActionString OPTIONAL
233   );
234 
235 EDKII_SMM_MEMORY_PROFILE_PROTOCOL mSmmProfileProtocol = {
236   SmramProfileProtocolGetData,
237   SmramProfileProtocolRegisterImage,
238   SmramProfileProtocolUnregisterImage,
239   SmramProfileProtocolGetRecordingState,
240   SmramProfileProtocolSetRecordingState,
241   SmramProfileProtocolRecord,
242 };
243 
244 /**
245   Return SMRAM profile context.
246 
247   @return SMRAM profile context.
248 
249 **/
250 MEMORY_PROFILE_CONTEXT_DATA *
GetSmramProfileContext(VOID)251 GetSmramProfileContext (
252   VOID
253   )
254 {
255   return mSmramProfileContextPtr;
256 }
257 
258 /**
259   Retrieves the magic value from the PE/COFF header.
260 
261   @param Hdr    The buffer in which to return the PE32, PE32+, or TE header.
262 
263   @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32
264   @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+
265 
266 **/
267 UINT16
InternalPeCoffGetPeHeaderMagicValue(IN EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr)268 InternalPeCoffGetPeHeaderMagicValue (
269   IN  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr
270   )
271 {
272   //
273   // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
274   //       in the PE/COFF Header.  If the MachineType is Itanium(IA64) and the
275   //       Magic value in the OptionalHeader is  EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
276   //       then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
277   //
278   if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
279     return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
280   }
281   //
282   // Return the magic value from the PC/COFF Optional Header
283   //
284   return Hdr.Pe32->OptionalHeader.Magic;
285 }
286 
287 /**
288   Retrieves and returns the Subsystem of a PE/COFF image that has been loaded into system memory.
289   If Pe32Data is NULL, then ASSERT().
290 
291   @param Pe32Data   The pointer to the PE/COFF image that is loaded in system memory.
292 
293   @return The Subsystem of the PE/COFF image.
294 
295 **/
296 UINT16
InternalPeCoffGetSubsystem(IN VOID * Pe32Data)297 InternalPeCoffGetSubsystem (
298   IN VOID  *Pe32Data
299   )
300 {
301   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;
302   EFI_IMAGE_DOS_HEADER                 *DosHdr;
303   UINT16                               Magic;
304 
305   ASSERT (Pe32Data != NULL);
306 
307   DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;
308   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
309     //
310     // DOS image header is present, so read the PE header after the DOS image header.
311     //
312     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
313   } else {
314     //
315     // DOS image header is not present, so PE header is at the image base.
316     //
317     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;
318   }
319 
320   if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
321     return Hdr.Te->Subsystem;
322   } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE)  {
323     Magic = InternalPeCoffGetPeHeaderMagicValue (Hdr);
324     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
325       return Hdr.Pe32->OptionalHeader.Subsystem;
326     } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
327       return Hdr.Pe32Plus->OptionalHeader.Subsystem;
328     }
329   }
330 
331   return 0x0000;
332 }
333 
334 /**
335   Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded
336   into system memory with the PE/COFF Loader Library functions.
337 
338   Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry
339   point in EntryPoint.  If the entry point could not be retrieved from the PE/COFF image, then
340   return RETURN_INVALID_PARAMETER.  Otherwise return RETURN_SUCCESS.
341   If Pe32Data is NULL, then ASSERT().
342   If EntryPoint is NULL, then ASSERT().
343 
344   @param  Pe32Data                  The pointer to the PE/COFF image that is loaded in system memory.
345   @param  EntryPoint                The pointer to entry point to the PE/COFF image to return.
346 
347   @retval RETURN_SUCCESS            EntryPoint was returned.
348   @retval RETURN_INVALID_PARAMETER  The entry point could not be found in the PE/COFF image.
349 
350 **/
351 RETURN_STATUS
InternalPeCoffGetEntryPoint(IN VOID * Pe32Data,OUT VOID ** EntryPoint)352 InternalPeCoffGetEntryPoint (
353   IN  VOID  *Pe32Data,
354   OUT VOID  **EntryPoint
355   )
356 {
357   EFI_IMAGE_DOS_HEADER                  *DosHdr;
358   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
359 
360   ASSERT (Pe32Data   != NULL);
361   ASSERT (EntryPoint != NULL);
362 
363   DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;
364   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
365     //
366     // DOS image header is present, so read the PE header after the DOS image header.
367     //
368     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
369   } else {
370     //
371     // DOS image header is not present, so PE header is at the image base.
372     //
373     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;
374   }
375 
376   //
377   // Calculate the entry point relative to the start of the image.
378   // AddressOfEntryPoint is common for PE32 & PE32+
379   //
380   if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
381     *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);
382     return RETURN_SUCCESS;
383   } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
384     *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff));
385     return RETURN_SUCCESS;
386   }
387 
388   return RETURN_UNSUPPORTED;
389 }
390 
391 /**
392   Build driver info.
393 
394   @param ContextData    Memory profile context.
395   @param FileName       File name of the image.
396   @param ImageBase      Image base address.
397   @param ImageSize      Image size.
398   @param EntryPoint     Entry point of the image.
399   @param ImageSubsystem Image subsystem of the image.
400   @param FileType       File type of the image.
401 
402   @return Pointer to memory profile driver info.
403 
404 **/
405 MEMORY_PROFILE_DRIVER_INFO_DATA *
BuildDriverInfo(IN MEMORY_PROFILE_CONTEXT_DATA * ContextData,IN EFI_GUID * FileName,IN PHYSICAL_ADDRESS ImageBase,IN UINT64 ImageSize,IN PHYSICAL_ADDRESS EntryPoint,IN UINT16 ImageSubsystem,IN EFI_FV_FILETYPE FileType)406 BuildDriverInfo (
407   IN MEMORY_PROFILE_CONTEXT_DATA    *ContextData,
408   IN EFI_GUID                       *FileName,
409   IN PHYSICAL_ADDRESS               ImageBase,
410   IN UINT64                         ImageSize,
411   IN PHYSICAL_ADDRESS               EntryPoint,
412   IN UINT16                         ImageSubsystem,
413   IN EFI_FV_FILETYPE                FileType
414   )
415 {
416   EFI_STATUS                        Status;
417   MEMORY_PROFILE_DRIVER_INFO        *DriverInfo;
418   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
419   VOID                              *EntryPointInImage;
420   CHAR8                             *PdbString;
421   UINTN                             PdbSize;
422   UINTN                             PdbOccupiedSize;
423 
424   PdbSize = 0;
425   PdbOccupiedSize = 0;
426   PdbString = NULL;
427   if (ImageBase != 0) {
428     PdbString = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageBase);
429     if (PdbString != NULL) {
430       PdbSize = AsciiStrSize (PdbString);
431       PdbOccupiedSize = GET_OCCUPIED_SIZE (PdbSize, sizeof (UINT64));
432     }
433   }
434 
435   //
436   // Use SmmInternalAllocatePool() that will not update profile for this AllocatePool action.
437   //
438   Status = SmmInternalAllocatePool (
439              EfiRuntimeServicesData,
440              sizeof (*DriverInfoData) + sizeof (LIST_ENTRY) + PdbSize,
441              (VOID **) &DriverInfoData
442              );
443   if (EFI_ERROR (Status)) {
444     return NULL;
445   }
446   ASSERT (DriverInfoData != NULL);
447 
448   ZeroMem (DriverInfoData, sizeof (*DriverInfoData));
449 
450   DriverInfo = &DriverInfoData->DriverInfo;
451   DriverInfoData->Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
452   DriverInfo->Header.Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
453   DriverInfo->Header.Length = (UINT16) (sizeof (MEMORY_PROFILE_DRIVER_INFO) + PdbOccupiedSize);
454   DriverInfo->Header.Revision = MEMORY_PROFILE_DRIVER_INFO_REVISION;
455   if (FileName != NULL) {
456     CopyMem (&DriverInfo->FileName, FileName, sizeof (EFI_GUID));
457   }
458   DriverInfo->ImageBase = ImageBase;
459   DriverInfo->ImageSize = ImageSize;
460   DriverInfo->EntryPoint = EntryPoint;
461   DriverInfo->ImageSubsystem = ImageSubsystem;
462   if ((EntryPoint != 0) && ((EntryPoint < ImageBase) || (EntryPoint >= (ImageBase + ImageSize)))) {
463     //
464     // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
465     // So patch ImageBuffer here to align the EntryPoint.
466     //
467     Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);
468     ASSERT_EFI_ERROR (Status);
469     DriverInfo->ImageBase = ImageBase + EntryPoint - (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
470   }
471   DriverInfo->FileType = FileType;
472   DriverInfoData->AllocInfoList = (LIST_ENTRY *) (DriverInfoData + 1);
473   InitializeListHead (DriverInfoData->AllocInfoList);
474   DriverInfo->CurrentUsage = 0;
475   DriverInfo->PeakUsage = 0;
476   DriverInfo->AllocRecordCount = 0;
477   if (PdbSize != 0) {
478     DriverInfo->PdbStringOffset = (UINT16) sizeof (MEMORY_PROFILE_DRIVER_INFO);
479     DriverInfoData->PdbString = (CHAR8 *) (DriverInfoData->AllocInfoList + 1);
480     CopyMem (DriverInfoData->PdbString, PdbString, PdbSize);
481   } else {
482     DriverInfo->PdbStringOffset = 0;
483     DriverInfoData->PdbString = NULL;
484   }
485 
486   InsertTailList (ContextData->DriverInfoList, &DriverInfoData->Link);
487   ContextData->Context.ImageCount ++;
488   ContextData->Context.TotalImageSize += DriverInfo->ImageSize;
489 
490   return DriverInfoData;
491 }
492 
493 /**
494   Register image to DXE.
495 
496   @param FileName       File name of the image.
497   @param ImageBase      Image base address.
498   @param ImageSize      Image size.
499   @param FileType       File type of the image.
500 
501 **/
502 VOID
RegisterImageToDxe(IN EFI_GUID * FileName,IN PHYSICAL_ADDRESS ImageBase,IN UINT64 ImageSize,IN EFI_FV_FILETYPE FileType)503 RegisterImageToDxe (
504   IN EFI_GUID                       *FileName,
505   IN PHYSICAL_ADDRESS               ImageBase,
506   IN UINT64                         ImageSize,
507   IN EFI_FV_FILETYPE                FileType
508   )
509 {
510   EFI_STATUS                        Status;
511   EDKII_MEMORY_PROFILE_PROTOCOL     *ProfileProtocol;
512   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
513   UINT8                             TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];
514 
515   if (IS_UEFI_MEMORY_PROFILE_ENABLED) {
516 
517     FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;
518     Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID **) &ProfileProtocol);
519     if (!EFI_ERROR (Status)) {
520       EfiInitializeFwVolDevicepathNode (FilePath, FileName);
521       SetDevicePathEndNode (FilePath + 1);
522 
523       Status = ProfileProtocol->RegisterImage (
524                                   ProfileProtocol,
525                                   (EFI_DEVICE_PATH_PROTOCOL *) FilePath,
526                                   ImageBase,
527                                   ImageSize,
528                                   FileType
529                                   );
530     }
531   }
532 }
533 
534 /**
535   Unregister image from DXE.
536 
537   @param FileName       File name of the image.
538   @param ImageBase      Image base address.
539   @param ImageSize      Image size.
540 
541 **/
542 VOID
UnregisterImageFromDxe(IN EFI_GUID * FileName,IN PHYSICAL_ADDRESS ImageBase,IN UINT64 ImageSize)543 UnregisterImageFromDxe (
544   IN EFI_GUID                       *FileName,
545   IN PHYSICAL_ADDRESS               ImageBase,
546   IN UINT64                         ImageSize
547   )
548 {
549   EFI_STATUS                        Status;
550   EDKII_MEMORY_PROFILE_PROTOCOL     *ProfileProtocol;
551   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
552   UINT8                             TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];
553 
554   if (IS_UEFI_MEMORY_PROFILE_ENABLED) {
555 
556     FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;
557     Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID *) &ProfileProtocol);
558     if (!EFI_ERROR (Status)) {
559       EfiInitializeFwVolDevicepathNode (FilePath, FileName);
560       SetDevicePathEndNode (FilePath + 1);
561 
562       Status = ProfileProtocol->UnregisterImage (
563                                   ProfileProtocol,
564                                   (EFI_DEVICE_PATH_PROTOCOL *) FilePath,
565                                   ImageBase,
566                                   ImageSize
567                                   );
568     }
569   }
570 }
571 
572 /**
573   Return if record for this driver is needed..
574 
575   @param DriverFilePath     Driver file path.
576 
577   @retval TRUE              Record for this driver is needed.
578   @retval FALSE             Record for this driver is not needed.
579 
580 **/
581 BOOLEAN
NeedRecordThisDriver(IN EFI_DEVICE_PATH_PROTOCOL * DriverFilePath)582 NeedRecordThisDriver (
583   IN EFI_DEVICE_PATH_PROTOCOL       *DriverFilePath
584   )
585 {
586   EFI_DEVICE_PATH_PROTOCOL    *TmpDevicePath;
587   EFI_DEVICE_PATH_PROTOCOL    *DevicePathInstance;
588   UINTN                       DevicePathSize;
589   UINTN                       FilePathSize;
590 
591   if (!IsDevicePathValid (mSmramProfileDriverPath, mSmramProfileDriverPathSize)) {
592     //
593     // Invalid Device Path means record all.
594     //
595     return TRUE;
596   }
597 
598   //
599   // Record FilePath without end node.
600   //
601   FilePathSize = GetDevicePathSize (DriverFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
602 
603   DevicePathInstance = mSmramProfileDriverPath;
604   do {
605     //
606     // Find End node (it might be END_ENTIRE or END_INSTANCE)
607     //
608     TmpDevicePath = DevicePathInstance;
609     while (!IsDevicePathEndType (TmpDevicePath)) {
610       TmpDevicePath = NextDevicePathNode (TmpDevicePath);
611     }
612 
613     //
614     // Do not compare END node
615     //
616     DevicePathSize = (UINTN)TmpDevicePath - (UINTN)DevicePathInstance;
617     if ((FilePathSize == DevicePathSize) &&
618         (CompareMem (DriverFilePath, DevicePathInstance, DevicePathSize) == 0)) {
619       return TRUE;
620     }
621 
622     //
623     // Get next instance
624     //
625     DevicePathInstance = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN)DevicePathInstance + DevicePathSize + DevicePathNodeLength(TmpDevicePath));
626   } while (DevicePathSubType (TmpDevicePath) != END_ENTIRE_DEVICE_PATH_SUBTYPE);
627 
628   return FALSE;
629 }
630 
631 /**
632   Register SMM Core to SMRAM profile.
633 
634   @param ContextData    SMRAM profile context.
635 
636   @retval TRUE          Register success.
637   @retval FALSE         Register fail.
638 
639 **/
640 BOOLEAN
RegisterSmmCore(IN MEMORY_PROFILE_CONTEXT_DATA * ContextData)641 RegisterSmmCore (
642   IN MEMORY_PROFILE_CONTEXT_DATA    *ContextData
643   )
644 {
645   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
646   PHYSICAL_ADDRESS                  ImageBase;
647   UINT8                             TempBuffer[sizeof(MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH_PROTOCOL)];
648   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
649 
650   FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempBuffer;
651   EfiInitializeFwVolDevicepathNode (FilePath, &gEfiCallerIdGuid);
652   SetDevicePathEndNode (FilePath + 1);
653 
654   if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *) FilePath)) {
655     return FALSE;
656   }
657 
658   ImageBase = gSmmCorePrivate->PiSmmCoreImageBase;
659   DriverInfoData = BuildDriverInfo (
660                      ContextData,
661                      &gEfiCallerIdGuid,
662                      ImageBase,
663                      gSmmCorePrivate->PiSmmCoreImageSize,
664                      gSmmCorePrivate->PiSmmCoreEntryPoint,
665                      InternalPeCoffGetSubsystem ((VOID *) (UINTN) ImageBase),
666                      EFI_FV_FILETYPE_SMM_CORE
667                      );
668   if (DriverInfoData == NULL) {
669     return FALSE;
670   }
671 
672   return TRUE;
673 }
674 
675 /**
676   Initialize SMRAM profile.
677 
678 **/
679 VOID
SmramProfileInit(VOID)680 SmramProfileInit (
681   VOID
682   )
683 {
684   MEMORY_PROFILE_CONTEXT_DATA *SmramProfileContext;
685 
686   RegisterImageToDxe (
687     &gEfiCallerIdGuid,
688     gSmmCorePrivate->PiSmmCoreImageBase,
689     gSmmCorePrivate->PiSmmCoreImageSize,
690     EFI_FV_FILETYPE_SMM_CORE
691     );
692 
693   if (!IS_SMRAM_PROFILE_ENABLED) {
694     return;
695   }
696 
697   SmramProfileContext = GetSmramProfileContext ();
698   if (SmramProfileContext != NULL) {
699     return;
700   }
701 
702   mSmramProfileGettingStatus = FALSE;
703   if ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT7) != 0) {
704     mSmramProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
705   } else {
706     mSmramProfileRecordingEnable = MEMORY_PROFILE_RECORDING_ENABLE;
707   }
708   mSmramProfileDriverPathSize = PcdGetSize (PcdMemoryProfileDriverPath);
709   mSmramProfileDriverPath = AllocateCopyPool (mSmramProfileDriverPathSize, PcdGetPtr (PcdMemoryProfileDriverPath));
710   mSmramProfileContextPtr = &mSmramProfileContext;
711 
712   RegisterSmmCore (&mSmramProfileContext);
713 
714   DEBUG ((EFI_D_INFO, "SmramProfileInit SmramProfileContext - 0x%x\n", &mSmramProfileContext));
715 }
716 
717 /**
718   Install SMRAM profile protocol.
719 
720 **/
721 VOID
SmramProfileInstallProtocol(VOID)722 SmramProfileInstallProtocol (
723   VOID
724   )
725 {
726   EFI_HANDLE    Handle;
727   EFI_STATUS    Status;
728 
729   if (!IS_SMRAM_PROFILE_ENABLED) {
730     return;
731   }
732 
733   Handle = NULL;
734   Status = SmmInstallProtocolInterface (
735              &Handle,
736              &gEdkiiSmmMemoryProfileGuid,
737              EFI_NATIVE_INTERFACE,
738              &mSmmProfileProtocol
739              );
740   ASSERT_EFI_ERROR (Status);
741 }
742 
743 /**
744   Get the GUID file name from the file path.
745 
746   @param FilePath  File path.
747 
748   @return The GUID file name from the file path.
749 
750 **/
751 EFI_GUID *
GetFileNameFromFilePath(IN EFI_DEVICE_PATH_PROTOCOL * FilePath)752 GetFileNameFromFilePath (
753   IN EFI_DEVICE_PATH_PROTOCOL   *FilePath
754   )
755 {
756   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH     *ThisFilePath;
757   EFI_GUID                              *FileName;
758 
759   FileName = NULL;
760   if (FilePath != NULL) {
761     ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) FilePath;
762     while (!IsDevicePathEnd (ThisFilePath)) {
763       FileName = EfiGetNameGuidFromFwVolDevicePathNode (ThisFilePath);
764       if (FileName != NULL) {
765         break;
766       }
767       ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) NextDevicePathNode (ThisFilePath);
768     }
769   }
770 
771   return FileName;
772 }
773 
774 /**
775   Register SMM image to SMRAM profile.
776 
777   @param DriverEntry    SMM image info.
778   @param RegisterToDxe  Register image to DXE.
779 
780   @return EFI_SUCCESS           Register successfully.
781   @return EFI_UNSUPPORTED       Memory profile is unsupported,
782                                 or memory profile for the image is not required.
783   @return EFI_OUT_OF_RESOURCES  No enough resource for this register.
784 
785 **/
786 EFI_STATUS
RegisterSmramProfileImage(IN EFI_SMM_DRIVER_ENTRY * DriverEntry,IN BOOLEAN RegisterToDxe)787 RegisterSmramProfileImage (
788   IN EFI_SMM_DRIVER_ENTRY   *DriverEntry,
789   IN BOOLEAN                RegisterToDxe
790   )
791 {
792   MEMORY_PROFILE_CONTEXT_DATA       *ContextData;
793   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
794   UINT8                             TempBuffer[sizeof(MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH_PROTOCOL)];
795   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
796 
797   if (RegisterToDxe) {
798     RegisterImageToDxe (
799       &DriverEntry->FileName,
800       DriverEntry->ImageBuffer,
801       EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage),
802       EFI_FV_FILETYPE_SMM
803       );
804   }
805 
806   if (!IS_SMRAM_PROFILE_ENABLED) {
807     return EFI_UNSUPPORTED;
808   }
809 
810   FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempBuffer;
811   EfiInitializeFwVolDevicepathNode (FilePath, &DriverEntry->FileName);
812   SetDevicePathEndNode (FilePath + 1);
813 
814   if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *) FilePath)) {
815     return EFI_UNSUPPORTED;
816   }
817 
818   ContextData = GetSmramProfileContext ();
819   if (ContextData == NULL) {
820     return EFI_UNSUPPORTED;
821   }
822 
823   DriverInfoData = BuildDriverInfo (
824                      ContextData,
825                      &DriverEntry->FileName,
826                      DriverEntry->ImageBuffer,
827                      EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage),
828                      DriverEntry->ImageEntryPoint,
829                      InternalPeCoffGetSubsystem ((VOID *) (UINTN) DriverEntry->ImageBuffer),
830                      EFI_FV_FILETYPE_SMM
831                      );
832   if (DriverInfoData == NULL) {
833     return EFI_OUT_OF_RESOURCES;
834   }
835 
836   return EFI_SUCCESS;
837 }
838 
839 /**
840   Search image from memory profile.
841 
842   @param ContextData    Memory profile context.
843   @param FileName       Image file name.
844   @param Address        Image Address.
845 
846   @return Pointer to memory profile driver info.
847 
848 **/
849 MEMORY_PROFILE_DRIVER_INFO_DATA *
GetMemoryProfileDriverInfoByFileNameAndAddress(IN MEMORY_PROFILE_CONTEXT_DATA * ContextData,IN EFI_GUID * FileName,IN PHYSICAL_ADDRESS Address)850 GetMemoryProfileDriverInfoByFileNameAndAddress (
851   IN MEMORY_PROFILE_CONTEXT_DATA    *ContextData,
852   IN EFI_GUID                       *FileName,
853   IN PHYSICAL_ADDRESS               Address
854   )
855 {
856   MEMORY_PROFILE_DRIVER_INFO        *DriverInfo;
857   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
858   LIST_ENTRY                        *DriverLink;
859   LIST_ENTRY                        *DriverInfoList;
860 
861   DriverInfoList = ContextData->DriverInfoList;
862 
863   for (DriverLink = DriverInfoList->ForwardLink;
864        DriverLink != DriverInfoList;
865        DriverLink = DriverLink->ForwardLink) {
866     DriverInfoData = CR (
867                        DriverLink,
868                        MEMORY_PROFILE_DRIVER_INFO_DATA,
869                        Link,
870                        MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
871                        );
872     DriverInfo = &DriverInfoData->DriverInfo;
873     if ((CompareGuid (&DriverInfo->FileName, FileName)) &&
874         (Address >= DriverInfo->ImageBase) &&
875         (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {
876       return DriverInfoData;
877     }
878   }
879 
880   return NULL;
881 }
882 
883 /**
884   Search image from memory profile.
885   It will return image, if (Address >= ImageBuffer) AND (Address < ImageBuffer + ImageSize)
886 
887   @param ContextData    Memory profile context.
888   @param Address        Image or Function address.
889 
890   @return Pointer to memory profile driver info.
891 
892 **/
893 MEMORY_PROFILE_DRIVER_INFO_DATA *
GetMemoryProfileDriverInfoFromAddress(IN MEMORY_PROFILE_CONTEXT_DATA * ContextData,IN PHYSICAL_ADDRESS Address)894 GetMemoryProfileDriverInfoFromAddress (
895   IN MEMORY_PROFILE_CONTEXT_DATA    *ContextData,
896   IN PHYSICAL_ADDRESS               Address
897   )
898 {
899   MEMORY_PROFILE_DRIVER_INFO        *DriverInfo;
900   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
901   LIST_ENTRY                        *DriverLink;
902   LIST_ENTRY                        *DriverInfoList;
903 
904   DriverInfoList = ContextData->DriverInfoList;
905 
906   for (DriverLink = DriverInfoList->ForwardLink;
907        DriverLink != DriverInfoList;
908        DriverLink = DriverLink->ForwardLink) {
909     DriverInfoData = CR (
910                        DriverLink,
911                        MEMORY_PROFILE_DRIVER_INFO_DATA,
912                        Link,
913                        MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
914                        );
915     DriverInfo = &DriverInfoData->DriverInfo;
916     if ((Address >= DriverInfo->ImageBase) &&
917         (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {
918       return DriverInfoData;
919     }
920   }
921 
922   return NULL;
923 }
924 
925 /**
926   Unregister image from SMRAM profile.
927 
928   @param DriverEntry        SMM image info.
929   @param UnregisterFromDxe  Unregister image from DXE.
930 
931   @return EFI_SUCCESS           Unregister successfully.
932   @return EFI_UNSUPPORTED       Memory profile is unsupported,
933                                 or memory profile for the image is not required.
934   @return EFI_NOT_FOUND         The image is not found.
935 
936 **/
937 EFI_STATUS
UnregisterSmramProfileImage(IN EFI_SMM_DRIVER_ENTRY * DriverEntry,IN BOOLEAN UnregisterFromDxe)938 UnregisterSmramProfileImage (
939   IN EFI_SMM_DRIVER_ENTRY  *DriverEntry,
940   IN BOOLEAN               UnregisterFromDxe
941   )
942 {
943   EFI_STATUS                        Status;
944   MEMORY_PROFILE_CONTEXT_DATA       *ContextData;
945   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
946   EFI_GUID                          *FileName;
947   PHYSICAL_ADDRESS                  ImageAddress;
948   VOID                              *EntryPointInImage;
949   UINT8                             TempBuffer[sizeof(MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH_PROTOCOL)];
950   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
951 
952   if (UnregisterFromDxe) {
953     UnregisterImageFromDxe (
954       &DriverEntry->FileName,
955       DriverEntry->ImageBuffer,
956       EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage)
957       );
958   }
959 
960   if (!IS_SMRAM_PROFILE_ENABLED) {
961     return EFI_UNSUPPORTED;
962   }
963 
964   FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempBuffer;
965   EfiInitializeFwVolDevicepathNode (FilePath, &DriverEntry->FileName);
966   SetDevicePathEndNode (FilePath + 1);
967 
968   if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *) FilePath)) {
969     return EFI_UNSUPPORTED;
970   }
971 
972   ContextData = GetSmramProfileContext ();
973   if (ContextData == NULL) {
974     return EFI_UNSUPPORTED;
975   }
976 
977   DriverInfoData = NULL;
978   FileName = &DriverEntry->FileName;
979   ImageAddress = DriverEntry->ImageBuffer;
980   if ((DriverEntry->ImageEntryPoint < ImageAddress) || (DriverEntry->ImageEntryPoint >= (ImageAddress + EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage)))) {
981     //
982     // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
983     // So patch ImageAddress here to align the EntryPoint.
984     //
985     Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageAddress, &EntryPointInImage);
986     ASSERT_EFI_ERROR (Status);
987     ImageAddress = ImageAddress + (UINTN) DriverEntry->ImageEntryPoint - (UINTN) EntryPointInImage;
988   }
989   if (FileName != NULL) {
990     DriverInfoData = GetMemoryProfileDriverInfoByFileNameAndAddress (ContextData, FileName, ImageAddress);
991   }
992   if (DriverInfoData == NULL) {
993     DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, ImageAddress);
994   }
995   if (DriverInfoData == NULL) {
996     return EFI_NOT_FOUND;
997   }
998 
999   ContextData->Context.TotalImageSize -= DriverInfoData->DriverInfo.ImageSize;
1000 
1001   // Keep the ImageBase for RVA calculation in Application.
1002   //DriverInfoData->DriverInfo.ImageBase = 0;
1003   DriverInfoData->DriverInfo.ImageSize = 0;
1004 
1005   if (DriverInfoData->DriverInfo.PeakUsage == 0) {
1006     ContextData->Context.ImageCount --;
1007     RemoveEntryList (&DriverInfoData->Link);
1008     //
1009     // Use SmmInternalFreePool() that will not update profile for this FreePool action.
1010     //
1011     SmmInternalFreePool (DriverInfoData);
1012   }
1013 
1014   return EFI_SUCCESS;
1015 }
1016 
1017 /**
1018   Return if this memory type needs to be recorded into memory profile.
1019   Only need to record EfiRuntimeServicesCode and EfiRuntimeServicesData for SMRAM profile.
1020 
1021   @param MemoryType     Memory type.
1022 
1023   @retval TRUE          This memory type need to be recorded.
1024   @retval FALSE         This memory type need not to be recorded.
1025 
1026 **/
1027 BOOLEAN
SmmCoreNeedRecordProfile(IN EFI_MEMORY_TYPE MemoryType)1028 SmmCoreNeedRecordProfile (
1029   IN EFI_MEMORY_TYPE    MemoryType
1030   )
1031 {
1032   UINT64 TestBit;
1033 
1034   if (MemoryType != EfiRuntimeServicesCode &&
1035       MemoryType != EfiRuntimeServicesData) {
1036     return FALSE;
1037   }
1038 
1039   TestBit = LShiftU64 (1, MemoryType);
1040 
1041   if ((PcdGet64 (PcdMemoryProfileMemoryType) & TestBit) != 0) {
1042     return TRUE;
1043   } else {
1044     return FALSE;
1045   }
1046 }
1047 
1048 /**
1049   Convert EFI memory type to profile memory index. The rule is:
1050   If BIOS memory type (0 ~ EfiMaxMemoryType - 1), ProfileMemoryIndex = MemoryType.
1051   As SMRAM profile is only to record EfiRuntimeServicesCode and EfiRuntimeServicesData,
1052   so return input memory type directly.
1053 
1054   @param MemoryType     Memory type.
1055 
1056   @return EFI memory type as profile memory index.
1057 
1058 **/
1059 EFI_MEMORY_TYPE
GetProfileMemoryIndex(IN EFI_MEMORY_TYPE MemoryType)1060 GetProfileMemoryIndex (
1061   IN EFI_MEMORY_TYPE    MemoryType
1062   )
1063 {
1064   return MemoryType;
1065 }
1066 
1067 /**
1068   Update SMRAM profile FreeMemoryPages information
1069 
1070   @param ContextData    Memory profile context.
1071 
1072 **/
1073 VOID
SmramProfileUpdateFreePages(IN MEMORY_PROFILE_CONTEXT_DATA * ContextData)1074 SmramProfileUpdateFreePages (
1075   IN MEMORY_PROFILE_CONTEXT_DATA  *ContextData
1076   )
1077 {
1078   LIST_ENTRY                      *Node;
1079   FREE_PAGE_LIST                  *Pages;
1080   LIST_ENTRY                      *FreePageList;
1081   UINTN                           NumberOfPages;
1082 
1083   NumberOfPages = 0;
1084   FreePageList = &mSmmMemoryMap;
1085   for (Node = FreePageList->BackLink;
1086        Node != FreePageList;
1087        Node = Node->BackLink) {
1088     Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
1089     NumberOfPages += Pages->NumberOfPages;
1090   }
1091 
1092   mSmramFreeMemory.TotalFreeMemoryPages = NumberOfPages;
1093 
1094   if (NumberOfPages <= SMRAM_INFO_DUMP_PAGE_THRESHOLD) {
1095     DumpSmramInfo ();
1096   }
1097 }
1098 
1099 /**
1100   Update SMRAM profile Allocate information.
1101 
1102   @param CallerAddress  Address of caller who call Allocate.
1103   @param Action         This Allocate action.
1104   @param MemoryType     Memory type.
1105   @param Size           Buffer size.
1106   @param Buffer         Buffer address.
1107   @param ActionString   String for memory profile action.
1108 
1109   @return EFI_SUCCESS           Memory profile is updated.
1110   @return EFI_UNSUPPORTED       Memory profile is unsupported,
1111                                 or memory profile for the image is not required.
1112   @return EFI_OUT_OF_RESOURCES  No enough resource to update memory profile for allocate action.
1113 
1114 **/
1115 EFI_STATUS
SmmCoreUpdateProfileAllocate(IN PHYSICAL_ADDRESS CallerAddress,IN MEMORY_PROFILE_ACTION Action,IN EFI_MEMORY_TYPE MemoryType,IN UINTN Size,IN VOID * Buffer,IN CHAR8 * ActionString OPTIONAL)1116 SmmCoreUpdateProfileAllocate (
1117   IN PHYSICAL_ADDRESS       CallerAddress,
1118   IN MEMORY_PROFILE_ACTION  Action,
1119   IN EFI_MEMORY_TYPE        MemoryType,
1120   IN UINTN                  Size,
1121   IN VOID                   *Buffer,
1122   IN CHAR8                  *ActionString OPTIONAL
1123   )
1124 {
1125   EFI_STATUS                        Status;
1126   MEMORY_PROFILE_CONTEXT            *Context;
1127   MEMORY_PROFILE_DRIVER_INFO        *DriverInfo;
1128   MEMORY_PROFILE_ALLOC_INFO         *AllocInfo;
1129   MEMORY_PROFILE_CONTEXT_DATA       *ContextData;
1130   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
1131   MEMORY_PROFILE_ALLOC_INFO_DATA    *AllocInfoData;
1132   EFI_MEMORY_TYPE                   ProfileMemoryIndex;
1133   MEMORY_PROFILE_ACTION             BasicAction;
1134   UINTN                             ActionStringSize;
1135   UINTN                             ActionStringOccupiedSize;
1136 
1137   BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
1138 
1139   ContextData = GetSmramProfileContext ();
1140   if (ContextData == NULL) {
1141     return EFI_UNSUPPORTED;
1142   }
1143 
1144   DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
1145   if (DriverInfoData == NULL) {
1146     return EFI_UNSUPPORTED;
1147   }
1148 
1149   ActionStringSize = 0;
1150   ActionStringOccupiedSize = 0;
1151   if (ActionString != NULL) {
1152     ActionStringSize = AsciiStrSize (ActionString);
1153     ActionStringOccupiedSize = GET_OCCUPIED_SIZE (ActionStringSize, sizeof (UINT64));
1154   }
1155 
1156   //
1157   // Use SmmInternalAllocatePool() that will not update profile for this AllocatePool action.
1158   //
1159   AllocInfoData = NULL;
1160   Status = SmmInternalAllocatePool (
1161              EfiRuntimeServicesData,
1162              sizeof (*AllocInfoData) + ActionStringSize,
1163              (VOID **) &AllocInfoData
1164              );
1165   if (EFI_ERROR (Status)) {
1166     return EFI_OUT_OF_RESOURCES;
1167   }
1168   ASSERT (AllocInfoData != NULL);
1169 
1170   //
1171   // Only update SequenceCount if and only if it is basic action.
1172   //
1173   if (Action == BasicAction) {
1174     ContextData->Context.SequenceCount ++;
1175   }
1176 
1177   AllocInfo = &AllocInfoData->AllocInfo;
1178   AllocInfoData->Signature      = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
1179   AllocInfo->Header.Signature   = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
1180   AllocInfo->Header.Length      = (UINT16) (sizeof (MEMORY_PROFILE_ALLOC_INFO) + ActionStringOccupiedSize);
1181   AllocInfo->Header.Revision    = MEMORY_PROFILE_ALLOC_INFO_REVISION;
1182   AllocInfo->CallerAddress      = CallerAddress;
1183   AllocInfo->SequenceId         = ContextData->Context.SequenceCount;
1184   AllocInfo->Action             = Action;
1185   AllocInfo->MemoryType         = MemoryType;
1186   AllocInfo->Buffer             = (PHYSICAL_ADDRESS) (UINTN) Buffer;
1187   AllocInfo->Size               = Size;
1188   if (ActionString != NULL) {
1189     AllocInfo->ActionStringOffset = (UINT16) sizeof (MEMORY_PROFILE_ALLOC_INFO);
1190     AllocInfoData->ActionString = (CHAR8 *) (AllocInfoData + 1);
1191     CopyMem (AllocInfoData->ActionString, ActionString, ActionStringSize);
1192   } else {
1193     AllocInfo->ActionStringOffset = 0;
1194     AllocInfoData->ActionString = NULL;
1195   }
1196 
1197   InsertTailList (DriverInfoData->AllocInfoList, &AllocInfoData->Link);
1198 
1199   Context = &ContextData->Context;
1200   DriverInfo = &DriverInfoData->DriverInfo;
1201   DriverInfo->AllocRecordCount ++;
1202 
1203   //
1204   // Update summary if and only if it is basic action.
1205   //
1206   if (Action == BasicAction) {
1207     ProfileMemoryIndex = GetProfileMemoryIndex (MemoryType);
1208 
1209     DriverInfo->CurrentUsage += Size;
1210     if (DriverInfo->PeakUsage < DriverInfo->CurrentUsage) {
1211       DriverInfo->PeakUsage = DriverInfo->CurrentUsage;
1212     }
1213     DriverInfo->CurrentUsageByType[ProfileMemoryIndex] += Size;
1214     if (DriverInfo->PeakUsageByType[ProfileMemoryIndex] < DriverInfo->CurrentUsageByType[ProfileMemoryIndex]) {
1215       DriverInfo->PeakUsageByType[ProfileMemoryIndex] = DriverInfo->CurrentUsageByType[ProfileMemoryIndex];
1216     }
1217 
1218     Context->CurrentTotalUsage += Size;
1219     if (Context->PeakTotalUsage < Context->CurrentTotalUsage) {
1220       Context->PeakTotalUsage = Context->CurrentTotalUsage;
1221     }
1222     Context->CurrentTotalUsageByType[ProfileMemoryIndex] += Size;
1223     if (Context->PeakTotalUsageByType[ProfileMemoryIndex] < Context->CurrentTotalUsageByType[ProfileMemoryIndex]) {
1224       Context->PeakTotalUsageByType[ProfileMemoryIndex] = Context->CurrentTotalUsageByType[ProfileMemoryIndex];
1225     }
1226 
1227     SmramProfileUpdateFreePages (ContextData);
1228   }
1229 
1230   return EFI_SUCCESS;
1231 }
1232 
1233 /**
1234   Get memory profile alloc info from memory profile
1235 
1236   @param DriverInfoData     Driver info
1237   @param BasicAction        This Free basic action
1238   @param Size               Buffer size
1239   @param Buffer             Buffer address
1240 
1241   @return Pointer to memory profile alloc info.
1242 **/
1243 MEMORY_PROFILE_ALLOC_INFO_DATA *
GetMemoryProfileAllocInfoFromAddress(IN MEMORY_PROFILE_DRIVER_INFO_DATA * DriverInfoData,IN MEMORY_PROFILE_ACTION BasicAction,IN UINTN Size,IN VOID * Buffer)1244 GetMemoryProfileAllocInfoFromAddress (
1245   IN MEMORY_PROFILE_DRIVER_INFO_DATA    *DriverInfoData,
1246   IN MEMORY_PROFILE_ACTION              BasicAction,
1247   IN UINTN                              Size,
1248   IN VOID                               *Buffer
1249   )
1250 {
1251   LIST_ENTRY                        *AllocInfoList;
1252   LIST_ENTRY                        *AllocLink;
1253   MEMORY_PROFILE_ALLOC_INFO         *AllocInfo;
1254   MEMORY_PROFILE_ALLOC_INFO_DATA    *AllocInfoData;
1255 
1256   AllocInfoList = DriverInfoData->AllocInfoList;
1257 
1258   for (AllocLink = AllocInfoList->ForwardLink;
1259        AllocLink != AllocInfoList;
1260        AllocLink = AllocLink->ForwardLink) {
1261     AllocInfoData = CR (
1262                       AllocLink,
1263                       MEMORY_PROFILE_ALLOC_INFO_DATA,
1264                       Link,
1265                       MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
1266                       );
1267     AllocInfo = &AllocInfoData->AllocInfo;
1268     if ((AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK) != BasicAction) {
1269       continue;
1270     }
1271     switch (BasicAction) {
1272       case MemoryProfileActionAllocatePages:
1273         if ((AllocInfo->Buffer <= (PHYSICAL_ADDRESS) (UINTN) Buffer) &&
1274             ((AllocInfo->Buffer + AllocInfo->Size) >= ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size))) {
1275           return AllocInfoData;
1276         }
1277         break;
1278       case MemoryProfileActionAllocatePool:
1279         if (AllocInfo->Buffer == (PHYSICAL_ADDRESS) (UINTN) Buffer) {
1280           return AllocInfoData;
1281         }
1282         break;
1283       default:
1284         ASSERT (FALSE);
1285         break;
1286     }
1287   }
1288 
1289   return NULL;
1290 }
1291 
1292 /**
1293   Update SMRAM profile Free information.
1294 
1295   @param CallerAddress  Address of caller who call Free.
1296   @param Action         This Free action.
1297   @param Size           Buffer size.
1298   @param Buffer         Buffer address.
1299 
1300   @return EFI_SUCCESS           Memory profile is updated.
1301   @return EFI_UNSUPPORTED       Memory profile is unsupported.
1302   @return EFI_NOT_FOUND         No matched allocate info found for free action.
1303 
1304 **/
1305 EFI_STATUS
SmmCoreUpdateProfileFree(IN PHYSICAL_ADDRESS CallerAddress,IN MEMORY_PROFILE_ACTION Action,IN UINTN Size,IN VOID * Buffer)1306 SmmCoreUpdateProfileFree (
1307   IN PHYSICAL_ADDRESS       CallerAddress,
1308   IN MEMORY_PROFILE_ACTION  Action,
1309   IN UINTN                  Size,
1310   IN VOID                   *Buffer
1311   )
1312 {
1313   MEMORY_PROFILE_CONTEXT           *Context;
1314   MEMORY_PROFILE_DRIVER_INFO       *DriverInfo;
1315   MEMORY_PROFILE_ALLOC_INFO        *AllocInfo;
1316   MEMORY_PROFILE_CONTEXT_DATA      *ContextData;
1317   MEMORY_PROFILE_DRIVER_INFO_DATA  *DriverInfoData;
1318   LIST_ENTRY                       *DriverLink;
1319   LIST_ENTRY                       *DriverInfoList;
1320   MEMORY_PROFILE_DRIVER_INFO_DATA  *ThisDriverInfoData;
1321   MEMORY_PROFILE_ALLOC_INFO_DATA   *AllocInfoData;
1322   EFI_MEMORY_TYPE                  ProfileMemoryIndex;
1323   MEMORY_PROFILE_ACTION            BasicAction;
1324   BOOLEAN                          Found;
1325 
1326   BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
1327 
1328   ContextData = GetSmramProfileContext ();
1329   if (ContextData == NULL) {
1330     return EFI_UNSUPPORTED;
1331   }
1332 
1333   DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
1334 
1335   //
1336   // Do not return if DriverInfoData == NULL here,
1337   // because driver A might free memory allocated by driver B.
1338   //
1339 
1340   //
1341   // Need use do-while loop to find all possible record,
1342   // because one address might be recorded multiple times.
1343   //
1344   Found = FALSE;
1345   AllocInfoData = NULL;
1346   do {
1347     if (DriverInfoData != NULL) {
1348       switch (BasicAction) {
1349         case MemoryProfileActionFreePages:
1350           AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
1351           break;
1352         case MemoryProfileActionFreePool:
1353           AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
1354           break;
1355         default:
1356           ASSERT (FALSE);
1357           AllocInfoData = NULL;
1358           break;
1359       }
1360     }
1361     if (AllocInfoData == NULL) {
1362       //
1363       // Legal case, because driver A might free memory allocated by driver B, by some protocol.
1364       //
1365       DriverInfoList = ContextData->DriverInfoList;
1366 
1367       for (DriverLink = DriverInfoList->ForwardLink;
1368            DriverLink != DriverInfoList;
1369            DriverLink = DriverLink->ForwardLink) {
1370         ThisDriverInfoData = CR (
1371                                DriverLink,
1372                                MEMORY_PROFILE_DRIVER_INFO_DATA,
1373                                Link,
1374                                MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
1375                                );
1376         switch (BasicAction) {
1377           case MemoryProfileActionFreePages:
1378             AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
1379             break;
1380           case MemoryProfileActionFreePool:
1381             AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
1382             break;
1383           default:
1384             ASSERT (FALSE);
1385             AllocInfoData = NULL;
1386             break;
1387         }
1388         if (AllocInfoData != NULL) {
1389           DriverInfoData = ThisDriverInfoData;
1390           break;
1391         }
1392       }
1393 
1394       if (AllocInfoData == NULL) {
1395         //
1396         // If (!Found), no matched allocate info is found for this free action.
1397         // It is because the specified memory type allocate actions have been filtered by
1398         // CoreNeedRecordProfile(), but free actions have no memory type information,
1399         // they can not be filtered by CoreNeedRecordProfile(). Then, they will be
1400         // filtered here.
1401         //
1402         // If (Found), it is normal exit path.
1403         return (Found ? EFI_SUCCESS : EFI_NOT_FOUND);
1404       }
1405     }
1406 
1407     ASSERT (DriverInfoData != NULL);
1408     ASSERT (AllocInfoData != NULL);
1409 
1410     Found = TRUE;
1411 
1412     Context = &ContextData->Context;
1413     DriverInfo = &DriverInfoData->DriverInfo;
1414     AllocInfo = &AllocInfoData->AllocInfo;
1415 
1416     DriverInfo->AllocRecordCount --;
1417     //
1418     // Update summary if and only if it is basic action.
1419     //
1420     if (AllocInfo->Action == (AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK)) {
1421       ProfileMemoryIndex = GetProfileMemoryIndex (AllocInfo->MemoryType);
1422 
1423       Context->CurrentTotalUsage -= AllocInfo->Size;
1424       Context->CurrentTotalUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
1425 
1426       DriverInfo->CurrentUsage -= AllocInfo->Size;
1427       DriverInfo->CurrentUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
1428     }
1429 
1430     RemoveEntryList (&AllocInfoData->Link);
1431 
1432     if (BasicAction == MemoryProfileActionFreePages) {
1433       if (AllocInfo->Buffer != (PHYSICAL_ADDRESS) (UINTN) Buffer) {
1434         SmmCoreUpdateProfileAllocate (
1435           AllocInfo->CallerAddress,
1436           AllocInfo->Action,
1437           AllocInfo->MemoryType,
1438           (UINTN) ((PHYSICAL_ADDRESS) (UINTN) Buffer - AllocInfo->Buffer),
1439           (VOID *) (UINTN) AllocInfo->Buffer,
1440           AllocInfoData->ActionString
1441           );
1442       }
1443       if (AllocInfo->Buffer + AllocInfo->Size != ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)) {
1444         SmmCoreUpdateProfileAllocate (
1445           AllocInfo->CallerAddress,
1446           AllocInfo->Action,
1447           AllocInfo->MemoryType,
1448           (UINTN) ((AllocInfo->Buffer + AllocInfo->Size) - ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)),
1449           (VOID *) ((UINTN) Buffer + Size),
1450           AllocInfoData->ActionString
1451           );
1452       }
1453     }
1454 
1455     //
1456     // Use SmmInternalFreePool() that will not update profile for this FreePool action.
1457     //
1458     SmmInternalFreePool (AllocInfoData);
1459   } while (TRUE);
1460 }
1461 
1462 /**
1463   Update SMRAM profile information.
1464 
1465   @param CallerAddress  Address of caller who call Allocate or Free.
1466   @param Action         This Allocate or Free action.
1467   @param MemoryType     Memory type.
1468                         EfiMaxMemoryType means the MemoryType is unknown.
1469   @param Size           Buffer size.
1470   @param Buffer         Buffer address.
1471   @param ActionString   String for memory profile action.
1472                         Only needed for user defined allocate action.
1473 
1474   @return EFI_SUCCESS           Memory profile is updated.
1475   @return EFI_UNSUPPORTED       Memory profile is unsupported,
1476                                 or memory profile for the image is not required,
1477                                 or memory profile for the memory type is not required.
1478   @return EFI_ACCESS_DENIED     It is during memory profile data getting.
1479   @return EFI_ABORTED           Memory profile recording is not enabled.
1480   @return EFI_OUT_OF_RESOURCES  No enough resource to update memory profile for allocate action.
1481   @return EFI_NOT_FOUND         No matched allocate info found for free action.
1482 
1483 **/
1484 EFI_STATUS
1485 EFIAPI
SmmCoreUpdateProfile(IN PHYSICAL_ADDRESS CallerAddress,IN MEMORY_PROFILE_ACTION Action,IN EFI_MEMORY_TYPE MemoryType,IN UINTN Size,IN VOID * Buffer,IN CHAR8 * ActionString OPTIONAL)1486 SmmCoreUpdateProfile (
1487   IN PHYSICAL_ADDRESS       CallerAddress,
1488   IN MEMORY_PROFILE_ACTION  Action,
1489   IN EFI_MEMORY_TYPE        MemoryType, // Valid for AllocatePages/AllocatePool
1490   IN UINTN                  Size,       // Valid for AllocatePages/FreePages/AllocatePool
1491   IN VOID                   *Buffer,
1492   IN CHAR8                  *ActionString OPTIONAL
1493   )
1494 {
1495   EFI_STATUS                    Status;
1496   MEMORY_PROFILE_CONTEXT_DATA   *ContextData;
1497   MEMORY_PROFILE_ACTION         BasicAction;
1498 
1499   if (!IS_SMRAM_PROFILE_ENABLED) {
1500     return EFI_UNSUPPORTED;
1501   }
1502 
1503   if (mSmramProfileGettingStatus) {
1504     return EFI_ACCESS_DENIED;
1505   }
1506 
1507   if (!mSmramProfileRecordingEnable) {
1508     return EFI_ABORTED;
1509   }
1510 
1511   //
1512   // Get the basic action to know how to process the record
1513   //
1514   BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
1515 
1516   //
1517   // Free operations have no memory type information, so skip the check.
1518   //
1519   if ((BasicAction == MemoryProfileActionAllocatePages) || (BasicAction == MemoryProfileActionAllocatePool)) {
1520     //
1521     // Only record limited MemoryType.
1522     //
1523     if (!SmmCoreNeedRecordProfile (MemoryType)) {
1524       return EFI_UNSUPPORTED;
1525     }
1526   }
1527 
1528   ContextData = GetSmramProfileContext ();
1529   if (ContextData == NULL) {
1530     return EFI_UNSUPPORTED;
1531   }
1532 
1533   switch (BasicAction) {
1534     case MemoryProfileActionAllocatePages:
1535       Status = SmmCoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
1536       break;
1537     case MemoryProfileActionFreePages:
1538       Status = SmmCoreUpdateProfileFree (CallerAddress, Action, Size, Buffer);
1539       break;
1540     case MemoryProfileActionAllocatePool:
1541       Status = SmmCoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
1542       break;
1543     case MemoryProfileActionFreePool:
1544       Status = SmmCoreUpdateProfileFree (CallerAddress, Action, 0, Buffer);
1545       break;
1546     default:
1547       ASSERT (FALSE);
1548       Status = EFI_UNSUPPORTED;
1549       break;
1550   }
1551 
1552   return Status;
1553 }
1554 
1555 /**
1556   SMRAM profile ready to lock callback function.
1557 
1558 **/
1559 VOID
SmramProfileReadyToLock(VOID)1560 SmramProfileReadyToLock (
1561   VOID
1562   )
1563 {
1564   if (!IS_SMRAM_PROFILE_ENABLED) {
1565     return;
1566   }
1567 
1568   DEBUG ((EFI_D_INFO, "SmramProfileReadyToLock\n"));
1569   mSmramReadyToLock = TRUE;
1570 }
1571 
1572 ////////////////////
1573 
1574 /**
1575   Get SMRAM profile data size.
1576 
1577   @return SMRAM profile data size.
1578 
1579 **/
1580 UINTN
SmramProfileGetDataSize(VOID)1581 SmramProfileGetDataSize (
1582   VOID
1583   )
1584 {
1585   MEMORY_PROFILE_CONTEXT_DATA       *ContextData;
1586   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
1587   MEMORY_PROFILE_ALLOC_INFO_DATA    *AllocInfoData;
1588   LIST_ENTRY                        *DriverInfoList;
1589   LIST_ENTRY                        *DriverLink;
1590   LIST_ENTRY                        *AllocInfoList;
1591   LIST_ENTRY                        *AllocLink;
1592   UINTN                             TotalSize;
1593   LIST_ENTRY                        *Node;
1594   LIST_ENTRY                        *FreePageList;
1595   LIST_ENTRY                        *FreePoolList;
1596   FREE_POOL_HEADER                  *Pool;
1597   UINTN                             PoolListIndex;
1598   UINTN                             Index;
1599   UINTN                             SmmPoolTypeIndex;
1600 
1601   ContextData = GetSmramProfileContext ();
1602   if (ContextData == NULL) {
1603     return 0;
1604   }
1605 
1606   TotalSize = sizeof (MEMORY_PROFILE_CONTEXT);
1607 
1608   DriverInfoList = ContextData->DriverInfoList;
1609   for (DriverLink = DriverInfoList->ForwardLink;
1610        DriverLink != DriverInfoList;
1611        DriverLink = DriverLink->ForwardLink) {
1612     DriverInfoData = CR (
1613                    DriverLink,
1614                    MEMORY_PROFILE_DRIVER_INFO_DATA,
1615                    Link,
1616                    MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
1617                    );
1618     TotalSize += DriverInfoData->DriverInfo.Header.Length;
1619 
1620     AllocInfoList = DriverInfoData->AllocInfoList;
1621     for (AllocLink = AllocInfoList->ForwardLink;
1622          AllocLink != AllocInfoList;
1623          AllocLink = AllocLink->ForwardLink) {
1624       AllocInfoData = CR (
1625                         AllocLink,
1626                         MEMORY_PROFILE_ALLOC_INFO_DATA,
1627                         Link,
1628                         MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
1629                         );
1630       TotalSize += AllocInfoData->AllocInfo.Header.Length;
1631     }
1632   }
1633 
1634 
1635   Index = 0;
1636   FreePageList = &mSmmMemoryMap;
1637   for (Node = FreePageList->BackLink;
1638        Node != FreePageList;
1639        Node = Node->BackLink) {
1640     Index++;
1641   }
1642   for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
1643     for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
1644       FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][PoolListIndex];
1645       for (Node = FreePoolList->BackLink;
1646            Node != FreePoolList;
1647            Node = Node->BackLink) {
1648         Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
1649         if (Pool->Header.Available) {
1650           Index++;
1651         }
1652       }
1653     }
1654   }
1655 
1656   TotalSize += (sizeof (MEMORY_PROFILE_FREE_MEMORY) + Index * sizeof (MEMORY_PROFILE_DESCRIPTOR));
1657   TotalSize += (sizeof (MEMORY_PROFILE_MEMORY_RANGE) + mFullSmramRangeCount * sizeof (MEMORY_PROFILE_DESCRIPTOR));
1658 
1659   return TotalSize;
1660 }
1661 
1662 /**
1663   Copy SMRAM profile data.
1664 
1665   @param ProfileBuffer  The buffer to hold SMRAM profile data.
1666   @param ProfileSize    On input, profile buffer size.
1667                         On output, actual profile data size copied.
1668   @param ProfileOffset  On input, profile buffer offset to copy.
1669                         On output, next time profile buffer offset to copy.
1670 
1671 **/
1672 VOID
SmramProfileCopyData(OUT VOID * ProfileBuffer,IN OUT UINT64 * ProfileSize,IN OUT UINT64 * ProfileOffset)1673 SmramProfileCopyData (
1674   OUT VOID      *ProfileBuffer,
1675   IN OUT UINT64 *ProfileSize,
1676   IN OUT UINT64 *ProfileOffset
1677   )
1678 {
1679   MEMORY_PROFILE_CONTEXT           *Context;
1680   MEMORY_PROFILE_DRIVER_INFO       *DriverInfo;
1681   MEMORY_PROFILE_ALLOC_INFO        *AllocInfo;
1682   MEMORY_PROFILE_CONTEXT_DATA      *ContextData;
1683   MEMORY_PROFILE_DRIVER_INFO_DATA  *DriverInfoData;
1684   MEMORY_PROFILE_ALLOC_INFO_DATA   *AllocInfoData;
1685   LIST_ENTRY                      *DriverInfoList;
1686   LIST_ENTRY                      *DriverLink;
1687   LIST_ENTRY                      *AllocInfoList;
1688   LIST_ENTRY                      *AllocLink;
1689   LIST_ENTRY                      *Node;
1690   FREE_PAGE_LIST                  *Pages;
1691   LIST_ENTRY                      *FreePageList;
1692   LIST_ENTRY                      *FreePoolList;
1693   FREE_POOL_HEADER                *Pool;
1694   UINTN                           PoolListIndex;
1695   UINT32                          Index;
1696   MEMORY_PROFILE_FREE_MEMORY      *FreeMemory;
1697   MEMORY_PROFILE_MEMORY_RANGE     *MemoryRange;
1698   MEMORY_PROFILE_DESCRIPTOR       *MemoryProfileDescriptor;
1699   UINT64                          Offset;
1700   UINT64                          RemainingSize;
1701   UINTN                           PdbSize;
1702   UINTN                           ActionStringSize;
1703   UINTN                           SmmPoolTypeIndex;
1704 
1705   ContextData = GetSmramProfileContext ();
1706   if (ContextData == NULL) {
1707     return ;
1708   }
1709 
1710   RemainingSize = *ProfileSize;
1711   Offset = 0;
1712 
1713   if (*ProfileOffset < sizeof (MEMORY_PROFILE_CONTEXT)) {
1714     if (RemainingSize >= sizeof (MEMORY_PROFILE_CONTEXT)) {
1715       Context = ProfileBuffer;
1716       CopyMem (Context, &ContextData->Context, sizeof (MEMORY_PROFILE_CONTEXT));
1717       RemainingSize -= sizeof (MEMORY_PROFILE_CONTEXT);
1718       ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_CONTEXT);
1719     } else {
1720       goto Done;
1721     }
1722   }
1723   Offset += sizeof (MEMORY_PROFILE_CONTEXT);
1724 
1725   DriverInfoList = ContextData->DriverInfoList;
1726   for (DriverLink = DriverInfoList->ForwardLink;
1727        DriverLink != DriverInfoList;
1728        DriverLink = DriverLink->ForwardLink) {
1729     DriverInfoData = CR (
1730                        DriverLink,
1731                        MEMORY_PROFILE_DRIVER_INFO_DATA,
1732                        Link,
1733                        MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
1734                        );
1735     if (*ProfileOffset < (Offset + DriverInfoData->DriverInfo.Header.Length)) {
1736       if (RemainingSize >= DriverInfoData->DriverInfo.Header.Length) {
1737         DriverInfo = ProfileBuffer;
1738         CopyMem (DriverInfo, &DriverInfoData->DriverInfo, sizeof (MEMORY_PROFILE_DRIVER_INFO));
1739         if (DriverInfo->PdbStringOffset != 0) {
1740           PdbSize = AsciiStrSize (DriverInfoData->PdbString);
1741           CopyMem ((VOID *) ((UINTN) DriverInfo + DriverInfo->PdbStringOffset), DriverInfoData->PdbString, PdbSize);
1742         }
1743         RemainingSize -= DriverInfo->Header.Length;
1744         ProfileBuffer = (UINT8 *) ProfileBuffer + DriverInfo->Header.Length;
1745       } else {
1746         goto Done;
1747       }
1748     }
1749     Offset += DriverInfoData->DriverInfo.Header.Length;
1750 
1751     AllocInfoList = DriverInfoData->AllocInfoList;
1752     for (AllocLink = AllocInfoList->ForwardLink;
1753          AllocLink != AllocInfoList;
1754          AllocLink = AllocLink->ForwardLink) {
1755       AllocInfoData = CR (
1756                         AllocLink,
1757                         MEMORY_PROFILE_ALLOC_INFO_DATA,
1758                         Link,
1759                         MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
1760                         );
1761       if (*ProfileOffset < (Offset + AllocInfoData->AllocInfo.Header.Length)) {
1762         if (RemainingSize >= AllocInfoData->AllocInfo.Header.Length) {
1763           AllocInfo = ProfileBuffer;
1764           CopyMem (AllocInfo, &AllocInfoData->AllocInfo, sizeof (MEMORY_PROFILE_ALLOC_INFO));
1765           if (AllocInfo->ActionStringOffset) {
1766             ActionStringSize = AsciiStrSize (AllocInfoData->ActionString);
1767             CopyMem ((VOID *) ((UINTN) AllocInfo + AllocInfo->ActionStringOffset), AllocInfoData->ActionString, ActionStringSize);
1768           }
1769           RemainingSize -= AllocInfo->Header.Length;
1770           ProfileBuffer = (UINT8 *) ProfileBuffer + AllocInfo->Header.Length;
1771         } else {
1772           goto Done;
1773         }
1774       }
1775       Offset += AllocInfoData->AllocInfo.Header.Length;
1776     }
1777   }
1778 
1779 
1780   if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_FREE_MEMORY))) {
1781     if (RemainingSize >= sizeof (MEMORY_PROFILE_FREE_MEMORY)) {
1782       FreeMemory = ProfileBuffer;
1783       CopyMem (FreeMemory, &mSmramFreeMemory, sizeof (MEMORY_PROFILE_FREE_MEMORY));
1784       Index = 0;
1785       FreePageList = &mSmmMemoryMap;
1786       for (Node = FreePageList->BackLink;
1787            Node != FreePageList;
1788            Node = Node->BackLink) {
1789         Index++;
1790       }
1791       for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
1792         for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
1793           FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][MAX_POOL_INDEX - PoolListIndex - 1];
1794           for (Node = FreePoolList->BackLink;
1795                Node != FreePoolList;
1796                Node = Node->BackLink) {
1797             Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
1798             if (Pool->Header.Available) {
1799               Index++;
1800             }
1801           }
1802         }
1803       }
1804       FreeMemory->FreeMemoryEntryCount = Index;
1805 
1806       RemainingSize -= sizeof (MEMORY_PROFILE_FREE_MEMORY);
1807       ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_FREE_MEMORY);
1808     } else {
1809       goto Done;
1810     }
1811   }
1812   Offset += sizeof (MEMORY_PROFILE_FREE_MEMORY);
1813   FreePageList = &mSmmMemoryMap;
1814   for (Node = FreePageList->BackLink;
1815        Node != FreePageList;
1816        Node = Node->BackLink) {
1817     if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_DESCRIPTOR))) {
1818       if (RemainingSize >= sizeof (MEMORY_PROFILE_DESCRIPTOR)) {
1819         Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
1820         MemoryProfileDescriptor = ProfileBuffer;
1821         MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;
1822         MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);
1823         MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;
1824         MemoryProfileDescriptor->Address = (PHYSICAL_ADDRESS) (UINTN) Pages;
1825         MemoryProfileDescriptor->Size = EFI_PAGES_TO_SIZE (Pages->NumberOfPages);
1826 
1827         RemainingSize -= sizeof (MEMORY_PROFILE_DESCRIPTOR);
1828         ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_DESCRIPTOR);
1829       } else {
1830         goto Done;
1831       }
1832     }
1833     Offset += sizeof (MEMORY_PROFILE_DESCRIPTOR);
1834   }
1835   for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
1836     for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
1837       FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][MAX_POOL_INDEX - PoolListIndex - 1];
1838       for (Node = FreePoolList->BackLink;
1839            Node != FreePoolList;
1840            Node = Node->BackLink) {
1841         Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
1842         if (Pool->Header.Available) {
1843           if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_DESCRIPTOR))) {
1844             if (RemainingSize >= sizeof (MEMORY_PROFILE_DESCRIPTOR)) {
1845               MemoryProfileDescriptor = ProfileBuffer;
1846               MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;
1847               MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);
1848               MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;
1849               MemoryProfileDescriptor->Address = (PHYSICAL_ADDRESS) (UINTN) Pool;
1850               MemoryProfileDescriptor->Size = Pool->Header.Size;
1851 
1852               RemainingSize -= sizeof (MEMORY_PROFILE_DESCRIPTOR);
1853               ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_DESCRIPTOR);
1854             } else {
1855               goto Done;
1856             }
1857           }
1858           Offset += sizeof (MEMORY_PROFILE_DESCRIPTOR);
1859         }
1860       }
1861     }
1862   }
1863 
1864   if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_MEMORY_RANGE))) {
1865     if (RemainingSize >= sizeof (MEMORY_PROFILE_MEMORY_RANGE)) {
1866       MemoryRange = ProfileBuffer;
1867       MemoryRange->Header.Signature = MEMORY_PROFILE_MEMORY_RANGE_SIGNATURE;
1868       MemoryRange->Header.Length = sizeof (MEMORY_PROFILE_MEMORY_RANGE);
1869       MemoryRange->Header.Revision = MEMORY_PROFILE_MEMORY_RANGE_REVISION;
1870       MemoryRange->MemoryRangeCount = (UINT32) mFullSmramRangeCount;
1871 
1872       RemainingSize -= sizeof (MEMORY_PROFILE_MEMORY_RANGE);
1873       ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_MEMORY_RANGE);
1874     } else {
1875       goto Done;
1876     }
1877   }
1878   Offset += sizeof (MEMORY_PROFILE_MEMORY_RANGE);
1879   for (Index = 0; Index < mFullSmramRangeCount; Index++) {
1880     if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_DESCRIPTOR))) {
1881       if (RemainingSize >= sizeof (MEMORY_PROFILE_DESCRIPTOR)) {
1882         MemoryProfileDescriptor = ProfileBuffer;
1883         MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;
1884         MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);
1885         MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;
1886         MemoryProfileDescriptor->Address = mFullSmramRanges[Index].PhysicalStart;
1887         MemoryProfileDescriptor->Size = mFullSmramRanges[Index].PhysicalSize;
1888 
1889         RemainingSize -= sizeof (MEMORY_PROFILE_DESCRIPTOR);
1890         ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_DESCRIPTOR);
1891       } else {
1892         goto Done;
1893       }
1894     }
1895     Offset += sizeof (MEMORY_PROFILE_DESCRIPTOR);
1896   }
1897 
1898 Done:
1899   //
1900   // On output, actual profile data size copied.
1901   //
1902   *ProfileSize -= RemainingSize;
1903   //
1904   // On output, next time profile buffer offset to copy.
1905   //
1906   *ProfileOffset = Offset;
1907 }
1908 
1909 /**
1910   Get memory profile data.
1911 
1912   @param[in]      This              The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
1913   @param[in, out] ProfileSize       On entry, points to the size in bytes of the ProfileBuffer.
1914                                     On return, points to the size of the data returned in ProfileBuffer.
1915   @param[out]     ProfileBuffer     Profile buffer.
1916 
1917   @return EFI_SUCCESS               Get the memory profile data successfully.
1918   @return EFI_UNSUPPORTED           Memory profile is unsupported.
1919   @return EFI_BUFFER_TO_SMALL       The ProfileSize is too small for the resulting data.
1920                                     ProfileSize is updated with the size required.
1921 
1922 **/
1923 EFI_STATUS
1924 EFIAPI
SmramProfileProtocolGetData(IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL * This,IN OUT UINT64 * ProfileSize,OUT VOID * ProfileBuffer)1925 SmramProfileProtocolGetData (
1926   IN     EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
1927   IN OUT UINT64                             *ProfileSize,
1928      OUT VOID                               *ProfileBuffer
1929   )
1930 {
1931   UINT64                                Size;
1932   UINT64                                Offset;
1933   MEMORY_PROFILE_CONTEXT_DATA           *ContextData;
1934   BOOLEAN                               SmramProfileGettingStatus;
1935 
1936   ContextData = GetSmramProfileContext ();
1937   if (ContextData == NULL) {
1938     return EFI_UNSUPPORTED;
1939   }
1940 
1941   SmramProfileGettingStatus = mSmramProfileGettingStatus;
1942   mSmramProfileGettingStatus = TRUE;
1943 
1944   Size = SmramProfileGetDataSize ();
1945 
1946   if (*ProfileSize < Size) {
1947     *ProfileSize = Size;
1948     mSmramProfileGettingStatus = SmramProfileGettingStatus;
1949     return EFI_BUFFER_TOO_SMALL;
1950   }
1951 
1952   Offset = 0;
1953   SmramProfileCopyData (ProfileBuffer, &Size, &Offset);
1954   *ProfileSize = Size;
1955 
1956   mSmramProfileGettingStatus = SmramProfileGettingStatus;
1957   return EFI_SUCCESS;
1958 }
1959 
1960 /**
1961   Register image to memory profile.
1962 
1963   @param[in] This               The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
1964   @param[in] FilePath           File path of the image.
1965   @param[in] ImageBase          Image base address.
1966   @param[in] ImageSize          Image size.
1967   @param[in] FileType           File type of the image.
1968 
1969   @return EFI_SUCCESS           Register successfully.
1970   @return EFI_UNSUPPORTED       Memory profile is unsupported,
1971                                 or memory profile for the image is not required.
1972   @return EFI_OUT_OF_RESOURCES  No enough resource for this register.
1973 
1974 **/
1975 EFI_STATUS
1976 EFIAPI
SmramProfileProtocolRegisterImage(IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL * This,IN EFI_DEVICE_PATH_PROTOCOL * FilePath,IN PHYSICAL_ADDRESS ImageBase,IN UINT64 ImageSize,IN EFI_FV_FILETYPE FileType)1977 SmramProfileProtocolRegisterImage (
1978   IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
1979   IN EFI_DEVICE_PATH_PROTOCOL           *FilePath,
1980   IN PHYSICAL_ADDRESS                   ImageBase,
1981   IN UINT64                             ImageSize,
1982   IN EFI_FV_FILETYPE                    FileType
1983   )
1984 {
1985   EFI_STATUS                        Status;
1986   EFI_SMM_DRIVER_ENTRY              DriverEntry;
1987   VOID                              *EntryPointInImage;
1988   EFI_GUID                          *Name;
1989 
1990   ZeroMem (&DriverEntry, sizeof (DriverEntry));
1991   Name = GetFileNameFromFilePath (FilePath);
1992   if (Name != NULL) {
1993     CopyMem (&DriverEntry.FileName, Name, sizeof (EFI_GUID));
1994   }
1995   DriverEntry.ImageBuffer = ImageBase;
1996   DriverEntry.NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN) ImageSize);
1997   Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) DriverEntry.ImageBuffer, &EntryPointInImage);
1998   ASSERT_EFI_ERROR (Status);
1999   DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
2000 
2001   return RegisterSmramProfileImage (&DriverEntry, FALSE);
2002 }
2003 
2004 /**
2005   Unregister image from memory profile.
2006 
2007   @param[in] This               The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
2008   @param[in] FilePath           File path of the image.
2009   @param[in] ImageBase          Image base address.
2010   @param[in] ImageSize          Image size.
2011 
2012   @return EFI_SUCCESS           Unregister successfully.
2013   @return EFI_UNSUPPORTED       Memory profile is unsupported,
2014                                 or memory profile for the image is not required.
2015   @return EFI_NOT_FOUND         The image is not found.
2016 
2017 **/
2018 EFI_STATUS
2019 EFIAPI
SmramProfileProtocolUnregisterImage(IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL * This,IN EFI_DEVICE_PATH_PROTOCOL * FilePath,IN PHYSICAL_ADDRESS ImageBase,IN UINT64 ImageSize)2020 SmramProfileProtocolUnregisterImage (
2021   IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
2022   IN EFI_DEVICE_PATH_PROTOCOL           *FilePath,
2023   IN PHYSICAL_ADDRESS                   ImageBase,
2024   IN UINT64                             ImageSize
2025   )
2026 {
2027   EFI_STATUS                        Status;
2028   EFI_SMM_DRIVER_ENTRY              DriverEntry;
2029   VOID                              *EntryPointInImage;
2030   EFI_GUID                          *Name;
2031 
2032   ZeroMem (&DriverEntry, sizeof (DriverEntry));
2033   Name = GetFileNameFromFilePath (FilePath);
2034   if (Name != NULL) {
2035     CopyMem (&DriverEntry.FileName, Name, sizeof (EFI_GUID));
2036   }
2037   DriverEntry.ImageBuffer = ImageBase;
2038   DriverEntry.NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN) ImageSize);
2039   Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) DriverEntry.ImageBuffer, &EntryPointInImage);
2040   ASSERT_EFI_ERROR (Status);
2041   DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
2042 
2043   return UnregisterSmramProfileImage (&DriverEntry, FALSE);
2044 }
2045 
2046 /**
2047   Get memory profile recording state.
2048 
2049   @param[in]  This              The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
2050   @param[out] RecordingState    Recording state.
2051 
2052   @return EFI_SUCCESS           Memory profile recording state is returned.
2053   @return EFI_UNSUPPORTED       Memory profile is unsupported.
2054   @return EFI_INVALID_PARAMETER RecordingState is NULL.
2055 
2056 **/
2057 EFI_STATUS
2058 EFIAPI
SmramProfileProtocolGetRecordingState(IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL * This,OUT BOOLEAN * RecordingState)2059 SmramProfileProtocolGetRecordingState (
2060   IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
2061   OUT BOOLEAN                           *RecordingState
2062   )
2063 {
2064   MEMORY_PROFILE_CONTEXT_DATA           *ContextData;
2065 
2066   ContextData = GetSmramProfileContext ();
2067   if (ContextData == NULL) {
2068     return EFI_UNSUPPORTED;
2069   }
2070 
2071   if (RecordingState == NULL) {
2072     return EFI_INVALID_PARAMETER;
2073   }
2074   *RecordingState = mSmramProfileRecordingEnable;
2075   return EFI_SUCCESS;
2076 }
2077 
2078 /**
2079   Set memory profile recording state.
2080 
2081   @param[in] This               The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
2082   @param[in] RecordingState     Recording state.
2083 
2084   @return EFI_SUCCESS           Set memory profile recording state successfully.
2085   @return EFI_UNSUPPORTED       Memory profile is unsupported.
2086 
2087 **/
2088 EFI_STATUS
2089 EFIAPI
SmramProfileProtocolSetRecordingState(IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL * This,IN BOOLEAN RecordingState)2090 SmramProfileProtocolSetRecordingState (
2091   IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
2092   IN BOOLEAN                            RecordingState
2093   )
2094 {
2095   MEMORY_PROFILE_CONTEXT_DATA           *ContextData;
2096 
2097   ContextData = GetSmramProfileContext ();
2098   if (ContextData == NULL) {
2099     return EFI_UNSUPPORTED;
2100   }
2101 
2102   mSmramProfileRecordingEnable = RecordingState;
2103   return EFI_SUCCESS;
2104 }
2105 
2106 /**
2107   Record memory profile of multilevel caller.
2108 
2109   @param[in] This               The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
2110   @param[in] CallerAddress      Address of caller.
2111   @param[in] Action             Memory profile action.
2112   @param[in] MemoryType         Memory type.
2113                                 EfiMaxMemoryType means the MemoryType is unknown.
2114   @param[in] Buffer             Buffer address.
2115   @param[in] Size               Buffer size.
2116   @param[in] ActionString       String for memory profile action.
2117                                 Only needed for user defined allocate action.
2118 
2119   @return EFI_SUCCESS           Memory profile is updated.
2120   @return EFI_UNSUPPORTED       Memory profile is unsupported,
2121                                 or memory profile for the image is not required,
2122                                 or memory profile for the memory type is not required.
2123   @return EFI_ACCESS_DENIED     It is during memory profile data getting.
2124   @return EFI_ABORTED           Memory profile recording is not enabled.
2125   @return EFI_OUT_OF_RESOURCES  No enough resource to update memory profile for allocate action.
2126   @return EFI_NOT_FOUND         No matched allocate info found for free action.
2127 
2128 **/
2129 EFI_STATUS
2130 EFIAPI
SmramProfileProtocolRecord(IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL * This,IN PHYSICAL_ADDRESS CallerAddress,IN MEMORY_PROFILE_ACTION Action,IN EFI_MEMORY_TYPE MemoryType,IN VOID * Buffer,IN UINTN Size,IN CHAR8 * ActionString OPTIONAL)2131 SmramProfileProtocolRecord (
2132   IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
2133   IN PHYSICAL_ADDRESS                   CallerAddress,
2134   IN MEMORY_PROFILE_ACTION              Action,
2135   IN EFI_MEMORY_TYPE                    MemoryType,
2136   IN VOID                               *Buffer,
2137   IN UINTN                              Size,
2138   IN CHAR8                              *ActionString OPTIONAL
2139   )
2140 {
2141   return SmmCoreUpdateProfile (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
2142 }
2143 
2144 /**
2145   SMRAM profile handler to get profile info.
2146 
2147   @param SmramProfileParameterGetInfo The parameter of SMM profile get size.
2148 
2149 **/
2150 VOID
SmramProfileHandlerGetInfo(IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO * SmramProfileParameterGetInfo)2151 SmramProfileHandlerGetInfo (
2152   IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO   *SmramProfileParameterGetInfo
2153   )
2154 {
2155   MEMORY_PROFILE_CONTEXT_DATA   *ContextData;
2156   BOOLEAN                       SmramProfileGettingStatus;
2157 
2158   ContextData = GetSmramProfileContext ();
2159   if (ContextData == NULL) {
2160     return ;
2161   }
2162 
2163   SmramProfileGettingStatus = mSmramProfileGettingStatus;
2164   mSmramProfileGettingStatus = TRUE;
2165 
2166   SmramProfileParameterGetInfo->ProfileSize = SmramProfileGetDataSize();
2167   SmramProfileParameterGetInfo->Header.ReturnStatus = 0;
2168 
2169   mSmramProfileGettingStatus = SmramProfileGettingStatus;
2170 }
2171 
2172 /**
2173   SMRAM profile handler to get profile data.
2174 
2175   @param SmramProfileParameterGetData The parameter of SMM profile get data.
2176 
2177 **/
2178 VOID
SmramProfileHandlerGetData(IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA * SmramProfileParameterGetData)2179 SmramProfileHandlerGetData (
2180   IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA   *SmramProfileParameterGetData
2181   )
2182 {
2183   UINT64                                    ProfileSize;
2184   UINT64                                    ProfileOffset;
2185   SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA  SmramProfileGetData;
2186   MEMORY_PROFILE_CONTEXT_DATA               *ContextData;
2187   BOOLEAN                                   SmramProfileGettingStatus;
2188 
2189   ContextData = GetSmramProfileContext ();
2190   if (ContextData == NULL) {
2191     return ;
2192   }
2193 
2194   SmramProfileGettingStatus = mSmramProfileGettingStatus;
2195   mSmramProfileGettingStatus = TRUE;
2196 
2197 
2198   CopyMem (&SmramProfileGetData, SmramProfileParameterGetData, sizeof (SmramProfileGetData));
2199 
2200   ProfileSize = SmramProfileGetDataSize();
2201 
2202   //
2203   // Sanity check
2204   //
2205   if (!SmmIsBufferOutsideSmmValid ((UINTN) SmramProfileGetData.ProfileBuffer, (UINTN) ProfileSize)) {
2206     DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetData: SMM ProfileBuffer in SMRAM or overflow!\n"));
2207     SmramProfileParameterGetData->ProfileSize = ProfileSize;
2208     SmramProfileParameterGetData->Header.ReturnStatus = (UINT64) (INT64) (INTN) EFI_ACCESS_DENIED;
2209     goto Done;
2210   }
2211 
2212   if (SmramProfileGetData.ProfileSize < ProfileSize) {
2213     SmramProfileParameterGetData->ProfileSize = ProfileSize;
2214     SmramProfileParameterGetData->Header.ReturnStatus = (UINT64) (INT64) (INTN) EFI_BUFFER_TOO_SMALL;
2215     goto Done;
2216   }
2217 
2218   ProfileOffset = 0;
2219   SmramProfileCopyData ((VOID *) (UINTN) SmramProfileGetData.ProfileBuffer, &ProfileSize, &ProfileOffset);
2220   SmramProfileParameterGetData->ProfileSize = ProfileSize;
2221   SmramProfileParameterGetData->Header.ReturnStatus = 0;
2222 
2223 Done:
2224   mSmramProfileGettingStatus = SmramProfileGettingStatus;
2225 }
2226 
2227 /**
2228   SMRAM profile handler to get profile data by offset.
2229 
2230   @param SmramProfileParameterGetDataByOffset   The parameter of SMM profile get data by offset.
2231 
2232 **/
2233 VOID
SmramProfileHandlerGetDataByOffset(IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET * SmramProfileParameterGetDataByOffset)2234 SmramProfileHandlerGetDataByOffset (
2235   IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET     *SmramProfileParameterGetDataByOffset
2236   )
2237 {
2238   SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET    SmramProfileGetDataByOffset;
2239   MEMORY_PROFILE_CONTEXT_DATA                           *ContextData;
2240   BOOLEAN                                               SmramProfileGettingStatus;
2241 
2242   ContextData = GetSmramProfileContext ();
2243   if (ContextData == NULL) {
2244     return ;
2245   }
2246 
2247   SmramProfileGettingStatus = mSmramProfileGettingStatus;
2248   mSmramProfileGettingStatus = TRUE;
2249 
2250 
2251   CopyMem (&SmramProfileGetDataByOffset, SmramProfileParameterGetDataByOffset, sizeof (SmramProfileGetDataByOffset));
2252 
2253   //
2254   // Sanity check
2255   //
2256   if (!SmmIsBufferOutsideSmmValid ((UINTN) SmramProfileGetDataByOffset.ProfileBuffer, (UINTN) SmramProfileGetDataByOffset.ProfileSize)) {
2257     DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetDataByOffset: SMM ProfileBuffer in SMRAM or overflow!\n"));
2258     SmramProfileParameterGetDataByOffset->Header.ReturnStatus = (UINT64) (INT64) (INTN) EFI_ACCESS_DENIED;
2259     goto Done;
2260   }
2261 
2262   SmramProfileCopyData ((VOID *) (UINTN) SmramProfileGetDataByOffset.ProfileBuffer, &SmramProfileGetDataByOffset.ProfileSize, &SmramProfileGetDataByOffset.ProfileOffset);
2263   CopyMem (SmramProfileParameterGetDataByOffset, &SmramProfileGetDataByOffset, sizeof (SmramProfileGetDataByOffset));
2264   SmramProfileParameterGetDataByOffset->Header.ReturnStatus = 0;
2265 
2266 Done:
2267   mSmramProfileGettingStatus = SmramProfileGettingStatus;
2268 }
2269 
2270 /**
2271   SMRAM profile handler to register SMM image.
2272 
2273   @param SmramProfileParameterRegisterImage The parameter of SMM profile register image.
2274 
2275 **/
2276 VOID
SmramProfileHandlerRegisterImage(IN SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE * SmramProfileParameterRegisterImage)2277 SmramProfileHandlerRegisterImage (
2278   IN SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE *SmramProfileParameterRegisterImage
2279   )
2280 {
2281   EFI_STATUS                        Status;
2282   EFI_SMM_DRIVER_ENTRY              DriverEntry;
2283   VOID                              *EntryPointInImage;
2284 
2285   ZeroMem (&DriverEntry, sizeof (DriverEntry));
2286   CopyMem (&DriverEntry.FileName, &SmramProfileParameterRegisterImage->FileName, sizeof(EFI_GUID));
2287   DriverEntry.ImageBuffer = SmramProfileParameterRegisterImage->ImageBuffer;
2288   DriverEntry.NumberOfPage = (UINTN) SmramProfileParameterRegisterImage->NumberOfPage;
2289   Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) DriverEntry.ImageBuffer, &EntryPointInImage);
2290   ASSERT_EFI_ERROR (Status);
2291   DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
2292 
2293   Status = RegisterSmramProfileImage (&DriverEntry, FALSE);
2294   if (!EFI_ERROR (Status)) {
2295     SmramProfileParameterRegisterImage->Header.ReturnStatus = 0;
2296   }
2297 }
2298 
2299 /**
2300   SMRAM profile handler to unregister SMM image.
2301 
2302   @param SmramProfileParameterUnregisterImage The parameter of SMM profile unregister image.
2303 
2304 **/
2305 VOID
SmramProfileHandlerUnregisterImage(IN SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE * SmramProfileParameterUnregisterImage)2306 SmramProfileHandlerUnregisterImage (
2307   IN SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE *SmramProfileParameterUnregisterImage
2308   )
2309 {
2310   EFI_STATUS                        Status;
2311   EFI_SMM_DRIVER_ENTRY              DriverEntry;
2312   VOID                              *EntryPointInImage;
2313 
2314   ZeroMem (&DriverEntry, sizeof (DriverEntry));
2315   CopyMem (&DriverEntry.FileName, &SmramProfileParameterUnregisterImage->FileName, sizeof (EFI_GUID));
2316   DriverEntry.ImageBuffer = SmramProfileParameterUnregisterImage->ImageBuffer;
2317   DriverEntry.NumberOfPage = (UINTN) SmramProfileParameterUnregisterImage->NumberOfPage;
2318   Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) DriverEntry.ImageBuffer, &EntryPointInImage);
2319   ASSERT_EFI_ERROR (Status);
2320   DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
2321 
2322   Status = UnregisterSmramProfileImage (&DriverEntry, FALSE);
2323   if (!EFI_ERROR (Status)) {
2324     SmramProfileParameterUnregisterImage->Header.ReturnStatus = 0;
2325   }
2326 }
2327 
2328 /**
2329   Dispatch function for a Software SMI handler.
2330 
2331   Caution: This function may receive untrusted input.
2332   Communicate buffer and buffer size are external input, so this function will do basic validation.
2333 
2334   @param DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
2335   @param Context         Points to an optional handler context which was specified when the
2336                          handler was registered.
2337   @param CommBuffer      A pointer to a collection of data in memory that will
2338                          be conveyed from a non-SMM environment into an SMM environment.
2339   @param CommBufferSize  The size of the CommBuffer.
2340 
2341   @retval EFI_SUCCESS Command is handled successfully.
2342 
2343 **/
2344 EFI_STATUS
2345 EFIAPI
SmramProfileHandler(IN EFI_HANDLE DispatchHandle,IN CONST VOID * Context OPTIONAL,IN OUT VOID * CommBuffer OPTIONAL,IN OUT UINTN * CommBufferSize OPTIONAL)2346 SmramProfileHandler (
2347   IN EFI_HANDLE  DispatchHandle,
2348   IN CONST VOID  *Context         OPTIONAL,
2349   IN OUT VOID    *CommBuffer      OPTIONAL,
2350   IN OUT UINTN   *CommBufferSize  OPTIONAL
2351   )
2352 {
2353   SMRAM_PROFILE_PARAMETER_HEADER           *SmramProfileParameterHeader;
2354   UINTN                                    TempCommBufferSize;
2355   SMRAM_PROFILE_PARAMETER_RECORDING_STATE  *ParameterRecordingState;
2356 
2357   DEBUG ((EFI_D_ERROR, "SmramProfileHandler Enter\n"));
2358 
2359   //
2360   // If input is invalid, stop processing this SMI
2361   //
2362   if (CommBuffer == NULL || CommBufferSize == NULL) {
2363     return EFI_SUCCESS;
2364   }
2365 
2366   TempCommBufferSize = *CommBufferSize;
2367 
2368   if (TempCommBufferSize < sizeof (SMRAM_PROFILE_PARAMETER_HEADER)) {
2369     DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
2370     return EFI_SUCCESS;
2371   }
2372 
2373   if (mSmramReadyToLock && !SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
2374     DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer in SMRAM or overflow!\n"));
2375     return EFI_SUCCESS;
2376   }
2377 
2378   SmramProfileParameterHeader = (SMRAM_PROFILE_PARAMETER_HEADER *) ((UINTN) CommBuffer);
2379 
2380   SmramProfileParameterHeader->ReturnStatus = (UINT64)-1;
2381 
2382   if (GetSmramProfileContext () == NULL) {
2383     SmramProfileParameterHeader->ReturnStatus = (UINT64) (INT64) (INTN) EFI_UNSUPPORTED;
2384     return EFI_SUCCESS;
2385   }
2386 
2387   switch (SmramProfileParameterHeader->Command) {
2388   case SMRAM_PROFILE_COMMAND_GET_PROFILE_INFO:
2389     DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetInfo\n"));
2390     if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO)) {
2391       DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
2392       return EFI_SUCCESS;
2393     }
2394     SmramProfileHandlerGetInfo ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *) (UINTN) CommBuffer);
2395     break;
2396   case SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA:
2397     DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetData\n"));
2398     if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA)) {
2399       DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
2400       return EFI_SUCCESS;
2401     }
2402     SmramProfileHandlerGetData ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA *) (UINTN) CommBuffer);
2403     break;
2404   case SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA_BY_OFFSET:
2405     DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetDataByOffset\n"));
2406     if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET)) {
2407       DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
2408       return EFI_SUCCESS;
2409     }
2410     SmramProfileHandlerGetDataByOffset ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET *) (UINTN) CommBuffer);
2411     break;
2412   case SMRAM_PROFILE_COMMAND_REGISTER_IMAGE:
2413     DEBUG ((EFI_D_ERROR, "SmramProfileHandlerRegisterImage\n"));
2414     if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE)) {
2415       DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
2416       return EFI_SUCCESS;
2417     }
2418     if (mSmramReadyToLock) {
2419       return EFI_SUCCESS;
2420     }
2421     SmramProfileHandlerRegisterImage ((SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE *) (UINTN) CommBuffer);
2422     break;
2423   case SMRAM_PROFILE_COMMAND_UNREGISTER_IMAGE:
2424     DEBUG ((EFI_D_ERROR, "SmramProfileHandlerUnregisterImage\n"));
2425     if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE)) {
2426       DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
2427       return EFI_SUCCESS;
2428     }
2429     if (mSmramReadyToLock) {
2430       return EFI_SUCCESS;
2431     }
2432     SmramProfileHandlerUnregisterImage ((SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE *) (UINTN) CommBuffer);
2433     break;
2434   case SMRAM_PROFILE_COMMAND_GET_RECORDING_STATE:
2435     DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetRecordingState\n"));
2436     if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE)) {
2437       DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
2438       return EFI_SUCCESS;
2439     }
2440     ParameterRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *) (UINTN) CommBuffer;
2441     ParameterRecordingState->RecordingState = mSmramProfileRecordingEnable;
2442     ParameterRecordingState->Header.ReturnStatus = 0;
2443     break;
2444   case SMRAM_PROFILE_COMMAND_SET_RECORDING_STATE:
2445     DEBUG ((EFI_D_ERROR, "SmramProfileHandlerSetRecordingState\n"));
2446     if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE)) {
2447       DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
2448       return EFI_SUCCESS;
2449     }
2450     ParameterRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *) (UINTN) CommBuffer;
2451     mSmramProfileRecordingEnable = ParameterRecordingState->RecordingState;
2452     ParameterRecordingState->Header.ReturnStatus = 0;
2453     break;
2454 
2455   default:
2456     break;
2457   }
2458 
2459   DEBUG ((EFI_D_ERROR, "SmramProfileHandler Exit\n"));
2460 
2461   return EFI_SUCCESS;
2462 }
2463 
2464 /**
2465   Register SMRAM profile handler.
2466 
2467 **/
2468 VOID
RegisterSmramProfileHandler(VOID)2469 RegisterSmramProfileHandler (
2470   VOID
2471   )
2472 {
2473   EFI_STATUS    Status;
2474   EFI_HANDLE    DispatchHandle;
2475 
2476   if (!IS_SMRAM_PROFILE_ENABLED) {
2477     return;
2478   }
2479 
2480   Status = SmiHandlerRegister (
2481              SmramProfileHandler,
2482              &gEdkiiMemoryProfileGuid,
2483              &DispatchHandle
2484              );
2485   ASSERT_EFI_ERROR (Status);
2486 }
2487 
2488 ////////////////////
2489 
2490 /**
2491   Dump SMRAM range.
2492 
2493 **/
2494 VOID
DumpSmramRange(VOID)2495 DumpSmramRange (
2496   VOID
2497   )
2498 {
2499   UINTN                         Index;
2500   MEMORY_PROFILE_CONTEXT_DATA   *ContextData;
2501   BOOLEAN                       SmramProfileGettingStatus;
2502 
2503   ContextData = GetSmramProfileContext ();
2504   if (ContextData == NULL) {
2505     return ;
2506   }
2507 
2508   SmramProfileGettingStatus = mSmramProfileGettingStatus;
2509   mSmramProfileGettingStatus = TRUE;
2510 
2511   DEBUG ((EFI_D_INFO, "FullSmramRange address - 0x%08x\n", mFullSmramRanges));
2512 
2513   DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));
2514 
2515   DEBUG ((EFI_D_INFO, "FullSmramRange:\n"));
2516   for (Index = 0; Index < mFullSmramRangeCount; Index++) {
2517     DEBUG ((EFI_D_INFO, "  FullSmramRange (0x%x)\n", Index));
2518     DEBUG ((EFI_D_INFO, "    PhysicalStart      - 0x%016lx\n", mFullSmramRanges[Index].PhysicalStart));
2519     DEBUG ((EFI_D_INFO, "    CpuStart           - 0x%016lx\n", mFullSmramRanges[Index].CpuStart));
2520     DEBUG ((EFI_D_INFO, "    PhysicalSize       - 0x%016lx\n", mFullSmramRanges[Index].PhysicalSize));
2521     DEBUG ((EFI_D_INFO, "    RegionState        - 0x%016lx\n", mFullSmramRanges[Index].RegionState));
2522   }
2523 
2524   DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));
2525 
2526   mSmramProfileGettingStatus = SmramProfileGettingStatus;
2527 }
2528 
2529 /**
2530   Dump SMRAM free page list.
2531 
2532 **/
2533 VOID
DumpFreePagesList(VOID)2534 DumpFreePagesList (
2535   VOID
2536   )
2537 {
2538   LIST_ENTRY                    *FreePageList;
2539   LIST_ENTRY                    *Node;
2540   FREE_PAGE_LIST                *Pages;
2541   UINTN                         Index;
2542   MEMORY_PROFILE_CONTEXT_DATA   *ContextData;
2543   BOOLEAN                       SmramProfileGettingStatus;
2544 
2545   ContextData = GetSmramProfileContext ();
2546   if (ContextData == NULL) {
2547     return ;
2548   }
2549 
2550   SmramProfileGettingStatus = mSmramProfileGettingStatus;
2551   mSmramProfileGettingStatus = TRUE;
2552 
2553   DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));
2554 
2555   DEBUG ((EFI_D_INFO, "FreePagesList:\n"));
2556   FreePageList = &mSmmMemoryMap;
2557   for (Node = FreePageList->BackLink, Index = 0;
2558        Node != FreePageList;
2559        Node = Node->BackLink, Index++) {
2560     Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
2561     DEBUG ((EFI_D_INFO, "  Index - 0x%x\n", Index));
2562     DEBUG ((EFI_D_INFO, "    PhysicalStart - 0x%016lx\n", (PHYSICAL_ADDRESS) (UINTN) Pages));
2563     DEBUG ((EFI_D_INFO, "    NumberOfPages - 0x%08x\n", Pages->NumberOfPages));
2564   }
2565 
2566   DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));
2567 
2568   mSmramProfileGettingStatus = SmramProfileGettingStatus;
2569 }
2570 
2571 /**
2572   Dump SMRAM free pool list.
2573 
2574 **/
2575 VOID
DumpFreePoolList(VOID)2576 DumpFreePoolList (
2577   VOID
2578   )
2579 {
2580   LIST_ENTRY                    *FreePoolList;
2581   LIST_ENTRY                    *Node;
2582   FREE_POOL_HEADER              *Pool;
2583   UINTN                         Index;
2584   UINTN                         PoolListIndex;
2585   MEMORY_PROFILE_CONTEXT_DATA   *ContextData;
2586   BOOLEAN                       SmramProfileGettingStatus;
2587   UINTN                         SmmPoolTypeIndex;
2588 
2589   ContextData = GetSmramProfileContext ();
2590   if (ContextData == NULL) {
2591     return ;
2592   }
2593 
2594   SmramProfileGettingStatus = mSmramProfileGettingStatus;
2595   mSmramProfileGettingStatus = TRUE;
2596 
2597   DEBUG ((DEBUG_INFO, "======= SmramProfile begin =======\n"));
2598 
2599   for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
2600     for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
2601       DEBUG ((DEBUG_INFO, "FreePoolList(%d)(%d):\n", SmmPoolTypeIndex, PoolListIndex));
2602       FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][PoolListIndex];
2603       for (Node = FreePoolList->BackLink, Index = 0;
2604            Node != FreePoolList;
2605            Node = Node->BackLink, Index++) {
2606         Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
2607         DEBUG ((DEBUG_INFO, "  Index - 0x%x\n", Index));
2608         DEBUG ((DEBUG_INFO, "    PhysicalStart - 0x%016lx\n", (PHYSICAL_ADDRESS) (UINTN) Pool));
2609         DEBUG ((DEBUG_INFO, "    Size          - 0x%08x\n", Pool->Header.Size));
2610         DEBUG ((DEBUG_INFO, "    Available     - 0x%02x\n", Pool->Header.Available));
2611       }
2612     }
2613   }
2614 
2615   DEBUG ((DEBUG_INFO, "======= SmramProfile end =======\n"));
2616 
2617   mSmramProfileGettingStatus = SmramProfileGettingStatus;
2618 }
2619 
2620 GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *mSmmActionString[] = {
2621   "SmmUnknown",
2622   "gSmst->SmmAllocatePages",
2623   "gSmst->SmmFreePages",
2624   "gSmst->SmmAllocatePool",
2625   "gSmst->SmmFreePool",
2626 };
2627 
2628 typedef struct {
2629   MEMORY_PROFILE_ACTION  Action;
2630   CHAR8                 *String;
2631 } ACTION_STRING;
2632 
2633 ACTION_STRING mExtActionString[] = {
2634   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_PAGES,                    "Lib:AllocatePages"},
2635   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_PAGES,            "Lib:AllocateRuntimePages"},
2636   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_PAGES,           "Lib:AllocateReservedPages"},
2637   {MEMORY_PROFILE_ACTION_LIB_FREE_PAGES,                        "Lib:FreePages"},
2638   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_PAGES,            "Lib:AllocateAlignedPages"},
2639   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RUNTIME_PAGES,    "Lib:AllocateAlignedRuntimePages"},
2640   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RESERVED_PAGES,   "Lib:AllocateAlignedReservedPages"},
2641   {MEMORY_PROFILE_ACTION_LIB_FREE_ALIGNED_PAGES,                "Lib:FreeAlignedPages"},
2642   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_POOL,                     "Lib:AllocatePool"},
2643   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_POOL,             "Lib:AllocateRuntimePool"},
2644   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_POOL,            "Lib:AllocateReservedPool"},
2645   {MEMORY_PROFILE_ACTION_LIB_FREE_POOL,                         "Lib:FreePool"},
2646   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ZERO_POOL,                "Lib:AllocateZeroPool"},
2647   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_ZERO_POOL,        "Lib:AllocateRuntimeZeroPool"},
2648   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_ZERO_POOL,       "Lib:AllocateReservedZeroPool"},
2649   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_COPY_POOL,                "Lib:AllocateCopyPool"},
2650   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_COPY_POOL,        "Lib:AllocateRuntimeCopyPool"},
2651   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_COPY_POOL,       "Lib:AllocateReservedCopyPool"},
2652   {MEMORY_PROFILE_ACTION_LIB_REALLOCATE_POOL,                   "Lib:ReallocatePool"},
2653   {MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RUNTIME_POOL,           "Lib:ReallocateRuntimePool"},
2654   {MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RESERVED_POOL,          "Lib:ReallocateReservedPool"},
2655 };
2656 
2657 GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mUserDefinedActionString[] = {"UserDefined-0x80000000"};
2658 
2659 typedef struct {
2660   EFI_MEMORY_TYPE   MemoryType;
2661   CHAR8             *MemoryTypeStr;
2662 } PROFILE_MEMORY_TYPE_STRING;
2663 
2664 GLOBAL_REMOVE_IF_UNREFERENCED PROFILE_MEMORY_TYPE_STRING mMemoryTypeString[] = {
2665   {EfiRuntimeServicesCode, "EfiRuntimeServicesCode"},
2666   {EfiRuntimeServicesData, "EfiRuntimeServicesData"}
2667 };
2668 
2669 /**
2670   Memory type to string.
2671 
2672   @param[in] MemoryType Memory type.
2673 
2674   @return Pointer to string.
2675 
2676 **/
2677 CHAR8 *
ProfileMemoryTypeToStr(IN EFI_MEMORY_TYPE MemoryType)2678 ProfileMemoryTypeToStr (
2679   IN EFI_MEMORY_TYPE    MemoryType
2680   )
2681 {
2682   UINTN     Index;
2683   for (Index = 0; Index < ARRAY_SIZE (mMemoryTypeString); Index++) {
2684     if (mMemoryTypeString[Index].MemoryType == MemoryType) {
2685       return mMemoryTypeString[Index].MemoryTypeStr;
2686     }
2687   }
2688 
2689   return "UnexpectedMemoryType";
2690 }
2691 
2692 /**
2693   Action to string.
2694 
2695   @param[in] Action                     Profile action.
2696 
2697   @return Pointer to string.
2698 
2699 **/
2700 CHAR8 *
ProfileActionToStr(IN MEMORY_PROFILE_ACTION Action)2701 ProfileActionToStr (
2702   IN MEMORY_PROFILE_ACTION  Action
2703   )
2704 {
2705   UINTN     Index;
2706   UINTN     ActionStringCount;
2707   CHAR8     **ActionString;
2708 
2709   ActionString = mSmmActionString;
2710   ActionStringCount = ARRAY_SIZE (mSmmActionString);
2711 
2712   if ((UINTN) (UINT32) Action < ActionStringCount) {
2713     return ActionString[Action];
2714   }
2715   for (Index = 0; Index < ARRAY_SIZE (mExtActionString); Index++) {
2716     if (mExtActionString[Index].Action == Action) {
2717       return mExtActionString[Index].String;
2718     }
2719   }
2720 
2721   return ActionString[0];
2722 }
2723 
2724 /**
2725   Dump SMRAM profile.
2726 
2727 **/
2728 VOID
DumpSmramProfile(VOID)2729 DumpSmramProfile (
2730   VOID
2731   )
2732 {
2733   MEMORY_PROFILE_CONTEXT            *Context;
2734   MEMORY_PROFILE_DRIVER_INFO        *DriverInfo;
2735   MEMORY_PROFILE_ALLOC_INFO         *AllocInfo;
2736   MEMORY_PROFILE_CONTEXT_DATA       *ContextData;
2737   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
2738   MEMORY_PROFILE_ALLOC_INFO_DATA    *AllocInfoData;
2739   LIST_ENTRY                        *SmramDriverInfoList;
2740   UINTN                             DriverIndex;
2741   LIST_ENTRY                        *DriverLink;
2742   LIST_ENTRY                        *AllocInfoList;
2743   UINTN                             AllocIndex;
2744   LIST_ENTRY                        *AllocLink;
2745   BOOLEAN                           SmramProfileGettingStatus;
2746   UINTN                             TypeIndex;
2747 
2748   ContextData = GetSmramProfileContext ();
2749   if (ContextData == NULL) {
2750     return ;
2751   }
2752 
2753   SmramProfileGettingStatus = mSmramProfileGettingStatus;
2754   mSmramProfileGettingStatus = TRUE;
2755 
2756   Context = &ContextData->Context;
2757   DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));
2758   DEBUG ((EFI_D_INFO, "MEMORY_PROFILE_CONTEXT\n"));
2759 
2760   DEBUG ((EFI_D_INFO, "  CurrentTotalUsage     - 0x%016lx\n", Context->CurrentTotalUsage));
2761   DEBUG ((EFI_D_INFO, "  PeakTotalUsage        - 0x%016lx\n", Context->PeakTotalUsage));
2762   for (TypeIndex = 0; TypeIndex < sizeof (Context->CurrentTotalUsageByType) / sizeof (Context->CurrentTotalUsageByType[0]); TypeIndex++) {
2763     if ((Context->CurrentTotalUsageByType[TypeIndex] != 0) ||
2764         (Context->PeakTotalUsageByType[TypeIndex] != 0)) {
2765       DEBUG ((EFI_D_INFO, "  CurrentTotalUsage[0x%02x]  - 0x%016lx (%a)\n", TypeIndex, Context->CurrentTotalUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
2766       DEBUG ((EFI_D_INFO, "  PeakTotalUsage[0x%02x]     - 0x%016lx (%a)\n", TypeIndex, Context->PeakTotalUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
2767     }
2768   }
2769   DEBUG ((EFI_D_INFO, "  TotalImageSize        - 0x%016lx\n", Context->TotalImageSize));
2770   DEBUG ((EFI_D_INFO, "  ImageCount            - 0x%08x\n", Context->ImageCount));
2771   DEBUG ((EFI_D_INFO, "  SequenceCount         - 0x%08x\n", Context->SequenceCount));
2772 
2773   SmramDriverInfoList = ContextData->DriverInfoList;
2774   for (DriverLink = SmramDriverInfoList->ForwardLink, DriverIndex = 0;
2775        DriverLink != SmramDriverInfoList;
2776        DriverLink = DriverLink->ForwardLink, DriverIndex++) {
2777     DriverInfoData = CR (
2778                    DriverLink,
2779                    MEMORY_PROFILE_DRIVER_INFO_DATA,
2780                    Link,
2781                    MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
2782                    );
2783     DriverInfo = &DriverInfoData->DriverInfo;
2784     DEBUG ((EFI_D_INFO, "  MEMORY_PROFILE_DRIVER_INFO (0x%x)\n", DriverIndex));
2785     DEBUG ((EFI_D_INFO, "    FileName            - %g\n", &DriverInfo->FileName));
2786     DEBUG ((EFI_D_INFO, "    ImageBase           - 0x%016lx\n", DriverInfo->ImageBase));
2787     DEBUG ((EFI_D_INFO, "    ImageSize           - 0x%016lx\n", DriverInfo->ImageSize));
2788     DEBUG ((EFI_D_INFO, "    EntryPoint          - 0x%016lx\n", DriverInfo->EntryPoint));
2789     DEBUG ((EFI_D_INFO, "    ImageSubsystem      - 0x%04x\n", DriverInfo->ImageSubsystem));
2790     DEBUG ((EFI_D_INFO, "    FileType            - 0x%02x\n", DriverInfo->FileType));
2791     DEBUG ((EFI_D_INFO, "    CurrentUsage        - 0x%016lx\n", DriverInfo->CurrentUsage));
2792     DEBUG ((EFI_D_INFO, "    PeakUsage           - 0x%016lx\n", DriverInfo->PeakUsage));
2793     for (TypeIndex = 0; TypeIndex < sizeof (DriverInfo->CurrentUsageByType) / sizeof (DriverInfo->CurrentUsageByType[0]); TypeIndex++) {
2794       if ((DriverInfo->CurrentUsageByType[TypeIndex] != 0) ||
2795           (DriverInfo->PeakUsageByType[TypeIndex] != 0)) {
2796         DEBUG ((EFI_D_INFO, "    CurrentUsage[0x%02x]     - 0x%016lx (%a)\n", TypeIndex, DriverInfo->CurrentUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
2797         DEBUG ((EFI_D_INFO, "    PeakUsage[0x%02x]        - 0x%016lx (%a)\n", TypeIndex, DriverInfo->PeakUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
2798       }
2799     }
2800     DEBUG ((EFI_D_INFO, "    AllocRecordCount    - 0x%08x\n", DriverInfo->AllocRecordCount));
2801 
2802     AllocInfoList = DriverInfoData->AllocInfoList;
2803     for (AllocLink = AllocInfoList->ForwardLink, AllocIndex = 0;
2804          AllocLink != AllocInfoList;
2805          AllocLink = AllocLink->ForwardLink, AllocIndex++) {
2806       AllocInfoData = CR (
2807                      AllocLink,
2808                      MEMORY_PROFILE_ALLOC_INFO_DATA,
2809                      Link,
2810                      MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
2811                      );
2812       AllocInfo = &AllocInfoData->AllocInfo;
2813       DEBUG ((EFI_D_INFO, "    MEMORY_PROFILE_ALLOC_INFO (0x%x)\n", AllocIndex));
2814       DEBUG ((EFI_D_INFO, "      CallerAddress  - 0x%016lx (Offset: 0x%08x)\n", AllocInfo->CallerAddress, AllocInfo->CallerAddress - DriverInfo->ImageBase));
2815       DEBUG ((EFI_D_INFO, "      SequenceId     - 0x%08x\n", AllocInfo->SequenceId));
2816       if ((AllocInfo->Action & MEMORY_PROFILE_ACTION_USER_DEFINED_MASK) != 0) {
2817         if (AllocInfoData->ActionString != NULL) {
2818           DEBUG ((EFI_D_INFO, "      Action         - 0x%08x (%a)\n", AllocInfo->Action, AllocInfoData->ActionString));
2819         } else {
2820           DEBUG ((EFI_D_INFO, "      Action         - 0x%08x (UserDefined-0x%08x)\n", AllocInfo->Action, AllocInfo->Action));
2821         }
2822       } else {
2823         DEBUG ((EFI_D_INFO, "      Action         - 0x%08x (%a)\n", AllocInfo->Action, ProfileActionToStr (AllocInfo->Action)));
2824       }
2825       DEBUG ((EFI_D_INFO, "      MemoryType     - 0x%08x (%a)\n", AllocInfo->MemoryType, ProfileMemoryTypeToStr (AllocInfo->MemoryType)));
2826       DEBUG ((EFI_D_INFO, "      Buffer         - 0x%016lx\n", AllocInfo->Buffer));
2827       DEBUG ((EFI_D_INFO, "      Size           - 0x%016lx\n", AllocInfo->Size));
2828     }
2829   }
2830 
2831   DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));
2832 
2833   mSmramProfileGettingStatus = SmramProfileGettingStatus;
2834 }
2835 
2836 /**
2837   Dump SMRAM infromation.
2838 
2839 **/
2840 VOID
DumpSmramInfo(VOID)2841 DumpSmramInfo (
2842   VOID
2843   )
2844 {
2845   DEBUG_CODE (
2846     if (IS_SMRAM_PROFILE_ENABLED) {
2847       DumpSmramProfile ();
2848       DumpFreePagesList ();
2849       DumpFreePoolList ();
2850       DumpSmramRange ();
2851     }
2852   );
2853 }
2854 
2855