]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c
MdeModulePkg PiSmmCore: Care runtime code/data only for SMRAM profile.
[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
092b852a 4 Copyright (c) 2014 - 2015, 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
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
092b852a
SZ
486 if (FilePath != NULL) {\r
487 ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) FilePath;\r
488 while (!IsDevicePathEnd (ThisFilePath)) {\r
489 FileName = EfiGetNameGuidFromFwVolDevicePathNode (ThisFilePath);\r
490 if (FileName != NULL) {\r
491 break;\r
492 }\r
493 ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) NextDevicePathNode (ThisFilePath);\r
84edd20b 494 }\r
84edd20b
SZ
495 }\r
496\r
497 return FileName;\r
498}\r
499\r
500/**\r
501 Register image to memory profile.\r
502\r
503 @param DriverEntry Image info.\r
504 @param FileType Image file type.\r
505\r
506 @retval TRUE Register success.\r
507 @retval FALSE Register fail.\r
508\r
509**/\r
510BOOLEAN\r
511RegisterMemoryProfileImage (\r
512 IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry,\r
513 IN EFI_FV_FILETYPE FileType\r
514 )\r
515{\r
516 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
517 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
518\r
519 if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {\r
520 return FALSE;\r
521 }\r
522\r
523 ContextData = GetMemoryProfileContext ();\r
524 if (ContextData == NULL) {\r
525 return FALSE;\r
526 }\r
527\r
528 DriverInfoData = BuildDriverInfo (\r
529 ContextData,\r
530 GetFileNameFromFilePath (DriverEntry->Info.FilePath),\r
531 DriverEntry->ImageContext.ImageAddress,\r
532 DriverEntry->ImageContext.ImageSize,\r
533 DriverEntry->ImageContext.EntryPoint,\r
534 DriverEntry->ImageContext.ImageType,\r
535 FileType\r
536 );\r
537 if (DriverInfoData == NULL) {\r
538 return FALSE;\r
539 }\r
540\r
541 return TRUE;\r
542}\r
543\r
544/**\r
545 Search image from memory profile.\r
546\r
547 @param ContextData Memory profile context.\r
548 @param FileName Image file name.\r
549 @param Address Image Address.\r
550\r
551 @return Pointer to memory profile driver info.\r
552\r
553**/\r
554MEMORY_PROFILE_DRIVER_INFO_DATA *\r
555GetMemoryProfileDriverInfoByFileNameAndAddress (\r
556 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,\r
557 IN EFI_GUID *FileName,\r
558 IN PHYSICAL_ADDRESS Address\r
559 )\r
560{\r
561 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
562 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
563 LIST_ENTRY *DriverLink;\r
564 LIST_ENTRY *DriverInfoList;\r
565\r
566 DriverInfoList = ContextData->DriverInfoList;\r
567\r
568 for (DriverLink = DriverInfoList->ForwardLink;\r
569 DriverLink != DriverInfoList;\r
570 DriverLink = DriverLink->ForwardLink) {\r
571 DriverInfoData = CR (\r
572 DriverLink,\r
573 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
574 Link,\r
575 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
576 );\r
577 DriverInfo = &DriverInfoData->DriverInfo;\r
578 if ((CompareGuid (&DriverInfo->FileName, FileName)) &&\r
579 (Address >= DriverInfo->ImageBase) &&\r
580 (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {\r
581 return DriverInfoData;\r
582 }\r
583 }\r
584\r
585 return NULL;\r
586}\r
587\r
588/**\r
589 Search dummy image from memory profile.\r
590\r
591 @param ContextData Memory profile context.\r
592\r
593 @return Pointer to memory profile driver info.\r
594\r
595**/\r
596MEMORY_PROFILE_DRIVER_INFO_DATA *\r
597FindDummyImage (\r
598 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData\r
599 )\r
600{\r
601 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
602 LIST_ENTRY *DriverLink;\r
603 LIST_ENTRY *DriverInfoList;\r
604\r
605 DriverInfoList = ContextData->DriverInfoList;\r
606\r
607 for (DriverLink = DriverInfoList->ForwardLink;\r
608 DriverLink != DriverInfoList;\r
609 DriverLink = DriverLink->ForwardLink) {\r
610 DriverInfoData = CR (\r
611 DriverLink,\r
612 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
613 Link,\r
614 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
615 );\r
616 if (CompareGuid (&gZeroGuid, &DriverInfoData->DriverInfo.FileName)) {\r
617 return DriverInfoData;\r
618 }\r
619 }\r
620\r
621 return BuildDriverInfo (ContextData, &gZeroGuid, 0, 0, 0, 0, 0);\r
622}\r
623\r
624/**\r
625 Search image from memory profile.\r
626 It will return image, if (Address >= ImageBuffer) AND (Address < ImageBuffer + ImageSize)\r
627\r
628 @param ContextData Memory profile context.\r
629 @param Address Image or Function address.\r
630\r
631 @return Pointer to memory profile driver info.\r
632\r
633**/\r
634MEMORY_PROFILE_DRIVER_INFO_DATA *\r
635GetMemoryProfileDriverInfoFromAddress (\r
636 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,\r
637 IN PHYSICAL_ADDRESS Address\r
638 )\r
639{\r
640 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
641 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
642 LIST_ENTRY *DriverLink;\r
643 LIST_ENTRY *DriverInfoList;\r
644\r
645 DriverInfoList = ContextData->DriverInfoList;\r
646\r
647 for (DriverLink = DriverInfoList->ForwardLink;\r
648 DriverLink != DriverInfoList;\r
649 DriverLink = DriverLink->ForwardLink) {\r
650 DriverInfoData = CR (\r
651 DriverLink,\r
652 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
653 Link,\r
654 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
655 );\r
656 DriverInfo = &DriverInfoData->DriverInfo;\r
657 if ((Address >= DriverInfo->ImageBase) &&\r
658 (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {\r
659 return DriverInfoData;\r
660 }\r
661 }\r
662\r
663 //\r
664 // Should never come here.\r
665 //\r
666 return FindDummyImage (ContextData);\r
667}\r
668\r
669/**\r
670 Unregister image from memory profile.\r
671\r
672 @param DriverEntry Image info.\r
673\r
674 @retval TRUE Unregister success.\r
675 @retval FALSE Unregister fail.\r
676\r
677**/\r
678BOOLEAN\r
679UnregisterMemoryProfileImage (\r
680 IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry\r
681 )\r
682{\r
683 EFI_STATUS Status;\r
684 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
685 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
686 EFI_GUID *FileName;\r
687 PHYSICAL_ADDRESS ImageAddress;\r
688 VOID *EntryPointInImage;\r
689\r
690 if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {\r
691 return FALSE;\r
692 }\r
693\r
694 ContextData = GetMemoryProfileContext ();\r
695 if (ContextData == NULL) {\r
696 return FALSE;\r
697 }\r
698\r
699 DriverInfoData = NULL;\r
700 FileName = GetFileNameFromFilePath (DriverEntry->Info.FilePath);\r
701 ImageAddress = DriverEntry->ImageContext.ImageAddress;\r
702 if ((DriverEntry->ImageContext.EntryPoint < ImageAddress) || (DriverEntry->ImageContext.EntryPoint >= (ImageAddress + DriverEntry->ImageContext.ImageSize))) {\r
703 //\r
704 // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.\r
705 // So patch ImageAddress here to align the EntryPoint.\r
706 //\r
707 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageAddress, &EntryPointInImage);\r
708 ASSERT_EFI_ERROR (Status);\r
709 ImageAddress = ImageAddress + (UINTN) DriverEntry->ImageContext.EntryPoint - (UINTN) EntryPointInImage;\r
710 }\r
711 if (FileName != NULL) {\r
712 DriverInfoData = GetMemoryProfileDriverInfoByFileNameAndAddress (ContextData, FileName, ImageAddress);\r
713 }\r
714 if (DriverInfoData == NULL) {\r
715 DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, ImageAddress);\r
716 }\r
717 if (DriverInfoData == NULL) {\r
718 return FALSE;\r
719 }\r
720\r
721 ContextData->Context.TotalImageSize -= DriverInfoData->DriverInfo.ImageSize;\r
722\r
723 DriverInfoData->DriverInfo.ImageBase = 0;\r
724 DriverInfoData->DriverInfo.ImageSize = 0;\r
725\r
726 if (DriverInfoData->DriverInfo.PeakUsage == 0) {\r
727 ContextData->Context.ImageCount --;\r
728 RemoveEntryList (&DriverInfoData->Link);\r
729 //\r
730 // Use CoreInternalFreePool() that will not update profile for this FreePool action.\r
731 //\r
732 CoreInternalFreePool (DriverInfoData);\r
733 }\r
734\r
735 return TRUE;\r
736}\r
737\r
738/**\r
739 Return if this memory type needs to be recorded into memory profile.\r
740 If BIOS memory type (0 ~ EfiMaxMemoryType), it checks bit (1 << MemoryType).\r
741 If OS memory type (0x80000000 ~ 0xFFFFFFFF), it checks bit63 - 0x8000000000000000.\r
742\r
743 @param MemoryType Memory type.\r
744\r
745 @retval TRUE This memory type need to be recorded.\r
746 @retval FALSE This memory type need not to be recorded.\r
747\r
748**/\r
749BOOLEAN\r
750CoreNeedRecordProfile (\r
751 IN EFI_MEMORY_TYPE MemoryType\r
752 )\r
753{\r
754 UINT64 TestBit;\r
755\r
756 if ((UINT32) MemoryType >= 0x80000000) {\r
757 TestBit = BIT63;\r
758 } else {\r
759 TestBit = LShiftU64 (1, MemoryType);\r
760 }\r
761\r
762 if ((PcdGet64 (PcdMemoryProfileMemoryType) & TestBit) != 0) {\r
763 return TRUE;\r
764 } else {\r
765 return FALSE;\r
766 }\r
767}\r
768\r
769/**\r
770 Convert EFI memory type to profile memory index. The rule is:\r
771 If BIOS memory type (0 ~ EfiMaxMemoryType), ProfileMemoryIndex = MemoryType.\r
772 If OS memory type (0x80000000 ~ 0xFFFFFFFF), ProfileMemoryIndex = EfiMaxMemoryType.\r
773\r
774 @param MemoryType Memory type.\r
775\r
776 @return EFI memory type as profile memory index.\r
777\r
778**/\r
779EFI_MEMORY_TYPE\r
780GetProfileMemoryIndex (\r
781 IN EFI_MEMORY_TYPE MemoryType\r
782 )\r
783{\r
784 if ((UINT32) MemoryType >= 0x80000000) {\r
785 return EfiMaxMemoryType;\r
786 } else {\r
787 return MemoryType;\r
788 }\r
789}\r
790\r
791/**\r
792 Update memory profile Allocate information.\r
793\r
794 @param CallerAddress Address of caller who call Allocate.\r
795 @param Action This Allocate action.\r
796 @param MemoryType Memory type.\r
797 @param Size Buffer size.\r
798 @param Buffer Buffer address.\r
799\r
800 @retval TRUE Profile udpate success.\r
801 @retval FALSE Profile update fail.\r
802\r
803**/\r
804BOOLEAN\r
805CoreUpdateProfileAllocate (\r
806 IN PHYSICAL_ADDRESS CallerAddress,\r
807 IN MEMORY_PROFILE_ACTION Action,\r
808 IN EFI_MEMORY_TYPE MemoryType,\r
809 IN UINTN Size,\r
810 IN VOID *Buffer\r
811 )\r
812{\r
813 EFI_STATUS Status;\r
814 MEMORY_PROFILE_CONTEXT *Context;\r
815 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
816 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
817 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
818 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
819 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
820 EFI_MEMORY_TYPE ProfileMemoryIndex;\r
821\r
f4420027
SZ
822 AllocInfoData = NULL;\r
823\r
84edd20b
SZ
824 ContextData = GetMemoryProfileContext ();\r
825 if (ContextData == NULL) {\r
826 return FALSE;\r
827 }\r
828\r
829 DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);\r
830 ASSERT (DriverInfoData != NULL);\r
831\r
832 //\r
833 // Use CoreInternalAllocatePool() that will not update profile for this AllocatePool action.\r
834 //\r
835 Status = CoreInternalAllocatePool (\r
836 EfiBootServicesData,\r
837 sizeof (*AllocInfoData),\r
838 (VOID **) &AllocInfoData\r
839 );\r
840 if (EFI_ERROR (Status)) {\r
841 return FALSE;\r
842 }\r
80fbf586 843 ASSERT (AllocInfoData != NULL);\r
84edd20b
SZ
844 AllocInfo = &AllocInfoData->AllocInfo;\r
845 AllocInfoData->Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;\r
846 AllocInfo->Header.Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;\r
847 AllocInfo->Header.Length = sizeof (MEMORY_PROFILE_ALLOC_INFO);\r
848 AllocInfo->Header.Revision = MEMORY_PROFILE_ALLOC_INFO_REVISION;\r
849 AllocInfo->CallerAddress = CallerAddress;\r
850 AllocInfo->SequenceId = ContextData->Context.SequenceCount;\r
851 AllocInfo->Action = Action;\r
852 AllocInfo->MemoryType = MemoryType;\r
853 AllocInfo->Buffer = (PHYSICAL_ADDRESS) (UINTN) Buffer;\r
854 AllocInfo->Size = Size;\r
855\r
856 InsertTailList (DriverInfoData->AllocInfoList, &AllocInfoData->Link);\r
857\r
858 ProfileMemoryIndex = GetProfileMemoryIndex (MemoryType);\r
859\r
860 DriverInfo = &DriverInfoData->DriverInfo;\r
861 DriverInfo->CurrentUsage += Size;\r
862 if (DriverInfo->PeakUsage < DriverInfo->CurrentUsage) {\r
863 DriverInfo->PeakUsage = DriverInfo->CurrentUsage;\r
864 }\r
865 DriverInfo->CurrentUsageByType[ProfileMemoryIndex] += Size;\r
866 if (DriverInfo->PeakUsageByType[ProfileMemoryIndex] < DriverInfo->CurrentUsageByType[ProfileMemoryIndex]) {\r
867 DriverInfo->PeakUsageByType[ProfileMemoryIndex] = DriverInfo->CurrentUsageByType[ProfileMemoryIndex];\r
868 }\r
869 DriverInfo->AllocRecordCount ++;\r
870\r
871 Context = &ContextData->Context;\r
872 Context->CurrentTotalUsage += Size;\r
873 if (Context->PeakTotalUsage < Context->CurrentTotalUsage) {\r
874 Context->PeakTotalUsage = Context->CurrentTotalUsage;\r
875 }\r
876 Context->CurrentTotalUsageByType[ProfileMemoryIndex] += Size;\r
877 if (Context->PeakTotalUsageByType[ProfileMemoryIndex] < Context->CurrentTotalUsageByType[ProfileMemoryIndex]) {\r
878 Context->PeakTotalUsageByType[ProfileMemoryIndex] = Context->CurrentTotalUsageByType[ProfileMemoryIndex];\r
879 }\r
880 Context->SequenceCount ++;\r
881\r
882 return TRUE;\r
883}\r
884\r
885/**\r
886 Get memory profile alloc info from memory profile\r
887\r
888 @param DriverInfoData Driver info\r
889 @param Action This Free action\r
890 @param Size Buffer size\r
891 @param Buffer Buffer address\r
892\r
893 @return Pointer to memory profile alloc info.\r
894**/\r
895MEMORY_PROFILE_ALLOC_INFO_DATA *\r
896GetMemoryProfileAllocInfoFromAddress (\r
897 IN MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData,\r
898 IN MEMORY_PROFILE_ACTION Action,\r
899 IN UINTN Size,\r
900 IN VOID *Buffer\r
901 )\r
902{\r
903 LIST_ENTRY *AllocInfoList;\r
904 LIST_ENTRY *AllocLink;\r
905 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
906 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
907\r
908 AllocInfoList = DriverInfoData->AllocInfoList;\r
909\r
910 for (AllocLink = AllocInfoList->ForwardLink;\r
911 AllocLink != AllocInfoList;\r
912 AllocLink = AllocLink->ForwardLink) {\r
913 AllocInfoData = CR (\r
914 AllocLink,\r
915 MEMORY_PROFILE_ALLOC_INFO_DATA,\r
916 Link,\r
917 MEMORY_PROFILE_ALLOC_INFO_SIGNATURE\r
918 );\r
919 AllocInfo = &AllocInfoData->AllocInfo;\r
920 if (AllocInfo->Action != Action) {\r
921 continue;\r
922 }\r
923 switch (Action) {\r
924 case MemoryProfileActionAllocatePages:\r
925 if ((AllocInfo->Buffer <= (PHYSICAL_ADDRESS) (UINTN) Buffer) &&\r
926 ((AllocInfo->Buffer + AllocInfo->Size) >= ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size))) {\r
927 return AllocInfoData;\r
928 }\r
929 break;\r
930 case MemoryProfileActionAllocatePool:\r
931 if (AllocInfo->Buffer == (PHYSICAL_ADDRESS) (UINTN) Buffer) {\r
932 return AllocInfoData;\r
933 }\r
934 break;\r
935 default:\r
936 ASSERT (FALSE);\r
937 break;\r
938 }\r
939 }\r
940\r
941 return NULL;\r
942}\r
943\r
944/**\r
945 Update memory profile Free information.\r
946\r
947 @param CallerAddress Address of caller who call Free.\r
948 @param Action This Free action.\r
949 @param Size Buffer size.\r
950 @param Buffer Buffer address.\r
951\r
952 @retval TRUE Profile udpate success.\r
953 @retval FALSE Profile update fail.\r
954\r
955**/\r
956BOOLEAN\r
957CoreUpdateProfileFree (\r
958 IN PHYSICAL_ADDRESS CallerAddress,\r
959 IN MEMORY_PROFILE_ACTION Action,\r
960 IN UINTN Size,\r
961 IN VOID *Buffer\r
962 )\r
963{\r
964 MEMORY_PROFILE_CONTEXT *Context;\r
965 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
966 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
967 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
968 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
969 LIST_ENTRY *DriverLink;\r
970 LIST_ENTRY *DriverInfoList;\r
971 MEMORY_PROFILE_DRIVER_INFO_DATA *ThisDriverInfoData;\r
972 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
973 EFI_MEMORY_TYPE ProfileMemoryIndex;\r
974\r
975 ContextData = GetMemoryProfileContext ();\r
976 if (ContextData == NULL) {\r
977 return FALSE;\r
978 }\r
979\r
980 DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);\r
981 ASSERT (DriverInfoData != NULL);\r
982\r
983 switch (Action) {\r
984 case MemoryProfileActionFreePages:\r
985 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);\r
986 break;\r
987 case MemoryProfileActionFreePool:\r
988 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);\r
989 break;\r
990 default:\r
991 ASSERT (FALSE);\r
992 AllocInfoData = NULL;\r
993 break;\r
994 }\r
995 if (AllocInfoData == NULL) {\r
996 //\r
997 // Legal case, because driver A might free memory allocated by driver B, by some protocol.\r
998 //\r
999 DriverInfoList = ContextData->DriverInfoList;\r
1000\r
1001 for (DriverLink = DriverInfoList->ForwardLink;\r
1002 DriverLink != DriverInfoList;\r
1003 DriverLink = DriverLink->ForwardLink) {\r
1004 ThisDriverInfoData = CR (\r
1005 DriverLink,\r
1006 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
1007 Link,\r
1008 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
1009 );\r
1010 switch (Action) {\r
1011 case MemoryProfileActionFreePages:\r
1012 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);\r
1013 break;\r
1014 case MemoryProfileActionFreePool:\r
1015 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);\r
1016 break;\r
1017 default:\r
1018 ASSERT (FALSE);\r
1019 AllocInfoData = NULL;\r
1020 break;\r
1021 }\r
1022 if (AllocInfoData != NULL) {\r
1023 DriverInfoData = ThisDriverInfoData;\r
1024 break;\r
1025 }\r
1026 }\r
1027\r
1028 if (AllocInfoData == NULL) {\r
1029 //\r
1030 // No matched allocate operation is found for this free operation.\r
1031 // It is because the specified memory type allocate operation has been\r
1032 // filtered by CoreNeedRecordProfile(), but free operations have no\r
1033 // memory type information, they can not be filtered by CoreNeedRecordProfile().\r
1034 // Then, they will be filtered here.\r
1035 //\r
1036 return FALSE;\r
1037 }\r
1038 }\r
1039\r
1040 Context = &ContextData->Context;\r
1041 DriverInfo = &DriverInfoData->DriverInfo;\r
1042 AllocInfo = &AllocInfoData->AllocInfo;\r
1043\r
1044 ProfileMemoryIndex = GetProfileMemoryIndex (AllocInfo->MemoryType);\r
1045\r
1046 Context->CurrentTotalUsage -= AllocInfo->Size;\r
1047 Context->CurrentTotalUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;\r
1048\r
1049 DriverInfo->CurrentUsage -= AllocInfo->Size;\r
1050 DriverInfo->CurrentUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;\r
1051 DriverInfo->AllocRecordCount --;\r
1052\r
1053 RemoveEntryList (&AllocInfoData->Link);\r
1054\r
1055 if (Action == MemoryProfileActionFreePages) {\r
1056 if (AllocInfo->Buffer != (PHYSICAL_ADDRESS) (UINTN) Buffer) {\r
1057 CoreUpdateProfileAllocate (\r
1058 AllocInfo->CallerAddress,\r
1059 MemoryProfileActionAllocatePages,\r
1060 AllocInfo->MemoryType,\r
1061 (UINTN) ((PHYSICAL_ADDRESS) (UINTN) Buffer - AllocInfo->Buffer),\r
1062 (VOID *) (UINTN) AllocInfo->Buffer\r
1063 );\r
1064 }\r
1065 if (AllocInfo->Buffer + AllocInfo->Size != ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)) {\r
1066 CoreUpdateProfileAllocate (\r
1067 AllocInfo->CallerAddress,\r
1068 MemoryProfileActionAllocatePages,\r
1069 AllocInfo->MemoryType,\r
1070 (UINTN) ((AllocInfo->Buffer + AllocInfo->Size) - ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)),\r
1071 (VOID *) ((UINTN) Buffer + Size)\r
1072 );\r
1073 }\r
1074 }\r
1075\r
1076 //\r
1077 // Use CoreInternalFreePool() that will not update profile for this FreePool action.\r
1078 //\r
1079 CoreInternalFreePool (AllocInfoData);\r
1080\r
1081 return TRUE;\r
1082}\r
1083\r
1084/**\r
1085 Update memory profile information.\r
1086\r
1087 @param CallerAddress Address of caller who call Allocate or Free.\r
1088 @param Action This Allocate or Free action.\r
1089 @param MemoryType Memory type.\r
1090 @param Size Buffer size.\r
1091 @param Buffer Buffer address.\r
1092\r
1093 @retval TRUE Profile udpate success.\r
1094 @retval FALSE Profile update fail.\r
1095\r
1096**/\r
1097BOOLEAN\r
1098CoreUpdateProfile (\r
1099 IN PHYSICAL_ADDRESS CallerAddress,\r
1100 IN MEMORY_PROFILE_ACTION Action,\r
1101 IN EFI_MEMORY_TYPE MemoryType, // Valid for AllocatePages/AllocatePool\r
1102 IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool\r
1103 IN VOID *Buffer\r
1104 )\r
1105{\r
1106 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1107\r
1108 if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {\r
1109 return FALSE;\r
1110 }\r
1111\r
1112 if (!mMemoryProfileRecordingStatus) {\r
1113 return FALSE;\r
1114 }\r
1115\r
1116 //\r
1117 // Free operations have no memory type information, so skip the check.\r
1118 //\r
1119 if ((Action == MemoryProfileActionAllocatePages) || (Action == MemoryProfileActionAllocatePool)) {\r
1120 //\r
1121 // Only record limited MemoryType.\r
1122 //\r
1123 if (!CoreNeedRecordProfile (MemoryType)) {\r
1124 return FALSE;\r
1125 }\r
1126 }\r
1127\r
1128 ContextData = GetMemoryProfileContext ();\r
1129 if (ContextData == NULL) {\r
1130 return FALSE;\r
1131 }\r
1132\r
1133 switch (Action) {\r
1134 case MemoryProfileActionAllocatePages:\r
1135 CoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer);\r
1136 break;\r
1137 case MemoryProfileActionFreePages:\r
1138 CoreUpdateProfileFree (CallerAddress, Action, Size, Buffer);\r
1139 break;\r
1140 case MemoryProfileActionAllocatePool:\r
1141 CoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer);\r
1142 break;\r
1143 case MemoryProfileActionFreePool:\r
1144 CoreUpdateProfileFree (CallerAddress, Action, 0, Buffer);\r
1145 break;\r
1146 default:\r
1147 ASSERT (FALSE);\r
1148 break;\r
1149 }\r
1150 return TRUE;\r
1151}\r
1152\r
1153////////////////////\r
1154\r
1155/**\r
1156 Get memory profile data size.\r
1157\r
1158 @return Memory profile data size.\r
1159\r
1160**/\r
1161UINTN\r
1162MemoryProfileGetDataSize (\r
1163 VOID\r
1164 )\r
1165{\r
1166 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1167 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
1168 LIST_ENTRY *DriverInfoList;\r
1169 LIST_ENTRY *DriverLink;\r
1170 UINTN TotalSize;\r
1171\r
1172\r
1173 ContextData = GetMemoryProfileContext ();\r
1174 if (ContextData == NULL) {\r
1175 return 0;\r
1176 }\r
1177\r
1178 TotalSize = sizeof (MEMORY_PROFILE_CONTEXT);\r
1179 TotalSize += sizeof (MEMORY_PROFILE_DRIVER_INFO) * (UINTN) ContextData->Context.ImageCount;\r
1180\r
1181 DriverInfoList = ContextData->DriverInfoList;\r
1182 for (DriverLink = DriverInfoList->ForwardLink;\r
1183 DriverLink != DriverInfoList;\r
1184 DriverLink = DriverLink->ForwardLink) {\r
1185 DriverInfoData = CR (\r
1186 DriverLink,\r
1187 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
1188 Link,\r
1189 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
1190 );\r
1191 TotalSize += sizeof (MEMORY_PROFILE_ALLOC_INFO) * (UINTN) DriverInfoData->DriverInfo.AllocRecordCount;\r
1192 }\r
1193\r
1194 return TotalSize;\r
1195}\r
1196\r
1197/**\r
1198 Copy memory profile data.\r
1199\r
1200 @param ProfileBuffer The buffer to hold memory profile data.\r
1201\r
1202**/\r
1203VOID\r
1204MemoryProfileCopyData (\r
1205 IN VOID *ProfileBuffer\r
1206 )\r
1207{\r
1208 MEMORY_PROFILE_CONTEXT *Context;\r
1209 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
1210 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
1211 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1212 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
1213 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
1214 LIST_ENTRY *DriverInfoList;\r
1215 LIST_ENTRY *DriverLink;\r
1216 LIST_ENTRY *AllocInfoList;\r
1217 LIST_ENTRY *AllocLink;\r
1218\r
1219 ContextData = GetMemoryProfileContext ();\r
1220 if (ContextData == NULL) {\r
1221 return ;\r
1222 }\r
1223\r
1224 Context = ProfileBuffer;\r
1225 CopyMem (Context, &ContextData->Context, sizeof (MEMORY_PROFILE_CONTEXT));\r
1226 DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) (Context + 1);\r
1227\r
1228 DriverInfoList = ContextData->DriverInfoList;\r
1229 for (DriverLink = DriverInfoList->ForwardLink;\r
1230 DriverLink != DriverInfoList;\r
1231 DriverLink = DriverLink->ForwardLink) {\r
1232 DriverInfoData = CR (\r
1233 DriverLink,\r
1234 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
1235 Link,\r
1236 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
1237 );\r
1238 CopyMem (DriverInfo, &DriverInfoData->DriverInfo, sizeof (MEMORY_PROFILE_DRIVER_INFO));\r
1239 AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) (DriverInfo + 1);\r
1240\r
1241 AllocInfoList = DriverInfoData->AllocInfoList;\r
1242 for (AllocLink = AllocInfoList->ForwardLink;\r
1243 AllocLink != AllocInfoList;\r
1244 AllocLink = AllocLink->ForwardLink) {\r
1245 AllocInfoData = CR (\r
1246 AllocLink,\r
1247 MEMORY_PROFILE_ALLOC_INFO_DATA,\r
1248 Link,\r
1249 MEMORY_PROFILE_ALLOC_INFO_SIGNATURE\r
1250 );\r
1251 CopyMem (AllocInfo, &AllocInfoData->AllocInfo, sizeof (MEMORY_PROFILE_ALLOC_INFO));\r
1252 AllocInfo += 1;\r
1253 }\r
1254\r
1255 DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) ((UINTN) (DriverInfo + 1) + sizeof (MEMORY_PROFILE_ALLOC_INFO) * (UINTN) DriverInfo->AllocRecordCount);\r
1256 }\r
1257}\r
1258\r
1259/**\r
1260 Get memory profile data.\r
1261\r
1262 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.\r
1263 @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.\r
1264 On return, points to the size of the data returned in ProfileBuffer.\r
1265 @param[out] ProfileBuffer Profile buffer.\r
1266 \r
1267 @return EFI_SUCCESS Get the memory profile data successfully.\r
1268 @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data. \r
1269 ProfileSize is updated with the size required.\r
1270\r
1271**/\r
1272EFI_STATUS\r
1273EFIAPI\r
1274ProfileProtocolGetData (\r
1275 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,\r
1276 IN OUT UINT64 *ProfileSize,\r
1277 OUT VOID *ProfileBuffer\r
1278 )\r
1279{\r
1280 UINTN Size;\r
1281 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1282 BOOLEAN MemoryProfileRecordingStatus;\r
1283\r
1284 ContextData = GetMemoryProfileContext ();\r
1285 if (ContextData == NULL) {\r
1286 return EFI_UNSUPPORTED;\r
1287 }\r
1288\r
1289 MemoryProfileRecordingStatus = mMemoryProfileRecordingStatus;\r
1290 mMemoryProfileRecordingStatus = FALSE;\r
1291\r
1292 Size = MemoryProfileGetDataSize ();\r
1293\r
1294 if (*ProfileSize < Size) {\r
1295 *ProfileSize = Size;\r
1296 mMemoryProfileRecordingStatus = MemoryProfileRecordingStatus;\r
1297 return EFI_BUFFER_TOO_SMALL;\r
1298 }\r
1299\r
1300 *ProfileSize = Size;\r
1301 MemoryProfileCopyData (ProfileBuffer);\r
1302\r
1303 mMemoryProfileRecordingStatus = MemoryProfileRecordingStatus;\r
1304 return EFI_SUCCESS;\r
1305}\r
1306\r
1307/**\r
1308 Register image to memory profile.\r
1309\r
1310 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.\r
1311 @param[in] FilePath File path of the image.\r
1312 @param[in] ImageBase Image base address.\r
1313 @param[in] ImageSize Image size.\r
1314 @param[in] FileType File type of the image.\r
1315\r
1316 @return EFI_SUCCESS Register success.\r
1317 @return EFI_OUT_OF_RESOURCE No enough resource for this register.\r
1318\r
1319**/\r
1320EFI_STATUS\r
1321EFIAPI\r
1322ProfileProtocolRegisterImage (\r
1323 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,\r
1324 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1325 IN PHYSICAL_ADDRESS ImageBase,\r
1326 IN UINT64 ImageSize,\r
1327 IN EFI_FV_FILETYPE FileType\r
1328 )\r
1329{\r
1330 EFI_STATUS Status;\r
1331 LOADED_IMAGE_PRIVATE_DATA DriverEntry;\r
1332 VOID *EntryPointInImage;\r
1333\r
1334 ZeroMem (&DriverEntry, sizeof (DriverEntry));\r
1335 DriverEntry.Info.FilePath = FilePath;\r
1336 DriverEntry.ImageContext.ImageAddress = ImageBase;\r
1337 DriverEntry.ImageContext.ImageSize = ImageSize;\r
1338 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);\r
1339 ASSERT_EFI_ERROR (Status);\r
1340 DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;\r
1341 DriverEntry.ImageContext.ImageType = InternalPeCoffGetSubsystem ((VOID *) (UINTN) ImageBase);\r
1342\r
1343 return RegisterMemoryProfileImage (&DriverEntry, FileType) ? EFI_SUCCESS: EFI_OUT_OF_RESOURCES;\r
1344}\r
1345\r
1346/**\r
1347 Unregister image from memory profile.\r
1348\r
1349 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.\r
1350 @param[in] FilePath File path of the image.\r
1351 @param[in] ImageBase Image base address.\r
1352 @param[in] ImageSize Image size.\r
1353\r
1354 @return EFI_SUCCESS Unregister success.\r
1355 @return EFI_NOT_FOUND The image is not found.\r
1356\r
1357**/\r
1358EFI_STATUS\r
1359EFIAPI\r
1360ProfileProtocolUnregisterImage (\r
1361 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,\r
1362 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1363 IN PHYSICAL_ADDRESS ImageBase,\r
1364 IN UINT64 ImageSize\r
1365 )\r
1366{\r
1367 EFI_STATUS Status;\r
1368 LOADED_IMAGE_PRIVATE_DATA DriverEntry;\r
1369 VOID *EntryPointInImage;\r
1370\r
1371 ZeroMem (&DriverEntry, sizeof (DriverEntry));\r
1372 DriverEntry.Info.FilePath = FilePath;\r
1373 DriverEntry.ImageContext.ImageAddress = ImageBase;\r
1374 DriverEntry.ImageContext.ImageSize = ImageSize;\r
1375 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);\r
1376 ASSERT_EFI_ERROR (Status);\r
1377 DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;\r
1378\r
1379 return UnregisterMemoryProfileImage (&DriverEntry) ? EFI_SUCCESS: EFI_NOT_FOUND;\r
1380}\r
1381\r
1382////////////////////\r