]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c
MdeModulePkg DxeCore/PiSmmCore: Add UEFI memory and SMRAM profile support.
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / SmramProfileRecord.c
CommitLineData
84edd20b
SZ
1/** @file\r
2 Support routines for SMRAM profile.\r
3\r
4 Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php.\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "PiSmmCore.h"\r
16\r
17#define IS_SMRAM_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT1) != 0)\r
18\r
19typedef struct {\r
20 UINT32 Signature;\r
21 MEMORY_PROFILE_CONTEXT Context;\r
22 LIST_ENTRY *DriverInfoList;\r
23} MEMORY_PROFILE_CONTEXT_DATA;\r
24\r
25typedef struct {\r
26 UINT32 Signature;\r
27 MEMORY_PROFILE_DRIVER_INFO DriverInfo;\r
28 LIST_ENTRY *AllocInfoList;\r
29 LIST_ENTRY Link;\r
30} MEMORY_PROFILE_DRIVER_INFO_DATA;\r
31\r
32typedef struct {\r
33 UINT32 Signature;\r
34 MEMORY_PROFILE_ALLOC_INFO AllocInfo;\r
35 LIST_ENTRY Link;\r
36} MEMORY_PROFILE_ALLOC_INFO_DATA;\r
37\r
38//\r
39// When free memory less than 4 pages, dump it.\r
40//\r
41#define SMRAM_INFO_DUMP_PAGE_THRESHOLD 4\r
42\r
43GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_FREE_MEMORY mSmramFreeMemory = {\r
44 {\r
45 MEMORY_PROFILE_FREE_MEMORY_SIGNATURE,\r
46 sizeof (MEMORY_PROFILE_FREE_MEMORY),\r
47 MEMORY_PROFILE_FREE_MEMORY_REVISION\r
48 },\r
49 0,\r
50 0\r
51};\r
52\r
53GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mImageQueue = INITIALIZE_LIST_HEAD_VARIABLE (mImageQueue);\r
54GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA mSmramProfileContext = {\r
55 MEMORY_PROFILE_CONTEXT_SIGNATURE,\r
56 {\r
57 {\r
58 MEMORY_PROFILE_CONTEXT_SIGNATURE,\r
59 sizeof (MEMORY_PROFILE_CONTEXT),\r
60 MEMORY_PROFILE_CONTEXT_REVISION\r
61 },\r
62 0,\r
63 0,\r
64 {0},\r
65 {0},\r
66 0,\r
67 0,\r
68 0\r
69 },\r
70 &mImageQueue,\r
71};\r
72GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA *mSmramProfileContextPtr;\r
73\r
74BOOLEAN mSmramReadyToLock;\r
75BOOLEAN mSmramProfileRecordingStatus = FALSE;\r
76\r
77/**\r
78 Return SMRAM profile context.\r
79\r
80 @return SMRAM profile context.\r
81\r
82**/\r
83MEMORY_PROFILE_CONTEXT_DATA *\r
84GetSmramProfileContext (\r
85 VOID\r
86 )\r
87{\r
88 return mSmramProfileContextPtr;\r
89}\r
90\r
91/**\r
92 Retrieves the magic value from the PE/COFF header.\r
93\r
94 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.\r
95\r
96 @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32\r
97 @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+\r
98\r
99**/\r
100UINT16\r
101InternalPeCoffGetPeHeaderMagicValue (\r
102 IN EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr\r
103 )\r
104{\r
105 //\r
106 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value\r
107 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the\r
108 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
109 // then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
110 //\r
111 if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
112 return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
113 }\r
114 //\r
115 // Return the magic value from the PC/COFF Optional Header\r
116 //\r
117 return Hdr.Pe32->OptionalHeader.Magic;\r
118}\r
119\r
120/**\r
121 Retrieves and returns the Subsystem of a PE/COFF image that has been loaded into system memory.\r
122 If Pe32Data is NULL, then ASSERT().\r
123\r
124 @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.\r
125\r
126 @return The Subsystem of the PE/COFF image.\r
127\r
128**/\r
129UINT16\r
130InternalPeCoffGetSubsystem (\r
131 IN VOID *Pe32Data\r
132 )\r
133{\r
134 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
135 EFI_IMAGE_DOS_HEADER *DosHdr;\r
136 UINT16 Magic;\r
137\r
138 ASSERT (Pe32Data != NULL);\r
139\r
140 DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;\r
141 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
142 //\r
143 // DOS image header is present, so read the PE header after the DOS image header.\r
144 //\r
145 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
146 } else {\r
147 //\r
148 // DOS image header is not present, so PE header is at the image base.\r
149 //\r
150 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;\r
151 }\r
152\r
153 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
154 return Hdr.Te->Subsystem;\r
155 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
156 Magic = InternalPeCoffGetPeHeaderMagicValue (Hdr);\r
157 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
158 return Hdr.Pe32->OptionalHeader.Subsystem;\r
159 } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
160 return Hdr.Pe32Plus->OptionalHeader.Subsystem;\r
161 }\r
162 }\r
163\r
164 return 0x0000;\r
165}\r
166\r
167/**\r
168 Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded\r
169 into system memory with the PE/COFF Loader Library functions.\r
170\r
171 Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry\r
172 point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then\r
173 return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS.\r
174 If Pe32Data is NULL, then ASSERT().\r
175 If EntryPoint is NULL, then ASSERT().\r
176\r
177 @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.\r
178 @param EntryPoint The pointer to entry point to the PE/COFF image to return.\r
179\r
180 @retval RETURN_SUCCESS EntryPoint was returned.\r
181 @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image.\r
182\r
183**/\r
184RETURN_STATUS\r
185InternalPeCoffGetEntryPoint (\r
186 IN VOID *Pe32Data,\r
187 OUT VOID **EntryPoint\r
188 )\r
189{\r
190 EFI_IMAGE_DOS_HEADER *DosHdr;\r
191 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
192\r
193 ASSERT (Pe32Data != NULL);\r
194 ASSERT (EntryPoint != NULL);\r
195\r
196 DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;\r
197 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
198 //\r
199 // DOS image header is present, so read the PE header after the DOS image header.\r
200 //\r
201 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
202 } else {\r
203 //\r
204 // DOS image header is not present, so PE header is at the image base.\r
205 //\r
206 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;\r
207 }\r
208\r
209 //\r
210 // Calculate the entry point relative to the start of the image.\r
211 // AddressOfEntryPoint is common for PE32 & PE32+\r
212 //\r
213 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
214 *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);\r
215 return RETURN_SUCCESS;\r
216 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
217 *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff));\r
218 return RETURN_SUCCESS;\r
219 }\r
220\r
221 return RETURN_UNSUPPORTED;\r
222}\r
223\r
224/**\r
225 Build driver info.\r
226\r
227 @param ContextData Memory profile context.\r
228 @param FileName File name of the image.\r
229 @param ImageBase Image base address.\r
230 @param ImageSize Image size.\r
231 @param EntryPoint Entry point of the image.\r
232 @param ImageSubsystem Image subsystem of the image.\r
233\r
234 @param FileType File type of the image.\r
235\r
236 @return Pointer to memory profile driver info.\r
237\r
238**/\r
239MEMORY_PROFILE_DRIVER_INFO_DATA *\r
240BuildDriverInfo (\r
241 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,\r
242 IN EFI_GUID *FileName,\r
243 IN PHYSICAL_ADDRESS ImageBase,\r
244 IN UINT64 ImageSize,\r
245 IN PHYSICAL_ADDRESS EntryPoint,\r
246 IN UINT16 ImageSubsystem,\r
247 IN EFI_FV_FILETYPE FileType\r
248 )\r
249{\r
250 EFI_STATUS Status;\r
251 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
252 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
253 VOID *EntryPointInImage;\r
254\r
255 //\r
256 // Use SmmInternalAllocatePool() that will not update profile for this AllocatePool action.\r
257 //\r
258 Status = SmmInternalAllocatePool (\r
259 EfiRuntimeServicesData,\r
260 sizeof (*DriverInfoData) + sizeof (LIST_ENTRY),\r
261 (VOID **) &DriverInfoData\r
262 );\r
263 if (EFI_ERROR (Status)) {\r
264 return NULL;\r
265 }\r
266\r
267 ZeroMem (DriverInfoData, sizeof (*DriverInfoData));\r
268\r
269 DriverInfo = &DriverInfoData->DriverInfo;\r
270 DriverInfoData->Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;\r
271 DriverInfo->Header.Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;\r
272 DriverInfo->Header.Length = sizeof (MEMORY_PROFILE_DRIVER_INFO);\r
273 DriverInfo->Header.Revision = MEMORY_PROFILE_DRIVER_INFO_REVISION;\r
274 if (FileName != NULL) {\r
275 CopyMem (&DriverInfo->FileName, FileName, sizeof (EFI_GUID));\r
276 }\r
277 DriverInfo->ImageBase = ImageBase;\r
278 DriverInfo->ImageSize = ImageSize;\r
279 DriverInfo->EntryPoint = EntryPoint;\r
280 DriverInfo->ImageSubsystem = ImageSubsystem;\r
281 if ((EntryPoint != 0) && ((EntryPoint < ImageBase) || (EntryPoint >= (ImageBase + ImageSize)))) {\r
282 //\r
283 // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.\r
284 // So patch ImageBuffer here to align the EntryPoint.\r
285 //\r
286 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);\r
287 ASSERT_EFI_ERROR (Status);\r
288 DriverInfo->ImageBase = ImageBase + EntryPoint - (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;\r
289 }\r
290 DriverInfo->FileType = FileType;\r
291 DriverInfoData->AllocInfoList = (LIST_ENTRY *) (DriverInfoData + 1);\r
292 InitializeListHead (DriverInfoData->AllocInfoList);\r
293 DriverInfo->CurrentUsage = 0;\r
294 DriverInfo->PeakUsage = 0;\r
295 DriverInfo->AllocRecordCount = 0;\r
296\r
297 InsertTailList (ContextData->DriverInfoList, &DriverInfoData->Link);\r
298 ContextData->Context.ImageCount ++;\r
299 ContextData->Context.TotalImageSize += DriverInfo->ImageSize;\r
300\r
301 return DriverInfoData;\r
302}\r
303\r
304/**\r
305 Register image to DXE.\r
306\r
307 @param FileName File name of the image.\r
308 @param ImageBase Image base address.\r
309 @param ImageSize Image size.\r
310 @param FileType File type of the image.\r
311\r
312**/\r
313VOID\r
314RegisterImageToDxe (\r
315 IN EFI_GUID *FileName,\r
316 IN PHYSICAL_ADDRESS ImageBase,\r
317 IN UINT64 ImageSize,\r
318 IN EFI_FV_FILETYPE FileType\r
319 )\r
320{\r
321 EFI_STATUS Status;\r
322 EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol;\r
323 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;\r
324 UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];\r
325\r
326 if (IS_SMRAM_PROFILE_ENABLED) {\r
327\r
328 FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;\r
329 Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID **) &ProfileProtocol);\r
330 if (!EFI_ERROR (Status)) {\r
331 EfiInitializeFwVolDevicepathNode (FilePath, FileName);\r
332 SetDevicePathEndNode (FilePath + 1);\r
333\r
334 Status = ProfileProtocol->RegisterImage (\r
335 ProfileProtocol,\r
336 (EFI_DEVICE_PATH_PROTOCOL *) FilePath,\r
337 ImageBase,\r
338 ImageSize,\r
339 FileType\r
340 );\r
341 }\r
342 }\r
343}\r
344\r
345/**\r
346 Unregister image from DXE.\r
347\r
348 @param FileName File name of the image.\r
349 @param ImageBase Image base address.\r
350 @param ImageSize Image size.\r
351\r
352**/\r
353VOID\r
354UnregisterImageFromDxe (\r
355 IN EFI_GUID *FileName,\r
356 IN PHYSICAL_ADDRESS ImageBase,\r
357 IN UINT64 ImageSize\r
358 )\r
359{\r
360 EFI_STATUS Status;\r
361 EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol;\r
362 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;\r
363 UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];\r
364\r
365 if (IS_SMRAM_PROFILE_ENABLED) {\r
366\r
367 FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;\r
368 Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID *) &ProfileProtocol);\r
369 if (!EFI_ERROR (Status)) {\r
370 EfiInitializeFwVolDevicepathNode (FilePath, FileName);\r
371 SetDevicePathEndNode (FilePath + 1);\r
372\r
373 Status = ProfileProtocol->UnregisterImage (\r
374 ProfileProtocol,\r
375 (EFI_DEVICE_PATH_PROTOCOL *) FilePath,\r
376 ImageBase,\r
377 ImageSize\r
378 );\r
379 }\r
380 }\r
381}\r
382\r
383/**\r
384 Register SMM Core to SMRAM profile.\r
385\r
386 @param ContextData SMRAM profile context.\r
387\r
388 @retval TRUE Register success.\r
389 @retval FALSE Register fail.\r
390\r
391**/\r
392BOOLEAN\r
393RegisterSmmCore (\r
394 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData\r
395 )\r
396{\r
397 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
398 PHYSICAL_ADDRESS ImageBase;\r
399\r
400 ASSERT (ContextData != NULL);\r
401\r
402 RegisterImageToDxe (\r
403 &gEfiCallerIdGuid,\r
404 gSmmCorePrivate->PiSmmCoreImageBase,\r
405 gSmmCorePrivate->PiSmmCoreImageSize,\r
406 EFI_FV_FILETYPE_SMM_CORE\r
407 );\r
408\r
409 ImageBase = gSmmCorePrivate->PiSmmCoreImageBase;\r
410 DriverInfoData = BuildDriverInfo (\r
411 ContextData,\r
412 &gEfiCallerIdGuid,\r
413 ImageBase,\r
414 gSmmCorePrivate->PiSmmCoreImageSize,\r
415 gSmmCorePrivate->PiSmmCoreEntryPoint,\r
416 InternalPeCoffGetSubsystem ((VOID *) (UINTN) ImageBase),\r
417 EFI_FV_FILETYPE_SMM_CORE\r
418 );\r
419 if (DriverInfoData == NULL) {\r
420 return FALSE;\r
421 }\r
422\r
423 return TRUE;\r
424}\r
425\r
426/**\r
427 Initialize SMRAM profile.\r
428\r
429**/\r
430VOID\r
431SmramProfileInit (\r
432 VOID\r
433 )\r
434{\r
435 MEMORY_PROFILE_CONTEXT_DATA *SmramProfileContext;\r
436\r
437 if (!IS_SMRAM_PROFILE_ENABLED) {\r
438 return;\r
439 }\r
440\r
441 SmramProfileContext = GetSmramProfileContext ();\r
442 if (SmramProfileContext != NULL) {\r
443 return;\r
444 }\r
445\r
446 mSmramProfileRecordingStatus = TRUE;\r
447 mSmramProfileContextPtr = &mSmramProfileContext;\r
448\r
449 RegisterSmmCore (&mSmramProfileContext);\r
450\r
451 DEBUG ((EFI_D_INFO, "SmramProfileInit SmramProfileContext - 0x%x\n", &mSmramProfileContext));\r
452}\r
453\r
454/**\r
455 Register SMM image to SMRAM profile.\r
456\r
457 @param DriverEntry SMM image info.\r
458 @param RegisterToDxe Register image to DXE.\r
459\r
460 @retval TRUE Register success.\r
461 @retval FALSE Register fail.\r
462\r
463**/\r
464BOOLEAN\r
465RegisterSmramProfileImage (\r
466 IN EFI_SMM_DRIVER_ENTRY *DriverEntry,\r
467 IN BOOLEAN RegisterToDxe\r
468 )\r
469{\r
470 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
471 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
472\r
473 if (!IS_SMRAM_PROFILE_ENABLED) {\r
474 return FALSE;\r
475 }\r
476\r
477 if (RegisterToDxe) {\r
478 RegisterImageToDxe (\r
479 &DriverEntry->FileName,\r
480 DriverEntry->ImageBuffer,\r
481 EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage),\r
482 EFI_FV_FILETYPE_SMM\r
483 );\r
484 }\r
485\r
486 ContextData = GetSmramProfileContext ();\r
487 if (ContextData == NULL) {\r
488 return FALSE;\r
489 }\r
490\r
491 DriverInfoData = BuildDriverInfo (\r
492 ContextData,\r
493 &DriverEntry->FileName,\r
494 DriverEntry->ImageBuffer,\r
495 EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage),\r
496 DriverEntry->ImageEntryPoint,\r
497 InternalPeCoffGetSubsystem ((VOID *) (UINTN) DriverEntry->ImageBuffer),\r
498 EFI_FV_FILETYPE_SMM\r
499 );\r
500 if (DriverInfoData == NULL) {\r
501 return FALSE;\r
502 }\r
503\r
504 return TRUE;\r
505}\r
506\r
507/**\r
508 Search image from memory profile.\r
509\r
510 @param ContextData Memory profile context.\r
511 @param FileName Image file name.\r
512 @param Address Image Address.\r
513\r
514 @return Pointer to memory profile driver info.\r
515\r
516**/\r
517MEMORY_PROFILE_DRIVER_INFO_DATA *\r
518GetMemoryProfileDriverInfoByFileNameAndAddress (\r
519 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,\r
520 IN EFI_GUID *FileName,\r
521 IN PHYSICAL_ADDRESS Address\r
522 )\r
523{\r
524 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
525 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
526 LIST_ENTRY *DriverLink;\r
527 LIST_ENTRY *DriverInfoList;\r
528\r
529 DriverInfoList = ContextData->DriverInfoList;\r
530\r
531 for (DriverLink = DriverInfoList->ForwardLink;\r
532 DriverLink != DriverInfoList;\r
533 DriverLink = DriverLink->ForwardLink) {\r
534 DriverInfoData = CR (\r
535 DriverLink,\r
536 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
537 Link,\r
538 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
539 );\r
540 DriverInfo = &DriverInfoData->DriverInfo;\r
541 if ((CompareGuid (&DriverInfo->FileName, FileName)) &&\r
542 (Address >= DriverInfo->ImageBase) &&\r
543 (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {\r
544 return DriverInfoData;\r
545 }\r
546 }\r
547\r
548 return NULL;\r
549}\r
550\r
551/**\r
552 Search dummy image from SMRAM profile.\r
553\r
554 @param ContextData Memory profile context.\r
555\r
556 @return Pointer to memory profile driver info.\r
557\r
558**/\r
559MEMORY_PROFILE_DRIVER_INFO_DATA *\r
560FindDummyImage (\r
561 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData\r
562 )\r
563{\r
564 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
565 LIST_ENTRY *DriverLink;\r
566 LIST_ENTRY *DriverInfoList;\r
567\r
568 DriverInfoList = ContextData->DriverInfoList;\r
569\r
570 for (DriverLink = DriverInfoList->ForwardLink;\r
571 DriverLink != DriverInfoList;\r
572 DriverLink = DriverLink->ForwardLink) {\r
573 DriverInfoData = CR (\r
574 DriverLink,\r
575 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
576 Link,\r
577 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
578 );\r
579 if (CompareGuid (&gZeroGuid, &DriverInfoData->DriverInfo.FileName)) {\r
580 return DriverInfoData;\r
581 }\r
582 }\r
583\r
584 return BuildDriverInfo (ContextData, &gZeroGuid, 0, 0, 0, 0, 0);\r
585}\r
586\r
587/**\r
588 Search image from memory profile.\r
589 It will return image, if (Address >= ImageBuffer) AND (Address < ImageBuffer + ImageSize)\r
590\r
591 @param ContextData Memory profile context.\r
592 @param Address Image or Function address.\r
593\r
594 @return Pointer to memory profile driver info.\r
595\r
596**/\r
597MEMORY_PROFILE_DRIVER_INFO_DATA *\r
598GetMemoryProfileDriverInfoFromAddress (\r
599 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,\r
600 IN PHYSICAL_ADDRESS Address\r
601 )\r
602{\r
603 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
604 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
605 LIST_ENTRY *DriverLink;\r
606 LIST_ENTRY *DriverInfoList;\r
607\r
608 DriverInfoList = ContextData->DriverInfoList;\r
609\r
610 for (DriverLink = DriverInfoList->ForwardLink;\r
611 DriverLink != DriverInfoList;\r
612 DriverLink = DriverLink->ForwardLink) {\r
613 DriverInfoData = CR (\r
614 DriverLink,\r
615 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
616 Link,\r
617 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
618 );\r
619 DriverInfo = &DriverInfoData->DriverInfo;\r
620 if ((Address >= DriverInfo->ImageBase) &&\r
621 (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {\r
622 return DriverInfoData;\r
623 }\r
624 }\r
625\r
626 //\r
627 // Should never come here.\r
628 //\r
629 return FindDummyImage (ContextData);\r
630}\r
631\r
632/**\r
633 Unregister image from SMRAM profile.\r
634\r
635 @param DriverEntry SMM image info.\r
636 @param UnregisterFromDxe Unregister image from DXE.\r
637\r
638 @retval TRUE Unregister success.\r
639 @retval FALSE Unregister fail.\r
640\r
641**/\r
642BOOLEAN\r
643UnregisterSmramProfileImage (\r
644 IN EFI_SMM_DRIVER_ENTRY *DriverEntry,\r
645 IN BOOLEAN UnregisterFromDxe\r
646 )\r
647{\r
648 EFI_STATUS Status;\r
649 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
650 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
651 EFI_GUID *FileName;\r
652 PHYSICAL_ADDRESS ImageAddress;\r
653 VOID *EntryPointInImage;\r
654\r
655 if (!IS_SMRAM_PROFILE_ENABLED) {\r
656 return FALSE;\r
657 }\r
658\r
659 if (UnregisterFromDxe) {\r
660 UnregisterImageFromDxe (\r
661 &DriverEntry->FileName,\r
662 DriverEntry->ImageBuffer,\r
663 EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage)\r
664 );\r
665 }\r
666\r
667 ContextData = GetSmramProfileContext ();\r
668 if (ContextData == NULL) {\r
669 return FALSE;\r
670 }\r
671\r
672 DriverInfoData = NULL;\r
673 FileName = &DriverEntry->FileName;\r
674 ImageAddress = DriverEntry->ImageBuffer;\r
675 if ((DriverEntry->ImageEntryPoint < ImageAddress) || (DriverEntry->ImageEntryPoint >= (ImageAddress + EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage)))) {\r
676 //\r
677 // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.\r
678 // So patch ImageAddress here to align the EntryPoint.\r
679 //\r
680 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageAddress, &EntryPointInImage);\r
681 ASSERT_EFI_ERROR (Status);\r
682 ImageAddress = ImageAddress + (UINTN) DriverEntry->ImageEntryPoint - (UINTN) EntryPointInImage;\r
683 }\r
684 if (FileName != NULL) {\r
685 DriverInfoData = GetMemoryProfileDriverInfoByFileNameAndAddress (ContextData, FileName, ImageAddress);\r
686 }\r
687 if (DriverInfoData == NULL) {\r
688 DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, ImageAddress);\r
689 }\r
690 if (DriverInfoData == NULL) {\r
691 return FALSE;\r
692 }\r
693\r
694 ContextData->Context.TotalImageSize -= DriverInfoData->DriverInfo.ImageSize;\r
695\r
696 DriverInfoData->DriverInfo.ImageBase = 0;\r
697 DriverInfoData->DriverInfo.ImageSize = 0;\r
698\r
699 if (DriverInfoData->DriverInfo.PeakUsage == 0) {\r
700 ContextData->Context.ImageCount --;\r
701 RemoveEntryList (&DriverInfoData->Link);\r
702 //\r
703 // Use SmmInternalFreePool() that will not update profile for this FreePool action.\r
704 //\r
705 SmmInternalFreePool (DriverInfoData);\r
706 }\r
707\r
708 return TRUE;\r
709}\r
710\r
711/**\r
712 Return if this memory type needs to be recorded into memory profile.\r
713 If BIOS memory type (0 ~ EfiMaxMemoryType), it checks bit (1 << MemoryType).\r
714 If OS memory type (0x80000000 ~ 0xFFFFFFFF), it checks bit63 - 0x8000000000000000.\r
715\r
716 @param MemoryType Memory type.\r
717\r
718 @retval TRUE This memory type need to be recorded.\r
719 @retval FALSE This memory type need not to be recorded.\r
720\r
721**/\r
722BOOLEAN\r
723SmmCoreNeedRecordProfile (\r
724 IN EFI_MEMORY_TYPE MemoryType\r
725 )\r
726{\r
727 UINT64 TestBit;\r
728\r
729 if ((UINT32) MemoryType >= 0x80000000) {\r
730 TestBit = BIT63;\r
731 } else {\r
732 TestBit = LShiftU64 (1, MemoryType);\r
733 }\r
734\r
735 if ((PcdGet64 (PcdMemoryProfileMemoryType) & TestBit) != 0) {\r
736 return TRUE;\r
737 } else {\r
738 return FALSE;\r
739 }\r
740}\r
741\r
742/**\r
743 Convert EFI memory type to profile memory index. The rule is:\r
744 If BIOS memory type (0 ~ EfiMaxMemoryType), ProfileMemoryIndex = MemoryType.\r
745 If OS memory type (0x80000000 ~ 0xFFFFFFFF), ProfileMemoryIndex = EfiMaxMemoryType.\r
746\r
747 @param MemoryType Memory type.\r
748\r
749 @return EFI memory type as profile memory index.\r
750\r
751**/\r
752EFI_MEMORY_TYPE\r
753GetProfileMemoryIndex (\r
754 IN EFI_MEMORY_TYPE MemoryType\r
755 )\r
756{\r
757 if ((UINT32) MemoryType >= 0x80000000) {\r
758 return EfiMaxMemoryType;\r
759 } else {\r
760 return MemoryType;\r
761 }\r
762}\r
763\r
764/**\r
765 Update SMRAM profile FreeMemoryPages information\r
766\r
767 @param ContextData Memory profile context.\r
768\r
769**/\r
770VOID\r
771SmramProfileUpdateFreePages (\r
772 IN MEMORY_PROFILE_CONTEXT_DATA *ContextData\r
773 )\r
774{\r
775 LIST_ENTRY *Node;\r
776 FREE_PAGE_LIST *Pages;\r
777 LIST_ENTRY *FreePageList;\r
778 UINTN NumberOfPages;\r
779\r
780 NumberOfPages = 0;\r
781 FreePageList = &mSmmMemoryMap;\r
782 for (Node = FreePageList->BackLink;\r
783 Node != FreePageList;\r
784 Node = Node->BackLink) {\r
785 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
786 NumberOfPages += Pages->NumberOfPages;\r
787 }\r
788\r
789 mSmramFreeMemory.TotalFreeMemoryPages = NumberOfPages;\r
790\r
791 if (NumberOfPages <= SMRAM_INFO_DUMP_PAGE_THRESHOLD) {\r
792 DumpSmramInfo ();\r
793 }\r
794}\r
795\r
796/**\r
797 Update SMRAM profile Allocate information.\r
798\r
799 @param CallerAddress Address of caller who call Allocate.\r
800 @param Action This Allocate action.\r
801 @param MemoryType Memory type.\r
802 @param Size Buffer size.\r
803 @param Buffer Buffer address.\r
804\r
805 @retval TRUE Profile udpate success.\r
806 @retval FALSE Profile update fail.\r
807\r
808**/\r
809BOOLEAN\r
810SmmCoreUpdateProfileAllocate (\r
811 IN PHYSICAL_ADDRESS CallerAddress,\r
812 IN MEMORY_PROFILE_ACTION Action,\r
813 IN EFI_MEMORY_TYPE MemoryType,\r
814 IN UINTN Size,\r
815 IN VOID *Buffer\r
816 )\r
817{\r
818 EFI_STATUS Status;\r
819 MEMORY_PROFILE_CONTEXT *Context;\r
820 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
821 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
822 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
823 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
824 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
825 EFI_MEMORY_TYPE ProfileMemoryIndex;\r
826\r
827 ContextData = GetSmramProfileContext ();\r
828 if (ContextData == NULL) {\r
829 return FALSE;\r
830 }\r
831\r
832 DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);\r
833 ASSERT (DriverInfoData != NULL);\r
834\r
835 //\r
836 // Use SmmInternalAllocatePool() that will not update profile for this AllocatePool action.\r
837 //\r
838 Status = SmmInternalAllocatePool (\r
839 EfiRuntimeServicesData,\r
840 sizeof (*AllocInfoData),\r
841 (VOID **) &AllocInfoData\r
842 );\r
843 if (EFI_ERROR (Status)) {\r
844 return FALSE;\r
845 }\r
846 AllocInfo = &AllocInfoData->AllocInfo;\r
847 AllocInfoData->Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;\r
848 AllocInfo->Header.Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;\r
849 AllocInfo->Header.Length = sizeof (MEMORY_PROFILE_ALLOC_INFO);\r
850 AllocInfo->Header.Revision = MEMORY_PROFILE_ALLOC_INFO_REVISION;\r
851 AllocInfo->CallerAddress = CallerAddress;\r
852 AllocInfo->SequenceId = ContextData->Context.SequenceCount;\r
853 AllocInfo->Action = Action;\r
854 AllocInfo->MemoryType = MemoryType;\r
855 AllocInfo->Buffer = (PHYSICAL_ADDRESS) (UINTN) Buffer;\r
856 AllocInfo->Size = Size;\r
857\r
858 InsertTailList (DriverInfoData->AllocInfoList, &AllocInfoData->Link);\r
859\r
860 ProfileMemoryIndex = GetProfileMemoryIndex (MemoryType);\r
861\r
862 DriverInfo = &DriverInfoData->DriverInfo;\r
863 DriverInfo->CurrentUsage += Size;\r
864 if (DriverInfo->PeakUsage < DriverInfo->CurrentUsage) {\r
865 DriverInfo->PeakUsage = DriverInfo->CurrentUsage;\r
866 }\r
867 DriverInfo->CurrentUsageByType[ProfileMemoryIndex] += Size;\r
868 if (DriverInfo->PeakUsageByType[ProfileMemoryIndex] < DriverInfo->CurrentUsageByType[ProfileMemoryIndex]) {\r
869 DriverInfo->PeakUsageByType[ProfileMemoryIndex] = DriverInfo->CurrentUsageByType[ProfileMemoryIndex];\r
870 }\r
871 DriverInfo->AllocRecordCount ++;\r
872\r
873 Context = &ContextData->Context;\r
874 Context->CurrentTotalUsage += Size;\r
875 if (Context->PeakTotalUsage < Context->CurrentTotalUsage) {\r
876 Context->PeakTotalUsage = Context->CurrentTotalUsage;\r
877 }\r
878 Context->CurrentTotalUsageByType[ProfileMemoryIndex] += Size;\r
879 if (Context->PeakTotalUsageByType[ProfileMemoryIndex] < Context->CurrentTotalUsageByType[ProfileMemoryIndex]) {\r
880 Context->PeakTotalUsageByType[ProfileMemoryIndex] = Context->CurrentTotalUsageByType[ProfileMemoryIndex];\r
881 }\r
882 Context->SequenceCount ++;\r
883\r
884 SmramProfileUpdateFreePages (ContextData);\r
885 return TRUE;\r
886}\r
887\r
888/**\r
889 Get memory profile alloc info from memory profile\r
890\r
891 @param DriverInfoData Driver info\r
892 @param Action This Free action\r
893 @param Size Buffer size\r
894 @param Buffer Buffer address\r
895\r
896 @return Pointer to memory profile alloc info.\r
897**/\r
898MEMORY_PROFILE_ALLOC_INFO_DATA *\r
899GetMemoryProfileAllocInfoFromAddress (\r
900 IN MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData,\r
901 IN MEMORY_PROFILE_ACTION Action,\r
902 IN UINTN Size,\r
903 IN VOID *Buffer\r
904 )\r
905{\r
906 LIST_ENTRY *AllocInfoList;\r
907 LIST_ENTRY *AllocLink;\r
908 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
909 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
910\r
911 AllocInfoList = DriverInfoData->AllocInfoList;\r
912\r
913 for (AllocLink = AllocInfoList->ForwardLink;\r
914 AllocLink != AllocInfoList;\r
915 AllocLink = AllocLink->ForwardLink) {\r
916 AllocInfoData = CR (\r
917 AllocLink,\r
918 MEMORY_PROFILE_ALLOC_INFO_DATA,\r
919 Link,\r
920 MEMORY_PROFILE_ALLOC_INFO_SIGNATURE\r
921 );\r
922 AllocInfo = &AllocInfoData->AllocInfo;\r
923 if (AllocInfo->Action != Action) {\r
924 continue;\r
925 }\r
926 switch (Action) {\r
927 case MemoryProfileActionAllocatePages:\r
928 if ((AllocInfo->Buffer <= (PHYSICAL_ADDRESS) (UINTN) Buffer) &&\r
929 ((AllocInfo->Buffer + AllocInfo->Size) >= ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size))) {\r
930 return AllocInfoData;\r
931 }\r
932 break;\r
933 case MemoryProfileActionAllocatePool:\r
934 if (AllocInfo->Buffer == (PHYSICAL_ADDRESS) (UINTN) Buffer) {\r
935 return AllocInfoData;\r
936 }\r
937 break;\r
938 default:\r
939 ASSERT (FALSE);\r
940 break;\r
941 }\r
942 }\r
943\r
944 return NULL;\r
945}\r
946\r
947/**\r
948 Update SMRAM profile Free information.\r
949\r
950 @param CallerAddress Address of caller who call Free.\r
951 @param Action This Free action.\r
952 @param Size Buffer size.\r
953 @param Buffer Buffer address.\r
954\r
955 @retval TRUE Profile udpate success.\r
956 @retval FALSE Profile update fail.\r
957\r
958**/\r
959BOOLEAN\r
960SmmCoreUpdateProfileFree (\r
961 IN PHYSICAL_ADDRESS CallerAddress,\r
962 IN MEMORY_PROFILE_ACTION Action,\r
963 IN UINTN Size,\r
964 IN VOID *Buffer\r
965 )\r
966{\r
967 MEMORY_PROFILE_CONTEXT *Context;\r
968 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
969 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
970 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
971 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
972 LIST_ENTRY *DriverLink;\r
973 LIST_ENTRY *DriverInfoList;\r
974 MEMORY_PROFILE_DRIVER_INFO_DATA *ThisDriverInfoData;\r
975 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
976 EFI_MEMORY_TYPE ProfileMemoryIndex;\r
977\r
978 ContextData = GetSmramProfileContext ();\r
979 if (ContextData == NULL) {\r
980 return FALSE;\r
981 }\r
982\r
983 DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);\r
984 ASSERT (DriverInfoData != NULL);\r
985\r
986 switch (Action) {\r
987 case MemoryProfileActionFreePages:\r
988 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);\r
989 break;\r
990 case MemoryProfileActionFreePool:\r
991 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);\r
992 break;\r
993 default:\r
994 ASSERT (FALSE);\r
995 AllocInfoData = NULL;\r
996 break;\r
997 }\r
998 if (AllocInfoData == NULL) {\r
999 //\r
1000 // Legal case, because driver A might free memory allocated by driver B, by some protocol.\r
1001 //\r
1002 DriverInfoList = ContextData->DriverInfoList;\r
1003\r
1004 for (DriverLink = DriverInfoList->ForwardLink;\r
1005 DriverLink != DriverInfoList;\r
1006 DriverLink = DriverLink->ForwardLink) {\r
1007 ThisDriverInfoData = CR (\r
1008 DriverLink,\r
1009 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
1010 Link,\r
1011 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
1012 );\r
1013 switch (Action) {\r
1014 case MemoryProfileActionFreePages:\r
1015 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);\r
1016 break;\r
1017 case MemoryProfileActionFreePool:\r
1018 AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);\r
1019 break;\r
1020 default:\r
1021 ASSERT (FALSE);\r
1022 AllocInfoData = NULL;\r
1023 break;\r
1024 }\r
1025 if (AllocInfoData != NULL) {\r
1026 DriverInfoData = ThisDriverInfoData;\r
1027 break;\r
1028 }\r
1029 }\r
1030\r
1031 if (AllocInfoData == NULL) {\r
1032 //\r
1033 // No matched allocate operation is found for this free operation.\r
1034 // It is because the specified memory type allocate operation has been\r
1035 // filtered by CoreNeedRecordProfile(), but free operations have no\r
1036 // memory type information, they can not be filtered by CoreNeedRecordProfile().\r
1037 // Then, they will be filtered here.\r
1038 //\r
1039 return FALSE;\r
1040 }\r
1041 }\r
1042\r
1043 Context = &ContextData->Context;\r
1044 DriverInfo = &DriverInfoData->DriverInfo;\r
1045 AllocInfo = &AllocInfoData->AllocInfo;\r
1046\r
1047 ProfileMemoryIndex = GetProfileMemoryIndex (AllocInfo->MemoryType);\r
1048\r
1049 Context->CurrentTotalUsage -= AllocInfo->Size;\r
1050 Context->CurrentTotalUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;\r
1051\r
1052 DriverInfo->CurrentUsage -= AllocInfo->Size;\r
1053 DriverInfo->CurrentUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;\r
1054 DriverInfo->AllocRecordCount --;\r
1055\r
1056 RemoveEntryList (&AllocInfoData->Link);\r
1057\r
1058 if (Action == MemoryProfileActionFreePages) {\r
1059 if (AllocInfo->Buffer != (PHYSICAL_ADDRESS) (UINTN) Buffer) {\r
1060 SmmCoreUpdateProfileAllocate (\r
1061 AllocInfo->CallerAddress,\r
1062 MemoryProfileActionAllocatePages,\r
1063 AllocInfo->MemoryType,\r
1064 (UINTN) ((PHYSICAL_ADDRESS) (UINTN) Buffer - AllocInfo->Buffer),\r
1065 (VOID *) (UINTN) AllocInfo->Buffer\r
1066 );\r
1067 }\r
1068 if (AllocInfo->Buffer + AllocInfo->Size != ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)) {\r
1069 SmmCoreUpdateProfileAllocate (\r
1070 AllocInfo->CallerAddress,\r
1071 MemoryProfileActionAllocatePages,\r
1072 AllocInfo->MemoryType,\r
1073 (UINTN) ((AllocInfo->Buffer + AllocInfo->Size) - ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)),\r
1074 (VOID *) ((UINTN) Buffer + Size)\r
1075 );\r
1076 }\r
1077 }\r
1078\r
1079 //\r
1080 // Use SmmInternalFreePool() that will not update profile for this FreePool action.\r
1081 //\r
1082 SmmInternalFreePool (AllocInfoData);\r
1083\r
1084 return TRUE;\r
1085}\r
1086\r
1087/**\r
1088 Update SMRAM profile information.\r
1089\r
1090 @param CallerAddress Address of caller who call Allocate or Free.\r
1091 @param Action This Allocate or Free action.\r
1092 @param MemoryType Memory type.\r
1093 @param Size Buffer size.\r
1094 @param Buffer Buffer address.\r
1095\r
1096 @retval TRUE Profile udpate success.\r
1097 @retval FALSE Profile update fail.\r
1098\r
1099**/\r
1100BOOLEAN\r
1101SmmCoreUpdateProfile (\r
1102 IN PHYSICAL_ADDRESS CallerAddress,\r
1103 IN MEMORY_PROFILE_ACTION Action,\r
1104 IN EFI_MEMORY_TYPE MemoryType, // Valid for AllocatePages/AllocatePool\r
1105 IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool\r
1106 IN VOID *Buffer\r
1107 )\r
1108{\r
1109 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1110\r
1111 if (!IS_SMRAM_PROFILE_ENABLED) {\r
1112 return FALSE;\r
1113 }\r
1114\r
1115 if (!mSmramProfileRecordingStatus) {\r
1116 return FALSE;\r
1117 }\r
1118\r
1119 //\r
1120 // Free operations have no memory type information, so skip the check.\r
1121 //\r
1122 if ((Action == MemoryProfileActionAllocatePages) || (Action == MemoryProfileActionAllocatePool)) {\r
1123 //\r
1124 // Only record limited MemoryType.\r
1125 //\r
1126 if (!SmmCoreNeedRecordProfile (MemoryType)) {\r
1127 return FALSE;\r
1128 }\r
1129 }\r
1130\r
1131 ContextData = GetSmramProfileContext ();\r
1132 if (ContextData == NULL) {\r
1133 return FALSE;\r
1134 }\r
1135\r
1136 switch (Action) {\r
1137 case MemoryProfileActionAllocatePages:\r
1138 SmmCoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer);\r
1139 break;\r
1140 case MemoryProfileActionFreePages:\r
1141 SmmCoreUpdateProfileFree (CallerAddress, Action, Size, Buffer);\r
1142 break;\r
1143 case MemoryProfileActionAllocatePool:\r
1144 SmmCoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer);\r
1145 break;\r
1146 case MemoryProfileActionFreePool:\r
1147 SmmCoreUpdateProfileFree (CallerAddress, Action, 0, Buffer);\r
1148 break;\r
1149 default:\r
1150 ASSERT (FALSE);\r
1151 break;\r
1152 }\r
1153\r
1154 return TRUE;\r
1155}\r
1156\r
1157/**\r
1158 SMRAM profile ready to lock callback function.\r
1159\r
1160**/\r
1161VOID\r
1162SmramProfileReadyToLock (\r
1163 VOID\r
1164 )\r
1165{\r
1166 if (!IS_SMRAM_PROFILE_ENABLED) {\r
1167 return;\r
1168 }\r
1169\r
1170 DEBUG ((EFI_D_INFO, "SmramProfileReadyToLock\n"));\r
1171 mSmramReadyToLock = TRUE;\r
1172}\r
1173\r
1174////////////////////\r
1175\r
1176/**\r
1177 This function check if the address is in SMRAM.\r
1178\r
1179 @param Buffer the buffer address to be checked.\r
1180 @param Length the buffer length to be checked.\r
1181\r
1182 @retval TRUE this address is in SMRAM.\r
1183 @retval FALSE this address is NOT in SMRAM.\r
1184\r
1185**/\r
1186BOOLEAN\r
1187InternalIsAddressInSmram (\r
1188 IN PHYSICAL_ADDRESS Buffer,\r
1189 IN UINT64 Length\r
1190 )\r
1191{\r
1192 UINTN Index;\r
1193\r
1194 for (Index = 0; Index < mFullSmramRangeCount; Index ++) {\r
1195 if (((Buffer >= mFullSmramRanges[Index].CpuStart) && (Buffer < mFullSmramRanges[Index].CpuStart + mFullSmramRanges[Index].PhysicalSize)) ||\r
1196 ((mFullSmramRanges[Index].CpuStart >= Buffer) && (mFullSmramRanges[Index].CpuStart < Buffer + Length))) {\r
1197 return TRUE;\r
1198 }\r
1199 }\r
1200\r
1201 return FALSE;\r
1202}\r
1203\r
1204/**\r
1205 This function check if the address refered by Buffer and Length is valid.\r
1206\r
1207 @param Buffer the buffer address to be checked.\r
1208 @param Length the buffer length to be checked.\r
1209\r
1210 @retval TRUE this address is valid.\r
1211 @retval FALSE this address is NOT valid.\r
1212**/\r
1213BOOLEAN\r
1214InternalIsAddressValid (\r
1215 IN UINTN Buffer,\r
1216 IN UINTN Length\r
1217 )\r
1218{\r
1219 if (Buffer > (MAX_ADDRESS - Length)) {\r
1220 //\r
1221 // Overflow happen\r
1222 //\r
1223 return FALSE;\r
1224 }\r
1225 if (InternalIsAddressInSmram ((PHYSICAL_ADDRESS) Buffer, (UINT64)Length)) {\r
1226 return FALSE;\r
1227 }\r
1228 return TRUE;\r
1229}\r
1230\r
1231/**\r
1232 Get SMRAM profile data size.\r
1233\r
1234 @return SMRAM profile data size.\r
1235\r
1236**/\r
1237UINTN\r
1238SmramProfileGetDataSize (\r
1239 VOID\r
1240 )\r
1241{\r
1242 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1243 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
1244 LIST_ENTRY *DriverInfoList;\r
1245 LIST_ENTRY *DriverLink;\r
1246 UINTN TotalSize;\r
1247 LIST_ENTRY *Node;\r
1248 LIST_ENTRY *FreePageList;\r
1249 LIST_ENTRY *FreePoolList;\r
1250 FREE_POOL_HEADER *Pool;\r
1251 UINTN PoolListIndex;\r
1252 UINTN Index;\r
1253\r
1254 ContextData = GetSmramProfileContext ();\r
1255 if (ContextData == NULL) {\r
1256 return 0;\r
1257 }\r
1258\r
1259 TotalSize = sizeof (MEMORY_PROFILE_CONTEXT);\r
1260 TotalSize += sizeof (MEMORY_PROFILE_DRIVER_INFO) * (UINTN) ContextData->Context.ImageCount;\r
1261\r
1262 DriverInfoList = ContextData->DriverInfoList;\r
1263 for (DriverLink = DriverInfoList->ForwardLink;\r
1264 DriverLink != DriverInfoList;\r
1265 DriverLink = DriverLink->ForwardLink) {\r
1266 DriverInfoData = CR (\r
1267 DriverLink,\r
1268 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
1269 Link,\r
1270 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
1271 );\r
1272 TotalSize += sizeof (MEMORY_PROFILE_ALLOC_INFO) * (UINTN) DriverInfoData->DriverInfo.AllocRecordCount;\r
1273 }\r
1274\r
1275\r
1276 Index = 0;\r
1277 FreePageList = &mSmmMemoryMap;\r
1278 for (Node = FreePageList->BackLink;\r
1279 Node != FreePageList;\r
1280 Node = Node->BackLink) {\r
1281 Index++;\r
1282 }\r
1283 for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {\r
1284 FreePoolList = &mSmmPoolLists[PoolListIndex];\r
1285 for (Node = FreePoolList->BackLink;\r
1286 Node != FreePoolList;\r
1287 Node = Node->BackLink) {\r
1288 Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);\r
1289 if (Pool->Header.Available) {\r
1290 Index++;\r
1291 }\r
1292 }\r
1293 }\r
1294\r
1295\r
1296 TotalSize += (sizeof (MEMORY_PROFILE_FREE_MEMORY) + Index * sizeof (MEMORY_PROFILE_DESCRIPTOR));\r
1297 TotalSize += (sizeof (MEMORY_PROFILE_MEMORY_RANGE) + mFullSmramRangeCount * sizeof (MEMORY_PROFILE_DESCRIPTOR));\r
1298\r
1299 return TotalSize;\r
1300}\r
1301\r
1302/**\r
1303 Copy SMRAM profile data.\r
1304\r
1305 @param ProfileBuffer The buffer to hold SMRAM profile data.\r
1306\r
1307**/\r
1308VOID\r
1309SmramProfileCopyData (\r
1310 IN VOID *ProfileBuffer\r
1311 )\r
1312{\r
1313 MEMORY_PROFILE_CONTEXT *Context;\r
1314 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
1315 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
1316 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1317 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
1318 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
1319 LIST_ENTRY *DriverInfoList;\r
1320 LIST_ENTRY *DriverLink;\r
1321 LIST_ENTRY *AllocInfoList;\r
1322 LIST_ENTRY *AllocLink;\r
1323 LIST_ENTRY *Node;\r
1324 FREE_PAGE_LIST *Pages;\r
1325 LIST_ENTRY *FreePageList;\r
1326 LIST_ENTRY *FreePoolList;\r
1327 FREE_POOL_HEADER *Pool;\r
1328 UINTN PoolListIndex;\r
1329 UINT32 Index;\r
1330 MEMORY_PROFILE_FREE_MEMORY *FreeMemory;\r
1331 MEMORY_PROFILE_MEMORY_RANGE *MemoryRange;\r
1332 MEMORY_PROFILE_DESCRIPTOR *MemoryProfileDescriptor;\r
1333\r
1334 ContextData = GetSmramProfileContext ();\r
1335 if (ContextData == NULL) {\r
1336 return ;\r
1337 }\r
1338\r
1339 Context = ProfileBuffer;\r
1340 CopyMem (Context, &ContextData->Context, sizeof (MEMORY_PROFILE_CONTEXT));\r
1341 DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) (Context + 1);\r
1342\r
1343 DriverInfoList = ContextData->DriverInfoList;\r
1344 for (DriverLink = DriverInfoList->ForwardLink;\r
1345 DriverLink != DriverInfoList;\r
1346 DriverLink = DriverLink->ForwardLink) {\r
1347 DriverInfoData = CR (\r
1348 DriverLink,\r
1349 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
1350 Link,\r
1351 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
1352 );\r
1353 CopyMem (DriverInfo, &DriverInfoData->DriverInfo, sizeof (MEMORY_PROFILE_DRIVER_INFO));\r
1354 AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) (DriverInfo + 1);\r
1355\r
1356 AllocInfoList = DriverInfoData->AllocInfoList;\r
1357 for (AllocLink = AllocInfoList->ForwardLink;\r
1358 AllocLink != AllocInfoList;\r
1359 AllocLink = AllocLink->ForwardLink) {\r
1360 AllocInfoData = CR (\r
1361 AllocLink,\r
1362 MEMORY_PROFILE_ALLOC_INFO_DATA,\r
1363 Link,\r
1364 MEMORY_PROFILE_ALLOC_INFO_SIGNATURE\r
1365 );\r
1366 CopyMem (AllocInfo, &AllocInfoData->AllocInfo, sizeof (MEMORY_PROFILE_ALLOC_INFO));\r
1367 AllocInfo += 1;\r
1368 }\r
1369\r
1370 DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) ((UINTN) (DriverInfo + 1) + sizeof (MEMORY_PROFILE_ALLOC_INFO) * (UINTN) DriverInfo->AllocRecordCount);\r
1371 }\r
1372\r
1373\r
1374 FreeMemory = (MEMORY_PROFILE_FREE_MEMORY *) DriverInfo;\r
1375 CopyMem (FreeMemory, &mSmramFreeMemory, sizeof (MEMORY_PROFILE_FREE_MEMORY));\r
1376 MemoryProfileDescriptor = (MEMORY_PROFILE_DESCRIPTOR *) (FreeMemory + 1);\r
1377 Index = 0;\r
1378 FreePageList = &mSmmMemoryMap;\r
1379 for (Node = FreePageList->BackLink;\r
1380 Node != FreePageList;\r
1381 Node = Node->BackLink) {\r
1382 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
1383 MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;\r
1384 MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);\r
1385 MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;\r
1386 MemoryProfileDescriptor->Address = (PHYSICAL_ADDRESS) (UINTN) Pages;\r
1387 MemoryProfileDescriptor->Size = EFI_PAGES_TO_SIZE (Pages->NumberOfPages);\r
1388 MemoryProfileDescriptor++;\r
1389 Index++;\r
1390 }\r
1391 for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {\r
1392 FreePoolList = &mSmmPoolLists[MAX_POOL_INDEX - PoolListIndex - 1];\r
1393 for (Node = FreePoolList->BackLink;\r
1394 Node != FreePoolList;\r
1395 Node = Node->BackLink) {\r
1396 Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);\r
1397 if (Pool->Header.Available) {\r
1398 MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;\r
1399 MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);\r
1400 MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;\r
1401 MemoryProfileDescriptor->Address = (PHYSICAL_ADDRESS) (UINTN) Pool;\r
1402 MemoryProfileDescriptor->Size = Pool->Header.Size;\r
1403 MemoryProfileDescriptor++;\r
1404 Index++;\r
1405 }\r
1406 }\r
1407 }\r
1408 FreeMemory->FreeMemoryEntryCount = Index;\r
1409\r
1410 MemoryRange = (MEMORY_PROFILE_MEMORY_RANGE *) MemoryProfileDescriptor;\r
1411 MemoryRange->Header.Signature = MEMORY_PROFILE_MEMORY_RANGE_SIGNATURE;\r
1412 MemoryRange->Header.Length = sizeof (MEMORY_PROFILE_MEMORY_RANGE);\r
1413 MemoryRange->Header.Revision = MEMORY_PROFILE_MEMORY_RANGE_REVISION;\r
1414 MemoryRange->MemoryRangeCount = (UINT32) mFullSmramRangeCount;\r
1415 MemoryProfileDescriptor = (MEMORY_PROFILE_DESCRIPTOR *) (MemoryRange + 1);\r
1416 for (Index = 0; Index < mFullSmramRangeCount; Index++) {\r
1417 MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;\r
1418 MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);\r
1419 MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;\r
1420 MemoryProfileDescriptor->Address = mFullSmramRanges[Index].PhysicalStart;\r
1421 MemoryProfileDescriptor->Size = mFullSmramRanges[Index].PhysicalSize;\r
1422 MemoryProfileDescriptor++; \r
1423 }\r
1424}\r
1425\r
1426/**\r
1427 SMRAM profile handler to get profile info.\r
1428\r
1429 @param SmramProfileParameterGetInfo The parameter of SMM profile get size.\r
1430\r
1431**/\r
1432VOID\r
1433SmramProfileHandlerGetInfo (\r
1434 IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *SmramProfileParameterGetInfo\r
1435 )\r
1436{\r
1437 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1438 BOOLEAN SmramProfileRecordingStatus;\r
1439\r
1440 ContextData = GetSmramProfileContext ();\r
1441 if (ContextData == NULL) {\r
1442 return ;\r
1443 }\r
1444\r
1445 SmramProfileRecordingStatus = mSmramProfileRecordingStatus;\r
1446 mSmramProfileRecordingStatus = FALSE;\r
1447\r
1448 SmramProfileParameterGetInfo->ProfileSize = SmramProfileGetDataSize();\r
1449 SmramProfileParameterGetInfo->Header.ReturnStatus = 0;\r
1450\r
1451 mSmramProfileRecordingStatus = SmramProfileRecordingStatus;\r
1452}\r
1453\r
1454/**\r
1455 SMRAM profile handler to get profile data.\r
1456\r
1457 @param SmramProfileParameterGetData The parameter of SMM profile get data.\r
1458\r
1459**/\r
1460VOID\r
1461SmramProfileHandlerGetData (\r
1462 IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA *SmramProfileParameterGetData\r
1463 )\r
1464{\r
1465 UINT64 ProfileSize;\r
1466 SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA SmramProfileGetData;\r
1467 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1468 BOOLEAN SmramProfileRecordingStatus;\r
1469\r
1470 ContextData = GetSmramProfileContext ();\r
1471 if (ContextData == NULL) {\r
1472 return ;\r
1473 }\r
1474\r
1475 SmramProfileRecordingStatus = mSmramProfileRecordingStatus;\r
1476 mSmramProfileRecordingStatus = FALSE;\r
1477\r
1478\r
1479 CopyMem (&SmramProfileGetData, SmramProfileParameterGetData, sizeof (SmramProfileGetData));\r
1480\r
1481 ProfileSize = SmramProfileGetDataSize();\r
1482\r
1483 //\r
1484 // Sanity check\r
1485 //\r
1486 if (!InternalIsAddressValid ((UINTN) SmramProfileGetData.ProfileBuffer, (UINTN) ProfileSize)) {\r
1487 DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetData: SMM ProfileBuffer in SMRAM or overflow!\n"));\r
1488 SmramProfileParameterGetData->ProfileSize = ProfileSize;\r
1489 SmramProfileParameterGetData->Header.ReturnStatus = (UINT64) (INT64) (INTN) EFI_ACCESS_DENIED;\r
1490 goto Done;\r
1491 }\r
1492\r
1493 if (SmramProfileGetData.ProfileSize < ProfileSize) {\r
1494 SmramProfileParameterGetData->ProfileSize = ProfileSize;\r
1495 SmramProfileParameterGetData->Header.ReturnStatus = (UINT64) (INT64) (INTN) EFI_BUFFER_TOO_SMALL;\r
1496 goto Done;\r
1497 }\r
1498\r
1499 SmramProfileParameterGetData->ProfileSize = ProfileSize;\r
1500 SmramProfileCopyData ((VOID *) (UINTN) SmramProfileGetData.ProfileBuffer);\r
1501 SmramProfileParameterGetData->Header.ReturnStatus = 0;\r
1502\r
1503Done:\r
1504 mSmramProfileRecordingStatus = SmramProfileRecordingStatus;\r
1505}\r
1506\r
1507/**\r
1508 SMRAM profile handler to register SMM image.\r
1509\r
1510 @param SmramProfileParameterRegisterImage The parameter of SMM profile register image.\r
1511\r
1512**/\r
1513VOID\r
1514SmramProfileHandlerRegisterImage (\r
1515 IN SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE *SmramProfileParameterRegisterImage\r
1516 )\r
1517{\r
1518 EFI_STATUS Status;\r
1519 EFI_SMM_DRIVER_ENTRY DriverEntry;\r
1520 VOID *EntryPointInImage;\r
1521 BOOLEAN Ret;\r
1522\r
1523 ZeroMem (&DriverEntry, sizeof (DriverEntry));\r
1524 CopyMem (&DriverEntry.FileName, &SmramProfileParameterRegisterImage->FileName, sizeof(EFI_GUID));\r
1525 DriverEntry.ImageBuffer = SmramProfileParameterRegisterImage->ImageBuffer;\r
1526 DriverEntry.NumberOfPage = (UINTN) SmramProfileParameterRegisterImage->NumberOfPage;\r
1527 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) DriverEntry.ImageBuffer, &EntryPointInImage);\r
1528 ASSERT_EFI_ERROR (Status);\r
1529 DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;\r
1530\r
1531 Ret = RegisterSmramProfileImage (&DriverEntry, FALSE);\r
1532 if (Ret) {\r
1533 SmramProfileParameterRegisterImage->Header.ReturnStatus = 0;\r
1534 }\r
1535}\r
1536\r
1537/**\r
1538 SMRAM profile handler to unregister SMM image.\r
1539\r
1540 @param SmramProfileParameterUnregisterImage The parameter of SMM profile unregister image.\r
1541\r
1542**/\r
1543VOID\r
1544SmramProfileHandlerUnregisterImage (\r
1545 IN SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE *SmramProfileParameterUnregisterImage\r
1546 )\r
1547{\r
1548 EFI_STATUS Status;\r
1549 EFI_SMM_DRIVER_ENTRY DriverEntry;\r
1550 VOID *EntryPointInImage;\r
1551 BOOLEAN Ret;\r
1552\r
1553 ZeroMem (&DriverEntry, sizeof (DriverEntry));\r
1554 CopyMem (&DriverEntry.FileName, &SmramProfileParameterUnregisterImage->FileName, sizeof (EFI_GUID));\r
1555 DriverEntry.ImageBuffer = SmramProfileParameterUnregisterImage->ImageBuffer;\r
1556 DriverEntry.NumberOfPage = (UINTN) SmramProfileParameterUnregisterImage->NumberOfPage;\r
1557 Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) DriverEntry.ImageBuffer, &EntryPointInImage);\r
1558 ASSERT_EFI_ERROR (Status);\r
1559 DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;\r
1560\r
1561 Ret = UnregisterSmramProfileImage (&DriverEntry, FALSE);\r
1562 if (Ret) {\r
1563 SmramProfileParameterUnregisterImage->Header.ReturnStatus = 0;\r
1564 }\r
1565}\r
1566\r
1567/**\r
1568 Dispatch function for a Software SMI handler.\r
1569\r
1570 Caution: This function may receive untrusted input.\r
1571 Communicate buffer and buffer size are external input, so this function will do basic validation.\r
1572\r
1573 @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
1574 @param Context Points to an optional handler context which was specified when the\r
1575 handler was registered.\r
1576 @param CommBuffer A pointer to a collection of data in memory that will\r
1577 be conveyed from a non-SMM environment into an SMM environment.\r
1578 @param CommBufferSize The size of the CommBuffer.\r
1579\r
1580 @retval EFI_SUCCESS Command is handled successfully.\r
1581\r
1582**/\r
1583EFI_STATUS\r
1584EFIAPI\r
1585SmramProfileHandler (\r
1586 IN EFI_HANDLE DispatchHandle,\r
1587 IN CONST VOID *Context OPTIONAL,\r
1588 IN OUT VOID *CommBuffer OPTIONAL,\r
1589 IN OUT UINTN *CommBufferSize OPTIONAL\r
1590 )\r
1591{\r
1592 SMRAM_PROFILE_PARAMETER_HEADER *SmramProfileParameterHeader;\r
1593 UINTN TempCommBufferSize;\r
1594\r
1595 DEBUG ((EFI_D_ERROR, "SmramProfileHandler Enter\n"));\r
1596\r
1597 //\r
1598 // If input is invalid, stop processing this SMI\r
1599 //\r
1600 if (CommBuffer == NULL || CommBufferSize == NULL) {\r
1601 return EFI_SUCCESS;\r
1602 }\r
1603\r
1604 TempCommBufferSize = *CommBufferSize;\r
1605\r
1606 if (TempCommBufferSize < sizeof (SMRAM_PROFILE_PARAMETER_HEADER)) {\r
1607 DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));\r
1608 return EFI_SUCCESS;\r
1609 }\r
1610\r
1611 if (mSmramReadyToLock && !InternalIsAddressValid ((UINTN)CommBuffer, TempCommBufferSize)) {\r
1612 DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer in SMRAM or overflow!\n"));\r
1613 return EFI_SUCCESS;\r
1614 }\r
1615\r
1616 SmramProfileParameterHeader = (SMRAM_PROFILE_PARAMETER_HEADER *) ((UINTN) CommBuffer);\r
1617\r
1618 SmramProfileParameterHeader->ReturnStatus = (UINT64)-1;\r
1619\r
1620 if (GetSmramProfileContext () == NULL) {\r
1621 SmramProfileParameterHeader->ReturnStatus = (UINT64) (INT64) (INTN) EFI_UNSUPPORTED;\r
1622 return EFI_SUCCESS;\r
1623 }\r
1624\r
1625 switch (SmramProfileParameterHeader->Command) {\r
1626 case SMRAM_PROFILE_COMMAND_GET_PROFILE_INFO:\r
1627 DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetInfo\n"));\r
1628 if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO)) {\r
1629 DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));\r
1630 return EFI_SUCCESS;\r
1631 }\r
1632 SmramProfileHandlerGetInfo ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *) (UINTN) CommBuffer);\r
1633 break;\r
1634 case SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA:\r
1635 DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetData\n"));\r
1636 if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA)) {\r
1637 DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));\r
1638 return EFI_SUCCESS;\r
1639 }\r
1640 SmramProfileHandlerGetData ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA *) (UINTN) CommBuffer);\r
1641 break;\r
1642 case SMRAM_PROFILE_COMMAND_REGISTER_IMAGE:\r
1643 DEBUG ((EFI_D_ERROR, "SmramProfileHandlerRegisterImage\n"));\r
1644 if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE)) {\r
1645 DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));\r
1646 return EFI_SUCCESS;\r
1647 }\r
1648 if (mSmramReadyToLock) {\r
1649 return EFI_SUCCESS;\r
1650 }\r
1651 SmramProfileHandlerRegisterImage ((SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE *) (UINTN) CommBuffer);\r
1652 break;\r
1653 case SMRAM_PROFILE_COMMAND_UNREGISTER_IMAGE:\r
1654 DEBUG ((EFI_D_ERROR, "SmramProfileHandlerUnregisterImage\n"));\r
1655 if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE)) {\r
1656 DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));\r
1657 return EFI_SUCCESS;\r
1658 }\r
1659 if (mSmramReadyToLock) {\r
1660 return EFI_SUCCESS;\r
1661 }\r
1662 SmramProfileHandlerUnregisterImage ((SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE *) (UINTN) CommBuffer);\r
1663 break;\r
1664 default:\r
1665 break;\r
1666 }\r
1667\r
1668 DEBUG ((EFI_D_ERROR, "SmramProfileHandler Exit\n"));\r
1669\r
1670 return EFI_SUCCESS;\r
1671}\r
1672\r
1673/**\r
1674 Register SMRAM profile handler.\r
1675\r
1676**/\r
1677VOID\r
1678RegisterSmramProfileHandler (\r
1679 VOID\r
1680 )\r
1681{\r
1682 EFI_STATUS Status;\r
1683 EFI_HANDLE DispatchHandle;\r
1684\r
1685 if (!IS_SMRAM_PROFILE_ENABLED) {\r
1686 return;\r
1687 }\r
1688\r
1689 Status = SmiHandlerRegister (\r
1690 SmramProfileHandler,\r
1691 &gEdkiiMemoryProfileGuid,\r
1692 &DispatchHandle\r
1693 );\r
1694 ASSERT_EFI_ERROR (Status);\r
1695}\r
1696\r
1697////////////////////\r
1698\r
1699/**\r
1700 Dump SMRAM range.\r
1701\r
1702**/\r
1703VOID\r
1704DumpSmramRange (\r
1705 VOID\r
1706 )\r
1707{\r
1708 UINTN Index;\r
1709 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1710 BOOLEAN SmramProfileRecordingStatus;\r
1711\r
1712 ContextData = GetSmramProfileContext ();\r
1713 if (ContextData == NULL) {\r
1714 return ;\r
1715 }\r
1716\r
1717 SmramProfileRecordingStatus = mSmramProfileRecordingStatus;\r
1718 mSmramProfileRecordingStatus = FALSE;\r
1719\r
1720 DEBUG ((EFI_D_INFO, "FullSmramRange address - 0x%08x\n", mFullSmramRanges));\r
1721\r
1722 DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));\r
1723\r
1724 DEBUG ((EFI_D_INFO, "FullSmramRange:\n"));\r
1725 for (Index = 0; Index < mFullSmramRangeCount; Index++) {\r
1726 DEBUG ((EFI_D_INFO, " FullSmramRange (0x%x)\n", Index));\r
1727 DEBUG ((EFI_D_INFO, " PhysicalStart - 0x%016lx\n", mFullSmramRanges[Index].PhysicalStart));\r
1728 DEBUG ((EFI_D_INFO, " CpuStart - 0x%016lx\n", mFullSmramRanges[Index].CpuStart));\r
1729 DEBUG ((EFI_D_INFO, " PhysicalSize - 0x%016lx\n", mFullSmramRanges[Index].PhysicalSize));\r
1730 DEBUG ((EFI_D_INFO, " RegionState - 0x%016lx\n", mFullSmramRanges[Index].RegionState));\r
1731 }\r
1732\r
1733 DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));\r
1734\r
1735 mSmramProfileRecordingStatus = SmramProfileRecordingStatus;\r
1736}\r
1737\r
1738/**\r
1739 Dump SMRAM free page list.\r
1740\r
1741**/\r
1742VOID\r
1743DumpFreePagesList (\r
1744 VOID\r
1745 )\r
1746{\r
1747 LIST_ENTRY *FreePageList;\r
1748 LIST_ENTRY *Node;\r
1749 FREE_PAGE_LIST *Pages;\r
1750 UINTN Index;\r
1751 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1752 BOOLEAN SmramProfileRecordingStatus;\r
1753\r
1754 ContextData = GetSmramProfileContext ();\r
1755 if (ContextData == NULL) {\r
1756 return ;\r
1757 }\r
1758\r
1759 SmramProfileRecordingStatus = mSmramProfileRecordingStatus;\r
1760 mSmramProfileRecordingStatus = FALSE;\r
1761\r
1762 DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));\r
1763\r
1764 DEBUG ((EFI_D_INFO, "FreePagesList:\n"));\r
1765 FreePageList = &mSmmMemoryMap;\r
1766 for (Node = FreePageList->BackLink, Index = 0;\r
1767 Node != FreePageList;\r
1768 Node = Node->BackLink, Index++) {\r
1769 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
1770 DEBUG ((EFI_D_INFO, " Index - 0x%x\n", Index));\r
1771 DEBUG ((EFI_D_INFO, " PhysicalStart - 0x%016lx\n", (PHYSICAL_ADDRESS) (UINTN) Pages));\r
1772 DEBUG ((EFI_D_INFO, " NumberOfPages - 0x%08x\n", Pages->NumberOfPages));\r
1773 }\r
1774\r
1775 DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));\r
1776\r
1777 mSmramProfileRecordingStatus = SmramProfileRecordingStatus;\r
1778}\r
1779\r
1780/**\r
1781 Dump SMRAM free pool list.\r
1782\r
1783**/\r
1784VOID\r
1785DumpFreePoolList (\r
1786 VOID\r
1787 )\r
1788{\r
1789 LIST_ENTRY *FreePoolList;\r
1790 LIST_ENTRY *Node;\r
1791 FREE_POOL_HEADER *Pool;\r
1792 UINTN Index;\r
1793 UINTN PoolListIndex;\r
1794 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1795 BOOLEAN SmramProfileRecordingStatus;\r
1796\r
1797 ContextData = GetSmramProfileContext ();\r
1798 if (ContextData == NULL) {\r
1799 return ;\r
1800 }\r
1801\r
1802 SmramProfileRecordingStatus = mSmramProfileRecordingStatus;\r
1803 mSmramProfileRecordingStatus = FALSE;\r
1804\r
1805 DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));\r
1806\r
1807 for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {\r
1808 DEBUG ((EFI_D_INFO, "FreePoolList (%d):\n", PoolListIndex));\r
1809 FreePoolList = &mSmmPoolLists[PoolListIndex];\r
1810 for (Node = FreePoolList->BackLink, Index = 0;\r
1811 Node != FreePoolList;\r
1812 Node = Node->BackLink, Index++) {\r
1813 Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);\r
1814 DEBUG ((EFI_D_INFO, " Index - 0x%x\n", Index));\r
1815 DEBUG ((EFI_D_INFO, " PhysicalStart - 0x%016lx\n", (PHYSICAL_ADDRESS) (UINTN) Pool));\r
1816 DEBUG ((EFI_D_INFO, " Size - 0x%08x\n", Pool->Header.Size));\r
1817 DEBUG ((EFI_D_INFO, " Available - 0x%02x\n", Pool->Header.Available));\r
1818 }\r
1819 }\r
1820\r
1821 DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));\r
1822\r
1823 mSmramProfileRecordingStatus = SmramProfileRecordingStatus;\r
1824}\r
1825\r
1826GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mActionString[] = {\r
1827 L"Unknown",\r
1828 L"AllocatePages",\r
1829 L"FreePages",\r
1830 L"AllocatePool",\r
1831 L"FreePool",\r
1832};\r
1833\r
1834GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mMemoryTypeString[] = {\r
1835 L"EfiReservedMemoryType",\r
1836 L"EfiLoaderCode",\r
1837 L"EfiLoaderData",\r
1838 L"EfiBootServicesCode",\r
1839 L"EfiBootServicesData",\r
1840 L"EfiRuntimeServicesCode",\r
1841 L"EfiRuntimeServicesData",\r
1842 L"EfiConventionalMemory",\r
1843 L"EfiUnusableMemory",\r
1844 L"EfiACPIReclaimMemory",\r
1845 L"EfiACPIMemoryNVS",\r
1846 L"EfiMemoryMappedIO",\r
1847 L"EfiMemoryMappedIOPortSpace",\r
1848 L"EfiPalCode",\r
1849 L"EfiOSReserved",\r
1850};\r
1851\r
1852\r
1853/**\r
1854 Dump SMRAM profile.\r
1855\r
1856**/\r
1857VOID\r
1858DumpSmramProfile (\r
1859 VOID\r
1860 )\r
1861{\r
1862 MEMORY_PROFILE_CONTEXT *Context;\r
1863 MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
1864 MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
1865 MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
1866 MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
1867 MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
1868 LIST_ENTRY *SmramDriverInfoList;\r
1869 UINTN DriverIndex;\r
1870 LIST_ENTRY *DriverLink;\r
1871 LIST_ENTRY *AllocInfoList;\r
1872 UINTN AllocIndex;\r
1873 LIST_ENTRY *AllocLink;\r
1874 BOOLEAN SmramProfileRecordingStatus;\r
1875 UINTN TypeIndex;\r
1876\r
1877 ContextData = GetSmramProfileContext ();\r
1878 if (ContextData == NULL) {\r
1879 return ;\r
1880 }\r
1881\r
1882 SmramProfileRecordingStatus = mSmramProfileRecordingStatus;\r
1883 mSmramProfileRecordingStatus = FALSE;\r
1884\r
1885 Context = &ContextData->Context;\r
1886 DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));\r
1887 DEBUG ((EFI_D_INFO, "MEMORY_PROFILE_CONTEXT\n"));\r
1888\r
1889 DEBUG ((EFI_D_INFO, " CurrentTotalUsage - 0x%016lx\n", Context->CurrentTotalUsage));\r
1890 DEBUG ((EFI_D_INFO, " PeakTotalUsage - 0x%016lx\n", Context->PeakTotalUsage));\r
1891 for (TypeIndex = 0; TypeIndex <= EfiMaxMemoryType; TypeIndex++) {\r
1892 if ((Context->CurrentTotalUsageByType[TypeIndex] != 0) ||\r
1893 (Context->PeakTotalUsageByType[TypeIndex] != 0)) {\r
1894 DEBUG ((EFI_D_INFO, " CurrentTotalUsage[0x%02x] - 0x%016lx (%s)\n", TypeIndex, Context->CurrentTotalUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]));\r
1895 DEBUG ((EFI_D_INFO, " PeakTotalUsage[0x%02x] - 0x%016lx (%s)\n", TypeIndex, Context->PeakTotalUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]));\r
1896 }\r
1897 }\r
1898 DEBUG ((EFI_D_INFO, " TotalImageSize - 0x%016lx\n", Context->TotalImageSize));\r
1899 DEBUG ((EFI_D_INFO, " ImageCount - 0x%08x\n", Context->ImageCount));\r
1900 DEBUG ((EFI_D_INFO, " SequenceCount - 0x%08x\n", Context->SequenceCount));\r
1901\r
1902 SmramDriverInfoList = ContextData->DriverInfoList;\r
1903 for (DriverLink = SmramDriverInfoList->ForwardLink, DriverIndex = 0;\r
1904 DriverLink != SmramDriverInfoList;\r
1905 DriverLink = DriverLink->ForwardLink, DriverIndex++) {\r
1906 DriverInfoData = CR (\r
1907 DriverLink,\r
1908 MEMORY_PROFILE_DRIVER_INFO_DATA,\r
1909 Link,\r
1910 MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
1911 );\r
1912 DriverInfo = &DriverInfoData->DriverInfo;\r
1913 DEBUG ((EFI_D_INFO, " MEMORY_PROFILE_DRIVER_INFO (0x%x)\n", DriverIndex));\r
1914 DEBUG ((EFI_D_INFO, " FileName - %g\n", &DriverInfo->FileName));\r
1915 DEBUG ((EFI_D_INFO, " ImageBase - 0x%016lx\n", DriverInfo->ImageBase));\r
1916 DEBUG ((EFI_D_INFO, " ImageSize - 0x%016lx\n", DriverInfo->ImageSize));\r
1917 DEBUG ((EFI_D_INFO, " EntryPoint - 0x%016lx\n", DriverInfo->EntryPoint));\r
1918 DEBUG ((EFI_D_INFO, " ImageSubsystem - 0x%04x\n", DriverInfo->ImageSubsystem));\r
1919 DEBUG ((EFI_D_INFO, " FileType - 0x%02x\n", DriverInfo->FileType));\r
1920 DEBUG ((EFI_D_INFO, " CurrentUsage - 0x%016lx\n", DriverInfo->CurrentUsage));\r
1921 DEBUG ((EFI_D_INFO, " PeakUsage - 0x%016lx\n", DriverInfo->PeakUsage));\r
1922 for (TypeIndex = 0; TypeIndex <= EfiMaxMemoryType; TypeIndex++) {\r
1923 if ((DriverInfo->CurrentUsageByType[TypeIndex] != 0) ||\r
1924 (DriverInfo->PeakUsageByType[TypeIndex] != 0)) {\r
1925 DEBUG ((EFI_D_INFO, " CurrentUsage[0x%02x] - 0x%016lx (%s)\n", TypeIndex, DriverInfo->CurrentUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]));\r
1926 DEBUG ((EFI_D_INFO, " PeakUsage[0x%02x] - 0x%016lx (%s)\n", TypeIndex, DriverInfo->PeakUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]));\r
1927 }\r
1928 }\r
1929 DEBUG ((EFI_D_INFO, " AllocRecordCount - 0x%08x\n", DriverInfo->AllocRecordCount));\r
1930\r
1931 AllocInfoList = DriverInfoData->AllocInfoList;\r
1932 for (AllocLink = AllocInfoList->ForwardLink, AllocIndex = 0;\r
1933 AllocLink != AllocInfoList;\r
1934 AllocLink = AllocLink->ForwardLink, AllocIndex++) {\r
1935 AllocInfoData = CR (\r
1936 AllocLink,\r
1937 MEMORY_PROFILE_ALLOC_INFO_DATA,\r
1938 Link,\r
1939 MEMORY_PROFILE_ALLOC_INFO_SIGNATURE\r
1940 );\r
1941 AllocInfo = &AllocInfoData->AllocInfo;\r
1942 DEBUG ((EFI_D_INFO, " MEMORY_PROFILE_ALLOC_INFO (0x%x)\n", AllocIndex));\r
1943 DEBUG ((EFI_D_INFO, " CallerAddress - 0x%016lx (Offset: 0x%08x)\n", AllocInfo->CallerAddress, AllocInfo->CallerAddress - DriverInfo->ImageBase));\r
1944 DEBUG ((EFI_D_INFO, " SequenceId - 0x%08x\n", AllocInfo->SequenceId));\r
1945 DEBUG ((EFI_D_INFO, " Action - 0x%08x (%s)\n", AllocInfo->Action, mActionString[(AllocInfo->Action < sizeof(mActionString)/sizeof(mActionString[0])) ? AllocInfo->Action : 0]));\r
1946 DEBUG ((EFI_D_INFO, " MemoryType - 0x%08x\n", AllocInfo->MemoryType));\r
1947 DEBUG ((EFI_D_INFO, " Buffer - 0x%016lx\n", AllocInfo->Buffer));\r
1948 DEBUG ((EFI_D_INFO, " Size - 0x%016lx\n", AllocInfo->Size));\r
1949 }\r
1950 }\r
1951\r
1952 DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));\r
1953\r
1954 mSmramProfileRecordingStatus = SmramProfileRecordingStatus;\r
1955}\r
1956\r
1957/**\r
1958 Dump SMRAM infromation.\r
1959\r
1960**/\r
1961VOID\r
1962DumpSmramInfo (\r
1963 VOID\r
1964 )\r
1965{\r
1966 DEBUG_CODE (\r
1967 if (IS_SMRAM_PROFILE_ENABLED) {\r
1968 DumpSmramProfile ();\r
1969 DumpFreePagesList ();\r
1970 DumpFreePoolList ();\r
1971 DumpSmramRange ();\r
1972 }\r
1973 );\r
1974}\r
1975\r