X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FCore%2FPiSmmCore%2FDispatcher.c;h=1c88c8fb17c57ea2177dac2a565fc4cb867095e9;hp=405f6dea481675725c55f9eef13695f2ae8b1ff7;hb=9d510e61fceee7b92955ef9a3c20343752d8ce3f;hpb=cd5ebaa06dca3e6ef3c464081e6defe00d358c69 diff --git a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c index 405f6dea48..1c88c8fb17 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,10 @@ 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 - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + Copyright (c) 2014, Hewlett-Packard Development Company, L.P. + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -103,7 +97,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,22 +116,23 @@ 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 correspoding -// memory page available or not. +// 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 avaliable, the function will mark the correponding 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 addres the image will be loaded at. + 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 **/ @@ -147,7 +143,7 @@ CheckAndMarkFixLoadingMemoryUsageBitMap ( ) { UINT32 SmmCodePageNumber; - UINT64 SmmCodeSize; + UINT64 SmmCodeSize; EFI_PHYSICAL_ADDRESS SmmCodeBase; UINTN BaseOffsetPageNumber; UINTN TopOffsetPageNumber; @@ -158,11 +154,11 @@ CheckAndMarkFixLoadingMemoryUsageBitMap ( 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 + // 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)); } @@ -176,38 +172,38 @@ CheckAndMarkFixLoadingMemoryUsageBitMap ( // 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; - } + return EFI_NOT_FOUND; + } // // Test if the memory is avalaible or not. - // - BaseOffsetPageNumber = (UINTN)EFI_SIZE_TO_PAGES((UINT32)(ImageBase - SmmCodeBase)); - TopOffsetPageNumber = (UINTN)EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - SmmCodeBase)); + // + 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; + 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; + return EFI_SUCCESS; } /** - Get the fixed loadding address from image header assigned by build tool. This function only be called + 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 loadding address. + @retval EFI_NOT_FOUND The image has no assigned fixed loading address. **/ EFI_STATUS @@ -215,82 +211,80 @@ 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 FixLoaddingAddress; - UINT16 Index; - UINTN Size; - UINT16 NumberOfSections; - UINT64 ValueInSectionHeader; - - FixLoaddingAddress = 0; - Status = EFI_NOT_FOUND; - - // - // Get PeHeader pointer - // - ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )ImageContext->Handle + ImageContext->PeCoffHeaderOffset); - SectionHeaderOffset = (UINTN)( - 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 ( + 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 fileds 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 uild tool saves the - // offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields - // - FixLoaddingAddress = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressSmramBase + (INT64)ValueInSectionHeader); - // - // Check if the memory range is avaliable. - // - Status = CheckAndMarkFixLoadingMemoryUsageBitMap (FixLoaddingAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment)); - if (!EFI_ERROR(Status)) { - // - // The assigned address is valid. Return the specified loadding address - // - ImageContext->ImageAddress = FixLoaddingAddress; - } - } - 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", FixLoaddingAddress, Status)); - return Status; + 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. @@ -321,7 +315,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; @@ -344,27 +340,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 // @@ -404,14 +392,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 // @@ -424,7 +443,7 @@ SmmLoadImage ( Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { if (Buffer != NULL) { - Status = gBS->FreePool (Buffer); + gBS->FreePool (Buffer); } return Status; } @@ -443,15 +462,15 @@ SmmLoadImage ( // following statements is to bypass SmmFreePages // PageCount = 0; - DstBuffer = (UINTN)gLoadModuleAtFixAddressSmramBase; + 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(ImageContext.ImageSize + ImageContext.SectionAlignment); + PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); DstBuffer = (UINTN)(-1); - + Status = SmmAllocatePages ( AllocateMaxAddress, EfiRuntimeServicesCode, @@ -460,16 +479,16 @@ SmmLoadImage ( ); if (EFI_ERROR (Status)) { if (Buffer != NULL) { - Status = gBS->FreePool (Buffer); - } + gBS->FreePool (Buffer); + } return Status; - } + } ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; } } else { - PageCount = (UINTN)EFI_SIZE_TO_PAGES(ImageContext.ImageSize + ImageContext.SectionAlignment); + PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); DstBuffer = (UINTN)(-1); - + Status = SmmAllocatePages ( AllocateMaxAddress, EfiRuntimeServicesCode, @@ -478,18 +497,18 @@ SmmLoadImage ( ); if (EFI_ERROR (Status)) { if (Buffer != NULL) { - Status = gBS->FreePool (Buffer); + gBS->FreePool (Buffer); } return Status; } - + 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 @@ -497,7 +516,7 @@ SmmLoadImage ( Status = PeCoffLoaderLoadImage (&ImageContext); if (EFI_ERROR (Status)) { if (Buffer != NULL) { - Status = gBS->FreePool (Buffer); + gBS->FreePool (Buffer); } SmmFreePages (DstBuffer, PageCount); return Status; @@ -509,7 +528,7 @@ SmmLoadImage ( Status = PeCoffLoaderRelocateImage (&ImageContext); if (EFI_ERROR (Status)) { if (Buffer != NULL) { - Status = gBS->FreePool (Buffer); + gBS->FreePool (Buffer); } SmmFreePages (DstBuffer, PageCount); return Status; @@ -524,7 +543,7 @@ SmmLoadImage ( // Save Image EntryPoint in DriverEntry // DriverEntry->ImageEntryPoint = ImageContext.EntryPoint; - DriverEntry->ImageBuffer = DstBuffer; + DriverEntry->ImageBuffer = DstBuffer; DriverEntry->NumberOfPage = PageCount; // @@ -533,12 +552,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. @@ -548,24 +568,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 // @@ -576,6 +620,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 // @@ -588,7 +645,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))); @@ -635,19 +692,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 . @@ -662,11 +720,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; @@ -735,8 +789,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; @@ -745,61 +799,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 @@ -808,10 +821,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; @@ -826,7 +839,6 @@ SmmDispatcher ( gDispatcherRunning = TRUE; - ReturnStatus = EFI_NOT_FOUND; do { // // Drain the Scheduled Queue @@ -851,22 +863,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); @@ -888,12 +889,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 ( @@ -903,7 +937,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; + } } // @@ -947,7 +993,7 @@ SmmDispatcher ( gDispatcherRunning = FALSE; - return ReturnStatus; + return EFI_SUCCESS; } /** @@ -974,12 +1020,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")); } } } @@ -998,12 +1049,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")); } } } @@ -1110,7 +1166,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. @@ -1195,7 +1251,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; @@ -1207,7 +1262,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; @@ -1224,8 +1281,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)) { // @@ -1256,42 +1313,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, @@ -1301,7 +1334,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)); } @@ -1332,14 +1413,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; } } @@ -1348,17 +1431,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; } /**