drivers to run. Drain the mScheduledQueue and load and start a PE\r
image for each driver. Search the mDiscoveredList to see if any driver can\r
be placed on the mScheduledQueue. If no drivers are placed on the\r
- mScheduledQueue exit the function. On exit it is assumed the Bds()\r
- will be called, and when the Bds() exits the Dispatcher will be called\r
- again.\r
-\r
+ mScheduledQueue exit the function. \r
+\r
+ @retval EFI_SUCCESS All of the SMM Drivers that could be dispatched\r
+ have been run and the SMM Entry Point has been\r
+ registered.\r
+ @retval EFI_NOT_READY The SMM Driver that registered the SMM Entry Point\r
+ was just dispatched.\r
+ @retval EFI_NOT_FOUND There are no SMM Drivers available to be dispatched.\r
@retval EFI_ALREADY_STARTED The SMM Dispatcher is already running\r
- @retval EFI_NOT_FOUND No SMM Drivers were dispatched\r
- @retval EFI_SUCCESS One or more SMM Drivers were dispatched\r
\r
**/\r
EFI_STATUS\r
)\r
{\r
EFI_STATUS Status;\r
- EFI_STATUS ReturnStatus;\r
LIST_ENTRY *Link;\r
EFI_SMM_DRIVER_ENTRY *DriverEntry;\r
BOOLEAN ReadyToRun;\r
+ BOOLEAN PreviousSmmEntryPointRegistered;\r
\r
if (!gRequestDispatch) {\r
return EFI_NOT_FOUND;\r
\r
gDispatcherRunning = TRUE;\r
\r
- ReturnStatus = EFI_NOT_FOUND;\r
do {\r
//\r
// Drain the Scheduled Queue\r
sizeof (DriverEntry->ImageHandle)\r
);\r
\r
+ //\r
+ // Cache state of SmmEntryPointRegistered before calling entry point\r
+ //\r
+ PreviousSmmEntryPointRegistered = gSmmCorePrivate->SmmEntryPointRegistered;\r
+\r
//\r
// For each SMM driver, pass NULL as ImageHandle\r
//\r
sizeof (DriverEntry->ImageHandle)\r
);\r
\r
- ReturnStatus = EFI_SUCCESS;\r
+ if (!PreviousSmmEntryPointRegistered && gSmmCorePrivate->SmmEntryPointRegistered) {\r
+ //\r
+ // Return immediately if the SMM Entry Point was registered by the SMM \r
+ // Driver that was just dispatched. The SMM IPL will reinvoke the SMM\r
+ // Core Dispatcher. This is required so SMM Mode may be enabled as soon \r
+ // as all the dependent SMM Drivers for SMM Mode have been dispatched. \r
+ // Once the SMM Entry Point has been registered, then SMM Mode will be \r
+ // used.\r
+ //\r
+ gRequestDispatch = TRUE;\r
+ gDispatcherRunning = FALSE;\r
+ return EFI_NOT_READY;\r
+ }\r
}\r
\r
//\r
\r
gDispatcherRunning = FALSE;\r
\r
- return ReturnStatus;\r
+ return EFI_SUCCESS;\r
}\r
\r
/**\r
// Execute the SMM Dispatcher on any newly discovered FVs and previously \r
// discovered SMM drivers that have been discovered but not dispatched.\r
//\r
- return SmmDispatcher ();\r
+ Status = SmmDispatcher ();\r
+\r
+ //\r
+ // Check to see if CommBuffer and CommBufferSize are valid\r
+ //\r
+ if (CommBuffer != NULL && CommBufferSize != NULL) {\r
+ if (*CommBufferSize > 0) {\r
+ if (Status == EFI_NOT_READY) {\r
+ //\r
+ // If a the SMM Core Entry Point was just registered, then set flag to \r
+ // request the SMM Dispatcher to be restarted.\r
+ //\r
+ *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_RESTART;\r
+ } else if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Set the flag to show that the SMM Dispatcher executed without errors\r
+ //\r
+ *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_SUCCESS;\r
+ } else {\r
+ //\r
+ // Set the flag to show that the SMM Dispatcher encountered an error\r
+ //\r
+ *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_ERROR;\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
}\r
\r
/**\r
@param Event The Event that is being processed, not used.\r
@param Context Event Context, not used.\r
\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmIplDxeDispatchEventNotify (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ );\r
+\r
+/**\r
+ Event notification that is fired when a GUIDed Event Group is signaled.\r
+\r
+ @param Event The Event that is being processed, not used.\r
+ @param Context Event Context, not used.\r
+\r
**/\r
VOID\r
EFIAPI\r
EFI_GUID *Guid;\r
EFI_EVENT_NOTIFY NotifyFunction;\r
VOID *NotifyContext;\r
+ EFI_TPL NotifyTpl;\r
EFI_EVENT Event;\r
} SMM_IPL_EVENT_NOTIFICATION;\r
\r
// the associated event is immediately signalled, so the notification function will be executed and the \r
// SMM Configuration Protocol will be found if it is already in the handle database.\r
//\r
- { TRUE, FALSE, &gEfiSmmConfigurationProtocolGuid, SmmIplSmmConfigurationEventNotify, &gEfiSmmConfigurationProtocolGuid, NULL },\r
+ { TRUE, FALSE, &gEfiSmmConfigurationProtocolGuid, SmmIplSmmConfigurationEventNotify, &gEfiSmmConfigurationProtocolGuid, TPL_NOTIFY, NULL },\r
//\r
// Declare protocl notification on DxeSmmReadyToLock protocols. When this notification is etablished, \r
// the associated event is immediately signalled, so the notification function will be executed and the \r
// DXE SMM Ready To Lock Protocol will be found if it is already in the handle database.\r
//\r
- { TRUE, TRUE, &gEfiDxeSmmReadyToLockProtocolGuid, SmmIplReadyToLockEventNotify, &gEfiDxeSmmReadyToLockProtocolGuid, NULL },\r
+ { TRUE, TRUE, &gEfiDxeSmmReadyToLockProtocolGuid, SmmIplReadyToLockEventNotify, &gEfiDxeSmmReadyToLockProtocolGuid, TPL_CALLBACK, NULL },\r
//\r
// Declare event notification on the DXE Dispatch Event Group. This event is signaled by the DXE Core\r
// each time the DXE Core dispatcher has completed its work. When this event is signalled, the SMM Core\r
// if notified, so the SMM Core can dispatch SMM drivers.\r
//\r
- { FALSE, TRUE, &gEfiEventDxeDispatchGuid, SmmIplGuidedEventNotify, &gEfiEventDxeDispatchGuid, NULL },\r
+ { FALSE, TRUE, &gEfiEventDxeDispatchGuid, SmmIplDxeDispatchEventNotify, &gEfiEventDxeDispatchGuid, TPL_CALLBACK, NULL },\r
//\r
// Declare event notification on Ready To Boot Event Group. This is an extra event notification that is\r
// used to make sure SMRAM is locked before any boot options are processed.\r
//\r
- { FALSE, TRUE, &gEfiEventReadyToBootGuid, SmmIplReadyToLockEventNotify, &gEfiEventReadyToBootGuid, NULL },\r
+ { FALSE, TRUE, &gEfiEventReadyToBootGuid, SmmIplReadyToLockEventNotify, &gEfiEventReadyToBootGuid, TPL_CALLBACK, NULL },\r
//\r
// Declare event notification on Legacy Boot Event Group. This is used to inform the SMM Core that the platform \r
// is performing a legacy boot operation, and that the UEFI environment is no longer available and the SMM Core \r
// must guarantee that it does not access any UEFI related structures outside of SMRAM.\r
//\r
- { FALSE, FALSE, &gEfiEventLegacyBootGuid, SmmIplGuidedEventNotify, &gEfiEventLegacyBootGuid, NULL },\r
+ { FALSE, FALSE, &gEfiEventLegacyBootGuid, SmmIplGuidedEventNotify, &gEfiEventLegacyBootGuid, TPL_CALLBACK, NULL },\r
//\r
// Declare event notification on SetVirtualAddressMap() Event Group. This is used to convert gSmmCorePrivate \r
// and mSmmControl2 from physical addresses to virtual addresses.\r
//\r
- { FALSE, FALSE, &gEfiEventVirtualAddressChangeGuid, SmmIplSetVirtualAddressNotify, NULL, NULL },\r
+ { FALSE, FALSE, &gEfiEventVirtualAddressChangeGuid, SmmIplSetVirtualAddressNotify, NULL, TPL_CALLBACK, NULL },\r
//\r
// Terminate the table of event notifications\r
//\r
- { FALSE, FALSE, NULL, NULL, NULL, NULL }\r
+ { FALSE, FALSE, NULL, NULL, NULL, TPL_CALLBACK, NULL }\r
};\r
\r
/**\r
}\r
\r
/**\r
- Event notification that is fired when DxeDispatch Event Group is signaled.\r
+ Event notification that is fired when GUIDed Event Group is signaled.\r
\r
@param Event The Event that is being processed, not used.\r
@param Context Event Context, not used.\r
SmmCommunicationCommunicate (&mSmmCommunication, &CommunicateHeader, &Size);\r
}\r
\r
+/**\r
+ Event notification that is fired when DxeDispatch Event Group is signaled.\r
+\r
+ @param Event The Event that is being processed, not used.\r
+ @param Context Event Context, not used.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmIplDxeDispatchEventNotify (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_SMM_COMMUNICATE_HEADER CommunicateHeader;\r
+ UINTN Size;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Keep calling the SMM Core Dispatcher until there is no request to restart it.\r
+ //\r
+ while (TRUE) {\r
+ //\r
+ // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure\r
+ // Clear the buffer passed into the Software SMI. This buffer will return\r
+ // the status of the SMM Core Dispatcher.\r
+ //\r
+ CopyGuid (&CommunicateHeader.HeaderGuid, (EFI_GUID *)Context);\r
+ CommunicateHeader.MessageLength = 1;\r
+ CommunicateHeader.Data[0] = 0;\r
+\r
+ //\r
+ // Generate the Software SMI and return the result\r
+ //\r
+ Size = sizeof (CommunicateHeader);\r
+ SmmCommunicationCommunicate (&mSmmCommunication, &CommunicateHeader, &Size);\r
+ \r
+ //\r
+ // Return if there is no request to restart the SMM Core Dispatcher\r
+ //\r
+ if (CommunicateHeader.Data[0] != COMM_BUFFER_SMM_DISPATCH_RESTART) {\r
+ return;\r
+ }\r
+ \r
+ //\r
+ // Attempt to reset SMRAM cacheability to UC\r
+ // Assume CPU AP is available at this time\r
+ //\r
+ Status = gDS->SetMemorySpaceAttributes(\r
+ mSmramCacheBase, \r
+ mSmramCacheSize,\r
+ EFI_MEMORY_UC\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_WARN, "SMM IPL failed to reset SMRAM window to EFI_MEMORY_UC\n"));\r
+ } \r
+\r
+ //\r
+ // Close all SMRAM ranges to protect SMRAM\r
+ //\r
+ Status = mSmmAccess->Close (mSmmAccess);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Print debug message that the SMRAM window is now closed.\r
+ //\r
+ DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));\r
+\r
+ //\r
+ // Lock the SMRAM (Note: Locking SMRAM may not be supported on all platforms)\r
+ //\r
+ mSmmAccess->Lock (mSmmAccess);\r
+\r
+ //\r
+ // Print debug message that the SMRAM window is now locked\r
+ //\r
+ DEBUG ((DEBUG_INFO, "SMM IPL locked SMRAM window\n"));\r
+ }\r
+}\r
+\r
/**\r
Event notification that is fired every time a gEfiSmmConfigurationProtocol installs.\r
\r
ASSERT_EFI_ERROR (Status);\r
\r
//\r
- // Set flag to indicate that the SM< Entry Point has been registered which \r
+ // Set flag to indicate that the SMM Entry Point has been registered which \r
// means that SMIs are now fully operational.\r
//\r
gSmmCorePrivate->SmmEntryPointRegistered = TRUE;\r
// Print debug message showing SMM Core entry point address.\r
//\r
DEBUG ((DEBUG_INFO, "SMM IPL registered SMM Entry Point address %p\n", (VOID *)(UINTN)gSmmCorePrivate->SmmEntryPoint));\r
-\r
- //\r
- // Attempt to reset SMRAM cacheability to UC\r
- // Assume CPU AP is available at this time\r
- //\r
- Status = gDS->SetMemorySpaceAttributes(\r
- mSmramCacheBase, \r
- mSmramCacheSize,\r
- EFI_MEMORY_UC\r
- );\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((DEBUG_WARN, "SMM IPL failed to reset SMRAM window to EFI_MEMORY_UC\n"));\r
- } \r
-\r
- //\r
- // Close all SMRAM ranges to protect SMRAM\r
- //\r
- Status = mSmmAccess->Close (mSmmAccess);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Print debug message that the SMRAM window is now closed.\r
- //\r
- DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));\r
}\r
\r
/**\r
if (mSmmIplEvents[Index].Protocol) {\r
mSmmIplEvents[Index].Event = EfiCreateProtocolNotifyEvent (\r
mSmmIplEvents[Index].Guid,\r
- TPL_CALLBACK,\r
+ mSmmIplEvents[Index].NotifyTpl,\r
mSmmIplEvents[Index].NotifyFunction,\r
mSmmIplEvents[Index].NotifyContext,\r
&Registration\r
} else {\r
Status = gBS->CreateEventEx (\r
EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
+ mSmmIplEvents[Index].NotifyTpl,\r
mSmmIplEvents[Index].NotifyFunction,\r
mSmmIplEvents[Index].NotifyContext,\r
mSmmIplEvents[Index].Guid,\r