]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c
MdeModulePkg DxeCore/PiSmmCore: Add UEFI memory and SMRAM profile support.
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / PiSmmIpl.c
index 21cd87c31550c32baedc5aae865b715df8bc1ded..21c69ca6ef5bbf8a503b97f8f561abbc9c0d4177 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   SMM IPL that produces SMM related runtime protocols and load the SMM Core into SMRAM\r
 \r
-  Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
   This program and the accompanying materials are licensed and made available \r
   under the terms and conditions of the BSD License which accompanies this \r
   distribution.  The full text of the license may be found at        \r
@@ -140,6 +140,20 @@ SmmIplReadyToLockEventNotify (
   @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
@@ -175,6 +189,7 @@ typedef struct {
   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
@@ -240,39 +255,45 @@ SMM_IPL_EVENT_NOTIFICATION  mSmmIplEvents[] = {
   // 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 EndOfDxe event.  When this notification is etablished, \r
+  // the associated event is immediately signalled, so the notification function will be executed and the \r
+  // SMM End Of Dxe Protocol will be found if it is already in the handle database.\r
+  //\r
+  { FALSE, FALSE,  &gEfiEndOfDxeEventGroupGuid,        SmmIplGuidedEventNotify,           &gEfiEndOfDxeEventGroupGuid,        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
@@ -454,9 +475,9 @@ SmmCommunicationCommunicate (
   }\r
 \r
   //\r
-  // Don't allow call SmiManage() directly when SMRAM is closed or locked.\r
+  // If we are not in SMM, don't allow call SmiManage() directly when SMRAM is closed or locked.\r
   //\r
-  if (!mSmmAccess->OpenState || mSmmAccess->LockState) {\r
+  if ((!gSmmCorePrivate->InSmm) && (!mSmmAccess->OpenState || mSmmAccess->LockState)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
  \r
@@ -489,11 +510,11 @@ SmmCommunicationCommunicate (
   //\r
   gSmmCorePrivate->InSmm = OldInSmm;\r
 \r
-  return (Status == EFI_WARN_INTERRUPT_SOURCE_QUIESCED) ? EFI_SUCCESS : EFI_NOT_FOUND;\r
+  return (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_NOT_FOUND;\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
@@ -523,6 +544,76 @@ SmmIplGuidedEventNotify (
   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
+\r
 /**\r
   Event notification that is fired every time a gEfiSmmConfigurationProtocol installs.\r
 \r
@@ -555,7 +646,7 @@ SmmIplSmmConfigurationEventNotify (
   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
@@ -564,30 +655,6 @@ SmmIplSmmConfigurationEventNotify (
   // 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
@@ -637,7 +704,7 @@ SmmIplReadyToLockEventNotify (
   // Lock the SMRAM (Note: Locking SMRAM may not be supported on all platforms)\r
   //\r
   mSmmAccess->Lock (mSmmAccess);\r
-\r
+  \r
   //\r
   // Close protocol and event notification events that do not apply after the \r
   // DXE SMM Ready To Lock Protocol has been installed or the Ready To Boot \r
@@ -852,7 +919,7 @@ ExecuteSmmCoreFromSmram (
       // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR \r
       // specified by SmramRange\r
       //\r
-      PageCount = (UINTN)EFI_SIZE_TO_PAGES(ImageContext.ImageSize + ImageContext.SectionAlignment);\r
+      PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);\r
 \r
       ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);\r
       ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));\r
@@ -870,7 +937,7 @@ ExecuteSmmCoreFromSmram (
     // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR \r
     // specified by SmramRange\r
     //\r
-    PageCount = (UINTN)EFI_SIZE_TO_PAGES(ImageContext.ImageSize + ImageContext.SectionAlignment);\r
+    PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);\r
 \r
     ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);\r
     ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));\r
@@ -885,7 +952,7 @@ ExecuteSmmCoreFromSmram (
   }\r
   \r
   ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;\r
-  ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);\r
+  ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1));\r
 \r
   //\r
   // Print debug message showing SMM Core load address.\r
@@ -912,6 +979,13 @@ ExecuteSmmCoreFromSmram (
       //\r
       DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint));\r
 \r
+      gSmmCorePrivate->PiSmmCoreImageBase = ImageContext.ImageAddress;\r
+      gSmmCorePrivate->PiSmmCoreImageSize = ImageContext.ImageSize;\r
+      DEBUG ((DEBUG_INFO, "PiSmmCoreImageBase - 0x%016lx\n", gSmmCorePrivate->PiSmmCoreImageBase));\r
+      DEBUG ((DEBUG_INFO, "PiSmmCoreImageSize - 0x%016lx\n", gSmmCorePrivate->PiSmmCoreImageSize));\r
+\r
+      gSmmCorePrivate->PiSmmCoreEntryPoint = ImageContext.EntryPoint;\r
+\r
       //\r
       // Execute image\r
       //\r
@@ -1009,6 +1083,14 @@ SmmIplEntry (
 \r
   gSmmCorePrivate->SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);\r
 \r
+  //\r
+  // Save a full copy\r
+  //\r
+  gSmmCorePrivate->FullSmramRangeCount = gSmmCorePrivate->SmramRangeCount;\r
+  gSmmCorePrivate->FullSmramRanges = (EFI_SMRAM_DESCRIPTOR *) AllocatePool (Size);\r
+  ASSERT (gSmmCorePrivate->FullSmramRanges != NULL);\r
+  CopyMem (gSmmCorePrivate->FullSmramRanges, gSmmCorePrivate->SmramRanges, Size);\r
+\r
   //\r
   // Open all SMRAM ranges\r
   //\r
@@ -1045,6 +1127,13 @@ SmmIplEntry (
   //\r
   mCurrentSmramRange = NULL;\r
   for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < gSmmCorePrivate->SmramRangeCount; Index++) {\r
+    //\r
+    // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization\r
+    //\r
+    if ((gSmmCorePrivate->SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {\r
+      continue;\r
+    }\r
+\r
     if (gSmmCorePrivate->SmramRanges[Index].CpuStart >= BASE_1MB) {\r
       if ((gSmmCorePrivate->SmramRanges[Index].CpuStart + gSmmCorePrivate->SmramRanges[Index].PhysicalSize) <= BASE_4GB) {\r
         if (gSmmCorePrivate->SmramRanges[Index].PhysicalSize >= MaxSize) {\r
@@ -1183,7 +1272,7 @@ SmmIplEntry (
     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
@@ -1191,7 +1280,7 @@ SmmIplEntry (
     } 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