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