]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c
MdeModulePkg: Extend memory profile definitions for memory leak detection
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Mem / MemoryProfileRecord.c
CommitLineData
84edd20b
SZ
1/** @file\r
2 Support routines for UEFI memory profile.\r
3\r
925f0d1a 4 Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>\r
84edd20b
SZ
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php.\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "DxeMain.h"\r
db9b00f1 16#include "Imem.h"\r
84edd20b
SZ
17\r
18#define IS_UEFI_MEMORY_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT0) != 0)\r
19\r
20typedef struct {\r
21 UINT32 Signature;\r
22 MEMORY_PROFILE_CONTEXT Context;\r
23 LIST_ENTRY *DriverInfoList;\r
24} MEMORY_PROFILE_CONTEXT_DATA;\r
25\r
26typedef struct {\r
27 UINT32 Signature;\r
28 MEMORY_PROFILE_DRIVER_INFO DriverInfo;\r
29 LIST_ENTRY *AllocInfoList;\r
30 LIST_ENTRY Link;\r
31} MEMORY_PROFILE_DRIVER_INFO_DATA;\r
32\r
33typedef struct {\r
34 UINT32 Signature;\r
35 MEMORY_PROFILE_ALLOC_INFO AllocInfo;\r
36 LIST_ENTRY Link;\r
37} MEMORY_PROFILE_ALLOC_INFO_DATA;\r
38\r
39\r
40GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mImageQueue = INITIALIZE_LIST_HEAD_VARIABLE (mImageQueue);\r
41GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA mMemoryProfileContext = {\r
42 MEMORY_PROFILE_CONTEXT_SIGNATURE,\r
43 {\r
44 {\r
45 MEMORY_PROFILE_CONTEXT_SIGNATURE,\r
46 sizeof (MEMORY_PROFILE_CONTEXT),\r
47 MEMORY_PROFILE_CONTEXT_REVISION\r
48 },\r
49 0,\r
50 0,\r
51 {0},\r
52 {0},\r
53 0,\r
54 0,\r
55 0\r
56 },\r
57 &mImageQueue,\r
58};\r
59GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA *mMemoryProfileContextPtr = NULL;\r
60\r
61BOOLEAN mMemoryProfileRecordingStatus = FALSE;\r
62\r
63/**\r
64 Get memory profile data.\r
65\r
66 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.\r
67 @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.\r
68 On return, points to the size of the data returned in ProfileBuffer.\r
69 @param[out] ProfileBuffer Profile buffer.\r
70 \r
71 @return EFI_SUCCESS Get the memory profile data successfully.\r
72 @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data. \r
73 ProfileSize is updated with the size required.\r
74\r
75**/\r
76EFI_STATUS\r
77EFIAPI\r
78ProfileProtocolGetData (\r
79 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,\r
80 IN OUT UINT64 *ProfileSize,\r
81 OUT VOID *ProfileBuffer\r
82 );\r
83\r
84/**\r
85 Register image to memory profile.\r
86\r
87 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.\r
88 @param[in] FilePath File path of the image.\r
89 @param[in] ImageBase Image base address.\r
90 @param[in] ImageSize Image size.\r
91 @param[in] FileType File type of the image.\r
92\r
93 @return EFI_SUCCESS Register success.\r
94 @return EFI_OUT_OF_RESOURCE No enough resource for this register.\r
95\r
96**/\r
97EFI_STATUS\r
98EFIAPI\r
99ProfileProtocolRegisterImage (\r
100 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,\r
101 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
102 IN PHYSICAL_ADDRESS ImageBase,\r
103 IN UINT64 ImageSize,\r
104 IN EFI_FV_FILETYPE FileType\r
105 );\r
106\r
107/**\r
108 Unregister image from memory profile.\r
109\r
110 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.\r
111 @param[in] FilePath File path of the image.\r
112 @param[in] ImageBase Image base address.\r
113 @param[in] ImageSize Image size.\r
114\r
115 @return EFI_SUCCESS Unregister success.\r
116 @return EFI_NOT_FOUND The image is not found.\r
117\r
118**/\r
119EFI_STATUS\r
120EFIAPI\r
121ProfileProtocolUnregisterImage (\r
122 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,\r
123 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
124 IN PHYSICAL_ADDRESS ImageBase,\r
125 IN UINT64 ImageSize\r
126 );\r
127\r
128EDKII_MEMORY_PROFILE_PROTOCOL mProfileProtocol = {\r
129 ProfileProtocolGetData,\r
130 ProfileProtocolRegisterImage,\r
131 ProfileProtocolUnregisterImage\r
132};\r
133\r
134/**\r
135 Return memory profile context.\r
136\r
137 @return Memory profile context.\r
138\r
139**/\r
140MEMORY_PROFILE_CONTEXT_DATA *\r
141GetMemoryProfileContext (\r
142 VOID\r
143 )\r
144{\r
145 return mMemoryProfileContextPtr;\r
146}\r
147\r
148/**\r
149 Retrieves the magic value from the PE/COFF header.\r
150\r
151 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.\r
152\r
153 @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32\r
154 @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+\r
155\r
156**/\r
157UINT16\r
158InternalPeCoffGetPeHeaderMagicValue (\r
159 IN EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr\r
160 )\r
161{\r
162 //\r
163 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value\r
164 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the\r
165 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
166 // then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
167 //\r
168 if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
169 return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
170 }\r
171 //\r
172 // Return the magic value from the PC/COFF Optional Header\r
173 //\r
174 return Hdr.Pe32->OptionalHeader.Magic;\r
175}\r
176\r
177/**\r
178 Retrieves and returns the Subsystem of a PE/COFF image that has been loaded into system memory.\r
179 If Pe32Data is NULL, then ASSERT().\r
180\r
181 @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.\r
182\r
183 @return The Subsystem of the PE/COFF image.\r
184\r
185**/\r
186UINT16\r
187InternalPeCoffGetSubsystem (\r
188 IN VOID *Pe32Data\r
189 )\r
190{\r
191 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
192 EFI_IMAGE_DOS_HEADER *DosHdr;\r
193 UINT16 Magic;\r
194\r
195 ASSERT (Pe32Data != NULL);\r
196\r
197 DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;\r
198 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
199 //\r
200 // DOS image header is present, so read the PE header after the DOS image header.\r
201 //\r
202 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
203 } else {\r
204 //\r
205 // DOS image header is not present, so PE header is at the image base.\r
206 //\r
207 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;\r
208 }\r
209\r
210 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
211 return Hdr.Te->Subsystem;\r
212 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
213 Magic = InternalPeCoffGetPeHeaderMagicValue (Hdr);\r
214 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
215 return Hdr.Pe32->OptionalHeader.Subsystem;\r
216 } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
217 return Hdr.Pe32Plus->OptionalHeader.Subsystem;\r
218 }\r
219 }\r
220\r
221 return 0x0000;\r
222}\r
223\r
224/**\r
225 Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded\r
226 into system memory with the PE/COFF Loader Library functions.\r
227\r
228 Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry\r
229 point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then\r
230 return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS.\r
231 If Pe32Data is NULL, then ASSERT().\r
232 If EntryPoint is NULL, then ASSERT().\r
233\r
234 @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.\r
235 @param EntryPoint The pointer to entry point to the PE/COFF image to return.\r
236\r
237 @retval RETURN_SUCCESS EntryPoint was returned.\r
238 @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image.\r
239\r
240**/\r
241RETURN_STATUS\r
242InternalPeCoffGetEntryPoint (\r
243 IN VOID *Pe32Data,\r
244 OUT VOID **EntryPoint\r
245 )\r
246{\r
247 EFI_IMAGE_DOS_HEADER *DosHdr;\r
248 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
249\r
250 ASSERT (Pe32Data != NULL);\r
251 ASSERT (EntryPoint != NULL);\r
252\r
253 DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;\r
254 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
255 //\r
256 // DOS image header is present, so read the PE header after the DOS image header.\r
257 //\r
258 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
259 } else {\r
260 //\r
261 // DOS image header is not present, so PE header is at the image base.\r
262 //\r
263 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;\r
264 }\r
265\r
266 //\r
267 // Calculate the entry point relative to the start of the image.\r
268 // AddressOfEntryPoint is common for PE32 & PE32+\r
269 //\r
270 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
271 *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);\r
272 return RETURN_SUCCESS;\r
273 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
274 *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff));\r
275 return RETURN_SUCCESS;\r
276 }\r
277\r
278 return RETURN_UNSUPPORTED;\r
279}\r
280\r
281/**\r
282 Build driver info.\r
283\r
284 @param ContextData Memory profile context.\r
285 @param FileName File name of the image.\r
286 @param ImageBase Image base address.\r
287 @param ImageSize Image size.\r
288 @param EntryPoint Entry point of the image.\r
289 @param ImageSubsystem Image subsystem of the image.\r
290 @param FileType File type of the image.\r
291\r
292 @return Pointer to memory profile driver info.\r
293\r
294**/\r
295MEMORY_PROFILE_DRIVER_INFO_DATA *\r
296BuildDriverInfo (\r
297 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,\r
298 IN EFI_GUID *FileName,\r
299 IN PHYSICAL_ADDRESS ImageBase,\r
300 IN UINT64 ImageSize,\r
301 IN PHYSICAL_ADDRESS EntryPoint,\r
302 IN UINT16 ImageSubsystem,\r
303 IN EFI_FV_FILETYPE FileType\r
304 )\r
305{\r
306 EFI_STATUS Status;\r
307 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
308 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
309 VOID *EntryPointInImage;\r
310\r
311 //\r
312 // Use CoreInternalAllocatePool() that will not update profile for this AllocatePool action.\r
313 //\r
314 Status = CoreInternalAllocatePool (\r
315 EfiBootServicesData,\r
316 sizeof (*DriverInfoData) + sizeof (LIST_ENTRY),\r
317 (VOID **) &DriverInfoData\r
318 );\r
319 if (EFI_ERROR (Status)) {\r
320 return NULL;\r
321 }\r
322\r
323 ZeroMem (DriverInfoData, sizeof (*DriverInfoData));\r
324\r
325 DriverInfo = &DriverInfoData->DriverInfo;\r
326 DriverInfoData->Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;\r
327 DriverInfo->Header.Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;\r
328 DriverInfo->Header.Length = sizeof (MEMORY_PROFILE_DRIVER_INFO);\r
329 DriverInfo->Header.Revision = MEMORY_PROFILE_DRIVER_INFO_REVISION;\r
330 if (FileName != NULL) {\r
331 CopyMem (&DriverInfo->FileName, FileName, sizeof (EFI_GUID));\r
332 }\r
333 DriverInfo->ImageBase = ImageBase;\r
334 DriverInfo->ImageSize = ImageSize;\r
335 DriverInfo->EntryPoint = EntryPoint;\r
336 DriverInfo->ImageSubsystem = ImageSubsystem;\r
337 if ((EntryPoint != 0) && ((EntryPoint < ImageBase) || (EntryPoint >= (ImageBase + ImageSize)))) {\r
338 //\r
339 // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.\r
340 // So patch ImageBuffer here to align the EntryPoint.\r
341 //\r
342 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);\r
343 ASSERT_EFI_ERROR (Status);\r
344 DriverInfo->ImageBase = ImageBase + EntryPoint - (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;\r
345 }\r
346 DriverInfo->FileType = FileType;\r
347 DriverInfoData->AllocInfoList = (LIST_ENTRY *) (DriverInfoData + 1);\r
348 InitializeListHead (DriverInfoData->AllocInfoList);\r
349 DriverInfo->CurrentUsage = 0;\r
350 DriverInfo->PeakUsage = 0;\r
351 DriverInfo->AllocRecordCount = 0;\r
352\r
353 InsertTailList (ContextData->DriverInfoList, &DriverInfoData->Link);\r
354 ContextData->Context.ImageCount ++;\r
355 ContextData->Context.TotalImageSize += DriverInfo->ImageSize;\r
356\r
357 return DriverInfoData;\r
358}\r
359\r
360/**\r
361 Register DXE Core to memory profile.\r
362\r
363 @param HobStart The start address of the HOB.\r
364 @param ContextData Memory profile context.\r
365\r
366 @retval TRUE Register success.\r
367 @retval FALSE Register fail.\r
368\r
369**/\r
370BOOLEAN\r
371RegisterDxeCore (\r
372 IN VOID *HobStart,\r
373 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData\r
374 )\r
375{\r
376 EFI_PEI_HOB_POINTERS DxeCoreHob;\r
377 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
378 PHYSICAL_ADDRESS ImageBase;\r
379\r
380 ASSERT (ContextData != NULL);\r
381\r
382 //\r
383 // Searching for image hob\r
384 //\r
385 DxeCoreHob.Raw = HobStart;\r
386 while ((DxeCoreHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, DxeCoreHob.Raw)) != NULL) {\r
387 if (CompareGuid (&DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {\r
388 //\r
389 // Find Dxe Core HOB\r
390 //\r
391 break;\r
392 }\r
393 DxeCoreHob.Raw = GET_NEXT_HOB (DxeCoreHob);\r
394 }\r
395 ASSERT (DxeCoreHob.Raw != NULL);\r
396\r
397 ImageBase = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress;\r
398 DriverInfoData = BuildDriverInfo (\r
399 ContextData,\r
400 &DxeCoreHob.MemoryAllocationModule->ModuleName,\r
401 ImageBase,\r
402 DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength,\r
403 DxeCoreHob.MemoryAllocationModule->EntryPoint,\r
404 InternalPeCoffGetSubsystem ((VOID *) (UINTN) ImageBase),\r
405 EFI_FV_FILETYPE_DXE_CORE\r
406 );\r
407 if (DriverInfoData == NULL) {\r
408 return FALSE;\r
409 }\r
410\r
411 return TRUE;\r
412}\r
413\r
414/**\r
415 Initialize memory profile.\r
416\r
417 @param HobStart The start address of the HOB.\r
418\r
419**/\r
420VOID\r
421MemoryProfileInit (\r
422 IN VOID *HobStart\r
423 )\r
424{\r
425 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
426\r
427 if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {\r
428 return;\r
429 }\r
430\r
431 ContextData = GetMemoryProfileContext ();\r
432 if (ContextData != NULL) {\r
433 return;\r
434 }\r
435\r
436 mMemoryProfileRecordingStatus = TRUE;\r
437 mMemoryProfileContextPtr = &mMemoryProfileContext;\r
438\r
439 RegisterDxeCore (HobStart, &mMemoryProfileContext);\r
440\r
441 DEBUG ((EFI_D_INFO, "MemoryProfileInit MemoryProfileContext - 0x%x\n", &mMemoryProfileContext));\r
442}\r
443\r
444/**\r
445 Install memory profile protocol.\r
446\r
447**/\r
448VOID\r
449MemoryProfileInstallProtocol (\r
450 VOID\r
451 )\r
452{\r
453 EFI_HANDLE Handle;\r
454 EFI_STATUS Status;\r
455\r
456 if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {\r
457 return;\r
458 }\r
459\r
460 Handle = NULL;\r
461 Status = CoreInstallMultipleProtocolInterfaces (\r
462 &Handle,\r
463 &gEdkiiMemoryProfileGuid,\r
464 &mProfileProtocol,\r
465 NULL\r
466 );\r
467 ASSERT_EFI_ERROR (Status);\r
468}\r
469\r
470/**\r
471 Get the GUID file name from the file path.\r
472\r
473 @param FilePath File path.\r
474\r
475 @return The GUID file name from the file path.\r
476\r
477**/\r
478EFI_GUID *\r
479GetFileNameFromFilePath (\r
480 IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
481 )\r
482{\r
483 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *ThisFilePath;\r
484 EFI_GUID *FileName;\r
485\r
486 FileName = NULL;\r
092b852a
SZ
487 if (FilePath != NULL) {\r
488 ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) FilePath;\r
489 while (!IsDevicePathEnd (ThisFilePath)) {\r
490 FileName = EfiGetNameGuidFromFwVolDevicePathNode (ThisFilePath);\r
491 if (FileName != NULL) {\r
492 break;\r
493 }\r
494 ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) NextDevicePathNode (ThisFilePath);\r
84edd20b 495 }\r
84edd20b
SZ
496 }\r
497\r
498 return FileName;\r
499}\r
500\r
501/**\r
502 Register image to memory profile.\r
503\r
504 @param DriverEntry Image info.\r
505 @param FileType Image file type.\r
506\r
507 @retval TRUE Register success.\r
508 @retval FALSE Register fail.\r
509\r
510**/\r
511BOOLEAN\r
512RegisterMemoryProfileImage (\r
513 IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry,\r
514 IN EFI_FV_FILETYPE FileType\r
515 )\r
516{\r
517 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
518 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
519\r
520 if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {\r
521 return FALSE;\r
522 }\r
523\r
524 ContextData = GetMemoryProfileContext ();\r
525 if (ContextData == NULL) {\r
526 return FALSE;\r
527 }\r
528\r
529 DriverInfoData = BuildDriverInfo (\r
530 ContextData,\r
531 GetFileNameFromFilePath (DriverEntry->Info.FilePath),\r
532 DriverEntry->ImageContext.ImageAddress,\r
533 DriverEntry->ImageContext.ImageSize,\r
534 DriverEntry->ImageContext.EntryPoint,\r
535 DriverEntry->ImageContext.ImageType,\r
536 FileType\r
537 );\r
538 if (DriverInfoData == NULL) {\r
539 return FALSE;\r
540 }\r
541\r
542 return TRUE;\r
543}\r
544\r
545/**\r
546 Search image from memory profile.\r
547\r
548 @param ContextData Memory profile context.\r
549 @param FileName Image file name.\r
550 @param Address Image Address.\r
551\r
552 @return Pointer to memory profile driver info.\r
553\r
554**/\r
555MEMORY_PROFILE_DRIVER_INFO_DATA *\r
556GetMemoryProfileDriverInfoByFileNameAndAddress (\r
557 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,\r
558 IN EFI_GUID *FileName,\r
559 IN PHYSICAL_ADDRESS Address\r
560 )\r
561{\r
562 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
563 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
564 LIST_ENTRY *DriverLink;\r
565 LIST_ENTRY *DriverInfoList;\r
566\r
567 DriverInfoList = ContextData->DriverInfoList;\r
568\r
569 for (DriverLink = DriverInfoList->ForwardLink;\r
570 DriverLink != DriverInfoList;\r
571 DriverLink = DriverLink->ForwardLink) {\r
572 DriverInfoData = CR (\r
573 DriverLink,\r
574 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
575 Link,\r
576 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
577 );\r
578 DriverInfo = &DriverInfoData->DriverInfo;\r
579 if ((CompareGuid (&DriverInfo->FileName, FileName)) &&\r
580 (Address >= DriverInfo->ImageBase) &&\r
581 (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {\r
582 return DriverInfoData;\r
583 }\r
584 }\r
585\r
586 return NULL;\r
587}\r
588\r
589/**\r
590 Search dummy image from memory profile.\r
591\r
592 @param ContextData Memory profile context.\r
593\r
594 @return Pointer to memory profile driver info.\r
595\r
596**/\r
597MEMORY_PROFILE_DRIVER_INFO_DATA *\r
598FindDummyImage (\r
599 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData\r
600 )\r
601{\r
602 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
603 LIST_ENTRY *DriverLink;\r
604 LIST_ENTRY *DriverInfoList;\r
605\r
606 DriverInfoList = ContextData->DriverInfoList;\r
607\r
608 for (DriverLink = DriverInfoList->ForwardLink;\r
609 DriverLink != DriverInfoList;\r
610 DriverLink = DriverLink->ForwardLink) {\r
611 DriverInfoData = CR (\r
612 DriverLink,\r
613 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
614 Link,\r
615 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
616 );\r
617 if (CompareGuid (&gZeroGuid, &DriverInfoData->DriverInfo.FileName)) {\r
618 return DriverInfoData;\r
619 }\r
620 }\r
621\r
622 return BuildDriverInfo (ContextData, &gZeroGuid, 0, 0, 0, 0, 0);\r
623}\r
624\r
625/**\r
626 Search image from memory profile.\r
627 It will return image, if (Address >= ImageBuffer) AND (Address < ImageBuffer + ImageSize)\r
628\r
629 @param ContextData Memory profile context.\r
630 @param Address Image or Function address.\r
631\r
632 @return Pointer to memory profile driver info.\r
633\r
634**/\r
635MEMORY_PROFILE_DRIVER_INFO_DATA *\r
636GetMemoryProfileDriverInfoFromAddress (\r
637 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,\r
638 IN PHYSICAL_ADDRESS Address\r
639 )\r
640{\r
641 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
642 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
643 LIST_ENTRY *DriverLink;\r
644 LIST_ENTRY *DriverInfoList;\r
645\r
646 DriverInfoList = ContextData->DriverInfoList;\r
647\r
648 for (DriverLink = DriverInfoList->ForwardLink;\r
649 DriverLink != DriverInfoList;\r
650 DriverLink = DriverLink->ForwardLink) {\r
651 DriverInfoData = CR (\r
652 DriverLink,\r
653 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
654 Link,\r
655 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
656 );\r
657 DriverInfo = &DriverInfoData->DriverInfo;\r
658 if ((Address >= DriverInfo->ImageBase) &&\r
659 (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {\r
660 return DriverInfoData;\r
661 }\r
662 }\r
663\r
664 //\r
665 // Should never come here.\r
666 //\r
667 return FindDummyImage (ContextData);\r
668}\r
669\r
670/**\r
671 Unregister image from memory profile.\r
672\r
673 @param DriverEntry Image info.\r
674\r
675 @retval TRUE Unregister success.\r
676 @retval FALSE Unregister fail.\r
677\r
678**/\r
679BOOLEAN\r
680UnregisterMemoryProfileImage (\r
681 IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry\r
682 )\r
683{\r
684 EFI_STATUS Status;\r
685 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
686 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
687 EFI_GUID *FileName;\r
688 PHYSICAL_ADDRESS ImageAddress;\r
689 VOID *EntryPointInImage;\r
690\r
691 if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {\r
692 return FALSE;\r
693 }\r
694\r
695 ContextData = GetMemoryProfileContext ();\r
696 if (ContextData == NULL) {\r
697 return FALSE;\r
698 }\r
699\r
700 DriverInfoData = NULL;\r
701 FileName = GetFileNameFromFilePath (DriverEntry->Info.FilePath);\r
702 ImageAddress = DriverEntry->ImageContext.ImageAddress;\r
703 if ((DriverEntry->ImageContext.EntryPoint < ImageAddress) || (DriverEntry->ImageContext.EntryPoint >= (ImageAddress + DriverEntry->ImageContext.ImageSize))) {\r
704 //\r
705 // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.\r
706 // So patch ImageAddress here to align the EntryPoint.\r
707 //\r
708 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageAddress, &EntryPointInImage);\r
709 ASSERT_EFI_ERROR (Status);\r
710 ImageAddress = ImageAddress + (UINTN) DriverEntry->ImageContext.EntryPoint - (UINTN) EntryPointInImage;\r
711 }\r
712 if (FileName != NULL) {\r
713 DriverInfoData = GetMemoryProfileDriverInfoByFileNameAndAddress (ContextData, FileName, ImageAddress);\r
714 }\r
715 if (DriverInfoData == NULL) {\r
716 DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, ImageAddress);\r
717 }\r
718 if (DriverInfoData == NULL) {\r
719 return FALSE;\r
720 }\r
721\r
722 ContextData->Context.TotalImageSize -= DriverInfoData->DriverInfo.ImageSize;\r
723\r
724 DriverInfoData->DriverInfo.ImageBase = 0;\r
725 DriverInfoData->DriverInfo.ImageSize = 0;\r
726\r
727 if (DriverInfoData->DriverInfo.PeakUsage == 0) {\r
728 ContextData->Context.ImageCount --;\r
729 RemoveEntryList (&DriverInfoData->Link);\r
730 //\r
731 // Use CoreInternalFreePool() that will not update profile for this FreePool action.\r
732 //\r
925f0d1a 733 CoreInternalFreePool (DriverInfoData, NULL);\r
84edd20b
SZ
734 }\r
735\r
736 return TRUE;\r
737}\r
738\r
739/**\r
740 Return if this memory type needs to be recorded into memory profile.\r
db9b00f1 741 If BIOS memory type (0 ~ EfiMaxMemoryType - 1), it checks bit (1 << MemoryType).\r
84edd20b 742 If OS memory type (0x80000000 ~ 0xFFFFFFFF), it checks bit63 - 0x8000000000000000.\r
db9b00f1 743 If OEM memory type (0x70000000 ~ 0x7FFFFFFF), it checks bit62 - 0x4000000000000000.\r
84edd20b
SZ
744\r
745 @param MemoryType Memory type.\r
746\r
747 @retval TRUE This memory type need to be recorded.\r
748 @retval FALSE This memory type need not to be recorded.\r
749\r
750**/\r
751BOOLEAN\r
752CoreNeedRecordProfile (\r
753 IN EFI_MEMORY_TYPE MemoryType\r
754 )\r
755{\r
756 UINT64 TestBit;\r
757\r
db9b00f1 758 if ((UINT32) MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {\r
84edd20b 759 TestBit = BIT63;\r
db9b00f1
SZ
760 } else if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {\r
761 TestBit = BIT62;\r
84edd20b
SZ
762 } else {\r
763 TestBit = LShiftU64 (1, MemoryType);\r
764 }\r
765\r
766 if ((PcdGet64 (PcdMemoryProfileMemoryType) & TestBit) != 0) {\r
767 return TRUE;\r
768 } else {\r
769 return FALSE;\r
770 }\r
771}\r
772\r
773/**\r
774 Convert EFI memory type to profile memory index. The rule is:\r
db9b00f1 775 If BIOS memory type (0 ~ EfiMaxMemoryType - 1), ProfileMemoryIndex = MemoryType.\r
84edd20b 776 If OS memory type (0x80000000 ~ 0xFFFFFFFF), ProfileMemoryIndex = EfiMaxMemoryType.\r
db9b00f1 777 If OEM memory type (0x70000000 ~ 0x7FFFFFFF), ProfileMemoryIndex = EfiMaxMemoryType + 1.\r
84edd20b
SZ
778\r
779 @param MemoryType Memory type.\r
780\r
97e64288 781 @return Profile memory index.\r
84edd20b
SZ
782\r
783**/\r
97e64288 784UINTN\r
84edd20b
SZ
785GetProfileMemoryIndex (\r
786 IN EFI_MEMORY_TYPE MemoryType\r
787 )\r
788{\r
db9b00f1 789 if ((UINT32) MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {\r
84edd20b 790 return EfiMaxMemoryType;\r
db9b00f1
SZ
791 } else if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {\r
792 return EfiMaxMemoryType + 1;\r
84edd20b
SZ
793 } else {\r
794 return MemoryType;\r
795 }\r
796}\r
797\r
798/**\r
799 Update memory profile Allocate information.\r
800\r
801 @param CallerAddress Address of caller who call Allocate.\r
802 @param Action This Allocate action.\r
803 @param MemoryType Memory type.\r
804 @param Size Buffer size.\r
805 @param Buffer Buffer address.\r
806\r
807 @retval TRUE Profile udpate success.\r
808 @retval FALSE Profile update fail.\r
809\r
810**/\r
811BOOLEAN\r
812CoreUpdateProfileAllocate (\r
813 IN PHYSICAL_ADDRESS CallerAddress,\r
814 IN MEMORY_PROFILE_ACTION Action,\r
815 IN EFI_MEMORY_TYPE MemoryType,\r
816 IN UINTN Size,\r
817 IN VOID *Buffer\r
818 )\r
819{\r
820 EFI_STATUS Status;\r
821 MEMORY_PROFILE_CONTEXT *Context;\r
822 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
823 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
824 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
825 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
826 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
97e64288 827 UINTN ProfileMemoryIndex;\r
84edd20b 828\r
f4420027
SZ
829 AllocInfoData = NULL;\r
830\r
84edd20b
SZ
831 ContextData = GetMemoryProfileContext ();\r
832 if (ContextData == NULL) {\r
833 return FALSE;\r
834 }\r
835\r
836 DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);\r
837 ASSERT (DriverInfoData != NULL);\r
838\r
839 //\r
840 // Use CoreInternalAllocatePool() that will not update profile for this AllocatePool action.\r
841 //\r
842 Status = CoreInternalAllocatePool (\r
843 EfiBootServicesData,\r
844 sizeof (*AllocInfoData),\r
845 (VOID **) &AllocInfoData\r
846 );\r
847 if (EFI_ERROR (Status)) {\r
848 return FALSE;\r
849 }\r
80fbf586 850 ASSERT (AllocInfoData != NULL);\r
84edd20b
SZ
851 AllocInfo = &AllocInfoData->AllocInfo;\r
852 AllocInfoData->Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;\r
853 AllocInfo->Header.Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;\r
854 AllocInfo->Header.Length = sizeof (MEMORY_PROFILE_ALLOC_INFO);\r
855 AllocInfo->Header.Revision = MEMORY_PROFILE_ALLOC_INFO_REVISION;\r
856 AllocInfo->CallerAddress = CallerAddress;\r
857 AllocInfo->SequenceId = ContextData->Context.SequenceCount;\r
858 AllocInfo->Action = Action;\r
859 AllocInfo->MemoryType = MemoryType;\r
860 AllocInfo->Buffer = (PHYSICAL_ADDRESS) (UINTN) Buffer;\r
861 AllocInfo->Size = Size;\r
862\r
863 InsertTailList (DriverInfoData->AllocInfoList, &AllocInfoData->Link);\r
864\r
865 ProfileMemoryIndex = GetProfileMemoryIndex (MemoryType);\r
866\r
867 DriverInfo = &DriverInfoData->DriverInfo;\r
868 DriverInfo->CurrentUsage += Size;\r
869 if (DriverInfo->PeakUsage < DriverInfo->CurrentUsage) {\r
870 DriverInfo->PeakUsage = DriverInfo->CurrentUsage;\r
871 }\r
872 DriverInfo->CurrentUsageByType[ProfileMemoryIndex] += Size;\r
873 if (DriverInfo->PeakUsageByType[ProfileMemoryIndex] < DriverInfo->CurrentUsageByType[ProfileMemoryIndex]) {\r
874 DriverInfo->PeakUsageByType[ProfileMemoryIndex] = DriverInfo->CurrentUsageByType[ProfileMemoryIndex];\r
875 }\r
876 DriverInfo->AllocRecordCount ++;\r
877\r
878 Context = &ContextData->Context;\r
879 Context->CurrentTotalUsage += Size;\r
880 if (Context->PeakTotalUsage < Context->CurrentTotalUsage) {\r
881 Context->PeakTotalUsage = Context->CurrentTotalUsage;\r
882 }\r
883 Context->CurrentTotalUsageByType[ProfileMemoryIndex] += Size;\r
884 if (Context->PeakTotalUsageByType[ProfileMemoryIndex] < Context->CurrentTotalUsageByType[ProfileMemoryIndex]) {\r
885 Context->PeakTotalUsageByType[ProfileMemoryIndex] = Context->CurrentTotalUsageByType[ProfileMemoryIndex];\r
886 }\r
887 Context->SequenceCount ++;\r
888\r
889 return TRUE;\r
890}\r
891\r
892/**\r
893 Get memory profile alloc info from memory profile\r
894\r
895 @param DriverInfoData Driver info\r
896 @param Action This Free action\r
897 @param Size Buffer size\r
898 @param Buffer Buffer address\r
899\r
900 @return Pointer to memory profile alloc info.\r
901**/\r
902MEMORY_PROFILE_ALLOC_INFO_DATA *\r
903GetMemoryProfileAllocInfoFromAddress (\r
904 IN MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData,\r
905 IN MEMORY_PROFILE_ACTION Action,\r
906 IN UINTN Size,\r
907 IN VOID *Buffer\r
908 )\r
909{\r
910 LIST_ENTRY *AllocInfoList;\r
911 LIST_ENTRY *AllocLink;\r
912 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
913 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
914\r
915 AllocInfoList = DriverInfoData->AllocInfoList;\r
916\r
917 for (AllocLink = AllocInfoList->ForwardLink;\r
918 AllocLink != AllocInfoList;\r
919 AllocLink = AllocLink->ForwardLink) {\r
920 AllocInfoData = CR (\r
921 AllocLink,\r
922 MEMORY_PROFILE_ALLOC_INFO_DATA,\r
923 Link,\r
924 MEMORY_PROFILE_ALLOC_INFO_SIGNATURE\r
925 );\r
926 AllocInfo = &AllocInfoData->AllocInfo;\r
927 if (AllocInfo->Action != Action) {\r
928 continue;\r
929 }\r
930 switch (Action) {\r
931 case MemoryProfileActionAllocatePages:\r
932 if ((AllocInfo->Buffer <= (PHYSICAL_ADDRESS) (UINTN) Buffer) &&\r
933 ((AllocInfo->Buffer + AllocInfo->Size) >= ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size))) {\r
934 return AllocInfoData;\r
935 }\r
936 break;\r
937 case MemoryProfileActionAllocatePool:\r
938 if (AllocInfo->Buffer == (PHYSICAL_ADDRESS) (UINTN) Buffer) {\r
939 return AllocInfoData;\r
940 }\r
941 break;\r
942 default:\r
943 ASSERT (FALSE);\r
944 break;\r
945 }\r
946 }\r
947\r
948 return NULL;\r
949}\r
950\r
951/**\r
952 Update memory profile Free information.\r
953\r
954 @param CallerAddress Address of caller who call Free.\r
955 @param Action This Free action.\r
956 @param Size Buffer size.\r
957 @param Buffer Buffer address.\r
958\r
959 @retval TRUE Profile udpate success.\r
960 @retval FALSE Profile update fail.\r
961\r
962**/\r
963BOOLEAN\r
964CoreUpdateProfileFree (\r
965 IN PHYSICAL_ADDRESS CallerAddress,\r
966 IN MEMORY_PROFILE_ACTION Action,\r
967 IN UINTN Size,\r
968 IN VOID *Buffer\r
969 )\r
970{\r
971 MEMORY_PROFILE_CONTEXT *Context;\r
972 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
973 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
974 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
975 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
976 LIST_ENTRY *DriverLink;\r
977 LIST_ENTRY *DriverInfoList;\r
978 MEMORY_PROFILE_DRIVER_INFO_DATA *ThisDriverInfoData;\r
979 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
97e64288 980 UINTN ProfileMemoryIndex;\r
84edd20b
SZ
981\r
982 ContextData = GetMemoryProfileContext ();\r
983 if (ContextData == NULL) {\r
984 return FALSE;\r
985 }\r
986\r
987 DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);\r
988 ASSERT (DriverInfoData != NULL);\r
989\r
990 switch (Action) {\r
991 case MemoryProfileActionFreePages:\r
992 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);\r
993 break;\r
994 case MemoryProfileActionFreePool:\r
995 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);\r
996 break;\r
997 default:\r
998 ASSERT (FALSE);\r
999 AllocInfoData = NULL;\r
1000 break;\r
1001 }\r
1002 if (AllocInfoData == NULL) {\r
1003 //\r
1004 // Legal case, because driver A might free memory allocated by driver B, by some protocol.\r
1005 //\r
1006 DriverInfoList = ContextData->DriverInfoList;\r
1007\r
1008 for (DriverLink = DriverInfoList->ForwardLink;\r
1009 DriverLink != DriverInfoList;\r
1010 DriverLink = DriverLink->ForwardLink) {\r
1011 ThisDriverInfoData = CR (\r
1012 DriverLink,\r
1013 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
1014 Link,\r
1015 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
1016 );\r
1017 switch (Action) {\r
1018 case MemoryProfileActionFreePages:\r
1019 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);\r
1020 break;\r
1021 case MemoryProfileActionFreePool:\r
1022 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);\r
1023 break;\r
1024 default:\r
1025 ASSERT (FALSE);\r
1026 AllocInfoData = NULL;\r
1027 break;\r
1028 }\r
1029 if (AllocInfoData != NULL) {\r
1030 DriverInfoData = ThisDriverInfoData;\r
1031 break;\r
1032 }\r
1033 }\r
1034\r
1035 if (AllocInfoData == NULL) {\r
1036 //\r
1037 // No matched allocate operation is found for this free operation.\r
1038 // It is because the specified memory type allocate operation has been\r
1039 // filtered by CoreNeedRecordProfile(), but free operations have no\r
1040 // memory type information, they can not be filtered by CoreNeedRecordProfile().\r
1041 // Then, they will be filtered here.\r
1042 //\r
1043 return FALSE;\r
1044 }\r
1045 }\r
1046\r
1047 Context = &ContextData->Context;\r
1048 DriverInfo = &DriverInfoData->DriverInfo;\r
1049 AllocInfo = &AllocInfoData->AllocInfo;\r
1050\r
1051 ProfileMemoryIndex = GetProfileMemoryIndex (AllocInfo->MemoryType);\r
1052\r
1053 Context->CurrentTotalUsage -= AllocInfo->Size;\r
1054 Context->CurrentTotalUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;\r
1055\r
1056 DriverInfo->CurrentUsage -= AllocInfo->Size;\r
1057 DriverInfo->CurrentUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;\r
1058 DriverInfo->AllocRecordCount --;\r
1059\r
1060 RemoveEntryList (&AllocInfoData->Link);\r
1061\r
1062 if (Action == MemoryProfileActionFreePages) {\r
1063 if (AllocInfo->Buffer != (PHYSICAL_ADDRESS) (UINTN) Buffer) {\r
1064 CoreUpdateProfileAllocate (\r
1065 AllocInfo->CallerAddress,\r
1066 MemoryProfileActionAllocatePages,\r
1067 AllocInfo->MemoryType,\r
1068 (UINTN) ((PHYSICAL_ADDRESS) (UINTN) Buffer - AllocInfo->Buffer),\r
1069 (VOID *) (UINTN) AllocInfo->Buffer\r
1070 );\r
1071 }\r
1072 if (AllocInfo->Buffer + AllocInfo->Size != ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)) {\r
1073 CoreUpdateProfileAllocate (\r
1074 AllocInfo->CallerAddress,\r
1075 MemoryProfileActionAllocatePages,\r
1076 AllocInfo->MemoryType,\r
1077 (UINTN) ((AllocInfo->Buffer + AllocInfo->Size) - ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)),\r
1078 (VOID *) ((UINTN) Buffer + Size)\r
1079 );\r
1080 }\r
1081 }\r
1082\r
1083 //\r
1084 // Use CoreInternalFreePool() that will not update profile for this FreePool action.\r
1085 //\r
925f0d1a 1086 CoreInternalFreePool (AllocInfoData, NULL);\r
84edd20b
SZ
1087\r
1088 return TRUE;\r
1089}\r
1090\r
1091/**\r
1092 Update memory profile information.\r
1093\r
1094 @param CallerAddress Address of caller who call Allocate or Free.\r
1095 @param Action This Allocate or Free action.\r
1096 @param MemoryType Memory type.\r
1097 @param Size Buffer size.\r
1098 @param Buffer Buffer address.\r
1099\r
1100 @retval TRUE Profile udpate success.\r
1101 @retval FALSE Profile update fail.\r
1102\r
1103**/\r
1104BOOLEAN\r
1105CoreUpdateProfile (\r
1106 IN PHYSICAL_ADDRESS CallerAddress,\r
1107 IN MEMORY_PROFILE_ACTION Action,\r
dea0d6bf 1108 IN EFI_MEMORY_TYPE MemoryType,\r
84edd20b
SZ
1109 IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool\r
1110 IN VOID *Buffer\r
1111 )\r
1112{\r
1113 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1114\r
1115 if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {\r
1116 return FALSE;\r
1117 }\r
1118\r
1119 if (!mMemoryProfileRecordingStatus) {\r
1120 return FALSE;\r
1121 }\r
1122\r
1123 //\r
dea0d6bf 1124 // Only record limited MemoryType.\r
84edd20b 1125 //\r
dea0d6bf
SZ
1126 if (!CoreNeedRecordProfile (MemoryType)) {\r
1127 return FALSE;\r
84edd20b
SZ
1128 }\r
1129\r
1130 ContextData = GetMemoryProfileContext ();\r
1131 if (ContextData == NULL) {\r
1132 return FALSE;\r
1133 }\r
1134\r
1135 switch (Action) {\r
1136 case MemoryProfileActionAllocatePages:\r
1137 CoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer);\r
1138 break;\r
1139 case MemoryProfileActionFreePages:\r
1140 CoreUpdateProfileFree (CallerAddress, Action, Size, Buffer);\r
1141 break;\r
1142 case MemoryProfileActionAllocatePool:\r
1143 CoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer);\r
1144 break;\r
1145 case MemoryProfileActionFreePool:\r
1146 CoreUpdateProfileFree (CallerAddress, Action, 0, Buffer);\r
1147 break;\r
1148 default:\r
1149 ASSERT (FALSE);\r
1150 break;\r
1151 }\r
1152 return TRUE;\r
1153}\r
1154\r
1155////////////////////\r
1156\r
1157/**\r
1158 Get memory profile data size.\r
1159\r
1160 @return Memory profile data size.\r
1161\r
1162**/\r
1163UINTN\r
1164MemoryProfileGetDataSize (\r
1165 VOID\r
1166 )\r
1167{\r
1168 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1169 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
1170 LIST_ENTRY *DriverInfoList;\r
1171 LIST_ENTRY *DriverLink;\r
1172 UINTN TotalSize;\r
1173\r
1174\r
1175 ContextData = GetMemoryProfileContext ();\r
1176 if (ContextData == NULL) {\r
1177 return 0;\r
1178 }\r
1179\r
1180 TotalSize = sizeof (MEMORY_PROFILE_CONTEXT);\r
1181 TotalSize += sizeof (MEMORY_PROFILE_DRIVER_INFO) * (UINTN) ContextData->Context.ImageCount;\r
1182\r
1183 DriverInfoList = ContextData->DriverInfoList;\r
1184 for (DriverLink = DriverInfoList->ForwardLink;\r
1185 DriverLink != DriverInfoList;\r
1186 DriverLink = DriverLink->ForwardLink) {\r
1187 DriverInfoData = CR (\r
1188 DriverLink,\r
1189 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
1190 Link,\r
1191 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
1192 );\r
1193 TotalSize += sizeof (MEMORY_PROFILE_ALLOC_INFO) * (UINTN) DriverInfoData->DriverInfo.AllocRecordCount;\r
1194 }\r
1195\r
1196 return TotalSize;\r
1197}\r
1198\r
1199/**\r
1200 Copy memory profile data.\r
1201\r
1202 @param ProfileBuffer The buffer to hold memory profile data.\r
1203\r
1204**/\r
1205VOID\r
1206MemoryProfileCopyData (\r
1207 IN VOID *ProfileBuffer\r
1208 )\r
1209{\r
1210 MEMORY_PROFILE_CONTEXT *Context;\r
1211 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
1212 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
1213 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1214 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
1215 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
1216 LIST_ENTRY *DriverInfoList;\r
1217 LIST_ENTRY *DriverLink;\r
1218 LIST_ENTRY *AllocInfoList;\r
1219 LIST_ENTRY *AllocLink;\r
1220\r
1221 ContextData = GetMemoryProfileContext ();\r
1222 if (ContextData == NULL) {\r
1223 return ;\r
1224 }\r
1225\r
1226 Context = ProfileBuffer;\r
1227 CopyMem (Context, &ContextData->Context, sizeof (MEMORY_PROFILE_CONTEXT));\r
1228 DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) (Context + 1);\r
1229\r
1230 DriverInfoList = ContextData->DriverInfoList;\r
1231 for (DriverLink = DriverInfoList->ForwardLink;\r
1232 DriverLink != DriverInfoList;\r
1233 DriverLink = DriverLink->ForwardLink) {\r
1234 DriverInfoData = CR (\r
1235 DriverLink,\r
1236 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
1237 Link,\r
1238 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
1239 );\r
1240 CopyMem (DriverInfo, &DriverInfoData->DriverInfo, sizeof (MEMORY_PROFILE_DRIVER_INFO));\r
1241 AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) (DriverInfo + 1);\r
1242\r
1243 AllocInfoList = DriverInfoData->AllocInfoList;\r
1244 for (AllocLink = AllocInfoList->ForwardLink;\r
1245 AllocLink != AllocInfoList;\r
1246 AllocLink = AllocLink->ForwardLink) {\r
1247 AllocInfoData = CR (\r
1248 AllocLink,\r
1249 MEMORY_PROFILE_ALLOC_INFO_DATA,\r
1250 Link,\r
1251 MEMORY_PROFILE_ALLOC_INFO_SIGNATURE\r
1252 );\r
1253 CopyMem (AllocInfo, &AllocInfoData->AllocInfo, sizeof (MEMORY_PROFILE_ALLOC_INFO));\r
1254 AllocInfo += 1;\r
1255 }\r
1256\r
1257 DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) ((UINTN) (DriverInfo + 1) + sizeof (MEMORY_PROFILE_ALLOC_INFO) * (UINTN) DriverInfo->AllocRecordCount);\r
1258 }\r
1259}\r
1260\r
1261/**\r
1262 Get memory profile data.\r
1263\r
1264 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.\r
1265 @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.\r
1266 On return, points to the size of the data returned in ProfileBuffer.\r
1267 @param[out] ProfileBuffer Profile buffer.\r
1268 \r
1269 @return EFI_SUCCESS Get the memory profile data successfully.\r
1270 @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data. \r
1271 ProfileSize is updated with the size required.\r
1272\r
1273**/\r
1274EFI_STATUS\r
1275EFIAPI\r
1276ProfileProtocolGetData (\r
1277 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,\r
1278 IN OUT UINT64 *ProfileSize,\r
1279 OUT VOID *ProfileBuffer\r
1280 )\r
1281{\r
1282 UINTN Size;\r
1283 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1284 BOOLEAN MemoryProfileRecordingStatus;\r
1285\r
1286 ContextData = GetMemoryProfileContext ();\r
1287 if (ContextData == NULL) {\r
1288 return EFI_UNSUPPORTED;\r
1289 }\r
1290\r
1291 MemoryProfileRecordingStatus = mMemoryProfileRecordingStatus;\r
1292 mMemoryProfileRecordingStatus = FALSE;\r
1293\r
1294 Size = MemoryProfileGetDataSize ();\r
1295\r
1296 if (*ProfileSize < Size) {\r
1297 *ProfileSize = Size;\r
1298 mMemoryProfileRecordingStatus = MemoryProfileRecordingStatus;\r
1299 return EFI_BUFFER_TOO_SMALL;\r
1300 }\r
1301\r
1302 *ProfileSize = Size;\r
1303 MemoryProfileCopyData (ProfileBuffer);\r
1304\r
1305 mMemoryProfileRecordingStatus = MemoryProfileRecordingStatus;\r
1306 return EFI_SUCCESS;\r
1307}\r
1308\r
1309/**\r
1310 Register image to memory profile.\r
1311\r
1312 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.\r
1313 @param[in] FilePath File path of the image.\r
1314 @param[in] ImageBase Image base address.\r
1315 @param[in] ImageSize Image size.\r
1316 @param[in] FileType File type of the image.\r
1317\r
1318 @return EFI_SUCCESS Register success.\r
1319 @return EFI_OUT_OF_RESOURCE No enough resource for this register.\r
1320\r
1321**/\r
1322EFI_STATUS\r
1323EFIAPI\r
1324ProfileProtocolRegisterImage (\r
1325 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,\r
1326 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1327 IN PHYSICAL_ADDRESS ImageBase,\r
1328 IN UINT64 ImageSize,\r
1329 IN EFI_FV_FILETYPE FileType\r
1330 )\r
1331{\r
1332 EFI_STATUS Status;\r
1333 LOADED_IMAGE_PRIVATE_DATA DriverEntry;\r
1334 VOID *EntryPointInImage;\r
1335\r
1336 ZeroMem (&DriverEntry, sizeof (DriverEntry));\r
1337 DriverEntry.Info.FilePath = FilePath;\r
1338 DriverEntry.ImageContext.ImageAddress = ImageBase;\r
1339 DriverEntry.ImageContext.ImageSize = ImageSize;\r
1340 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);\r
1341 ASSERT_EFI_ERROR (Status);\r
1342 DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;\r
1343 DriverEntry.ImageContext.ImageType = InternalPeCoffGetSubsystem ((VOID *) (UINTN) ImageBase);\r
1344\r
1345 return RegisterMemoryProfileImage (&DriverEntry, FileType) ? EFI_SUCCESS: EFI_OUT_OF_RESOURCES;\r
1346}\r
1347\r
1348/**\r
1349 Unregister image from memory profile.\r
1350\r
1351 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.\r
1352 @param[in] FilePath File path of the image.\r
1353 @param[in] ImageBase Image base address.\r
1354 @param[in] ImageSize Image size.\r
1355\r
1356 @return EFI_SUCCESS Unregister success.\r
1357 @return EFI_NOT_FOUND The image is not found.\r
1358\r
1359**/\r
1360EFI_STATUS\r
1361EFIAPI\r
1362ProfileProtocolUnregisterImage (\r
1363 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,\r
1364 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1365 IN PHYSICAL_ADDRESS ImageBase,\r
1366 IN UINT64 ImageSize\r
1367 )\r
1368{\r
1369 EFI_STATUS Status;\r
1370 LOADED_IMAGE_PRIVATE_DATA DriverEntry;\r
1371 VOID *EntryPointInImage;\r
1372\r
1373 ZeroMem (&DriverEntry, sizeof (DriverEntry));\r
1374 DriverEntry.Info.FilePath = FilePath;\r
1375 DriverEntry.ImageContext.ImageAddress = ImageBase;\r
1376 DriverEntry.ImageContext.ImageSize = ImageSize;\r
1377 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);\r
1378 ASSERT_EFI_ERROR (Status);\r
1379 DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;\r
1380\r
1381 return UnregisterMemoryProfileImage (&DriverEntry) ? EFI_SUCCESS: EFI_NOT_FOUND;\r
1382}\r
1383\r
1384////////////////////\r