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