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