summaryrefslogtreecommitdiff
path: root/Core/EM/SMM/SmmCommunicate.c
diff options
context:
space:
mode:
authorraywu <raywu0301@gmail.com>2018-06-15 00:00:50 +0800
committerraywu <raywu0301@gmail.com>2018-06-15 00:00:50 +0800
commitb7c51c9cf4864df6aabb99a1ae843becd577237c (patch)
treeeebe9b0d0ca03062955223097e57da84dd618b9a /Core/EM/SMM/SmmCommunicate.c
downloadzprj-b7c51c9cf4864df6aabb99a1ae843becd577237c.tar.xz
init. 1AQQW051HEADmaster
Diffstat (limited to 'Core/EM/SMM/SmmCommunicate.c')
-rw-r--r--Core/EM/SMM/SmmCommunicate.c462
1 files changed, 462 insertions, 0 deletions
diff --git a/Core/EM/SMM/SmmCommunicate.c b/Core/EM/SMM/SmmCommunicate.c
new file mode 100644
index 0000000..929118e
--- /dev/null
+++ b/Core/EM/SMM/SmmCommunicate.c
@@ -0,0 +1,462 @@
+//*************************************************************************
+//*************************************************************************
+//** **
+//** (C)Copyright 1985-2011 American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//*************************************************************************
+//*************************************************************************
+
+//**********************************************************************
+// $Header: /Alaska/SOURCE/Modules/SMM/SmmCommunicate/SmmCommunicate.c 5 3/22/12 11:38a Markw $
+//
+// $Revision: 5 $
+//
+// $Date: 3/22/12 11:38a $
+//**********************************************************************
+// Revision History
+// ----------------
+// $Log: /Alaska/SOURCE/Modules/SMM/SmmCommunicate/SmmCommunicate.c $
+//
+// 5 3/22/12 11:38a Markw
+// [TAG] EIP84198
+// [Category] Bug Fix
+// [Severity] Important
+// [Symptom] Using SMM Communication can cause OS to hang
+// [RootCause] SMM Communication Protocol’s Communicate API does not
+// function in UEFI OS after Exit boot services event because
+// ConvertPointer() did not convert SMM_COMMUNICATE_DATA *gCommunicateData
+// pointer from a Physical Memory Map Pointer to a Virtual Memory Map
+// Pointer. gCommunicateData is allocated in EfiACPIMemoryNVS.
+// [Solution] Allocate memory gCommunicateData as Runtime Services Data.
+// [Files] SmmCommunicate.c
+//
+// 4 10/03/11 3:56p Markw
+// Use tokens for SW SMI. Comment publishing ACPI table until ready.
+// Files: SmmCommunicate.sdl, SmmCommunicate.c
+//
+// 3 9/14/11 11:30a Markw
+// Add comment for pRS->GetVariable in CommunicateCallback, and in SMM
+// Communcate generating SW SMI.
+//
+// 2 9/12/11 9:58a Markw
+// [TAG] EIP64115
+// [Category] Bug Fix
+// [Severity] Normal
+// [Symptom] SmmCommuncate hangs in OS.
+// [RootCause] SMM Communciate not available in OS.
+// [Solution] Update SMM Communicate to work under OS by making it a
+// runtime driver and converting pointers to virtual points on
+// EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
+//
+// [Files] SmmCommunicate.c, SmmCommunicate.mak
+//
+// 1 4/18/11 12:03p Markw
+// [TAG] EIP57440
+// [Category] New Feature
+// [Description] Add SMM PI 1.1 Communicate Support.
+// [Files] SmmCommunicate.cif
+// SmmCommunicate.sdl
+// SmmCommunicate.c
+// SmmCommunicate.dxs
+// SmmDxeCommunicate.dxs
+// SmmCommunicate.mak
+//
+//
+//**********************************************************************
+
+//<AMI_FHDR_START>
+//---------------------------------------------------------------------------
+//
+// Name: SmmCommunicate.c
+//
+// Description: Provide SMM Communicate Protocol
+//
+//---------------------------------------------------------------------------
+//<AMI_FHDR_END>
+
+#include <Efi.h>
+#include <Acpi.h>
+#include <AmiDxeLib.h>
+#include <SmmPi.h>
+#include <Protocol\SmmBase2.h>
+#include <Protocol\SmmCommunication.h>
+#include <Protocol\SmmSwDispatch2.h>
+#include <Protocol\AcpiSupport.h>
+#include <Protocol\AmiInternalSmmComm.h>
+#include <Token.h>
+
+typedef struct {
+ VOID *CommBuffer;
+ UINTN *CommSize;
+ EFI_STATUS Status;
+} SMM_COMMUNICATE_DATA;
+
+#define SMM_COMMUNICATE_DATA_VARIABLE L"SMM_COMMUNICATE_DATA"
+
+// {08F10CB6-3131-4919-9D70-5C8A17366EE8}
+#define SMM_COMMUNICATE_DATA_GUID \
+ {0x8f10cb6, 0x3131, 0x4919, 0x9d, 0x70, 0x5c, 0x8a, 0x17, 0x36, 0x6e, 0xe8}
+
+EFI_HANDLE gImageHandle;
+
+EFI_GUID gEfiSmmBase2ProtocolGuid = EFI_SMM_BASE2_PROTOCOL_GUID;
+EFI_GUID gEfiSmmCommunicationProtocolGuid = EFI_SMM_COMMUNICATION_PROTOCOL_GUID;
+EFI_GUID gAmiIntSmmCommProtocolGuid = AMI_INT_SMM_COMM_PROTOCOL_GUID;
+EFI_GUID gSmmCommunicateDataGuid = SMM_COMMUNICATE_DATA_GUID;
+EFI_GUID gEfiAcpiSupportGuid = EFI_ACPI_SUPPORT_GUID;
+
+
+EFI_SMM_BASE2_PROTOCOL *gSmmBase2;
+
+
+SMM_COMMUNICATE_DATA *gCommunicateData = NULL;
+
+/////////////////////SMM//////////////////
+EFI_GUID gEfiSmmSwDispatch2ProtocolGuid = EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID;
+
+EFI_SMM_SW_DISPATCH2_PROTOCOL *gSmmSw2;
+EFI_SMM_SYSTEM_TABLE2 *Smst2;
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: CommunicateCallBack
+//
+// Description: Sw SMI callback to call communicate functions.
+//
+// Input:
+// IN EFI_HANDLE DispatchHandle - Unused
+// IN CONST VOID *Context OPTIONAL - Unused
+// IN OUT VOID *CommBuffer OPTIONAL - Unused
+// IN OUT UINTN *CommBufferSize OPTIONAL - Unused
+//
+// Output: EFI_STATUS
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS CommunicateCallBack(
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+)
+{
+ EFI_SMM_COMMUNICATE_HEADER *Header;
+ EFI_STATUS Status;
+
+ if (gCommunicateData == NULL) {
+ UINTN VariableSize = sizeof(EFI_SMM_COMMUNICATE_HEADER*);
+
+ //SMM_COMMUNICATE_DATA_VARIABLE variable is not available during
+ // SMM entry. When this variable is set in DXE before BDS,
+ // a SW SMI is executed, and gCommunicateData is initialized
+ // before SMM Communciate protocol is published.
+ Status = pRS->GetVariable(
+ SMM_COMMUNICATE_DATA_VARIABLE,
+ &gSmmCommunicateDataGuid,
+ NULL,
+ &VariableSize,
+ &gCommunicateData
+ );
+ ASSERT_EFI_ERROR(Status);
+ if (!EFI_ERROR(Status)) gCommunicateData->Status = Status;
+ return EFI_SUCCESS;
+ }
+
+ if (gCommunicateData->CommBuffer == NULL) {
+ gCommunicateData->Status = EFI_INVALID_PARAMETER;
+ return EFI_SUCCESS;
+ }
+
+ gCommunicateData->Status = EFI_NOT_FOUND; //Default no handler found.
+
+ Header = (EFI_SMM_COMMUNICATE_HEADER*)(gCommunicateData->CommBuffer);
+ Status = Smst2->SmiManage(&Header->HeaderGuid, NULL, Header->Data, &Header->MessageLength);
+
+ //Default Status of SmiManage is EFI_INTERRUPT_PENDING. Thus, no handler found.
+ if (Status != EFI_INTERRUPT_PENDING) gCommunicateData->Status = EFI_SUCCESS;
+ return EFI_SUCCESS;
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: InitSmm
+//
+// Description: Initialize SMM part of SMM Communicate.
+//
+// Input: VOID
+//
+// Output: EFI_STATUS
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS InitSmm()
+{
+ EFI_STATUS Status;
+ EFI_SMM_SW_REGISTER_CONTEXT RegisterContext = {SMM_COMM_SW_SMI};
+ EFI_HANDLE ImageHandle = NULL;
+ EFI_HANDLE DispatchHandle;
+
+ Status = gSmmBase2->GetSmstLocation(gSmmBase2, &Smst2);
+ ASSERT_EFI_ERROR(Status);
+
+ Status = Smst2->SmmLocateProtocol(&gEfiSmmSwDispatch2ProtocolGuid, NULL, &gSmmSw2);
+ ASSERT_EFI_ERROR(Status);
+
+ Status = gSmmSw2->Register(
+ gSmmSw2,
+ CommunicateCallBack,
+ &RegisterContext,
+ &DispatchHandle
+ );
+ ASSERT_EFI_ERROR(Status);
+ if (EFI_ERROR(Status)) return Status;
+
+
+//Signal that Handler is ready
+ Status = pBS->InstallMultipleProtocolInterfaces(
+ &ImageHandle,
+ &gAmiIntSmmCommProtocolGuid, NULL,
+ NULL
+ );
+
+ return Status;
+}
+
+
+/////////////////////ACPI//////////////////
+
+#pragma pack(push, 1)
+typedef struct {
+ ACPI_HDR Hdr;
+ EFI_GUID Identifier;
+ UINT16 DataOffset;
+ UINT32 SwSmi;
+ UINT64 BufferPtr;
+} ACPI_SMM_COMM_TABLE;
+#pragma pack(pop)
+
+ACPI_SMM_COMM_TABLE gAcpiSmmCommTable =
+{
+ 'UEFI',
+ sizeof(ACPI_SMM_COMM_TABLE),
+ 1, //Revision
+ 0, //Checksum
+ CONVERT_TO_STRING(T_ACPI_OEM_ID),
+ CONVERT_TO_STRING(T_ACPI_OEM_TBL_ID),
+ ACPI_OEM_REV,
+ 0, //Creator ID
+ 0, //Creator Revision,
+ EFI_SMM_COMMUNICATION_PROTOCOL_GUID,
+ EFI_FIELD_OFFSET(ACPI_SMM_COMM_TABLE, SwSmi),
+ SMM_COMM_SW_SMI,
+ 0
+};
+
+EFI_ACPI_SUPPORT_PROTOCOL *gAcpiSupport;
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: InitAcpi
+//
+// Description: Initialize Acpi SMM Communicate part.
+//
+// Input: VOID
+//
+// Output: EFI_STATUS
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS InitAcpi()
+{
+//TODO: Proper support for ACPI SMM communicate will be in SMM label 45.
+#if 0
+ EFI_STATUS Status;
+ UINTN AcpiHandle = 0;
+
+ Status = pBS->LocateProtocol(&gEfiAcpiSupportGuid, NULL, &gAcpiSupport);
+ ASSERT_EFI_ERROR(Status);
+ if (EFI_ERROR(Status)) return Status;
+
+ Status = gAcpiSupport->SetAcpiTable(
+ gAcpiSupport,
+ &gAcpiSmmCommTable,
+ TRUE,
+ EFI_ACPI_TABLE_VERSION_ALL,
+ &AcpiHandle
+ );
+ ASSERT_EFI_ERROR(Status);
+ if (EFI_ERROR(Status)) return Status;
+#endif
+
+ return EFI_SUCCESS;
+}
+
+/////////////////////DXE//////////////////
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: SmmCommunicate
+//
+// Description: SmmCommunicate Protocol function. This will generate SW SMI.
+//
+// Input:
+// IN CONST EFI_SMM_COMMUNICATION_PROTOCOL *This,
+// IN OUT VOID *CommBuffer,
+// IN OUT UINTN *CommSize
+//
+// Output: EFI_STATUS
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS SmmCommunicate(
+ IN CONST EFI_SMM_COMMUNICATION_PROTOCOL *This,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommSize
+)
+{
+ gCommunicateData->CommBuffer = CommBuffer;
+ gCommunicateData->CommSize = CommSize;
+ gCommunicateData->Status = EFI_DEVICE_ERROR; //Pre-initialize status in case SMI doesn't happen.
+
+ //Execute SW SMI to initialize
+ IoWrite8(SW_SMI_IO_ADDRESS, SMM_COMM_SW_SMI);
+
+ return gCommunicateData->Status;
+}
+
+EFI_SMM_COMMUNICATION_PROTOCOL gEfiSmmCommunicationProtocol = {
+ SmmCommunicate
+};
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: VirtAddrChg
+//
+// Description: Change pointer of gCommunicateData to virtual address.
+//
+// Input:
+// IN EFI_EVENT Event
+// IN VOID *Context
+//
+// Output: VOID
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID VirtAddrChg(IN EFI_EVENT Event, IN VOID *Context)
+{
+ pRS->ConvertPointer(0, (VOID**)&gCommunicateData);
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: InitDxe
+//
+// Description: Initialize DXE SMM Communicate part.
+//
+// Input: VOID
+//
+// Output: EFI_STATUS
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS InitDxe()
+{
+ EFI_STATUS Status;
+ EFI_EVENT VirtAddrChgEvt;
+
+ Status = pBS->AllocatePool(EfiRuntimeServicesData, sizeof(SMM_COMMUNICATE_DATA), &gCommunicateData);
+ ASSERT_EFI_ERROR(Status);
+
+ //Pass gCommunicateData to SMM Dispatcher.
+ gCommunicateData->Status = EFI_DEVICE_ERROR; //Pre-initialize status in case SMI doesn't happen.
+
+ //Set Value
+ Status = pRS->SetVariable(
+ SMM_COMMUNICATE_DATA_VARIABLE,
+ &gSmmCommunicateDataGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof(SMM_COMMUNICATE_DATA*),
+ &gCommunicateData
+ );
+
+ IoWrite8(SW_SMI_IO_ADDRESS, SMM_COMM_SW_SMI);
+
+ if (gCommunicateData->Status == EFI_DEVICE_ERROR) return EFI_DEVICE_ERROR;
+
+ InitAcpi();
+
+ Status = pBS->CreateEvent(
+ EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
+ TPL_CALLBACK,
+ &VirtAddrChg,
+ NULL,
+ &VirtAddrChgEvt
+ );
+ ASSERT_EFI_ERROR(Status);
+
+
+ Status = pBS->InstallMultipleProtocolInterfaces(
+ &gImageHandle,
+ &gEfiSmmCommunicationProtocolGuid, &gEfiSmmCommunicationProtocol,
+ NULL
+ );
+
+ return Status;
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: SmmCommunicateEntry
+//
+// Description: Smm Communciation entry point to initialize provide SMM Communicate Protocol.
+//
+// Input:
+// IN EFI_HANDLE ImageHandle,
+// IN EFI_SYSTEM_TABLE *SystemTable
+//
+// Output: EFI_STATUS
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS SmmCommunicateEntry(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+)
+{
+ EFI_STATUS Status;
+ BOOLEAN InSmram;
+
+ InitAmiLib(ImageHandle,SystemTable);
+
+ gImageHandle = ImageHandle;
+
+ Status = pBS->LocateProtocol(&gEfiSmmBase2ProtocolGuid, NULL, &gSmmBase2);
+ ASSERT_EFI_ERROR(Status);
+
+ Status = gSmmBase2->InSmm(gSmmBase2, &InSmram);
+ ASSERT_EFI_ERROR(Status);
+
+ if (InSmram) return InitSmm();
+ return InitDxe();
+}