alder_lake_bios/Insyde/InsydeModulePkg/Universal/Smbios/PnpSmm/PnpSmm.c

420 lines
13 KiB
C

/** @file
PnpSmm driver initialization
;******************************************************************************
;* Copyright (c) 2012 - 2021, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include "PnpSmm.h"
#include <Library/IoLib.h>
#include <Guid/FlashMapHob.h>
#include <EfiFlashMap.h> // for GPNV
#include <Library/MemoryAllocationLib.h>
#include <Protocol/SmmLegacyBoot.h>
#define FixedPcdGetPtrSize(TokenName) (UINTN)_PCD_PATCHABLE_##TokenName##_SIZE
UINT8 *mSmmSMBIOSPnpBuffer = NULL;
EFI_SMM_SYSTEM_TABLE2 *mSmst;
EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *mSmmFwBlockService;
H2O_IHISI_PROTOCOL *mH2OIhisiPnp = NULL;
PLATFORM_GPNV_MAP_BUFFER GPNVMapBuffer;
PLATFORM_GPNV_HEADER *GPNVHeader = NULL;
UINTN UpdateableStringCount;
DMI_UPDATABLE_STRING *mUpdatableStrings;
UINTN OemGPNVHandleCount = 0;
BOOLEAN mIsOemGPNVMap = FALSE;
BOOLEAN mLegacyBoot = FALSE;
BOOLEAN mSmmSmbiosEndOfDxe = FALSE;
typedef struct {
UINT8 Type;
BOOLEAN Updatable;
UINTN StringNum;
UINT8 StringOffset[1];
} MODIFY_UPDATABLE_INFO;
/**
Notification for SMM EndOfDxe protocol.
@param[in] Protocol Points to the protocol's unique identifier.
@param[in] Interface Points to the interface instance.
@param[in] Handle The handle on which the interface was installed.
@retval EFI_SUCCESS Notification runs successfully.
**/
EFI_STATUS
EFIAPI
SmbiosSmmEndOfDxe (
IN CONST EFI_GUID *Protocol,
IN VOID *Interface,
IN EFI_HANDLE Handle
)
{
mSmmSmbiosEndOfDxe = TRUE;
return EFI_SUCCESS;
}
/**
This callback fucntion gets the SMBIOS table entry point and pass into SmmSmbiosPnpHandler.
@param[In] Event Event type
@param[In] Context Context for the event
**/
VOID
EFIAPI
GetSmbiosEntryCallback (
IN EFI_EVENT Event,
IN VOID *Cotext
)
{
EFI_STATUS Status;
EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateBufHeader;
SMM_SMBIOS_PNP_COMMUNICATE_HEADER *SmmSMBIOSPnpHeader;
EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication;
EFI_PHYSICAL_ADDRESS SMBIOSTableEntryAddress;
EFI_PHYSICAL_ADDRESS SMBIOSTableEntryAddress64Bit;
SMM_SMBIOS_PNP_ADDRESS *SmmSMBIOSPnpAddress;
UINTN CommSize;
gBS->CloseEvent (Event);
//
// Initial Communication buffer
//
SmmCommunicateBufHeader = (EFI_SMM_COMMUNICATE_HEADER *) mSmmSMBIOSPnpBuffer;
CopyGuid (&SmmCommunicateBufHeader->HeaderGuid, &gH2OSmmPnPCommunicationGuid);
SmmCommunicateBufHeader->MessageLength = (SMM_SMBIOS_PNP_COMM_BUFF_SIZE - OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data));
SmmSMBIOSPnpHeader = (SMM_SMBIOS_PNP_COMMUNICATE_HEADER *) SmmCommunicateBufHeader->Data;
SmmSMBIOSPnpHeader->Function = SMM_COMM_SMBIOS_PNP_ENTRY_SET;
SmmSMBIOSPnpAddress = (SMM_SMBIOS_PNP_ADDRESS *)SmmSMBIOSPnpHeader->Data;
//
// Need to pass SMBIOS table entry point into SmmSmbiosPnpHandler.
//
Status = EFI_SUCCESS;
SMBIOSTableEntryAddress = 0;
SMBIOSTableEntryAddress64Bit = 0;
if (((PcdGet16 (PcdSmbiosVersion) >> 8) < 0x3) ||
(((PcdGet16 (PcdSmbiosVersion) >> 8) >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT0) == BIT0))) {
Status = EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid, (VOID **) &SMBIOSTableEntryAddress);
}
ASSERT_EFI_ERROR (Status);
if (((PcdGet16 (PcdSmbiosVersion) >> 8) >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT1) == BIT1)) {
Status = EfiGetSystemConfigurationTable (&gEfiSmbios3TableGuid, (VOID **) &SMBIOSTableEntryAddress64Bit);
}
ASSERT_EFI_ERROR (Status);
SmmSMBIOSPnpAddress->Address = SMBIOSTableEntryAddress;
SmmSMBIOSPnpAddress->Address64Bit = SMBIOSTableEntryAddress64Bit;
Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &SmmCommunication);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
return;
}
CommSize = SMM_SMBIOS_PNP_COMM_BUFF_SIZE;
Status = SmmCommunication->Communicate (SmmCommunication, mSmmSMBIOSPnpBuffer, &CommSize);
ASSERT_EFI_ERROR (Status);
}
EFI_STATUS
FillPlatformGPNVMapBuffer (
IN OEM_GPNV_MAP *GPNVMap
)
{
UINTN Index;
if (OemGPNVHandleCount >= FixedPcdGet16 (PcdDefaultGpnvMapBufferSize)) {
return EFI_INVALID_PARAMETER;
}
for (Index = 0; Index < OemGPNVHandleCount; Index++) {
GPNVMapBuffer.PlatFormGPNVMap[Index].Handle = GPNVMap->Handle;
GPNVMapBuffer.PlatFormGPNVMap[Index].MinGPNVSize = GPNVMap->GPNVSize;
GPNVMapBuffer.PlatFormGPNVMap[Index].GPNVSize = GPNVMap->GPNVSize;
GPNVMapBuffer.PlatFormGPNVMap[Index].BaseAddress = GPNVMap->GPNVBaseAddress;
++GPNVMap;
}
return EFI_SUCCESS;
}
/**
SMM Legacy boot callback to indicate gLegacyBootProtocolGuid event is signaled
@retval EFI_SUCCESS: Locate EFI_SMM_SW_DISPATCH2_PROTOCOL success
@retval Others EFI_SMM_SW_DISPATCH2_PROTOCOL not installed
**/
STATIC
EFI_STATUS
EFIAPI
SmmLegacyBootCallback (
IN CONST EFI_GUID *Protocol,
IN VOID *Interface,
IN EFI_HANDLE Handle
)
{
mLegacyBoot = TRUE;
return EFI_SUCCESS;
}
/**
Entry point for SmmPnp drivers.
@param[In] ImageHandle EFI_HANDLE
@param[In] SystemTable EFI_SYSTEM_TABLE
@retval EFI_SUCCESS Success
@retval EFI_DEVICE_ERROR Fail
**/
EFI_STATUS
EFIAPI
SmmPnpInit (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_HANDLE SwHandle;
EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
EFI_SMM_SW_REGISTER_CONTEXT SwContext;
EFI_EVENT SmbiosGetTableEvent;
DMI_UPDATABLE_STRING *TempStringTable;
OEM_GPNV_MAP *OemGPNVMap;
EFI_SMM_BASE2_PROTOCOL *SmmBase;
BOOLEAN InSmm;
BOOLEAN NeedFreePnpTable;
EFI_PCD_PROTOCOL *Pcd = NULL;
EFI_HANDLE DispatchHandle;
VOID *Registration;
VOID *LegacyBootRegistration;
EFI_HANDLE Handle;
SmmBase = NULL;
TempStringTable = NULL;
Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID **)&SmmBase);
InSmm = FALSE;
if (!EFI_ERROR (Status)) {
SmmBase->InSmm (SmmBase, &InSmm);
}
if (InSmm) {
Status = SmmBase->GetSmstLocation (SmmBase, &mSmst);
if (EFI_ERROR (Status)) {
return Status;
}
Status = mSmst->SmmLocateProtocol (&gEfiSmmFwBlockServiceProtocolGuid, NULL, (VOID **)&mSmmFwBlockService);
//
// Perfrom DMI reclaim if needed
//
Status = mSmst->SmmRegisterProtocolNotify (
&gEfiSmmEndOfDxeProtocolGuid,
SmbiosSmmEndOfDxe,
&Registration
);
if (!EFI_ERROR(Status)) {
DmiReclaimBeforeEndOfDxe();
}
UpdateableStringCount = 0;
mUpdatableStrings = NULL;
//
// OemServices (Smm)
//
NeedFreePnpTable = TRUE;
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices Call: OemSvcSmmInstallPnpStringTable \n"));
Status = OemSvcSmmInstallPnpStringTable (
&UpdateableStringCount,
&TempStringTable
);
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices OemSvcSmmInstallPnpStringTable Status: %r\n", Status));
if (Status == EFI_UNSUPPORTED) {
Status = gBS->LocateProtocol (&gEfiPcdProtocolGuid, NULL, (VOID **) &Pcd);
if (EFI_ERROR(Status)) {
return Status;
}
NeedFreePnpTable = FALSE;
TempStringTable = PcdGetPtr (PcdSmbiosUpdatableStringTable);
UpdateableStringCount = FixedPcdGetPtrSize (PcdSmbiosUpdatableStringTable) / sizeof (DMI_UPDATABLE_STRING);
}
if ((TempStringTable != NULL) && (UpdateableStringCount != 0)) {
mUpdatableStrings = AllocateRuntimePool (UpdateableStringCount * sizeof (DMI_UPDATABLE_STRING));
if (mUpdatableStrings != NULL) {
CopyMem (mUpdatableStrings, TempStringTable, UpdateableStringCount * sizeof (DMI_UPDATABLE_STRING));
}
if (NeedFreePnpTable) {
FreePool (TempStringTable);
}
}
//
// OemServices (Smm)
//
OemGPNVHandleCount = 0;
OemGPNVMap = NULL;
mIsOemGPNVMap = FALSE;
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices Call: OemSvcSmmInstallPnpGpnvTable \n"));
Status = OemSvcSmmInstallPnpGpnvTable (&OemGPNVHandleCount, &OemGPNVMap);
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices OemSvcSmmInstallPnpGpnvTable Status: %r\n", Status));
if (Status == EFI_MEDIA_CHANGED && OemGPNVMap != NULL) {
Status = FillPlatformGPNVMapBuffer (OemGPNVMap);
ASSERT_EFI_ERROR (Status);
if (!EFI_ERROR (Status)) {
mIsOemGPNVMap = TRUE;
}
}
Status = mSmst->SmmRegisterProtocolNotify (
&gEdkiiSmmLegacyBootProtocolGuid,
SmmLegacyBootCallback,
&LegacyBootRegistration
);
ASSERT_EFI_ERROR (Status);
//
// Get the Sw dispatch protocol
//
Status = mSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID **)&SwDispatch);
ASSERT_EFI_ERROR (Status);
//
// Register SMBIOS call SMI function
//
SwContext.SwSmiInputValue = SMM_PnP_BIOS_CALL;
SwHandle = NULL;
Status = SwDispatch->Register (SwDispatch, PnPBiosCallback, &SwContext, &SwHandle);
ASSERT_EFI_ERROR (Status);
Status = gBS->LocateProtocol (
&gEfiCallerIdGuid,
NULL,
(VOID **) &mSmmSMBIOSPnpBuffer
);
//
// Register SMBIOS PnP SMI Communication handler
//
Status = mSmst->SmiHandlerRegister (
SmmSmbiosPnpHandler,
&gH2OSmmPnPCommunicationGuid,
&DispatchHandle
);
ASSERT_EFI_ERROR (Status);
} else {
//
// This event will be triggered after SMBIOS table entry point is ready.
// So, we can get the address of entry point and save it.
//
Status = EfiCreateEventReadyToBootEx (
TPL_CALLBACK - 1,
GetSmbiosEntryCallback,
NULL,
&SmbiosGetTableEvent
);
mSmmSMBIOSPnpBuffer = AllocateReservedPool (SMM_SMBIOS_PNP_COMM_BUFF_SIZE);
if (mSmmSMBIOSPnpBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Handle = NULL;
Status = gBS->InstallMultipleProtocolInterfaces (
&Handle,
&gEfiCallerIdGuid,
mSmmSMBIOSPnpBuffer,
NULL
);
if (EFI_ERROR (Status)) {
return Status;
}
}
return EFI_SUCCESS;
}
/**
Check the input memory buffer whether lies within the command buffer..
@param[in] Buffer Pointer to the first byte in a buffer.
@param[in] BufferSize Unsigned integer that specifies the size of the Buffer, in bytes.
@retval TURE Buffer lies within the command buffer.
@retval FALSE Buffer lies outside the command buffer.
**/
BOOLEAN
EFIAPI
BufferInCmdBufferPnp (
IN VOID *Buffer,
IN UINTN BufferSize
)
{
EFI_STATUS Status;
if (mLegacyBoot) {
return TRUE;
}
if (mH2OIhisiPnp == NULL) {
Status = mSmst->SmmLocateProtocol (
&gH2OIhisiProtocolGuid,
NULL,
(VOID **) &mH2OIhisiPnp
);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
return TRUE;
}
}
return mH2OIhisiPnp->BufferInCmdBuffer((VOID *) Buffer, BufferSize);
}
/**
Check the input memory buffer is whether overlap the SMRAM ranges.
@param[in] Buffer The pointer to the buffer to be checked.
@param[in] BufferSize The size in bytes of the input buffer
@retval TURE The buffer overlaps SMRAM ranges.
@retval FALSE The buffer doesn't overlap SMRAM ranges.
**/
BOOLEAN
EFIAPI
BufferOverlapSmramPnp (
IN VOID *Buffer,
IN UINTN BufferSize
)
{
EFI_STATUS Status;
if (mH2OIhisiPnp == NULL) {
Status = mSmst->SmmLocateProtocol (
&gH2OIhisiProtocolGuid,
NULL,
(VOID **) &mH2OIhisiPnp
);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
return TRUE;
}
}
if (mH2OIhisiPnp->BufferOverlapSmram((VOID *) Buffer, BufferSize)) {
return TRUE;
}
return FALSE;
}