]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c
MdeModulePkg: Change OPTIONAL keyword usage style
[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 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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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 *
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 *
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
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
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
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 }