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