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