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