MdeModulePkg/SmmCore: Fix memory leak on Profile unregistered.
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / SmiHandlerProfile.c
CommitLineData
ca41f3f4
JY
1/** @file\r
2 SMI handler profile support.\r
3\r
4Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include <PiSmm.h>\r
16#include <Library/BaseLib.h>\r
17#include <Library/BaseMemoryLib.h>\r
18#include <Library/MemoryAllocationLib.h>\r
19#include <Library/UefiBootServicesTableLib.h>\r
20#include <Library/SmmServicesTableLib.h>\r
21#include <Library/DebugLib.h>\r
22#include <Library/PrintLib.h>\r
23#include <Library/UefiLib.h>\r
24#include <Library/DevicePathLib.h>\r
25#include <Library/PeCoffGetEntryPointLib.h>\r
26#include <Library/DxeServicesLib.h>\r
27#include <Protocol/LoadedImage.h>\r
28#include <Protocol/SmmAccess2.h>\r
29#include <Protocol/SmmReadyToLock.h>\r
30#include <Protocol/SmmEndOfDxe.h>\r
31\r
32#include <Guid/SmiHandlerProfile.h>\r
33\r
34#include "PiSmmCore.h"\r
35\r
36typedef struct {\r
37 EFI_GUID FileGuid;\r
38 UINTN ImageRef;\r
39 UINTN EntryPoint;\r
40 UINTN ImageBase;\r
41 UINTN ImageSize;\r
42 UINTN PdbStringSize;\r
43 CHAR8 *PdbString;\r
44} IMAGE_STRUCT;\r
45\r
46/**\r
47 Register SMI handler profile handler.\r
48**/\r
49VOID\r
50RegisterSmiHandlerProfileHandler(\r
51 VOID\r
52 );\r
53\r
54/**\r
55 Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded\r
56 into system memory with the PE/COFF Loader Library functions.\r
57\r
58 Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry\r
59 point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then\r
60 return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS.\r
61 If Pe32Data is NULL, then ASSERT().\r
62 If EntryPoint is NULL, then ASSERT().\r
63\r
64 @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.\r
65 @param EntryPoint The pointer to entry point to the PE/COFF image to return.\r
66\r
67 @retval RETURN_SUCCESS EntryPoint was returned.\r
68 @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image.\r
69\r
70**/\r
71RETURN_STATUS\r
72InternalPeCoffGetEntryPoint (\r
73 IN VOID *Pe32Data,\r
74 OUT VOID **EntryPoint\r
75 );\r
76\r
77extern LIST_ENTRY mSmiEntryList;\r
78extern LIST_ENTRY mHardwareSmiEntryList;\r
79extern SMI_ENTRY mRootSmiEntry;\r
80\r
81extern SMI_HANDLER_PROFILE_PROTOCOL mSmiHandlerProfile;\r
82\r
83GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mHardwareSmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mHardwareSmiEntryList);\r
84\r
85GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mRootSmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntryList);\r
86\r
87GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY *mSmmCoreRootSmiEntryList = &mRootSmiEntryList;\r
88GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY *mSmmCoreSmiEntryList = &mSmiEntryList;\r
89GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY *mSmmCoreHardwareSmiEntryList = &mHardwareSmiEntryList;\r
90\r
91GLOBAL_REMOVE_IF_UNREFERENCED IMAGE_STRUCT *mImageStruct;\r
92GLOBAL_REMOVE_IF_UNREFERENCED UINTN mImageStructCountMax;\r
93GLOBAL_REMOVE_IF_UNREFERENCED UINTN mImageStructCount;\r
94\r
95GLOBAL_REMOVE_IF_UNREFERENCED VOID *mSmiHandlerProfileDatabase;\r
96GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmiHandlerProfileDatabaseSize;\r
97\r
98GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmmImageDatabaseSize;\r
99GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmmRootSmiDatabaseSize;\r
100GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmmSmiDatabaseSize;\r
101GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmmHardwareSmiDatabaseSize;\r
102\r
103GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mSmiHandlerProfileRecordingStatus;\r
104\r
105GLOBAL_REMOVE_IF_UNREFERENCED SMI_HANDLER_PROFILE_PROTOCOL mSmiHandlerProfile = {\r
106 SmiHandlerProfileRegisterHandler,\r
107 SmiHandlerProfileUnregisterHandler,\r
108};\r
109\r
110/**\r
111 This function dump raw data.\r
112\r
113 @param Data raw data\r
114 @param Size raw data size\r
115**/\r
116VOID\r
117InternalDumpData (\r
118 IN UINT8 *Data,\r
119 IN UINTN Size\r
120 )\r
121{\r
122 UINTN Index;\r
123 for (Index = 0; Index < Size; Index++) {\r
124 DEBUG ((DEBUG_INFO, "%02x ", (UINTN)Data[Index]));\r
125 }\r
126}\r
127\r
128/**\r
129 Get GUID name for an image.\r
130\r
131 @param[in] LoadedImage LoadedImage protocol.\r
132 @param[out] Guid Guid of the FFS\r
133**/\r
134VOID\r
135GetDriverGuid (\r
136 IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,\r
137 OUT EFI_GUID *Guid\r
138 )\r
139{\r
140 EFI_GUID *FileName;\r
141\r
142 FileName = NULL;\r
143 if ((DevicePathType(LoadedImage->FilePath) == MEDIA_DEVICE_PATH) &&\r
144 (DevicePathSubType(LoadedImage->FilePath) == MEDIA_PIWG_FW_FILE_DP)) {\r
145 FileName = &((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)LoadedImage->FilePath)->FvFileName;\r
146 }\r
147 if (FileName != NULL) {\r
148 CopyGuid(Guid, FileName);\r
149 } else {\r
150 ZeroMem(Guid, sizeof(EFI_GUID));\r
151 }\r
152}\r
153\r
154/**\r
155 Add image structure.\r
156\r
157 @param ImageBase image base\r
158 @param ImageSize image size\r
159 @param EntryPoint image entry point\r
160 @param Guid FFS GUID of the image\r
161 @param PdbString image PDB string\r
162**/\r
163VOID\r
164AddImageStruct(\r
165 IN UINTN ImageBase,\r
166 IN UINTN ImageSize,\r
167 IN UINTN EntryPoint,\r
168 IN EFI_GUID *Guid,\r
169 IN CHAR8 *PdbString\r
170 )\r
171{\r
172 UINTN PdbStringSize;\r
173\r
174 if (mImageStructCount >= mImageStructCountMax) {\r
175 ASSERT(FALSE);\r
176 return;\r
177 }\r
178\r
179 CopyGuid(&mImageStruct[mImageStructCount].FileGuid, Guid);\r
180 mImageStruct[mImageStructCount].ImageRef = mImageStructCount;\r
181 mImageStruct[mImageStructCount].ImageBase = ImageBase;\r
182 mImageStruct[mImageStructCount].ImageSize = ImageSize;\r
183 mImageStruct[mImageStructCount].EntryPoint = EntryPoint;\r
184 if (PdbString != NULL) {\r
185 PdbStringSize = AsciiStrSize(PdbString);\r
186 mImageStruct[mImageStructCount].PdbString = AllocateCopyPool (PdbStringSize, PdbString);\r
187 if (mImageStruct[mImageStructCount].PdbString != NULL) {\r
188 mImageStruct[mImageStructCount].PdbStringSize = PdbStringSize;\r
189 }\r
190 }\r
191\r
192 mImageStructCount++;\r
193}\r
194\r
195/**\r
196 return an image structure based upon image address.\r
197\r
198 @param Address image address\r
199\r
200 @return image structure\r
201**/\r
202IMAGE_STRUCT *\r
203AddressToImageStruct(\r
204 IN UINTN Address\r
205 )\r
206{\r
207 UINTN Index;\r
208\r
209 for (Index = 0; Index < mImageStructCount; Index++) {\r
210 if ((Address >= mImageStruct[Index].ImageBase) &&\r
211 (Address < mImageStruct[Index].ImageBase + mImageStruct[Index].ImageSize)) {\r
212 return &mImageStruct[Index];\r
213 }\r
214 }\r
215 return NULL;\r
216}\r
217\r
218/**\r
219 return an image reference index based upon image address.\r
220\r
221 @param Address image address\r
222\r
223 @return image reference index\r
224**/\r
225UINTN\r
226AddressToImageRef(\r
227 IN UINTN Address\r
228 )\r
229{\r
230 IMAGE_STRUCT *ImageStruct;\r
231\r
232 ImageStruct = AddressToImageStruct(Address);\r
233 if (ImageStruct != NULL) {\r
234 return ImageStruct->ImageRef;\r
235 }\r
236 return (UINTN)-1;\r
237}\r
238\r
239/**\r
240 Collect SMM image information based upon loaded image protocol.\r
241**/\r
242VOID\r
243GetSmmLoadedImage(\r
244 VOID\r
245 )\r
246{\r
247 EFI_STATUS Status;\r
248 UINTN NoHandles;\r
249 UINTN HandleBufferSize;\r
250 EFI_HANDLE *HandleBuffer;\r
251 UINTN Index;\r
252 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
253 CHAR16 *PathStr;\r
254 EFI_SMM_DRIVER_ENTRY *LoadedImagePrivate;\r
255 UINTN EntryPoint;\r
256 VOID *EntryPointInImage;\r
257 EFI_GUID Guid;\r
258 CHAR8 *PdbString;\r
259 UINTN RealImageBase;\r
260\r
261 HandleBufferSize = 0;\r
262 HandleBuffer = NULL;\r
263 Status = gSmst->SmmLocateHandle(\r
264 ByProtocol,\r
265 &gEfiLoadedImageProtocolGuid,\r
266 NULL,\r
267 &HandleBufferSize,\r
268 HandleBuffer\r
269 );\r
270 if (Status != EFI_BUFFER_TOO_SMALL) {\r
271 return;\r
272 }\r
273 HandleBuffer = AllocateZeroPool (HandleBufferSize);\r
274 if (HandleBuffer == NULL) {\r
275 return;\r
276 }\r
277 Status = gSmst->SmmLocateHandle(\r
278 ByProtocol,\r
279 &gEfiLoadedImageProtocolGuid,\r
280 NULL,\r
281 &HandleBufferSize,\r
282 HandleBuffer\r
283 );\r
284 if (EFI_ERROR(Status)) {\r
285 return;\r
286 }\r
287\r
288 NoHandles = HandleBufferSize/sizeof(EFI_HANDLE);\r
289 mImageStructCountMax = NoHandles;\r
290 mImageStruct = AllocateZeroPool(mImageStructCountMax * sizeof(IMAGE_STRUCT));\r
291 if (mImageStruct == NULL) {\r
292 goto Done;\r
293 }\r
294\r
295 for (Index = 0; Index < NoHandles; Index++) {\r
296 Status = gSmst->SmmHandleProtocol(\r
297 HandleBuffer[Index],\r
298 &gEfiLoadedImageProtocolGuid,\r
299 (VOID **)&LoadedImage\r
300 );\r
301 if (EFI_ERROR(Status)) {\r
302 continue;\r
303 }\r
304 PathStr = ConvertDevicePathToText(LoadedImage->FilePath, TRUE, TRUE);\r
305 GetDriverGuid(LoadedImage, &Guid);\r
306 DEBUG ((DEBUG_INFO, "Image: %g ", &Guid));\r
307\r
308 EntryPoint = 0;\r
309 LoadedImagePrivate = BASE_CR(LoadedImage, EFI_SMM_DRIVER_ENTRY, SmmLoadedImage);\r
310 RealImageBase = (UINTN)LoadedImage->ImageBase;\r
311 if (LoadedImagePrivate->Signature == EFI_SMM_DRIVER_ENTRY_SIGNATURE) {\r
312 EntryPoint = (UINTN)LoadedImagePrivate->ImageEntryPoint;\r
313 if ((EntryPoint != 0) && ((EntryPoint < (UINTN)LoadedImage->ImageBase) || (EntryPoint >= ((UINTN)LoadedImage->ImageBase + (UINTN)LoadedImage->ImageSize)))) {\r
314 //\r
315 // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.\r
316 // So patch ImageBuffer here to align the EntryPoint.\r
317 //\r
318 Status = InternalPeCoffGetEntryPoint(LoadedImage->ImageBase, &EntryPointInImage);\r
319 ASSERT_EFI_ERROR(Status);\r
320 RealImageBase = (UINTN)LoadedImage->ImageBase + EntryPoint - (UINTN)EntryPointInImage;\r
321 }\r
322 }\r
323 DEBUG ((DEBUG_INFO, "(0x%x - 0x%x", RealImageBase, (UINTN)LoadedImage->ImageSize));\r
324 if (EntryPoint != 0) {\r
325 DEBUG ((DEBUG_INFO, ", EntryPoint:0x%x", EntryPoint));\r
326 }\r
327 DEBUG ((DEBUG_INFO, ")\n"));\r
328\r
329 if (RealImageBase != 0) {\r
330 PdbString = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) RealImageBase);\r
331 DEBUG ((DEBUG_INFO, " pdb - %a\n", PdbString));\r
332 } else {\r
333 PdbString = NULL;\r
334 }\r
335 DEBUG ((DEBUG_INFO, " (%s)\n", PathStr));\r
336\r
337 AddImageStruct((UINTN)RealImageBase, (UINTN)LoadedImage->ImageSize, EntryPoint, &Guid, PdbString);\r
338 }\r
339\r
340Done:\r
341 FreePool(HandleBuffer);\r
342 return;\r
343}\r
344\r
345/**\r
346 Dump SMI child context.\r
347\r
348 @param HandlerType the handler type\r
349 @param Context the handler context\r
350 @param ContextSize the handler context size\r
351**/\r
352VOID\r
353DumpSmiChildContext (\r
354 IN EFI_GUID *HandlerType,\r
355 IN VOID *Context,\r
356 IN UINTN ContextSize\r
357 )\r
358{\r
359 if (CompareGuid (HandlerType, &gEfiSmmSwDispatch2ProtocolGuid)) {\r
360 DEBUG ((DEBUG_INFO, " SwSmi - 0x%x\n", ((EFI_SMM_SW_REGISTER_CONTEXT *)Context)->SwSmiInputValue));\r
361 } else if (CompareGuid (HandlerType, &gEfiSmmSxDispatch2ProtocolGuid)) {\r
362 DEBUG ((DEBUG_INFO, " SxType - 0x%x\n", ((EFI_SMM_SX_REGISTER_CONTEXT *)Context)->Type));\r
363 DEBUG ((DEBUG_INFO, " SxPhase - 0x%x\n", ((EFI_SMM_SX_REGISTER_CONTEXT *)Context)->Phase));\r
364 } else if (CompareGuid (HandlerType, &gEfiSmmPowerButtonDispatch2ProtocolGuid)) {\r
365 DEBUG ((DEBUG_INFO, " PowerButtonPhase - 0x%x\n", ((EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT *)Context)->Phase));\r
366 } else if (CompareGuid (HandlerType, &gEfiSmmStandbyButtonDispatch2ProtocolGuid)) {\r
367 DEBUG ((DEBUG_INFO, " StandbyButtonPhase - 0x%x\n", ((EFI_SMM_STANDBY_BUTTON_REGISTER_CONTEXT *)Context)->Phase));\r
368 } else if (CompareGuid (HandlerType, &gEfiSmmPeriodicTimerDispatch2ProtocolGuid)) {\r
369 DEBUG ((DEBUG_INFO, " PeriodicTimerPeriod - %ld\n", ((EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT *)Context)->Period));\r
370 DEBUG ((DEBUG_INFO, " PeriodicTimerSmiTickInterval - %ld\n", ((EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT *)Context)->SmiTickInterval));\r
371 } else if (CompareGuid (HandlerType, &gEfiSmmGpiDispatch2ProtocolGuid)) {\r
372 DEBUG ((DEBUG_INFO, " GpiNum - 0x%lx\n", ((EFI_SMM_GPI_REGISTER_CONTEXT *)Context)->GpiNum));\r
373 } else if (CompareGuid (HandlerType, &gEfiSmmIoTrapDispatch2ProtocolGuid)) {\r
374 DEBUG ((DEBUG_INFO, " IoTrapAddress - 0x%x\n", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Address));\r
375 DEBUG ((DEBUG_INFO, " IoTrapLength - 0x%x\n", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Length));\r
376 DEBUG ((DEBUG_INFO, " IoTrapType - 0x%x\n", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Type));\r
377 } else if (CompareGuid (HandlerType, &gEfiSmmUsbDispatch2ProtocolGuid)) {\r
378 DEBUG ((DEBUG_INFO, " UsbType - 0x%x\n", ((SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *)Context)->Type));\r
379 DEBUG ((DEBUG_INFO, " UsbDevicePath - %s\n", ConvertDevicePathToText((EFI_DEVICE_PATH_PROTOCOL *)(((SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *)Context) + 1), TRUE, TRUE)));\r
380 } else {\r
381 DEBUG ((DEBUG_INFO, " Context - "));\r
382 InternalDumpData (Context, ContextSize);\r
383 DEBUG ((DEBUG_INFO, "\n"));\r
384 }\r
385}\r
386\r
387/**\r
388 Dump all SMI handlers associated with SmiEntry.\r
389\r
390 @param SmiEntry SMI entry.\r
391**/\r
392VOID\r
393DumpSmiHandlerOnSmiEntry(\r
394 IN SMI_ENTRY *SmiEntry\r
395 )\r
396{\r
397 LIST_ENTRY *ListEntry;\r
398 SMI_HANDLER *SmiHandler;\r
399 IMAGE_STRUCT *ImageStruct;\r
400\r
401 ListEntry = &SmiEntry->SmiHandlers;\r
402 for (ListEntry = ListEntry->ForwardLink;\r
403 ListEntry != &SmiEntry->SmiHandlers;\r
404 ListEntry = ListEntry->ForwardLink) {\r
405 SmiHandler = CR(ListEntry, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);\r
406 ImageStruct = AddressToImageStruct((UINTN)SmiHandler->Handler);\r
407 if (ImageStruct != NULL) {\r
408 DEBUG ((DEBUG_INFO, " Module - %g", &ImageStruct->FileGuid));\r
409 }\r
410 if ((ImageStruct != NULL) && (ImageStruct->PdbString[0] != 0)) {\r
411 DEBUG ((DEBUG_INFO, " (Pdb - %a)", ImageStruct->PdbString));\r
412 }\r
413 DEBUG ((DEBUG_INFO, "\n"));\r
414 if (SmiHandler->ContextSize != 0) {\r
415 DumpSmiChildContext (&SmiEntry->HandlerType, SmiHandler->Context, SmiHandler->ContextSize);\r
416 }\r
417 DEBUG ((DEBUG_INFO, " Handler - 0x%x", SmiHandler->Handler));\r
418 if (ImageStruct != NULL) {\r
419 DEBUG ((DEBUG_INFO, " <== RVA - 0x%x", (UINTN)SmiHandler->Handler - ImageStruct->ImageBase));\r
420 }\r
421 DEBUG ((DEBUG_INFO, "\n"));\r
422 DEBUG ((DEBUG_INFO, " CallerAddr - 0x%x", SmiHandler->CallerAddr));\r
423 if (ImageStruct != NULL) {\r
424 DEBUG ((DEBUG_INFO, " <== RVA - 0x%x", SmiHandler->CallerAddr - ImageStruct->ImageBase));\r
425 }\r
426 DEBUG ((DEBUG_INFO, "\n"));\r
427 }\r
428\r
429 return;\r
430}\r
431\r
432/**\r
433 Dump all SMI entry on the list.\r
434\r
435 @param SmiEntryList a list of SMI entry.\r
436**/\r
437VOID\r
438DumpSmiEntryList(\r
439 IN LIST_ENTRY *SmiEntryList\r
440 )\r
441{\r
442 LIST_ENTRY *ListEntry;\r
443 SMI_ENTRY *SmiEntry;\r
444\r
445 ListEntry = SmiEntryList;\r
446 for (ListEntry = ListEntry->ForwardLink;\r
447 ListEntry != SmiEntryList;\r
448 ListEntry = ListEntry->ForwardLink) {\r
449 SmiEntry = CR(ListEntry, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);\r
450 DEBUG ((DEBUG_INFO, "SmiEntry - %g\n", &SmiEntry->HandlerType));\r
451 DumpSmiHandlerOnSmiEntry(SmiEntry);\r
452 }\r
453\r
454 return;\r
455}\r
456\r
457/**\r
458 SMM Ready To Lock event notification handler.\r
459\r
460 This function collects all SMM image information and build SmiHandleProfile database,\r
461 and register SmiHandlerProfile SMI handler.\r
462\r
463 @param[in] Protocol Points to the protocol's unique identifier.\r
464 @param[in] Interface Points to the interface instance.\r
465 @param[in] Handle The handle on which the interface was installed.\r
466\r
467 @retval EFI_SUCCESS Notification handler runs successfully.\r
468**/\r
469EFI_STATUS\r
470EFIAPI\r
471SmmReadyToLockInSmiHandlerProfile (\r
472 IN CONST EFI_GUID *Protocol,\r
473 IN VOID *Interface,\r
474 IN EFI_HANDLE Handle\r
475 )\r
476{\r
477 //\r
478 // Dump all image\r
479 //\r
480 DEBUG ((DEBUG_INFO, "##################\n"));\r
481 DEBUG ((DEBUG_INFO, "# IMAGE DATABASE #\n"));\r
482 DEBUG ((DEBUG_INFO, "##################\n"));\r
483 GetSmmLoadedImage ();\r
484 DEBUG ((DEBUG_INFO, "\n"));\r
485\r
486 //\r
487 // Dump SMI Handler\r
488 //\r
489 DEBUG ((DEBUG_INFO, "########################\n"));\r
490 DEBUG ((DEBUG_INFO, "# SMI Handler DATABASE #\n"));\r
491 DEBUG ((DEBUG_INFO, "########################\n"));\r
492\r
493 DEBUG ((DEBUG_INFO, "# 1. ROOT SMI Handler #\n"));\r
494 DEBUG_CODE (\r
495 DumpSmiEntryList(mSmmCoreRootSmiEntryList);\r
496 );\r
497\r
498 DEBUG ((DEBUG_INFO, "# 2. GUID SMI Handler #\n"));\r
499 DEBUG_CODE (\r
500 DumpSmiEntryList(mSmmCoreSmiEntryList);\r
501 );\r
502\r
503 DEBUG ((DEBUG_INFO, "# 3. Hardware SMI Handler #\n"));\r
504 DEBUG_CODE (\r
505 DumpSmiEntryList(mSmmCoreHardwareSmiEntryList);\r
506 );\r
507\r
508 DEBUG ((DEBUG_INFO, "\n"));\r
509\r
510 RegisterSmiHandlerProfileHandler();\r
511\r
512 if (mImageStruct != NULL) {\r
513 FreePool(mImageStruct);\r
514 }\r
515\r
516 return EFI_SUCCESS;\r
517}\r
518\r
519/**\r
520 returns SMM image data base size.\r
521\r
522 @return SMM image data base size.\r
523**/\r
524UINTN\r
525GetSmmImageDatabaseSize(\r
526 VOID\r
527 )\r
528{\r
529 UINTN Size;\r
530 UINTN Index;\r
531\r
532 Size = (sizeof(SMM_CORE_IMAGE_DATABASE_STRUCTURE)) * mImageStructCount;\r
533 for (Index = 0; Index < mImageStructCount; Index++) {\r
534 Size += mImageStruct[Index].PdbStringSize;\r
535 }\r
536 return Size;\r
537}\r
538\r
539/**\r
540 returns all SMI handlers' size associated with SmiEntry.\r
541\r
542 @param SmiEntry SMI entry.\r
543\r
544 @return all SMI handlers' size associated with SmiEntry.\r
545**/\r
546UINTN\r
547GetSmmSmiHandlerSizeOnSmiEntry(\r
548 IN SMI_ENTRY *SmiEntry\r
549 )\r
550{\r
551 LIST_ENTRY *ListEntry;\r
552 SMI_HANDLER *SmiHandler;\r
553 UINTN Size;\r
554\r
555 Size = 0;\r
556 ListEntry = &SmiEntry->SmiHandlers;\r
557 for (ListEntry = ListEntry->ForwardLink;\r
558 ListEntry != &SmiEntry->SmiHandlers;\r
559 ListEntry = ListEntry->ForwardLink) {\r
560 SmiHandler = CR(ListEntry, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);\r
561 Size += sizeof(SMM_CORE_SMI_HANDLER_STRUCTURE) + SmiHandler->ContextSize;\r
562 }\r
563\r
564 return Size;\r
565}\r
566\r
567/**\r
568 return all SMI handler database size on the SMI entry list.\r
569\r
570 @param SmiEntryList a list of SMI entry.\r
571\r
572 @return all SMI handler database size on the SMI entry list.\r
573**/\r
574UINTN\r
575GetSmmSmiDatabaseSize(\r
576 IN LIST_ENTRY *SmiEntryList\r
577 )\r
578{\r
579 LIST_ENTRY *ListEntry;\r
580 SMI_ENTRY *SmiEntry;\r
581 UINTN Size;\r
582\r
583 Size = 0;\r
584 ListEntry = SmiEntryList;\r
585 for (ListEntry = ListEntry->ForwardLink;\r
586 ListEntry != SmiEntryList;\r
587 ListEntry = ListEntry->ForwardLink) {\r
588 SmiEntry = CR(ListEntry, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);\r
589 Size += sizeof(SMM_CORE_SMI_DATABASE_STRUCTURE);\r
590 Size += GetSmmSmiHandlerSizeOnSmiEntry(SmiEntry);\r
591 }\r
592 return Size;\r
593}\r
594\r
595/**\r
596 return SMI handler profile database size.\r
597\r
598 @return SMI handler profile database size.\r
599**/\r
600UINTN\r
601GetSmiHandlerProfileDatabaseSize (\r
602 VOID\r
603 )\r
604{\r
605 mSmmImageDatabaseSize = GetSmmImageDatabaseSize();\r
606 mSmmRootSmiDatabaseSize = GetSmmSmiDatabaseSize(mSmmCoreRootSmiEntryList);\r
607 mSmmSmiDatabaseSize = GetSmmSmiDatabaseSize(mSmmCoreSmiEntryList);\r
608 mSmmHardwareSmiDatabaseSize = GetSmmSmiDatabaseSize(mSmmCoreHardwareSmiEntryList);\r
609\r
610 return mSmmImageDatabaseSize + mSmmSmiDatabaseSize + mSmmRootSmiDatabaseSize + mSmmHardwareSmiDatabaseSize;\r
611}\r
612\r
613/**\r
614 get SMM image database.\r
615\r
616 @param Data The buffer to hold SMM image database\r
617 @param ExpectedSize The expected size of the SMM image database\r
618\r
619 @return SMM image data base size.\r
620**/\r
621UINTN\r
622GetSmmImageDatabaseData (\r
623 IN OUT VOID *Data,\r
624 IN UINTN ExpectedSize\r
625 )\r
626{\r
627 SMM_CORE_IMAGE_DATABASE_STRUCTURE *ImageStruct;\r
628 UINTN Size;\r
629 UINTN Index;\r
630\r
631 ImageStruct = Data;\r
632 Size = 0;\r
633 for (Index = 0; Index < mImageStructCount; Index++) {\r
634 if (Size >= ExpectedSize) {\r
635 return 0;\r
636 }\r
637 if (sizeof(SMM_CORE_IMAGE_DATABASE_STRUCTURE) + mImageStruct[Index].PdbStringSize > ExpectedSize - Size) {\r
638 return 0;\r
639 }\r
640 ImageStruct->Header.Signature = SMM_CORE_IMAGE_DATABASE_SIGNATURE;\r
641 ImageStruct->Header.Length = (UINT32)(sizeof(SMM_CORE_IMAGE_DATABASE_STRUCTURE) + mImageStruct[Index].PdbStringSize);\r
642 ImageStruct->Header.Revision = SMM_CORE_IMAGE_DATABASE_REVISION;\r
643 CopyGuid(&ImageStruct->FileGuid, &mImageStruct[Index].FileGuid);\r
644 ImageStruct->ImageRef = mImageStruct[Index].ImageRef;\r
645 ImageStruct->EntryPoint = mImageStruct[Index].EntryPoint;\r
646 ImageStruct->ImageBase = mImageStruct[Index].ImageBase;\r
647 ImageStruct->ImageSize = mImageStruct[Index].ImageSize;\r
648 ImageStruct->PdbStringOffset = sizeof(SMM_CORE_IMAGE_DATABASE_STRUCTURE);\r
649 CopyMem ((VOID *)((UINTN)ImageStruct + ImageStruct->PdbStringOffset), mImageStruct[Index].PdbString, mImageStruct[Index].PdbStringSize);\r
650 ImageStruct = (SMM_CORE_IMAGE_DATABASE_STRUCTURE *)((UINTN)ImageStruct + ImageStruct->Header.Length);\r
651 Size += sizeof(SMM_CORE_IMAGE_DATABASE_STRUCTURE) + mImageStruct[Index].PdbStringSize;\r
652 }\r
653\r
654 if (ExpectedSize != Size) {\r
655 return 0;\r
656 }\r
657 return Size;\r
658}\r
659\r
660/**\r
661 get all SMI handler data associated with SmiEntry.\r
662\r
663 @param SmiEntry SMI entry.\r
664 @param Data The buffer to hold all SMI handler data\r
665 @param MaxSize The max size of the SMM image database\r
666 @param Count The count of the SMI handler.\r
667\r
668 @return SMM image data base size.\r
669**/\r
670UINTN\r
671GetSmmSmiHandlerDataOnSmiEntry(\r
672 IN SMI_ENTRY *SmiEntry,\r
673 IN OUT VOID *Data,\r
674 IN UINTN MaxSize,\r
675 OUT UINTN *Count\r
676 )\r
677{\r
678 SMM_CORE_SMI_HANDLER_STRUCTURE *SmiHandlerStruct;\r
679 LIST_ENTRY *ListEntry;\r
680 SMI_HANDLER *SmiHandler;\r
681 UINTN Size;\r
682\r
683 SmiHandlerStruct = Data;\r
684 Size = 0;\r
685 *Count = 0;\r
686 ListEntry = &SmiEntry->SmiHandlers;\r
687 for (ListEntry = ListEntry->ForwardLink;\r
688 ListEntry != &SmiEntry->SmiHandlers;\r
689 ListEntry = ListEntry->ForwardLink) {\r
690 SmiHandler = CR(ListEntry, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);\r
691 if (Size >= MaxSize) {\r
692 *Count = 0;\r
693 return 0;\r
694 }\r
695 if (sizeof(SMM_CORE_SMI_HANDLER_STRUCTURE) + SmiHandler->ContextSize > MaxSize - Size) {\r
696 *Count = 0;\r
697 return 0;\r
698 }\r
699 SmiHandlerStruct->Length = (UINT32)(sizeof(SMM_CORE_SMI_HANDLER_STRUCTURE) + SmiHandler->ContextSize);\r
700 SmiHandlerStruct->CallerAddr = (UINTN)SmiHandler->CallerAddr;\r
701 SmiHandlerStruct->Handler = (UINTN)SmiHandler->Handler;\r
702 SmiHandlerStruct->ImageRef = AddressToImageRef((UINTN)SmiHandler->Handler);\r
703 SmiHandlerStruct->ContextBufferSize = (UINT32)SmiHandler->ContextSize;\r
704 if (SmiHandler->ContextSize != 0) {\r
705 SmiHandlerStruct->ContextBufferOffset = sizeof(SMM_CORE_SMI_HANDLER_STRUCTURE);\r
706 CopyMem ((UINT8 *)SmiHandlerStruct + SmiHandlerStruct->ContextBufferOffset, SmiHandler->Context, SmiHandler->ContextSize);\r
707 } else {\r
708 SmiHandlerStruct->ContextBufferOffset = 0;\r
709 }\r
710 Size += sizeof(SMM_CORE_SMI_HANDLER_STRUCTURE) + SmiHandler->ContextSize;\r
711 SmiHandlerStruct = (SMM_CORE_SMI_HANDLER_STRUCTURE *)((UINTN)SmiHandlerStruct + SmiHandlerStruct->Length);\r
712 *Count = *Count + 1;\r
713 }\r
714\r
715 return Size;\r
716}\r
717\r
718/**\r
719 get all SMI handler database on the SMI entry list.\r
720\r
721 @param SmiEntryList a list of SMI entry.\r
722 @param HandlerCategory The handler category\r
723 @param Data The buffer to hold all SMI handler database\r
724 @param ExpectedSize The expected size of the SMM image database\r
725\r
726 @return all SMI database size on the SMI entry list.\r
727**/\r
728UINTN\r
729GetSmmSmiDatabaseData(\r
730 IN LIST_ENTRY *SmiEntryList,\r
731 IN UINT32 HandlerCategory,\r
732 IN OUT VOID *Data,\r
733 IN UINTN ExpectedSize\r
734 )\r
735{\r
736 SMM_CORE_SMI_DATABASE_STRUCTURE *SmiStruct;\r
737 LIST_ENTRY *ListEntry;\r
738 SMI_ENTRY *SmiEntry;\r
739 UINTN Size;\r
740 UINTN SmiHandlerSize;\r
741 UINTN SmiHandlerCount;\r
742\r
743 SmiStruct = Data;\r
744 Size = 0;\r
745 ListEntry = SmiEntryList;\r
746 for (ListEntry = ListEntry->ForwardLink;\r
747 ListEntry != SmiEntryList;\r
748 ListEntry = ListEntry->ForwardLink) {\r
749 SmiEntry = CR(ListEntry, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);\r
750 if (Size >= ExpectedSize) {\r
751 return 0;\r
752 }\r
753 if (sizeof(SMM_CORE_SMI_DATABASE_STRUCTURE) > ExpectedSize - Size) {\r
754 return 0;\r
755 }\r
756\r
757 SmiStruct->Header.Signature = SMM_CORE_SMI_DATABASE_SIGNATURE;\r
758 SmiStruct->Header.Length = sizeof(SMM_CORE_SMI_DATABASE_STRUCTURE);\r
759 SmiStruct->Header.Revision = SMM_CORE_SMI_DATABASE_REVISION;\r
760 SmiStruct->HandlerCategory = HandlerCategory;\r
761 CopyGuid(&SmiStruct->HandlerType, &SmiEntry->HandlerType);\r
762 Size += sizeof(SMM_CORE_SMI_DATABASE_STRUCTURE);\r
763 SmiHandlerSize = GetSmmSmiHandlerDataOnSmiEntry(SmiEntry, (UINT8 *)SmiStruct + SmiStruct->Header.Length, ExpectedSize - Size, &SmiHandlerCount);\r
764 SmiStruct->HandlerCount = SmiHandlerCount;\r
765 Size += SmiHandlerSize;\r
766 SmiStruct->Header.Length += (UINT32)SmiHandlerSize;\r
767 SmiStruct = (VOID *)((UINTN)SmiStruct + SmiStruct->Header.Length);\r
768 }\r
769 if (ExpectedSize != Size) {\r
770 return 0;\r
771 }\r
772 return Size;\r
773}\r
774\r
775/**\r
776 Get SMI handler profile database.\r
777\r
778 @param Data the buffer to hold SMI handler profile database\r
779\r
780 @retval EFI_SUCCESS the database is got.\r
781 @retval EFI_INVALID_PARAMETER the database size mismatch.\r
782**/\r
783EFI_STATUS\r
784GetSmiHandlerProfileDatabaseData(\r
785 IN OUT VOID *Data\r
786 )\r
787{\r
788 UINTN SmmImageDatabaseSize;\r
789 UINTN SmmSmiDatabaseSize;\r
790 UINTN SmmRootSmiDatabaseSize;\r
791 UINTN SmmHardwareSmiDatabaseSize;\r
792\r
793 DEBUG((DEBUG_VERBOSE, "GetSmiHandlerProfileDatabaseData\n"));\r
794 SmmImageDatabaseSize = GetSmmImageDatabaseData(Data, mSmmImageDatabaseSize);\r
795 if (SmmImageDatabaseSize != mSmmImageDatabaseSize) {\r
796 DEBUG((DEBUG_ERROR, "GetSmiHandlerProfileDatabaseData - SmmImageDatabaseSize mismatch!\n"));\r
797 return EFI_INVALID_PARAMETER;\r
798 }\r
799 SmmRootSmiDatabaseSize = GetSmmSmiDatabaseData(mSmmCoreRootSmiEntryList, SmmCoreSmiHandlerCategoryRootHandler, (UINT8 *)Data + SmmImageDatabaseSize, mSmmRootSmiDatabaseSize);\r
800 if (SmmRootSmiDatabaseSize != mSmmRootSmiDatabaseSize) {\r
801 DEBUG((DEBUG_ERROR, "GetSmiHandlerProfileDatabaseData - SmmRootSmiDatabaseSize mismatch!\n"));\r
802 return EFI_INVALID_PARAMETER;\r
803 }\r
804 SmmSmiDatabaseSize = GetSmmSmiDatabaseData(mSmmCoreSmiEntryList, SmmCoreSmiHandlerCategoryGuidHandler, (UINT8 *)Data + SmmImageDatabaseSize + mSmmRootSmiDatabaseSize, mSmmSmiDatabaseSize);\r
805 if (SmmSmiDatabaseSize != mSmmSmiDatabaseSize) {\r
806 DEBUG((DEBUG_ERROR, "GetSmiHandlerProfileDatabaseData - SmmSmiDatabaseSize mismatch!\n"));\r
807 return EFI_INVALID_PARAMETER;\r
808 }\r
809 SmmHardwareSmiDatabaseSize = GetSmmSmiDatabaseData(mSmmCoreHardwareSmiEntryList, SmmCoreSmiHandlerCategoryHardwareHandler, (UINT8 *)Data + SmmImageDatabaseSize + SmmRootSmiDatabaseSize + SmmSmiDatabaseSize, mSmmHardwareSmiDatabaseSize);\r
810 if (SmmHardwareSmiDatabaseSize != mSmmHardwareSmiDatabaseSize) {\r
811 DEBUG((DEBUG_ERROR, "GetSmiHandlerProfileDatabaseData - SmmHardwareSmiDatabaseSize mismatch!\n"));\r
812 return EFI_INVALID_PARAMETER;\r
813 }\r
814\r
815 return EFI_SUCCESS;\r
816}\r
817\r
818/**\r
819 build SMI handler profile database.\r
820**/\r
821VOID\r
822BuildSmiHandlerProfileDatabase(\r
823 VOID\r
824 )\r
825{\r
826 EFI_STATUS Status;\r
827 mSmiHandlerProfileDatabaseSize = GetSmiHandlerProfileDatabaseSize();\r
828 mSmiHandlerProfileDatabase = AllocatePool(mSmiHandlerProfileDatabaseSize);\r
829 if (mSmiHandlerProfileDatabase == NULL) {\r
830 return;\r
831 }\r
832 Status = GetSmiHandlerProfileDatabaseData(mSmiHandlerProfileDatabase);\r
833 if (EFI_ERROR(Status)) {\r
834 FreePool(mSmiHandlerProfileDatabase);\r
835 mSmiHandlerProfileDatabase = NULL;\r
836 }\r
837}\r
838\r
839/**\r
840 Copy SMI handler profile data.\r
841\r
842 @param DataBuffer The buffer to hold SMI handler profile data.\r
843 @param DataSize On input, data buffer size.\r
844 On output, actual data buffer size copied.\r
845 @param DataOffset On input, data buffer offset to copy.\r
846 On output, next time data buffer offset to copy.\r
847\r
848**/\r
849VOID\r
850SmiHandlerProfileCopyData(\r
851 OUT VOID *DataBuffer,\r
852 IN OUT UINT64 *DataSize,\r
853 IN OUT UINT64 *DataOffset\r
854 )\r
855{\r
856 if (*DataOffset >= mSmiHandlerProfileDatabaseSize) {\r
857 *DataOffset = mSmiHandlerProfileDatabaseSize;\r
858 return;\r
859 }\r
860 if (mSmiHandlerProfileDatabaseSize - *DataOffset < *DataSize) {\r
861 *DataSize = mSmiHandlerProfileDatabaseSize - *DataOffset;\r
862 }\r
863\r
864 CopyMem(\r
865 DataBuffer,\r
866 (UINT8 *)mSmiHandlerProfileDatabase + *DataOffset,\r
867 (UINTN)*DataSize\r
868 );\r
869 *DataOffset = *DataOffset + *DataSize;\r
870}\r
871\r
872/**\r
873 SMI handler profile handler to get info.\r
874\r
875 @param SmiHandlerProfileParameterGetInfo The parameter of SMI handler profile get info.\r
876\r
877**/\r
878VOID\r
879SmiHandlerProfileHandlerGetInfo(\r
880 IN SMI_HANDLER_PROFILE_PARAMETER_GET_INFO *SmiHandlerProfileParameterGetInfo\r
881 )\r
882{\r
883 BOOLEAN SmiHandlerProfileRecordingStatus;\r
884\r
885 SmiHandlerProfileRecordingStatus = mSmiHandlerProfileRecordingStatus;\r
886 mSmiHandlerProfileRecordingStatus = FALSE;\r
887\r
888 SmiHandlerProfileParameterGetInfo->DataSize = mSmiHandlerProfileDatabaseSize;\r
889 SmiHandlerProfileParameterGetInfo->Header.ReturnStatus = 0;\r
890\r
891 mSmiHandlerProfileRecordingStatus = SmiHandlerProfileRecordingStatus;\r
892}\r
893\r
894/**\r
895 SMI handler profile handler to get data by offset.\r
896\r
897 @param SmiHandlerProfileParameterGetDataByOffset The parameter of SMI handler profile get data by offset.\r
898\r
899**/\r
900VOID\r
901SmiHandlerProfileHandlerGetDataByOffset(\r
902 IN SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET *SmiHandlerProfileParameterGetDataByOffset\r
903 )\r
904{\r
905 SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET SmiHandlerProfileGetDataByOffset;\r
906 BOOLEAN SmiHandlerProfileRecordingStatus;\r
907\r
908 SmiHandlerProfileRecordingStatus = mSmiHandlerProfileRecordingStatus;\r
909 mSmiHandlerProfileRecordingStatus = FALSE;\r
910\r
911 CopyMem(&SmiHandlerProfileGetDataByOffset, SmiHandlerProfileParameterGetDataByOffset, sizeof(SmiHandlerProfileGetDataByOffset));\r
912\r
913 //\r
914 // Sanity check\r
915 //\r
916 if (!SmmIsBufferOutsideSmmValid((UINTN)SmiHandlerProfileGetDataByOffset.DataBuffer, (UINTN)SmiHandlerProfileGetDataByOffset.DataSize)) {\r
917 DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandlerGetDataByOffset: SMI handler profile get data in SMRAM or overflow!\n"));\r
918 SmiHandlerProfileParameterGetDataByOffset->Header.ReturnStatus = (UINT64)(INT64)(INTN)EFI_ACCESS_DENIED;\r
919 goto Done;\r
920 }\r
921\r
922 SmiHandlerProfileCopyData((VOID *)(UINTN)SmiHandlerProfileGetDataByOffset.DataBuffer, &SmiHandlerProfileGetDataByOffset.DataSize, &SmiHandlerProfileGetDataByOffset.DataOffset);\r
923 CopyMem(SmiHandlerProfileParameterGetDataByOffset, &SmiHandlerProfileGetDataByOffset, sizeof(SmiHandlerProfileGetDataByOffset));\r
924 SmiHandlerProfileParameterGetDataByOffset->Header.ReturnStatus = 0;\r
925\r
926Done:\r
927 mSmiHandlerProfileRecordingStatus = SmiHandlerProfileRecordingStatus;\r
928}\r
929\r
930/**\r
931 Dispatch function for a Software SMI handler.\r
932\r
933 Caution: This function may receive untrusted input.\r
934 Communicate buffer and buffer size are external input, so this function will do basic validation.\r
935\r
936 @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
937 @param Context Points to an optional handler context which was specified when the\r
938 handler was registered.\r
939 @param CommBuffer A pointer to a collection of data in memory that will\r
940 be conveyed from a non-SMM environment into an SMM environment.\r
941 @param CommBufferSize The size of the CommBuffer.\r
942\r
943 @retval EFI_SUCCESS Command is handled successfully.\r
944**/\r
945EFI_STATUS\r
946EFIAPI\r
947SmiHandlerProfileHandler(\r
948 IN EFI_HANDLE DispatchHandle,\r
949 IN CONST VOID *Context OPTIONAL,\r
950 IN OUT VOID *CommBuffer OPTIONAL,\r
951 IN OUT UINTN *CommBufferSize OPTIONAL\r
952 )\r
953{\r
954 SMI_HANDLER_PROFILE_PARAMETER_HEADER *SmiHandlerProfileParameterHeader;\r
955 UINTN TempCommBufferSize;\r
956\r
957 DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandler Enter\n"));\r
958\r
959 if (mSmiHandlerProfileDatabase == NULL) {\r
960 return EFI_SUCCESS;\r
961 }\r
962\r
963 //\r
964 // If input is invalid, stop processing this SMI\r
965 //\r
966 if (CommBuffer == NULL || CommBufferSize == NULL) {\r
967 return EFI_SUCCESS;\r
968 }\r
969\r
970 TempCommBufferSize = *CommBufferSize;\r
971\r
972 if (TempCommBufferSize < sizeof(SMI_HANDLER_PROFILE_PARAMETER_HEADER)) {\r
973 DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandler: SMM communication buffer size invalid!\n"));\r
974 return EFI_SUCCESS;\r
975 }\r
976\r
977 if (!SmmIsBufferOutsideSmmValid((UINTN)CommBuffer, TempCommBufferSize)) {\r
978 DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandler: SMM communication buffer in SMRAM or overflow!\n"));\r
979 return EFI_SUCCESS;\r
980 }\r
981\r
982 SmiHandlerProfileParameterHeader = (SMI_HANDLER_PROFILE_PARAMETER_HEADER *)((UINTN)CommBuffer);\r
983 SmiHandlerProfileParameterHeader->ReturnStatus = (UINT64)-1;\r
984\r
985 switch (SmiHandlerProfileParameterHeader->Command) {\r
986 case SMI_HANDLER_PROFILE_COMMAND_GET_INFO:\r
987 DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandlerGetInfo\n"));\r
988 if (TempCommBufferSize != sizeof(SMI_HANDLER_PROFILE_PARAMETER_GET_INFO)) {\r
989 DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandler: SMM communication buffer size invalid!\n"));\r
990 return EFI_SUCCESS;\r
991 }\r
992 SmiHandlerProfileHandlerGetInfo((SMI_HANDLER_PROFILE_PARAMETER_GET_INFO *)(UINTN)CommBuffer);\r
993 break;\r
994 case SMI_HANDLER_PROFILE_COMMAND_GET_DATA_BY_OFFSET:\r
995 DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandlerGetDataByOffset\n"));\r
996 if (TempCommBufferSize != sizeof(SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET)) {\r
997 DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandler: SMM communication buffer size invalid!\n"));\r
998 return EFI_SUCCESS;\r
999 }\r
1000 SmiHandlerProfileHandlerGetDataByOffset((SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET *)(UINTN)CommBuffer);\r
1001 break;\r
1002 default:\r
1003 break;\r
1004 }\r
1005\r
1006 DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandler Exit\n"));\r
1007\r
1008 return EFI_SUCCESS;\r
1009}\r
1010\r
1011/**\r
1012 Register SMI handler profile handler.\r
1013**/\r
1014VOID\r
1015RegisterSmiHandlerProfileHandler (\r
1016 VOID\r
1017 )\r
1018{\r
1019 EFI_STATUS Status;\r
1020 EFI_HANDLE DispatchHandle;\r
1021\r
1022 Status = gSmst->SmiHandlerRegister (\r
1023 SmiHandlerProfileHandler,\r
1024 &gSmiHandlerProfileGuid,\r
1025 &DispatchHandle\r
1026 );\r
1027 ASSERT_EFI_ERROR (Status);\r
1028\r
1029 BuildSmiHandlerProfileDatabase();\r
1030}\r
1031\r
1032/**\r
1033 Finds the SMI entry for the requested handler type.\r
1034\r
1035 @param HandlerType The type of the interrupt\r
1036 @param Create Create a new entry if not found\r
1037\r
1038 @return SMI entry\r
1039**/\r
1040SMI_ENTRY *\r
1041SmmCoreFindHardwareSmiEntry (\r
1042 IN EFI_GUID *HandlerType,\r
1043 IN BOOLEAN Create\r
1044 )\r
1045{\r
1046 LIST_ENTRY *Link;\r
1047 SMI_ENTRY *Item;\r
1048 SMI_ENTRY *SmiEntry;\r
1049\r
1050 //\r
1051 // Search the SMI entry list for the matching GUID\r
1052 //\r
1053 SmiEntry = NULL;\r
1054 for (Link = mHardwareSmiEntryList.ForwardLink;\r
1055 Link != &mHardwareSmiEntryList;\r
1056 Link = Link->ForwardLink) {\r
1057\r
1058 Item = CR (Link, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);\r
1059 if (CompareGuid (&Item->HandlerType, HandlerType)) {\r
1060 //\r
1061 // This is the SMI entry\r
1062 //\r
1063 SmiEntry = Item;\r
1064 break;\r
1065 }\r
1066 }\r
1067\r
1068 //\r
1069 // If the protocol entry was not found and Create is TRUE, then\r
1070 // allocate a new entry\r
1071 //\r
1072 if ((SmiEntry == NULL) && Create) {\r
1073 SmiEntry = AllocatePool (sizeof(SMI_ENTRY));\r
1074 if (SmiEntry != NULL) {\r
1075 //\r
1076 // Initialize new SMI entry structure\r
1077 //\r
1078 SmiEntry->Signature = SMI_ENTRY_SIGNATURE;\r
1079 CopyGuid ((VOID *)&SmiEntry->HandlerType, HandlerType);\r
1080 InitializeListHead (&SmiEntry->SmiHandlers);\r
1081\r
1082 //\r
1083 // Add it to SMI entry list\r
1084 //\r
1085 InsertTailList (&mHardwareSmiEntryList, &SmiEntry->AllEntries);\r
1086 }\r
1087 }\r
1088 return SmiEntry;\r
1089}\r
1090\r
1c3ac4b9
JY
1091/**\r
1092 Convert EFI_SMM_USB_REGISTER_CONTEXT to SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT.\r
1093\r
1094 @param UsbContext A pointer to EFI_SMM_USB_REGISTER_CONTEXT\r
1095 @param UsbContextSize The size of EFI_SMM_USB_REGISTER_CONTEXT in bytes\r
1096 @param SmiHandlerUsbContextSize The size of SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT in bytes\r
1097\r
1098 @return SmiHandlerUsbContext A pointer to SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT\r
1099**/\r
1100SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *\r
1101ConvertSmiHandlerUsbContext (\r
1102 IN EFI_SMM_USB_REGISTER_CONTEXT *UsbContext,\r
1103 IN UINTN UsbContextSize,\r
1104 OUT UINTN *SmiHandlerUsbContextSize\r
1105 )\r
1106{\r
1107 UINTN DevicePathSize;\r
1108 SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *SmiHandlerUsbContext;\r
1109\r
1110 ASSERT (UsbContextSize == sizeof(EFI_SMM_USB_REGISTER_CONTEXT));\r
1111\r
1112 DevicePathSize = GetDevicePathSize (UsbContext->Device);\r
1113 SmiHandlerUsbContext = AllocatePool (sizeof (SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT) + DevicePathSize);\r
1114 if (SmiHandlerUsbContext == NULL) {\r
1115 *SmiHandlerUsbContextSize = 0;\r
1116 return NULL;\r
1117 }\r
1118 SmiHandlerUsbContext->Type = UsbContext->Type;\r
1119 SmiHandlerUsbContext->DevicePathSize = (UINT32)DevicePathSize;\r
1120 CopyMem (SmiHandlerUsbContext + 1, UsbContext->Device, DevicePathSize);\r
1121 *SmiHandlerUsbContextSize = sizeof (SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT) + DevicePathSize;\r
1122 return SmiHandlerUsbContext;\r
1123}\r
1124\r
ca41f3f4
JY
1125/**\r
1126 This function is called by SmmChildDispatcher module to report\r
1127 a new SMI handler is registered, to SmmCore.\r
1128\r
1129 @param This The protocol instance\r
1130 @param HandlerGuid The GUID to identify the type of the handler.\r
1131 For the SmmChildDispatch protocol, the HandlerGuid\r
1132 must be the GUID of SmmChildDispatch protocol.\r
1133 @param Handler The SMI handler.\r
1134 @param CallerAddress The address of the module who registers the SMI handler.\r
1135 @param Context The context of the SMI handler.\r
1136 For the SmmChildDispatch protocol, the Context\r
1137 must match the one defined for SmmChildDispatch protocol.\r
1138 @param ContextSize The size of the context in bytes.\r
1139 For the SmmChildDispatch protocol, the Context\r
1140 must match the one defined for SmmChildDispatch protocol.\r
1141\r
1142 @retval EFI_SUCCESS The information is recorded.\r
1143 @retval EFI_OUT_OF_RESOURCES There is no enough resource to record the information.\r
1144**/\r
1145EFI_STATUS\r
1146EFIAPI\r
1147SmiHandlerProfileRegisterHandler (\r
1148 IN SMI_HANDLER_PROFILE_PROTOCOL *This,\r
1149 IN EFI_GUID *HandlerGuid,\r
1150 IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,\r
1151 IN PHYSICAL_ADDRESS CallerAddress,\r
1152 IN VOID *Context, OPTIONAL\r
1153 IN UINTN ContextSize OPTIONAL\r
1154 )\r
1155{\r
1156 SMI_HANDLER *SmiHandler;\r
1157 SMI_ENTRY *SmiEntry;\r
1158 LIST_ENTRY *List;\r
1159\r
1c3ac4b9
JY
1160 if (((ContextSize == 0) && (Context != NULL)) ||\r
1161 ((ContextSize != 0) && (Context == NULL))) {\r
1162 return EFI_INVALID_PARAMETER;\r
1163 }\r
1164\r
ca41f3f4
JY
1165 SmiHandler = AllocateZeroPool (sizeof (SMI_HANDLER));\r
1166 if (SmiHandler == NULL) {\r
1167 return EFI_OUT_OF_RESOURCES;\r
1168 }\r
1169\r
1170 SmiHandler->Signature = SMI_HANDLER_SIGNATURE;\r
1171 SmiHandler->Handler = Handler;\r
1172 SmiHandler->CallerAddr = (UINTN)CallerAddress;\r
1c3ac4b9
JY
1173 SmiHandler->Context = Context;\r
1174 SmiHandler->ContextSize = ContextSize;\r
1175\r
1176 if (Context != NULL) {\r
ca41f3f4 1177 if (CompareGuid (HandlerGuid, &gEfiSmmUsbDispatch2ProtocolGuid)) {\r
1c3ac4b9 1178 SmiHandler->Context = ConvertSmiHandlerUsbContext (Context, ContextSize, &SmiHandler->ContextSize);\r
ca41f3f4
JY
1179 } else {\r
1180 SmiHandler->Context = AllocateCopyPool (ContextSize, Context);\r
1181 }\r
1182 }\r
1c3ac4b9
JY
1183 if (SmiHandler->Context == NULL) {\r
1184 SmiHandler->ContextSize = 0;\r
ca41f3f4
JY
1185 }\r
1186\r
1187 SmiEntry = SmmCoreFindHardwareSmiEntry (HandlerGuid, TRUE);\r
1188 if (SmiEntry == NULL) {\r
251779fc
JY
1189 if (SmiHandler->Context != NULL) {\r
1190 FreePool (SmiHandler->Context);\r
1191 }\r
1c3ac4b9 1192 FreePool (SmiHandler);\r
ca41f3f4
JY
1193 return EFI_OUT_OF_RESOURCES;\r
1194 }\r
1195\r
1196 List = &SmiEntry->SmiHandlers;\r
1197\r
1198 SmiHandler->SmiEntry = SmiEntry;\r
1199 InsertTailList (List, &SmiHandler->Link);\r
1200\r
1201 return EFI_SUCCESS;\r
1202}\r
1203\r
1204/**\r
1205 This function is called by SmmChildDispatcher module to report\r
1206 an existing SMI handler is unregistered, to SmmCore.\r
1207\r
1208 @param This The protocol instance\r
1209 @param HandlerGuid The GUID to identify the type of the handler.\r
1210 For the SmmChildDispatch protocol, the HandlerGuid\r
1211 must be the GUID of SmmChildDispatch protocol.\r
1212 @param Handler The SMI handler.\r
1c3ac4b9
JY
1213 @param Context The context of the SMI handler.\r
1214 If it is NOT NULL, it will be used to check what is registered.\r
1215 @param ContextSize The size of the context in bytes.\r
1216 If Context is NOT NULL, it will be used to check what is registered.\r
ca41f3f4
JY
1217\r
1218 @retval EFI_SUCCESS The original record is removed.\r
1219 @retval EFI_NOT_FOUND There is no record for the HandlerGuid and handler.\r
1220**/\r
1221EFI_STATUS\r
1222EFIAPI\r
1223SmiHandlerProfileUnregisterHandler (\r
1224 IN SMI_HANDLER_PROFILE_PROTOCOL *This,\r
1225 IN EFI_GUID *HandlerGuid,\r
1c3ac4b9
JY
1226 IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,\r
1227 IN VOID *Context, OPTIONAL\r
1228 IN UINTN ContextSize OPTIONAL\r
ca41f3f4
JY
1229 )\r
1230{\r
1231 LIST_ENTRY *Link;\r
1232 LIST_ENTRY *Head;\r
1233 SMI_HANDLER *SmiHandler;\r
1234 SMI_ENTRY *SmiEntry;\r
1235 SMI_HANDLER *TargetSmiHandler;\r
1c3ac4b9
JY
1236 VOID *SearchContext;\r
1237 UINTN SearchContextSize;\r
1238\r
1239 if (((ContextSize == 0) && (Context != NULL)) ||\r
1240 ((ContextSize != 0) && (Context == NULL))) {\r
1241 return EFI_INVALID_PARAMETER;\r
1242 }\r
ca41f3f4
JY
1243\r
1244 SmiEntry = SmmCoreFindHardwareSmiEntry (HandlerGuid, FALSE);\r
1245 if (SmiEntry == NULL) {\r
1246 return EFI_NOT_FOUND;\r
1247 }\r
1248\r
1c3ac4b9
JY
1249 SearchContext = Context;\r
1250 SearchContextSize = ContextSize;\r
1251 if (Context != NULL) {\r
1252 if (CompareGuid (HandlerGuid, &gEfiSmmUsbDispatch2ProtocolGuid)) {\r
1253 SearchContext = ConvertSmiHandlerUsbContext (Context, ContextSize, &SearchContextSize);\r
1254 }\r
1255 }\r
1256\r
ca41f3f4
JY
1257 TargetSmiHandler = NULL;\r
1258 Head = &SmiEntry->SmiHandlers;\r
1259 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
1260 SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);\r
1261 if (SmiHandler->Handler == Handler) {\r
1c3ac4b9
JY
1262 if ((SearchContext == NULL) ||\r
1263 ((SearchContextSize == SmiHandler->ContextSize) && (CompareMem (SearchContext, SmiHandler->Context, SearchContextSize) == 0))) {\r
1264 TargetSmiHandler = SmiHandler;\r
1265 break;\r
1266 }\r
1267 }\r
1268 }\r
1269\r
1270 if (SearchContext != NULL) {\r
1271 if (CompareGuid (HandlerGuid, &gEfiSmmUsbDispatch2ProtocolGuid)) {\r
1272 FreePool (SearchContext);\r
ca41f3f4
JY
1273 }\r
1274 }\r
1c3ac4b9 1275\r
ca41f3f4
JY
1276 if (TargetSmiHandler == NULL) {\r
1277 return EFI_NOT_FOUND;\r
1278 }\r
1279 SmiHandler = TargetSmiHandler;\r
1280\r
1281 RemoveEntryList (&SmiHandler->Link);\r
251779fc
JY
1282 if (SmiHandler->Context != NULL) {\r
1283 FreePool (SmiHandler->Context);\r
1284 }\r
ca41f3f4
JY
1285 FreePool (SmiHandler);\r
1286\r
1287 if (IsListEmpty (&SmiEntry->SmiHandlers)) {\r
1288 RemoveEntryList (&SmiEntry->AllEntries);\r
1289 FreePool (SmiEntry);\r
1290 }\r
1291\r
1292 return EFI_SUCCESS;\r
1293}\r
1294\r
1295/**\r
1296 Initialize SmiHandler profile feature.\r
1297**/\r
1298VOID\r
1299SmmCoreInitializeSmiHandlerProfile (\r
1300 VOID\r
1301 )\r
1302{\r
1303 EFI_STATUS Status;\r
1304 VOID *Registration;\r
1305 EFI_HANDLE Handle;\r
1306\r
1307 if ((PcdGet8 (PcdSmiHandlerProfilePropertyMask) & 0x1) != 0) {\r
1308 InsertTailList (&mRootSmiEntryList, &mRootSmiEntry.AllEntries);\r
1309\r
1310 Status = gSmst->SmmRegisterProtocolNotify (\r
1311 &gEfiSmmReadyToLockProtocolGuid,\r
1312 SmmReadyToLockInSmiHandlerProfile,\r
1313 &Registration\r
1314 );\r
1315 ASSERT_EFI_ERROR (Status);\r
1316\r
1317 Handle = NULL;\r
1318 Status = gSmst->SmmInstallProtocolInterface (\r
1319 &Handle,\r
1320 &gSmiHandlerProfileGuid,\r
1321 EFI_NATIVE_INTERFACE,\r
1322 &mSmiHandlerProfile\r
1323 );\r
1324 ASSERT_EFI_ERROR (Status);\r
1325 }\r
1326}\r
1327\r