X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FCore%2FPiSmmCore%2FDispatcher.c;h=7ad0d34178532c2fe95f2ce308e3dd784e484591;hb=9917def3294bac4d14cd86ba382652aa41c6c1d6;hp=9e1a77890079e9f4907d17d4bee60080f17c2fe7;hpb=e42e94041f7c71a5e2e57154bd568f3c14fd6eec;p=mirror_edk2.git
diff --git a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
index 9e1a778900..7ad0d34178 100644
--- a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
+++ b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
@@ -2,7 +2,7 @@
SMM Driver Dispatcher.
Step #1 - When a FV protocol is added to the system every driver in the FV
- is added to the mDiscoveredList. The SOR, Before, and After Depex are
+ is added to the mDiscoveredList. The Before, and After Depex are
pre-processed as drivers are added to the mDiscoveredList. If an Apriori
file exists in the FV those drivers are addeded to the
mScheduledQueue. The mFvHandleList is used to make sure a
@@ -26,16 +26,16 @@
is the state diagram for the DXE dispatcher
Depex - Dependency Expresion.
- SOR - Schedule On Request - Don't schedule if this bit is set.
- Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
- This program and the accompanying materials are licensed and made available
- under the terms and conditions of the BSD License which accompanies this
- distribution. The full text of the license may be found at
- http://opensource.org/licenses/bsd-license.php
+ Copyright (c) 2014, Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
@@ -103,7 +103,8 @@ BOOLEAN gRequestDispatch = FALSE;
//
EFI_FV_FILETYPE mSmmFileTypes[] = {
EFI_FV_FILETYPE_SMM,
- EFI_FV_FILETYPE_COMBINED_SMM_DXE
+ EFI_FV_FILETYPE_COMBINED_SMM_DXE,
+ EFI_FV_FILETYPE_SMM_CORE,
//
// Note: DXE core will process the FV image file, so skip it in SMM core
// EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
@@ -121,7 +122,176 @@ FV_FILEPATH_DEVICE_PATH mFvDevicePath;
// DXE Architecture Protocols
//
EFI_SECURITY_ARCH_PROTOCOL *mSecurity = NULL;
+EFI_SECURITY2_ARCH_PROTOCOL *mSecurity2 = NULL;
+//
+// The global variable is defined for Loading modules at fixed address feature to track the SMM code
+// memory range usage. It is a bit mapped array in which every bit indicates the corresponding
+// memory page available or not.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT64 *mSmmCodeMemoryRangeUsageBitMap=NULL;
+
+/**
+ 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
+ memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used.
+ The function is only invoked when load modules at fixed address feature is enabled.
+
+ @param ImageBase The base address the image will be loaded at.
+ @param ImageSize The size of the image
+
+ @retval EFI_SUCCESS The memory range the image will be loaded in is available
+ @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available
+**/
+EFI_STATUS
+CheckAndMarkFixLoadingMemoryUsageBitMap (
+ IN EFI_PHYSICAL_ADDRESS ImageBase,
+ IN UINTN ImageSize
+ )
+{
+ UINT32 SmmCodePageNumber;
+ UINT64 SmmCodeSize;
+ EFI_PHYSICAL_ADDRESS SmmCodeBase;
+ UINTN BaseOffsetPageNumber;
+ UINTN TopOffsetPageNumber;
+ UINTN Index;
+ //
+ // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
+ //
+ SmmCodePageNumber = PcdGet32(PcdLoadFixAddressSmmCodePageNumber);
+ SmmCodeSize = EFI_PAGES_TO_SIZE (SmmCodePageNumber);
+ SmmCodeBase = gLoadModuleAtFixAddressSmramBase;
+
+ //
+ // If the memory usage bit map is not initialized, do it. Every bit in the array
+ // indicate the status of the corresponding memory page, available or not
+ //
+ if (mSmmCodeMemoryRangeUsageBitMap == NULL) {
+ mSmmCodeMemoryRangeUsageBitMap = AllocateZeroPool(((SmmCodePageNumber / 64) + 1)*sizeof(UINT64));
+ }
+ //
+ // If the Dxe code memory range is not allocated or the bit map array allocation failed, return EFI_NOT_FOUND
+ //
+ if (mSmmCodeMemoryRangeUsageBitMap == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // see if the memory range for loading the image is in the SMM code range.
+ //
+ if (SmmCodeBase + SmmCodeSize < ImageBase + ImageSize || SmmCodeBase > ImageBase) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Test if the memory is avalaible or not.
+ //
+ BaseOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase - SmmCodeBase));
+ TopOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - SmmCodeBase));
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
+ if ((mSmmCodeMemoryRangeUsageBitMap[Index / 64] & LShiftU64(1, (Index % 64))) != 0) {
+ //
+ // This page is already used.
+ //
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // Being here means the memory range is available. So mark the bits for the memory range
+ //
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
+ mSmmCodeMemoryRangeUsageBitMap[Index / 64] |= LShiftU64(1, (Index % 64));
+ }
+ return EFI_SUCCESS;
+}
+/**
+ Get the fixed loading address from image header assigned by build tool. This function only be called
+ when Loading module at Fixed address feature enabled.
+
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF
+ image that needs to be examined by this function.
+ @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .
+ @retval EFI_NOT_FOUND The image has no assigned fixed loading address.
+
+**/
+EFI_STATUS
+GetPeCoffImageFixLoadingAssignedAddress(
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ UINTN SectionHeaderOffset;
+ EFI_STATUS Status;
+ EFI_IMAGE_SECTION_HEADER SectionHeader;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ EFI_PHYSICAL_ADDRESS FixLoadingAddress;
+ UINT16 Index;
+ UINTN Size;
+ UINT16 NumberOfSections;
+ UINT64 ValueInSectionHeader;
+
+ FixLoadingAddress = 0;
+ Status = EFI_NOT_FOUND;
+
+ //
+ // Get PeHeader pointer
+ //
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
+ SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +
+ sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER) +
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader;
+ NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
+
+ //
+ // Get base address from the first section header that doesn't point to code section.
+ //
+ for (Index = 0; Index < NumberOfSections; Index++) {
+ //
+ // Read section header from file
+ //
+ Size = sizeof (EFI_IMAGE_SECTION_HEADER);
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ SectionHeaderOffset,
+ &Size,
+ &SectionHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EFI_NOT_FOUND;
+
+ if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
+ //
+ // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header
+ // that doesn't point to code section in image header.So there is an assumption that when the feature is enabled,
+ // if a module with a loading address assigned by tools, the PointerToRelocations & PointerToLineNumbers fields
+ // should not be Zero, or else, these 2 fields should be set to Zero
+ //
+ ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations);
+ if (ValueInSectionHeader != 0) {
+ //
+ // Found first section header that doesn't point to code section in which build tool saves the
+ // offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields
+ //
+ FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressSmramBase + (INT64)ValueInSectionHeader);
+ //
+ // Check if the memory range is available.
+ //
+ Status = CheckAndMarkFixLoadingMemoryUsageBitMap (FixLoadingAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment));
+ if (!EFI_ERROR(Status)) {
+ //
+ // The assigned address is valid. Return the specified loading address
+ //
+ ImageContext->ImageAddress = FixLoadingAddress;
+ }
+ }
+ break;
+ }
+ SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
+ }
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address %x, Status = %r\n", FixLoadingAddress, Status));
+ return Status;
+}
/**
Loads an EFI image into SMRAM.
@@ -151,7 +321,9 @@ SmmLoadImage (
EFI_DEVICE_PATH_PROTOCOL *HandleFilePath;
EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
-
+
+ PERF_LOAD_IMAGE_BEGIN (DriverEntry->ImageHandle);
+
Buffer = NULL;
Size = 0;
Fv = DriverEntry->Fv;
@@ -174,27 +346,19 @@ SmmLoadImage (
}
//
- // If the Security Architectural Protocol has not been located yet, then attempt to locate it
+ // If the Security2 and Security Architectural Protocol has not been located yet, then attempt to locate it
//
+ if (mSecurity2 == NULL) {
+ gBS->LocateProtocol (&gEfiSecurity2ArchProtocolGuid, NULL, (VOID**)&mSecurity2);
+ }
if (mSecurity == NULL) {
gBS->LocateProtocol (&gEfiSecurityArchProtocolGuid, NULL, (VOID**)&mSecurity);
}
-
//
- // Verify the Authentication Status through the Security Architectural Protocol
+ // When Security2 is installed, Security Architectural Protocol must be published.
//
- if ((mSecurity != NULL) && (OriginalFilePath != NULL)) {
- SecurityStatus = mSecurity->FileAuthenticationState (
- mSecurity,
- AuthenticationStatus,
- OriginalFilePath
- );
- if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) {
- Status = SecurityStatus;
- return Status;
- }
- }
-
+ ASSERT (mSecurity2 == NULL || mSecurity != NULL);
+
//
// Pull out just the file portion of the DevicePath for the LoadedImage FilePath
//
@@ -234,14 +398,45 @@ SmmLoadImage (
&AuthenticationStatus
);
}
-
+
if (EFI_ERROR (Status)) {
if (Buffer != NULL) {
- Status = gBS->FreePool (Buffer);
+ gBS->FreePool (Buffer);
}
return Status;
}
+ //
+ // Verify File Authentication through the Security2 Architectural Protocol
+ //
+ if (mSecurity2 != NULL) {
+ SecurityStatus = mSecurity2->FileAuthentication (
+ mSecurity2,
+ OriginalFilePath,
+ Buffer,
+ Size,
+ FALSE
+ );
+ }
+
+ //
+ // Verify the Authentication Status through the Security Architectural Protocol
+ // Only on images that have been read using Firmware Volume protocol.
+ // All SMM images are from FV protocol.
+ //
+ if (!EFI_ERROR (SecurityStatus) && (mSecurity != NULL)) {
+ SecurityStatus = mSecurity->FileAuthenticationState (
+ mSecurity,
+ AuthenticationStatus,
+ OriginalFilePath
+ );
+ }
+
+ if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) {
+ Status = SecurityStatus;
+ return Status;
+ }
+
//
// Initialize ImageContext
//
@@ -254,33 +449,72 @@ SmmLoadImage (
Status = PeCoffLoaderGetImageInfo (&ImageContext);
if (EFI_ERROR (Status)) {
if (Buffer != NULL) {
- Status = gBS->FreePool (Buffer);
+ gBS->FreePool (Buffer);
}
return Status;
}
-
- PageCount = (UINTN)EFI_SIZE_TO_PAGES(ImageContext.ImageSize + ImageContext.SectionAlignment);
- DstBuffer = (UINTN)(-1);
-
- Status = SmmAllocatePages (
- AllocateMaxAddress,
- EfiRuntimeServicesCode,
- PageCount,
- &DstBuffer
- );
- if (EFI_ERROR (Status)) {
- if (Buffer != NULL) {
- Status = gBS->FreePool (Buffer);
+ //
+ // if Loading module at Fixed Address feature is enabled, then cut out a memory range started from TESG BASE
+ // to hold the Smm driver code
+ //
+ if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
+ //
+ // Get the fixed loading address assigned by Build tool
+ //
+ Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Since the memory range to load Smm core alreay been cut out, so no need to allocate and free this range
+ // following statements is to bypass SmmFreePages
+ //
+ PageCount = 0;
+ DstBuffer = (UINTN)gLoadModuleAtFixAddressSmramBase;
+ } else {
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
+ //
+ // allocate the memory to load the SMM driver
+ //
+ PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+ DstBuffer = (UINTN)(-1);
+
+ Status = SmmAllocatePages (
+ AllocateMaxAddress,
+ EfiRuntimeServicesCode,
+ PageCount,
+ &DstBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ if (Buffer != NULL) {
+ gBS->FreePool (Buffer);
+ }
+ return Status;
+ }
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer;
}
- return Status;
+ } else {
+ PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+ DstBuffer = (UINTN)(-1);
+
+ Status = SmmAllocatePages (
+ AllocateMaxAddress,
+ EfiRuntimeServicesCode,
+ PageCount,
+ &DstBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ if (Buffer != NULL) {
+ gBS->FreePool (Buffer);
+ }
+ return Status;
+ }
+
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer;
}
-
- ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer;
//
- // Align buffer on section boundry
+ // Align buffer on section boundary
//
ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
- ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);
+ ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
//
// Load the image to our new buffer
@@ -288,7 +522,7 @@ SmmLoadImage (
Status = PeCoffLoaderLoadImage (&ImageContext);
if (EFI_ERROR (Status)) {
if (Buffer != NULL) {
- Status = gBS->FreePool (Buffer);
+ gBS->FreePool (Buffer);
}
SmmFreePages (DstBuffer, PageCount);
return Status;
@@ -300,7 +534,7 @@ SmmLoadImage (
Status = PeCoffLoaderRelocateImage (&ImageContext);
if (EFI_ERROR (Status)) {
if (Buffer != NULL) {
- Status = gBS->FreePool (Buffer);
+ gBS->FreePool (Buffer);
}
SmmFreePages (DstBuffer, PageCount);
return Status;
@@ -315,7 +549,7 @@ SmmLoadImage (
// Save Image EntryPoint in DriverEntry
//
DriverEntry->ImageEntryPoint = ImageContext.EntryPoint;
- DriverEntry->ImageBuffer = DstBuffer;
+ DriverEntry->ImageBuffer = DstBuffer;
DriverEntry->NumberOfPage = PageCount;
//
@@ -324,12 +558,13 @@ SmmLoadImage (
Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&DriverEntry->LoadedImage);
if (EFI_ERROR (Status)) {
if (Buffer != NULL) {
- Status = gBS->FreePool (Buffer);
+ gBS->FreePool (Buffer);
}
SmmFreePages (DstBuffer, PageCount);
return Status;
}
+ ZeroMem (DriverEntry->LoadedImage, sizeof (EFI_LOADED_IMAGE_PROTOCOL));
//
// Fill in the remaining fields of the Loaded Image Protocol instance.
// Note: ImageBase is an SMRAM address that can not be accessed outside of SMRAM if SMRAM window is closed.
@@ -339,24 +574,48 @@ SmmLoadImage (
DriverEntry->LoadedImage->SystemTable = gST;
DriverEntry->LoadedImage->DeviceHandle = DeviceHandle;
+ DriverEntry->SmmLoadedImage.Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
+ DriverEntry->SmmLoadedImage.ParentHandle = gSmmCorePrivate->SmmIplImageHandle;
+ DriverEntry->SmmLoadedImage.SystemTable = gST;
+ DriverEntry->SmmLoadedImage.DeviceHandle = DeviceHandle;
+
//
// Make an EfiBootServicesData buffer copy of FilePath
//
Status = gBS->AllocatePool (EfiBootServicesData, GetDevicePathSize (FilePath), (VOID **)&DriverEntry->LoadedImage->FilePath);
if (EFI_ERROR (Status)) {
if (Buffer != NULL) {
- Status = gBS->FreePool (Buffer);
+ gBS->FreePool (Buffer);
}
SmmFreePages (DstBuffer, PageCount);
return Status;
}
CopyMem (DriverEntry->LoadedImage->FilePath, FilePath, GetDevicePathSize (FilePath));
- DriverEntry->LoadedImage->ImageBase = (VOID *)(UINTN)DriverEntry->ImageBuffer;
+ DriverEntry->LoadedImage->ImageBase = (VOID *)(UINTN) ImageContext.ImageAddress;
DriverEntry->LoadedImage->ImageSize = ImageContext.ImageSize;
DriverEntry->LoadedImage->ImageCodeType = EfiRuntimeServicesCode;
DriverEntry->LoadedImage->ImageDataType = EfiRuntimeServicesData;
+ //
+ // Make a buffer copy of FilePath
+ //
+ Status = SmmAllocatePool (EfiRuntimeServicesData, GetDevicePathSize(FilePath), (VOID **)&DriverEntry->SmmLoadedImage.FilePath);
+ if (EFI_ERROR (Status)) {
+ if (Buffer != NULL) {
+ gBS->FreePool (Buffer);
+ }
+ gBS->FreePool (DriverEntry->LoadedImage->FilePath);
+ SmmFreePages (DstBuffer, PageCount);
+ return Status;
+ }
+ CopyMem (DriverEntry->SmmLoadedImage.FilePath, FilePath, GetDevicePathSize(FilePath));
+
+ DriverEntry->SmmLoadedImage.ImageBase = (VOID *)(UINTN) ImageContext.ImageAddress;
+ DriverEntry->SmmLoadedImage.ImageSize = ImageContext.ImageSize;
+ DriverEntry->SmmLoadedImage.ImageCodeType = EfiRuntimeServicesCode;
+ DriverEntry->SmmLoadedImage.ImageDataType = EfiRuntimeServicesData;
+
//
// Create a new image handle in the UEFI handle database for the SMM Driver
//
@@ -367,6 +626,19 @@ SmmLoadImage (
NULL
);
+ //
+ // Create a new image handle in the SMM handle database for the SMM Driver
+ //
+ DriverEntry->SmmImageHandle = NULL;
+ Status = SmmInstallProtocolInterface (
+ &DriverEntry->SmmImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &DriverEntry->SmmLoadedImage
+ );
+
+ PERF_LOAD_IMAGE_END (DriverEntry->ImageHandle);
+
//
// Print the load address and the PDB file name if it is available
//
@@ -379,7 +651,7 @@ SmmLoadImage (
DEBUG ((DEBUG_INFO | DEBUG_LOAD,
- "Loading driver at 0x%11p EntryPoint=0x%11p ",
+ "Loading SMM driver at 0x%11p EntryPoint=0x%11p ",
(VOID *)(UINTN) ImageContext.ImageAddress,
FUNCTION_ENTRY_POINT (ImageContext.EntryPoint)));
@@ -426,19 +698,20 @@ SmmLoadImage (
//
// Free buffer allocated by Fv->ReadSection.
//
- // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection
+ // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection
// used the UEFI Boot Services AllocatePool() function
//
Status = gBS->FreePool(Buffer);
- return Status;
+ if (!EFI_ERROR (Status) && EFI_ERROR (SecurityStatus)) {
+ Status = SecurityStatus;
+ }
+ return Status;
}
/**
Preprocess dependency expression and update DriverEntry to reflect the
- state of Before, After, and SOR dependencies. If DriverEntry->Before
- or DriverEntry->After is set it will never be cleared. If SOR is set
- it will be cleared by SmmSchedule(), and then the driver can be
- dispatched.
+ state of Before and After dependencies. If DriverEntry->Before
+ or DriverEntry->After is set it will never be cleared.
@param DriverEntry DriverEntry element to update .
@@ -453,11 +726,7 @@ SmmPreProcessDepex (
UINT8 *Iterator;
Iterator = DriverEntry->Depex;
- if (*Iterator == EFI_DEP_SOR) {
- DriverEntry->Unrequested = TRUE;
- } else {
- DriverEntry->Dependent = TRUE;
- }
+ DriverEntry->Dependent = TRUE;
if (*Iterator == EFI_DEP_BEFORE) {
DriverEntry->Before = TRUE;
@@ -526,8 +795,8 @@ SmmGetDepexSectionAndPreProccess (
}
} else {
//
- // Set Before, After, and Unrequested state information based on Depex
- // Driver will be put in Dependent or Unrequested state
+ // Set Before and After state information based on Depex
+ // Driver will be put in Dependent state
//
SmmPreProcessDepex (DriverEntry);
DriverEntry->DepexProtocolError = FALSE;
@@ -536,61 +805,20 @@ SmmGetDepexSectionAndPreProccess (
return Status;
}
-/**
- Check every driver and locate a matching one. If the driver is found, the Unrequested
- state flag is cleared.
-
- @param FirmwareVolumeHandle The handle of the Firmware Volume that contains
- the firmware file specified by DriverName.
- @param DriverName The Driver name to put in the Dependent state.
-
- @retval EFI_SUCCESS The DriverName was found and it's SOR bit was
- cleared
- @retval EFI_NOT_FOUND The DriverName does not exist or it's SOR bit was
- not set.
-
-**/
-EFI_STATUS
-SmmSchedule (
- IN EFI_HANDLE FirmwareVolumeHandle,
- IN EFI_GUID *DriverName
- )
-{
- LIST_ENTRY *Link;
- EFI_SMM_DRIVER_ENTRY *DriverEntry;
-
- //
- // Check every driver
- //
- for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
- DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
- if (DriverEntry->FvHandle == FirmwareVolumeHandle &&
- DriverEntry->Unrequested &&
- CompareGuid (DriverName, &DriverEntry->FileName)) {
- //
- // Move the driver from the Unrequested to the Dependent state
- //
- DriverEntry->Unrequested = FALSE;
- DriverEntry->Dependent = TRUE;
-
- return EFI_SUCCESS;
- }
- }
- return EFI_NOT_FOUND;
-}
-
/**
This is the main Dispatcher for SMM and it exits when there are no more
drivers to run. Drain the mScheduledQueue and load and start a PE
image for each driver. Search the mDiscoveredList to see if any driver can
be placed on the mScheduledQueue. If no drivers are placed on the
- mScheduledQueue exit the function. On exit it is assumed the Bds()
- will be called, and when the Bds() exits the Dispatcher will be called
- again.
-
+ mScheduledQueue exit the function.
+
+ @retval EFI_SUCCESS All of the SMM Drivers that could be dispatched
+ have been run and the SMM Entry Point has been
+ registered.
+ @retval EFI_NOT_READY The SMM Driver that registered the SMM Entry Point
+ was just dispatched.
+ @retval EFI_NOT_FOUND There are no SMM Drivers available to be dispatched.
@retval EFI_ALREADY_STARTED The SMM Dispatcher is already running
- @retval EFI_NOT_FOUND No SMM Drivers were dispatched
- @retval EFI_SUCCESS One or more SMM Drivers were dispatched
**/
EFI_STATUS
@@ -599,10 +827,10 @@ SmmDispatcher (
)
{
EFI_STATUS Status;
- EFI_STATUS ReturnStatus;
LIST_ENTRY *Link;
EFI_SMM_DRIVER_ENTRY *DriverEntry;
BOOLEAN ReadyToRun;
+ BOOLEAN PreviousSmmEntryPointRegistered;
if (!gRequestDispatch) {
return EFI_NOT_FOUND;
@@ -617,7 +845,6 @@ SmmDispatcher (
gDispatcherRunning = TRUE;
- ReturnStatus = EFI_NOT_FOUND;
do {
//
// Drain the Scheduled Queue
@@ -642,22 +869,11 @@ SmmDispatcher (
// Update the driver state to reflect that it's been loaded
//
if (EFI_ERROR (Status)) {
-
- if (Status == EFI_SECURITY_VIOLATION) {
- //
- // Take driver from Scheduled to Untrused state
- //
- DriverEntry->Untrusted = TRUE;
- } else {
- //
- // The SMM Driver could not be loaded, and do not attempt to load or start it again.
- // Take driver from Scheduled to Initialized.
- //
- // This case include the Never Trusted state if EFI_ACCESS_DENIED is returned
- //
- DriverEntry->Initialized = TRUE;
- }
-
+ //
+ // The SMM Driver could not be loaded, and do not attempt to load or start it again.
+ // Take driver from Scheduled to Initialized.
+ //
+ DriverEntry->Initialized = TRUE;
DriverEntry->Scheduled = FALSE;
RemoveEntryList (&DriverEntry->ScheduledLink);
@@ -679,12 +895,45 @@ SmmDispatcher (
sizeof (DriverEntry->ImageHandle)
);
+ //
+ // Cache state of SmmEntryPointRegistered before calling entry point
+ //
+ PreviousSmmEntryPointRegistered = gSmmCorePrivate->SmmEntryPointRegistered;
+
//
// For each SMM driver, pass NULL as ImageHandle
//
+ RegisterSmramProfileImage (DriverEntry, TRUE);
+ PERF_START_IMAGE_BEGIN (DriverEntry->ImageHandle);
Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, gST);
+ PERF_START_IMAGE_END (DriverEntry->ImageHandle);
if (EFI_ERROR(Status)){
+ UnregisterSmramProfileImage (DriverEntry, TRUE);
SmmFreePages(DriverEntry->ImageBuffer, DriverEntry->NumberOfPage);
+ //
+ // Uninstall LoadedImage
+ //
+ Status = gBS->UninstallProtocolInterface (
+ DriverEntry->ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ DriverEntry->LoadedImage
+ );
+ if (!EFI_ERROR (Status)) {
+ if (DriverEntry->LoadedImage->FilePath != NULL) {
+ gBS->FreePool (DriverEntry->LoadedImage->FilePath);
+ }
+ gBS->FreePool (DriverEntry->LoadedImage);
+ }
+ Status = SmmUninstallProtocolInterface (
+ DriverEntry->SmmImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ &DriverEntry->SmmLoadedImage
+ );
+ if (!EFI_ERROR(Status)) {
+ if (DriverEntry->SmmLoadedImage.FilePath != NULL) {
+ SmmFreePool (DriverEntry->SmmLoadedImage.FilePath);
+ }
+ }
}
REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
@@ -694,7 +943,19 @@ SmmDispatcher (
sizeof (DriverEntry->ImageHandle)
);
- ReturnStatus = EFI_SUCCESS;
+ if (!PreviousSmmEntryPointRegistered && gSmmCorePrivate->SmmEntryPointRegistered) {
+ //
+ // Return immediately if the SMM Entry Point was registered by the SMM
+ // Driver that was just dispatched. The SMM IPL will reinvoke the SMM
+ // Core Dispatcher. This is required so SMM Mode may be enabled as soon
+ // as all the dependent SMM Drivers for SMM Mode have been dispatched.
+ // Once the SMM Entry Point has been registered, then SMM Mode will be
+ // used.
+ //
+ gRequestDispatch = TRUE;
+ gDispatcherRunning = FALSE;
+ return EFI_NOT_READY;
+ }
}
//
@@ -738,7 +999,7 @@ SmmDispatcher (
gDispatcherRunning = FALSE;
- return ReturnStatus;
+ return EFI_SUCCESS;
}
/**
@@ -765,12 +1026,17 @@ SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
//
for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
- if (DriverEntry->Before && DriverEntry->Dependent) {
+ if (DriverEntry->Before && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate SMM DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+ DEBUG ((DEBUG_DISPATCH, " BEFORE FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
//
// Recursively process BEFORE
//
+ DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));
SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
+ } else {
+ DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));
}
}
}
@@ -789,12 +1055,17 @@ SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
//
for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
- if (DriverEntry->After && DriverEntry->Dependent) {
+ if (DriverEntry->After && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate SMM DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+ DEBUG ((DEBUG_DISPATCH, " AFTER FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
//
// Recursively process AFTER
//
+ DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));
SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
+ } else {
+ DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));
}
}
}
@@ -901,7 +1172,7 @@ SmmFvToDevicePath (
/**
Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
and initilize any state variables. Read the Depex from the FV and store it
- in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.
+ in DriverEntry. Pre-process the Depex to set the Before and After state.
The Discovered list is never free'ed and contains booleans that represent the
other possible SMM driver states.
@@ -986,7 +1257,6 @@ SmmDriverDispatchHandler (
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
EFI_STATUS GetNextFileStatus;
- EFI_STATUS SecurityStatus;
EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
EFI_HANDLE FvHandle;
@@ -998,7 +1268,9 @@ SmmDriverDispatchHandler (
EFI_SMM_DRIVER_ENTRY *DriverEntry;
EFI_GUID *AprioriFile;
UINTN AprioriEntryCount;
- UINTN Index;
+ UINTN HandleIndex;
+ UINTN SmmTypeIndex;
+ UINTN AprioriIndex;
LIST_ENTRY *Link;
UINT32 AuthenticationStatus;
UINTN SizeOfBuffer;
@@ -1015,8 +1287,8 @@ SmmDriverDispatchHandler (
return EFI_NOT_FOUND;
}
- for (Index = 0; Index < HandleCount; Index++) {
- FvHandle = HandleBuffer[Index];
+ for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
+ FvHandle = HandleBuffer[HandleIndex];
if (FvHasBeenProcessed (FvHandle)) {
//
@@ -1047,42 +1319,18 @@ SmmDriverDispatchHandler (
continue;
}
- //
- // If the Security Architectural Protocol has not been located yet, then attempt to locate it
- //
- if (mSecurity == NULL) {
- gBS->LocateProtocol (&gEfiSecurityArchProtocolGuid, NULL, (VOID**)&mSecurity);
- }
-
- //
- // Evaluate the authentication status of the Firmware Volume through
- // Security Architectural Protocol
- //
- if (mSecurity != NULL) {
- SecurityStatus = mSecurity->FileAuthenticationState (
- mSecurity,
- 0,
- FvDevicePath
- );
- if (SecurityStatus != EFI_SUCCESS) {
- //
- // Security check failed. The firmware volume should not be used for any purpose.
- //
- continue;
- }
- }
-
//
// Discover Drivers in FV and add them to the Discovered Driver List.
// Process EFI_FV_FILETYPE_SMM type and then EFI_FV_FILETYPE_COMBINED_SMM_DXE
+ // EFI_FV_FILETYPE_SMM_CORE is processed to produce a Loaded Image protocol for the core
//
- for (Index = 0; Index < sizeof (mSmmFileTypes)/sizeof (EFI_FV_FILETYPE); Index++) {
+ for (SmmTypeIndex = 0; SmmTypeIndex < sizeof (mSmmFileTypes)/sizeof (EFI_FV_FILETYPE); SmmTypeIndex++) {
//
// Initialize the search key
//
Key = 0;
do {
- Type = mSmmFileTypes[Index];
+ Type = mSmmFileTypes[SmmTypeIndex];
GetNextFileStatus = Fv->GetNextFile (
Fv,
&Key,
@@ -1092,7 +1340,55 @@ SmmDriverDispatchHandler (
&Size
);
if (!EFI_ERROR (GetNextFileStatus)) {
- SmmAddToDriverList (Fv, FvHandle, &NameGuid);
+ if (Type == EFI_FV_FILETYPE_SMM_CORE) {
+ //
+ // If this is the SMM core fill in it's DevicePath & DeviceHandle
+ //
+ if (mSmmCoreLoadedImage->FilePath == NULL) {
+ //
+ // Maybe one special FV contains only one SMM_CORE module, so its device path must
+ // be initialized completely.
+ //
+ EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);
+ SetDevicePathEndNode (&mFvDevicePath.End);
+
+ //
+ // Make an EfiBootServicesData buffer copy of FilePath
+ //
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath),
+ (VOID **)&mSmmCoreLoadedImage->FilePath
+ );
+ ASSERT_EFI_ERROR (Status);
+ CopyMem (mSmmCoreLoadedImage->FilePath, &mFvDevicePath, GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath));
+
+ mSmmCoreLoadedImage->DeviceHandle = FvHandle;
+ }
+ if (mSmmCoreDriverEntry->SmmLoadedImage.FilePath == NULL) {
+ //
+ // Maybe one special FV contains only one SMM_CORE module, so its device path must
+ // be initialized completely.
+ //
+ EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);
+ SetDevicePathEndNode (&mFvDevicePath.End);
+
+ //
+ // Make a buffer copy FilePath
+ //
+ Status = SmmAllocatePool (
+ EfiRuntimeServicesData,
+ GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath),
+ (VOID **)&mSmmCoreDriverEntry->SmmLoadedImage.FilePath
+ );
+ ASSERT_EFI_ERROR (Status);
+ CopyMem (mSmmCoreDriverEntry->SmmLoadedImage.FilePath, &mFvDevicePath, GetDevicePathSize((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath));
+
+ mSmmCoreDriverEntry->SmmLoadedImage.DeviceHandle = FvHandle;
+ }
+ } else {
+ SmmAddToDriverList (Fv, FvHandle, &NameGuid);
+ }
}
} while (!EFI_ERROR (GetNextFileStatus));
}
@@ -1123,14 +1419,16 @@ SmmDriverDispatchHandler (
// is only valid for the FV that it resided in.
//
- for (Index = 0; Index < AprioriEntryCount; Index++) {
+ for (AprioriIndex = 0; AprioriIndex < AprioriEntryCount; AprioriIndex++) {
for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
- if (CompareGuid (&DriverEntry->FileName, &AprioriFile[Index]) &&
+ if (CompareGuid (&DriverEntry->FileName, &AprioriFile[AprioriIndex]) &&
(FvHandle == DriverEntry->FvHandle)) {
DriverEntry->Dependent = FALSE;
DriverEntry->Scheduled = TRUE;
InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
+ DEBUG ((DEBUG_DISPATCH, "Evaluate SMM DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+ DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (Apriori)\n"));
break;
}
}
@@ -1139,17 +1437,44 @@ SmmDriverDispatchHandler (
//
// Free data allocated by Fv->ReadSection ()
//
- // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection
+ // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection
// used the UEFI Boot Services AllocatePool() function
//
gBS->FreePool (AprioriFile);
}
//
- // Execute the SMM Dispatcher on any newly discovered FVs and previously
+ // Execute the SMM Dispatcher on any newly discovered FVs and previously
// discovered SMM drivers that have been discovered but not dispatched.
//
- return SmmDispatcher ();
+ Status = SmmDispatcher ();
+
+ //
+ // Check to see if CommBuffer and CommBufferSize are valid
+ //
+ if (CommBuffer != NULL && CommBufferSize != NULL) {
+ if (*CommBufferSize > 0) {
+ if (Status == EFI_NOT_READY) {
+ //
+ // If a the SMM Core Entry Point was just registered, then set flag to
+ // request the SMM Dispatcher to be restarted.
+ //
+ *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_RESTART;
+ } else if (!EFI_ERROR (Status)) {
+ //
+ // Set the flag to show that the SMM Dispatcher executed without errors
+ //
+ *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_SUCCESS;
+ } else {
+ //
+ // Set the flag to show that the SMM Dispatcher encountered an error
+ //
+ *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_ERROR;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
}
/**