4 Step #1 - When a FV protocol is added to the system every driver in the FV
5 is added to the mDiscoveredList. The Before, and After Depex are
6 pre-processed as drivers are added to the mDiscoveredList. If an Apriori
7 file exists in the FV those drivers are addeded to the
8 mScheduledQueue. The mFvHandleList is used to make sure a
9 FV is only processed once.
11 Step #2 - Dispatch. Remove driver from the mScheduledQueue and load and
12 start it. After mScheduledQueue is drained check the
13 mDiscoveredList to see if any item has a Depex that is ready to
14 be placed on the mScheduledQueue.
16 Step #3 - Adding to the mScheduledQueue requires that you process Before
17 and After dependencies. This is done recursively as the call to add
18 to the mScheduledQueue checks for Before and recursively adds
19 all Befores. It then addes the item that was passed in and then
20 processes the After dependencies by recursively calling the routine.
23 The rules for the dispatcher are similar to the DXE dispatcher.
25 The rules for DXE dispatcher are in chapter 10 of the DXE CIS. Figure 10-3
26 is the state diagram for the DXE dispatcher
28 Depex - Dependency Expression.
30 Copyright (c) 2014, Hewlett-Packard Development Company, L.P.
31 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
32 SPDX-License-Identifier: BSD-2-Clause-Patent
36 #include "PiSmmCore.h"
39 // SMM Dispatcher Data structures
41 #define KNOWN_HANDLE_SIGNATURE SIGNATURE_32('k','n','o','w')
44 LIST_ENTRY Link
; // mFvHandleList
49 // Function Prototypes
53 Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
54 must add any driver with a before dependency on InsertedDriverEntry first.
55 You do this by recursively calling this routine. After all the Befores are
56 processed you can add InsertedDriverEntry to the mScheduledQueue.
57 Then you can add any driver with an After dependency on InsertedDriverEntry
58 by recursively calling this routine.
60 @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
64 SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
65 IN EFI_SMM_DRIVER_ENTRY
*InsertedDriverEntry
69 // The Driver List contains one copy of every driver that has been discovered.
70 // Items are never removed from the driver list. List of EFI_SMM_DRIVER_ENTRY
72 LIST_ENTRY mDiscoveredList
= INITIALIZE_LIST_HEAD_VARIABLE (mDiscoveredList
);
75 // Queue of drivers that are ready to dispatch. This queue is a subset of the
76 // mDiscoveredList.list of EFI_SMM_DRIVER_ENTRY.
78 LIST_ENTRY mScheduledQueue
= INITIALIZE_LIST_HEAD_VARIABLE (mScheduledQueue
);
81 // List of handles who's Fv's have been parsed and added to the mFwDriverList.
83 LIST_ENTRY mFvHandleList
= INITIALIZE_LIST_HEAD_VARIABLE (mFvHandleList
);
86 // Flag for the SMM Dispatcher. TRUE if dispatcher is executing.
88 BOOLEAN gDispatcherRunning
= FALSE
;
91 // Flag for the SMM Dispatcher. TRUE if there is one or more SMM drivers ready to be dispatched
93 BOOLEAN gRequestDispatch
= FALSE
;
96 // List of file types supported by dispatcher
98 EFI_FV_FILETYPE mSmmFileTypes
[] = {
100 EFI_FV_FILETYPE_COMBINED_SMM_DXE
,
101 EFI_FV_FILETYPE_SMM_CORE
,
103 // Note: DXE core will process the FV image file, so skip it in SMM core
104 // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
109 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH File
;
110 EFI_DEVICE_PATH_PROTOCOL End
;
111 } FV_FILEPATH_DEVICE_PATH
;
113 FV_FILEPATH_DEVICE_PATH mFvDevicePath
;
116 // DXE Architecture Protocols
118 EFI_SECURITY_ARCH_PROTOCOL
*mSecurity
= NULL
;
119 EFI_SECURITY2_ARCH_PROTOCOL
*mSecurity2
= NULL
;
122 // The global variable is defined for Loading modules at fixed address feature to track the SMM code
123 // memory range usage. It is a bit mapped array in which every bit indicates the corresponding
124 // memory page available or not.
126 GLOBAL_REMOVE_IF_UNREFERENCED UINT64
*mSmmCodeMemoryRangeUsageBitMap
= NULL
;
129 To check memory usage bit map array to figure out if the memory range in which the image will be loaded is available or not. If
130 memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used.
131 The function is only invoked when load modules at fixed address feature is enabled.
133 @param ImageBase The base address the image will be loaded at.
134 @param ImageSize The size of the image
136 @retval EFI_SUCCESS The memory range the image will be loaded in is available
137 @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available
140 CheckAndMarkFixLoadingMemoryUsageBitMap (
141 IN EFI_PHYSICAL_ADDRESS ImageBase
,
145 UINT32 SmmCodePageNumber
;
147 EFI_PHYSICAL_ADDRESS SmmCodeBase
;
148 UINTN BaseOffsetPageNumber
;
149 UINTN TopOffsetPageNumber
;
153 // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
155 SmmCodePageNumber
= PcdGet32 (PcdLoadFixAddressSmmCodePageNumber
);
156 SmmCodeSize
= EFI_PAGES_TO_SIZE (SmmCodePageNumber
);
157 SmmCodeBase
= gLoadModuleAtFixAddressSmramBase
;
160 // If the memory usage bit map is not initialized, do it. Every bit in the array
161 // indicate the status of the corresponding memory page, available or not
163 if (mSmmCodeMemoryRangeUsageBitMap
== NULL
) {
164 mSmmCodeMemoryRangeUsageBitMap
= AllocateZeroPool (((SmmCodePageNumber
/ 64) + 1)*sizeof (UINT64
));
168 // If the Dxe code memory range is not allocated or the bit map array allocation failed, return EFI_NOT_FOUND
170 if (mSmmCodeMemoryRangeUsageBitMap
== NULL
) {
171 return EFI_NOT_FOUND
;
175 // see if the memory range for loading the image is in the SMM code range.
177 if ((SmmCodeBase
+ SmmCodeSize
< ImageBase
+ ImageSize
) || (SmmCodeBase
> ImageBase
)) {
178 return EFI_NOT_FOUND
;
182 // Test if the memory is available or not.
184 BaseOffsetPageNumber
= EFI_SIZE_TO_PAGES ((UINT32
)(ImageBase
- SmmCodeBase
));
185 TopOffsetPageNumber
= EFI_SIZE_TO_PAGES ((UINT32
)(ImageBase
+ ImageSize
- SmmCodeBase
));
186 for (Index
= BaseOffsetPageNumber
; Index
< TopOffsetPageNumber
; Index
++) {
187 if ((mSmmCodeMemoryRangeUsageBitMap
[Index
/ 64] & LShiftU64 (1, (Index
% 64))) != 0) {
189 // This page is already used.
191 return EFI_NOT_FOUND
;
196 // Being here means the memory range is available. So mark the bits for the memory range
198 for (Index
= BaseOffsetPageNumber
; Index
< TopOffsetPageNumber
; Index
++) {
199 mSmmCodeMemoryRangeUsageBitMap
[Index
/ 64] |= LShiftU64 (1, (Index
% 64));
206 Get the fixed loading address from image header assigned by build tool. This function only be called
207 when Loading module at Fixed address feature enabled.
209 @param ImageContext Pointer to the image context structure that describes the PE/COFF
210 image that needs to be examined by this function.
211 @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .
212 @retval EFI_NOT_FOUND The image has no assigned fixed loading address.
216 GetPeCoffImageFixLoadingAssignedAddress (
217 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
220 UINTN SectionHeaderOffset
;
222 EFI_IMAGE_SECTION_HEADER SectionHeader
;
223 EFI_IMAGE_OPTIONAL_HEADER_UNION
*ImgHdr
;
224 EFI_PHYSICAL_ADDRESS FixLoadingAddress
;
227 UINT16 NumberOfSections
;
228 UINT64 ValueInSectionHeader
;
230 FixLoadingAddress
= 0;
231 Status
= EFI_NOT_FOUND
;
234 // Get PeHeader pointer
236 ImgHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)((CHAR8
*)ImageContext
->Handle
+ ImageContext
->PeCoffHeaderOffset
);
237 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+
239 sizeof (EFI_IMAGE_FILE_HEADER
) +
240 ImgHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
;
241 NumberOfSections
= ImgHdr
->Pe32
.FileHeader
.NumberOfSections
;
244 // Get base address from the first section header that doesn't point to code section.
246 for (Index
= 0; Index
< NumberOfSections
; Index
++) {
248 // Read section header from file
250 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
251 Status
= ImageContext
->ImageRead (
252 ImageContext
->Handle
,
257 if (EFI_ERROR (Status
)) {
261 Status
= EFI_NOT_FOUND
;
263 if ((SectionHeader
.Characteristics
& EFI_IMAGE_SCN_CNT_CODE
) == 0) {
265 // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header
266 // that doesn't point to code section in image header.So there is an assumption that when the feature is enabled,
267 // if a module with a loading address assigned by tools, the PointerToRelocations & PointerToLineNumbers fields
268 // should not be Zero, or else, these 2 fields should be set to Zero
270 ValueInSectionHeader
= ReadUnaligned64 ((UINT64
*)&SectionHeader
.PointerToRelocations
);
271 if (ValueInSectionHeader
!= 0) {
273 // Found first section header that doesn't point to code section in which build tool saves the
274 // offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields
276 FixLoadingAddress
= (EFI_PHYSICAL_ADDRESS
)(gLoadModuleAtFixAddressSmramBase
+ (INT64
)ValueInSectionHeader
);
278 // Check if the memory range is available.
280 Status
= CheckAndMarkFixLoadingMemoryUsageBitMap (FixLoadingAddress
, (UINTN
)(ImageContext
->ImageSize
+ ImageContext
->SectionAlignment
));
281 if (!EFI_ERROR (Status
)) {
283 // The assigned address is valid. Return the specified loading address
285 ImageContext
->ImageAddress
= FixLoadingAddress
;
292 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
295 DEBUG ((DEBUG_INFO
|DEBUG_LOAD
, "LOADING MODULE FIXED INFO: Loading module at fixed address %x, Status = %r\n", FixLoadingAddress
, Status
));
300 Loads an EFI image into SMRAM.
302 @param DriverEntry EFI_SMM_DRIVER_ENTRY instance
310 IN OUT EFI_SMM_DRIVER_ENTRY
*DriverEntry
313 UINT32 AuthenticationStatus
;
320 EFI_STATUS SecurityStatus
;
321 EFI_HANDLE DeviceHandle
;
322 EFI_PHYSICAL_ADDRESS DstBuffer
;
323 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
324 EFI_DEVICE_PATH_PROTOCOL
*OriginalFilePath
;
325 EFI_DEVICE_PATH_PROTOCOL
*HandleFilePath
;
326 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
327 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
329 PERF_LOAD_IMAGE_BEGIN (DriverEntry
->ImageHandle
);
333 Fv
= DriverEntry
->Fv
;
334 NameGuid
= &DriverEntry
->FileName
;
335 FilePath
= DriverEntry
->FvFileDevicePath
;
337 OriginalFilePath
= FilePath
;
338 HandleFilePath
= FilePath
;
340 SecurityStatus
= EFI_SUCCESS
;
341 Status
= EFI_SUCCESS
;
342 AuthenticationStatus
= 0;
345 // Try to get the image device handle by checking the match protocol.
347 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &HandleFilePath
, &DeviceHandle
);
348 if (EFI_ERROR (Status
)) {
353 // If the Security2 and Security Architectural Protocol has not been located yet, then attempt to locate it
355 if (mSecurity2
== NULL
) {
356 gBS
->LocateProtocol (&gEfiSecurity2ArchProtocolGuid
, NULL
, (VOID
**)&mSecurity2
);
359 if (mSecurity
== NULL
) {
360 gBS
->LocateProtocol (&gEfiSecurityArchProtocolGuid
, NULL
, (VOID
**)&mSecurity
);
364 // When Security2 is installed, Security Architectural Protocol must be published.
366 ASSERT (mSecurity2
== NULL
|| mSecurity
!= NULL
);
369 // Pull out just the file portion of the DevicePath for the LoadedImage FilePath
371 FilePath
= OriginalFilePath
;
372 Status
= gBS
->HandleProtocol (DeviceHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&HandleFilePath
);
373 if (!EFI_ERROR (Status
)) {
374 FilePathSize
= GetDevicePathSize (HandleFilePath
) - sizeof (EFI_DEVICE_PATH_PROTOCOL
);
375 FilePath
= (EFI_DEVICE_PATH_PROTOCOL
*)(((UINT8
*)FilePath
) + FilePathSize
);
379 // Try reading PE32 section firstly
381 Status
= Fv
->ReadSection (
388 &AuthenticationStatus
391 if (EFI_ERROR (Status
)) {
393 // Try reading TE section secondly
397 Status
= Fv
->ReadSection (
404 &AuthenticationStatus
408 if (EFI_ERROR (Status
)) {
409 if (Buffer
!= NULL
) {
410 gBS
->FreePool (Buffer
);
417 // Verify File Authentication through the Security2 Architectural Protocol
419 if (mSecurity2
!= NULL
) {
420 SecurityStatus
= mSecurity2
->FileAuthentication (
430 // Verify the Authentication Status through the Security Architectural Protocol
431 // Only on images that have been read using Firmware Volume protocol.
432 // All SMM images are from FV protocol.
434 if (!EFI_ERROR (SecurityStatus
) && (mSecurity
!= NULL
)) {
435 SecurityStatus
= mSecurity
->FileAuthenticationState (
437 AuthenticationStatus
,
442 if (EFI_ERROR (SecurityStatus
) && (SecurityStatus
!= EFI_SECURITY_VIOLATION
)) {
443 Status
= SecurityStatus
;
448 // Initialize ImageContext
450 ImageContext
.Handle
= Buffer
;
451 ImageContext
.ImageRead
= PeCoffLoaderImageReadFromMemory
;
454 // Get information about the image being loaded
456 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
457 if (EFI_ERROR (Status
)) {
458 if (Buffer
!= NULL
) {
459 gBS
->FreePool (Buffer
);
466 // if Loading module at Fixed Address feature is enabled, then cut out a memory range started from TESG BASE
467 // to hold the Smm driver code
469 if (PcdGet64 (PcdLoadModuleAtFixAddressEnable
) != 0) {
471 // Get the fixed loading address assigned by Build tool
473 Status
= GetPeCoffImageFixLoadingAssignedAddress (&ImageContext
);
474 if (!EFI_ERROR (Status
)) {
476 // Since the memory range to load Smm core already been cut out, so no need to allocate and free this range
477 // following statements is to bypass SmmFreePages
480 DstBuffer
= (UINTN
)gLoadModuleAtFixAddressSmramBase
;
482 DEBUG ((DEBUG_INFO
|DEBUG_LOAD
, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
484 // allocate the memory to load the SMM driver
486 PageCount
= (UINTN
)EFI_SIZE_TO_PAGES ((UINTN
)ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
487 DstBuffer
= (UINTN
)(-1);
489 Status
= SmmAllocatePages (
491 EfiRuntimeServicesCode
,
495 if (EFI_ERROR (Status
)) {
496 if (Buffer
!= NULL
) {
497 gBS
->FreePool (Buffer
);
503 ImageContext
.ImageAddress
= (EFI_PHYSICAL_ADDRESS
)DstBuffer
;
506 PageCount
= (UINTN
)EFI_SIZE_TO_PAGES ((UINTN
)ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
507 DstBuffer
= (UINTN
)(-1);
509 Status
= SmmAllocatePages (
511 EfiRuntimeServicesCode
,
515 if (EFI_ERROR (Status
)) {
516 if (Buffer
!= NULL
) {
517 gBS
->FreePool (Buffer
);
523 ImageContext
.ImageAddress
= (EFI_PHYSICAL_ADDRESS
)DstBuffer
;
527 // Align buffer on section boundary
529 ImageContext
.ImageAddress
+= ImageContext
.SectionAlignment
- 1;
530 ImageContext
.ImageAddress
&= ~((EFI_PHYSICAL_ADDRESS
)ImageContext
.SectionAlignment
- 1);
533 // Load the image to our new buffer
535 Status
= PeCoffLoaderLoadImage (&ImageContext
);
536 if (EFI_ERROR (Status
)) {
537 if (Buffer
!= NULL
) {
538 gBS
->FreePool (Buffer
);
541 SmmFreePages (DstBuffer
, PageCount
);
546 // Relocate the image in our new buffer
548 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
549 if (EFI_ERROR (Status
)) {
550 if (Buffer
!= NULL
) {
551 gBS
->FreePool (Buffer
);
554 SmmFreePages (DstBuffer
, PageCount
);
559 // Flush the instruction cache so the image data are written before we execute it
561 InvalidateInstructionCacheRange ((VOID
*)(UINTN
)ImageContext
.ImageAddress
, (UINTN
)ImageContext
.ImageSize
);
564 // Save Image EntryPoint in DriverEntry
566 DriverEntry
->ImageEntryPoint
= ImageContext
.EntryPoint
;
567 DriverEntry
->ImageBuffer
= DstBuffer
;
568 DriverEntry
->NumberOfPage
= PageCount
;
571 // Allocate a Loaded Image Protocol in EfiBootServicesData
573 Status
= gBS
->AllocatePool (EfiBootServicesData
, sizeof (EFI_LOADED_IMAGE_PROTOCOL
), (VOID
**)&DriverEntry
->LoadedImage
);
574 if (EFI_ERROR (Status
)) {
575 if (Buffer
!= NULL
) {
576 gBS
->FreePool (Buffer
);
579 SmmFreePages (DstBuffer
, PageCount
);
583 ZeroMem (DriverEntry
->LoadedImage
, sizeof (EFI_LOADED_IMAGE_PROTOCOL
));
585 // Fill in the remaining fields of the Loaded Image Protocol instance.
586 // Note: ImageBase is an SMRAM address that can not be accessed outside of SMRAM if SMRAM window is closed.
588 DriverEntry
->LoadedImage
->Revision
= EFI_LOADED_IMAGE_PROTOCOL_REVISION
;
589 DriverEntry
->LoadedImage
->ParentHandle
= gSmmCorePrivate
->SmmIplImageHandle
;
590 DriverEntry
->LoadedImage
->SystemTable
= gST
;
591 DriverEntry
->LoadedImage
->DeviceHandle
= DeviceHandle
;
593 DriverEntry
->SmmLoadedImage
.Revision
= EFI_LOADED_IMAGE_PROTOCOL_REVISION
;
594 DriverEntry
->SmmLoadedImage
.ParentHandle
= gSmmCorePrivate
->SmmIplImageHandle
;
595 DriverEntry
->SmmLoadedImage
.SystemTable
= gST
;
596 DriverEntry
->SmmLoadedImage
.DeviceHandle
= DeviceHandle
;
599 // Make an EfiBootServicesData buffer copy of FilePath
601 Status
= gBS
->AllocatePool (EfiBootServicesData
, GetDevicePathSize (FilePath
), (VOID
**)&DriverEntry
->LoadedImage
->FilePath
);
602 if (EFI_ERROR (Status
)) {
603 if (Buffer
!= NULL
) {
604 gBS
->FreePool (Buffer
);
607 SmmFreePages (DstBuffer
, PageCount
);
611 CopyMem (DriverEntry
->LoadedImage
->FilePath
, FilePath
, GetDevicePathSize (FilePath
));
613 DriverEntry
->LoadedImage
->ImageBase
= (VOID
*)(UINTN
)ImageContext
.ImageAddress
;
614 DriverEntry
->LoadedImage
->ImageSize
= ImageContext
.ImageSize
;
615 DriverEntry
->LoadedImage
->ImageCodeType
= EfiRuntimeServicesCode
;
616 DriverEntry
->LoadedImage
->ImageDataType
= EfiRuntimeServicesData
;
619 // Make a buffer copy of FilePath
621 Status
= SmmAllocatePool (EfiRuntimeServicesData
, GetDevicePathSize (FilePath
), (VOID
**)&DriverEntry
->SmmLoadedImage
.FilePath
);
622 if (EFI_ERROR (Status
)) {
623 if (Buffer
!= NULL
) {
624 gBS
->FreePool (Buffer
);
627 gBS
->FreePool (DriverEntry
->LoadedImage
->FilePath
);
628 SmmFreePages (DstBuffer
, PageCount
);
632 CopyMem (DriverEntry
->SmmLoadedImage
.FilePath
, FilePath
, GetDevicePathSize (FilePath
));
634 DriverEntry
->SmmLoadedImage
.ImageBase
= (VOID
*)(UINTN
)ImageContext
.ImageAddress
;
635 DriverEntry
->SmmLoadedImage
.ImageSize
= ImageContext
.ImageSize
;
636 DriverEntry
->SmmLoadedImage
.ImageCodeType
= EfiRuntimeServicesCode
;
637 DriverEntry
->SmmLoadedImage
.ImageDataType
= EfiRuntimeServicesData
;
640 // Create a new image handle in the UEFI handle database for the SMM Driver
642 DriverEntry
->ImageHandle
= NULL
;
643 Status
= gBS
->InstallMultipleProtocolInterfaces (
644 &DriverEntry
->ImageHandle
,
645 &gEfiLoadedImageProtocolGuid
,
646 DriverEntry
->LoadedImage
,
651 // Create a new image handle in the SMM handle database for the SMM Driver
653 DriverEntry
->SmmImageHandle
= NULL
;
654 Status
= SmmInstallProtocolInterface (
655 &DriverEntry
->SmmImageHandle
,
656 &gEfiLoadedImageProtocolGuid
,
657 EFI_NATIVE_INTERFACE
,
658 &DriverEntry
->SmmLoadedImage
661 PERF_LOAD_IMAGE_END (DriverEntry
->ImageHandle
);
664 // Print the load address and the PDB file name if it is available
671 CHAR8 EfiFileName
[256];
674 DEBUG_INFO
| DEBUG_LOAD
,
675 "Loading SMM driver at 0x%11p EntryPoint=0x%11p ",
676 (VOID
*)(UINTN
)ImageContext
.ImageAddress
,
677 FUNCTION_ENTRY_POINT (ImageContext
.EntryPoint
)
681 // Print Module Name by Pdb file path.
682 // Windows and Unix style file path are all trimmed correctly.
684 if (ImageContext
.PdbPointer
!= NULL
) {
686 for (Index
= 0; ImageContext
.PdbPointer
[Index
] != 0; Index
++) {
687 if ((ImageContext
.PdbPointer
[Index
] == '\\') || (ImageContext
.PdbPointer
[Index
] == '/')) {
688 StartIndex
= Index
+ 1;
693 // Copy the PDB file name to our temporary string, and replace .pdb with .efi
694 // The PDB file name is limited in the range of 0~255.
695 // If the length is bigger than 255, trim the redundant characters to avoid overflow in array boundary.
697 for (Index
= 0; Index
< sizeof (EfiFileName
) - 4; Index
++) {
698 EfiFileName
[Index
] = ImageContext
.PdbPointer
[Index
+ StartIndex
];
699 if (EfiFileName
[Index
] == 0) {
700 EfiFileName
[Index
] = '.';
703 if (EfiFileName
[Index
] == '.') {
704 EfiFileName
[Index
+ 1] = 'e';
705 EfiFileName
[Index
+ 2] = 'f';
706 EfiFileName
[Index
+ 3] = 'i';
707 EfiFileName
[Index
+ 4] = 0;
712 if (Index
== sizeof (EfiFileName
) - 4) {
713 EfiFileName
[Index
] = 0;
716 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "%a", EfiFileName
)); // &Image->ImageContext.PdbPointer[StartIndex]));
719 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "\n"));
724 // Free buffer allocated by Fv->ReadSection.
726 // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection
727 // used the UEFI Boot Services AllocatePool() function
729 Status
= gBS
->FreePool (Buffer
);
730 if (!EFI_ERROR (Status
) && EFI_ERROR (SecurityStatus
)) {
731 Status
= SecurityStatus
;
738 Preprocess dependency expression and update DriverEntry to reflect the
739 state of Before and After dependencies. If DriverEntry->Before
740 or DriverEntry->After is set it will never be cleared.
742 @param DriverEntry DriverEntry element to update .
744 @retval EFI_SUCCESS It always works.
749 IN EFI_SMM_DRIVER_ENTRY
*DriverEntry
754 Iterator
= DriverEntry
->Depex
;
755 DriverEntry
->Dependent
= TRUE
;
757 if (*Iterator
== EFI_DEP_BEFORE
) {
758 DriverEntry
->Before
= TRUE
;
759 } else if (*Iterator
== EFI_DEP_AFTER
) {
760 DriverEntry
->After
= TRUE
;
763 if (DriverEntry
->Before
|| DriverEntry
->After
) {
764 CopyMem (&DriverEntry
->BeforeAfterGuid
, Iterator
+ 1, sizeof (EFI_GUID
));
771 Read Depex and pre-process the Depex for Before and After. If Section Extraction
772 protocol returns an error via ReadSection defer the reading of the Depex.
774 @param DriverEntry Driver to work on.
776 @retval EFI_SUCCESS Depex read and preprocessed
777 @retval EFI_PROTOCOL_ERROR The section extraction protocol returned an error
778 and Depex reading needs to be retried.
779 @retval Error DEPEX not found.
783 SmmGetDepexSectionAndPreProccess (
784 IN EFI_SMM_DRIVER_ENTRY
*DriverEntry
788 EFI_SECTION_TYPE SectionType
;
789 UINT32 AuthenticationStatus
;
790 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
792 Fv
= DriverEntry
->Fv
;
795 // Grab Depex info, it will never be free'ed.
796 // (Note: DriverEntry->Depex is in DXE memory)
798 SectionType
= EFI_SECTION_SMM_DEPEX
;
799 Status
= Fv
->ReadSection (
801 &DriverEntry
->FileName
,
805 (UINTN
*)&DriverEntry
->DepexSize
,
806 &AuthenticationStatus
808 if (EFI_ERROR (Status
)) {
809 if (Status
== EFI_PROTOCOL_ERROR
) {
811 // The section extraction protocol failed so set protocol error flag
813 DriverEntry
->DepexProtocolError
= TRUE
;
816 // If no Depex assume depend on all architectural protocols
818 DriverEntry
->Depex
= NULL
;
819 DriverEntry
->Dependent
= TRUE
;
820 DriverEntry
->DepexProtocolError
= FALSE
;
824 // Set Before and After state information based on Depex
825 // Driver will be put in Dependent state
827 SmmPreProcessDepex (DriverEntry
);
828 DriverEntry
->DepexProtocolError
= FALSE
;
835 This is the main Dispatcher for SMM and it exits when there are no more
836 drivers to run. Drain the mScheduledQueue and load and start a PE
837 image for each driver. Search the mDiscoveredList to see if any driver can
838 be placed on the mScheduledQueue. If no drivers are placed on the
839 mScheduledQueue exit the function.
841 @retval EFI_SUCCESS All of the SMM Drivers that could be dispatched
842 have been run and the SMM Entry Point has been
844 @retval EFI_NOT_READY The SMM Driver that registered the SMM Entry Point
846 @retval EFI_NOT_FOUND There are no SMM Drivers available to be dispatched.
847 @retval EFI_ALREADY_STARTED The SMM Dispatcher is already running
857 EFI_SMM_DRIVER_ENTRY
*DriverEntry
;
859 BOOLEAN PreviousSmmEntryPointRegistered
;
861 if (!gRequestDispatch
) {
862 return EFI_NOT_FOUND
;
865 if (gDispatcherRunning
) {
867 // If the dispatcher is running don't let it be restarted.
869 return EFI_ALREADY_STARTED
;
872 gDispatcherRunning
= TRUE
;
876 // Drain the Scheduled Queue
878 while (!IsListEmpty (&mScheduledQueue
)) {
880 mScheduledQueue
.ForwardLink
,
881 EFI_SMM_DRIVER_ENTRY
,
883 EFI_SMM_DRIVER_ENTRY_SIGNATURE
887 // Load the SMM Driver image into memory. If the Driver was transitioned from
888 // Untrused to Scheduled it would have already been loaded so we may need to
889 // skip the LoadImage
891 if (DriverEntry
->ImageHandle
== NULL
) {
892 Status
= SmmLoadImage (DriverEntry
);
895 // Update the driver state to reflect that it's been loaded
897 if (EFI_ERROR (Status
)) {
899 // The SMM Driver could not be loaded, and do not attempt to load or start it again.
900 // Take driver from Scheduled to Initialized.
902 DriverEntry
->Initialized
= TRUE
;
903 DriverEntry
->Scheduled
= FALSE
;
904 RemoveEntryList (&DriverEntry
->ScheduledLink
);
907 // If it's an error don't try the StartImage
913 DriverEntry
->Scheduled
= FALSE
;
914 DriverEntry
->Initialized
= TRUE
;
915 RemoveEntryList (&DriverEntry
->ScheduledLink
);
917 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
919 EFI_SOFTWARE_SMM_DRIVER
| EFI_SW_PC_INIT_BEGIN
,
920 &DriverEntry
->ImageHandle
,
921 sizeof (DriverEntry
->ImageHandle
)
925 // Cache state of SmmEntryPointRegistered before calling entry point
927 PreviousSmmEntryPointRegistered
= gSmmCorePrivate
->SmmEntryPointRegistered
;
930 // For each SMM driver, pass NULL as ImageHandle
932 RegisterSmramProfileImage (DriverEntry
, TRUE
);
933 PERF_START_IMAGE_BEGIN (DriverEntry
->ImageHandle
);
934 Status
= ((EFI_IMAGE_ENTRY_POINT
)(UINTN
)DriverEntry
->ImageEntryPoint
)(DriverEntry
->ImageHandle
, gST
);
935 PERF_START_IMAGE_END (DriverEntry
->ImageHandle
);
936 if (EFI_ERROR (Status
)) {
939 "Error: SMM image at %11p start failed: %r\n",
940 DriverEntry
->SmmLoadedImage
.ImageBase
,
943 UnregisterSmramProfileImage (DriverEntry
, TRUE
);
944 SmmFreePages (DriverEntry
->ImageBuffer
, DriverEntry
->NumberOfPage
);
946 // Uninstall LoadedImage
948 Status
= gBS
->UninstallProtocolInterface (
949 DriverEntry
->ImageHandle
,
950 &gEfiLoadedImageProtocolGuid
,
951 DriverEntry
->LoadedImage
953 if (!EFI_ERROR (Status
)) {
954 if (DriverEntry
->LoadedImage
->FilePath
!= NULL
) {
955 gBS
->FreePool (DriverEntry
->LoadedImage
->FilePath
);
958 gBS
->FreePool (DriverEntry
->LoadedImage
);
961 Status
= SmmUninstallProtocolInterface (
962 DriverEntry
->SmmImageHandle
,
963 &gEfiLoadedImageProtocolGuid
,
964 &DriverEntry
->SmmLoadedImage
966 if (!EFI_ERROR (Status
)) {
967 if (DriverEntry
->SmmLoadedImage
.FilePath
!= NULL
) {
968 SmmFreePool (DriverEntry
->SmmLoadedImage
.FilePath
);
973 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
975 EFI_SOFTWARE_SMM_DRIVER
| EFI_SW_PC_INIT_END
,
976 &DriverEntry
->ImageHandle
,
977 sizeof (DriverEntry
->ImageHandle
)
980 if (!PreviousSmmEntryPointRegistered
&& gSmmCorePrivate
->SmmEntryPointRegistered
) {
982 // Return immediately if the SMM Entry Point was registered by the SMM
983 // Driver that was just dispatched. The SMM IPL will reinvoke the SMM
984 // Core Dispatcher. This is required so SMM Mode may be enabled as soon
985 // as all the dependent SMM Drivers for SMM Mode have been dispatched.
986 // Once the SMM Entry Point has been registered, then SMM Mode will be
989 gRequestDispatch
= TRUE
;
990 gDispatcherRunning
= FALSE
;
991 return EFI_NOT_READY
;
996 // Search DriverList for items to place on Scheduled Queue
999 for (Link
= mDiscoveredList
.ForwardLink
; Link
!= &mDiscoveredList
; Link
= Link
->ForwardLink
) {
1000 DriverEntry
= CR (Link
, EFI_SMM_DRIVER_ENTRY
, Link
, EFI_SMM_DRIVER_ENTRY_SIGNATURE
);
1002 if (DriverEntry
->DepexProtocolError
) {
1004 // If Section Extraction Protocol did not let the Depex be read before retry the read
1006 Status
= SmmGetDepexSectionAndPreProccess (DriverEntry
);
1009 if (DriverEntry
->Dependent
) {
1010 if (SmmIsSchedulable (DriverEntry
)) {
1011 SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry
);
1016 } while (ReadyToRun
);
1019 // If there is no more SMM driver to dispatch, stop the dispatch request
1021 gRequestDispatch
= FALSE
;
1022 for (Link
= mDiscoveredList
.ForwardLink
; Link
!= &mDiscoveredList
; Link
= Link
->ForwardLink
) {
1023 DriverEntry
= CR (Link
, EFI_SMM_DRIVER_ENTRY
, Link
, EFI_SMM_DRIVER_ENTRY_SIGNATURE
);
1025 if (!DriverEntry
->Initialized
) {
1027 // We have SMM driver pending to dispatch
1029 gRequestDispatch
= TRUE
;
1034 gDispatcherRunning
= FALSE
;
1040 Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
1041 must add any driver with a before dependency on InsertedDriverEntry first.
1042 You do this by recursively calling this routine. After all the Befores are
1043 processed you can add InsertedDriverEntry to the mScheduledQueue.
1044 Then you can add any driver with an After dependency on InsertedDriverEntry
1045 by recursively calling this routine.
1047 @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
1051 SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
1052 IN EFI_SMM_DRIVER_ENTRY
*InsertedDriverEntry
1056 EFI_SMM_DRIVER_ENTRY
*DriverEntry
;
1059 // Process Before Dependency
1061 for (Link
= mDiscoveredList
.ForwardLink
; Link
!= &mDiscoveredList
; Link
= Link
->ForwardLink
) {
1062 DriverEntry
= CR (Link
, EFI_SMM_DRIVER_ENTRY
, Link
, EFI_SMM_DRIVER_ENTRY_SIGNATURE
);
1063 if (DriverEntry
->Before
&& DriverEntry
->Dependent
&& (DriverEntry
!= InsertedDriverEntry
)) {
1064 DEBUG ((DEBUG_DISPATCH
, "Evaluate SMM DEPEX for FFS(%g)\n", &DriverEntry
->FileName
));
1065 DEBUG ((DEBUG_DISPATCH
, " BEFORE FFS(%g) = ", &DriverEntry
->BeforeAfterGuid
));
1066 if (CompareGuid (&InsertedDriverEntry
->FileName
, &DriverEntry
->BeforeAfterGuid
)) {
1068 // Recursively process BEFORE
1070 DEBUG ((DEBUG_DISPATCH
, "TRUE\n END\n RESULT = TRUE\n"));
1071 SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry
);
1073 DEBUG ((DEBUG_DISPATCH
, "FALSE\n END\n RESULT = FALSE\n"));
1079 // Convert driver from Dependent to Scheduled state
1082 InsertedDriverEntry
->Dependent
= FALSE
;
1083 InsertedDriverEntry
->Scheduled
= TRUE
;
1084 InsertTailList (&mScheduledQueue
, &InsertedDriverEntry
->ScheduledLink
);
1087 // Process After Dependency
1089 for (Link
= mDiscoveredList
.ForwardLink
; Link
!= &mDiscoveredList
; Link
= Link
->ForwardLink
) {
1090 DriverEntry
= CR (Link
, EFI_SMM_DRIVER_ENTRY
, Link
, EFI_SMM_DRIVER_ENTRY_SIGNATURE
);
1091 if (DriverEntry
->After
&& DriverEntry
->Dependent
&& (DriverEntry
!= InsertedDriverEntry
)) {
1092 DEBUG ((DEBUG_DISPATCH
, "Evaluate SMM DEPEX for FFS(%g)\n", &DriverEntry
->FileName
));
1093 DEBUG ((DEBUG_DISPATCH
, " AFTER FFS(%g) = ", &DriverEntry
->BeforeAfterGuid
));
1094 if (CompareGuid (&InsertedDriverEntry
->FileName
, &DriverEntry
->BeforeAfterGuid
)) {
1096 // Recursively process AFTER
1098 DEBUG ((DEBUG_DISPATCH
, "TRUE\n END\n RESULT = TRUE\n"));
1099 SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry
);
1101 DEBUG ((DEBUG_DISPATCH
, "FALSE\n END\n RESULT = FALSE\n"));
1108 Return TRUE if the Fv has been processed, FALSE if not.
1110 @param FvHandle The handle of a FV that's being tested
1112 @retval TRUE Fv protocol on FvHandle has been processed
1113 @retval FALSE Fv protocol on FvHandle has not yet been
1118 FvHasBeenProcessed (
1119 IN EFI_HANDLE FvHandle
1123 KNOWN_HANDLE
*KnownHandle
;
1125 for (Link
= mFvHandleList
.ForwardLink
; Link
!= &mFvHandleList
; Link
= Link
->ForwardLink
) {
1126 KnownHandle
= CR (Link
, KNOWN_HANDLE
, Link
, KNOWN_HANDLE_SIGNATURE
);
1127 if (KnownHandle
->Handle
== FvHandle
) {
1136 Remember that Fv protocol on FvHandle has had its drivers placed on the
1137 mDiscoveredList. This function adds entries on the mFvHandleList. Items are
1138 never removed/freed from the mFvHandleList.
1140 @param FvHandle The handle of a FV that has been processed
1144 FvIsBeingProcessed (
1145 IN EFI_HANDLE FvHandle
1148 KNOWN_HANDLE
*KnownHandle
;
1150 KnownHandle
= AllocatePool (sizeof (KNOWN_HANDLE
));
1151 ASSERT (KnownHandle
!= NULL
);
1153 KnownHandle
->Signature
= KNOWN_HANDLE_SIGNATURE
;
1154 KnownHandle
->Handle
= FvHandle
;
1155 InsertTailList (&mFvHandleList
, &KnownHandle
->Link
);
1159 Convert FvHandle and DriverName into an EFI device path
1161 @param Fv Fv protocol, needed to read Depex info out of
1163 @param FvHandle Handle for Fv, needed in the
1164 EFI_SMM_DRIVER_ENTRY so that the PE image can be
1165 read out of the FV at a later time.
1166 @param DriverName Name of driver to add to mDiscoveredList.
1168 @return Pointer to device path constructed from FvHandle and DriverName
1171 EFI_DEVICE_PATH_PROTOCOL
*
1173 IN EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
,
1174 IN EFI_HANDLE FvHandle
,
1175 IN EFI_GUID
*DriverName
1179 EFI_DEVICE_PATH_PROTOCOL
*FvDevicePath
;
1180 EFI_DEVICE_PATH_PROTOCOL
*FileNameDevicePath
;
1183 // Remember the device path of the FV
1185 Status
= gBS
->HandleProtocol (FvHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&FvDevicePath
);
1186 if (EFI_ERROR (Status
)) {
1187 FileNameDevicePath
= NULL
;
1190 // Build a device path to the file in the FV to pass into gBS->LoadImage
1192 EfiInitializeFwVolDevicepathNode (&mFvDevicePath
.File
, DriverName
);
1193 SetDevicePathEndNode (&mFvDevicePath
.End
);
1196 // Note: FileNameDevicePath is in DXE memory
1198 FileNameDevicePath
= AppendDevicePath (
1200 (EFI_DEVICE_PATH_PROTOCOL
*)&mFvDevicePath
1204 return FileNameDevicePath
;
1208 Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
1209 and initialize any state variables. Read the Depex from the FV and store it
1210 in DriverEntry. Pre-process the Depex to set the Before and After state.
1211 The Discovered list is never free'ed and contains booleans that represent the
1212 other possible SMM driver states.
1214 @param Fv Fv protocol, needed to read Depex info out of
1216 @param FvHandle Handle for Fv, needed in the
1217 EFI_SMM_DRIVER_ENTRY so that the PE image can be
1218 read out of the FV at a later time.
1219 @param DriverName Name of driver to add to mDiscoveredList.
1221 @retval EFI_SUCCESS If driver was added to the mDiscoveredList.
1222 @retval EFI_ALREADY_STARTED The driver has already been started. Only one
1223 DriverName may be active in the system at any one
1228 SmmAddToDriverList (
1229 IN EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
,
1230 IN EFI_HANDLE FvHandle
,
1231 IN EFI_GUID
*DriverName
1234 EFI_SMM_DRIVER_ENTRY
*DriverEntry
;
1237 // Create the Driver Entry for the list. ZeroPool initializes lots of variables to
1240 DriverEntry
= AllocateZeroPool (sizeof (EFI_SMM_DRIVER_ENTRY
));
1241 ASSERT (DriverEntry
!= NULL
);
1243 DriverEntry
->Signature
= EFI_SMM_DRIVER_ENTRY_SIGNATURE
;
1244 CopyGuid (&DriverEntry
->FileName
, DriverName
);
1245 DriverEntry
->FvHandle
= FvHandle
;
1246 DriverEntry
->Fv
= Fv
;
1247 DriverEntry
->FvFileDevicePath
= SmmFvToDevicePath (Fv
, FvHandle
, DriverName
);
1249 SmmGetDepexSectionAndPreProccess (DriverEntry
);
1251 InsertTailList (&mDiscoveredList
, &DriverEntry
->Link
);
1252 gRequestDispatch
= TRUE
;
1258 This function is the main entry point for an SMM handler dispatch
1259 or communicate-based callback.
1261 Event notification that is fired every time a FV dispatch protocol is added.
1262 More than one protocol may have been added when this event is fired, so you
1263 must loop on SmmLocateHandle () to see how many protocols were added and
1264 do the following to each FV:
1265 If the Fv has already been processed, skip it. If the Fv has not been
1266 processed then mark it as being processed, as we are about to process it.
1267 Read the Fv and add any driver in the Fv to the mDiscoveredList.The
1268 mDiscoveredList is never free'ed and contains variables that define
1269 the other states the SMM driver transitions to..
1270 While you are at it read the A Priori file into memory.
1271 Place drivers in the A Priori list onto the mScheduledQueue.
1273 @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
1274 @param Context Points to an optional handler context which was specified when the handler was registered.
1275 @param CommBuffer A pointer to a collection of data in memory that will
1276 be conveyed from a non-SMM environment into an SMM environment.
1277 @param CommBufferSize The size of the CommBuffer.
1284 SmmDriverDispatchHandler (
1285 IN EFI_HANDLE DispatchHandle
,
1286 IN CONST VOID
*Context OPTIONAL
,
1287 IN OUT VOID
*CommBuffer OPTIONAL
,
1288 IN OUT UINTN
*CommBufferSize OPTIONAL
1293 EFI_HANDLE
*HandleBuffer
;
1294 EFI_STATUS GetNextFileStatus
;
1295 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
1296 EFI_DEVICE_PATH_PROTOCOL
*FvDevicePath
;
1297 EFI_HANDLE FvHandle
;
1300 EFI_FV_FILETYPE Type
;
1301 EFI_FV_FILE_ATTRIBUTES Attributes
;
1303 EFI_SMM_DRIVER_ENTRY
*DriverEntry
;
1304 EFI_GUID
*AprioriFile
;
1305 UINTN AprioriEntryCount
;
1310 UINT32 AuthenticationStatus
;
1313 HandleBuffer
= NULL
;
1314 Status
= gBS
->LocateHandleBuffer (
1316 &gEfiFirmwareVolume2ProtocolGuid
,
1321 if (EFI_ERROR (Status
)) {
1322 return EFI_NOT_FOUND
;
1325 for (HandleIndex
= 0; HandleIndex
< HandleCount
; HandleIndex
++) {
1326 FvHandle
= HandleBuffer
[HandleIndex
];
1328 if (FvHasBeenProcessed (FvHandle
)) {
1330 // This Fv has already been processed so lets skip it!
1336 // Since we are about to process this Fv mark it as processed.
1338 FvIsBeingProcessed (FvHandle
);
1340 Status
= gBS
->HandleProtocol (FvHandle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&Fv
);
1341 if (EFI_ERROR (Status
)) {
1343 // FvHandle must have a Firmware Volume2 Protocol thus we should never get here.
1349 Status
= gBS
->HandleProtocol (FvHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&FvDevicePath
);
1350 if (EFI_ERROR (Status
)) {
1352 // The Firmware volume doesn't have device path, can't be dispatched.
1358 // Discover Drivers in FV and add them to the Discovered Driver List.
1359 // Process EFI_FV_FILETYPE_SMM type and then EFI_FV_FILETYPE_COMBINED_SMM_DXE
1360 // EFI_FV_FILETYPE_SMM_CORE is processed to produce a Loaded Image protocol for the core
1362 for (SmmTypeIndex
= 0; SmmTypeIndex
< sizeof (mSmmFileTypes
)/sizeof (EFI_FV_FILETYPE
); SmmTypeIndex
++) {
1364 // Initialize the search key
1368 Type
= mSmmFileTypes
[SmmTypeIndex
];
1369 GetNextFileStatus
= Fv
->GetNextFile (
1377 if (!EFI_ERROR (GetNextFileStatus
)) {
1378 if (Type
== EFI_FV_FILETYPE_SMM_CORE
) {
1380 // If this is the SMM core fill in it's DevicePath & DeviceHandle
1382 if (mSmmCoreLoadedImage
->FilePath
== NULL
) {
1384 // Maybe one special FV contains only one SMM_CORE module, so its device path must
1385 // be initialized completely.
1387 EfiInitializeFwVolDevicepathNode (&mFvDevicePath
.File
, &NameGuid
);
1388 SetDevicePathEndNode (&mFvDevicePath
.End
);
1391 // Make an EfiBootServicesData buffer copy of FilePath
1393 Status
= gBS
->AllocatePool (
1394 EfiBootServicesData
,
1395 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*)&mFvDevicePath
),
1396 (VOID
**)&mSmmCoreLoadedImage
->FilePath
1398 ASSERT_EFI_ERROR (Status
);
1399 CopyMem (mSmmCoreLoadedImage
->FilePath
, &mFvDevicePath
, GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*)&mFvDevicePath
));
1401 mSmmCoreLoadedImage
->DeviceHandle
= FvHandle
;
1404 if (mSmmCoreDriverEntry
->SmmLoadedImage
.FilePath
== NULL
) {
1406 // Maybe one special FV contains only one SMM_CORE module, so its device path must
1407 // be initialized completely.
1409 EfiInitializeFwVolDevicepathNode (&mFvDevicePath
.File
, &NameGuid
);
1410 SetDevicePathEndNode (&mFvDevicePath
.End
);
1413 // Make a buffer copy FilePath
1415 Status
= SmmAllocatePool (
1416 EfiRuntimeServicesData
,
1417 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*)&mFvDevicePath
),
1418 (VOID
**)&mSmmCoreDriverEntry
->SmmLoadedImage
.FilePath
1420 ASSERT_EFI_ERROR (Status
);
1421 CopyMem (mSmmCoreDriverEntry
->SmmLoadedImage
.FilePath
, &mFvDevicePath
, GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*)&mFvDevicePath
));
1423 mSmmCoreDriverEntry
->SmmLoadedImage
.DeviceHandle
= FvHandle
;
1426 SmmAddToDriverList (Fv
, FvHandle
, &NameGuid
);
1429 } while (!EFI_ERROR (GetNextFileStatus
));
1433 // Read the array of GUIDs from the Apriori file if it is present in the firmware volume
1434 // (Note: AprioriFile is in DXE memory)
1437 Status
= Fv
->ReadSection (
1442 (VOID
**)&AprioriFile
,
1444 &AuthenticationStatus
1446 if (!EFI_ERROR (Status
)) {
1447 AprioriEntryCount
= SizeOfBuffer
/ sizeof (EFI_GUID
);
1449 AprioriEntryCount
= 0;
1453 // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes
1454 // drivers not in the current FV and these must be skipped since the a priori list
1455 // is only valid for the FV that it resided in.
1458 for (AprioriIndex
= 0; AprioriIndex
< AprioriEntryCount
; AprioriIndex
++) {
1459 for (Link
= mDiscoveredList
.ForwardLink
; Link
!= &mDiscoveredList
; Link
= Link
->ForwardLink
) {
1460 DriverEntry
= CR (Link
, EFI_SMM_DRIVER_ENTRY
, Link
, EFI_SMM_DRIVER_ENTRY_SIGNATURE
);
1461 if (CompareGuid (&DriverEntry
->FileName
, &AprioriFile
[AprioriIndex
]) &&
1462 (FvHandle
== DriverEntry
->FvHandle
))
1464 DriverEntry
->Dependent
= FALSE
;
1465 DriverEntry
->Scheduled
= TRUE
;
1466 InsertTailList (&mScheduledQueue
, &DriverEntry
->ScheduledLink
);
1467 DEBUG ((DEBUG_DISPATCH
, "Evaluate SMM DEPEX for FFS(%g)\n", &DriverEntry
->FileName
));
1468 DEBUG ((DEBUG_DISPATCH
, " RESULT = TRUE (Apriori)\n"));
1475 // Free data allocated by Fv->ReadSection ()
1477 // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection
1478 // used the UEFI Boot Services AllocatePool() function
1480 gBS
->FreePool (AprioriFile
);
1484 // Execute the SMM Dispatcher on any newly discovered FVs and previously
1485 // discovered SMM drivers that have been discovered but not dispatched.
1487 Status
= SmmDispatcher ();
1490 // Check to see if CommBuffer and CommBufferSize are valid
1492 if ((CommBuffer
!= NULL
) && (CommBufferSize
!= NULL
)) {
1493 if (*CommBufferSize
> 0) {
1494 if (Status
== EFI_NOT_READY
) {
1496 // If a the SMM Core Entry Point was just registered, then set flag to
1497 // request the SMM Dispatcher to be restarted.
1499 *(UINT8
*)CommBuffer
= COMM_BUFFER_SMM_DISPATCH_RESTART
;
1500 } else if (!EFI_ERROR (Status
)) {
1502 // Set the flag to show that the SMM Dispatcher executed without errors
1504 *(UINT8
*)CommBuffer
= COMM_BUFFER_SMM_DISPATCH_SUCCESS
;
1507 // Set the flag to show that the SMM Dispatcher encountered an error
1509 *(UINT8
*)CommBuffer
= COMM_BUFFER_SMM_DISPATCH_ERROR
;
1518 Traverse the discovered list for any drivers that were discovered but not loaded
1519 because the dependency expressions evaluated to false.
1523 SmmDisplayDiscoveredNotDispatched (
1528 EFI_SMM_DRIVER_ENTRY
*DriverEntry
;
1530 for (Link
= mDiscoveredList
.ForwardLink
; Link
!= &mDiscoveredList
; Link
= Link
->ForwardLink
) {
1531 DriverEntry
= CR (Link
, EFI_SMM_DRIVER_ENTRY
, Link
, EFI_SMM_DRIVER_ENTRY_SIGNATURE
);
1532 if (DriverEntry
->Dependent
) {
1533 DEBUG ((DEBUG_LOAD
, "SMM Driver %g was discovered but not loaded!!\n", &DriverEntry
->FileName
));