1 /** @file
2   Support routines for UEFI memory 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 "DxeMain.h"
16 #include "Imem.h"
17 
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 GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY  mImageQueue = INITIALIZE_LIST_HEAD_VARIABLE (mImageQueue);
46 GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA mMemoryProfileContext = {
47   MEMORY_PROFILE_CONTEXT_SIGNATURE,
48   {
49     {
50       MEMORY_PROFILE_CONTEXT_SIGNATURE,
51       sizeof (MEMORY_PROFILE_CONTEXT),
52       MEMORY_PROFILE_CONTEXT_REVISION
53     },
54     0,
55     0,
56     {0},
57     {0},
58     0,
59     0,
60     0
61   },
62   &mImageQueue,
63 };
64 GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA *mMemoryProfileContextPtr = NULL;
65 
66 EFI_LOCK mMemoryProfileLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
67 BOOLEAN mMemoryProfileGettingStatus = FALSE;
68 BOOLEAN mMemoryProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
69 EFI_DEVICE_PATH_PROTOCOL *mMemoryProfileDriverPath;
70 UINTN                    mMemoryProfileDriverPathSize;
71 
72 /**
73   Get memory profile data.
74 
75   @param[in]      This              The EDKII_MEMORY_PROFILE_PROTOCOL instance.
76   @param[in, out] ProfileSize       On entry, points to the size in bytes of the ProfileBuffer.
77                                     On return, points to the size of the data returned in ProfileBuffer.
78   @param[out]     ProfileBuffer     Profile buffer.
79 
80   @return EFI_SUCCESS               Get the memory profile data successfully.
81   @return EFI_UNSUPPORTED           Memory profile is unsupported.
82   @return EFI_BUFFER_TO_SMALL       The ProfileSize is too small for the resulting data.
83                                     ProfileSize is updated with the size required.
84 
85 **/
86 EFI_STATUS
87 EFIAPI
88 ProfileProtocolGetData (
89   IN     EDKII_MEMORY_PROFILE_PROTOCOL  *This,
90   IN OUT UINT64                         *ProfileSize,
91      OUT VOID                           *ProfileBuffer
92   );
93 
94 /**
95   Register image to memory profile.
96 
97   @param[in] This               The EDKII_MEMORY_PROFILE_PROTOCOL instance.
98   @param[in] FilePath           File path of the image.
99   @param[in] ImageBase          Image base address.
100   @param[in] ImageSize          Image size.
101   @param[in] FileType           File type of the image.
102 
103   @return EFI_SUCCESS           Register successfully.
104   @return EFI_UNSUPPORTED       Memory profile is unsupported,
105                                 or memory profile for the image is not required.
106   @return EFI_OUT_OF_RESOURCE   No enough resource for this register.
107 
108 **/
109 EFI_STATUS
110 EFIAPI
111 ProfileProtocolRegisterImage (
112   IN EDKII_MEMORY_PROFILE_PROTOCOL      *This,
113   IN EFI_DEVICE_PATH_PROTOCOL           *FilePath,
114   IN PHYSICAL_ADDRESS                   ImageBase,
115   IN UINT64                             ImageSize,
116   IN EFI_FV_FILETYPE                    FileType
117   );
118 
119 /**
120   Unregister image from memory profile.
121 
122   @param[in] This               The EDKII_MEMORY_PROFILE_PROTOCOL instance.
123   @param[in] FilePath           File path of the image.
124   @param[in] ImageBase          Image base address.
125   @param[in] ImageSize          Image size.
126 
127   @return EFI_SUCCESS           Unregister successfully.
128   @return EFI_UNSUPPORTED       Memory profile is unsupported,
129                                 or memory profile for the image is not required.
130   @return EFI_NOT_FOUND         The image is not found.
131 
132 **/
133 EFI_STATUS
134 EFIAPI
135 ProfileProtocolUnregisterImage (
136   IN EDKII_MEMORY_PROFILE_PROTOCOL      *This,
137   IN EFI_DEVICE_PATH_PROTOCOL           *FilePath,
138   IN PHYSICAL_ADDRESS                   ImageBase,
139   IN UINT64                             ImageSize
140   );
141 
142 /**
143   Get memory profile recording state.
144 
145   @param[in]  This              The EDKII_MEMORY_PROFILE_PROTOCOL instance.
146   @param[out] RecordingState    Recording state.
147 
148   @return EFI_SUCCESS           Memory profile recording state is returned.
149   @return EFI_UNSUPPORTED       Memory profile is unsupported.
150   @return EFI_INVALID_PARAMETER RecordingState is NULL.
151 
152 **/
153 EFI_STATUS
154 EFIAPI
155 ProfileProtocolGetRecordingState (
156   IN EDKII_MEMORY_PROFILE_PROTOCOL      *This,
157   OUT BOOLEAN                           *RecordingState
158   );
159 
160 /**
161   Set memory profile recording state.
162 
163   @param[in] This               The EDKII_MEMORY_PROFILE_PROTOCOL instance.
164   @param[in] RecordingState     Recording state.
165 
166   @return EFI_SUCCESS           Set memory profile recording state successfully.
167   @return EFI_UNSUPPORTED       Memory profile is unsupported.
168 
169 **/
170 EFI_STATUS
171 EFIAPI
172 ProfileProtocolSetRecordingState (
173   IN EDKII_MEMORY_PROFILE_PROTOCOL      *This,
174   IN BOOLEAN                            RecordingState
175   );
176 
177 /**
178   Record memory profile of multilevel caller.
179 
180   @param[in] This               The EDKII_MEMORY_PROFILE_PROTOCOL instance.
181   @param[in] CallerAddress      Address of caller.
182   @param[in] Action             Memory profile action.
183   @param[in] MemoryType         Memory type.
184                                 EfiMaxMemoryType means the MemoryType is unknown.
185   @param[in] Buffer             Buffer address.
186   @param[in] Size               Buffer size.
187   @param[in] ActionString       String for memory profile action.
188                                 Only needed for user defined allocate action.
189 
190   @return EFI_SUCCESS           Memory profile is updated.
191   @return EFI_UNSUPPORTED       Memory profile is unsupported,
192                                 or memory profile for the image is not required,
193                                 or memory profile for the memory type is not required.
194   @return EFI_ACCESS_DENIED     It is during memory profile data getting.
195   @return EFI_ABORTED           Memory profile recording is not enabled.
196   @return EFI_OUT_OF_RESOURCES  No enough resource to update memory profile for allocate action.
197   @return EFI_NOT_FOUND         No matched allocate info found for free action.
198 
199 **/
200 EFI_STATUS
201 EFIAPI
202 ProfileProtocolRecord (
203   IN EDKII_MEMORY_PROFILE_PROTOCOL      *This,
204   IN PHYSICAL_ADDRESS                   CallerAddress,
205   IN MEMORY_PROFILE_ACTION              Action,
206   IN EFI_MEMORY_TYPE                    MemoryType,
207   IN VOID                               *Buffer,
208   IN UINTN                              Size,
209   IN CHAR8                              *ActionString OPTIONAL
210   );
211 
212 EDKII_MEMORY_PROFILE_PROTOCOL mProfileProtocol = {
213   ProfileProtocolGetData,
214   ProfileProtocolRegisterImage,
215   ProfileProtocolUnregisterImage,
216   ProfileProtocolGetRecordingState,
217   ProfileProtocolSetRecordingState,
218   ProfileProtocolRecord,
219 };
220 
221 /**
222   Acquire lock on mMemoryProfileLock.
223 **/
224 VOID
CoreAcquireMemoryProfileLock(VOID)225 CoreAcquireMemoryProfileLock (
226   VOID
227   )
228 {
229   CoreAcquireLock (&mMemoryProfileLock);
230 }
231 
232 /**
233   Release lock on mMemoryProfileLock.
234 **/
235 VOID
CoreReleaseMemoryProfileLock(VOID)236 CoreReleaseMemoryProfileLock (
237   VOID
238   )
239 {
240   CoreReleaseLock (&mMemoryProfileLock);
241 }
242 
243 /**
244   Return memory profile context.
245 
246   @return Memory profile context.
247 
248 **/
249 MEMORY_PROFILE_CONTEXT_DATA *
GetMemoryProfileContext(VOID)250 GetMemoryProfileContext (
251   VOID
252   )
253 {
254   return mMemoryProfileContextPtr;
255 }
256 
257 /**
258   Retrieves the magic value from the PE/COFF header.
259 
260   @param Hdr    The buffer in which to return the PE32, PE32+, or TE header.
261 
262   @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32
263   @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+
264 
265 **/
266 UINT16
InternalPeCoffGetPeHeaderMagicValue(IN EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr)267 InternalPeCoffGetPeHeaderMagicValue (
268   IN  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr
269   )
270 {
271   //
272   // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
273   //       in the PE/COFF Header.  If the MachineType is Itanium(IA64) and the
274   //       Magic value in the OptionalHeader is  EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
275   //       then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
276   //
277   if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
278     return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
279   }
280   //
281   // Return the magic value from the PC/COFF Optional Header
282   //
283   return Hdr.Pe32->OptionalHeader.Magic;
284 }
285 
286 /**
287   Retrieves and returns the Subsystem of a PE/COFF image that has been loaded into system memory.
288   If Pe32Data is NULL, then ASSERT().
289 
290   @param Pe32Data   The pointer to the PE/COFF image that is loaded in system memory.
291 
292   @return The Subsystem of the PE/COFF image.
293 
294 **/
295 UINT16
InternalPeCoffGetSubsystem(IN VOID * Pe32Data)296 InternalPeCoffGetSubsystem (
297   IN VOID  *Pe32Data
298   )
299 {
300   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;
301   EFI_IMAGE_DOS_HEADER                 *DosHdr;
302   UINT16                               Magic;
303 
304   ASSERT (Pe32Data != NULL);
305 
306   DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;
307   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
308     //
309     // DOS image header is present, so read the PE header after the DOS image header.
310     //
311     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
312   } else {
313     //
314     // DOS image header is not present, so PE header is at the image base.
315     //
316     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;
317   }
318 
319   if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
320     return Hdr.Te->Subsystem;
321   } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE)  {
322     Magic = InternalPeCoffGetPeHeaderMagicValue (Hdr);
323     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
324       return Hdr.Pe32->OptionalHeader.Subsystem;
325     } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
326       return Hdr.Pe32Plus->OptionalHeader.Subsystem;
327     }
328   }
329 
330   return 0x0000;
331 }
332 
333 /**
334   Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded
335   into system memory with the PE/COFF Loader Library functions.
336 
337   Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry
338   point in EntryPoint.  If the entry point could not be retrieved from the PE/COFF image, then
339   return RETURN_INVALID_PARAMETER.  Otherwise return RETURN_SUCCESS.
340   If Pe32Data is NULL, then ASSERT().
341   If EntryPoint is NULL, then ASSERT().
342 
343   @param  Pe32Data                  The pointer to the PE/COFF image that is loaded in system memory.
344   @param  EntryPoint                The pointer to entry point to the PE/COFF image to return.
345 
346   @retval RETURN_SUCCESS            EntryPoint was returned.
347   @retval RETURN_INVALID_PARAMETER  The entry point could not be found in the PE/COFF image.
348 
349 **/
350 RETURN_STATUS
InternalPeCoffGetEntryPoint(IN VOID * Pe32Data,OUT VOID ** EntryPoint)351 InternalPeCoffGetEntryPoint (
352   IN  VOID  *Pe32Data,
353   OUT VOID  **EntryPoint
354   )
355 {
356   EFI_IMAGE_DOS_HEADER                  *DosHdr;
357   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
358 
359   ASSERT (Pe32Data   != NULL);
360   ASSERT (EntryPoint != NULL);
361 
362   DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;
363   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
364     //
365     // DOS image header is present, so read the PE header after the DOS image header.
366     //
367     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
368   } else {
369     //
370     // DOS image header is not present, so PE header is at the image base.
371     //
372     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;
373   }
374 
375   //
376   // Calculate the entry point relative to the start of the image.
377   // AddressOfEntryPoint is common for PE32 & PE32+
378   //
379   if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
380     *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);
381     return RETURN_SUCCESS;
382   } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
383     *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff));
384     return RETURN_SUCCESS;
385   }
386 
387   return RETURN_UNSUPPORTED;
388 }
389 
390 /**
391   Build driver info.
392 
393   @param ContextData    Memory profile context.
394   @param FileName       File name of the image.
395   @param ImageBase      Image base address.
396   @param ImageSize      Image size.
397   @param EntryPoint     Entry point of the image.
398   @param ImageSubsystem Image subsystem of the image.
399   @param FileType       File type of the image.
400 
401   @return Pointer to memory profile driver info.
402 
403 **/
404 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)405 BuildDriverInfo (
406   IN MEMORY_PROFILE_CONTEXT_DATA    *ContextData,
407   IN EFI_GUID                       *FileName,
408   IN PHYSICAL_ADDRESS               ImageBase,
409   IN UINT64                         ImageSize,
410   IN PHYSICAL_ADDRESS               EntryPoint,
411   IN UINT16                         ImageSubsystem,
412   IN EFI_FV_FILETYPE                FileType
413   )
414 {
415   EFI_STATUS                        Status;
416   MEMORY_PROFILE_DRIVER_INFO        *DriverInfo;
417   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
418   VOID                              *EntryPointInImage;
419   CHAR8                             *PdbString;
420   UINTN                             PdbSize;
421   UINTN                             PdbOccupiedSize;
422 
423   PdbSize = 0;
424   PdbOccupiedSize = 0;
425   PdbString = NULL;
426   if (ImageBase != 0) {
427     PdbString = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageBase);
428     if (PdbString != NULL) {
429       PdbSize = AsciiStrSize (PdbString);
430       PdbOccupiedSize = GET_OCCUPIED_SIZE (PdbSize, sizeof (UINT64));
431     }
432   }
433 
434   //
435   // Use CoreInternalAllocatePool() that will not update profile for this AllocatePool action.
436   //
437   Status = CoreInternalAllocatePool (
438              EfiBootServicesData,
439              sizeof (*DriverInfoData) + sizeof (LIST_ENTRY) + PdbSize,
440              (VOID **) &DriverInfoData
441              );
442   if (EFI_ERROR (Status)) {
443     return NULL;
444   }
445   ASSERT (DriverInfoData != NULL);
446 
447   ZeroMem (DriverInfoData, sizeof (*DriverInfoData));
448 
449   DriverInfo = &DriverInfoData->DriverInfo;
450   DriverInfoData->Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
451   DriverInfo->Header.Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
452   DriverInfo->Header.Length = (UINT16) (sizeof (MEMORY_PROFILE_DRIVER_INFO) + PdbOccupiedSize);
453   DriverInfo->Header.Revision = MEMORY_PROFILE_DRIVER_INFO_REVISION;
454   if (FileName != NULL) {
455     CopyMem (&DriverInfo->FileName, FileName, sizeof (EFI_GUID));
456   }
457   DriverInfo->ImageBase = ImageBase;
458   DriverInfo->ImageSize = ImageSize;
459   DriverInfo->EntryPoint = EntryPoint;
460   DriverInfo->ImageSubsystem = ImageSubsystem;
461   if ((EntryPoint != 0) && ((EntryPoint < ImageBase) || (EntryPoint >= (ImageBase + ImageSize)))) {
462     //
463     // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
464     // So patch ImageBuffer here to align the EntryPoint.
465     //
466     Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);
467     ASSERT_EFI_ERROR (Status);
468     DriverInfo->ImageBase = ImageBase + EntryPoint - (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
469   }
470   DriverInfo->FileType = FileType;
471   DriverInfoData->AllocInfoList = (LIST_ENTRY *) (DriverInfoData + 1);
472   InitializeListHead (DriverInfoData->AllocInfoList);
473   DriverInfo->CurrentUsage = 0;
474   DriverInfo->PeakUsage = 0;
475   DriverInfo->AllocRecordCount = 0;
476   if (PdbSize != 0) {
477     DriverInfo->PdbStringOffset = (UINT16) sizeof (MEMORY_PROFILE_DRIVER_INFO);
478     DriverInfoData->PdbString = (CHAR8 *) (DriverInfoData->AllocInfoList + 1);
479     CopyMem (DriverInfoData->PdbString, PdbString, PdbSize);
480   } else {
481     DriverInfo->PdbStringOffset = 0;
482     DriverInfoData->PdbString = NULL;
483   }
484 
485   InsertTailList (ContextData->DriverInfoList, &DriverInfoData->Link);
486   ContextData->Context.ImageCount ++;
487   ContextData->Context.TotalImageSize += DriverInfo->ImageSize;
488 
489   return DriverInfoData;
490 }
491 
492 /**
493   Return if record for this driver is needed..
494 
495   @param DriverFilePath     Driver file path.
496 
497   @retval TRUE              Record for this driver is needed.
498   @retval FALSE             Record for this driver is not needed.
499 
500 **/
501 BOOLEAN
NeedRecordThisDriver(IN EFI_DEVICE_PATH_PROTOCOL * DriverFilePath)502 NeedRecordThisDriver (
503   IN EFI_DEVICE_PATH_PROTOCOL       *DriverFilePath
504   )
505 {
506   EFI_DEVICE_PATH_PROTOCOL          *TmpDevicePath;
507   EFI_DEVICE_PATH_PROTOCOL          *DevicePathInstance;
508   UINTN                             DevicePathSize;
509   UINTN                             FilePathSize;
510 
511   if (!IsDevicePathValid (mMemoryProfileDriverPath, mMemoryProfileDriverPathSize)) {
512     //
513     // Invalid Device Path means record all.
514     //
515     return TRUE;
516   }
517 
518   //
519   // Record FilePath without END node.
520   //
521   FilePathSize = GetDevicePathSize (DriverFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
522 
523   DevicePathInstance = mMemoryProfileDriverPath;
524   do {
525     //
526     // Find END node (it might be END_ENTIRE or END_INSTANCE).
527     //
528     TmpDevicePath = DevicePathInstance;
529     while (!IsDevicePathEndType (TmpDevicePath)) {
530       TmpDevicePath = NextDevicePathNode (TmpDevicePath);
531     }
532 
533     //
534     // Do not compare END node.
535     //
536     DevicePathSize = (UINTN)TmpDevicePath - (UINTN)DevicePathInstance;
537     if ((FilePathSize == DevicePathSize) &&
538         (CompareMem (DriverFilePath, DevicePathInstance, DevicePathSize) == 0)) {
539       return TRUE;
540     }
541 
542     //
543     // Get next instance.
544     //
545     DevicePathInstance = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN)DevicePathInstance + DevicePathSize + DevicePathNodeLength(TmpDevicePath));
546   } while (DevicePathSubType (TmpDevicePath) != END_ENTIRE_DEVICE_PATH_SUBTYPE);
547 
548   return FALSE;
549 }
550 
551 /**
552   Register DXE Core to memory profile.
553 
554   @param HobStart       The start address of the HOB.
555   @param ContextData    Memory profile context.
556 
557   @retval TRUE      Register success.
558   @retval FALSE     Register fail.
559 
560 **/
561 BOOLEAN
RegisterDxeCore(IN VOID * HobStart,IN MEMORY_PROFILE_CONTEXT_DATA * ContextData)562 RegisterDxeCore (
563   IN VOID                           *HobStart,
564   IN MEMORY_PROFILE_CONTEXT_DATA    *ContextData
565   )
566 {
567   EFI_PEI_HOB_POINTERS              DxeCoreHob;
568   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
569   PHYSICAL_ADDRESS                  ImageBase;
570   UINT8                             TempBuffer[sizeof(MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH_PROTOCOL)];
571   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
572 
573   ASSERT (ContextData != NULL);
574 
575   //
576   // Searching for image hob
577   //
578   DxeCoreHob.Raw          = HobStart;
579   while ((DxeCoreHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, DxeCoreHob.Raw)) != NULL) {
580     if (CompareGuid (&DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {
581       //
582       // Find Dxe Core HOB
583       //
584       break;
585     }
586     DxeCoreHob.Raw = GET_NEXT_HOB (DxeCoreHob);
587   }
588   ASSERT (DxeCoreHob.Raw != NULL);
589 
590   FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempBuffer;
591   EfiInitializeFwVolDevicepathNode (FilePath, &DxeCoreHob.MemoryAllocationModule->ModuleName);
592   SetDevicePathEndNode (FilePath + 1);
593 
594   if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *) FilePath)) {
595     return FALSE;
596   }
597 
598   ImageBase = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress;
599   DriverInfoData = BuildDriverInfo (
600                      ContextData,
601                      &DxeCoreHob.MemoryAllocationModule->ModuleName,
602                      ImageBase,
603                      DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength,
604                      DxeCoreHob.MemoryAllocationModule->EntryPoint,
605                      InternalPeCoffGetSubsystem ((VOID *) (UINTN) ImageBase),
606                      EFI_FV_FILETYPE_DXE_CORE
607                      );
608   if (DriverInfoData == NULL) {
609     return FALSE;
610   }
611 
612   return TRUE;
613 }
614 
615 /**
616   Initialize memory profile.
617 
618   @param HobStart   The start address of the HOB.
619 
620 **/
621 VOID
MemoryProfileInit(IN VOID * HobStart)622 MemoryProfileInit (
623   IN VOID   *HobStart
624   )
625 {
626   MEMORY_PROFILE_CONTEXT_DATA   *ContextData;
627 
628   if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
629     return;
630   }
631 
632   ContextData = GetMemoryProfileContext ();
633   if (ContextData != NULL) {
634     return;
635   }
636 
637   mMemoryProfileGettingStatus = FALSE;
638   if ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT7) != 0) {
639     mMemoryProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
640   } else {
641     mMemoryProfileRecordingEnable = MEMORY_PROFILE_RECORDING_ENABLE;
642   }
643   mMemoryProfileDriverPathSize = PcdGetSize (PcdMemoryProfileDriverPath);
644   mMemoryProfileDriverPath = AllocateCopyPool (mMemoryProfileDriverPathSize, PcdGetPtr (PcdMemoryProfileDriverPath));
645   mMemoryProfileContextPtr = &mMemoryProfileContext;
646 
647   RegisterDxeCore (HobStart, &mMemoryProfileContext);
648 
649   DEBUG ((EFI_D_INFO, "MemoryProfileInit MemoryProfileContext - 0x%x\n", &mMemoryProfileContext));
650 }
651 
652 /**
653   Install memory profile protocol.
654 
655 **/
656 VOID
MemoryProfileInstallProtocol(VOID)657 MemoryProfileInstallProtocol (
658   VOID
659   )
660 {
661   EFI_HANDLE    Handle;
662   EFI_STATUS    Status;
663 
664   if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
665     return;
666   }
667 
668   Handle = NULL;
669   Status = CoreInstallMultipleProtocolInterfaces (
670              &Handle,
671              &gEdkiiMemoryProfileGuid,
672              &mProfileProtocol,
673              NULL
674              );
675   ASSERT_EFI_ERROR (Status);
676 }
677 
678 /**
679   Get the GUID file name from the file path.
680 
681   @param FilePath  File path.
682 
683   @return The GUID file name from the file path.
684 
685 **/
686 EFI_GUID *
GetFileNameFromFilePath(IN EFI_DEVICE_PATH_PROTOCOL * FilePath)687 GetFileNameFromFilePath (
688   IN EFI_DEVICE_PATH_PROTOCOL   *FilePath
689   )
690 {
691   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH     *ThisFilePath;
692   EFI_GUID                              *FileName;
693 
694   FileName = NULL;
695   if (FilePath != NULL) {
696     ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) FilePath;
697     while (!IsDevicePathEnd (ThisFilePath)) {
698       FileName = EfiGetNameGuidFromFwVolDevicePathNode (ThisFilePath);
699       if (FileName != NULL) {
700         break;
701       }
702       ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) NextDevicePathNode (ThisFilePath);
703     }
704   }
705 
706   return FileName;
707 }
708 
709 /**
710   Register image to memory profile.
711 
712   @param DriverEntry    Image info.
713   @param FileType       Image file type.
714 
715   @return EFI_SUCCESS           Register successfully.
716   @return EFI_UNSUPPORTED       Memory profile is unsupported,
717                                 or memory profile for the image is not required.
718   @return EFI_OUT_OF_RESOURCES  No enough resource for this register.
719 
720 **/
721 EFI_STATUS
RegisterMemoryProfileImage(IN LOADED_IMAGE_PRIVATE_DATA * DriverEntry,IN EFI_FV_FILETYPE FileType)722 RegisterMemoryProfileImage (
723   IN LOADED_IMAGE_PRIVATE_DATA  *DriverEntry,
724   IN EFI_FV_FILETYPE            FileType
725   )
726 {
727   MEMORY_PROFILE_CONTEXT_DATA       *ContextData;
728   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
729 
730   if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
731     return EFI_UNSUPPORTED;
732   }
733 
734   if (!NeedRecordThisDriver (DriverEntry->Info.FilePath)) {
735     return EFI_UNSUPPORTED;
736   }
737 
738   ContextData = GetMemoryProfileContext ();
739   if (ContextData == NULL) {
740     return EFI_UNSUPPORTED;
741   }
742 
743   DriverInfoData = BuildDriverInfo (
744                      ContextData,
745                      GetFileNameFromFilePath (DriverEntry->Info.FilePath),
746                      DriverEntry->ImageContext.ImageAddress,
747                      DriverEntry->ImageContext.ImageSize,
748                      DriverEntry->ImageContext.EntryPoint,
749                      DriverEntry->ImageContext.ImageType,
750                      FileType
751                      );
752   if (DriverInfoData == NULL) {
753     return EFI_OUT_OF_RESOURCES;
754   }
755 
756   return EFI_SUCCESS;
757 }
758 
759 /**
760   Search image from memory profile.
761 
762   @param ContextData    Memory profile context.
763   @param FileName       Image file name.
764   @param Address        Image Address.
765 
766   @return Pointer to memory profile driver info.
767 
768 **/
769 MEMORY_PROFILE_DRIVER_INFO_DATA *
GetMemoryProfileDriverInfoByFileNameAndAddress(IN MEMORY_PROFILE_CONTEXT_DATA * ContextData,IN EFI_GUID * FileName,IN PHYSICAL_ADDRESS Address)770 GetMemoryProfileDriverInfoByFileNameAndAddress (
771   IN MEMORY_PROFILE_CONTEXT_DATA    *ContextData,
772   IN EFI_GUID                       *FileName,
773   IN PHYSICAL_ADDRESS               Address
774   )
775 {
776   MEMORY_PROFILE_DRIVER_INFO        *DriverInfo;
777   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
778   LIST_ENTRY                        *DriverLink;
779   LIST_ENTRY                        *DriverInfoList;
780 
781   DriverInfoList = ContextData->DriverInfoList;
782 
783   for (DriverLink = DriverInfoList->ForwardLink;
784        DriverLink != DriverInfoList;
785        DriverLink = DriverLink->ForwardLink) {
786     DriverInfoData = CR (
787                        DriverLink,
788                        MEMORY_PROFILE_DRIVER_INFO_DATA,
789                        Link,
790                        MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
791                        );
792     DriverInfo = &DriverInfoData->DriverInfo;
793     if ((CompareGuid (&DriverInfo->FileName, FileName)) &&
794         (Address >= DriverInfo->ImageBase) &&
795         (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {
796       return DriverInfoData;
797     }
798   }
799 
800   return NULL;
801 }
802 
803 /**
804   Search image from memory profile.
805   It will return image, if (Address >= ImageBuffer) AND (Address < ImageBuffer + ImageSize).
806 
807   @param ContextData    Memory profile context.
808   @param Address        Image or Function address.
809 
810   @return Pointer to memory profile driver info.
811 
812 **/
813 MEMORY_PROFILE_DRIVER_INFO_DATA *
GetMemoryProfileDriverInfoFromAddress(IN MEMORY_PROFILE_CONTEXT_DATA * ContextData,IN PHYSICAL_ADDRESS Address)814 GetMemoryProfileDriverInfoFromAddress (
815   IN MEMORY_PROFILE_CONTEXT_DATA    *ContextData,
816   IN PHYSICAL_ADDRESS               Address
817   )
818 {
819   MEMORY_PROFILE_DRIVER_INFO        *DriverInfo;
820   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
821   LIST_ENTRY                        *DriverLink;
822   LIST_ENTRY                        *DriverInfoList;
823 
824   DriverInfoList = ContextData->DriverInfoList;
825 
826   for (DriverLink = DriverInfoList->ForwardLink;
827        DriverLink != DriverInfoList;
828        DriverLink = DriverLink->ForwardLink) {
829     DriverInfoData = CR (
830                        DriverLink,
831                        MEMORY_PROFILE_DRIVER_INFO_DATA,
832                        Link,
833                        MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
834                        );
835     DriverInfo = &DriverInfoData->DriverInfo;
836     if ((Address >= DriverInfo->ImageBase) &&
837         (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {
838       return DriverInfoData;
839     }
840   }
841 
842   return NULL;
843 }
844 
845 /**
846   Unregister image from memory profile.
847 
848   @param DriverEntry    Image info.
849 
850   @return EFI_SUCCESS           Unregister successfully.
851   @return EFI_UNSUPPORTED       Memory profile is unsupported,
852                                 or memory profile for the image is not required.
853   @return EFI_NOT_FOUND         The image is not found.
854 
855 **/
856 EFI_STATUS
UnregisterMemoryProfileImage(IN LOADED_IMAGE_PRIVATE_DATA * DriverEntry)857 UnregisterMemoryProfileImage (
858   IN LOADED_IMAGE_PRIVATE_DATA      *DriverEntry
859   )
860 {
861   EFI_STATUS                        Status;
862   MEMORY_PROFILE_CONTEXT_DATA       *ContextData;
863   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
864   EFI_GUID                          *FileName;
865   PHYSICAL_ADDRESS                  ImageAddress;
866   VOID                              *EntryPointInImage;
867 
868   if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
869     return EFI_UNSUPPORTED;
870   }
871 
872   if (!NeedRecordThisDriver (DriverEntry->Info.FilePath)) {
873     return EFI_UNSUPPORTED;
874   }
875 
876   ContextData = GetMemoryProfileContext ();
877   if (ContextData == NULL) {
878     return EFI_UNSUPPORTED;
879   }
880 
881   DriverInfoData = NULL;
882   FileName = GetFileNameFromFilePath (DriverEntry->Info.FilePath);
883   ImageAddress = DriverEntry->ImageContext.ImageAddress;
884   if ((DriverEntry->ImageContext.EntryPoint < ImageAddress) || (DriverEntry->ImageContext.EntryPoint >= (ImageAddress + DriverEntry->ImageContext.ImageSize))) {
885     //
886     // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
887     // So patch ImageAddress here to align the EntryPoint.
888     //
889     Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageAddress, &EntryPointInImage);
890     ASSERT_EFI_ERROR (Status);
891     ImageAddress = ImageAddress + (UINTN) DriverEntry->ImageContext.EntryPoint - (UINTN) EntryPointInImage;
892   }
893   if (FileName != NULL) {
894     DriverInfoData = GetMemoryProfileDriverInfoByFileNameAndAddress (ContextData, FileName, ImageAddress);
895   }
896   if (DriverInfoData == NULL) {
897     DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, ImageAddress);
898   }
899   if (DriverInfoData == NULL) {
900     return EFI_NOT_FOUND;
901   }
902 
903   ContextData->Context.TotalImageSize -= DriverInfoData->DriverInfo.ImageSize;
904 
905   // Keep the ImageBase for RVA calculation in Application.
906   //DriverInfoData->DriverInfo.ImageBase = 0;
907   DriverInfoData->DriverInfo.ImageSize = 0;
908 
909   if (DriverInfoData->DriverInfo.PeakUsage == 0) {
910     ContextData->Context.ImageCount --;
911     RemoveEntryList (&DriverInfoData->Link);
912     //
913     // Use CoreInternalFreePool() that will not update profile for this FreePool action.
914     //
915     CoreInternalFreePool (DriverInfoData, NULL);
916   }
917 
918   return EFI_SUCCESS;
919 }
920 
921 /**
922   Return if this memory type needs to be recorded into memory profile.
923   If BIOS memory type (0 ~ EfiMaxMemoryType - 1), it checks bit (1 << MemoryType).
924   If OS memory type (0x80000000 ~ 0xFFFFFFFF), it checks bit63 - 0x8000000000000000.
925   If OEM memory type (0x70000000 ~ 0x7FFFFFFF), it checks bit62 - 0x4000000000000000.
926 
927   @param MemoryType     Memory type.
928 
929   @retval TRUE          This memory type need to be recorded.
930   @retval FALSE         This memory type need not to be recorded.
931 
932 **/
933 BOOLEAN
CoreNeedRecordProfile(IN EFI_MEMORY_TYPE MemoryType)934 CoreNeedRecordProfile (
935   IN EFI_MEMORY_TYPE    MemoryType
936   )
937 {
938   UINT64 TestBit;
939 
940   if ((UINT32) MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
941     TestBit = BIT63;
942   } else if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
943     TestBit = BIT62;
944   } else {
945     TestBit = LShiftU64 (1, MemoryType);
946   }
947 
948   if ((PcdGet64 (PcdMemoryProfileMemoryType) & TestBit) != 0) {
949     return TRUE;
950   } else {
951     return FALSE;
952   }
953 }
954 
955 /**
956   Convert EFI memory type to profile memory index. The rule is:
957   If BIOS memory type (0 ~ EfiMaxMemoryType - 1), ProfileMemoryIndex = MemoryType.
958   If OS memory type (0x80000000 ~ 0xFFFFFFFF), ProfileMemoryIndex = EfiMaxMemoryType.
959   If OEM memory type (0x70000000 ~ 0x7FFFFFFF), ProfileMemoryIndex = EfiMaxMemoryType + 1.
960 
961   @param MemoryType     Memory type.
962 
963   @return Profile memory index.
964 
965 **/
966 UINTN
GetProfileMemoryIndex(IN EFI_MEMORY_TYPE MemoryType)967 GetProfileMemoryIndex (
968   IN EFI_MEMORY_TYPE    MemoryType
969   )
970 {
971   if ((UINT32) MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
972     return EfiMaxMemoryType;
973   } else if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
974     return EfiMaxMemoryType + 1;
975   } else {
976     return MemoryType;
977   }
978 }
979 
980 /**
981   Update memory profile Allocate information.
982 
983   @param CallerAddress  Address of caller who call Allocate.
984   @param Action         This Allocate action.
985   @param MemoryType     Memory type.
986   @param Size           Buffer size.
987   @param Buffer         Buffer address.
988   @param ActionString   String for memory profile action.
989 
990   @return EFI_SUCCESS           Memory profile is updated.
991   @return EFI_UNSUPPORTED       Memory profile is unsupported,
992                                 or memory profile for the image is not required.
993   @return EFI_OUT_OF_RESOURCES  No enough resource to update memory profile for allocate action.
994 
995 **/
996 EFI_STATUS
CoreUpdateProfileAllocate(IN PHYSICAL_ADDRESS CallerAddress,IN MEMORY_PROFILE_ACTION Action,IN EFI_MEMORY_TYPE MemoryType,IN UINTN Size,IN VOID * Buffer,IN CHAR8 * ActionString OPTIONAL)997 CoreUpdateProfileAllocate (
998   IN PHYSICAL_ADDRESS       CallerAddress,
999   IN MEMORY_PROFILE_ACTION  Action,
1000   IN EFI_MEMORY_TYPE        MemoryType,
1001   IN UINTN                  Size,
1002   IN VOID                   *Buffer,
1003   IN CHAR8                  *ActionString OPTIONAL
1004   )
1005 {
1006   EFI_STATUS                        Status;
1007   MEMORY_PROFILE_CONTEXT            *Context;
1008   MEMORY_PROFILE_DRIVER_INFO        *DriverInfo;
1009   MEMORY_PROFILE_ALLOC_INFO         *AllocInfo;
1010   MEMORY_PROFILE_CONTEXT_DATA       *ContextData;
1011   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
1012   MEMORY_PROFILE_ALLOC_INFO_DATA    *AllocInfoData;
1013   UINTN                             ProfileMemoryIndex;
1014   MEMORY_PROFILE_ACTION             BasicAction;
1015   UINTN                             ActionStringSize;
1016   UINTN                             ActionStringOccupiedSize;
1017 
1018   BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
1019 
1020   ContextData = GetMemoryProfileContext ();
1021   if (ContextData == NULL) {
1022     return EFI_UNSUPPORTED;
1023   }
1024 
1025   DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
1026   if (DriverInfoData == NULL) {
1027     return EFI_UNSUPPORTED;
1028   }
1029 
1030   ActionStringSize = 0;
1031   ActionStringOccupiedSize = 0;
1032   if (ActionString != NULL) {
1033     ActionStringSize = AsciiStrSize (ActionString);
1034     ActionStringOccupiedSize = GET_OCCUPIED_SIZE (ActionStringSize, sizeof (UINT64));
1035   }
1036 
1037   //
1038   // Use CoreInternalAllocatePool() that will not update profile for this AllocatePool action.
1039   //
1040   AllocInfoData = NULL;
1041   Status = CoreInternalAllocatePool (
1042              EfiBootServicesData,
1043              sizeof (*AllocInfoData) + ActionStringSize,
1044              (VOID **) &AllocInfoData
1045              );
1046   if (EFI_ERROR (Status)) {
1047     return EFI_OUT_OF_RESOURCES;
1048   }
1049   ASSERT (AllocInfoData != NULL);
1050 
1051   //
1052   // Only update SequenceCount if and only if it is basic action.
1053   //
1054   if (Action == BasicAction) {
1055     ContextData->Context.SequenceCount ++;
1056   }
1057 
1058   AllocInfo = &AllocInfoData->AllocInfo;
1059   AllocInfoData->Signature      = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
1060   AllocInfo->Header.Signature   = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
1061   AllocInfo->Header.Length      = (UINT16) (sizeof (MEMORY_PROFILE_ALLOC_INFO) + ActionStringOccupiedSize);
1062   AllocInfo->Header.Revision    = MEMORY_PROFILE_ALLOC_INFO_REVISION;
1063   AllocInfo->CallerAddress      = CallerAddress;
1064   AllocInfo->SequenceId         = ContextData->Context.SequenceCount;
1065   AllocInfo->Action             = Action;
1066   AllocInfo->MemoryType         = MemoryType;
1067   AllocInfo->Buffer             = (PHYSICAL_ADDRESS) (UINTN) Buffer;
1068   AllocInfo->Size               = Size;
1069   if (ActionString != NULL) {
1070     AllocInfo->ActionStringOffset = (UINT16) sizeof (MEMORY_PROFILE_ALLOC_INFO);
1071     AllocInfoData->ActionString = (CHAR8 *) (AllocInfoData + 1);
1072     CopyMem (AllocInfoData->ActionString, ActionString, ActionStringSize);
1073   } else {
1074     AllocInfo->ActionStringOffset = 0;
1075     AllocInfoData->ActionString = NULL;
1076   }
1077 
1078   InsertTailList (DriverInfoData->AllocInfoList, &AllocInfoData->Link);
1079 
1080   Context = &ContextData->Context;
1081   DriverInfo = &DriverInfoData->DriverInfo;
1082   DriverInfo->AllocRecordCount ++;
1083 
1084   //
1085   // Update summary if and only if it is basic action.
1086   //
1087   if (Action == BasicAction) {
1088     ProfileMemoryIndex = GetProfileMemoryIndex (MemoryType);
1089 
1090     DriverInfo->CurrentUsage += Size;
1091     if (DriverInfo->PeakUsage < DriverInfo->CurrentUsage) {
1092       DriverInfo->PeakUsage = DriverInfo->CurrentUsage;
1093     }
1094     DriverInfo->CurrentUsageByType[ProfileMemoryIndex] += Size;
1095     if (DriverInfo->PeakUsageByType[ProfileMemoryIndex] < DriverInfo->CurrentUsageByType[ProfileMemoryIndex]) {
1096       DriverInfo->PeakUsageByType[ProfileMemoryIndex] = DriverInfo->CurrentUsageByType[ProfileMemoryIndex];
1097     }
1098 
1099     Context->CurrentTotalUsage += Size;
1100     if (Context->PeakTotalUsage < Context->CurrentTotalUsage) {
1101       Context->PeakTotalUsage = Context->CurrentTotalUsage;
1102     }
1103     Context->CurrentTotalUsageByType[ProfileMemoryIndex] += Size;
1104     if (Context->PeakTotalUsageByType[ProfileMemoryIndex] < Context->CurrentTotalUsageByType[ProfileMemoryIndex]) {
1105       Context->PeakTotalUsageByType[ProfileMemoryIndex] = Context->CurrentTotalUsageByType[ProfileMemoryIndex];
1106     }
1107   }
1108 
1109   return EFI_SUCCESS;
1110 }
1111 
1112 /**
1113   Get memory profile alloc info from memory profile.
1114 
1115   @param DriverInfoData     Driver info.
1116   @param BasicAction        This Free basic action.
1117   @param Size               Buffer size.
1118   @param Buffer             Buffer address.
1119 
1120   @return Pointer to memory profile alloc info.
1121 
1122 **/
1123 MEMORY_PROFILE_ALLOC_INFO_DATA *
GetMemoryProfileAllocInfoFromAddress(IN MEMORY_PROFILE_DRIVER_INFO_DATA * DriverInfoData,IN MEMORY_PROFILE_ACTION BasicAction,IN UINTN Size,IN VOID * Buffer)1124 GetMemoryProfileAllocInfoFromAddress (
1125   IN MEMORY_PROFILE_DRIVER_INFO_DATA    *DriverInfoData,
1126   IN MEMORY_PROFILE_ACTION              BasicAction,
1127   IN UINTN                              Size,
1128   IN VOID                               *Buffer
1129   )
1130 {
1131   LIST_ENTRY                        *AllocInfoList;
1132   LIST_ENTRY                        *AllocLink;
1133   MEMORY_PROFILE_ALLOC_INFO         *AllocInfo;
1134   MEMORY_PROFILE_ALLOC_INFO_DATA    *AllocInfoData;
1135 
1136   AllocInfoList = DriverInfoData->AllocInfoList;
1137 
1138   for (AllocLink = AllocInfoList->ForwardLink;
1139        AllocLink != AllocInfoList;
1140        AllocLink = AllocLink->ForwardLink) {
1141     AllocInfoData = CR (
1142                       AllocLink,
1143                       MEMORY_PROFILE_ALLOC_INFO_DATA,
1144                       Link,
1145                       MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
1146                       );
1147     AllocInfo = &AllocInfoData->AllocInfo;
1148     if ((AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK) != BasicAction) {
1149       continue;
1150     }
1151     switch (BasicAction) {
1152       case MemoryProfileActionAllocatePages:
1153         if ((AllocInfo->Buffer <= (PHYSICAL_ADDRESS) (UINTN) Buffer) &&
1154             ((AllocInfo->Buffer + AllocInfo->Size) >= ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size))) {
1155           return AllocInfoData;
1156         }
1157         break;
1158       case MemoryProfileActionAllocatePool:
1159         if (AllocInfo->Buffer == (PHYSICAL_ADDRESS) (UINTN) Buffer) {
1160           return AllocInfoData;
1161         }
1162         break;
1163       default:
1164         ASSERT (FALSE);
1165         break;
1166     }
1167   }
1168 
1169   return NULL;
1170 }
1171 
1172 /**
1173   Update memory profile Free information.
1174 
1175   @param CallerAddress  Address of caller who call Free.
1176   @param Action         This Free action.
1177   @param Size           Buffer size.
1178   @param Buffer         Buffer address.
1179 
1180   @return EFI_SUCCESS           Memory profile is updated.
1181   @return EFI_UNSUPPORTED       Memory profile is unsupported.
1182   @return EFI_NOT_FOUND         No matched allocate info found for free action.
1183 
1184 **/
1185 EFI_STATUS
CoreUpdateProfileFree(IN PHYSICAL_ADDRESS CallerAddress,IN MEMORY_PROFILE_ACTION Action,IN UINTN Size,IN VOID * Buffer)1186 CoreUpdateProfileFree (
1187   IN PHYSICAL_ADDRESS       CallerAddress,
1188   IN MEMORY_PROFILE_ACTION  Action,
1189   IN UINTN                  Size,
1190   IN VOID                   *Buffer
1191   )
1192 {
1193   MEMORY_PROFILE_CONTEXT           *Context;
1194   MEMORY_PROFILE_DRIVER_INFO       *DriverInfo;
1195   MEMORY_PROFILE_ALLOC_INFO        *AllocInfo;
1196   MEMORY_PROFILE_CONTEXT_DATA      *ContextData;
1197   MEMORY_PROFILE_DRIVER_INFO_DATA  *DriverInfoData;
1198   LIST_ENTRY                       *DriverLink;
1199   LIST_ENTRY                       *DriverInfoList;
1200   MEMORY_PROFILE_DRIVER_INFO_DATA  *ThisDriverInfoData;
1201   MEMORY_PROFILE_ALLOC_INFO_DATA   *AllocInfoData;
1202   UINTN                            ProfileMemoryIndex;
1203   MEMORY_PROFILE_ACTION            BasicAction;
1204   BOOLEAN                          Found;
1205 
1206   BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
1207 
1208   ContextData = GetMemoryProfileContext ();
1209   if (ContextData == NULL) {
1210     return EFI_UNSUPPORTED;
1211   }
1212 
1213   DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
1214 
1215   //
1216   // Do not return if DriverInfoData == NULL here,
1217   // because driver A might free memory allocated by driver B.
1218   //
1219 
1220   //
1221   // Need use do-while loop to find all possible records,
1222   // because one address might be recorded multiple times.
1223   //
1224   Found = FALSE;
1225   AllocInfoData = NULL;
1226   do {
1227     if (DriverInfoData != NULL) {
1228       switch (BasicAction) {
1229         case MemoryProfileActionFreePages:
1230           AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
1231           break;
1232         case MemoryProfileActionFreePool:
1233           AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
1234           break;
1235         default:
1236           ASSERT (FALSE);
1237           AllocInfoData = NULL;
1238           break;
1239       }
1240     }
1241     if (AllocInfoData == NULL) {
1242       //
1243       // Legal case, because driver A might free memory allocated by driver B, by some protocol.
1244       //
1245       DriverInfoList = ContextData->DriverInfoList;
1246 
1247       for (DriverLink = DriverInfoList->ForwardLink;
1248            DriverLink != DriverInfoList;
1249            DriverLink = DriverLink->ForwardLink) {
1250         ThisDriverInfoData = CR (
1251                                DriverLink,
1252                                MEMORY_PROFILE_DRIVER_INFO_DATA,
1253                                Link,
1254                                MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
1255                                );
1256         switch (BasicAction) {
1257           case MemoryProfileActionFreePages:
1258             AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
1259             break;
1260           case MemoryProfileActionFreePool:
1261             AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
1262             break;
1263           default:
1264             ASSERT (FALSE);
1265             AllocInfoData = NULL;
1266             break;
1267         }
1268         if (AllocInfoData != NULL) {
1269           DriverInfoData = ThisDriverInfoData;
1270           break;
1271         }
1272       }
1273 
1274       if (AllocInfoData == NULL) {
1275         //
1276         // If (!Found), no matched allocate info is found for this free action.
1277         // It is because the specified memory type allocate actions have been filtered by
1278         // CoreNeedRecordProfile(), but free actions may have no memory type information,
1279         // they can not be filtered by CoreNeedRecordProfile(). Then, they will be
1280         // filtered here.
1281         //
1282         // If (Found), it is normal exit path.
1283         return (Found ? EFI_SUCCESS : EFI_NOT_FOUND);
1284       }
1285     }
1286 
1287     ASSERT (DriverInfoData != NULL);
1288     ASSERT (AllocInfoData != NULL);
1289 
1290     Found = TRUE;
1291 
1292     Context = &ContextData->Context;
1293     DriverInfo = &DriverInfoData->DriverInfo;
1294     AllocInfo = &AllocInfoData->AllocInfo;
1295 
1296     DriverInfo->AllocRecordCount --;
1297     //
1298     // Update summary if and only if it is basic action.
1299     //
1300     if (AllocInfo->Action == (AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK)) {
1301       ProfileMemoryIndex = GetProfileMemoryIndex (AllocInfo->MemoryType);
1302 
1303       Context->CurrentTotalUsage -= AllocInfo->Size;
1304       Context->CurrentTotalUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
1305 
1306       DriverInfo->CurrentUsage -= AllocInfo->Size;
1307       DriverInfo->CurrentUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
1308     }
1309 
1310     RemoveEntryList (&AllocInfoData->Link);
1311 
1312     if (BasicAction == MemoryProfileActionFreePages) {
1313       if (AllocInfo->Buffer != (PHYSICAL_ADDRESS) (UINTN) Buffer) {
1314         CoreUpdateProfileAllocate (
1315           AllocInfo->CallerAddress,
1316           AllocInfo->Action,
1317           AllocInfo->MemoryType,
1318           (UINTN) ((PHYSICAL_ADDRESS) (UINTN) Buffer - AllocInfo->Buffer),
1319           (VOID *) (UINTN) AllocInfo->Buffer,
1320           AllocInfoData->ActionString
1321           );
1322       }
1323       if (AllocInfo->Buffer + AllocInfo->Size != ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)) {
1324         CoreUpdateProfileAllocate (
1325           AllocInfo->CallerAddress,
1326           AllocInfo->Action,
1327           AllocInfo->MemoryType,
1328           (UINTN) ((AllocInfo->Buffer + AllocInfo->Size) - ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)),
1329           (VOID *) ((UINTN) Buffer + Size),
1330           AllocInfoData->ActionString
1331           );
1332       }
1333     }
1334 
1335     //
1336     // Use CoreInternalFreePool() that will not update profile for this FreePool action.
1337     //
1338     CoreInternalFreePool (AllocInfoData, NULL);
1339   } while (TRUE);
1340 }
1341 
1342 /**
1343   Update memory profile information.
1344 
1345   @param CallerAddress  Address of caller who call Allocate or Free.
1346   @param Action         This Allocate or Free action.
1347   @param MemoryType     Memory type.
1348                         EfiMaxMemoryType means the MemoryType is unknown.
1349   @param Size           Buffer size.
1350   @param Buffer         Buffer address.
1351   @param ActionString   String for memory profile action.
1352                         Only needed for user defined allocate action.
1353 
1354   @return EFI_SUCCESS           Memory profile is updated.
1355   @return EFI_UNSUPPORTED       Memory profile is unsupported,
1356                                 or memory profile for the image is not required,
1357                                 or memory profile for the memory type is not required.
1358   @return EFI_ACCESS_DENIED     It is during memory profile data getting.
1359   @return EFI_ABORTED           Memory profile recording is not enabled.
1360   @return EFI_OUT_OF_RESOURCES  No enough resource to update memory profile for allocate action.
1361   @return EFI_NOT_FOUND         No matched allocate info found for free action.
1362 
1363 **/
1364 EFI_STATUS
1365 EFIAPI
CoreUpdateProfile(IN PHYSICAL_ADDRESS CallerAddress,IN MEMORY_PROFILE_ACTION Action,IN EFI_MEMORY_TYPE MemoryType,IN UINTN Size,IN VOID * Buffer,IN CHAR8 * ActionString OPTIONAL)1366 CoreUpdateProfile (
1367   IN PHYSICAL_ADDRESS       CallerAddress,
1368   IN MEMORY_PROFILE_ACTION  Action,
1369   IN EFI_MEMORY_TYPE        MemoryType,
1370   IN UINTN                  Size,       // Valid for AllocatePages/FreePages/AllocatePool
1371   IN VOID                   *Buffer,
1372   IN CHAR8                  *ActionString OPTIONAL
1373   )
1374 {
1375   EFI_STATUS                    Status;
1376   MEMORY_PROFILE_CONTEXT_DATA   *ContextData;
1377   MEMORY_PROFILE_ACTION         BasicAction;
1378 
1379   if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
1380     return EFI_UNSUPPORTED;
1381   }
1382 
1383   if (mMemoryProfileGettingStatus) {
1384     return EFI_ACCESS_DENIED;
1385   }
1386 
1387   if (!mMemoryProfileRecordingEnable) {
1388     return EFI_ABORTED;
1389   }
1390 
1391   //
1392   // Get the basic action to know how to process the record
1393   //
1394   BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
1395 
1396   //
1397   // EfiMaxMemoryType means the MemoryType is unknown.
1398   //
1399   if (MemoryType != EfiMaxMemoryType) {
1400     //
1401     // Only record limited MemoryType.
1402     //
1403     if (!CoreNeedRecordProfile (MemoryType)) {
1404       return EFI_UNSUPPORTED;
1405     }
1406   }
1407 
1408   ContextData = GetMemoryProfileContext ();
1409   if (ContextData == NULL) {
1410     return EFI_UNSUPPORTED;
1411   }
1412 
1413   CoreAcquireMemoryProfileLock ();
1414   switch (BasicAction) {
1415     case MemoryProfileActionAllocatePages:
1416       Status = CoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
1417       break;
1418     case MemoryProfileActionFreePages:
1419       Status = CoreUpdateProfileFree (CallerAddress, Action, Size, Buffer);
1420       break;
1421     case MemoryProfileActionAllocatePool:
1422       Status = CoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
1423       break;
1424     case MemoryProfileActionFreePool:
1425       Status = CoreUpdateProfileFree (CallerAddress, Action, 0, Buffer);
1426       break;
1427     default:
1428       ASSERT (FALSE);
1429       Status = EFI_UNSUPPORTED;
1430       break;
1431   }
1432   CoreReleaseMemoryProfileLock ();
1433 
1434   return Status;
1435 }
1436 
1437 ////////////////////
1438 
1439 /**
1440   Get memory profile data size.
1441 
1442   @return Memory profile data size.
1443 
1444 **/
1445 UINTN
MemoryProfileGetDataSize(VOID)1446 MemoryProfileGetDataSize (
1447   VOID
1448   )
1449 {
1450   MEMORY_PROFILE_CONTEXT_DATA       *ContextData;
1451   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
1452   MEMORY_PROFILE_ALLOC_INFO_DATA    *AllocInfoData;
1453   LIST_ENTRY                        *DriverInfoList;
1454   LIST_ENTRY                        *DriverLink;
1455   LIST_ENTRY                        *AllocInfoList;
1456   LIST_ENTRY                        *AllocLink;
1457   UINTN                             TotalSize;
1458 
1459 
1460   ContextData = GetMemoryProfileContext ();
1461   if (ContextData == NULL) {
1462     return 0;
1463   }
1464 
1465   TotalSize = sizeof (MEMORY_PROFILE_CONTEXT);
1466 
1467   DriverInfoList = ContextData->DriverInfoList;
1468   for (DriverLink = DriverInfoList->ForwardLink;
1469        DriverLink != DriverInfoList;
1470        DriverLink = DriverLink->ForwardLink) {
1471     DriverInfoData = CR (
1472                        DriverLink,
1473                        MEMORY_PROFILE_DRIVER_INFO_DATA,
1474                        Link,
1475                        MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
1476                        );
1477     TotalSize += DriverInfoData->DriverInfo.Header.Length;
1478 
1479     AllocInfoList = DriverInfoData->AllocInfoList;
1480     for (AllocLink = AllocInfoList->ForwardLink;
1481          AllocLink != AllocInfoList;
1482          AllocLink = AllocLink->ForwardLink) {
1483       AllocInfoData = CR (
1484                         AllocLink,
1485                         MEMORY_PROFILE_ALLOC_INFO_DATA,
1486                         Link,
1487                         MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
1488                         );
1489       TotalSize += AllocInfoData->AllocInfo.Header.Length;
1490     }
1491   }
1492 
1493   return TotalSize;
1494 }
1495 
1496 /**
1497   Copy memory profile data.
1498 
1499   @param ProfileBuffer  The buffer to hold memory profile data.
1500 
1501 **/
1502 VOID
MemoryProfileCopyData(IN VOID * ProfileBuffer)1503 MemoryProfileCopyData (
1504   IN VOID   *ProfileBuffer
1505   )
1506 {
1507   MEMORY_PROFILE_CONTEXT            *Context;
1508   MEMORY_PROFILE_DRIVER_INFO        *DriverInfo;
1509   MEMORY_PROFILE_ALLOC_INFO         *AllocInfo;
1510   MEMORY_PROFILE_CONTEXT_DATA       *ContextData;
1511   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
1512   MEMORY_PROFILE_ALLOC_INFO_DATA    *AllocInfoData;
1513   LIST_ENTRY                        *DriverInfoList;
1514   LIST_ENTRY                        *DriverLink;
1515   LIST_ENTRY                        *AllocInfoList;
1516   LIST_ENTRY                        *AllocLink;
1517   UINTN                             PdbSize;
1518   UINTN                             ActionStringSize;
1519 
1520   ContextData = GetMemoryProfileContext ();
1521   if (ContextData == NULL) {
1522     return ;
1523   }
1524 
1525   Context = ProfileBuffer;
1526   CopyMem (Context, &ContextData->Context, sizeof (MEMORY_PROFILE_CONTEXT));
1527   DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) (Context + 1);
1528 
1529   DriverInfoList = ContextData->DriverInfoList;
1530   for (DriverLink = DriverInfoList->ForwardLink;
1531        DriverLink != DriverInfoList;
1532        DriverLink = DriverLink->ForwardLink) {
1533     DriverInfoData = CR (
1534                        DriverLink,
1535                        MEMORY_PROFILE_DRIVER_INFO_DATA,
1536                        Link,
1537                        MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
1538                        );
1539     CopyMem (DriverInfo, &DriverInfoData->DriverInfo, sizeof (MEMORY_PROFILE_DRIVER_INFO));
1540     if (DriverInfo->PdbStringOffset != 0) {
1541       PdbSize = AsciiStrSize (DriverInfoData->PdbString);
1542       CopyMem ((VOID *) ((UINTN) DriverInfo + DriverInfo->PdbStringOffset), DriverInfoData->PdbString, PdbSize);
1543     }
1544     AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) ((UINTN) DriverInfo + DriverInfo->Header.Length);
1545 
1546     AllocInfoList = DriverInfoData->AllocInfoList;
1547     for (AllocLink = AllocInfoList->ForwardLink;
1548          AllocLink != AllocInfoList;
1549          AllocLink = AllocLink->ForwardLink) {
1550       AllocInfoData = CR (
1551                         AllocLink,
1552                         MEMORY_PROFILE_ALLOC_INFO_DATA,
1553                         Link,
1554                         MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
1555                         );
1556       CopyMem (AllocInfo, &AllocInfoData->AllocInfo, sizeof (MEMORY_PROFILE_ALLOC_INFO));
1557       if (AllocInfo->ActionStringOffset != 0) {
1558         ActionStringSize = AsciiStrSize (AllocInfoData->ActionString);
1559         CopyMem ((VOID *) ((UINTN) AllocInfo + AllocInfo->ActionStringOffset), AllocInfoData->ActionString, ActionStringSize);
1560       }
1561       AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) ((UINTN) AllocInfo + AllocInfo->Header.Length);
1562     }
1563 
1564     DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *)  AllocInfo;
1565   }
1566 }
1567 
1568 /**
1569   Get memory profile data.
1570 
1571   @param[in]      This              The EDKII_MEMORY_PROFILE_PROTOCOL instance.
1572   @param[in, out] ProfileSize       On entry, points to the size in bytes of the ProfileBuffer.
1573                                     On return, points to the size of the data returned in ProfileBuffer.
1574   @param[out]     ProfileBuffer     Profile buffer.
1575 
1576   @return EFI_SUCCESS               Get the memory profile data successfully.
1577   @return EFI_UNSUPPORTED           Memory profile is unsupported.
1578   @return EFI_BUFFER_TO_SMALL       The ProfileSize is too small for the resulting data.
1579                                     ProfileSize is updated with the size required.
1580 
1581 **/
1582 EFI_STATUS
1583 EFIAPI
ProfileProtocolGetData(IN EDKII_MEMORY_PROFILE_PROTOCOL * This,IN OUT UINT64 * ProfileSize,OUT VOID * ProfileBuffer)1584 ProfileProtocolGetData (
1585   IN     EDKII_MEMORY_PROFILE_PROTOCOL  *This,
1586   IN OUT UINT64                         *ProfileSize,
1587      OUT VOID                           *ProfileBuffer
1588   )
1589 {
1590   UINTN                                 Size;
1591   MEMORY_PROFILE_CONTEXT_DATA           *ContextData;
1592   BOOLEAN                               MemoryProfileGettingStatus;
1593 
1594   ContextData = GetMemoryProfileContext ();
1595   if (ContextData == NULL) {
1596     return EFI_UNSUPPORTED;
1597   }
1598 
1599   MemoryProfileGettingStatus = mMemoryProfileGettingStatus;
1600   mMemoryProfileGettingStatus = TRUE;
1601 
1602   Size = MemoryProfileGetDataSize ();
1603 
1604   if (*ProfileSize < Size) {
1605     *ProfileSize = Size;
1606     mMemoryProfileGettingStatus = MemoryProfileGettingStatus;
1607     return EFI_BUFFER_TOO_SMALL;
1608   }
1609 
1610   *ProfileSize = Size;
1611   MemoryProfileCopyData (ProfileBuffer);
1612 
1613   mMemoryProfileGettingStatus = MemoryProfileGettingStatus;
1614   return EFI_SUCCESS;
1615 }
1616 
1617 /**
1618   Register image to memory profile.
1619 
1620   @param[in] This               The EDKII_MEMORY_PROFILE_PROTOCOL instance.
1621   @param[in] FilePath           File path of the image.
1622   @param[in] ImageBase          Image base address.
1623   @param[in] ImageSize          Image size.
1624   @param[in] FileType           File type of the image.
1625 
1626   @return EFI_SUCCESS           Register successfully.
1627   @return EFI_UNSUPPORTED       Memory profile is unsupported,
1628                                 or memory profile for the image is not required.
1629   @return EFI_OUT_OF_RESOURCES  No enough resource for this register.
1630 
1631 **/
1632 EFI_STATUS
1633 EFIAPI
ProfileProtocolRegisterImage(IN EDKII_MEMORY_PROFILE_PROTOCOL * This,IN EFI_DEVICE_PATH_PROTOCOL * FilePath,IN PHYSICAL_ADDRESS ImageBase,IN UINT64 ImageSize,IN EFI_FV_FILETYPE FileType)1634 ProfileProtocolRegisterImage (
1635   IN EDKII_MEMORY_PROFILE_PROTOCOL  *This,
1636   IN EFI_DEVICE_PATH_PROTOCOL       *FilePath,
1637   IN PHYSICAL_ADDRESS               ImageBase,
1638   IN UINT64                         ImageSize,
1639   IN EFI_FV_FILETYPE                FileType
1640   )
1641 {
1642   EFI_STATUS                        Status;
1643   LOADED_IMAGE_PRIVATE_DATA         DriverEntry;
1644   VOID                              *EntryPointInImage;
1645 
1646   ZeroMem (&DriverEntry, sizeof (DriverEntry));
1647   DriverEntry.Info.FilePath = FilePath;
1648   DriverEntry.ImageContext.ImageAddress = ImageBase;
1649   DriverEntry.ImageContext.ImageSize = ImageSize;
1650   Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);
1651   ASSERT_EFI_ERROR (Status);
1652   DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
1653   DriverEntry.ImageContext.ImageType = InternalPeCoffGetSubsystem ((VOID *) (UINTN) ImageBase);
1654 
1655   return RegisterMemoryProfileImage (&DriverEntry, FileType);
1656 }
1657 
1658 /**
1659   Unregister image from memory profile.
1660 
1661   @param[in] This               The EDKII_MEMORY_PROFILE_PROTOCOL instance.
1662   @param[in] FilePath           File path of the image.
1663   @param[in] ImageBase          Image base address.
1664   @param[in] ImageSize          Image size.
1665 
1666   @return EFI_SUCCESS           Unregister successfully.
1667   @return EFI_UNSUPPORTED       Memory profile is unsupported,
1668                                 or memory profile for the image is not required.
1669   @return EFI_NOT_FOUND         The image is not found.
1670 
1671 **/
1672 EFI_STATUS
1673 EFIAPI
ProfileProtocolUnregisterImage(IN EDKII_MEMORY_PROFILE_PROTOCOL * This,IN EFI_DEVICE_PATH_PROTOCOL * FilePath,IN PHYSICAL_ADDRESS ImageBase,IN UINT64 ImageSize)1674 ProfileProtocolUnregisterImage (
1675   IN EDKII_MEMORY_PROFILE_PROTOCOL  *This,
1676   IN EFI_DEVICE_PATH_PROTOCOL       *FilePath,
1677   IN PHYSICAL_ADDRESS               ImageBase,
1678   IN UINT64                         ImageSize
1679   )
1680 {
1681   EFI_STATUS                        Status;
1682   LOADED_IMAGE_PRIVATE_DATA         DriverEntry;
1683   VOID                              *EntryPointInImage;
1684 
1685   ZeroMem (&DriverEntry, sizeof (DriverEntry));
1686   DriverEntry.Info.FilePath = FilePath;
1687   DriverEntry.ImageContext.ImageAddress = ImageBase;
1688   DriverEntry.ImageContext.ImageSize = ImageSize;
1689   Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);
1690   ASSERT_EFI_ERROR (Status);
1691   DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
1692 
1693   return UnregisterMemoryProfileImage (&DriverEntry);
1694 }
1695 
1696 /**
1697   Get memory profile recording state.
1698 
1699   @param[in]  This              The EDKII_MEMORY_PROFILE_PROTOCOL instance.
1700   @param[out] RecordingState    Recording state.
1701 
1702   @return EFI_SUCCESS           Memory profile recording state is returned.
1703   @return EFI_UNSUPPORTED       Memory profile is unsupported.
1704   @return EFI_INVALID_PARAMETER RecordingState is NULL.
1705 
1706 **/
1707 EFI_STATUS
1708 EFIAPI
ProfileProtocolGetRecordingState(IN EDKII_MEMORY_PROFILE_PROTOCOL * This,OUT BOOLEAN * RecordingState)1709 ProfileProtocolGetRecordingState (
1710   IN EDKII_MEMORY_PROFILE_PROTOCOL      *This,
1711   OUT BOOLEAN                           *RecordingState
1712   )
1713 {
1714   MEMORY_PROFILE_CONTEXT_DATA       *ContextData;
1715 
1716   ContextData = GetMemoryProfileContext ();
1717   if (ContextData == NULL) {
1718     return EFI_UNSUPPORTED;
1719   }
1720 
1721   if (RecordingState == NULL) {
1722     return EFI_INVALID_PARAMETER;
1723   }
1724   *RecordingState = mMemoryProfileRecordingEnable;
1725   return EFI_SUCCESS;
1726 }
1727 
1728 /**
1729   Set memory profile recording state.
1730 
1731   @param[in] This               The EDKII_MEMORY_PROFILE_PROTOCOL instance.
1732   @param[in] RecordingState     Recording state.
1733 
1734   @return EFI_SUCCESS           Set memory profile recording state successfully.
1735   @return EFI_UNSUPPORTED       Memory profile is unsupported.
1736 
1737 **/
1738 EFI_STATUS
1739 EFIAPI
ProfileProtocolSetRecordingState(IN EDKII_MEMORY_PROFILE_PROTOCOL * This,IN BOOLEAN RecordingState)1740 ProfileProtocolSetRecordingState (
1741   IN EDKII_MEMORY_PROFILE_PROTOCOL      *This,
1742   IN BOOLEAN                            RecordingState
1743   )
1744 {
1745   MEMORY_PROFILE_CONTEXT_DATA       *ContextData;
1746 
1747   ContextData = GetMemoryProfileContext ();
1748   if (ContextData == NULL) {
1749     return EFI_UNSUPPORTED;
1750   }
1751 
1752   mMemoryProfileRecordingEnable = RecordingState;
1753   return EFI_SUCCESS;
1754 }
1755 
1756 /**
1757   Record memory profile of multilevel caller.
1758 
1759   @param[in] This               The EDKII_MEMORY_PROFILE_PROTOCOL instance.
1760   @param[in] CallerAddress      Address of caller.
1761   @param[in] Action             Memory profile action.
1762   @param[in] MemoryType         Memory type.
1763                                 EfiMaxMemoryType means the MemoryType is unknown.
1764   @param[in] Buffer             Buffer address.
1765   @param[in] Size               Buffer size.
1766   @param[in] ActionString       String for memory profile action.
1767                                 Only needed for user defined allocate action.
1768 
1769   @return EFI_SUCCESS           Memory profile is updated.
1770   @return EFI_UNSUPPORTED       Memory profile is unsupported,
1771                                 or memory profile for the image is not required,
1772                                 or memory profile for the memory type is not required.
1773   @return EFI_ACCESS_DENIED     It is during memory profile data getting.
1774   @return EFI_ABORTED           Memory profile recording is not enabled.
1775   @return EFI_OUT_OF_RESOURCES  No enough resource to update memory profile for allocate action.
1776   @return EFI_NOT_FOUND         No matched allocate info found for free action.
1777 
1778 **/
1779 EFI_STATUS
1780 EFIAPI
ProfileProtocolRecord(IN EDKII_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)1781 ProfileProtocolRecord (
1782   IN EDKII_MEMORY_PROFILE_PROTOCOL      *This,
1783   IN PHYSICAL_ADDRESS                   CallerAddress,
1784   IN MEMORY_PROFILE_ACTION              Action,
1785   IN EFI_MEMORY_TYPE                    MemoryType,
1786   IN VOID                               *Buffer,
1787   IN UINTN                              Size,
1788   IN CHAR8                              *ActionString OPTIONAL
1789   )
1790 {
1791   return CoreUpdateProfile (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
1792 }
1793 
1794 ////////////////////
1795