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