summaryrefslogtreecommitdiff
path: root/EdkCompatibilityPkg/Compatibility/SmmBaseHelper
diff options
context:
space:
mode:
authorrsun3 <rsun3@6f19259b-4bc3-4df7-8a09-765794883524>2009-12-31 08:42:28 +0000
committerrsun3 <rsun3@6f19259b-4bc3-4df7-8a09-765794883524>2009-12-31 08:42:28 +0000
commit9e620719100f80892adfa8e2f810a485bce32fb9 (patch)
tree23f2cf4fd9ab14e563539569e7b143e7986c4f1d /EdkCompatibilityPkg/Compatibility/SmmBaseHelper
parenta77e0eb17aecf3c4504e526063771eb8b4cc0968 (diff)
downloadedk2-platforms-9e620719100f80892adfa8e2f810a485bce32fb9.tar.xz
Add 4 Framework/PI SMM thunk drivers. Combined use of these drivers can support usage model of PI SMM infrastructure + Framework Chipset SMM code + Framework platform SMM code in ECP platforms.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9657 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'EdkCompatibilityPkg/Compatibility/SmmBaseHelper')
-rw-r--r--EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.c698
-rw-r--r--EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.h57
-rw-r--r--EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.inf62
3 files changed, 817 insertions, 0 deletions
diff --git a/EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.c b/EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.c
new file mode 100644
index 0000000000..381f6ae2ed
--- /dev/null
+++ b/EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.c
@@ -0,0 +1,698 @@
+/** @file
+ SMM Base Helper SMM driver.
+
+ This driver is the counterpart of the SMM Base On SMM Base2 Thunk driver. It
+ provides helping services in SMM to the SMM Base On SMM Base2 Thunk driver.
+
+ Copyright (c) 2009, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "SmmBaseHelper.h"
+
+EFI_HANDLE mDispatchHandle;
+EFI_SMM_CPU_PROTOCOL *mSmmCpu;
+EFI_GUID mEfiSmmCpuIoGuid = EFI_SMM_CPU_IO_GUID;
+EFI_SMM_BASE_HELPER_READY_PROTOCOL *mSmmBaseHelperReady;
+EFI_SMM_SYSTEM_TABLE *mFrameworkSmst;
+
+LIST_ENTRY mCallbackInfoListHead = INITIALIZE_LIST_HEAD_VARIABLE (mCallbackInfoListHead);
+
+CPU_SAVE_STATE_CONVERSION mCpuSaveStateConvTable[] = {
+ {EFI_SMM_SAVE_STATE_REGISTER_LDTBASE , CPU_SAVE_STATE_GET_OFFSET(LDTBase)},
+ {EFI_SMM_SAVE_STATE_REGISTER_ES , CPU_SAVE_STATE_GET_OFFSET(ES)},
+ {EFI_SMM_SAVE_STATE_REGISTER_CS , CPU_SAVE_STATE_GET_OFFSET(CS)},
+ {EFI_SMM_SAVE_STATE_REGISTER_SS , CPU_SAVE_STATE_GET_OFFSET(SS)},
+ {EFI_SMM_SAVE_STATE_REGISTER_DS , CPU_SAVE_STATE_GET_OFFSET(DS)},
+ {EFI_SMM_SAVE_STATE_REGISTER_FS , CPU_SAVE_STATE_GET_OFFSET(FS)},
+ {EFI_SMM_SAVE_STATE_REGISTER_GS , CPU_SAVE_STATE_GET_OFFSET(GS)},
+ {EFI_SMM_SAVE_STATE_REGISTER_TR_SEL , CPU_SAVE_STATE_GET_OFFSET(TR)},
+ {EFI_SMM_SAVE_STATE_REGISTER_DR7 , CPU_SAVE_STATE_GET_OFFSET(DR7)},
+ {EFI_SMM_SAVE_STATE_REGISTER_DR6 , CPU_SAVE_STATE_GET_OFFSET(DR6)},
+ {EFI_SMM_SAVE_STATE_REGISTER_RAX , CPU_SAVE_STATE_GET_OFFSET(EAX)},
+ {EFI_SMM_SAVE_STATE_REGISTER_RBX , CPU_SAVE_STATE_GET_OFFSET(EBX)},
+ {EFI_SMM_SAVE_STATE_REGISTER_RCX , CPU_SAVE_STATE_GET_OFFSET(ECX)},
+ {EFI_SMM_SAVE_STATE_REGISTER_RDX , CPU_SAVE_STATE_GET_OFFSET(EDX)},
+ {EFI_SMM_SAVE_STATE_REGISTER_RSP , CPU_SAVE_STATE_GET_OFFSET(ESP)},
+ {EFI_SMM_SAVE_STATE_REGISTER_RBP , CPU_SAVE_STATE_GET_OFFSET(EBP)},
+ {EFI_SMM_SAVE_STATE_REGISTER_RSI , CPU_SAVE_STATE_GET_OFFSET(ESI)},
+ {EFI_SMM_SAVE_STATE_REGISTER_RDI , CPU_SAVE_STATE_GET_OFFSET(EDI)},
+ {EFI_SMM_SAVE_STATE_REGISTER_RIP , CPU_SAVE_STATE_GET_OFFSET(EIP)},
+ {EFI_SMM_SAVE_STATE_REGISTER_RFLAGS , CPU_SAVE_STATE_GET_OFFSET(EFLAGS)},
+ {EFI_SMM_SAVE_STATE_REGISTER_CR0 , CPU_SAVE_STATE_GET_OFFSET(CR0)},
+ {EFI_SMM_SAVE_STATE_REGISTER_CR3 , CPU_SAVE_STATE_GET_OFFSET(CR3)}
+};
+
+/**
+ Framework SMST SmmInstallConfigurationTable() Thunk.
+
+ This thunk calls the PI SMM SmmInstallConfigurationTable() and then update the configuration
+ table related fields in the Framework SMST because the PI SMM SmmInstallConfigurationTable()
+ function may modify these fields.
+
+ @param[in] SystemTable A pointer to the SMM System Table.
+ @param[in] Guid A pointer to the GUID for the entry to add, update, or remove.
+ @param[in] Table A pointer to the buffer of the table to add.
+ @param[in] TableSize The size of the table to install.
+
+ @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed.
+ @retval EFI_INVALID_PARAMETER Guid is not valid.
+ @retval EFI_NOT_FOUND An attempt was made to delete a non-existent entry.
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation.
+**/
+EFI_STATUS
+EFIAPI
+SmmInstallConfigurationTable (
+ IN EFI_SMM_SYSTEM_TABLE *SystemTable,
+ IN EFI_GUID *Guid,
+ IN VOID *Table,
+ IN UINTN TableSize
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gSmst->SmmInstallConfigurationTable (gSmst, Guid, Table, TableSize);
+ if (!EFI_ERROR (Status)) {
+ mFrameworkSmst->NumberOfTableEntries = gSmst->NumberOfTableEntries;
+ mFrameworkSmst->SmmConfigurationTable = gSmst->SmmConfigurationTable;
+ }
+ return Status;
+}
+
+/**
+ Construct a Framework SMST based on the PI SMM SMST.
+
+ @return Pointer to the constructed Framework SMST.
+**/
+EFI_SMM_SYSTEM_TABLE *
+ConstructFrameworkSmst (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_SYSTEM_TABLE *FrameworkSmst;
+
+ Status = gSmst->SmmAllocatePool (
+ EfiRuntimeServicesData,
+ sizeof (EFI_SMM_SYSTEM_TABLE),
+ (VOID **)&FrameworkSmst
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Copy same things from PI SMST to Framework SMST
+ ///
+ CopyMem (FrameworkSmst, gSmst, (UINTN)(&((EFI_SMM_SYSTEM_TABLE *)0)->SmmIo));
+ CopyMem (
+ &FrameworkSmst->SmmIo,
+ &gSmst->SmmIo,
+ sizeof (EFI_SMM_SYSTEM_TABLE) - (UINTN)(&((EFI_SMM_SYSTEM_TABLE *)0)->SmmIo)
+ );
+
+ ///
+ /// Update Framework SMST
+ ///
+ FrameworkSmst->Hdr.Revision = EFI_SMM_SYSTEM_TABLE_REVISION;
+ CopyGuid (&FrameworkSmst->EfiSmmCpuIoGuid, &mEfiSmmCpuIoGuid);
+
+ Status = gSmst->SmmAllocatePool (
+ EfiRuntimeServicesData,
+ gSmst->NumberOfCpus * sizeof (EFI_SMI_CPU_SAVE_STATE),
+ (VOID **)&FrameworkSmst->CpuSaveState
+ );
+ ASSERT_EFI_ERROR (Status);
+ ZeroMem (FrameworkSmst->CpuSaveState, gSmst->NumberOfCpus * sizeof (EFI_SMI_CPU_SAVE_STATE));
+
+ ///
+ /// Do not support floating point state now
+ ///
+ FrameworkSmst->CpuOptionalFloatingPointState = NULL;
+
+ FrameworkSmst->SmmInstallConfigurationTable = SmmInstallConfigurationTable;
+
+ return FrameworkSmst;
+}
+
+/**
+ Load a given Framework SMM driver into SMRAM and invoke its entry point.
+
+ @param[in] FilePath Location of the image to be installed as the handler.
+ @param[in] SourceBuffer Optional source buffer in case the image file
+ is in memory.
+ @param[in] SourceSize Size of the source image file, if in memory.
+ @param[out] ImageHandle The handle that the base driver uses to decode
+ the handler. Unique among SMM handlers only,
+ not unique across DXE/EFI.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval EFI_OUT_OF_RESOURCES There were no additional SMRAM resources to load the handler
+ @retval EFI_UNSUPPORTED Can not find its copy in normal memory.
+ @retval EFI_INVALID_PARAMETER The handlers was not the correct image type
+**/
+EFI_STATUS
+LoadImage (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN VOID *SourceBuffer,
+ IN UINTN SourceSize,
+ OUT EFI_HANDLE *ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ UINTN PageCount;
+ EFI_PHYSICAL_ADDRESS Buffer;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ EFI_HANDLE PesudoImageHandle;
+ UINTN NumHandles;
+ UINTN Index;
+ EFI_HANDLE *HandleBuffer;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ EFI_DEVICE_PATH *LoadedImageDevicePath;
+ UINTN DevicePathSize;
+
+ if (FilePath == NULL || ImageHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ///
+ /// Assume Framework SMM driver has an image copy in memory before registering itself into SMRAM.
+ /// Currently only supports load Framework SMM driver from existing image copy in memory.
+ /// Load PE32 Image Protocol can be used to support loading Framework SMM driver directly from FV.
+ ///
+ if (SourceBuffer == NULL) {
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ NULL,
+ &NumHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DevicePathSize = GetDevicePathSize (FilePath);
+
+ for (Index = 0; Index < NumHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ (VOID **)&LoadedImageDevicePath
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (GetDevicePathSize (LoadedImageDevicePath) == DevicePathSize &&
+ CompareMem (LoadedImageDevicePath, FilePath, DevicePathSize) == 0) {
+ break;
+ }
+ }
+
+ if (Index < NumHandles) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **)&LoadedImage
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ SourceBuffer = LoadedImage->ImageBase;
+ gBS->FreePool (HandleBuffer);
+ } else {
+ gBS->FreePool (HandleBuffer);
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ ImageContext.Handle = SourceBuffer;
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+
+ ///
+ /// Get information about the image being loaded
+ ///
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ///
+ /// Allocate buffer for loading image into SMRAM
+ ///
+ PageCount = (UINTN)EFI_SIZE_TO_PAGES (ImageContext.ImageSize + ImageContext.SectionAlignment);
+ Status = gSmst->SmmAllocatePages (AllocateAnyPages, EfiRuntimeServicesCode, PageCount, &Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ImageContext.ImageAddress = (PHYSICAL_ADDRESS)Buffer;
+
+ ///
+ /// Align buffer on section boundry
+ ///
+ ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
+ ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);
+
+ ///
+ /// Load the image into SMRAM
+ ///
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ ///
+ /// Relocate the image in our new buffer
+ ///
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ ///
+ /// Flush the instruction cache so the image data are written before we execute it
+ ///
+ InvalidateInstructionCacheRange ((VOID *)(UINTN) ImageContext.ImageAddress, (UINTN) ImageContext.ImageSize);
+
+ ///
+ /// Update MP state in Framework SMST before transferring control to Framework SMM driver entry point
+ /// in case it may invoke AP
+ ///
+ mFrameworkSmst->CurrentlyExecutingCpu = gSmst->CurrentlyExecutingCpu;
+
+ ///
+ /// For Framework SMM, ImageHandle does not have to be a UEFI image handle. The only requirement is that the
+ /// ImageHandle is a unique value. Use image base address as the unique value.
+ ///
+ PesudoImageHandle = (EFI_HANDLE)(UINTN)ImageContext.ImageAddress;
+
+ Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)ImageContext.EntryPoint) (PesudoImageHandle, gST);
+ if (!EFI_ERROR (Status)) {
+ *ImageHandle = PesudoImageHandle;
+ return EFI_SUCCESS;
+ }
+
+Error:
+ gSmst->SmmFreePages (Buffer, PageCount);
+ return Status;
+}
+
+/**
+ Thunk service of EFI_SMM_BASE_PROTOCOL.Register().
+
+ @param[in] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
+*/
+VOID
+Register (
+ IN OUT SMMBASE_FUNCTION_DATA *FunctionData
+ )
+{
+ EFI_STATUS Status;
+
+ if (FunctionData->Args.Register.LegacyIA32Binary) {
+ Status = EFI_UNSUPPORTED;
+ } else {
+ Status = LoadImage (
+ FunctionData->Args.Register.FilePath,
+ FunctionData->Args.Register.SourceBuffer,
+ FunctionData->Args.Register.SourceSize,
+ FunctionData->Args.Register.ImageHandle
+ );
+ }
+ FunctionData->Status = Status;
+}
+
+/**
+ Thunk service of EFI_SMM_BASE_PROTOCOL.UnRegister().
+
+ @param[in] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
+*/
+VOID
+UnRegister (
+ IN OUT SMMBASE_FUNCTION_DATA *FunctionData
+ )
+{
+ ///
+ /// Unregister not supported now
+ ///
+ FunctionData->Status = EFI_UNSUPPORTED;
+}
+
+/**
+ Search for Framework SMI handler information according to specific PI SMM dispatch handle.
+
+ @param[in] DispatchHandle The unique handle assigned by SmiHandlerRegister().
+
+ @return Pointer to CALLBACK_INFO.
+**/
+CALLBACK_INFO *
+GetCallbackInfo (
+ IN EFI_HANDLE DispatchHandle
+ )
+{
+ LIST_ENTRY *Node;
+
+ Node = GetFirstNode (&mCallbackInfoListHead);
+ while (!IsNull (&mCallbackInfoListHead, Node)) {
+ if (((CALLBACK_INFO *)Node)->DispatchHandle == DispatchHandle) {
+ return (CALLBACK_INFO *)Node;
+ }
+ Node = GetNextNode (&mCallbackInfoListHead, Node);
+ }
+ return NULL;
+}
+
+/**
+ Callback thunk for Framework SMI handler.
+
+ This thunk functions calls the Framework SMI handler and converts the return value
+ defined from Framework SMI handlers to a correpsonding return value defined by PI SMM.
+
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param[in] Context Points to an optional handler context which was specified when the
+ handler was registered.
+ @param[in,out] CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param[in,out] CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
+ should still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
+ still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
+ be called.
+ @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
+**/
+EFI_STATUS
+EFIAPI
+CallbackThunk (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ CALLBACK_INFO *CallbackInfo;
+ UINTN Index;
+ UINTN CpuIndex;
+ EFI_SMM_CPU_STATE *State;
+ EFI_SMI_CPU_SAVE_STATE *SaveState;
+
+ ///
+ /// Before transferring the control into the Framework SMI handler, update CPU Save States
+ /// and MP states in the Framework SMST.
+ ///
+
+ for (CpuIndex = 0; CpuIndex < gSmst->NumberOfCpus; CpuIndex++) {
+ State = (EFI_SMM_CPU_STATE *)gSmst->CpuSaveState[CpuIndex];
+ SaveState = &mFrameworkSmst->CpuSaveState[CpuIndex].Ia32SaveState;
+
+ if (State->x86.SMMRevId < EFI_SMM_MIN_REV_ID_x64) {
+ SaveState->SMBASE = State->x86.SMBASE;
+ SaveState->SMMRevId = State->x86.SMMRevId;
+ SaveState->IORestart = State->x86.IORestart;
+ SaveState->AutoHALTRestart = State->x86.AutoHALTRestart;
+ } else {
+ SaveState->SMBASE = State->x64.SMBASE;
+ SaveState->SMMRevId = State->x64.SMMRevId;
+ SaveState->IORestart = State->x64.IORestart;
+ SaveState->AutoHALTRestart = State->x64.AutoHALTRestart;
+ }
+
+ for (Index = 0; Index < sizeof (mCpuSaveStateConvTable) / sizeof (CPU_SAVE_STATE_CONVERSION); Index++) {
+ ///
+ /// Try to use SMM CPU Protocol to access CPU save states if possible
+ ///
+ Status = mSmmCpu->ReadSaveState (
+ mSmmCpu,
+ EFI_SMM_SAVE_STATE_IO_WIDTH_UINT32,
+ mCpuSaveStateConvTable[Index].Register,
+ CpuIndex,
+ ((UINT8 *)SaveState) + mCpuSaveStateConvTable[Index].Offset
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ mFrameworkSmst->CurrentlyExecutingCpu = gSmst->CurrentlyExecutingCpu;
+
+ ///
+ /// Search for Framework SMI handler information
+ ///
+ CallbackInfo = GetCallbackInfo (DispatchHandle);
+ ASSERT (CallbackInfo != NULL);
+
+ ///
+ /// Thunk into original Framwork SMI handler
+ ///
+ Status = (CallbackInfo->CallbackAddress) (
+ CallbackInfo->SmmImageHandle,
+ CommBuffer,
+ CommBufferSize
+ );
+ ///
+ /// Save CPU Save States in case any of them was modified
+ ///
+ for (CpuIndex = 0; CpuIndex < gSmst->NumberOfCpus; CpuIndex++) {
+ for (Index = 0; Index < sizeof (mCpuSaveStateConvTable) / sizeof (CPU_SAVE_STATE_CONVERSION); Index++) {
+ Status = mSmmCpu->WriteSaveState (
+ mSmmCpu,
+ EFI_SMM_SAVE_STATE_IO_WIDTH_UINT32,
+ mCpuSaveStateConvTable[Index].Register,
+ CpuIndex,
+ ((UINT8 *)&mFrameworkSmst->CpuSaveState[CpuIndex].Ia32SaveState) +
+ mCpuSaveStateConvTable[Index].Offset
+ );
+ }
+ }
+
+ ///
+ /// Conversion of returned status code
+ ///
+ switch (Status) {
+ case EFI_HANDLER_SUCCESS:
+ Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED;
+ break;
+ case EFI_HANDLER_CRITICAL_EXIT:
+ case EFI_HANDLER_SOURCE_QUIESCED:
+ Status = EFI_SUCCESS;
+ break;
+ case EFI_HANDLER_SOURCE_PENDING:
+ Status = EFI_WARN_INTERRUPT_SOURCE_PENDING;
+ break;
+ }
+ return Status;
+}
+
+/**
+ Thunk service of EFI_SMM_BASE_PROTOCOL.RegisterCallback().
+
+ @param[in] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
+*/
+VOID
+RegisterCallback (
+ IN OUT SMMBASE_FUNCTION_DATA *FunctionData
+ )
+{
+ EFI_STATUS Status;
+ CALLBACK_INFO *Buffer;
+
+ ///
+ /// Note that MakeLast and FloatingPointSave options are not supported in PI SMM
+ ///
+
+ ///
+ /// Allocate buffer for callback thunk information
+ ///
+ Status = gSmst->SmmAllocatePool (
+ EfiRuntimeServicesCode,
+ sizeof (CALLBACK_INFO),
+ (VOID **)&Buffer
+ );
+ if (!EFI_ERROR (Status)) {
+ ///
+ /// Fill SmmImageHandle and CallbackAddress into the thunk
+ ///
+ Buffer->SmmImageHandle = FunctionData->Args.RegisterCallback.SmmImageHandle;
+ Buffer->CallbackAddress = FunctionData->Args.RegisterCallback.CallbackAddress;
+
+ ///
+ /// Register the thunk code as a root SMI handler
+ ///
+ Status = gSmst->SmiHandlerRegister (
+ CallbackThunk,
+ NULL,
+ &Buffer->DispatchHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ ///
+ /// Save this callback info
+ ///
+ InsertTailList (&mCallbackInfoListHead, &Buffer->Link);
+ } else {
+ gSmst->SmmFreePool (Buffer);
+ }
+ }
+ FunctionData->Status = Status;
+}
+
+
+/**
+ Thunk service of EFI_SMM_BASE_PROTOCOL.SmmAllocatePool().
+
+ @param[in] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
+*/
+VOID
+HelperAllocatePool (
+ IN OUT SMMBASE_FUNCTION_DATA *FunctionData
+ )
+{
+ FunctionData->Status = gSmst->SmmAllocatePool (
+ FunctionData->Args.AllocatePool.PoolType,
+ FunctionData->Args.AllocatePool.Size,
+ FunctionData->Args.AllocatePool.Buffer
+ );
+}
+
+/**
+ Thunk service of EFI_SMM_BASE_PROTOCOL.SmmFreePool().
+
+ @param[in] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
+*/
+VOID
+HelperFreePool (
+ IN OUT SMMBASE_FUNCTION_DATA *FunctionData
+ )
+{
+ FunctionData->Status = gSmst->SmmFreePool (
+ FunctionData->Args.FreePool.Buffer
+ );
+}
+
+/**
+ Communication service SMI Handler entry.
+
+ This SMI handler provides services for the SMM Base Thunk driver.
+
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param[in] Context Points to an optional handler context which was specified when the
+ handler was registered.
+ @param[in,out] CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param[in,out] CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
+ should still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
+ still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
+ be called.
+ @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
+**/
+EFI_STATUS
+EFIAPI
+SmmHandlerEntry (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *RegisterContext,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ SMMBASE_FUNCTION_DATA *FunctionData;
+
+ ASSERT (CommBuffer != NULL);
+ ASSERT (*CommBufferSize == sizeof (SMMBASE_FUNCTION_DATA));
+
+ FunctionData = (SMMBASE_FUNCTION_DATA *)CommBuffer;
+
+ switch (FunctionData->Function) {
+ case SMMBASE_REGISTER:
+ Register (FunctionData);
+ break;
+ case SMMBASE_UNREGISTER:
+ UnRegister (FunctionData);
+ break;
+ case SMMBASE_REGISTER_CALLBACK:
+ RegisterCallback (FunctionData);
+ break;
+ case SMMBASE_ALLOCATE_POOL:
+ HelperAllocatePool (FunctionData);
+ break;
+ case SMMBASE_FREE_POOL:
+ HelperFreePool (FunctionData);
+ break;
+ default:
+ ASSERT (FALSE);
+ FunctionData->Status = EFI_UNSUPPORTED;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Entry point function of the SMM Base Helper SMM driver.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+**/
+EFI_STATUS
+EFIAPI
+SmmBaseHelperMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle = NULL;
+
+ ///
+ /// Locate SMM CPU Protocol which is used later to update CPU Save States
+ ///
+ Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **) &mSmmCpu);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Interface structure of SMM BASE Helper Ready Protocol is allocated from UEFI pool
+ /// instead of SMM pool so that SMM Base Thunk driver can access it in Non-SMM mode.
+ ///
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (EFI_SMM_BASE_HELPER_READY_PROTOCOL),
+ (VOID **)&mSmmBaseHelperReady
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Construct Framework SMST from PI SMST
+ ///
+ mFrameworkSmst = ConstructFrameworkSmst ();
+ mSmmBaseHelperReady->FrameworkSmst = mFrameworkSmst;
+ mSmmBaseHelperReady->ServiceEntry = SmmHandlerEntry;
+
+ ///
+ /// Register SMM Base Helper services for SMM Base Thunk driver
+ ///
+ Status = gSmst->SmiHandlerRegister (SmmHandlerEntry, &gEfiSmmBaseThunkCommunicationGuid, &mDispatchHandle);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Install EFI SMM Base Helper Protocol in the UEFI handle database
+ ///
+ Status = gBS->InstallProtocolInterface (
+ &Handle,
+ &gEfiSmmBaseHelperReadyProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ mSmmBaseHelperReady
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
diff --git a/EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.h b/EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.h
new file mode 100644
index 0000000000..b372f700fa
--- /dev/null
+++ b/EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.h
@@ -0,0 +1,57 @@
+/** @file
+ Include file for SMM Base Helper SMM driver.
+
+ Copyright (c) 2009, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _SMM_BASE_HELPER_H_
+#define _SMM_BASE_HELPER_H_
+
+#include <PiSmm.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Guid/SmmBaseThunkCommunication.h>
+#include <Protocol/SmmBaseHelperReady.h>
+#include <Protocol/SmmCpu.h>
+#include <Protocol/LoadedImage.h>
+#include <Common/CpuSaveState.h>
+
+///
+/// Structure for tracking paired information of registered Framework SMI handler
+/// and correpsonding dispatch handle for SMI handler thunk.
+///
+typedef struct {
+ LIST_ENTRY Link;
+ EFI_HANDLE DispatchHandle;
+ EFI_HANDLE SmmImageHandle;
+ EFI_SMM_CALLBACK_ENTRY_POINT CallbackAddress;
+} CALLBACK_INFO;
+
+typedef struct {
+ ///
+ /// PI SMM CPU Save State register index
+ ///
+ EFI_SMM_SAVE_STATE_REGISTER Register;
+ ///
+ /// Offset in Framework SMST
+ ///
+ UINTN Offset;
+} CPU_SAVE_STATE_CONVERSION;
+
+#define CPU_SAVE_STATE_GET_OFFSET(Field) (UINTN)(&(((EFI_SMM_CPU_SAVE_STATE *) 0)->Ia32SaveState.Field))
+
+#endif
diff --git a/EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.inf b/EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.inf
new file mode 100644
index 0000000000..6a12600551
--- /dev/null
+++ b/EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.inf
@@ -0,0 +1,62 @@
+## @file
+# Component description file for SMM Base Helper SMM driver.
+#
+# Copyright (c) 2009, Intel Corporation.
+#
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmBaseHelper
+ FILE_GUID = 8C87E0A0-B390-4be3-819C-7C6C83CAE4EB
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+
+ ENTRY_POINT = SmmBaseHelperMain
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmBaseHelper.c
+ SmmBaseHelper.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IA32FamilyCpuPkg/IA32FamilyCpuPkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ EdkCompatibilityPkg/EdkCompatibilityPkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ SmmServicesTableLib
+ BaseMemoryLib
+ PeCoffLib
+ DevicePathLib
+ CacheMaintenanceLib
+
+[Guids]
+ gEfiSmmBaseThunkCommunicationGuid
+
+[Protocols]
+ gEfiSmmBaseHelperReadyProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+ gEfiSmmCpuProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiLoadedImageProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiLoadedImageDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+
+[Depex]
+ gEfiSmmCpuProtocolGuid
+