/** @file | |
PiSmmCommunication SMM Driver. | |
Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR> | |
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 <PiSmm.h> | |
#include <Library/UefiDriverEntryPoint.h> | |
#include <Library/UefiBootServicesTableLib.h> | |
#include <Library/UefiRuntimeServicesTableLib.h> | |
#include <Library/SmmServicesTableLib.h> | |
#include <Library/BaseLib.h> | |
#include <Library/BaseMemoryLib.h> | |
#include <Library/HobLib.h> | |
#include <Library/DebugLib.h> | |
#include <Library/SmmMemLib.h> | |
#include <Library/PcdLib.h> | |
#include <Protocol/SmmSwDispatch2.h> | |
#include <Protocol/SmmReadyToLock.h> | |
#include <Protocol/SmmCommunication.h> | |
#include <Protocol/AcpiTable.h> | |
#include <Ppi/SmmCommunication.h> | |
#include <Guid/Acpi.h> | |
#include "PiSmmCommunicationPrivate.h" | |
EFI_SMM_COMMUNICATION_CONTEXT mSmmCommunicationContext = { | |
SMM_COMMUNICATION_SIGNATURE | |
}; | |
EFI_SMM_COMMUNICATION_ACPI_TABLE mSmmCommunicationAcpiTable = { | |
{ | |
{ | |
EFI_ACPI_4_0_UEFI_ACPI_DATA_TABLE_SIGNATURE, | |
sizeof (EFI_SMM_COMMUNICATION_ACPI_TABLE), | |
0x1, // Revision | |
0x0, // Checksum | |
{0x0}, // OemId[6] | |
0x0, // OemTableId | |
0x0, // OemRevision | |
0x0, // CreatorId | |
0x0 // CreatorRevision | |
}, | |
{0x0}, // Identifier | |
OFFSET_OF (EFI_SMM_COMMUNICATION_ACPI_TABLE, SwSmiNumber) // DataOffset | |
}, | |
0x0, // SwSmiNumber | |
0x0 // BufferPtrAddress | |
}; | |
/** | |
Set SMM communication context. | |
**/ | |
VOID | |
SetCommunicationContext ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
Status = gSmst->SmmInstallConfigurationTable ( | |
gSmst, | |
&gEfiPeiSmmCommunicationPpiGuid, | |
&mSmmCommunicationContext, | |
sizeof(mSmmCommunicationContext) | |
); | |
ASSERT_EFI_ERROR (Status); | |
} | |
/** | |
Dispatch function for a Software SMI handler. | |
@param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). | |
@param Context Points to an optional handler context which was specified when the | |
handler was registered. | |
@param CommBuffer A pointer to a collection of data in memory that will | |
be conveyed from a non-SMM environment into an SMM environment. | |
@param CommBufferSize The size of the CommBuffer. | |
@retval EFI_SUCCESS Command is handled successfully. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
PiSmmCommunicationHandler ( | |
IN EFI_HANDLE DispatchHandle, | |
IN CONST VOID *Context OPTIONAL, | |
IN OUT VOID *CommBuffer OPTIONAL, | |
IN OUT UINTN *CommBufferSize OPTIONAL | |
) | |
{ | |
UINTN CommSize; | |
EFI_STATUS Status; | |
EFI_SMM_COMMUNICATE_HEADER *CommunicateHeader; | |
EFI_PHYSICAL_ADDRESS *BufferPtrAddress; | |
DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Enter\n")); | |
BufferPtrAddress = (EFI_PHYSICAL_ADDRESS *)(UINTN)mSmmCommunicationContext.BufferPtrAddress; | |
CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)(UINTN)*BufferPtrAddress; | |
DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateHeader - %x\n", CommunicateHeader)); | |
if (CommunicateHeader == NULL) { | |
DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler is NULL, needn't to call dispatch function\n")); | |
Status = EFI_SUCCESS; | |
} else { | |
if (!SmmIsBufferOutsideSmmValid ((UINTN)CommunicateHeader, OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data))) { | |
DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateHeader invalid - 0x%x\n", CommunicateHeader)); | |
Status = EFI_SUCCESS; | |
goto Done; | |
} | |
CommSize = (UINTN)CommunicateHeader->MessageLength; | |
if (!SmmIsBufferOutsideSmmValid ((UINTN)&CommunicateHeader->Data[0], CommSize)) { | |
DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateData invalid - 0x%x\n", &CommunicateHeader->Data[0])); | |
Status = EFI_SUCCESS; | |
goto Done; | |
} | |
// | |
// Call dispatch function | |
// | |
DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Data - %x\n", &CommunicateHeader->Data[0])); | |
Status = gSmst->SmiManage ( | |
&CommunicateHeader->HeaderGuid, | |
NULL, | |
&CommunicateHeader->Data[0], | |
&CommSize | |
); | |
} | |
Done: | |
DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler %r\n", Status)); | |
DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Exit\n")); | |
return (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_INTERRUPT_PENDING; | |
} | |
/** | |
Allocate EfiACPIMemoryNVS below 4G memory address. | |
This function allocates EfiACPIMemoryNVS below 4G memory address. | |
@param Size Size of memory to allocate. | |
@return Allocated address for output. | |
**/ | |
VOID* | |
AllocateAcpiNvsMemoryBelow4G ( | |
IN UINTN Size | |
) | |
{ | |
UINTN Pages; | |
EFI_PHYSICAL_ADDRESS Address; | |
EFI_STATUS Status; | |
VOID* Buffer; | |
Pages = EFI_SIZE_TO_PAGES (Size); | |
Address = 0xffffffff; | |
Status = gBS->AllocatePages ( | |
AllocateMaxAddress, | |
EfiACPIMemoryNVS, | |
Pages, | |
&Address | |
); | |
ASSERT_EFI_ERROR (Status); | |
Buffer = (VOID *) (UINTN) Address; | |
ZeroMem (Buffer, Size); | |
return Buffer; | |
} | |
/** | |
Entry Point for PI SMM communication SMM driver. | |
@param[in] ImageHandle Image handle of this driver. | |
@param[in] SystemTable A Pointer to the EFI System Table. | |
@retval EFI_SUCEESS | |
@return Others Some error occurs. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
PiSmmCommunicationSmmEntryPoint ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_SMM_SW_DISPATCH2_PROTOCOL *SmmSwDispatch2; | |
EFI_SMM_SW_REGISTER_CONTEXT SmmSwDispatchContext; | |
EFI_HANDLE DispatchHandle; | |
EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol; | |
UINTN TableKey; | |
UINT64 OemTableId; | |
EFI_PHYSICAL_ADDRESS *BufferPtrAddress; | |
CopyMem ( | |
mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemId, | |
PcdGetPtr (PcdAcpiDefaultOemId), | |
sizeof (mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemId) | |
); | |
OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId); | |
CopyMem (&mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemTableId, &OemTableId, sizeof (UINT64)); | |
mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision); | |
mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); | |
mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); | |
// | |
// Register software SMI handler | |
// | |
Status = gSmst->SmmLocateProtocol ( | |
&gEfiSmmSwDispatch2ProtocolGuid, | |
NULL, | |
(VOID **)&SmmSwDispatch2 | |
); | |
ASSERT_EFI_ERROR (Status); | |
SmmSwDispatchContext.SwSmiInputValue = (UINTN)-1; | |
Status = SmmSwDispatch2->Register ( | |
SmmSwDispatch2, | |
PiSmmCommunicationHandler, | |
&SmmSwDispatchContext, | |
&DispatchHandle | |
); | |
ASSERT_EFI_ERROR (Status); | |
DEBUG ((EFI_D_INFO, "SmmCommunication SwSmi: %x\n", (UINTN)SmmSwDispatchContext.SwSmiInputValue)); | |
// | |
// Set ACPI table | |
// | |
Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol); | |
ASSERT_EFI_ERROR (Status); | |
mSmmCommunicationAcpiTable.SwSmiNumber = (UINT32)SmmSwDispatchContext.SwSmiInputValue; | |
BufferPtrAddress = AllocateAcpiNvsMemoryBelow4G (sizeof(EFI_PHYSICAL_ADDRESS)); | |
ASSERT (BufferPtrAddress != NULL); | |
DEBUG ((EFI_D_INFO, "SmmCommunication BufferPtrAddress: 0x%016lx, BufferPtr: 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)BufferPtrAddress, *BufferPtrAddress)); | |
mSmmCommunicationAcpiTable.BufferPtrAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)BufferPtrAddress; | |
CopyMem (&mSmmCommunicationAcpiTable.UefiAcpiDataTable.Identifier, &gEfiSmmCommunicationProtocolGuid, sizeof(gEfiSmmCommunicationProtocolGuid)); | |
Status = AcpiTableProtocol->InstallAcpiTable ( | |
AcpiTableProtocol, | |
&mSmmCommunicationAcpiTable, | |
sizeof(mSmmCommunicationAcpiTable), | |
&TableKey | |
); | |
ASSERT_EFI_ERROR (Status); | |
// | |
// Save context | |
// | |
mSmmCommunicationContext.SwSmiNumber = (UINT32)SmmSwDispatchContext.SwSmiInputValue; | |
mSmmCommunicationContext.BufferPtrAddress = mSmmCommunicationAcpiTable.BufferPtrAddress; | |
SetCommunicationContext (); | |
return Status; | |
} |