+/** @file\r
+ SMM Base Helper SMM driver.\r
+\r
+ This driver is the counterpart of the SMM Base On SMM Base2 Thunk driver. It\r
+ provides helping services in SMM to the SMM Base On SMM Base2 Thunk driver.\r
+\r
+ Copyright (c) 2009, Intel Corporation\r
+ All rights reserved. This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this 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
+\r
+**/\r
+\r
+#include "SmmBaseHelper.h"\r
+\r
+EFI_HANDLE mDispatchHandle;\r
+EFI_SMM_CPU_PROTOCOL *mSmmCpu;\r
+EFI_GUID mEfiSmmCpuIoGuid = EFI_SMM_CPU_IO_GUID;\r
+EFI_SMM_BASE_HELPER_READY_PROTOCOL *mSmmBaseHelperReady;\r
+EFI_SMM_SYSTEM_TABLE *mFrameworkSmst;\r
+\r
+LIST_ENTRY mCallbackInfoListHead = INITIALIZE_LIST_HEAD_VARIABLE (mCallbackInfoListHead);\r
+\r
+CPU_SAVE_STATE_CONVERSION mCpuSaveStateConvTable[] = {\r
+ {EFI_SMM_SAVE_STATE_REGISTER_LDTBASE , CPU_SAVE_STATE_GET_OFFSET(LDTBase)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_ES , CPU_SAVE_STATE_GET_OFFSET(ES)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_CS , CPU_SAVE_STATE_GET_OFFSET(CS)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_SS , CPU_SAVE_STATE_GET_OFFSET(SS)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_DS , CPU_SAVE_STATE_GET_OFFSET(DS)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_FS , CPU_SAVE_STATE_GET_OFFSET(FS)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_GS , CPU_SAVE_STATE_GET_OFFSET(GS)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_TR_SEL , CPU_SAVE_STATE_GET_OFFSET(TR)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_DR7 , CPU_SAVE_STATE_GET_OFFSET(DR7)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_DR6 , CPU_SAVE_STATE_GET_OFFSET(DR6)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_RAX , CPU_SAVE_STATE_GET_OFFSET(EAX)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_RBX , CPU_SAVE_STATE_GET_OFFSET(EBX)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_RCX , CPU_SAVE_STATE_GET_OFFSET(ECX)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_RDX , CPU_SAVE_STATE_GET_OFFSET(EDX)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_RSP , CPU_SAVE_STATE_GET_OFFSET(ESP)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_RBP , CPU_SAVE_STATE_GET_OFFSET(EBP)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_RSI , CPU_SAVE_STATE_GET_OFFSET(ESI)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_RDI , CPU_SAVE_STATE_GET_OFFSET(EDI)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_RIP , CPU_SAVE_STATE_GET_OFFSET(EIP)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_RFLAGS , CPU_SAVE_STATE_GET_OFFSET(EFLAGS)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_CR0 , CPU_SAVE_STATE_GET_OFFSET(CR0)},\r
+ {EFI_SMM_SAVE_STATE_REGISTER_CR3 , CPU_SAVE_STATE_GET_OFFSET(CR3)}\r
+};\r
+\r
+/**\r
+ Framework SMST SmmInstallConfigurationTable() Thunk.\r
+\r
+ This thunk calls the PI SMM SmmInstallConfigurationTable() and then update the configuration\r
+ table related fields in the Framework SMST because the PI SMM SmmInstallConfigurationTable()\r
+ function may modify these fields.\r
+\r
+ @param[in] SystemTable A pointer to the SMM System Table.\r
+ @param[in] Guid A pointer to the GUID for the entry to add, update, or remove.\r
+ @param[in] Table A pointer to the buffer of the table to add.\r
+ @param[in] TableSize The size of the table to install.\r
+\r
+ @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed.\r
+ @retval EFI_INVALID_PARAMETER Guid is not valid.\r
+ @retval EFI_NOT_FOUND An attempt was made to delete a non-existent entry.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmInstallConfigurationTable (\r
+ IN EFI_SMM_SYSTEM_TABLE *SystemTable,\r
+ IN EFI_GUID *Guid,\r
+ IN VOID *Table,\r
+ IN UINTN TableSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ \r
+ Status = gSmst->SmmInstallConfigurationTable (gSmst, Guid, Table, TableSize);\r
+ if (!EFI_ERROR (Status)) {\r
+ mFrameworkSmst->NumberOfTableEntries = gSmst->NumberOfTableEntries;\r
+ mFrameworkSmst->SmmConfigurationTable = gSmst->SmmConfigurationTable;\r
+ }\r
+ return Status; \r
+}\r
+\r
+/**\r
+ Construct a Framework SMST based on the PI SMM SMST.\r
+\r
+ @return Pointer to the constructed Framework SMST.\r
+**/\r
+EFI_SMM_SYSTEM_TABLE *\r
+ConstructFrameworkSmst (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SMM_SYSTEM_TABLE *FrameworkSmst;\r
+\r
+ Status = gSmst->SmmAllocatePool (\r
+ EfiRuntimeServicesData,\r
+ sizeof (EFI_SMM_SYSTEM_TABLE),\r
+ (VOID **)&FrameworkSmst\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ ///\r
+ /// Copy same things from PI SMST to Framework SMST\r
+ ///\r
+ CopyMem (FrameworkSmst, gSmst, (UINTN)(&((EFI_SMM_SYSTEM_TABLE *)0)->SmmIo));\r
+ CopyMem (\r
+ &FrameworkSmst->SmmIo, \r
+ &gSmst->SmmIo,\r
+ sizeof (EFI_SMM_SYSTEM_TABLE) - (UINTN)(&((EFI_SMM_SYSTEM_TABLE *)0)->SmmIo)\r
+ );\r
+\r
+ ///\r
+ /// Update Framework SMST\r
+ ///\r
+ FrameworkSmst->Hdr.Revision = EFI_SMM_SYSTEM_TABLE_REVISION;\r
+ CopyGuid (&FrameworkSmst->EfiSmmCpuIoGuid, &mEfiSmmCpuIoGuid);\r
+\r
+ Status = gSmst->SmmAllocatePool (\r
+ EfiRuntimeServicesData,\r
+ gSmst->NumberOfCpus * sizeof (EFI_SMI_CPU_SAVE_STATE),\r
+ (VOID **)&FrameworkSmst->CpuSaveState\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ ZeroMem (FrameworkSmst->CpuSaveState, gSmst->NumberOfCpus * sizeof (EFI_SMI_CPU_SAVE_STATE));\r
+\r
+ ///\r
+ /// Do not support floating point state now\r
+ ///\r
+ FrameworkSmst->CpuOptionalFloatingPointState = NULL;\r
+\r
+ FrameworkSmst->SmmInstallConfigurationTable = SmmInstallConfigurationTable;\r
+\r
+ return FrameworkSmst;\r
+}\r
+\r
+/**\r
+ Load a given Framework SMM driver into SMRAM and invoke its entry point.\r
+\r
+ @param[in] FilePath Location of the image to be installed as the handler.\r
+ @param[in] SourceBuffer Optional source buffer in case the image file\r
+ is in memory.\r
+ @param[in] SourceSize Size of the source image file, if in memory.\r
+ @param[out] ImageHandle The handle that the base driver uses to decode \r
+ the handler. Unique among SMM handlers only, \r
+ not unique across DXE/EFI.\r
+\r
+ @retval EFI_SUCCESS The operation was successful.\r
+ @retval EFI_OUT_OF_RESOURCES There were no additional SMRAM resources to load the handler\r
+ @retval EFI_UNSUPPORTED Can not find its copy in normal memory.\r
+ @retval EFI_INVALID_PARAMETER The handlers was not the correct image type\r
+**/\r
+EFI_STATUS\r
+LoadImage (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
+ IN VOID *SourceBuffer,\r
+ IN UINTN SourceSize,\r
+ OUT EFI_HANDLE *ImageHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN PageCount;\r
+ EFI_PHYSICAL_ADDRESS Buffer;\r
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
+ EFI_HANDLE PesudoImageHandle;\r
+ UINTN NumHandles;\r
+ UINTN Index;\r
+ EFI_HANDLE *HandleBuffer;\r
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
+ EFI_DEVICE_PATH *LoadedImageDevicePath;\r
+ UINTN DevicePathSize;\r
+\r
+ if (FilePath == NULL || ImageHandle == NULL) { \r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ///\r
+ /// Assume Framework SMM driver has an image copy in memory before registering itself into SMRAM.\r
+ /// Currently only supports load Framework SMM driver from existing image copy in memory.\r
+ /// Load PE32 Image Protocol can be used to support loading Framework SMM driver directly from FV.\r
+ ///\r
+ if (SourceBuffer == NULL) {\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiLoadedImageDevicePathProtocolGuid,\r
+ NULL,\r
+ &NumHandles,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ DevicePathSize = GetDevicePathSize (FilePath);\r
+\r
+ for (Index = 0; Index < NumHandles; Index++) {\r
+ Status = gBS->HandleProtocol (\r
+ HandleBuffer[Index],\r
+ &gEfiLoadedImageDevicePathProtocolGuid,\r
+ (VOID **)&LoadedImageDevicePath\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ if (GetDevicePathSize (LoadedImageDevicePath) == DevicePathSize &&\r
+ CompareMem (LoadedImageDevicePath, FilePath, DevicePathSize) == 0) {\r
+ break;\r
+ } \r
+ }\r
+\r
+ if (Index < NumHandles) {\r
+ Status = gBS->HandleProtocol (\r
+ HandleBuffer[Index],\r
+ &gEfiLoadedImageProtocolGuid,\r
+ (VOID **)&LoadedImage\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ \r
+ SourceBuffer = LoadedImage->ImageBase;\r
+ gBS->FreePool (HandleBuffer);\r
+ } else {\r
+ gBS->FreePool (HandleBuffer);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+\r
+ ImageContext.Handle = SourceBuffer;\r
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
+\r
+ ///\r
+ /// Get information about the image being loaded\r
+ ///\r
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ ///\r
+ /// Allocate buffer for loading image into SMRAM\r
+ ///\r
+ PageCount = (UINTN)EFI_SIZE_TO_PAGES (ImageContext.ImageSize + ImageContext.SectionAlignment);\r
+ Status = gSmst->SmmAllocatePages (AllocateAnyPages, EfiRuntimeServicesCode, PageCount, &Buffer);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ ImageContext.ImageAddress = (PHYSICAL_ADDRESS)Buffer;\r
+\r
+ ///\r
+ /// Align buffer on section boundry\r
+ ///\r
+ ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;\r
+ ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);\r
+\r
+ ///\r
+ /// Load the image into SMRAM\r
+ ///\r
+ Status = PeCoffLoaderLoadImage (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+\r
+ ///\r
+ /// Relocate the image in our new buffer\r
+ ///\r
+ Status = PeCoffLoaderRelocateImage (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+\r
+ ///\r
+ /// Flush the instruction cache so the image data are written before we execute it\r
+ ///\r
+ InvalidateInstructionCacheRange ((VOID *)(UINTN) ImageContext.ImageAddress, (UINTN) ImageContext.ImageSize);\r
+\r
+ ///\r
+ /// Update MP state in Framework SMST before transferring control to Framework SMM driver entry point\r
+ /// in case it may invoke AP\r
+ ///\r
+ mFrameworkSmst->CurrentlyExecutingCpu = gSmst->CurrentlyExecutingCpu;\r
+\r
+ ///\r
+ /// For Framework SMM, ImageHandle does not have to be a UEFI image handle. The only requirement is that the \r
+ /// ImageHandle is a unique value. Use image base address as the unique value.\r
+ ///\r
+ PesudoImageHandle = (EFI_HANDLE)(UINTN)ImageContext.ImageAddress;\r
+\r
+ Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)ImageContext.EntryPoint) (PesudoImageHandle, gST);\r
+ if (!EFI_ERROR (Status)) {\r
+ *ImageHandle = PesudoImageHandle;\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+Error:\r
+ gSmst->SmmFreePages (Buffer, PageCount);\r
+ return Status;\r
+}\r
+\r
+/** \r
+ Thunk service of EFI_SMM_BASE_PROTOCOL.Register().\r
+\r
+ @param[in] FunctionData Pointer to SMMBASE_FUNCTION_DATA.\r
+*/\r
+VOID\r
+Register (\r
+ IN OUT SMMBASE_FUNCTION_DATA *FunctionData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if (FunctionData->Args.Register.LegacyIA32Binary) {\r
+ Status = EFI_UNSUPPORTED;\r
+ } else {\r
+ Status = LoadImage (\r
+ FunctionData->Args.Register.FilePath,\r
+ FunctionData->Args.Register.SourceBuffer,\r
+ FunctionData->Args.Register.SourceSize,\r
+ FunctionData->Args.Register.ImageHandle\r
+ );\r
+ }\r
+ FunctionData->Status = Status;\r
+}\r
+\r
+/** \r
+ Thunk service of EFI_SMM_BASE_PROTOCOL.UnRegister().\r
+\r
+ @param[in] FunctionData Pointer to SMMBASE_FUNCTION_DATA.\r
+*/\r
+VOID\r
+UnRegister (\r
+ IN OUT SMMBASE_FUNCTION_DATA *FunctionData\r
+ )\r
+{\r
+ ///\r
+ /// Unregister not supported now\r
+ ///\r
+ FunctionData->Status = EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ Search for Framework SMI handler information according to specific PI SMM dispatch handle.\r
+\r
+ @param[in] DispatchHandle The unique handle assigned by SmiHandlerRegister(). \r
+\r
+ @return Pointer to CALLBACK_INFO.\r
+**/\r
+CALLBACK_INFO *\r
+GetCallbackInfo (\r
+ IN EFI_HANDLE DispatchHandle\r
+ )\r
+{\r
+ LIST_ENTRY *Node;\r
+\r
+ Node = GetFirstNode (&mCallbackInfoListHead);\r
+ while (!IsNull (&mCallbackInfoListHead, Node)) {\r
+ if (((CALLBACK_INFO *)Node)->DispatchHandle == DispatchHandle) {\r
+ return (CALLBACK_INFO *)Node;\r
+ }\r
+ Node = GetNextNode (&mCallbackInfoListHead, Node);\r
+ }\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Callback thunk for Framework SMI handler.\r
+\r
+ This thunk functions calls the Framework SMI handler and converts the return value\r
+ defined from Framework SMI handlers to a correpsonding return value defined by PI SMM.\r
+\r
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
+ @param[in] Context Points to an optional handler context which was specified when the\r
+ handler was registered.\r
+ @param[in,out] CommBuffer A pointer to a collection of data in memory that will\r
+ be conveyed from a non-SMM environment into an SMM environment.\r
+ @param[in,out] CommBufferSize The size of the CommBuffer.\r
+\r
+ @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers \r
+ should still be called.\r
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should \r
+ still be called.\r
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still \r
+ be called.\r
+ @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CallbackThunk (\r
+ IN EFI_HANDLE DispatchHandle,\r
+ IN CONST VOID *Context OPTIONAL,\r
+ IN OUT VOID *CommBuffer OPTIONAL,\r
+ IN OUT UINTN *CommBufferSize OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CALLBACK_INFO *CallbackInfo;\r
+ UINTN Index;\r
+ UINTN CpuIndex;\r
+ EFI_SMM_CPU_STATE *State;\r
+ EFI_SMI_CPU_SAVE_STATE *SaveState;\r
+\r
+ ///\r
+ /// Before transferring the control into the Framework SMI handler, update CPU Save States\r
+ /// and MP states in the Framework SMST.\r
+ ///\r
+\r
+ for (CpuIndex = 0; CpuIndex < gSmst->NumberOfCpus; CpuIndex++) {\r
+ State = (EFI_SMM_CPU_STATE *)gSmst->CpuSaveState[CpuIndex];\r
+ SaveState = &mFrameworkSmst->CpuSaveState[CpuIndex].Ia32SaveState;\r
+\r
+ if (State->x86.SMMRevId < EFI_SMM_MIN_REV_ID_x64) {\r
+ SaveState->SMBASE = State->x86.SMBASE;\r
+ SaveState->SMMRevId = State->x86.SMMRevId;\r
+ SaveState->IORestart = State->x86.IORestart;\r
+ SaveState->AutoHALTRestart = State->x86.AutoHALTRestart;\r
+ } else {\r
+ SaveState->SMBASE = State->x64.SMBASE;\r
+ SaveState->SMMRevId = State->x64.SMMRevId;\r
+ SaveState->IORestart = State->x64.IORestart;\r
+ SaveState->AutoHALTRestart = State->x64.AutoHALTRestart;\r
+ }\r
+\r
+ for (Index = 0; Index < sizeof (mCpuSaveStateConvTable) / sizeof (CPU_SAVE_STATE_CONVERSION); Index++) {\r
+ ///\r
+ /// Try to use SMM CPU Protocol to access CPU save states if possible\r
+ ///\r
+ Status = mSmmCpu->ReadSaveState (\r
+ mSmmCpu,\r
+ EFI_SMM_SAVE_STATE_IO_WIDTH_UINT32,\r
+ mCpuSaveStateConvTable[Index].Register,\r
+ CpuIndex,\r
+ ((UINT8 *)SaveState) + mCpuSaveStateConvTable[Index].Offset\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ }\r
+\r
+ mFrameworkSmst->CurrentlyExecutingCpu = gSmst->CurrentlyExecutingCpu;\r
+\r
+ ///\r
+ /// Search for Framework SMI handler information\r
+ ///\r
+ CallbackInfo = GetCallbackInfo (DispatchHandle);\r
+ ASSERT (CallbackInfo != NULL);\r
+\r
+ ///\r
+ /// Thunk into original Framwork SMI handler\r
+ ///\r
+ Status = (CallbackInfo->CallbackAddress) (\r
+ CallbackInfo->SmmImageHandle,\r
+ CommBuffer,\r
+ CommBufferSize\r
+ );\r
+ ///\r
+ /// Save CPU Save States in case any of them was modified\r
+ ///\r
+ for (CpuIndex = 0; CpuIndex < gSmst->NumberOfCpus; CpuIndex++) {\r
+ for (Index = 0; Index < sizeof (mCpuSaveStateConvTable) / sizeof (CPU_SAVE_STATE_CONVERSION); Index++) {\r
+ Status = mSmmCpu->WriteSaveState (\r
+ mSmmCpu,\r
+ EFI_SMM_SAVE_STATE_IO_WIDTH_UINT32,\r
+ mCpuSaveStateConvTable[Index].Register,\r
+ CpuIndex,\r
+ ((UINT8 *)&mFrameworkSmst->CpuSaveState[CpuIndex].Ia32SaveState) + \r
+ mCpuSaveStateConvTable[Index].Offset\r
+ );\r
+ }\r
+ }\r
+\r
+ ///\r
+ /// Conversion of returned status code\r
+ ///\r
+ switch (Status) {\r
+ case EFI_HANDLER_SUCCESS:\r
+ Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED;\r
+ break;\r
+ case EFI_HANDLER_CRITICAL_EXIT:\r
+ case EFI_HANDLER_SOURCE_QUIESCED:\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+ case EFI_HANDLER_SOURCE_PENDING:\r
+ Status = EFI_WARN_INTERRUPT_SOURCE_PENDING;\r
+ break;\r
+ }\r
+ return Status;\r
+}\r
+\r
+/** \r
+ Thunk service of EFI_SMM_BASE_PROTOCOL.RegisterCallback().\r
+\r
+ @param[in] FunctionData Pointer to SMMBASE_FUNCTION_DATA.\r
+*/\r
+VOID\r
+RegisterCallback (\r
+ IN OUT SMMBASE_FUNCTION_DATA *FunctionData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CALLBACK_INFO *Buffer;\r
+\r
+ ///\r
+ /// Note that MakeLast and FloatingPointSave options are not supported in PI SMM\r
+ ///\r
+\r
+ ///\r
+ /// Allocate buffer for callback thunk information\r
+ ///\r
+ Status = gSmst->SmmAllocatePool (\r
+ EfiRuntimeServicesCode,\r
+ sizeof (CALLBACK_INFO),\r
+ (VOID **)&Buffer\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ ///\r
+ /// Fill SmmImageHandle and CallbackAddress into the thunk\r
+ ///\r
+ Buffer->SmmImageHandle = FunctionData->Args.RegisterCallback.SmmImageHandle;\r
+ Buffer->CallbackAddress = FunctionData->Args.RegisterCallback.CallbackAddress;\r
+\r
+ ///\r
+ /// Register the thunk code as a root SMI handler\r
+ ///\r
+ Status = gSmst->SmiHandlerRegister (\r
+ CallbackThunk,\r
+ NULL,\r
+ &Buffer->DispatchHandle\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ ///\r
+ /// Save this callback info\r
+ ///\r
+ InsertTailList (&mCallbackInfoListHead, &Buffer->Link);\r
+ } else {\r
+ gSmst->SmmFreePool (Buffer);\r
+ }\r
+ }\r
+ FunctionData->Status = Status;\r
+}\r
+\r
+\r
+/** \r
+ Thunk service of EFI_SMM_BASE_PROTOCOL.SmmAllocatePool().\r
+\r
+ @param[in] FunctionData Pointer to SMMBASE_FUNCTION_DATA.\r
+*/\r
+VOID\r
+HelperAllocatePool (\r
+ IN OUT SMMBASE_FUNCTION_DATA *FunctionData\r
+ )\r
+{\r
+ FunctionData->Status = gSmst->SmmAllocatePool (\r
+ FunctionData->Args.AllocatePool.PoolType,\r
+ FunctionData->Args.AllocatePool.Size,\r
+ FunctionData->Args.AllocatePool.Buffer\r
+ );\r
+}\r
+\r
+/** \r
+ Thunk service of EFI_SMM_BASE_PROTOCOL.SmmFreePool().\r
+\r
+ @param[in] FunctionData Pointer to SMMBASE_FUNCTION_DATA.\r
+*/\r
+VOID\r
+HelperFreePool (\r
+ IN OUT SMMBASE_FUNCTION_DATA *FunctionData\r
+ )\r
+{\r
+ FunctionData->Status = gSmst->SmmFreePool (\r
+ FunctionData->Args.FreePool.Buffer\r
+ );\r
+}\r
+\r
+/**\r
+ Communication service SMI Handler entry.\r
+\r
+ This SMI handler provides services for the SMM Base Thunk driver.\r
+\r
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
+ @param[in] Context Points to an optional handler context which was specified when the\r
+ handler was registered.\r
+ @param[in,out] CommBuffer A pointer to a collection of data in memory that will\r
+ be conveyed from a non-SMM environment into an SMM environment.\r
+ @param[in,out] CommBufferSize The size of the CommBuffer.\r
+\r
+ @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers \r
+ should still be called.\r
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should \r
+ still be called.\r
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still \r
+ be called.\r
+ @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmHandlerEntry (\r
+ IN EFI_HANDLE DispatchHandle,\r
+ IN CONST VOID *RegisterContext,\r
+ IN OUT VOID *CommBuffer,\r
+ IN OUT UINTN *CommBufferSize\r
+ )\r
+{\r
+ SMMBASE_FUNCTION_DATA *FunctionData;\r
+\r
+ ASSERT (CommBuffer != NULL);\r
+ ASSERT (*CommBufferSize == sizeof (SMMBASE_FUNCTION_DATA));\r
+\r
+ FunctionData = (SMMBASE_FUNCTION_DATA *)CommBuffer;\r
+\r
+ switch (FunctionData->Function) {\r
+ case SMMBASE_REGISTER:\r
+ Register (FunctionData);\r
+ break;\r
+ case SMMBASE_UNREGISTER:\r
+ UnRegister (FunctionData);\r
+ break;\r
+ case SMMBASE_REGISTER_CALLBACK:\r
+ RegisterCallback (FunctionData);\r
+ break;\r
+ case SMMBASE_ALLOCATE_POOL:\r
+ HelperAllocatePool (FunctionData);\r
+ break;\r
+ case SMMBASE_FREE_POOL:\r
+ HelperFreePool (FunctionData);\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ FunctionData->Status = EFI_UNSUPPORTED;\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Entry point function of the SMM Base Helper SMM driver.\r
+\r
+ @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
+ @param[in] SystemTable A pointer to the EFI System Table.\r
+ \r
+ @retval EFI_SUCCESS The entry point is executed successfully.\r
+ @retval other Some error occurs when executing this entry point.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmBaseHelperMain (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE Handle = NULL;\r
+\r
+ ///\r
+ /// Locate SMM CPU Protocol which is used later to update CPU Save States\r
+ ///\r
+ Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **) &mSmmCpu);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ ///\r
+ /// Interface structure of SMM BASE Helper Ready Protocol is allocated from UEFI pool\r
+ /// instead of SMM pool so that SMM Base Thunk driver can access it in Non-SMM mode.\r
+ ///\r
+ Status = gBS->AllocatePool (\r
+ EfiBootServicesData,\r
+ sizeof (EFI_SMM_BASE_HELPER_READY_PROTOCOL),\r
+ (VOID **)&mSmmBaseHelperReady\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ ///\r
+ /// Construct Framework SMST from PI SMST\r
+ ///\r
+ mFrameworkSmst = ConstructFrameworkSmst ();\r
+ mSmmBaseHelperReady->FrameworkSmst = mFrameworkSmst;\r
+ mSmmBaseHelperReady->ServiceEntry = SmmHandlerEntry;\r
+\r
+ ///\r
+ /// Register SMM Base Helper services for SMM Base Thunk driver\r
+ ///\r
+ Status = gSmst->SmiHandlerRegister (SmmHandlerEntry, &gEfiSmmBaseThunkCommunicationGuid, &mDispatchHandle);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ ///\r
+ /// Install EFI SMM Base Helper Protocol in the UEFI handle database\r
+ ///\r
+ Status = gBS->InstallProtocolInterface (\r
+ &Handle,\r
+ &gEfiSmmBaseHelperReadyProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ mSmmBaseHelperReady\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r
+\r