/** @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
- 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
- http://opensource.org/licenses/bsd-license.php \r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
\r
#include <Protocol/SmmBase2.h>\r
#include <Protocol/SmmCommunication.h>\r
+#include <Protocol/MmCommunication2.h>\r
#include <Protocol/SmmAccess2.h>\r
#include <Protocol/SmmConfiguration.h>\r
#include <Protocol/SmmControl2.h>\r
#include <Protocol/DxeSmmReadyToLock.h>\r
-#include <Protocol/FirmwareVolume2.h>\r
+#include <Protocol/Cpu.h>\r
\r
#include <Guid/EventGroup.h>\r
#include <Guid/EventLegacyBios.h>\r
+#include <Guid/LoadModuleAtFixedAddress.h>\r
\r
#include <Library/BaseLib.h>\r
#include <Library/BaseMemoryLib.h>\r
#include <Library/DebugLib.h>\r
#include <Library/UefiBootServicesTableLib.h>\r
#include <Library/DxeServicesTableLib.h>\r
+#include <Library/DxeServicesLib.h>\r
#include <Library/UefiLib.h>\r
#include <Library/UefiRuntimeLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/ReportStatusCodeLib.h>\r
\r
#include "PiSmmCorePrivateData.h"\r
\r
+#define SMRAM_CAPABILITIES (EFI_MEMORY_WB | EFI_MEMORY_UC)\r
+\r
//\r
// Function prototypes from produced protocols\r
//\r
\r
/**\r
Communicates with a registered handler.\r
- \r
- This function provides a service to send and receive messages from a registered \r
- UEFI service. This function is part of the SMM Communication Protocol that may \r
- be called in physical mode prior to SetVirtualAddressMap() and in virtual mode \r
+\r
+ This function provides a service to send and receive messages from a registered\r
+ UEFI service. This function is part of the SMM Communication Protocol that may\r
+ be called in physical mode prior to SetVirtualAddressMap() and in virtual mode\r
after SetVirtualAddressMap().\r
\r
- @param[in] This The EFI_SMM_COMMUNICATION_PROTOCOL instance.\r
- @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM.\r
- @param[in, out] CommSize The size of the data buffer being passed in.On exit, the size of data\r
- being returned. Zero if the handler does not wish to reply with any data.\r
+ @param[in] This The EFI_SMM_COMMUNICATION_PROTOCOL instance.\r
+ @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM.\r
+ @param[in, out] CommSize The size of the data buffer being passed in. On exit, the size of data\r
+ being returned. Zero if the handler does not wish to reply with any data.\r
+ This parameter is optional and may be NULL.\r
+\r
+ @retval EFI_SUCCESS The message was successfully posted.\r
+ @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.\r
+ @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation.\r
+ If this error is returned, the MessageLength field\r
+ in the CommBuffer header or the integer pointed by\r
+ CommSize, are updated to reflect the maximum payload\r
+ size the implementation can accommodate.\r
+ @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter,\r
+ if not omitted, are in address range that cannot be\r
+ accessed by the MM environment.\r
\r
- @retval EFI_SUCCESS The message was successfully posted.\r
- @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.\r
**/\r
EFI_STATUS\r
EFIAPI\r
SmmCommunicationCommunicate (\r
IN CONST EFI_SMM_COMMUNICATION_PROTOCOL *This,\r
IN OUT VOID *CommBuffer,\r
- IN OUT UINTN *CommSize\r
+ IN OUT UINTN *CommSize OPTIONAL\r
+ );\r
+\r
+/**\r
+ Communicates with a registered handler.\r
+\r
+ This function provides a service to send and receive messages from a registered UEFI service.\r
+\r
+ @param[in] This The EFI_MM_COMMUNICATION_PROTOCOL instance.\r
+ @param[in] CommBufferPhysical Physical address of the MM communication buffer\r
+ @param[in] CommBufferVirtual Virtual address of the MM communication buffer\r
+ @param[in] CommSize The size of the data buffer being passed in. On exit, the size of data\r
+ being returned. Zero if the handler does not wish to reply with any data.\r
+ This parameter is optional and may be NULL.\r
+\r
+ @retval EFI_SUCCESS The message was successfully posted.\r
+ @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.\r
+ @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation.\r
+ If this error is returned, the MessageLength field\r
+ in the CommBuffer header or the integer pointed by\r
+ CommSize, are updated to reflect the maximum payload\r
+ size the implementation can accommodate.\r
+ @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter,\r
+ if not omitted, are in address range that cannot be\r
+ accessed by the MM environment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmCommunicationMmCommunicate2 (\r
+ IN CONST EFI_MM_COMMUNICATION2_PROTOCOL *This,\r
+ IN OUT VOID *CommBufferPhysical,\r
+ IN OUT VOID *CommBufferVirtual,\r
+ IN OUT UINTN *CommSize OPTIONAL\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
IN VOID *Context\r
);\r
\r
+/**\r
+ Event notification that is fired when EndOfDxe 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
+SmmIplEndOfDxeEventNotify (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ );\r
+\r
/**\r
Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
\r
);\r
\r
//\r
-// Data structure used to declare a table of protocol notifications and event \r
+// Data structure used to declare a table of protocol notifications and event\r
// notifications required by the SMM IPL\r
//\r
typedef struct {\r
- BOOLEAN Protocol;\r
- BOOLEAN CloseOnLock;\r
- EFI_GUID *Guid;\r
- EFI_EVENT_NOTIFY NotifyFunction;\r
- VOID *NotifyContext;\r
- EFI_EVENT Event;\r
+ BOOLEAN Protocol;\r
+ BOOLEAN CloseOnLock;\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
//\r
SmmCommunicationCommunicate\r
};\r
\r
+//\r
+// PI 1.7 MM Communication Protocol 2 instance\r
+//\r
+EFI_MM_COMMUNICATION2_PROTOCOL mMmCommunication2 = {\r
+ SmmCommunicationMmCommunicate2\r
+};\r
+\r
//\r
// SMM Core Private Data structure that contains the data shared between\r
// the SMM IPL and the SMM Core.\r
FALSE, // SmmEntryPointRegistered\r
FALSE, // InSmm\r
NULL, // Smst\r
- 0, // BufferSize\r
NULL, // CommunicationBuffer\r
+ 0, // BufferSize\r
EFI_SUCCESS // ReturnStatus\r
};\r
\r
EFI_SMM_ACCESS2_PROTOCOL *mSmmAccess;\r
EFI_SMRAM_DESCRIPTOR *mCurrentSmramRange;\r
BOOLEAN mSmmLocked = FALSE;\r
+BOOLEAN mEndOfDxe = FALSE;\r
+EFI_PHYSICAL_ADDRESS mSmramCacheBase;\r
+UINT64 mSmramCacheSize;\r
+\r
+EFI_SMM_COMMUNICATE_HEADER mCommunicateHeader;\r
+EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE *mLMFAConfigurationTable = NULL;\r
\r
//\r
// Table of Protocol notification and GUIDed Event notifications that the SMM IPL requires\r
//\r
SMM_IPL_EVENT_NOTIFICATION mSmmIplEvents[] = {\r
//\r
- // Declare protocol notification on the SMM Configuration protocol. When this notification is etablished, \r
- // the associated event is immediately signalled, so the notification function will be executed and the \r
+ // Declare protocol notification on the SMM Configuration protocol. When this notification is established,\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
+ // Declare protocol notification on DxeSmmReadyToLock protocols. When this notification is established,\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 established,\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, TRUE, &gEfiEndOfDxeEventGroupGuid, SmmIplGuidedEventNotify, &gEfiEndOfDxeEventGroupGuid, TPL_CALLBACK, NULL },\r
+ //\r
+ // Declare event notification on EndOfDxe event. This is used to set EndOfDxe event signaled flag.\r
+ //\r
+ { FALSE, TRUE, &gEfiEndOfDxeEventGroupGuid, SmmIplEndOfDxeEventNotify, &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
+ // 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
+ // It is also to inform the SMM Core to notify SMM driver that system enter legacy boot.\r
+ //\r
+ { FALSE, FALSE, &gEfiEventLegacyBootGuid, SmmIplGuidedEventNotify, &gEfiEventLegacyBootGuid, TPL_CALLBACK, NULL },\r
+ //\r
+ // Declare event notification on Exit Boot Services Event Group. This is used to inform the SMM Core\r
+ // to notify SMM driver that system enter exit boot services.\r
+ //\r
+ { FALSE, FALSE, &gEfiEventExitBootServicesGuid, SmmIplGuidedEventNotify, &gEfiEventExitBootServicesGuid, TPL_CALLBACK, NULL },\r
//\r
- { FALSE, FALSE, &gEfiEventLegacyBootGuid, SmmIplGuidedEventNotify, &gEfiEventLegacyBootGuid, NULL },\r
+ // Declare event notification on Ready To Boot Event Group. This is used to inform the SMM Core\r
+ // to notify SMM driver that system enter ready to boot.\r
//\r
- // Declare event notification on SetVirtualAddressMap() Event Group. This is used to convert gSmmCorePrivate \r
+ { FALSE, FALSE, &gEfiEventReadyToBootGuid, SmmIplGuidedEventNotify, &gEfiEventReadyToBootGuid, 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
+ Find the maximum SMRAM cache range that covers the range specified by SmramRange.\r
+\r
+ This function searches and joins all adjacent ranges of SmramRange into a range to be cached.\r
+\r
+ @param SmramRange The SMRAM range to search from.\r
+ @param SmramCacheBase The returned cache range base.\r
+ @param SmramCacheSize The returned cache range size.\r
+\r
+**/\r
+VOID\r
+GetSmramCacheRange (\r
+ IN EFI_SMRAM_DESCRIPTOR *SmramRange,\r
+ OUT EFI_PHYSICAL_ADDRESS *SmramCacheBase,\r
+ OUT UINT64 *SmramCacheSize\r
+ )\r
+{\r
+ UINTN Index;\r
+ EFI_PHYSICAL_ADDRESS RangeCpuStart;\r
+ UINT64 RangePhysicalSize;\r
+ BOOLEAN FoundAjacentRange;\r
+\r
+ *SmramCacheBase = SmramRange->CpuStart;\r
+ *SmramCacheSize = SmramRange->PhysicalSize;\r
+\r
+ do {\r
+ FoundAjacentRange = FALSE;\r
+ for (Index = 0; Index < gSmmCorePrivate->SmramRangeCount; Index++) {\r
+ RangeCpuStart = gSmmCorePrivate->SmramRanges[Index].CpuStart;\r
+ RangePhysicalSize = gSmmCorePrivate->SmramRanges[Index].PhysicalSize;\r
+ if ((RangeCpuStart < *SmramCacheBase) && (*SmramCacheBase == (RangeCpuStart + RangePhysicalSize))) {\r
+ *SmramCacheBase = RangeCpuStart;\r
+ *SmramCacheSize += RangePhysicalSize;\r
+ FoundAjacentRange = TRUE;\r
+ } else if (((*SmramCacheBase + *SmramCacheSize) == RangeCpuStart) && (RangePhysicalSize > 0)) {\r
+ *SmramCacheSize += RangePhysicalSize;\r
+ FoundAjacentRange = TRUE;\r
+ }\r
+ }\r
+ } while (FoundAjacentRange);\r
+}\r
+\r
/**\r
Indicate whether the driver is currently executing in the SMM Initialization phase.\r
\r
OUT EFI_SMM_SYSTEM_TABLE2 **Smst\r
)\r
{\r
- if ((This == NULL) ||(Smst == NULL)) {\r
+ if ((This == NULL) || (Smst == NULL)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
- \r
+\r
if (!gSmmCorePrivate->InSmm) {\r
return EFI_UNSUPPORTED;\r
}\r
- \r
+\r
*Smst = gSmmCorePrivate->Smst;\r
\r
return EFI_SUCCESS;\r
\r
/**\r
Communicates with a registered handler.\r
- \r
- This function provides a service to send and receive messages from a registered \r
- UEFI service. This function is part of the SMM Communication Protocol that may \r
- be called in physical mode prior to SetVirtualAddressMap() and in virtual mode \r
+\r
+ This function provides a service to send and receive messages from a registered\r
+ UEFI service. This function is part of the SMM Communication Protocol that may\r
+ be called in physical mode prior to SetVirtualAddressMap() and in virtual mode\r
after SetVirtualAddressMap().\r
\r
@param[in] This The EFI_SMM_COMMUNICATION_PROTOCOL instance.\r
- @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM.\r
- @param[in, out] CommSize The size of the data buffer being passed in.On exit, the size of data\r
+ @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM.\r
+ @param[in, out] CommSize The size of the data buffer being passed in. On exit, the size of data\r
being returned. Zero if the handler does not wish to reply with any data.\r
+ This parameter is optional and may be NULL.\r
\r
@retval EFI_SUCCESS The message was successfully posted.\r
@retval EFI_INVALID_PARAMETER The CommBuffer was NULL.\r
+ @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation.\r
+ If this error is returned, the MessageLength field\r
+ in the CommBuffer header or the integer pointed by\r
+ CommSize, are updated to reflect the maximum payload\r
+ size the implementation can accommodate.\r
+ @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter,\r
+ if not omitted, are in address range that cannot be\r
+ accessed by the MM environment.\r
+\r
**/\r
EFI_STATUS\r
EFIAPI\r
SmmCommunicationCommunicate (\r
IN CONST EFI_SMM_COMMUNICATION_PROTOCOL *This,\r
IN OUT VOID *CommBuffer,\r
- IN OUT UINTN *CommSize\r
+ IN OUT UINTN *CommSize OPTIONAL\r
)\r
{\r
EFI_STATUS Status;\r
EFI_SMM_COMMUNICATE_HEADER *CommunicateHeader;\r
BOOLEAN OldInSmm;\r
+ UINTN TempCommSize;\r
\r
//\r
// Check parameters\r
//\r
- if ((CommBuffer == NULL) || (CommSize == NULL)) {\r
+ if (CommBuffer == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)CommBuffer;\r
+\r
+ if (CommSize == NULL) {\r
+ TempCommSize = OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + CommunicateHeader->MessageLength;\r
+ } else {\r
+ TempCommSize = *CommSize;\r
+ //\r
+ // CommSize must hold HeaderGuid and MessageLength\r
+ //\r
+ if (TempCommSize < OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
//\r
// If not already in SMM, then generate a Software SMI\r
//\r
// Put arguments for Software SMI in gSmmCorePrivate\r
//\r
gSmmCorePrivate->CommunicationBuffer = CommBuffer;\r
- gSmmCorePrivate->BufferSize = CommSize;\r
+ gSmmCorePrivate->BufferSize = TempCommSize;\r
\r
//\r
// Generate Software SMI\r
}\r
\r
//\r
- // Return status from software SMI \r
+ // Return status from software SMI\r
//\r
+ if (CommSize != NULL) {\r
+ *CommSize = gSmmCorePrivate->BufferSize;\r
+ }\r
+\r
return gSmmCorePrivate->ReturnStatus;\r
}\r
\r
//\r
// If we are in SMM, then the execution mode must be physical, which means that\r
// OS established virtual addresses can not be used. If SetVirtualAddressMap()\r
- // has been called, then a direct invocation of the Software SMI is not \r
- // not allowed so return EFI_INVALID_PARAMETER.\r
+ // has been called, then a direct invocation of the Software SMI is not allowed,\r
+ // so return EFI_INVALID_PARAMETER.\r
//\r
- if (EfiGoneVirtual()) {\r
+ if (EfiGoneVirtual ()) {\r
return EFI_INVALID_PARAMETER;\r
}\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
+\r
//\r
// Save current InSmm state and set InSmm state to TRUE\r
//\r
- OldInSmm = gSmmCorePrivate->InSmm;\r
+ OldInSmm = gSmmCorePrivate->InSmm;\r
gSmmCorePrivate->InSmm = TRUE;\r
\r
//\r
- // Already in SMM and before SetVirtualAddressMap(), so call SmiManage() directly.\r
- //\r
- CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)CommBuffer;\r
- *CommSize -= OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);\r
- Status = gSmmCorePrivate->Smst->SmiManage (\r
- &CommunicateHeader->HeaderGuid, \r
- NULL, \r
- CommunicateHeader->Data, \r
- CommSize\r
- );\r
-\r
- //\r
- // Update CommunicationBuffer, BufferSize and ReturnStatus\r
- // Communicate service finished, reset the pointer to CommBuffer to NULL\r
+ // Before SetVirtualAddressMap(), we are in SMM or SMRAM is open and unlocked, call SmiManage() directly.\r
//\r
- *CommSize += OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);\r
+ TempCommSize -= OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);\r
+ Status = gSmmCorePrivate->Smst->SmiManage (\r
+ &CommunicateHeader->HeaderGuid,\r
+ NULL,\r
+ CommunicateHeader->Data,\r
+ &TempCommSize\r
+ );\r
+ TempCommSize += OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);\r
+ if (CommSize != NULL) {\r
+ *CommSize = TempCommSize;\r
+ }\r
\r
//\r
// Restore original InSmm state\r
//\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
+ Communicates with a registered handler.\r
+\r
+ This function provides a service to send and receive messages from a registered UEFI service.\r
+\r
+ @param[in] This The EFI_MM_COMMUNICATION_PROTOCOL instance.\r
+ @param[in] CommBufferPhysical Physical address of the MM communication buffer\r
+ @param[in] CommBufferVirtual Virtual address of the MM communication buffer\r
+ @param[in] CommSize The size of the data buffer being passed in. On exit, the size of data\r
+ being returned. Zero if the handler does not wish to reply with any data.\r
+ This parameter is optional and may be NULL.\r
+\r
+ @retval EFI_SUCCESS The message was successfully posted.\r
+ @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.\r
+ @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation.\r
+ If this error is returned, the MessageLength field\r
+ in the CommBuffer header or the integer pointed by\r
+ CommSize, are updated to reflect the maximum payload\r
+ size the implementation can accommodate.\r
+ @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter,\r
+ if not omitted, are in address range that cannot be\r
+ accessed by the MM environment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmCommunicationMmCommunicate2 (\r
+ IN CONST EFI_MM_COMMUNICATION2_PROTOCOL *This,\r
+ IN OUT VOID *CommBufferPhysical,\r
+ IN OUT VOID *CommBufferVirtual,\r
+ IN OUT UINTN *CommSize OPTIONAL\r
+ )\r
+{\r
+ return SmmCommunicationCommunicate (\r
+ &mSmmCommunication,\r
+ CommBufferPhysical,\r
+ CommSize\r
+ );\r
+}\r
+\r
+/**\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
IN VOID *Context\r
)\r
{\r
- EFI_SMM_COMMUNICATE_HEADER CommunicateHeader;\r
- UINTN Size;\r
+ UINTN Size;\r
\r
//\r
- // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure \r
+ // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure\r
//\r
- CopyGuid (&CommunicateHeader.HeaderGuid, (EFI_GUID *)Context);\r
- CommunicateHeader.MessageLength = 1;\r
- CommunicateHeader.Data[0] = 0;\r
+ CopyGuid (&mCommunicateHeader.HeaderGuid, (EFI_GUID *)Context);\r
+ mCommunicateHeader.MessageLength = 1;\r
+ mCommunicateHeader.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
+ Size = sizeof (mCommunicateHeader);\r
+ SmmCommunicationCommunicate (&mSmmCommunication, &mCommunicateHeader, &Size);\r
+}\r
+\r
+/**\r
+ Event notification that is fired when EndOfDxe 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
+SmmIplEndOfDxeEventNotify (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ mEndOfDxe = TRUE;\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
+ 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 (&mCommunicateHeader.HeaderGuid, (EFI_GUID *)Context);\r
+ mCommunicateHeader.MessageLength = 1;\r
+ mCommunicateHeader.Data[0] = 0;\r
+\r
+ //\r
+ // Generate the Software SMI and return the result\r
+ //\r
+ Size = sizeof (mCommunicateHeader);\r
+ SmmCommunicationCommunicate (&mSmmCommunication, &mCommunicateHeader, &Size);\r
+\r
+ //\r
+ // Return if there is no request to restart the SMM Core Dispatcher\r
+ //\r
+ if (mCommunicateHeader.Data[0] != COMM_BUFFER_SMM_DISPATCH_RESTART) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Close all SMRAM ranges to protect SMRAM\r
+ // NOTE: SMRR is enabled by CPU SMM driver by calling SmmCpuFeaturesInitializeProcessor() from SmmCpuFeaturesLib\r
+ // so no need to reset the SMRAM to UC in MTRR.\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
}\r
\r
//\r
- // Register the SMM Entry Point provided by the SMM Core with the SMM COnfiguration protocol\r
+ // Register the SMM Entry Point provided by the SMM Core with the SMM Configuration protocol\r
//\r
Status = SmmConfiguration->RegisterSmmEntry (SmmConfiguration, gSmmCorePrivate->SmmEntryPoint);\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
- //\r
- Status = gDS->SetMemorySpaceAttributes(\r
- mCurrentSmramRange->CpuStart, \r
- mCurrentSmramRange->PhysicalSize,\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
Event notification that is fired every time a DxeSmmReadyToLock protocol is added\r
- or if gEfiEventReadyToBootGuid is signalled.\r
+ or if gEfiEventReadyToBootGuid is signaled.\r
\r
@param Event The Event that is being processed, not used.\r
@param Context Event Context, not used.\r
if (mSmmLocked) {\r
return;\r
}\r
- \r
+\r
//\r
// Make sure this notification is for this handler\r
//\r
}\r
} else {\r
//\r
- // If SMM is not locked yet and we got here from gEfiEventReadyToBootGuid being \r
- // signalled, then gEfiDxeSmmReadyToLockProtocolGuid was not installed as expected.\r
+ // If SMM is not locked yet and we got here from gEfiEventReadyToBootGuid being\r
+ // signaled, then gEfiDxeSmmReadyToLockProtocolGuid was not installed as expected.\r
// Print a warning on debug builds.\r
//\r
DEBUG ((DEBUG_WARN, "SMM IPL! DXE SMM Ready To Lock Protocol not installed before Ready To Boot signal\n"));\r
}\r
\r
+ if (!mEndOfDxe) {\r
+ DEBUG ((DEBUG_ERROR, "EndOfDxe Event must be signaled before DxeSmmReadyToLock Protocol installation!\n"));\r
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED,\r
+ (EFI_SOFTWARE_SMM_DRIVER | EFI_SW_EC_ILLEGAL_SOFTWARE_STATE)\r
+ );\r
+ ASSERT (FALSE);\r
+ }\r
+\r
//\r
// Lock the SMRAM (Note: Locking SMRAM may not be supported on all platforms)\r
//\r
mSmmAccess->Lock (mSmmAccess);\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
+ // 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
// event has been signalled.\r
//\r
for (Index = 0; mSmmIplEvents[Index].NotifyFunction != NULL; Index++) {\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
// Set flag so this operation will not be performed again\r
//\r
}\r
\r
/**\r
- Searches all Firmware Volumes for the first file matching FileType and SectionType and returns the section data.\r
-\r
- @param FileType FileType to search for within any of the firmware volumes in the platform.\r
- @param SectionType SectionType to search for within any of the matching FileTypes in the firmware volumes in the platform.\r
- @param SourceSize Return the size of the returned section data..\r
-\r
- @retval != NULL Pointer to the allocated buffer containing the section data.\r
- @retval NULL Section data was not found.\r
+ Get the fixed loading address from image header assigned by build tool. This function only be called\r
+ when Loading module at Fixed address feature enabled.\r
\r
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF\r
+ image that needs to be examined by this function.\r
+ @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .\r
+ @retval EFI_NOT_FOUND The image has no assigned fixed loading address.\r
**/\r
-VOID *\r
-GetSectionInAnyFv (\r
- IN EFI_FV_FILETYPE FileType,\r
- IN EFI_SECTION_TYPE SectionType,\r
- OUT UINTN *SourceSize\r
+EFI_STATUS\r
+GetPeCoffImageFixLoadingAssignedAddress (\r
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
)\r
{\r
- EFI_STATUS Status;\r
- UINTN HandleCount;\r
- EFI_HANDLE *HandleBuffer;\r
- UINTN Index;\r
- EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
- UINTN Key;\r
- EFI_GUID NameGuid;\r
- EFI_FV_FILE_ATTRIBUTES Attributes;\r
- VOID *SourceBuffer;\r
- UINT32 AuthenticationStatus;\r
-\r
- HandleBuffer = NULL;\r
- Status = gBS->LocateHandleBuffer (\r
- ByProtocol,\r
- &gEfiFirmwareVolume2ProtocolGuid,\r
- NULL,\r
- &HandleCount,\r
- &HandleBuffer\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return NULL;\r
- }\r
+ UINTN SectionHeaderOffset;\r
+ EFI_STATUS Status;\r
+ EFI_IMAGE_SECTION_HEADER SectionHeader;\r
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;\r
+ EFI_PHYSICAL_ADDRESS FixLoadingAddress;\r
+ UINT16 Index;\r
+ UINTN Size;\r
+ UINT16 NumberOfSections;\r
+ EFI_PHYSICAL_ADDRESS SmramBase;\r
+ UINT64 SmmCodeSize;\r
+ UINT64 ValueInSectionHeader;\r
\r
- for (Index = 0; Index < HandleCount; Index++) {\r
- Status = gBS->HandleProtocol (\r
- HandleBuffer[Index],\r
- &gEfiFirmwareVolume2ProtocolGuid,\r
- (VOID **)&Fv\r
- );\r
- if (EFI_ERROR (Status)) {\r
- continue;\r
- }\r
+ //\r
+ // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber\r
+ //\r
+ SmmCodeSize = EFI_PAGES_TO_SIZE (PcdGet32 (PcdLoadFixAddressSmmCodePageNumber));\r
+\r
+ FixLoadingAddress = 0;\r
+ Status = EFI_NOT_FOUND;\r
+ SmramBase = mLMFAConfigurationTable->SmramBase;\r
+ //\r
+ // Get PeHeader pointer\r
+ //\r
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8 *)ImageContext->Handle + ImageContext->PeCoffHeaderOffset);\r
+ SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +\r
+ sizeof (UINT32) +\r
+ sizeof (EFI_IMAGE_FILE_HEADER) +\r
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader;\r
+ NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;\r
\r
+ //\r
+ // Get base address from the first section header that doesn't point to code section.\r
+ //\r
+ for (Index = 0; Index < NumberOfSections; Index++) {\r
//\r
- // Use Firmware Volume 2 Protocol to search for a file of type FileType\r
+ // Read section header from file\r
//\r
- Key = 0; \r
- Status = Fv->GetNextFile (Fv, &Key, &FileType, &NameGuid, &Attributes, SourceSize);\r
+ Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
+ Status = ImageContext->ImageRead (\r
+ ImageContext->Handle,\r
+ SectionHeaderOffset,\r
+ &Size,\r
+ &SectionHeader\r
+ );\r
if (EFI_ERROR (Status)) {\r
- continue;\r
+ return Status;\r
}\r
\r
- //\r
- // Use Firmware Volume 2 Protocol to read a section of type SectionType\r
- //\r
- SourceBuffer = NULL;\r
- Status = Fv->ReadSection (Fv, &NameGuid, SectionType, 0, &SourceBuffer, SourceSize, &AuthenticationStatus);\r
- if (!EFI_ERROR (Status)) {\r
- FreePool (HandleBuffer);\r
- return SourceBuffer;\r
+ Status = EFI_NOT_FOUND;\r
+\r
+ if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {\r
+ //\r
+ // Build tool saves the offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields in the\r
+ // first section header that doesn't point to code section in image header. And there is an assumption that when the\r
+ // feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations & PointerToLineNumbers\r
+ // fields should NOT be Zero, or else, these 2 fields should be set to Zero\r
+ //\r
+ ValueInSectionHeader = ReadUnaligned64 ((UINT64 *)&SectionHeader.PointerToRelocations);\r
+ if (ValueInSectionHeader != 0) {\r
+ //\r
+ // Found first section header that doesn't point to code section in which build tool saves the\r
+ // offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields\r
+ //\r
+ FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(SmramBase + (INT64)ValueInSectionHeader);\r
+\r
+ if ((SmramBase + SmmCodeSize > FixLoadingAddress) && (SmramBase <= FixLoadingAddress)) {\r
+ //\r
+ // The assigned address is valid. Return the specified loading address\r
+ //\r
+ ImageContext->ImageAddress = FixLoadingAddress;\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ break;\r
}\r
- } \r
\r
- FreePool(HandleBuffer);\r
- \r
- return NULL;\r
+ SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address %x, Status = %r \n", FixLoadingAddress, Status));\r
+ return Status;\r
}\r
\r
/**\r
Load the SMM Core image into SMRAM and executes the SMM Core from SMRAM.\r
\r
- @param[in] SmramRange Descriptor for the range of SMRAM to reload the \r
- currently executing image.\r
- @param[in] Context Context to pass into SMM Core\r
+ @param[in, out] SmramRange Descriptor for the range of SMRAM to reload the\r
+ currently executing image, the rang of SMRAM to\r
+ hold SMM Core will be excluded.\r
+ @param[in, out] SmramRangeSmmCore Descriptor for the range of SMRAM to hold SMM Core.\r
+\r
+ @param[in] Context Context to pass into SMM Core\r
\r
@return EFI_STATUS\r
\r
**/\r
EFI_STATUS\r
ExecuteSmmCoreFromSmram (\r
- IN EFI_SMRAM_DESCRIPTOR *SmramRange,\r
- IN VOID *Context\r
+ IN OUT EFI_SMRAM_DESCRIPTOR *SmramRange,\r
+ IN OUT EFI_SMRAM_DESCRIPTOR *SmramRangeSmmCore,\r
+ IN VOID *Context\r
)\r
{\r
EFI_STATUS Status;\r
UINTN SourceSize;\r
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
UINTN PageCount;\r
- EFI_PHYSICAL_ADDRESS DestinationBuffer;\r
EFI_IMAGE_ENTRY_POINT EntryPoint;\r
\r
//\r
// Search all Firmware Volumes for a PE/COFF image in a file of type SMM_CORE\r
- // \r
- SourceBuffer = GetSectionInAnyFv (EFI_FV_FILETYPE_SMM_CORE, EFI_SECTION_PE32, &SourceSize);\r
- if (SourceBuffer == NULL) {\r
- return EFI_NOT_FOUND;\r
+ //\r
+ Status = GetSectionFromAnyFvByFileType (\r
+ EFI_FV_FILETYPE_SMM_CORE,\r
+ 0,\r
+ EFI_SECTION_PE32,\r
+ 0,\r
+ &SourceBuffer,\r
+ &SourceSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
}\r
- \r
+\r
//\r
- // Initilize ImageContext\r
+ // Initialize ImageContext\r
//\r
ImageContext.Handle = SourceBuffer;\r
ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
}\r
\r
//\r
- // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR \r
- // specified by SmramRange\r
+ // if Loading module at Fixed Address feature is enabled, the SMM core driver will be loaded to\r
+ // the address assigned by build tool.\r
//\r
- PageCount = (UINTN)EFI_SIZE_TO_PAGES(ImageContext.ImageSize + ImageContext.SectionAlignment);\r
+ if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {\r
+ //\r
+ // Get the fixed loading address assigned by Build tool\r
+ //\r
+ Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Since the memory range to load SMM CORE will be cut out in SMM core, so no need to allocate and free this range\r
+ //\r
+ PageCount = 0;\r
+ //\r
+ // Reserved Smram Region for SmmCore is not used, and remove it from SmramRangeCount.\r
+ //\r
+ gSmmCorePrivate->SmramRangeCount--;\r
+ } else {\r
+ DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR: Loading module at fixed address at address failed\n"));\r
+ //\r
+ // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR\r
+ // specified by SmramRange\r
+ //\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
+ ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);\r
+ ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));\r
\r
- SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount);\r
- DestinationBuffer = SmramRange->CpuStart + SmramRange->PhysicalSize;\r
+ SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount);\r
+ SmramRangeSmmCore->CpuStart = SmramRange->CpuStart + SmramRange->PhysicalSize;\r
+ SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart + SmramRange->PhysicalSize;\r
+ SmramRangeSmmCore->RegionState = SmramRange->RegionState | EFI_ALLOCATED;\r
+ SmramRangeSmmCore->PhysicalSize = EFI_PAGES_TO_SIZE (PageCount);\r
+\r
+ //\r
+ // Align buffer on section boundary\r
+ //\r
+ ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart;\r
+ }\r
+ } else {\r
+ //\r
+ // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR\r
+ // specified by SmramRange\r
+ //\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
+\r
+ SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount);\r
+ SmramRangeSmmCore->CpuStart = SmramRange->CpuStart + SmramRange->PhysicalSize;\r
+ SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart + SmramRange->PhysicalSize;\r
+ SmramRangeSmmCore->RegionState = SmramRange->RegionState | EFI_ALLOCATED;\r
+ SmramRangeSmmCore->PhysicalSize = EFI_PAGES_TO_SIZE (PageCount);\r
+\r
+ //\r
+ // Align buffer on section boundary\r
+ //\r
+ ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart;\r
+ }\r
\r
- //\r
- // Align buffer on section boundry\r
- //\r
- ImageContext.ImageAddress = DestinationBuffer;\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
//\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
EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)ImageContext.EntryPoint;\r
- Status = EntryPoint ((EFI_HANDLE)Context, gST);\r
+ Status = EntryPoint ((EFI_HANDLE)Context, gST);\r
}\r
}\r
\r
//\r
- // If the load operation, relocate operation, or the image execution return an\r
- // error, then free memory allocated from the EFI_SRAM_DESCRIPTOR specified by \r
- // SmramRange\r
+ // Always free memory allocated by GetFileBufferByFilePath ()\r
//\r
- if (EFI_ERROR (Status)) {\r
- SmramRange->PhysicalSize += EFI_PAGES_TO_SIZE (PageCount);\r
+ FreePool (SourceBuffer);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ SMM split SMRAM entry.\r
+\r
+ @param[in, out] RangeToCompare Pointer to EFI_SMRAM_DESCRIPTOR to compare.\r
+ @param[in, out] ReservedRangeToCompare Pointer to EFI_SMM_RESERVED_SMRAM_REGION to compare.\r
+ @param[out] Ranges Output pointer to hold split EFI_SMRAM_DESCRIPTOR entry.\r
+ @param[in, out] RangeCount Pointer to range count.\r
+ @param[out] ReservedRanges Output pointer to hold split EFI_SMM_RESERVED_SMRAM_REGION entry.\r
+ @param[in, out] ReservedRangeCount Pointer to reserved range count.\r
+ @param[out] FinalRanges Output pointer to hold split final EFI_SMRAM_DESCRIPTOR entry\r
+ that no need to be split anymore.\r
+ @param[in, out] FinalRangeCount Pointer to final range count.\r
+\r
+**/\r
+VOID\r
+SmmSplitSmramEntry (\r
+ IN OUT EFI_SMRAM_DESCRIPTOR *RangeToCompare,\r
+ IN OUT EFI_SMM_RESERVED_SMRAM_REGION *ReservedRangeToCompare,\r
+ OUT EFI_SMRAM_DESCRIPTOR *Ranges,\r
+ IN OUT UINTN *RangeCount,\r
+ OUT EFI_SMM_RESERVED_SMRAM_REGION *ReservedRanges,\r
+ IN OUT UINTN *ReservedRangeCount,\r
+ OUT EFI_SMRAM_DESCRIPTOR *FinalRanges,\r
+ IN OUT UINTN *FinalRangeCount\r
+ )\r
+{\r
+ UINT64 RangeToCompareEnd;\r
+ UINT64 ReservedRangeToCompareEnd;\r
+\r
+ RangeToCompareEnd = RangeToCompare->CpuStart + RangeToCompare->PhysicalSize;\r
+ ReservedRangeToCompareEnd = ReservedRangeToCompare->SmramReservedStart + ReservedRangeToCompare->SmramReservedSize;\r
+\r
+ if ((RangeToCompare->CpuStart >= ReservedRangeToCompare->SmramReservedStart) &&\r
+ (RangeToCompare->CpuStart < ReservedRangeToCompareEnd))\r
+ {\r
+ if (RangeToCompareEnd < ReservedRangeToCompareEnd) {\r
+ //\r
+ // RangeToCompare ReservedRangeToCompare\r
+ // ---- ---- --------------------------------------\r
+ // | | | | -> 1. ReservedRangeToCompare\r
+ // ---- | | |--| --------------------------------------\r
+ // | | | | | |\r
+ // | | | | | | -> 2. FinalRanges[*FinalRangeCount] and increment *FinalRangeCount\r
+ // | | | | | | RangeToCompare->PhysicalSize = 0\r
+ // ---- | | |--| --------------------------------------\r
+ // | | | | -> 3. ReservedRanges[*ReservedRangeCount] and increment *ReservedRangeCount\r
+ // ---- ---- --------------------------------------\r
+ //\r
+\r
+ //\r
+ // 1. Update ReservedRangeToCompare.\r
+ //\r
+ ReservedRangeToCompare->SmramReservedSize = RangeToCompare->CpuStart - ReservedRangeToCompare->SmramReservedStart;\r
+ //\r
+ // 2. Update FinalRanges[FinalRangeCount] and increment *FinalRangeCount.\r
+ // Zero RangeToCompare->PhysicalSize.\r
+ //\r
+ FinalRanges[*FinalRangeCount].CpuStart = RangeToCompare->CpuStart;\r
+ FinalRanges[*FinalRangeCount].PhysicalStart = RangeToCompare->PhysicalStart;\r
+ FinalRanges[*FinalRangeCount].RegionState = RangeToCompare->RegionState | EFI_ALLOCATED;\r
+ FinalRanges[*FinalRangeCount].PhysicalSize = RangeToCompare->PhysicalSize;\r
+ *FinalRangeCount += 1;\r
+ RangeToCompare->PhysicalSize = 0;\r
+ //\r
+ // 3. Update ReservedRanges[*ReservedRangeCount] and increment *ReservedRangeCount.\r
+ //\r
+ ReservedRanges[*ReservedRangeCount].SmramReservedStart = FinalRanges[*FinalRangeCount - 1].CpuStart + FinalRanges[*FinalRangeCount - 1].PhysicalSize;\r
+ ReservedRanges[*ReservedRangeCount].SmramReservedSize = ReservedRangeToCompareEnd - RangeToCompareEnd;\r
+ *ReservedRangeCount += 1;\r
+ } else {\r
+ //\r
+ // RangeToCompare ReservedRangeToCompare\r
+ // ---- ---- --------------------------------------\r
+ // | | | | -> 1. ReservedRangeToCompare\r
+ // ---- | | |--| --------------------------------------\r
+ // | | | | | |\r
+ // | | | | | | -> 2. FinalRanges[*FinalRangeCount] and increment *FinalRangeCount\r
+ // | | | | | |\r
+ // | | ---- |--| --------------------------------------\r
+ // | | | | -> 3. RangeToCompare\r
+ // ---- ---- --------------------------------------\r
+ //\r
+\r
+ //\r
+ // 1. Update ReservedRangeToCompare.\r
+ //\r
+ ReservedRangeToCompare->SmramReservedSize = RangeToCompare->CpuStart - ReservedRangeToCompare->SmramReservedStart;\r
+ //\r
+ // 2. Update FinalRanges[FinalRangeCount] and increment *FinalRangeCount.\r
+ //\r
+ FinalRanges[*FinalRangeCount].CpuStart = RangeToCompare->CpuStart;\r
+ FinalRanges[*FinalRangeCount].PhysicalStart = RangeToCompare->PhysicalStart;\r
+ FinalRanges[*FinalRangeCount].RegionState = RangeToCompare->RegionState | EFI_ALLOCATED;\r
+ FinalRanges[*FinalRangeCount].PhysicalSize = ReservedRangeToCompareEnd - RangeToCompare->CpuStart;\r
+ *FinalRangeCount += 1;\r
+ //\r
+ // 3. Update RangeToCompare.\r
+ //\r
+ RangeToCompare->CpuStart += FinalRanges[*FinalRangeCount - 1].PhysicalSize;\r
+ RangeToCompare->PhysicalStart += FinalRanges[*FinalRangeCount - 1].PhysicalSize;\r
+ RangeToCompare->PhysicalSize -= FinalRanges[*FinalRangeCount - 1].PhysicalSize;\r
+ }\r
+ } else if ((ReservedRangeToCompare->SmramReservedStart >= RangeToCompare->CpuStart) &&\r
+ (ReservedRangeToCompare->SmramReservedStart < RangeToCompareEnd))\r
+ {\r
+ if (ReservedRangeToCompareEnd < RangeToCompareEnd) {\r
+ //\r
+ // RangeToCompare ReservedRangeToCompare\r
+ // ---- ---- --------------------------------------\r
+ // | | | | -> 1. RangeToCompare\r
+ // | | ---- |--| --------------------------------------\r
+ // | | | | | |\r
+ // | | | | | | -> 2. FinalRanges[*FinalRangeCount] and increment *FinalRangeCount\r
+ // | | | | | | ReservedRangeToCompare->SmramReservedSize = 0\r
+ // | | ---- |--| --------------------------------------\r
+ // | | | | -> 3. Ranges[*RangeCount] and increment *RangeCount\r
+ // ---- ---- --------------------------------------\r
+ //\r
+\r
+ //\r
+ // 1. Update RangeToCompare.\r
+ //\r
+ RangeToCompare->PhysicalSize = ReservedRangeToCompare->SmramReservedStart - RangeToCompare->CpuStart;\r
+ //\r
+ // 2. Update FinalRanges[FinalRangeCount] and increment *FinalRangeCount.\r
+ // ReservedRangeToCompare->SmramReservedSize = 0\r
+ //\r
+ FinalRanges[*FinalRangeCount].CpuStart = ReservedRangeToCompare->SmramReservedStart;\r
+ FinalRanges[*FinalRangeCount].PhysicalStart = RangeToCompare->PhysicalStart + RangeToCompare->PhysicalSize;\r
+ FinalRanges[*FinalRangeCount].RegionState = RangeToCompare->RegionState | EFI_ALLOCATED;\r
+ FinalRanges[*FinalRangeCount].PhysicalSize = ReservedRangeToCompare->SmramReservedSize;\r
+ *FinalRangeCount += 1;\r
+ ReservedRangeToCompare->SmramReservedSize = 0;\r
+ //\r
+ // 3. Update Ranges[*RangeCount] and increment *RangeCount.\r
+ //\r
+ Ranges[*RangeCount].CpuStart = FinalRanges[*FinalRangeCount - 1].CpuStart + FinalRanges[*FinalRangeCount - 1].PhysicalSize;\r
+ Ranges[*RangeCount].PhysicalStart = FinalRanges[*FinalRangeCount - 1].PhysicalStart + FinalRanges[*FinalRangeCount - 1].PhysicalSize;\r
+ Ranges[*RangeCount].RegionState = RangeToCompare->RegionState;\r
+ Ranges[*RangeCount].PhysicalSize = RangeToCompareEnd - ReservedRangeToCompareEnd;\r
+ *RangeCount += 1;\r
+ } else {\r
+ //\r
+ // RangeToCompare ReservedRangeToCompare\r
+ // ---- ---- --------------------------------------\r
+ // | | | | -> 1. RangeToCompare\r
+ // | | ---- |--| --------------------------------------\r
+ // | | | | | |\r
+ // | | | | | | -> 2. FinalRanges[*FinalRangeCount] and increment *FinalRangeCount\r
+ // | | | | | |\r
+ // ---- | | |--| --------------------------------------\r
+ // | | | | -> 3. ReservedRangeToCompare\r
+ // ---- ---- --------------------------------------\r
+ //\r
+\r
+ //\r
+ // 1. Update RangeToCompare.\r
+ //\r
+ RangeToCompare->PhysicalSize = ReservedRangeToCompare->SmramReservedStart - RangeToCompare->CpuStart;\r
+ //\r
+ // 2. Update FinalRanges[FinalRangeCount] and increment *FinalRangeCount.\r
+ // ReservedRangeToCompare->SmramReservedSize = 0\r
+ //\r
+ FinalRanges[*FinalRangeCount].CpuStart = ReservedRangeToCompare->SmramReservedStart;\r
+ FinalRanges[*FinalRangeCount].PhysicalStart = RangeToCompare->PhysicalStart + RangeToCompare->PhysicalSize;\r
+ FinalRanges[*FinalRangeCount].RegionState = RangeToCompare->RegionState | EFI_ALLOCATED;\r
+ FinalRanges[*FinalRangeCount].PhysicalSize = RangeToCompareEnd - ReservedRangeToCompare->SmramReservedStart;\r
+ *FinalRangeCount += 1;\r
+ //\r
+ // 3. Update ReservedRangeToCompare.\r
+ //\r
+ ReservedRangeToCompare->SmramReservedStart += FinalRanges[*FinalRangeCount - 1].PhysicalSize;\r
+ ReservedRangeToCompare->SmramReservedSize -= FinalRanges[*FinalRangeCount - 1].PhysicalSize;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Returns if SMRAM range and SMRAM reserved range are overlapped.\r
+\r
+ @param[in] RangeToCompare Pointer to EFI_SMRAM_DESCRIPTOR to compare.\r
+ @param[in] ReservedRangeToCompare Pointer to EFI_SMM_RESERVED_SMRAM_REGION to compare.\r
+\r
+ @retval TRUE There is overlap.\r
+ @retval FALSE There is no overlap.\r
+\r
+**/\r
+BOOLEAN\r
+SmmIsSmramOverlap (\r
+ IN EFI_SMRAM_DESCRIPTOR *RangeToCompare,\r
+ IN EFI_SMM_RESERVED_SMRAM_REGION *ReservedRangeToCompare\r
+ )\r
+{\r
+ UINT64 RangeToCompareEnd;\r
+ UINT64 ReservedRangeToCompareEnd;\r
+\r
+ RangeToCompareEnd = RangeToCompare->CpuStart + RangeToCompare->PhysicalSize;\r
+ ReservedRangeToCompareEnd = ReservedRangeToCompare->SmramReservedStart + ReservedRangeToCompare->SmramReservedSize;\r
+\r
+ if ((RangeToCompare->CpuStart >= ReservedRangeToCompare->SmramReservedStart) &&\r
+ (RangeToCompare->CpuStart < ReservedRangeToCompareEnd))\r
+ {\r
+ return TRUE;\r
+ } else if ((ReservedRangeToCompare->SmramReservedStart >= RangeToCompare->CpuStart) &&\r
+ (ReservedRangeToCompare->SmramReservedStart < RangeToCompareEnd))\r
+ {\r
+ return TRUE;\r
}\r
\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Get full SMRAM ranges.\r
+\r
+ It will get SMRAM ranges from SmmAccess protocol and SMRAM reserved ranges from\r
+ SmmConfiguration protocol, split the entries if there is overlap between them.\r
+ It will also reserve one entry for SMM core.\r
+\r
+ @param[out] FullSmramRangeCount Output pointer to full SMRAM range count.\r
+\r
+ @return Pointer to full SMRAM ranges.\r
+\r
+**/\r
+EFI_SMRAM_DESCRIPTOR *\r
+GetFullSmramRanges (\r
+ OUT UINTN *FullSmramRangeCount\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SMM_CONFIGURATION_PROTOCOL *SmmConfiguration;\r
+ UINTN Size;\r
+ UINTN Index;\r
+ UINTN Index2;\r
+ EFI_SMRAM_DESCRIPTOR *FullSmramRanges;\r
+ UINTN TempSmramRangeCount;\r
+ UINTN AdditionSmramRangeCount;\r
+ EFI_SMRAM_DESCRIPTOR *TempSmramRanges;\r
+ UINTN SmramRangeCount;\r
+ EFI_SMRAM_DESCRIPTOR *SmramRanges;\r
+ UINTN SmramReservedCount;\r
+ EFI_SMM_RESERVED_SMRAM_REGION *SmramReservedRanges;\r
+ UINTN MaxCount;\r
+ BOOLEAN Rescan;\r
+\r
//\r
- // Always free memory allocted by GetFileBufferByFilePath ()\r
+ // Get SMM Configuration Protocol if it is present.\r
//\r
- FreePool (SourceBuffer);\r
+ SmmConfiguration = NULL;\r
+ Status = gBS->LocateProtocol (&gEfiSmmConfigurationProtocolGuid, NULL, (VOID **)&SmmConfiguration);\r
\r
- return Status;\r
+ //\r
+ // Get SMRAM information.\r
+ //\r
+ Size = 0;\r
+ Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, NULL);\r
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
+\r
+ SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);\r
+\r
+ //\r
+ // Get SMRAM reserved region count.\r
+ //\r
+ SmramReservedCount = 0;\r
+ if (SmmConfiguration != NULL) {\r
+ while (SmmConfiguration->SmramReservedRegions[SmramReservedCount].SmramReservedSize != 0) {\r
+ SmramReservedCount++;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Reserve one entry for SMM Core in the full SMRAM ranges.\r
+ //\r
+ AdditionSmramRangeCount = 1;\r
+ if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {\r
+ //\r
+ // Reserve two entries for all SMM drivers and SMM Core in the full SMRAM ranges.\r
+ //\r
+ AdditionSmramRangeCount = 2;\r
+ }\r
+\r
+ if (SmramReservedCount == 0) {\r
+ //\r
+ // No reserved SMRAM entry from SMM Configuration Protocol.\r
+ //\r
+ *FullSmramRangeCount = SmramRangeCount + AdditionSmramRangeCount;\r
+ Size = (*FullSmramRangeCount) * sizeof (EFI_SMRAM_DESCRIPTOR);\r
+ FullSmramRanges = (EFI_SMRAM_DESCRIPTOR *)AllocateZeroPool (Size);\r
+ ASSERT (FullSmramRanges != NULL);\r
+\r
+ Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, FullSmramRanges);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return FullSmramRanges;\r
+ }\r
+\r
+ //\r
+ // Why MaxCount = X + 2 * Y?\r
+ // Take Y = 1 as example below, Y > 1 case is just the iteration of Y = 1.\r
+ //\r
+ // X = 1 Y = 1 MaxCount = 3 = 1 + 2 * 1\r
+ // ---- ----\r
+ // | | ---- |--|\r
+ // | | | | -> | |\r
+ // | | ---- |--|\r
+ // ---- ----\r
+ //\r
+ // X = 2 Y = 1 MaxCount = 4 = 2 + 2 * 1\r
+ // ---- ----\r
+ // | | | |\r
+ // | | ---- |--|\r
+ // | | | | | |\r
+ // |--| | | -> |--|\r
+ // | | | | | |\r
+ // | | ---- |--|\r
+ // | | | |\r
+ // ---- ----\r
+ //\r
+ // X = 3 Y = 1 MaxCount = 5 = 3 + 2 * 1\r
+ // ---- ----\r
+ // | | | |\r
+ // | | ---- |--|\r
+ // |--| | | |--|\r
+ // | | | | -> | |\r
+ // |--| | | |--|\r
+ // | | ---- |--|\r
+ // | | | |\r
+ // ---- ----\r
+ //\r
+ // ......\r
+ //\r
+ MaxCount = SmramRangeCount + 2 * SmramReservedCount;\r
+\r
+ Size = MaxCount * sizeof (EFI_SMM_RESERVED_SMRAM_REGION);\r
+ SmramReservedRanges = (EFI_SMM_RESERVED_SMRAM_REGION *)AllocatePool (Size);\r
+ ASSERT (SmramReservedRanges != NULL);\r
+ for (Index = 0; Index < SmramReservedCount; Index++) {\r
+ CopyMem (&SmramReservedRanges[Index], &SmmConfiguration->SmramReservedRegions[Index], sizeof (EFI_SMM_RESERVED_SMRAM_REGION));\r
+ }\r
+\r
+ Size = MaxCount * sizeof (EFI_SMRAM_DESCRIPTOR);\r
+ TempSmramRanges = (EFI_SMRAM_DESCRIPTOR *)AllocatePool (Size);\r
+ ASSERT (TempSmramRanges != NULL);\r
+ TempSmramRangeCount = 0;\r
+\r
+ SmramRanges = (EFI_SMRAM_DESCRIPTOR *)AllocatePool (Size);\r
+ ASSERT (SmramRanges != NULL);\r
+ Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, SmramRanges);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ do {\r
+ Rescan = FALSE;\r
+ for (Index = 0; (Index < SmramRangeCount) && !Rescan; Index++) {\r
+ //\r
+ // Skip zero size entry.\r
+ //\r
+ if (SmramRanges[Index].PhysicalSize != 0) {\r
+ for (Index2 = 0; (Index2 < SmramReservedCount) && !Rescan; Index2++) {\r
+ //\r
+ // Skip zero size entry.\r
+ //\r
+ if (SmramReservedRanges[Index2].SmramReservedSize != 0) {\r
+ if (SmmIsSmramOverlap (\r
+ &SmramRanges[Index],\r
+ &SmramReservedRanges[Index2]\r
+ ))\r
+ {\r
+ //\r
+ // There is overlap, need to split entry and then rescan.\r
+ //\r
+ SmmSplitSmramEntry (\r
+ &SmramRanges[Index],\r
+ &SmramReservedRanges[Index2],\r
+ SmramRanges,\r
+ &SmramRangeCount,\r
+ SmramReservedRanges,\r
+ &SmramReservedCount,\r
+ TempSmramRanges,\r
+ &TempSmramRangeCount\r
+ );\r
+ Rescan = TRUE;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (!Rescan) {\r
+ //\r
+ // No any overlap, copy the entry to the temp SMRAM ranges.\r
+ // Zero SmramRanges[Index].PhysicalSize = 0;\r
+ //\r
+ CopyMem (&TempSmramRanges[TempSmramRangeCount++], &SmramRanges[Index], sizeof (EFI_SMRAM_DESCRIPTOR));\r
+ SmramRanges[Index].PhysicalSize = 0;\r
+ }\r
+ }\r
+ }\r
+ } while (Rescan);\r
+\r
+ ASSERT (TempSmramRangeCount <= MaxCount);\r
+\r
+ //\r
+ // Sort the entries\r
+ //\r
+ FullSmramRanges = AllocateZeroPool ((TempSmramRangeCount + AdditionSmramRangeCount) * sizeof (EFI_SMRAM_DESCRIPTOR));\r
+ ASSERT (FullSmramRanges != NULL);\r
+ *FullSmramRangeCount = 0;\r
+ do {\r
+ for (Index = 0; Index < TempSmramRangeCount; Index++) {\r
+ if (TempSmramRanges[Index].PhysicalSize != 0) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ ASSERT (Index < TempSmramRangeCount);\r
+ for (Index2 = 0; Index2 < TempSmramRangeCount; Index2++) {\r
+ if ((Index2 != Index) && (TempSmramRanges[Index2].PhysicalSize != 0) && (TempSmramRanges[Index2].CpuStart < TempSmramRanges[Index].CpuStart)) {\r
+ Index = Index2;\r
+ }\r
+ }\r
+\r
+ CopyMem (&FullSmramRanges[*FullSmramRangeCount], &TempSmramRanges[Index], sizeof (EFI_SMRAM_DESCRIPTOR));\r
+ *FullSmramRangeCount += 1;\r
+ TempSmramRanges[Index].PhysicalSize = 0;\r
+ } while (*FullSmramRangeCount < TempSmramRangeCount);\r
+\r
+ ASSERT (*FullSmramRangeCount == TempSmramRangeCount);\r
+ *FullSmramRangeCount += AdditionSmramRangeCount;\r
+\r
+ FreePool (SmramRanges);\r
+ FreePool (SmramReservedRanges);\r
+ FreePool (TempSmramRanges);\r
+\r
+ return FullSmramRanges;\r
}\r
\r
/**\r
The Entry Point for SMM IPL\r
\r
- Load SMM Core into SMRAM, register SMM Core entry point for SMIs, install \r
- SMM Base 2 Protocol and SMM Communication Protocol, and register for the \r
+ Load SMM Core into SMRAM, register SMM Core entry point for SMIs, install\r
+ SMM Base 2 Protocol and SMM Communication Protocol, and register for the\r
critical events required to coordinate between DXE and SMM environments.\r
- \r
+\r
@param ImageHandle The firmware allocated handle for the EFI image.\r
@param SystemTable A pointer to the EFI System Table.\r
\r
IN EFI_SYSTEM_TABLE *SystemTable\r
)\r
{\r
- EFI_STATUS Status;\r
- EFI_SMM_CONFIGURATION_PROTOCOL *SmmConfiguration;\r
- UINTN Size;\r
- UINTN Index;\r
- EFI_SMM_RESERVED_SMRAM_REGION *SmramResRegion;\r
- UINT64 MaxSize;\r
- VOID *Registration;\r
-\r
- //\r
- // Fill in the image handle of the SMM IPL so the SMM Core can use this as the \r
- // ParentImageHandle field of the Load Image Protocol for all SMM Drivers loaded \r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ UINT64 MaxSize;\r
+ VOID *Registration;\r
+ UINT64 SmmCodeSize;\r
+ EFI_CPU_ARCH_PROTOCOL *CpuArch;\r
+ EFI_STATUS SetAttrStatus;\r
+ EFI_SMRAM_DESCRIPTOR *SmramRangeSmmDriver;\r
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc;\r
+\r
+ //\r
+ // Fill in the image handle of the SMM IPL so the SMM Core can use this as the\r
+ // ParentImageHandle field of the Load Image Protocol for all SMM Drivers loaded\r
// by the SMM Core\r
//\r
mSmmCorePrivateData.SmmIplImageHandle = ImageHandle;\r
Status = gBS->LocateProtocol (&gEfiSmmControl2ProtocolGuid, NULL, (VOID **)&mSmmControl2);\r
ASSERT_EFI_ERROR (Status);\r
\r
- //\r
- // Get SMM Configuration Protocol if it is present\r
- //\r
- SmmConfiguration = NULL;\r
- Status = gBS->LocateProtocol (&gEfiSmmConfigurationProtocolGuid, NULL, (VOID **) &SmmConfiguration);\r
-\r
- //\r
- // Get SMRAM information\r
- //\r
- Size = 0;\r
- Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, NULL);\r
- ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
-\r
- gSmmCorePrivate->SmramRanges = (EFI_SMRAM_DESCRIPTOR *)AllocatePool (Size);\r
- ASSERT (gSmmCorePrivate->SmramRanges != NULL);\r
-\r
- Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, gSmmCorePrivate->SmramRanges);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- gSmmCorePrivate->SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);\r
+ gSmmCorePrivate->SmramRanges = GetFullSmramRanges (&gSmmCorePrivate->SmramRangeCount);\r
\r
//\r
// Open all SMRAM ranges\r
//\r
DEBUG ((DEBUG_INFO, "SMM IPL opened SMRAM window\n"));\r
\r
- //\r
- // Subtract SMRAM any reserved SMRAM regions.\r
- //\r
- if (SmmConfiguration != NULL) {\r
- SmramResRegion = SmmConfiguration->SmramReservedRegions;\r
- while (SmramResRegion->SmramReservedSize != 0) {\r
- for (Index = 0; Index < gSmmCorePrivate->SmramRangeCount; Index ++) {\r
- if ((SmramResRegion->SmramReservedStart >= gSmmCorePrivate->SmramRanges[Index].CpuStart) && \\r
- ((SmramResRegion->SmramReservedStart + SmramResRegion->SmramReservedSize) <= \\r
- (gSmmCorePrivate->SmramRanges[Index].CpuStart + gSmmCorePrivate->SmramRanges[Index].PhysicalSize))) {\r
- //\r
- // This range has reserved area, calculate the left free size\r
- //\r
- gSmmCorePrivate->SmramRanges[Index].PhysicalSize = SmramResRegion->SmramReservedStart - gSmmCorePrivate->SmramRanges[Index].CpuStart;\r
- }\r
- }\r
- SmramResRegion++;\r
- }\r
- }\r
- \r
//\r
// Find the largest SMRAM range between 1MB and 4GB that is at least 256KB - 4K in size\r
//\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].CpuStart + gSmmCorePrivate->SmramRanges[Index].PhysicalSize - 1) <= MAX_ADDRESS) {\r
if (gSmmCorePrivate->SmramRanges[Index].PhysicalSize >= MaxSize) {\r
- MaxSize = gSmmCorePrivate->SmramRanges[Index].PhysicalSize;\r
+ MaxSize = gSmmCorePrivate->SmramRanges[Index].PhysicalSize;\r
mCurrentSmramRange = &gSmmCorePrivate->SmramRanges[Index];\r
}\r
}\r
//\r
// Print debug message showing SMRAM window that will be used by SMM IPL and SMM Core\r
//\r
- DEBUG ((DEBUG_INFO, "SMM IPL found SMRAM window %p - %p\n", \r
- (VOID *)(UINTN)mCurrentSmramRange->CpuStart, \r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "SMM IPL found SMRAM window %p - %p\n",\r
+ (VOID *)(UINTN)mCurrentSmramRange->CpuStart,\r
(VOID *)(UINTN)(mCurrentSmramRange->CpuStart + mCurrentSmramRange->PhysicalSize - 1)\r
));\r
\r
+ GetSmramCacheRange (mCurrentSmramRange, &mSmramCacheBase, &mSmramCacheSize);\r
//\r
- // Attempt to set SMRAM cacheability to WB\r
+ // Make sure we can change the desired memory attributes.\r
//\r
- Status = gDS->SetMemorySpaceAttributes(\r
- mCurrentSmramRange->CpuStart, \r
- mCurrentSmramRange->PhysicalSize,\r
- EFI_MEMORY_WB\r
+ Status = gDS->GetMemorySpaceDescriptor (\r
+ mSmramCacheBase,\r
+ &MemDesc\r
);\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((DEBUG_WARN, "SMM IPL failed to set SMRAM window to EFI_MEMORY_WB\n"));\r
- } \r
+ ASSERT_EFI_ERROR (Status);\r
+ if ((MemDesc.Capabilities & SMRAM_CAPABILITIES) != SMRAM_CAPABILITIES) {\r
+ gDS->SetMemorySpaceCapabilities (\r
+ mSmramCacheBase,\r
+ mSmramCacheSize,\r
+ MemDesc.Capabilities | SMRAM_CAPABILITIES\r
+ );\r
+ }\r
+\r
+ //\r
+ // If CPU AP is present, attempt to set SMRAM cacheability to WB and clear\r
+ // all paging attributes.\r
+ // Note that it is expected that cacheability of SMRAM has been set to WB if CPU AP\r
+ // is not available here.\r
+ //\r
+ CpuArch = NULL;\r
+ Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&CpuArch);\r
+ if (!EFI_ERROR (Status)) {\r
+ MemDesc.Attributes &= ~(EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK);\r
+ MemDesc.Attributes |= EFI_MEMORY_WB;\r
+ Status = gDS->SetMemorySpaceAttributes (\r
+ mSmramCacheBase,\r
+ mSmramCacheSize,\r
+ MemDesc.Attributes\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_WARN, "SMM IPL failed to set SMRAM window to EFI_MEMORY_WB\n"));\r
+ }\r
+\r
+ DEBUG_CODE (\r
+ gDS->GetMemorySpaceDescriptor (\r
+ mSmramCacheBase,\r
+ &MemDesc\r
+ );\r
+ DEBUG ((DEBUG_INFO, "SMRAM attributes: %016lx\n", MemDesc.Attributes));\r
+ ASSERT ((MemDesc.Attributes & EFI_MEMORY_ATTRIBUTE_MASK) == 0);\r
+ );\r
+ }\r
+\r
+ //\r
+ // if Loading module at Fixed Address feature is enabled, save the SMRAM base to Load\r
+ // Modules At Fixed Address Configuration Table.\r
+ //\r
+ if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {\r
+ //\r
+ // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber\r
+ //\r
+ SmmCodeSize = LShiftU64 (PcdGet32 (PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT);\r
+ //\r
+ // The SMRAM available memory is assumed to be larger than SmmCodeSize\r
+ //\r
+ ASSERT (mCurrentSmramRange->PhysicalSize > SmmCodeSize);\r
+ //\r
+ // Retrieve Load modules At fixed address configuration table and save the SMRAM base.\r
+ //\r
+ Status = EfiGetSystemConfigurationTable (\r
+ &gLoadFixedAddressConfigurationTableGuid,\r
+ (VOID **)&mLMFAConfigurationTable\r
+ );\r
+ if (!EFI_ERROR (Status) && (mLMFAConfigurationTable != NULL)) {\r
+ mLMFAConfigurationTable->SmramBase = mCurrentSmramRange->CpuStart;\r
+ //\r
+ // Print the SMRAM base\r
+ //\r
+ DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: TSEG BASE is %x. \n", mLMFAConfigurationTable->SmramBase));\r
+ }\r
+\r
+ //\r
+ // Fill the Smram range for all SMM code\r
+ //\r
+ SmramRangeSmmDriver = &gSmmCorePrivate->SmramRanges[gSmmCorePrivate->SmramRangeCount - 2];\r
+ SmramRangeSmmDriver->CpuStart = mCurrentSmramRange->CpuStart;\r
+ SmramRangeSmmDriver->PhysicalStart = mCurrentSmramRange->PhysicalStart;\r
+ SmramRangeSmmDriver->RegionState = mCurrentSmramRange->RegionState | EFI_ALLOCATED;\r
+ SmramRangeSmmDriver->PhysicalSize = SmmCodeSize;\r
+\r
+ mCurrentSmramRange->PhysicalSize -= SmmCodeSize;\r
+ mCurrentSmramRange->CpuStart = mCurrentSmramRange->CpuStart + SmmCodeSize;\r
+ mCurrentSmramRange->PhysicalStart = mCurrentSmramRange->PhysicalStart + SmmCodeSize;\r
+ }\r
\r
//\r
// Load SMM Core into SMRAM and execute it from SMRAM\r
//\r
- Status = ExecuteSmmCoreFromSmram (mCurrentSmramRange, gSmmCorePrivate);\r
+ Status = ExecuteSmmCoreFromSmram (\r
+ mCurrentSmramRange,\r
+ &gSmmCorePrivate->SmramRanges[gSmmCorePrivate->SmramRangeCount - 1],\r
+ gSmmCorePrivate\r
+ );\r
if (EFI_ERROR (Status)) {\r
//\r
// Print error message that the SMM Core failed to be loaded and executed.\r
//\r
// Attempt to reset SMRAM cacheability to UC\r
//\r
- Status = gDS->SetMemorySpaceAttributes(\r
- mCurrentSmramRange->CpuStart, \r
- mCurrentSmramRange->PhysicalSize,\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
+ if (CpuArch != NULL) {\r
+ SetAttrStatus = gDS->SetMemorySpaceAttributes (\r
+ mSmramCacheBase,\r
+ mSmramCacheSize,\r
+ EFI_MEMORY_UC\r
+ );\r
+ if (EFI_ERROR (SetAttrStatus)) {\r
+ DEBUG ((DEBUG_WARN, "SMM IPL failed to reset SMRAM window to EFI_MEMORY_UC\n"));\r
+ }\r
+ }\r
}\r
} else {\r
//\r
}\r
\r
//\r
- // If the SMM Core could not be loaded then close SMRAM window, free allocated \r
+ // If the SMM Core could not be loaded then close SMRAM window, free allocated\r
// resources, and return an error so SMM IPL will be unloaded.\r
//\r
- if (mCurrentSmramRange == NULL || EFI_ERROR (Status)) {\r
+ if ((mCurrentSmramRange == NULL) || EFI_ERROR (Status)) {\r
//\r
// Close all SMRAM ranges\r
//\r
// Free all allocated resources\r
//\r
FreePool (gSmmCorePrivate->SmramRanges);\r
- \r
+\r
return EFI_UNSUPPORTED;\r
}\r
- \r
+\r
//\r
// Install SMM Base2 Protocol and SMM Communication Protocol\r
//\r
Status = gBS->InstallMultipleProtocolInterfaces (\r
&mSmmIplHandle,\r
- &gEfiSmmBase2ProtocolGuid, &mSmmBase2,\r
- &gEfiSmmCommunicationProtocolGuid, &mSmmCommunication,\r
+ &gEfiSmmBase2ProtocolGuid,\r
+ &mSmmBase2,\r
+ &gEfiSmmCommunicationProtocolGuid,\r
+ &mSmmCommunication,\r
+ &gEfiMmCommunication2ProtocolGuid,\r
+ &mMmCommunication2,\r
NULL\r
);\r
ASSERT_EFI_ERROR (Status);\r
\r
//\r
- // Create the set of protocol and event notififcations that the SMM IPL requires\r
+ // Create the set of protocol and event notifications that the SMM IPL requires\r
//\r
for (Index = 0; mSmmIplEvents[Index].NotifyFunction != NULL; Index++) {\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
- );\r
+ &Registration\r
+ );\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