From 5657b268e71cd78ddbdfd2be7774289bfab03ea6 Mon Sep 17 00:00:00 2001 From: mdkinney Date: Wed, 24 Aug 2011 06:49:21 +0000 Subject: [PATCH] Update SMM Core to use SMM Mode as soon as SMM Mode is available Signed-off-by: mdkinney Reviewed-by: rsun3 git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12190 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Core/PiSmmCore/Dispatcher.c | 67 +++++++-- .../Core/PiSmmCore/PiSmmCorePrivateData.h | 18 ++- MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c | 141 +++++++++++++----- 3 files changed, 179 insertions(+), 47 deletions(-) diff --git a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c index 78c29ffe22..53eedbbf61 100644 --- a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c +++ b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c @@ -743,13 +743,15 @@ SmmGetDepexSectionAndPreProccess ( 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 @@ -758,10 +760,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; @@ -776,7 +778,6 @@ SmmDispatcher ( gDispatcherRunning = TRUE; - ReturnStatus = EFI_NOT_FOUND; do { // // Drain the Scheduled Queue @@ -827,6 +828,11 @@ SmmDispatcher ( sizeof (DriverEntry->ImageHandle) ); + // + // Cache state of SmmEntryPointRegistered before calling entry point + // + PreviousSmmEntryPointRegistered = gSmmCorePrivate->SmmEntryPointRegistered; + // // For each SMM driver, pass NULL as ImageHandle // @@ -842,7 +848,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; + } } // @@ -886,7 +904,7 @@ SmmDispatcher ( gDispatcherRunning = FALSE; - return ReturnStatus; + return EFI_SUCCESS; } /** @@ -1309,7 +1327,34 @@ SmmDriverDispatchHandler ( // 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; } /** diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h b/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h index bfacfbb6bd..411ebd823f 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h @@ -2,7 +2,7 @@ The internal header file that declared a data structure that is shared between the SMM IPL and the SMM Core. - Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2011, 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 @@ -16,6 +16,22 @@ #ifndef _PI_SMM_CORE_PRIVATE_DATA_H_ #define _PI_SMM_CORE_PRIVATE_DATA_H_ +/// +/// Define values for the communications buffer used when gEfiEventDxeDispatchGuid is +/// event signaled. This event is signaled by the DXE Core each time the DXE Core +/// dispatcher has completed its work. When this event is signaled, the SMM Core +/// if notified, so the SMM Core can dispatch SMM drivers. If COMM_BUFFER_SMM_DISPATCH_ERROR +/// is returned in the communication buffer, then an error occurred dispatching SMM +/// Drivers. If COMM_BUFFER_SMM_DISPATCH_SUCCESS is returned, then the SMM Core +/// dispatched all the drivers it could. If COMM_BUFFER_SMM_DISPATCH_RESTART is +/// returned, then the SMM Core just dispatched the SMM Driver that registered +/// the SMM Entry Point enabling the use of SMM Mode. In this case, the SMM Core +/// should be notified again to dispatch more SMM Drivers using SMM Mode. +/// +#define COMM_BUFFER_SMM_DISPATCH_ERROR 0x00 +#define COMM_BUFFER_SMM_DISPATCH_SUCCESS 0x01 +#define COMM_BUFFER_SMM_DISPATCH_RESTART 0x02 + /// /// Signature for the private structure shared between the SMM IPL and the SMM Core /// diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c index 0cfd746a07..fa6f2f1eb9 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c @@ -140,6 +140,20 @@ SmmIplReadyToLockEventNotify ( @param Event The Event that is being processed, not used. @param Context Event Context, not used. +**/ +VOID +EFIAPI +SmmIplDxeDispatchEventNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Event notification that is fired when a GUIDed Event Group is signaled. + + @param Event The Event that is being processed, not used. + @param Context Event Context, not used. + **/ VOID EFIAPI @@ -175,6 +189,7 @@ typedef struct { EFI_GUID *Guid; EFI_EVENT_NOTIFY NotifyFunction; VOID *NotifyContext; + EFI_TPL NotifyTpl; EFI_EVENT Event; } SMM_IPL_EVENT_NOTIFICATION; @@ -240,39 +255,39 @@ SMM_IPL_EVENT_NOTIFICATION mSmmIplEvents[] = { // the associated event is immediately signalled, so the notification function will be executed and the // SMM Configuration Protocol will be found if it is already in the handle database. // - { TRUE, FALSE, &gEfiSmmConfigurationProtocolGuid, SmmIplSmmConfigurationEventNotify, &gEfiSmmConfigurationProtocolGuid, NULL }, + { TRUE, FALSE, &gEfiSmmConfigurationProtocolGuid, SmmIplSmmConfigurationEventNotify, &gEfiSmmConfigurationProtocolGuid, TPL_NOTIFY, NULL }, // // Declare protocl notification on DxeSmmReadyToLock protocols. When this notification is etablished, // the associated event is immediately signalled, so the notification function will be executed and the // DXE SMM Ready To Lock Protocol will be found if it is already in the handle database. // - { TRUE, TRUE, &gEfiDxeSmmReadyToLockProtocolGuid, SmmIplReadyToLockEventNotify, &gEfiDxeSmmReadyToLockProtocolGuid, NULL }, + { TRUE, TRUE, &gEfiDxeSmmReadyToLockProtocolGuid, SmmIplReadyToLockEventNotify, &gEfiDxeSmmReadyToLockProtocolGuid, TPL_CALLBACK, NULL }, // // Declare event notification on the DXE Dispatch Event Group. This event is signaled by the DXE Core // each time the DXE Core dispatcher has completed its work. When this event is signalled, the SMM Core // if notified, so the SMM Core can dispatch SMM drivers. // - { FALSE, TRUE, &gEfiEventDxeDispatchGuid, SmmIplGuidedEventNotify, &gEfiEventDxeDispatchGuid, NULL }, + { FALSE, TRUE, &gEfiEventDxeDispatchGuid, SmmIplDxeDispatchEventNotify, &gEfiEventDxeDispatchGuid, TPL_CALLBACK, NULL }, // // Declare event notification on Ready To Boot Event Group. This is an extra event notification that is // used to make sure SMRAM is locked before any boot options are processed. // - { FALSE, TRUE, &gEfiEventReadyToBootGuid, SmmIplReadyToLockEventNotify, &gEfiEventReadyToBootGuid, NULL }, + { FALSE, TRUE, &gEfiEventReadyToBootGuid, SmmIplReadyToLockEventNotify, &gEfiEventReadyToBootGuid, TPL_CALLBACK, NULL }, // // Declare event notification on Legacy Boot Event Group. This is used to inform the SMM Core that the platform // is performing a legacy boot operation, and that the UEFI environment is no longer available and the SMM Core // must guarantee that it does not access any UEFI related structures outside of SMRAM. // - { FALSE, FALSE, &gEfiEventLegacyBootGuid, SmmIplGuidedEventNotify, &gEfiEventLegacyBootGuid, NULL }, + { FALSE, FALSE, &gEfiEventLegacyBootGuid, SmmIplGuidedEventNotify, &gEfiEventLegacyBootGuid, TPL_CALLBACK, NULL }, // // Declare event notification on SetVirtualAddressMap() Event Group. This is used to convert gSmmCorePrivate // and mSmmControl2 from physical addresses to virtual addresses. // - { FALSE, FALSE, &gEfiEventVirtualAddressChangeGuid, SmmIplSetVirtualAddressNotify, NULL, NULL }, + { FALSE, FALSE, &gEfiEventVirtualAddressChangeGuid, SmmIplSetVirtualAddressNotify, NULL, TPL_CALLBACK, NULL }, // // Terminate the table of event notifications // - { FALSE, FALSE, NULL, NULL, NULL, NULL } + { FALSE, FALSE, NULL, NULL, NULL, TPL_CALLBACK, NULL } }; /** @@ -493,7 +508,7 @@ SmmCommunicationCommunicate ( } /** - Event notification that is fired when DxeDispatch Event Group is signaled. + Event notification that is fired when GUIDed Event Group is signaled. @param Event The Event that is being processed, not used. @param Context Event Context, not used. @@ -523,6 +538,86 @@ SmmIplGuidedEventNotify ( SmmCommunicationCommunicate (&mSmmCommunication, &CommunicateHeader, &Size); } +/** + Event notification that is fired when DxeDispatch Event Group is signaled. + + @param Event The Event that is being processed, not used. + @param Context Event Context, not used. + +**/ +VOID +EFIAPI +SmmIplDxeDispatchEventNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_SMM_COMMUNICATE_HEADER CommunicateHeader; + UINTN Size; + EFI_STATUS Status; + + // + // Keep calling the SMM Core Dispatcher until there is no request to restart it. + // + while (TRUE) { + // + // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure + // Clear the buffer passed into the Software SMI. This buffer will return + // the status of the SMM Core Dispatcher. + // + CopyGuid (&CommunicateHeader.HeaderGuid, (EFI_GUID *)Context); + CommunicateHeader.MessageLength = 1; + CommunicateHeader.Data[0] = 0; + + // + // Generate the Software SMI and return the result + // + Size = sizeof (CommunicateHeader); + SmmCommunicationCommunicate (&mSmmCommunication, &CommunicateHeader, &Size); + + // + // Return if there is no request to restart the SMM Core Dispatcher + // + if (CommunicateHeader.Data[0] != COMM_BUFFER_SMM_DISPATCH_RESTART) { + return; + } + + // + // Attempt to reset SMRAM cacheability to UC + // Assume CPU AP is available at this time + // + Status = gDS->SetMemorySpaceAttributes( + mSmramCacheBase, + mSmramCacheSize, + EFI_MEMORY_UC + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "SMM IPL failed to reset SMRAM window to EFI_MEMORY_UC\n")); + } + + // + // Close all SMRAM ranges to protect SMRAM + // + Status = mSmmAccess->Close (mSmmAccess); + ASSERT_EFI_ERROR (Status); + + // + // Print debug message that the SMRAM window is now closed. + // + DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n")); + + // + // Lock the SMRAM (Note: Locking SMRAM may not be supported on all platforms) + // + mSmmAccess->Lock (mSmmAccess); + + // + // Print debug message that the SMRAM window is now locked + // + DEBUG ((DEBUG_INFO, "SMM IPL locked SMRAM window\n")); + } +} + /** Event notification that is fired every time a gEfiSmmConfigurationProtocol installs. @@ -555,7 +650,7 @@ SmmIplSmmConfigurationEventNotify ( ASSERT_EFI_ERROR (Status); // - // Set flag to indicate that the SM< Entry Point has been registered which + // Set flag to indicate that the SMM Entry Point has been registered which // means that SMIs are now fully operational. // gSmmCorePrivate->SmmEntryPointRegistered = TRUE; @@ -564,30 +659,6 @@ SmmIplSmmConfigurationEventNotify ( // Print debug message showing SMM Core entry point address. // DEBUG ((DEBUG_INFO, "SMM IPL registered SMM Entry Point address %p\n", (VOID *)(UINTN)gSmmCorePrivate->SmmEntryPoint)); - - // - // Attempt to reset SMRAM cacheability to UC - // Assume CPU AP is available at this time - // - Status = gDS->SetMemorySpaceAttributes( - mSmramCacheBase, - mSmramCacheSize, - EFI_MEMORY_UC - ); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_WARN, "SMM IPL failed to reset SMRAM window to EFI_MEMORY_UC\n")); - } - - // - // Close all SMRAM ranges to protect SMRAM - // - Status = mSmmAccess->Close (mSmmAccess); - ASSERT_EFI_ERROR (Status); - - // - // Print debug message that the SMRAM window is now closed. - // - DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n")); } /** @@ -1190,7 +1261,7 @@ SmmIplEntry ( if (mSmmIplEvents[Index].Protocol) { mSmmIplEvents[Index].Event = EfiCreateProtocolNotifyEvent ( mSmmIplEvents[Index].Guid, - TPL_CALLBACK, + mSmmIplEvents[Index].NotifyTpl, mSmmIplEvents[Index].NotifyFunction, mSmmIplEvents[Index].NotifyContext, &Registration @@ -1198,7 +1269,7 @@ SmmIplEntry ( } else { Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, - TPL_CALLBACK, + mSmmIplEvents[Index].NotifyTpl, mSmmIplEvents[Index].NotifyFunction, mSmmIplEvents[Index].NotifyContext, mSmmIplEvents[Index].Guid, -- 2.39.2