/** Frees one or more 4KB pages that were previously allocated with one of the aligned page allocation functions in the Memory Allocation Library. Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer must have been allocated on a previous call to the aligned page allocation services of the Memory Allocation Library. If it is not possible to free allocated pages, then this function will perform no actions. If Buffer was not allocated with an aligned page allocation function in the Memory Allocation Library, then ASSERT(). If Pages is zero, then ASSERT(). @param Buffer Pointer to the buffer of pages to free. @param Pages The number of 4 KB pages to free. **/ VOID EFIAPI FreeAlignedPages ( IN VOID *Buffer, IN UINTN Pages ) { EFI_STATUS Status; ASSERT (Pages != 0); if (BufferInSmram (Buffer)) { // // When Buffer is in SMRAM range, it should be allocated by SmmAllocatePages() service. // So, SmmFreePages() service is used to free it. // Status = SmmFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages); } else { // // When Buffer is out of SMRAM range, it should be allocated by gBS->AllocatePages() service. // So, gBS->FreePages() service is used to free it. // Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages); } ASSERT_EFI_ERROR (Status); }
/** Add free SMRAM region for use by memory service. @param MemBase Base address of memory region. @param MemLength Length of the memory region. @param Type Memory type. @param Attributes Memory region state. **/ VOID SmmAddMemoryRegion ( IN EFI_PHYSICAL_ADDRESS MemBase, IN UINT64 MemLength, IN EFI_MEMORY_TYPE Type, IN UINT64 Attributes ) { UINTN AlignedMemBase; // // Do not add memory regions that is already allocated, needs testing, or needs ECC initialization // if ((Attributes & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) { return; } // // Align range on an EFI_PAGE_SIZE boundary // AlignedMemBase = (UINTN)(MemBase + EFI_PAGE_MASK) & ~EFI_PAGE_MASK; MemLength -= AlignedMemBase - MemBase; SmmFreePages (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength)); }
/** Allocates one or more 4KB pages of a certain memory type at a specified alignment. Allocates the number of 4KB pages specified by Pages of a certain memory type with an alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is returned. If there is not enough memory at the specified alignment remaining to satisfy the request, then NULL is returned. If Alignment is not a power of two and Alignment is not zero, then ASSERT(). If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). @param MemoryType The type of memory to allocate. @param Pages The number of 4 KB pages to allocate. @param Alignment The requested alignment of the allocation. Must be a power of two. If Alignment is zero, then byte alignment is used. @return A pointer to the allocated buffer or NULL if allocation fails. **/ VOID * InternalAllocateAlignedPages ( IN EFI_MEMORY_TYPE MemoryType, IN UINTN Pages, IN UINTN Alignment ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS Memory; UINTN AlignedMemory; UINTN AlignmentMask; UINTN UnalignedPages; UINTN RealPages; // // Alignment must be a power of two or zero. // ASSERT ((Alignment & (Alignment - 1)) == 0); if (Pages == 0) { return NULL; } if (Alignment > EFI_PAGE_SIZE) { // // Caculate the total number of pages since alignment is larger than page size. // AlignmentMask = Alignment - 1; RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment); // // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow. // ASSERT (RealPages > Pages); Status = SmmAllocatePages (AllocateAnyPages, MemoryType, RealPages, &Memory); if (EFI_ERROR (Status)) { return NULL; } AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask; UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory); if (UnalignedPages > 0) { // // Free first unaligned page(s). // Status = SmmFreePages (Memory, UnalignedPages); ASSERT_EFI_ERROR (Status); } Memory = (EFI_PHYSICAL_ADDRESS) (AlignedMemory + EFI_PAGES_TO_SIZE (Pages)); UnalignedPages = RealPages - Pages - UnalignedPages; if (UnalignedPages > 0) { // // Free last unaligned page(s). // Status = SmmFreePages (Memory, UnalignedPages); ASSERT_EFI_ERROR (Status); } } else { // // Do not over-allocate pages in this case. // Status = SmmAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory); if (EFI_ERROR (Status)) { return NULL; } AlignedMemory = (UINTN) Memory; } return (VOID *) AlignedMemory; }
/** 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. @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 **/ EFI_STATUS SmmDispatcher ( VOID ) { EFI_STATUS Status; LIST_ENTRY *Link; EFI_SMM_DRIVER_ENTRY *DriverEntry; BOOLEAN ReadyToRun; BOOLEAN PreviousSmmEntryPointRegistered; if (!gRequestDispatch) { return EFI_NOT_FOUND; } if (gDispatcherRunning) { // // If the dispatcher is running don't let it be restarted. // return EFI_ALREADY_STARTED; } gDispatcherRunning = TRUE; do { // // Drain the Scheduled Queue // while (!IsListEmpty (&mScheduledQueue)) { DriverEntry = CR ( mScheduledQueue.ForwardLink, EFI_SMM_DRIVER_ENTRY, ScheduledLink, EFI_SMM_DRIVER_ENTRY_SIGNATURE ); // // Load the SMM Driver image into memory. If the Driver was transitioned from // Untrused to Scheduled it would have already been loaded so we may need to // skip the LoadImage // if (DriverEntry->ImageHandle == NULL) { Status = SmmLoadImage (DriverEntry); // // Update the driver state to reflect that it's been loaded // if (EFI_ERROR (Status)) { // // 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); // // If it's an error don't try the StartImage // continue; } } DriverEntry->Scheduled = FALSE; DriverEntry->Initialized = TRUE; RemoveEntryList (&DriverEntry->ScheduledLink); REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( EFI_PROGRESS_CODE, EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_BEGIN, &DriverEntry->ImageHandle, sizeof (DriverEntry->ImageHandle) ); // // Cache state of SmmEntryPointRegistered before calling entry point // PreviousSmmEntryPointRegistered = gSmmCorePrivate->SmmEntryPointRegistered; // // For each SMM driver, pass NULL as ImageHandle // Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, gST); if (EFI_ERROR(Status)){ SmmFreePages(DriverEntry->ImageBuffer, DriverEntry->NumberOfPage); } REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( EFI_PROGRESS_CODE, EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_END, &DriverEntry->ImageHandle, sizeof (DriverEntry->ImageHandle) ); 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; } } // // Search DriverList for items to place on Scheduled Queue // ReadyToRun = FALSE; for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE); if (DriverEntry->DepexProtocolError){ // // If Section Extraction Protocol did not let the Depex be read before retry the read // Status = SmmGetDepexSectionAndPreProccess (DriverEntry); } if (DriverEntry->Dependent) { if (SmmIsSchedulable (DriverEntry)) { SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry); ReadyToRun = TRUE; } } } } while (ReadyToRun); // // If there is no more SMM driver to dispatch, stop the dispatch request // gRequestDispatch = FALSE; for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE); if (!DriverEntry->Initialized){ // // We have SMM driver pending to dispatch // gRequestDispatch = TRUE; break; } } gDispatcherRunning = FALSE; return EFI_SUCCESS; }
/** Loads an EFI image into SMRAM. @param DriverEntry EFI_SMM_DRIVER_ENTRY instance @return EFI_STATUS **/ EFI_STATUS EFIAPI SmmLoadImage ( IN OUT EFI_SMM_DRIVER_ENTRY *DriverEntry ) { UINT32 AuthenticationStatus; UINTN FilePathSize; VOID *Buffer; UINTN Size; UINTN PageCount; EFI_GUID *NameGuid; EFI_STATUS Status; EFI_STATUS SecurityStatus; EFI_HANDLE DeviceHandle; EFI_PHYSICAL_ADDRESS DstBuffer; EFI_DEVICE_PATH_PROTOCOL *FilePath; EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath; EFI_DEVICE_PATH_PROTOCOL *HandleFilePath; EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; Buffer = NULL; Size = 0; Fv = DriverEntry->Fv; NameGuid = &DriverEntry->FileName; FilePath = DriverEntry->FvFileDevicePath; OriginalFilePath = FilePath; HandleFilePath = FilePath; DeviceHandle = NULL; SecurityStatus = EFI_SUCCESS; Status = EFI_SUCCESS; AuthenticationStatus = 0; // // Try to get the image device handle by checking the match protocol. // Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle); if (EFI_ERROR(Status)) { return Status; } // // If the Security Architectural Protocol has not been located yet, then attempt to locate it // if (mSecurity == NULL) { gBS->LocateProtocol (&gEfiSecurityArchProtocolGuid, NULL, (VOID**)&mSecurity); } // // Verify the Authentication Status through the Security Architectural Protocol // if ((mSecurity != NULL) && (OriginalFilePath != NULL)) { SecurityStatus = mSecurity->FileAuthenticationState ( mSecurity, AuthenticationStatus, OriginalFilePath ); if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) { Status = SecurityStatus; return Status; } } // // Pull out just the file portion of the DevicePath for the LoadedImage FilePath // FilePath = OriginalFilePath; Status = gBS->HandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath); if (!EFI_ERROR (Status)) { FilePathSize = GetDevicePathSize (HandleFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL); FilePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *)FilePath) + FilePathSize ); } // // Try reading PE32 section firstly // Status = Fv->ReadSection ( Fv, NameGuid, EFI_SECTION_PE32, 0, &Buffer, &Size, &AuthenticationStatus ); if (EFI_ERROR (Status)) { // // Try reading TE section secondly // Buffer = NULL; Size = 0; Status = Fv->ReadSection ( Fv, NameGuid, EFI_SECTION_TE, 0, &Buffer, &Size, &AuthenticationStatus ); } if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } return Status; } // // Initialize ImageContext // ImageContext.Handle = Buffer; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } return Status; } // // 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) { Status = gBS->FreePool (Buffer); } return Status; } ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; } } 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) { Status = gBS->FreePool (Buffer); } return Status; } ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; } // // Align buffer on section boundry // ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1); // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } SmmFreePages (DstBuffer, PageCount); return Status; } // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } SmmFreePages (DstBuffer, PageCount); return Status; } // // Flush the instruction cache so the image data are written before we execute it // InvalidateInstructionCacheRange ((VOID *)(UINTN) ImageContext.ImageAddress, (UINTN) ImageContext.ImageSize); // // Save Image EntryPoint in DriverEntry // DriverEntry->ImageEntryPoint = ImageContext.EntryPoint; DriverEntry->ImageBuffer = DstBuffer; DriverEntry->NumberOfPage = PageCount; // // Allocate a Loaded Image Protocol in EfiBootServicesData // Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&DriverEntry->LoadedImage); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } SmmFreePages (DstBuffer, PageCount); return Status; } // // 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. // DriverEntry->LoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; DriverEntry->LoadedImage->ParentHandle = gSmmCorePrivate->SmmIplImageHandle; DriverEntry->LoadedImage->SystemTable = gST; DriverEntry->LoadedImage->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); } SmmFreePages (DstBuffer, PageCount); return Status; } CopyMem (DriverEntry->LoadedImage->FilePath, FilePath, GetDevicePathSize (FilePath)); DriverEntry->LoadedImage->ImageBase = (VOID *)(UINTN)DriverEntry->ImageBuffer; DriverEntry->LoadedImage->ImageSize = ImageContext.ImageSize; DriverEntry->LoadedImage->ImageCodeType = EfiRuntimeServicesCode; DriverEntry->LoadedImage->ImageDataType = EfiRuntimeServicesData; // // Create a new image handle in the UEFI handle database for the SMM Driver // DriverEntry->ImageHandle = NULL; Status = gBS->InstallMultipleProtocolInterfaces ( &DriverEntry->ImageHandle, &gEfiLoadedImageProtocolGuid, DriverEntry->LoadedImage, NULL ); // // Print the load address and the PDB file name if it is available // DEBUG_CODE_BEGIN (); UINTN Index; UINTN StartIndex; CHAR8 EfiFileName[256]; DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading SMM driver at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN) ImageContext.ImageAddress, FUNCTION_ENTRY_POINT (ImageContext.EntryPoint))); // // Print Module Name by Pdb file path. // Windows and Unix style file path are all trimmed correctly. // if (ImageContext.PdbPointer != NULL) { StartIndex = 0; for (Index = 0; ImageContext.PdbPointer[Index] != 0; Index++) { if ((ImageContext.PdbPointer[Index] == '\\') || (ImageContext.PdbPointer[Index] == '/')) { StartIndex = Index + 1; } } // // Copy the PDB file name to our temporary string, and replace .pdb with .efi // The PDB file name is limited in the range of 0~255. // If the length is bigger than 255, trim the redudant characters to avoid overflow in array boundary. // for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) { EfiFileName[Index] = ImageContext.PdbPointer[Index + StartIndex]; if (EfiFileName[Index] == 0) { EfiFileName[Index] = '.'; } if (EfiFileName[Index] == '.') { EfiFileName[Index + 1] = 'e'; EfiFileName[Index + 2] = 'f'; EfiFileName[Index + 3] = 'i'; EfiFileName[Index + 4] = 0; break; } } if (Index == sizeof (EfiFileName) - 4) { EfiFileName[Index] = 0; } DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex])); } DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n")); DEBUG_CODE_END (); // // Free buffer allocated by 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; }
/** 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. @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 SmmDispatcher ( VOID ) { EFI_STATUS Status; EFI_STATUS ReturnStatus; LIST_ENTRY *Link; EFI_SMM_DRIVER_ENTRY *DriverEntry; BOOLEAN ReadyToRun; if (!gRequestDispatch) { return EFI_NOT_FOUND; } if (gDispatcherRunning) { // // If the dispatcher is running don't let it be restarted. // return EFI_ALREADY_STARTED; } gDispatcherRunning = TRUE; ReturnStatus = EFI_NOT_FOUND; do { // // Drain the Scheduled Queue // while (!IsListEmpty (&mScheduledQueue)) { DriverEntry = CR ( mScheduledQueue.ForwardLink, EFI_SMM_DRIVER_ENTRY, ScheduledLink, EFI_SMM_DRIVER_ENTRY_SIGNATURE ); // // Load the SMM Driver image into memory. If the Driver was transitioned from // Untrused to Scheduled it would have already been loaded so we may need to // skip the LoadImage // if (DriverEntry->ImageHandle == NULL) { Status = SmmLoadImage (DriverEntry); // // 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; } DriverEntry->Scheduled = FALSE; RemoveEntryList (&DriverEntry->ScheduledLink); // // If it's an error don't try the StartImage // continue; } } DriverEntry->Scheduled = FALSE; DriverEntry->Initialized = TRUE; RemoveEntryList (&DriverEntry->ScheduledLink); REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( EFI_PROGRESS_CODE, EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_BEGIN, &DriverEntry->ImageHandle, sizeof (DriverEntry->ImageHandle) ); // // For each SMM driver, pass NULL as ImageHandle // Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, gST); if (EFI_ERROR(Status)){ SmmFreePages(DriverEntry->ImageBuffer, DriverEntry->NumberOfPage); } REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( EFI_PROGRESS_CODE, EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_END, &DriverEntry->ImageHandle, sizeof (DriverEntry->ImageHandle) ); ReturnStatus = EFI_SUCCESS; } // // Search DriverList for items to place on Scheduled Queue // ReadyToRun = FALSE; for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE); if (DriverEntry->DepexProtocolError){ // // If Section Extraction Protocol did not let the Depex be read before retry the read // Status = SmmGetDepexSectionAndPreProccess (DriverEntry); } if (DriverEntry->Dependent) { if (SmmIsSchedulable (DriverEntry)) { SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry); ReadyToRun = TRUE; } } } } while (ReadyToRun); // // If there is no more SMM driver to dispatch, stop the dispatch request // gRequestDispatch = FALSE; for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE); if (!DriverEntry->Initialized){ // // We have SMM driver pending to dispatch // gRequestDispatch = TRUE; break; } } gDispatcherRunning = FALSE; return ReturnStatus; }