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