]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c
MdeModulePkg DxeCore/PiSmmCore: Add UEFI memory and SMRAM profile support.
[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
820 ContextData = GetMemoryProfileContext ();\r
821 if (ContextData == NULL) {\r
822 return FALSE;\r
823 }\r
824\r
825 DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);\r
826 ASSERT (DriverInfoData != NULL);\r
827\r
828 //\r
829 // Use CoreInternalAllocatePool() that will not update profile for this AllocatePool action.\r
830 //\r
831 Status = CoreInternalAllocatePool (\r
832 EfiBootServicesData,\r
833 sizeof (*AllocInfoData),\r
834 (VOID **) &AllocInfoData\r
835 );\r
836 if (EFI_ERROR (Status)) {\r
837 return FALSE;\r
838 }\r
839 AllocInfo = &AllocInfoData->AllocInfo;\r
840 AllocInfoData->Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;\r
841 AllocInfo->Header.Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;\r
842 AllocInfo->Header.Length = sizeof (MEMORY_PROFILE_ALLOC_INFO);\r
843 AllocInfo->Header.Revision = MEMORY_PROFILE_ALLOC_INFO_REVISION;\r
844 AllocInfo->CallerAddress = CallerAddress;\r
845 AllocInfo->SequenceId = ContextData->Context.SequenceCount;\r
846 AllocInfo->Action = Action;\r
847 AllocInfo->MemoryType = MemoryType;\r
848 AllocInfo->Buffer = (PHYSICAL_ADDRESS) (UINTN) Buffer;\r
849 AllocInfo->Size = Size;\r
850\r
851 InsertTailList (DriverInfoData->AllocInfoList, &AllocInfoData->Link);\r
852\r
853 ProfileMemoryIndex = GetProfileMemoryIndex (MemoryType);\r
854\r
855 DriverInfo = &DriverInfoData->DriverInfo;\r
856 DriverInfo->CurrentUsage += Size;\r
857 if (DriverInfo->PeakUsage < DriverInfo->CurrentUsage) {\r
858 DriverInfo->PeakUsage = DriverInfo->CurrentUsage;\r
859 }\r
860 DriverInfo->CurrentUsageByType[ProfileMemoryIndex] += Size;\r
861 if (DriverInfo->PeakUsageByType[ProfileMemoryIndex] < DriverInfo->CurrentUsageByType[ProfileMemoryIndex]) {\r
862 DriverInfo->PeakUsageByType[ProfileMemoryIndex] = DriverInfo->CurrentUsageByType[ProfileMemoryIndex];\r
863 }\r
864 DriverInfo->AllocRecordCount ++;\r
865\r
866 Context = &ContextData->Context;\r
867 Context->CurrentTotalUsage += Size;\r
868 if (Context->PeakTotalUsage < Context->CurrentTotalUsage) {\r
869 Context->PeakTotalUsage = Context->CurrentTotalUsage;\r
870 }\r
871 Context->CurrentTotalUsageByType[ProfileMemoryIndex] += Size;\r
872 if (Context->PeakTotalUsageByType[ProfileMemoryIndex] < Context->CurrentTotalUsageByType[ProfileMemoryIndex]) {\r
873 Context->PeakTotalUsageByType[ProfileMemoryIndex] = Context->CurrentTotalUsageByType[ProfileMemoryIndex];\r
874 }\r
875 Context->SequenceCount ++;\r
876\r
877 return TRUE;\r
878}\r
879\r
880/**\r
881 Get memory profile alloc info from memory profile\r
882\r
883 @param DriverInfoData Driver info\r
884 @param Action This Free action\r
885 @param Size Buffer size\r
886 @param Buffer Buffer address\r
887\r
888 @return Pointer to memory profile alloc info.\r
889**/\r
890MEMORY_PROFILE_ALLOC_INFO_DATA *\r
891GetMemoryProfileAllocInfoFromAddress (\r
892 IN MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData,\r
893 IN MEMORY_PROFILE_ACTION Action,\r
894 IN UINTN Size,\r
895 IN VOID *Buffer\r
896 )\r
897{\r
898 LIST_ENTRY *AllocInfoList;\r
899 LIST_ENTRY *AllocLink;\r
900 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
901 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
902\r
903 AllocInfoList = DriverInfoData->AllocInfoList;\r
904\r
905 for (AllocLink = AllocInfoList->ForwardLink;\r
906 AllocLink != AllocInfoList;\r
907 AllocLink = AllocLink->ForwardLink) {\r
908 AllocInfoData = CR (\r
909 AllocLink,\r
910 MEMORY_PROFILE_ALLOC_INFO_DATA,\r
911 Link,\r
912 MEMORY_PROFILE_ALLOC_INFO_SIGNATURE\r
913 );\r
914 AllocInfo = &AllocInfoData->AllocInfo;\r
915 if (AllocInfo->Action != Action) {\r
916 continue;\r
917 }\r
918 switch (Action) {\r
919 case MemoryProfileActionAllocatePages:\r
920 if ((AllocInfo->Buffer <= (PHYSICAL_ADDRESS) (UINTN) Buffer) &&\r
921 ((AllocInfo->Buffer + AllocInfo->Size) >= ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size))) {\r
922 return AllocInfoData;\r
923 }\r
924 break;\r
925 case MemoryProfileActionAllocatePool:\r
926 if (AllocInfo->Buffer == (PHYSICAL_ADDRESS) (UINTN) Buffer) {\r
927 return AllocInfoData;\r
928 }\r
929 break;\r
930 default:\r
931 ASSERT (FALSE);\r
932 break;\r
933 }\r
934 }\r
935\r
936 return NULL;\r
937}\r
938\r
939/**\r
940 Update memory profile Free information.\r
941\r
942 @param CallerAddress Address of caller who call Free.\r
943 @param Action This Free action.\r
944 @param Size Buffer size.\r
945 @param Buffer Buffer address.\r
946\r
947 @retval TRUE Profile udpate success.\r
948 @retval FALSE Profile update fail.\r
949\r
950**/\r
951BOOLEAN\r
952CoreUpdateProfileFree (\r
953 IN PHYSICAL_ADDRESS CallerAddress,\r
954 IN MEMORY_PROFILE_ACTION Action,\r
955 IN UINTN Size,\r
956 IN VOID *Buffer\r
957 )\r
958{\r
959 MEMORY_PROFILE_CONTEXT *Context;\r
960 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
961 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
962 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
963 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
964 LIST_ENTRY *DriverLink;\r
965 LIST_ENTRY *DriverInfoList;\r
966 MEMORY_PROFILE_DRIVER_INFO_DATA *ThisDriverInfoData;\r
967 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
968 EFI_MEMORY_TYPE ProfileMemoryIndex;\r
969\r
970 ContextData = GetMemoryProfileContext ();\r
971 if (ContextData == NULL) {\r
972 return FALSE;\r
973 }\r
974\r
975 DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);\r
976 ASSERT (DriverInfoData != NULL);\r
977\r
978 switch (Action) {\r
979 case MemoryProfileActionFreePages:\r
980 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);\r
981 break;\r
982 case MemoryProfileActionFreePool:\r
983 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);\r
984 break;\r
985 default:\r
986 ASSERT (FALSE);\r
987 AllocInfoData = NULL;\r
988 break;\r
989 }\r
990 if (AllocInfoData == NULL) {\r
991 //\r
992 // Legal case, because driver A might free memory allocated by driver B, by some protocol.\r
993 //\r
994 DriverInfoList = ContextData->DriverInfoList;\r
995\r
996 for (DriverLink = DriverInfoList->ForwardLink;\r
997 DriverLink != DriverInfoList;\r
998 DriverLink = DriverLink->ForwardLink) {\r
999 ThisDriverInfoData = CR (\r
1000 DriverLink,\r
1001 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
1002 Link,\r
1003 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
1004 );\r
1005 switch (Action) {\r
1006 case MemoryProfileActionFreePages:\r
1007 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);\r
1008 break;\r
1009 case MemoryProfileActionFreePool:\r
1010 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);\r
1011 break;\r
1012 default:\r
1013 ASSERT (FALSE);\r
1014 AllocInfoData = NULL;\r
1015 break;\r
1016 }\r
1017 if (AllocInfoData != NULL) {\r
1018 DriverInfoData = ThisDriverInfoData;\r
1019 break;\r
1020 }\r
1021 }\r
1022\r
1023 if (AllocInfoData == NULL) {\r
1024 //\r
1025 // No matched allocate operation is found for this free operation.\r
1026 // It is because the specified memory type allocate operation has been\r
1027 // filtered by CoreNeedRecordProfile(), but free operations have no\r
1028 // memory type information, they can not be filtered by CoreNeedRecordProfile().\r
1029 // Then, they will be filtered here.\r
1030 //\r
1031 return FALSE;\r
1032 }\r
1033 }\r
1034\r
1035 Context = &ContextData->Context;\r
1036 DriverInfo = &DriverInfoData->DriverInfo;\r
1037 AllocInfo = &AllocInfoData->AllocInfo;\r
1038\r
1039 ProfileMemoryIndex = GetProfileMemoryIndex (AllocInfo->MemoryType);\r
1040\r
1041 Context->CurrentTotalUsage -= AllocInfo->Size;\r
1042 Context->CurrentTotalUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;\r
1043\r
1044 DriverInfo->CurrentUsage -= AllocInfo->Size;\r
1045 DriverInfo->CurrentUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;\r
1046 DriverInfo->AllocRecordCount --;\r
1047\r
1048 RemoveEntryList (&AllocInfoData->Link);\r
1049\r
1050 if (Action == MemoryProfileActionFreePages) {\r
1051 if (AllocInfo->Buffer != (PHYSICAL_ADDRESS) (UINTN) Buffer) {\r
1052 CoreUpdateProfileAllocate (\r
1053 AllocInfo->CallerAddress,\r
1054 MemoryProfileActionAllocatePages,\r
1055 AllocInfo->MemoryType,\r
1056 (UINTN) ((PHYSICAL_ADDRESS) (UINTN) Buffer - AllocInfo->Buffer),\r
1057 (VOID *) (UINTN) AllocInfo->Buffer\r
1058 );\r
1059 }\r
1060 if (AllocInfo->Buffer + AllocInfo->Size != ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)) {\r
1061 CoreUpdateProfileAllocate (\r
1062 AllocInfo->CallerAddress,\r
1063 MemoryProfileActionAllocatePages,\r
1064 AllocInfo->MemoryType,\r
1065 (UINTN) ((AllocInfo->Buffer + AllocInfo->Size) - ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)),\r
1066 (VOID *) ((UINTN) Buffer + Size)\r
1067 );\r
1068 }\r
1069 }\r
1070\r
1071 //\r
1072 // Use CoreInternalFreePool() that will not update profile for this FreePool action.\r
1073 //\r
1074 CoreInternalFreePool (AllocInfoData);\r
1075\r
1076 return TRUE;\r
1077}\r
1078\r
1079/**\r
1080 Update memory profile information.\r
1081\r
1082 @param CallerAddress Address of caller who call Allocate or Free.\r
1083 @param Action This Allocate or Free action.\r
1084 @param MemoryType Memory type.\r
1085 @param Size Buffer size.\r
1086 @param Buffer Buffer address.\r
1087\r
1088 @retval TRUE Profile udpate success.\r
1089 @retval FALSE Profile update fail.\r
1090\r
1091**/\r
1092BOOLEAN\r
1093CoreUpdateProfile (\r
1094 IN PHYSICAL_ADDRESS CallerAddress,\r
1095 IN MEMORY_PROFILE_ACTION Action,\r
1096 IN EFI_MEMORY_TYPE MemoryType, // Valid for AllocatePages/AllocatePool\r
1097 IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool\r
1098 IN VOID *Buffer\r
1099 )\r
1100{\r
1101 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1102\r
1103 if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {\r
1104 return FALSE;\r
1105 }\r
1106\r
1107 if (!mMemoryProfileRecordingStatus) {\r
1108 return FALSE;\r
1109 }\r
1110\r
1111 //\r
1112 // Free operations have no memory type information, so skip the check.\r
1113 //\r
1114 if ((Action == MemoryProfileActionAllocatePages) || (Action == MemoryProfileActionAllocatePool)) {\r
1115 //\r
1116 // Only record limited MemoryType.\r
1117 //\r
1118 if (!CoreNeedRecordProfile (MemoryType)) {\r
1119 return FALSE;\r
1120 }\r
1121 }\r
1122\r
1123 ContextData = GetMemoryProfileContext ();\r
1124 if (ContextData == NULL) {\r
1125 return FALSE;\r
1126 }\r
1127\r
1128 switch (Action) {\r
1129 case MemoryProfileActionAllocatePages:\r
1130 CoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer);\r
1131 break;\r
1132 case MemoryProfileActionFreePages:\r
1133 CoreUpdateProfileFree (CallerAddress, Action, Size, Buffer);\r
1134 break;\r
1135 case MemoryProfileActionAllocatePool:\r
1136 CoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer);\r
1137 break;\r
1138 case MemoryProfileActionFreePool:\r
1139 CoreUpdateProfileFree (CallerAddress, Action, 0, Buffer);\r
1140 break;\r
1141 default:\r
1142 ASSERT (FALSE);\r
1143 break;\r
1144 }\r
1145 return TRUE;\r
1146}\r
1147\r
1148////////////////////\r
1149\r
1150/**\r
1151 Get memory profile data size.\r
1152\r
1153 @return Memory profile data size.\r
1154\r
1155**/\r
1156UINTN\r
1157MemoryProfileGetDataSize (\r
1158 VOID\r
1159 )\r
1160{\r
1161 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1162 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
1163 LIST_ENTRY *DriverInfoList;\r
1164 LIST_ENTRY *DriverLink;\r
1165 UINTN TotalSize;\r
1166\r
1167\r
1168 ContextData = GetMemoryProfileContext ();\r
1169 if (ContextData == NULL) {\r
1170 return 0;\r
1171 }\r
1172\r
1173 TotalSize = sizeof (MEMORY_PROFILE_CONTEXT);\r
1174 TotalSize += sizeof (MEMORY_PROFILE_DRIVER_INFO) * (UINTN) ContextData->Context.ImageCount;\r
1175\r
1176 DriverInfoList = ContextData->DriverInfoList;\r
1177 for (DriverLink = DriverInfoList->ForwardLink;\r
1178 DriverLink != DriverInfoList;\r
1179 DriverLink = DriverLink->ForwardLink) {\r
1180 DriverInfoData = CR (\r
1181 DriverLink,\r
1182 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
1183 Link,\r
1184 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
1185 );\r
1186 TotalSize += sizeof (MEMORY_PROFILE_ALLOC_INFO) * (UINTN) DriverInfoData->DriverInfo.AllocRecordCount;\r
1187 }\r
1188\r
1189 return TotalSize;\r
1190}\r
1191\r
1192/**\r
1193 Copy memory profile data.\r
1194\r
1195 @param ProfileBuffer The buffer to hold memory profile data.\r
1196\r
1197**/\r
1198VOID\r
1199MemoryProfileCopyData (\r
1200 IN VOID *ProfileBuffer\r
1201 )\r
1202{\r
1203 MEMORY_PROFILE_CONTEXT *Context;\r
1204 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
1205 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
1206 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1207 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
1208 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
1209 LIST_ENTRY *DriverInfoList;\r
1210 LIST_ENTRY *DriverLink;\r
1211 LIST_ENTRY *AllocInfoList;\r
1212 LIST_ENTRY *AllocLink;\r
1213\r
1214 ContextData = GetMemoryProfileContext ();\r
1215 if (ContextData == NULL) {\r
1216 return ;\r
1217 }\r
1218\r
1219 Context = ProfileBuffer;\r
1220 CopyMem (Context, &ContextData->Context, sizeof (MEMORY_PROFILE_CONTEXT));\r
1221 DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) (Context + 1);\r
1222\r
1223 DriverInfoList = ContextData->DriverInfoList;\r
1224 for (DriverLink = DriverInfoList->ForwardLink;\r
1225 DriverLink != DriverInfoList;\r
1226 DriverLink = DriverLink->ForwardLink) {\r
1227 DriverInfoData = CR (\r
1228 DriverLink,\r
1229 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
1230 Link,\r
1231 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
1232 );\r
1233 CopyMem (DriverInfo, &DriverInfoData->DriverInfo, sizeof (MEMORY_PROFILE_DRIVER_INFO));\r
1234 AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) (DriverInfo + 1);\r
1235\r
1236 AllocInfoList = DriverInfoData->AllocInfoList;\r
1237 for (AllocLink = AllocInfoList->ForwardLink;\r
1238 AllocLink != AllocInfoList;\r
1239 AllocLink = AllocLink->ForwardLink) {\r
1240 AllocInfoData = CR (\r
1241 AllocLink,\r
1242 MEMORY_PROFILE_ALLOC_INFO_DATA,\r
1243 Link,\r
1244 MEMORY_PROFILE_ALLOC_INFO_SIGNATURE\r
1245 );\r
1246 CopyMem (AllocInfo, &AllocInfoData->AllocInfo, sizeof (MEMORY_PROFILE_ALLOC_INFO));\r
1247 AllocInfo += 1;\r
1248 }\r
1249\r
1250 DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) ((UINTN) (DriverInfo + 1) + sizeof (MEMORY_PROFILE_ALLOC_INFO) * (UINTN) DriverInfo->AllocRecordCount);\r
1251 }\r
1252}\r
1253\r
1254/**\r
1255 Get memory profile data.\r
1256\r
1257 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.\r
1258 @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.\r
1259 On return, points to the size of the data returned in ProfileBuffer.\r
1260 @param[out] ProfileBuffer Profile buffer.\r
1261 \r
1262 @return EFI_SUCCESS Get the memory profile data successfully.\r
1263 @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data. \r
1264 ProfileSize is updated with the size required.\r
1265\r
1266**/\r
1267EFI_STATUS\r
1268EFIAPI\r
1269ProfileProtocolGetData (\r
1270 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,\r
1271 IN OUT UINT64 *ProfileSize,\r
1272 OUT VOID *ProfileBuffer\r
1273 )\r
1274{\r
1275 UINTN Size;\r
1276 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1277 BOOLEAN MemoryProfileRecordingStatus;\r
1278\r
1279 ContextData = GetMemoryProfileContext ();\r
1280 if (ContextData == NULL) {\r
1281 return EFI_UNSUPPORTED;\r
1282 }\r
1283\r
1284 MemoryProfileRecordingStatus = mMemoryProfileRecordingStatus;\r
1285 mMemoryProfileRecordingStatus = FALSE;\r
1286\r
1287 Size = MemoryProfileGetDataSize ();\r
1288\r
1289 if (*ProfileSize < Size) {\r
1290 *ProfileSize = Size;\r
1291 mMemoryProfileRecordingStatus = MemoryProfileRecordingStatus;\r
1292 return EFI_BUFFER_TOO_SMALL;\r
1293 }\r
1294\r
1295 *ProfileSize = Size;\r
1296 MemoryProfileCopyData (ProfileBuffer);\r
1297\r
1298 mMemoryProfileRecordingStatus = MemoryProfileRecordingStatus;\r
1299 return EFI_SUCCESS;\r
1300}\r
1301\r
1302/**\r
1303 Register image to memory profile.\r
1304\r
1305 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.\r
1306 @param[in] FilePath File path of the image.\r
1307 @param[in] ImageBase Image base address.\r
1308 @param[in] ImageSize Image size.\r
1309 @param[in] FileType File type of the image.\r
1310\r
1311 @return EFI_SUCCESS Register success.\r
1312 @return EFI_OUT_OF_RESOURCE No enough resource for this register.\r
1313\r
1314**/\r
1315EFI_STATUS\r
1316EFIAPI\r
1317ProfileProtocolRegisterImage (\r
1318 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,\r
1319 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1320 IN PHYSICAL_ADDRESS ImageBase,\r
1321 IN UINT64 ImageSize,\r
1322 IN EFI_FV_FILETYPE FileType\r
1323 )\r
1324{\r
1325 EFI_STATUS Status;\r
1326 LOADED_IMAGE_PRIVATE_DATA DriverEntry;\r
1327 VOID *EntryPointInImage;\r
1328\r
1329 ZeroMem (&DriverEntry, sizeof (DriverEntry));\r
1330 DriverEntry.Info.FilePath = FilePath;\r
1331 DriverEntry.ImageContext.ImageAddress = ImageBase;\r
1332 DriverEntry.ImageContext.ImageSize = ImageSize;\r
1333 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);\r
1334 ASSERT_EFI_ERROR (Status);\r
1335 DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;\r
1336 DriverEntry.ImageContext.ImageType = InternalPeCoffGetSubsystem ((VOID *) (UINTN) ImageBase);\r
1337\r
1338 return RegisterMemoryProfileImage (&DriverEntry, FileType) ? EFI_SUCCESS: EFI_OUT_OF_RESOURCES;\r
1339}\r
1340\r
1341/**\r
1342 Unregister image from memory profile.\r
1343\r
1344 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.\r
1345 @param[in] FilePath File path of the image.\r
1346 @param[in] ImageBase Image base address.\r
1347 @param[in] ImageSize Image size.\r
1348\r
1349 @return EFI_SUCCESS Unregister success.\r
1350 @return EFI_NOT_FOUND The image is not found.\r
1351\r
1352**/\r
1353EFI_STATUS\r
1354EFIAPI\r
1355ProfileProtocolUnregisterImage (\r
1356 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,\r
1357 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1358 IN PHYSICAL_ADDRESS ImageBase,\r
1359 IN UINT64 ImageSize\r
1360 )\r
1361{\r
1362 EFI_STATUS Status;\r
1363 LOADED_IMAGE_PRIVATE_DATA DriverEntry;\r
1364 VOID *EntryPointInImage;\r
1365\r
1366 ZeroMem (&DriverEntry, sizeof (DriverEntry));\r
1367 DriverEntry.Info.FilePath = FilePath;\r
1368 DriverEntry.ImageContext.ImageAddress = ImageBase;\r
1369 DriverEntry.ImageContext.ImageSize = ImageSize;\r
1370 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);\r
1371 ASSERT_EFI_ERROR (Status);\r
1372 DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;\r
1373\r
1374 return UnregisterMemoryProfileImage (&DriverEntry) ? EFI_SUCCESS: EFI_NOT_FOUND;\r
1375}\r
1376\r
1377////////////////////\r