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