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