]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Mem / MemoryProfileRecord.c
1 /** @file
2 Support routines for UEFI memory profile.
3
4 Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "DxeMain.h"
10 #include "Imem.h"
11
12 #define IS_UEFI_MEMORY_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT0) != 0)
13
14 #define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
15 ((ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)))
16
17 typedef struct {
18 UINT32 Signature;
19 MEMORY_PROFILE_CONTEXT Context;
20 LIST_ENTRY *DriverInfoList;
21 } MEMORY_PROFILE_CONTEXT_DATA;
22
23 typedef struct {
24 UINT32 Signature;
25 MEMORY_PROFILE_DRIVER_INFO DriverInfo;
26 LIST_ENTRY *AllocInfoList;
27 CHAR8 *PdbString;
28 LIST_ENTRY Link;
29 } MEMORY_PROFILE_DRIVER_INFO_DATA;
30
31 typedef struct {
32 UINT32 Signature;
33 MEMORY_PROFILE_ALLOC_INFO AllocInfo;
34 CHAR8 *ActionString;
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 GLOBAL_REMOVE_IF_UNREFERENCED EFI_LOCK mMemoryProfileLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
61 GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mMemoryProfileGettingStatus = FALSE;
62 GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mMemoryProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
63 GLOBAL_REMOVE_IF_UNREFERENCED EFI_DEVICE_PATH_PROTOCOL *mMemoryProfileDriverPath;
64 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mMemoryProfileDriverPathSize;
65
66 /**
67 Get memory profile data.
68
69 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
70 @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.
71 On return, points to the size of the data returned in ProfileBuffer.
72 @param[out] ProfileBuffer Profile buffer.
73
74 @return EFI_SUCCESS Get the memory profile data successfully.
75 @return EFI_UNSUPPORTED Memory profile is unsupported.
76 @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data.
77 ProfileSize is updated with the size required.
78
79 **/
80 EFI_STATUS
81 EFIAPI
82 ProfileProtocolGetData (
83 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
84 IN OUT UINT64 *ProfileSize,
85 OUT VOID *ProfileBuffer
86 );
87
88 /**
89 Register image to memory profile.
90
91 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
92 @param[in] FilePath File path of the image.
93 @param[in] ImageBase Image base address.
94 @param[in] ImageSize Image size.
95 @param[in] FileType File type of the image.
96
97 @return EFI_SUCCESS Register successfully.
98 @return EFI_UNSUPPORTED Memory profile is unsupported,
99 or memory profile for the image is not required.
100 @return EFI_OUT_OF_RESOURCE No enough resource for this register.
101
102 **/
103 EFI_STATUS
104 EFIAPI
105 ProfileProtocolRegisterImage (
106 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
107 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
108 IN PHYSICAL_ADDRESS ImageBase,
109 IN UINT64 ImageSize,
110 IN EFI_FV_FILETYPE FileType
111 );
112
113 /**
114 Unregister image from memory profile.
115
116 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
117 @param[in] FilePath File path of the image.
118 @param[in] ImageBase Image base address.
119 @param[in] ImageSize Image size.
120
121 @return EFI_SUCCESS Unregister successfully.
122 @return EFI_UNSUPPORTED Memory profile is unsupported,
123 or memory profile for the image is not required.
124 @return EFI_NOT_FOUND The image is not found.
125
126 **/
127 EFI_STATUS
128 EFIAPI
129 ProfileProtocolUnregisterImage (
130 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
131 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
132 IN PHYSICAL_ADDRESS ImageBase,
133 IN UINT64 ImageSize
134 );
135
136 /**
137 Get memory profile recording state.
138
139 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
140 @param[out] RecordingState Recording state.
141
142 @return EFI_SUCCESS Memory profile recording state is returned.
143 @return EFI_UNSUPPORTED Memory profile is unsupported.
144 @return EFI_INVALID_PARAMETER RecordingState is NULL.
145
146 **/
147 EFI_STATUS
148 EFIAPI
149 ProfileProtocolGetRecordingState (
150 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
151 OUT BOOLEAN *RecordingState
152 );
153
154 /**
155 Set memory profile recording state.
156
157 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
158 @param[in] RecordingState Recording state.
159
160 @return EFI_SUCCESS Set memory profile recording state successfully.
161 @return EFI_UNSUPPORTED Memory profile is unsupported.
162
163 **/
164 EFI_STATUS
165 EFIAPI
166 ProfileProtocolSetRecordingState (
167 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
168 IN BOOLEAN RecordingState
169 );
170
171 /**
172 Record memory profile of multilevel caller.
173
174 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
175 @param[in] CallerAddress Address of caller.
176 @param[in] Action Memory profile action.
177 @param[in] MemoryType Memory type.
178 EfiMaxMemoryType means the MemoryType is unknown.
179 @param[in] Buffer Buffer address.
180 @param[in] Size Buffer size.
181 @param[in] ActionString String for memory profile action.
182 Only needed for user defined allocate action.
183
184 @return EFI_SUCCESS Memory profile is updated.
185 @return EFI_UNSUPPORTED Memory profile is unsupported,
186 or memory profile for the image is not required,
187 or memory profile for the memory type is not required.
188 @return EFI_ACCESS_DENIED It is during memory profile data getting.
189 @return EFI_ABORTED Memory profile recording is not enabled.
190 @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
191 @return EFI_NOT_FOUND No matched allocate info found for free action.
192
193 **/
194 EFI_STATUS
195 EFIAPI
196 ProfileProtocolRecord (
197 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
198 IN PHYSICAL_ADDRESS CallerAddress,
199 IN MEMORY_PROFILE_ACTION Action,
200 IN EFI_MEMORY_TYPE MemoryType,
201 IN VOID *Buffer,
202 IN UINTN Size,
203 IN CHAR8 *ActionString OPTIONAL
204 );
205
206 GLOBAL_REMOVE_IF_UNREFERENCED EDKII_MEMORY_PROFILE_PROTOCOL mProfileProtocol = {
207 ProfileProtocolGetData,
208 ProfileProtocolRegisterImage,
209 ProfileProtocolUnregisterImage,
210 ProfileProtocolGetRecordingState,
211 ProfileProtocolSetRecordingState,
212 ProfileProtocolRecord,
213 };
214
215 /**
216 Acquire lock on mMemoryProfileLock.
217 **/
218 VOID
219 CoreAcquireMemoryProfileLock (
220 VOID
221 )
222 {
223 CoreAcquireLock (&mMemoryProfileLock);
224 }
225
226 /**
227 Release lock on mMemoryProfileLock.
228 **/
229 VOID
230 CoreReleaseMemoryProfileLock (
231 VOID
232 )
233 {
234 CoreReleaseLock (&mMemoryProfileLock);
235 }
236
237 /**
238 Return memory profile context.
239
240 @return Memory profile context.
241
242 **/
243 MEMORY_PROFILE_CONTEXT_DATA *
244 GetMemoryProfileContext (
245 VOID
246 )
247 {
248 return mMemoryProfileContextPtr;
249 }
250
251 /**
252 Retrieves and returns the Subsystem of a PE/COFF image that has been loaded into system memory.
253 If Pe32Data is NULL, then ASSERT().
254
255 @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.
256
257 @return The Subsystem of the PE/COFF image.
258
259 **/
260 UINT16
261 InternalPeCoffGetSubsystem (
262 IN VOID *Pe32Data
263 )
264 {
265 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
266 EFI_IMAGE_DOS_HEADER *DosHdr;
267 UINT16 Magic;
268
269 ASSERT (Pe32Data != NULL);
270
271 DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;
272 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
273 //
274 // DOS image header is present, so read the PE header after the DOS image header.
275 //
276 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
277 } else {
278 //
279 // DOS image header is not present, so PE header is at the image base.
280 //
281 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;
282 }
283
284 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
285 return Hdr.Te->Subsystem;
286 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
287 Magic = Hdr.Pe32->OptionalHeader.Magic;
288 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
289 return Hdr.Pe32->OptionalHeader.Subsystem;
290 } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
291 return Hdr.Pe32Plus->OptionalHeader.Subsystem;
292 }
293 }
294
295 return 0x0000;
296 }
297
298 /**
299 Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded
300 into system memory with the PE/COFF Loader Library functions.
301
302 Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry
303 point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then
304 return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS.
305 If Pe32Data is NULL, then ASSERT().
306 If EntryPoint is NULL, then ASSERT().
307
308 @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.
309 @param EntryPoint The pointer to entry point to the PE/COFF image to return.
310
311 @retval RETURN_SUCCESS EntryPoint was returned.
312 @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image.
313
314 **/
315 RETURN_STATUS
316 InternalPeCoffGetEntryPoint (
317 IN VOID *Pe32Data,
318 OUT VOID **EntryPoint
319 )
320 {
321 EFI_IMAGE_DOS_HEADER *DosHdr;
322 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
323
324 ASSERT (Pe32Data != NULL);
325 ASSERT (EntryPoint != NULL);
326
327 DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;
328 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
329 //
330 // DOS image header is present, so read the PE header after the DOS image header.
331 //
332 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
333 } else {
334 //
335 // DOS image header is not present, so PE header is at the image base.
336 //
337 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;
338 }
339
340 //
341 // Calculate the entry point relative to the start of the image.
342 // AddressOfEntryPoint is common for PE32 & PE32+
343 //
344 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
345 *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);
346 return RETURN_SUCCESS;
347 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
348 *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff));
349 return RETURN_SUCCESS;
350 }
351
352 return RETURN_UNSUPPORTED;
353 }
354
355 /**
356 Build driver info.
357
358 @param ContextData Memory profile context.
359 @param FileName File name of the image.
360 @param ImageBase Image base address.
361 @param ImageSize Image size.
362 @param EntryPoint Entry point of the image.
363 @param ImageSubsystem Image subsystem of the image.
364 @param FileType File type of the image.
365
366 @return Pointer to memory profile driver info.
367
368 **/
369 MEMORY_PROFILE_DRIVER_INFO_DATA *
370 BuildDriverInfo (
371 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
372 IN EFI_GUID *FileName,
373 IN PHYSICAL_ADDRESS ImageBase,
374 IN UINT64 ImageSize,
375 IN PHYSICAL_ADDRESS EntryPoint,
376 IN UINT16 ImageSubsystem,
377 IN EFI_FV_FILETYPE FileType
378 )
379 {
380 EFI_STATUS Status;
381 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
382 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
383 VOID *EntryPointInImage;
384 CHAR8 *PdbString;
385 UINTN PdbSize;
386 UINTN PdbOccupiedSize;
387
388 PdbSize = 0;
389 PdbOccupiedSize = 0;
390 PdbString = NULL;
391 if (ImageBase != 0) {
392 PdbString = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageBase);
393 if (PdbString != NULL) {
394 PdbSize = AsciiStrSize (PdbString);
395 PdbOccupiedSize = GET_OCCUPIED_SIZE (PdbSize, sizeof (UINT64));
396 }
397 }
398
399 //
400 // Use CoreInternalAllocatePool() that will not update profile for this AllocatePool action.
401 //
402 Status = CoreInternalAllocatePool (
403 EfiBootServicesData,
404 sizeof (*DriverInfoData) + sizeof (LIST_ENTRY) + PdbSize,
405 (VOID **) &DriverInfoData
406 );
407 if (EFI_ERROR (Status)) {
408 return NULL;
409 }
410 ASSERT (DriverInfoData != NULL);
411
412 ZeroMem (DriverInfoData, sizeof (*DriverInfoData));
413
414 DriverInfo = &DriverInfoData->DriverInfo;
415 DriverInfoData->Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
416 DriverInfo->Header.Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
417 DriverInfo->Header.Length = (UINT16) (sizeof (MEMORY_PROFILE_DRIVER_INFO) + PdbOccupiedSize);
418 DriverInfo->Header.Revision = MEMORY_PROFILE_DRIVER_INFO_REVISION;
419 if (FileName != NULL) {
420 CopyMem (&DriverInfo->FileName, FileName, sizeof (EFI_GUID));
421 }
422 DriverInfo->ImageBase = ImageBase;
423 DriverInfo->ImageSize = ImageSize;
424 DriverInfo->EntryPoint = EntryPoint;
425 DriverInfo->ImageSubsystem = ImageSubsystem;
426 if ((EntryPoint != 0) && ((EntryPoint < ImageBase) || (EntryPoint >= (ImageBase + ImageSize)))) {
427 //
428 // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
429 // So patch ImageBuffer here to align the EntryPoint.
430 //
431 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);
432 ASSERT_EFI_ERROR (Status);
433 DriverInfo->ImageBase = ImageBase + EntryPoint - (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
434 }
435 DriverInfo->FileType = FileType;
436 DriverInfoData->AllocInfoList = (LIST_ENTRY *) (DriverInfoData + 1);
437 InitializeListHead (DriverInfoData->AllocInfoList);
438 DriverInfo->CurrentUsage = 0;
439 DriverInfo->PeakUsage = 0;
440 DriverInfo->AllocRecordCount = 0;
441 if (PdbSize != 0) {
442 DriverInfo->PdbStringOffset = (UINT16) sizeof (MEMORY_PROFILE_DRIVER_INFO);
443 DriverInfoData->PdbString = (CHAR8 *) (DriverInfoData->AllocInfoList + 1);
444 CopyMem (DriverInfoData->PdbString, PdbString, PdbSize);
445 } else {
446 DriverInfo->PdbStringOffset = 0;
447 DriverInfoData->PdbString = NULL;
448 }
449
450 InsertTailList (ContextData->DriverInfoList, &DriverInfoData->Link);
451 ContextData->Context.ImageCount ++;
452 ContextData->Context.TotalImageSize += DriverInfo->ImageSize;
453
454 return DriverInfoData;
455 }
456
457 /**
458 Return if record for this driver is needed..
459
460 @param DriverFilePath Driver file path.
461
462 @retval TRUE Record for this driver is needed.
463 @retval FALSE Record for this driver is not needed.
464
465 **/
466 BOOLEAN
467 NeedRecordThisDriver (
468 IN EFI_DEVICE_PATH_PROTOCOL *DriverFilePath
469 )
470 {
471 EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
472 EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance;
473 UINTN DevicePathSize;
474 UINTN FilePathSize;
475
476 if (!IsDevicePathValid (mMemoryProfileDriverPath, mMemoryProfileDriverPathSize)) {
477 //
478 // Invalid Device Path means record all.
479 //
480 return TRUE;
481 }
482
483 //
484 // Record FilePath without END node.
485 //
486 FilePathSize = GetDevicePathSize (DriverFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
487
488 DevicePathInstance = mMemoryProfileDriverPath;
489 do {
490 //
491 // Find END node (it might be END_ENTIRE or END_INSTANCE).
492 //
493 TmpDevicePath = DevicePathInstance;
494 while (!IsDevicePathEndType (TmpDevicePath)) {
495 TmpDevicePath = NextDevicePathNode (TmpDevicePath);
496 }
497
498 //
499 // Do not compare END node.
500 //
501 DevicePathSize = (UINTN)TmpDevicePath - (UINTN)DevicePathInstance;
502 if ((FilePathSize == DevicePathSize) &&
503 (CompareMem (DriverFilePath, DevicePathInstance, DevicePathSize) == 0)) {
504 return TRUE;
505 }
506
507 //
508 // Get next instance.
509 //
510 DevicePathInstance = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN)DevicePathInstance + DevicePathSize + DevicePathNodeLength(TmpDevicePath));
511 } while (DevicePathSubType (TmpDevicePath) != END_ENTIRE_DEVICE_PATH_SUBTYPE);
512
513 return FALSE;
514 }
515
516 /**
517 Register DXE Core to memory profile.
518
519 @param HobStart The start address of the HOB.
520 @param ContextData Memory profile context.
521
522 @retval TRUE Register success.
523 @retval FALSE Register fail.
524
525 **/
526 BOOLEAN
527 RegisterDxeCore (
528 IN VOID *HobStart,
529 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData
530 )
531 {
532 EFI_PEI_HOB_POINTERS DxeCoreHob;
533 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
534 PHYSICAL_ADDRESS ImageBase;
535 UINT8 TempBuffer[sizeof(MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH_PROTOCOL)];
536 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
537
538 ASSERT (ContextData != NULL);
539
540 //
541 // Searching for image hob
542 //
543 DxeCoreHob.Raw = HobStart;
544 while ((DxeCoreHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, DxeCoreHob.Raw)) != NULL) {
545 if (CompareGuid (&DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {
546 //
547 // Find Dxe Core HOB
548 //
549 break;
550 }
551 DxeCoreHob.Raw = GET_NEXT_HOB (DxeCoreHob);
552 }
553 ASSERT (DxeCoreHob.Raw != NULL);
554
555 FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempBuffer;
556 EfiInitializeFwVolDevicepathNode (FilePath, &DxeCoreHob.MemoryAllocationModule->ModuleName);
557 SetDevicePathEndNode (FilePath + 1);
558
559 if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *) FilePath)) {
560 return FALSE;
561 }
562
563 ImageBase = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress;
564 DriverInfoData = BuildDriverInfo (
565 ContextData,
566 &DxeCoreHob.MemoryAllocationModule->ModuleName,
567 ImageBase,
568 DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength,
569 DxeCoreHob.MemoryAllocationModule->EntryPoint,
570 InternalPeCoffGetSubsystem ((VOID *) (UINTN) ImageBase),
571 EFI_FV_FILETYPE_DXE_CORE
572 );
573 if (DriverInfoData == NULL) {
574 return FALSE;
575 }
576
577 return TRUE;
578 }
579
580 /**
581 Initialize memory profile.
582
583 @param HobStart The start address of the HOB.
584
585 **/
586 VOID
587 MemoryProfileInit (
588 IN VOID *HobStart
589 )
590 {
591 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
592
593 if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
594 return;
595 }
596
597 ContextData = GetMemoryProfileContext ();
598 if (ContextData != NULL) {
599 return;
600 }
601
602 mMemoryProfileGettingStatus = FALSE;
603 if ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT7) != 0) {
604 mMemoryProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
605 } else {
606 mMemoryProfileRecordingEnable = MEMORY_PROFILE_RECORDING_ENABLE;
607 }
608 mMemoryProfileDriverPathSize = PcdGetSize (PcdMemoryProfileDriverPath);
609 mMemoryProfileDriverPath = AllocateCopyPool (mMemoryProfileDriverPathSize, PcdGetPtr (PcdMemoryProfileDriverPath));
610 mMemoryProfileContextPtr = &mMemoryProfileContext;
611
612 RegisterDxeCore (HobStart, &mMemoryProfileContext);
613
614 DEBUG ((EFI_D_INFO, "MemoryProfileInit MemoryProfileContext - 0x%x\n", &mMemoryProfileContext));
615 }
616
617 /**
618 Install memory profile protocol.
619
620 **/
621 VOID
622 MemoryProfileInstallProtocol (
623 VOID
624 )
625 {
626 EFI_HANDLE Handle;
627 EFI_STATUS Status;
628
629 if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
630 return;
631 }
632
633 Handle = NULL;
634 Status = CoreInstallMultipleProtocolInterfaces (
635 &Handle,
636 &gEdkiiMemoryProfileGuid,
637 &mProfileProtocol,
638 NULL
639 );
640 ASSERT_EFI_ERROR (Status);
641 }
642
643 /**
644 Get the GUID file name from the file path.
645
646 @param FilePath File path.
647
648 @return The GUID file name from the file path.
649
650 **/
651 EFI_GUID *
652 GetFileNameFromFilePath (
653 IN EFI_DEVICE_PATH_PROTOCOL *FilePath
654 )
655 {
656 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *ThisFilePath;
657 EFI_GUID *FileName;
658
659 FileName = NULL;
660 if (FilePath != NULL) {
661 ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) FilePath;
662 while (!IsDevicePathEnd (ThisFilePath)) {
663 FileName = EfiGetNameGuidFromFwVolDevicePathNode (ThisFilePath);
664 if (FileName != NULL) {
665 break;
666 }
667 ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) NextDevicePathNode (ThisFilePath);
668 }
669 }
670
671 return FileName;
672 }
673
674 /**
675 Register image to memory profile.
676
677 @param DriverEntry Image info.
678 @param FileType Image file type.
679
680 @return EFI_SUCCESS Register successfully.
681 @return EFI_UNSUPPORTED Memory profile is unsupported,
682 or memory profile for the image is not required.
683 @return EFI_OUT_OF_RESOURCES No enough resource for this register.
684
685 **/
686 EFI_STATUS
687 RegisterMemoryProfileImage (
688 IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry,
689 IN EFI_FV_FILETYPE FileType
690 )
691 {
692 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
693 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
694
695 if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
696 return EFI_UNSUPPORTED;
697 }
698
699 if (!NeedRecordThisDriver (DriverEntry->Info.FilePath)) {
700 return EFI_UNSUPPORTED;
701 }
702
703 ContextData = GetMemoryProfileContext ();
704 if (ContextData == NULL) {
705 return EFI_UNSUPPORTED;
706 }
707
708 DriverInfoData = BuildDriverInfo (
709 ContextData,
710 GetFileNameFromFilePath (DriverEntry->Info.FilePath),
711 DriverEntry->ImageContext.ImageAddress,
712 DriverEntry->ImageContext.ImageSize,
713 DriverEntry->ImageContext.EntryPoint,
714 DriverEntry->ImageContext.ImageType,
715 FileType
716 );
717 if (DriverInfoData == NULL) {
718 return EFI_OUT_OF_RESOURCES;
719 }
720
721 return EFI_SUCCESS;
722 }
723
724 /**
725 Search image from memory profile.
726
727 @param ContextData Memory profile context.
728 @param FileName Image file name.
729 @param Address Image Address.
730
731 @return Pointer to memory profile driver info.
732
733 **/
734 MEMORY_PROFILE_DRIVER_INFO_DATA *
735 GetMemoryProfileDriverInfoByFileNameAndAddress (
736 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
737 IN EFI_GUID *FileName,
738 IN PHYSICAL_ADDRESS Address
739 )
740 {
741 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
742 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
743 LIST_ENTRY *DriverLink;
744 LIST_ENTRY *DriverInfoList;
745
746 DriverInfoList = ContextData->DriverInfoList;
747
748 for (DriverLink = DriverInfoList->ForwardLink;
749 DriverLink != DriverInfoList;
750 DriverLink = DriverLink->ForwardLink) {
751 DriverInfoData = CR (
752 DriverLink,
753 MEMORY_PROFILE_DRIVER_INFO_DATA,
754 Link,
755 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
756 );
757 DriverInfo = &DriverInfoData->DriverInfo;
758 if ((CompareGuid (&DriverInfo->FileName, FileName)) &&
759 (Address >= DriverInfo->ImageBase) &&
760 (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {
761 return DriverInfoData;
762 }
763 }
764
765 return NULL;
766 }
767
768 /**
769 Search image from memory profile.
770 It will return image, if (Address >= ImageBuffer) AND (Address < ImageBuffer + ImageSize).
771
772 @param ContextData Memory profile context.
773 @param Address Image or Function address.
774
775 @return Pointer to memory profile driver info.
776
777 **/
778 MEMORY_PROFILE_DRIVER_INFO_DATA *
779 GetMemoryProfileDriverInfoFromAddress (
780 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
781 IN PHYSICAL_ADDRESS Address
782 )
783 {
784 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
785 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
786 LIST_ENTRY *DriverLink;
787 LIST_ENTRY *DriverInfoList;
788
789 DriverInfoList = ContextData->DriverInfoList;
790
791 for (DriverLink = DriverInfoList->ForwardLink;
792 DriverLink != DriverInfoList;
793 DriverLink = DriverLink->ForwardLink) {
794 DriverInfoData = CR (
795 DriverLink,
796 MEMORY_PROFILE_DRIVER_INFO_DATA,
797 Link,
798 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
799 );
800 DriverInfo = &DriverInfoData->DriverInfo;
801 if ((Address >= DriverInfo->ImageBase) &&
802 (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {
803 return DriverInfoData;
804 }
805 }
806
807 return NULL;
808 }
809
810 /**
811 Unregister image from memory profile.
812
813 @param DriverEntry Image info.
814
815 @return EFI_SUCCESS Unregister successfully.
816 @return EFI_UNSUPPORTED Memory profile is unsupported,
817 or memory profile for the image is not required.
818 @return EFI_NOT_FOUND The image is not found.
819
820 **/
821 EFI_STATUS
822 UnregisterMemoryProfileImage (
823 IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry
824 )
825 {
826 EFI_STATUS Status;
827 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
828 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
829 EFI_GUID *FileName;
830 PHYSICAL_ADDRESS ImageAddress;
831 VOID *EntryPointInImage;
832
833 if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
834 return EFI_UNSUPPORTED;
835 }
836
837 if (!NeedRecordThisDriver (DriverEntry->Info.FilePath)) {
838 return EFI_UNSUPPORTED;
839 }
840
841 ContextData = GetMemoryProfileContext ();
842 if (ContextData == NULL) {
843 return EFI_UNSUPPORTED;
844 }
845
846 DriverInfoData = NULL;
847 FileName = GetFileNameFromFilePath (DriverEntry->Info.FilePath);
848 ImageAddress = DriverEntry->ImageContext.ImageAddress;
849 if ((DriverEntry->ImageContext.EntryPoint < ImageAddress) || (DriverEntry->ImageContext.EntryPoint >= (ImageAddress + DriverEntry->ImageContext.ImageSize))) {
850 //
851 // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
852 // So patch ImageAddress here to align the EntryPoint.
853 //
854 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageAddress, &EntryPointInImage);
855 ASSERT_EFI_ERROR (Status);
856 ImageAddress = ImageAddress + (UINTN) DriverEntry->ImageContext.EntryPoint - (UINTN) EntryPointInImage;
857 }
858 if (FileName != NULL) {
859 DriverInfoData = GetMemoryProfileDriverInfoByFileNameAndAddress (ContextData, FileName, ImageAddress);
860 }
861 if (DriverInfoData == NULL) {
862 DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, ImageAddress);
863 }
864 if (DriverInfoData == NULL) {
865 return EFI_NOT_FOUND;
866 }
867
868 ContextData->Context.TotalImageSize -= DriverInfoData->DriverInfo.ImageSize;
869
870 // Keep the ImageBase for RVA calculation in Application.
871 //DriverInfoData->DriverInfo.ImageBase = 0;
872 DriverInfoData->DriverInfo.ImageSize = 0;
873
874 if (DriverInfoData->DriverInfo.PeakUsage == 0) {
875 ContextData->Context.ImageCount --;
876 RemoveEntryList (&DriverInfoData->Link);
877 //
878 // Use CoreInternalFreePool() that will not update profile for this FreePool action.
879 //
880 CoreInternalFreePool (DriverInfoData, NULL);
881 }
882
883 return EFI_SUCCESS;
884 }
885
886 /**
887 Return if this memory type needs to be recorded into memory profile.
888 If BIOS memory type (0 ~ EfiMaxMemoryType - 1), it checks bit (1 << MemoryType).
889 If OS memory type (0x80000000 ~ 0xFFFFFFFF), it checks bit63 - 0x8000000000000000.
890 If OEM memory type (0x70000000 ~ 0x7FFFFFFF), it checks bit62 - 0x4000000000000000.
891
892 @param MemoryType Memory type.
893
894 @retval TRUE This memory type need to be recorded.
895 @retval FALSE This memory type need not to be recorded.
896
897 **/
898 BOOLEAN
899 CoreNeedRecordProfile (
900 IN EFI_MEMORY_TYPE MemoryType
901 )
902 {
903 UINT64 TestBit;
904
905 if ((UINT32) MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
906 TestBit = BIT63;
907 } else if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
908 TestBit = BIT62;
909 } else {
910 TestBit = LShiftU64 (1, MemoryType);
911 }
912
913 if ((PcdGet64 (PcdMemoryProfileMemoryType) & TestBit) != 0) {
914 return TRUE;
915 } else {
916 return FALSE;
917 }
918 }
919
920 /**
921 Convert EFI memory type to profile memory index. The rule is:
922 If BIOS memory type (0 ~ EfiMaxMemoryType - 1), ProfileMemoryIndex = MemoryType.
923 If OS memory type (0x80000000 ~ 0xFFFFFFFF), ProfileMemoryIndex = EfiMaxMemoryType.
924 If OEM memory type (0x70000000 ~ 0x7FFFFFFF), ProfileMemoryIndex = EfiMaxMemoryType + 1.
925
926 @param MemoryType Memory type.
927
928 @return Profile memory index.
929
930 **/
931 UINTN
932 GetProfileMemoryIndex (
933 IN EFI_MEMORY_TYPE MemoryType
934 )
935 {
936 if ((UINT32) MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
937 return EfiMaxMemoryType;
938 } else if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
939 return EfiMaxMemoryType + 1;
940 } else {
941 return MemoryType;
942 }
943 }
944
945 /**
946 Update memory profile Allocate information.
947
948 @param CallerAddress Address of caller who call Allocate.
949 @param Action This Allocate action.
950 @param MemoryType Memory type.
951 @param Size Buffer size.
952 @param Buffer Buffer address.
953 @param ActionString String for memory profile action.
954
955 @return EFI_SUCCESS Memory profile is updated.
956 @return EFI_UNSUPPORTED Memory profile is unsupported,
957 or memory profile for the image is not required.
958 @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
959
960 **/
961 EFI_STATUS
962 CoreUpdateProfileAllocate (
963 IN PHYSICAL_ADDRESS CallerAddress,
964 IN MEMORY_PROFILE_ACTION Action,
965 IN EFI_MEMORY_TYPE MemoryType,
966 IN UINTN Size,
967 IN VOID *Buffer,
968 IN CHAR8 *ActionString OPTIONAL
969 )
970 {
971 EFI_STATUS Status;
972 MEMORY_PROFILE_CONTEXT *Context;
973 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
974 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
975 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
976 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
977 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
978 UINTN ProfileMemoryIndex;
979 MEMORY_PROFILE_ACTION BasicAction;
980 UINTN ActionStringSize;
981 UINTN ActionStringOccupiedSize;
982
983 BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
984
985 ContextData = GetMemoryProfileContext ();
986 if (ContextData == NULL) {
987 return EFI_UNSUPPORTED;
988 }
989
990 DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
991 if (DriverInfoData == NULL) {
992 return EFI_UNSUPPORTED;
993 }
994
995 ActionStringSize = 0;
996 ActionStringOccupiedSize = 0;
997 if (ActionString != NULL) {
998 ActionStringSize = AsciiStrSize (ActionString);
999 ActionStringOccupiedSize = GET_OCCUPIED_SIZE (ActionStringSize, sizeof (UINT64));
1000 }
1001
1002 //
1003 // Use CoreInternalAllocatePool() that will not update profile for this AllocatePool action.
1004 //
1005 AllocInfoData = NULL;
1006 Status = CoreInternalAllocatePool (
1007 EfiBootServicesData,
1008 sizeof (*AllocInfoData) + ActionStringSize,
1009 (VOID **) &AllocInfoData
1010 );
1011 if (EFI_ERROR (Status)) {
1012 return EFI_OUT_OF_RESOURCES;
1013 }
1014 ASSERT (AllocInfoData != NULL);
1015
1016 //
1017 // Only update SequenceCount if and only if it is basic action.
1018 //
1019 if (Action == BasicAction) {
1020 ContextData->Context.SequenceCount ++;
1021 }
1022
1023 AllocInfo = &AllocInfoData->AllocInfo;
1024 AllocInfoData->Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
1025 AllocInfo->Header.Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
1026 AllocInfo->Header.Length = (UINT16) (sizeof (MEMORY_PROFILE_ALLOC_INFO) + ActionStringOccupiedSize);
1027 AllocInfo->Header.Revision = MEMORY_PROFILE_ALLOC_INFO_REVISION;
1028 AllocInfo->CallerAddress = CallerAddress;
1029 AllocInfo->SequenceId = ContextData->Context.SequenceCount;
1030 AllocInfo->Action = Action;
1031 AllocInfo->MemoryType = MemoryType;
1032 AllocInfo->Buffer = (PHYSICAL_ADDRESS) (UINTN) Buffer;
1033 AllocInfo->Size = Size;
1034 if (ActionString != NULL) {
1035 AllocInfo->ActionStringOffset = (UINT16) sizeof (MEMORY_PROFILE_ALLOC_INFO);
1036 AllocInfoData->ActionString = (CHAR8 *) (AllocInfoData + 1);
1037 CopyMem (AllocInfoData->ActionString, ActionString, ActionStringSize);
1038 } else {
1039 AllocInfo->ActionStringOffset = 0;
1040 AllocInfoData->ActionString = NULL;
1041 }
1042
1043 InsertTailList (DriverInfoData->AllocInfoList, &AllocInfoData->Link);
1044
1045 Context = &ContextData->Context;
1046 DriverInfo = &DriverInfoData->DriverInfo;
1047 DriverInfo->AllocRecordCount ++;
1048
1049 //
1050 // Update summary if and only if it is basic action.
1051 //
1052 if (Action == BasicAction) {
1053 ProfileMemoryIndex = GetProfileMemoryIndex (MemoryType);
1054
1055 DriverInfo->CurrentUsage += Size;
1056 if (DriverInfo->PeakUsage < DriverInfo->CurrentUsage) {
1057 DriverInfo->PeakUsage = DriverInfo->CurrentUsage;
1058 }
1059 DriverInfo->CurrentUsageByType[ProfileMemoryIndex] += Size;
1060 if (DriverInfo->PeakUsageByType[ProfileMemoryIndex] < DriverInfo->CurrentUsageByType[ProfileMemoryIndex]) {
1061 DriverInfo->PeakUsageByType[ProfileMemoryIndex] = DriverInfo->CurrentUsageByType[ProfileMemoryIndex];
1062 }
1063
1064 Context->CurrentTotalUsage += Size;
1065 if (Context->PeakTotalUsage < Context->CurrentTotalUsage) {
1066 Context->PeakTotalUsage = Context->CurrentTotalUsage;
1067 }
1068 Context->CurrentTotalUsageByType[ProfileMemoryIndex] += Size;
1069 if (Context->PeakTotalUsageByType[ProfileMemoryIndex] < Context->CurrentTotalUsageByType[ProfileMemoryIndex]) {
1070 Context->PeakTotalUsageByType[ProfileMemoryIndex] = Context->CurrentTotalUsageByType[ProfileMemoryIndex];
1071 }
1072 }
1073
1074 return EFI_SUCCESS;
1075 }
1076
1077 /**
1078 Get memory profile alloc info from memory profile.
1079
1080 @param DriverInfoData Driver info.
1081 @param BasicAction This Free basic action.
1082 @param Size Buffer size.
1083 @param Buffer Buffer address.
1084
1085 @return Pointer to memory profile alloc info.
1086
1087 **/
1088 MEMORY_PROFILE_ALLOC_INFO_DATA *
1089 GetMemoryProfileAllocInfoFromAddress (
1090 IN MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData,
1091 IN MEMORY_PROFILE_ACTION BasicAction,
1092 IN UINTN Size,
1093 IN VOID *Buffer
1094 )
1095 {
1096 LIST_ENTRY *AllocInfoList;
1097 LIST_ENTRY *AllocLink;
1098 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
1099 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
1100
1101 AllocInfoList = DriverInfoData->AllocInfoList;
1102
1103 for (AllocLink = AllocInfoList->ForwardLink;
1104 AllocLink != AllocInfoList;
1105 AllocLink = AllocLink->ForwardLink) {
1106 AllocInfoData = CR (
1107 AllocLink,
1108 MEMORY_PROFILE_ALLOC_INFO_DATA,
1109 Link,
1110 MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
1111 );
1112 AllocInfo = &AllocInfoData->AllocInfo;
1113 if ((AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK) != BasicAction) {
1114 continue;
1115 }
1116 switch (BasicAction) {
1117 case MemoryProfileActionAllocatePages:
1118 if ((AllocInfo->Buffer <= (PHYSICAL_ADDRESS) (UINTN) Buffer) &&
1119 ((AllocInfo->Buffer + AllocInfo->Size) >= ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size))) {
1120 return AllocInfoData;
1121 }
1122 break;
1123 case MemoryProfileActionAllocatePool:
1124 if (AllocInfo->Buffer == (PHYSICAL_ADDRESS) (UINTN) Buffer) {
1125 return AllocInfoData;
1126 }
1127 break;
1128 default:
1129 ASSERT (FALSE);
1130 break;
1131 }
1132 }
1133
1134 return NULL;
1135 }
1136
1137 /**
1138 Update memory profile Free information.
1139
1140 @param CallerAddress Address of caller who call Free.
1141 @param Action This Free action.
1142 @param Size Buffer size.
1143 @param Buffer Buffer address.
1144
1145 @return EFI_SUCCESS Memory profile is updated.
1146 @return EFI_UNSUPPORTED Memory profile is unsupported.
1147 @return EFI_NOT_FOUND No matched allocate info found for free action.
1148
1149 **/
1150 EFI_STATUS
1151 CoreUpdateProfileFree (
1152 IN PHYSICAL_ADDRESS CallerAddress,
1153 IN MEMORY_PROFILE_ACTION Action,
1154 IN UINTN Size,
1155 IN VOID *Buffer
1156 )
1157 {
1158 MEMORY_PROFILE_CONTEXT *Context;
1159 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
1160 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
1161 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
1162 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
1163 LIST_ENTRY *DriverLink;
1164 LIST_ENTRY *DriverInfoList;
1165 MEMORY_PROFILE_DRIVER_INFO_DATA *ThisDriverInfoData;
1166 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
1167 UINTN ProfileMemoryIndex;
1168 MEMORY_PROFILE_ACTION BasicAction;
1169 BOOLEAN Found;
1170
1171 BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
1172
1173 ContextData = GetMemoryProfileContext ();
1174 if (ContextData == NULL) {
1175 return EFI_UNSUPPORTED;
1176 }
1177
1178 DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
1179
1180 //
1181 // Do not return if DriverInfoData == NULL here,
1182 // because driver A might free memory allocated by driver B.
1183 //
1184
1185 //
1186 // Need use do-while loop to find all possible records,
1187 // because one address might be recorded multiple times.
1188 //
1189 Found = FALSE;
1190 AllocInfoData = NULL;
1191 do {
1192 if (DriverInfoData != NULL) {
1193 switch (BasicAction) {
1194 case MemoryProfileActionFreePages:
1195 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
1196 break;
1197 case MemoryProfileActionFreePool:
1198 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
1199 break;
1200 default:
1201 ASSERT (FALSE);
1202 AllocInfoData = NULL;
1203 break;
1204 }
1205 }
1206 if (AllocInfoData == NULL) {
1207 //
1208 // Legal case, because driver A might free memory allocated by driver B, by some protocol.
1209 //
1210 DriverInfoList = ContextData->DriverInfoList;
1211
1212 for (DriverLink = DriverInfoList->ForwardLink;
1213 DriverLink != DriverInfoList;
1214 DriverLink = DriverLink->ForwardLink) {
1215 ThisDriverInfoData = CR (
1216 DriverLink,
1217 MEMORY_PROFILE_DRIVER_INFO_DATA,
1218 Link,
1219 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
1220 );
1221 switch (BasicAction) {
1222 case MemoryProfileActionFreePages:
1223 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
1224 break;
1225 case MemoryProfileActionFreePool:
1226 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
1227 break;
1228 default:
1229 ASSERT (FALSE);
1230 AllocInfoData = NULL;
1231 break;
1232 }
1233 if (AllocInfoData != NULL) {
1234 DriverInfoData = ThisDriverInfoData;
1235 break;
1236 }
1237 }
1238
1239 if (AllocInfoData == NULL) {
1240 //
1241 // If (!Found), no matched allocate info is found for this free action.
1242 // It is because the specified memory type allocate actions have been filtered by
1243 // CoreNeedRecordProfile(), but free actions may have no memory type information,
1244 // they can not be filtered by CoreNeedRecordProfile(). Then, they will be
1245 // filtered here.
1246 //
1247 // If (Found), it is normal exit path.
1248 return (Found ? EFI_SUCCESS : EFI_NOT_FOUND);
1249 }
1250 }
1251
1252 ASSERT (DriverInfoData != NULL);
1253 ASSERT (AllocInfoData != NULL);
1254
1255 Found = TRUE;
1256
1257 Context = &ContextData->Context;
1258 DriverInfo = &DriverInfoData->DriverInfo;
1259 AllocInfo = &AllocInfoData->AllocInfo;
1260
1261 DriverInfo->AllocRecordCount --;
1262 //
1263 // Update summary if and only if it is basic action.
1264 //
1265 if (AllocInfo->Action == (AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK)) {
1266 ProfileMemoryIndex = GetProfileMemoryIndex (AllocInfo->MemoryType);
1267
1268 Context->CurrentTotalUsage -= AllocInfo->Size;
1269 Context->CurrentTotalUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
1270
1271 DriverInfo->CurrentUsage -= AllocInfo->Size;
1272 DriverInfo->CurrentUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
1273 }
1274
1275 RemoveEntryList (&AllocInfoData->Link);
1276
1277 if (BasicAction == MemoryProfileActionFreePages) {
1278 if (AllocInfo->Buffer != (PHYSICAL_ADDRESS) (UINTN) Buffer) {
1279 CoreUpdateProfileAllocate (
1280 AllocInfo->CallerAddress,
1281 AllocInfo->Action,
1282 AllocInfo->MemoryType,
1283 (UINTN) ((PHYSICAL_ADDRESS) (UINTN) Buffer - AllocInfo->Buffer),
1284 (VOID *) (UINTN) AllocInfo->Buffer,
1285 AllocInfoData->ActionString
1286 );
1287 }
1288 if (AllocInfo->Buffer + AllocInfo->Size != ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)) {
1289 CoreUpdateProfileAllocate (
1290 AllocInfo->CallerAddress,
1291 AllocInfo->Action,
1292 AllocInfo->MemoryType,
1293 (UINTN) ((AllocInfo->Buffer + AllocInfo->Size) - ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)),
1294 (VOID *) ((UINTN) Buffer + Size),
1295 AllocInfoData->ActionString
1296 );
1297 }
1298 }
1299
1300 //
1301 // Use CoreInternalFreePool() that will not update profile for this FreePool action.
1302 //
1303 CoreInternalFreePool (AllocInfoData, NULL);
1304 } while (TRUE);
1305 }
1306
1307 /**
1308 Update memory profile information.
1309
1310 @param CallerAddress Address of caller who call Allocate or Free.
1311 @param Action This Allocate or Free action.
1312 @param MemoryType Memory type.
1313 EfiMaxMemoryType means the MemoryType is unknown.
1314 @param Size Buffer size.
1315 @param Buffer Buffer address.
1316 @param ActionString String for memory profile action.
1317 Only needed for user defined allocate action.
1318
1319 @return EFI_SUCCESS Memory profile is updated.
1320 @return EFI_UNSUPPORTED Memory profile is unsupported,
1321 or memory profile for the image is not required,
1322 or memory profile for the memory type is not required.
1323 @return EFI_ACCESS_DENIED It is during memory profile data getting.
1324 @return EFI_ABORTED Memory profile recording is not enabled.
1325 @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
1326 @return EFI_NOT_FOUND No matched allocate info found for free action.
1327
1328 **/
1329 EFI_STATUS
1330 EFIAPI
1331 CoreUpdateProfile (
1332 IN PHYSICAL_ADDRESS CallerAddress,
1333 IN MEMORY_PROFILE_ACTION Action,
1334 IN EFI_MEMORY_TYPE MemoryType,
1335 IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool
1336 IN VOID *Buffer,
1337 IN CHAR8 *ActionString OPTIONAL
1338 )
1339 {
1340 EFI_STATUS Status;
1341 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
1342 MEMORY_PROFILE_ACTION BasicAction;
1343
1344 if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
1345 return EFI_UNSUPPORTED;
1346 }
1347
1348 if (mMemoryProfileGettingStatus) {
1349 return EFI_ACCESS_DENIED;
1350 }
1351
1352 if (!mMemoryProfileRecordingEnable) {
1353 return EFI_ABORTED;
1354 }
1355
1356 //
1357 // Get the basic action to know how to process the record
1358 //
1359 BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
1360
1361 //
1362 // EfiMaxMemoryType means the MemoryType is unknown.
1363 //
1364 if (MemoryType != EfiMaxMemoryType) {
1365 //
1366 // Only record limited MemoryType.
1367 //
1368 if (!CoreNeedRecordProfile (MemoryType)) {
1369 return EFI_UNSUPPORTED;
1370 }
1371 }
1372
1373 ContextData = GetMemoryProfileContext ();
1374 if (ContextData == NULL) {
1375 return EFI_UNSUPPORTED;
1376 }
1377
1378 CoreAcquireMemoryProfileLock ();
1379 switch (BasicAction) {
1380 case MemoryProfileActionAllocatePages:
1381 Status = CoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
1382 break;
1383 case MemoryProfileActionFreePages:
1384 Status = CoreUpdateProfileFree (CallerAddress, Action, Size, Buffer);
1385 break;
1386 case MemoryProfileActionAllocatePool:
1387 Status = CoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
1388 break;
1389 case MemoryProfileActionFreePool:
1390 Status = CoreUpdateProfileFree (CallerAddress, Action, 0, Buffer);
1391 break;
1392 default:
1393 ASSERT (FALSE);
1394 Status = EFI_UNSUPPORTED;
1395 break;
1396 }
1397 CoreReleaseMemoryProfileLock ();
1398
1399 return Status;
1400 }
1401
1402 ////////////////////
1403
1404 /**
1405 Get memory profile data size.
1406
1407 @return Memory profile data size.
1408
1409 **/
1410 UINTN
1411 MemoryProfileGetDataSize (
1412 VOID
1413 )
1414 {
1415 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
1416 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
1417 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
1418 LIST_ENTRY *DriverInfoList;
1419 LIST_ENTRY *DriverLink;
1420 LIST_ENTRY *AllocInfoList;
1421 LIST_ENTRY *AllocLink;
1422 UINTN TotalSize;
1423
1424
1425 ContextData = GetMemoryProfileContext ();
1426 if (ContextData == NULL) {
1427 return 0;
1428 }
1429
1430 TotalSize = sizeof (MEMORY_PROFILE_CONTEXT);
1431
1432 DriverInfoList = ContextData->DriverInfoList;
1433 for (DriverLink = DriverInfoList->ForwardLink;
1434 DriverLink != DriverInfoList;
1435 DriverLink = DriverLink->ForwardLink) {
1436 DriverInfoData = CR (
1437 DriverLink,
1438 MEMORY_PROFILE_DRIVER_INFO_DATA,
1439 Link,
1440 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
1441 );
1442 TotalSize += DriverInfoData->DriverInfo.Header.Length;
1443
1444 AllocInfoList = DriverInfoData->AllocInfoList;
1445 for (AllocLink = AllocInfoList->ForwardLink;
1446 AllocLink != AllocInfoList;
1447 AllocLink = AllocLink->ForwardLink) {
1448 AllocInfoData = CR (
1449 AllocLink,
1450 MEMORY_PROFILE_ALLOC_INFO_DATA,
1451 Link,
1452 MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
1453 );
1454 TotalSize += AllocInfoData->AllocInfo.Header.Length;
1455 }
1456 }
1457
1458 return TotalSize;
1459 }
1460
1461 /**
1462 Copy memory profile data.
1463
1464 @param ProfileBuffer The buffer to hold memory profile data.
1465
1466 **/
1467 VOID
1468 MemoryProfileCopyData (
1469 IN VOID *ProfileBuffer
1470 )
1471 {
1472 MEMORY_PROFILE_CONTEXT *Context;
1473 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
1474 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
1475 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
1476 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
1477 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
1478 LIST_ENTRY *DriverInfoList;
1479 LIST_ENTRY *DriverLink;
1480 LIST_ENTRY *AllocInfoList;
1481 LIST_ENTRY *AllocLink;
1482 UINTN PdbSize;
1483 UINTN ActionStringSize;
1484
1485 ContextData = GetMemoryProfileContext ();
1486 if (ContextData == NULL) {
1487 return ;
1488 }
1489
1490 Context = ProfileBuffer;
1491 CopyMem (Context, &ContextData->Context, sizeof (MEMORY_PROFILE_CONTEXT));
1492 DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) (Context + 1);
1493
1494 DriverInfoList = ContextData->DriverInfoList;
1495 for (DriverLink = DriverInfoList->ForwardLink;
1496 DriverLink != DriverInfoList;
1497 DriverLink = DriverLink->ForwardLink) {
1498 DriverInfoData = CR (
1499 DriverLink,
1500 MEMORY_PROFILE_DRIVER_INFO_DATA,
1501 Link,
1502 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
1503 );
1504 CopyMem (DriverInfo, &DriverInfoData->DriverInfo, sizeof (MEMORY_PROFILE_DRIVER_INFO));
1505 if (DriverInfo->PdbStringOffset != 0) {
1506 PdbSize = AsciiStrSize (DriverInfoData->PdbString);
1507 CopyMem ((VOID *) ((UINTN) DriverInfo + DriverInfo->PdbStringOffset), DriverInfoData->PdbString, PdbSize);
1508 }
1509 AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) ((UINTN) DriverInfo + DriverInfo->Header.Length);
1510
1511 AllocInfoList = DriverInfoData->AllocInfoList;
1512 for (AllocLink = AllocInfoList->ForwardLink;
1513 AllocLink != AllocInfoList;
1514 AllocLink = AllocLink->ForwardLink) {
1515 AllocInfoData = CR (
1516 AllocLink,
1517 MEMORY_PROFILE_ALLOC_INFO_DATA,
1518 Link,
1519 MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
1520 );
1521 CopyMem (AllocInfo, &AllocInfoData->AllocInfo, sizeof (MEMORY_PROFILE_ALLOC_INFO));
1522 if (AllocInfo->ActionStringOffset != 0) {
1523 ActionStringSize = AsciiStrSize (AllocInfoData->ActionString);
1524 CopyMem ((VOID *) ((UINTN) AllocInfo + AllocInfo->ActionStringOffset), AllocInfoData->ActionString, ActionStringSize);
1525 }
1526 AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) ((UINTN) AllocInfo + AllocInfo->Header.Length);
1527 }
1528
1529 DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) AllocInfo;
1530 }
1531 }
1532
1533 /**
1534 Get memory profile data.
1535
1536 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
1537 @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.
1538 On return, points to the size of the data returned in ProfileBuffer.
1539 @param[out] ProfileBuffer Profile buffer.
1540
1541 @return EFI_SUCCESS Get the memory profile data successfully.
1542 @return EFI_UNSUPPORTED Memory profile is unsupported.
1543 @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data.
1544 ProfileSize is updated with the size required.
1545
1546 **/
1547 EFI_STATUS
1548 EFIAPI
1549 ProfileProtocolGetData (
1550 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
1551 IN OUT UINT64 *ProfileSize,
1552 OUT VOID *ProfileBuffer
1553 )
1554 {
1555 UINTN Size;
1556 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
1557 BOOLEAN MemoryProfileGettingStatus;
1558
1559 ContextData = GetMemoryProfileContext ();
1560 if (ContextData == NULL) {
1561 return EFI_UNSUPPORTED;
1562 }
1563
1564 MemoryProfileGettingStatus = mMemoryProfileGettingStatus;
1565 mMemoryProfileGettingStatus = TRUE;
1566
1567 Size = MemoryProfileGetDataSize ();
1568
1569 if (*ProfileSize < Size) {
1570 *ProfileSize = Size;
1571 mMemoryProfileGettingStatus = MemoryProfileGettingStatus;
1572 return EFI_BUFFER_TOO_SMALL;
1573 }
1574
1575 *ProfileSize = Size;
1576 MemoryProfileCopyData (ProfileBuffer);
1577
1578 mMemoryProfileGettingStatus = MemoryProfileGettingStatus;
1579 return EFI_SUCCESS;
1580 }
1581
1582 /**
1583 Register image to memory profile.
1584
1585 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
1586 @param[in] FilePath File path of the image.
1587 @param[in] ImageBase Image base address.
1588 @param[in] ImageSize Image size.
1589 @param[in] FileType File type of the image.
1590
1591 @return EFI_SUCCESS Register successfully.
1592 @return EFI_UNSUPPORTED Memory profile is unsupported,
1593 or memory profile for the image is not required.
1594 @return EFI_OUT_OF_RESOURCES No enough resource for this register.
1595
1596 **/
1597 EFI_STATUS
1598 EFIAPI
1599 ProfileProtocolRegisterImage (
1600 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
1601 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
1602 IN PHYSICAL_ADDRESS ImageBase,
1603 IN UINT64 ImageSize,
1604 IN EFI_FV_FILETYPE FileType
1605 )
1606 {
1607 EFI_STATUS Status;
1608 LOADED_IMAGE_PRIVATE_DATA DriverEntry;
1609 VOID *EntryPointInImage;
1610
1611 ZeroMem (&DriverEntry, sizeof (DriverEntry));
1612 DriverEntry.Info.FilePath = FilePath;
1613 DriverEntry.ImageContext.ImageAddress = ImageBase;
1614 DriverEntry.ImageContext.ImageSize = ImageSize;
1615 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);
1616 ASSERT_EFI_ERROR (Status);
1617 DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
1618 DriverEntry.ImageContext.ImageType = InternalPeCoffGetSubsystem ((VOID *) (UINTN) ImageBase);
1619
1620 return RegisterMemoryProfileImage (&DriverEntry, FileType);
1621 }
1622
1623 /**
1624 Unregister image from memory profile.
1625
1626 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
1627 @param[in] FilePath File path of the image.
1628 @param[in] ImageBase Image base address.
1629 @param[in] ImageSize Image size.
1630
1631 @return EFI_SUCCESS Unregister successfully.
1632 @return EFI_UNSUPPORTED Memory profile is unsupported,
1633 or memory profile for the image is not required.
1634 @return EFI_NOT_FOUND The image is not found.
1635
1636 **/
1637 EFI_STATUS
1638 EFIAPI
1639 ProfileProtocolUnregisterImage (
1640 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
1641 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
1642 IN PHYSICAL_ADDRESS ImageBase,
1643 IN UINT64 ImageSize
1644 )
1645 {
1646 EFI_STATUS Status;
1647 LOADED_IMAGE_PRIVATE_DATA DriverEntry;
1648 VOID *EntryPointInImage;
1649
1650 ZeroMem (&DriverEntry, sizeof (DriverEntry));
1651 DriverEntry.Info.FilePath = FilePath;
1652 DriverEntry.ImageContext.ImageAddress = ImageBase;
1653 DriverEntry.ImageContext.ImageSize = ImageSize;
1654 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);
1655 ASSERT_EFI_ERROR (Status);
1656 DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
1657
1658 return UnregisterMemoryProfileImage (&DriverEntry);
1659 }
1660
1661 /**
1662 Get memory profile recording state.
1663
1664 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
1665 @param[out] RecordingState Recording state.
1666
1667 @return EFI_SUCCESS Memory profile recording state is returned.
1668 @return EFI_UNSUPPORTED Memory profile is unsupported.
1669 @return EFI_INVALID_PARAMETER RecordingState is NULL.
1670
1671 **/
1672 EFI_STATUS
1673 EFIAPI
1674 ProfileProtocolGetRecordingState (
1675 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
1676 OUT BOOLEAN *RecordingState
1677 )
1678 {
1679 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
1680
1681 ContextData = GetMemoryProfileContext ();
1682 if (ContextData == NULL) {
1683 return EFI_UNSUPPORTED;
1684 }
1685
1686 if (RecordingState == NULL) {
1687 return EFI_INVALID_PARAMETER;
1688 }
1689 *RecordingState = mMemoryProfileRecordingEnable;
1690 return EFI_SUCCESS;
1691 }
1692
1693 /**
1694 Set memory profile recording state.
1695
1696 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
1697 @param[in] RecordingState Recording state.
1698
1699 @return EFI_SUCCESS Set memory profile recording state successfully.
1700 @return EFI_UNSUPPORTED Memory profile is unsupported.
1701
1702 **/
1703 EFI_STATUS
1704 EFIAPI
1705 ProfileProtocolSetRecordingState (
1706 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
1707 IN BOOLEAN RecordingState
1708 )
1709 {
1710 MEMORY_PROFILE_CONTEXT_DATA *ContextData;
1711
1712 ContextData = GetMemoryProfileContext ();
1713 if (ContextData == NULL) {
1714 return EFI_UNSUPPORTED;
1715 }
1716
1717 mMemoryProfileRecordingEnable = RecordingState;
1718 return EFI_SUCCESS;
1719 }
1720
1721 /**
1722 Record memory profile of multilevel caller.
1723
1724 @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
1725 @param[in] CallerAddress Address of caller.
1726 @param[in] Action Memory profile action.
1727 @param[in] MemoryType Memory type.
1728 EfiMaxMemoryType means the MemoryType is unknown.
1729 @param[in] Buffer Buffer address.
1730 @param[in] Size Buffer size.
1731 @param[in] ActionString String for memory profile action.
1732 Only needed for user defined allocate action.
1733
1734 @return EFI_SUCCESS Memory profile is updated.
1735 @return EFI_UNSUPPORTED Memory profile is unsupported,
1736 or memory profile for the image is not required,
1737 or memory profile for the memory type is not required.
1738 @return EFI_ACCESS_DENIED It is during memory profile data getting.
1739 @return EFI_ABORTED Memory profile recording is not enabled.
1740 @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
1741 @return EFI_NOT_FOUND No matched allocate info found for free action.
1742
1743 **/
1744 EFI_STATUS
1745 EFIAPI
1746 ProfileProtocolRecord (
1747 IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
1748 IN PHYSICAL_ADDRESS CallerAddress,
1749 IN MEMORY_PROFILE_ACTION Action,
1750 IN EFI_MEMORY_TYPE MemoryType,
1751 IN VOID *Buffer,
1752 IN UINTN Size,
1753 IN CHAR8 *ActionString OPTIONAL
1754 )
1755 {
1756 return CoreUpdateProfile (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
1757 }
1758
1759 ////////////////////