From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by mx.groups.io with SMTP id smtpd.web09.27647.1612143476489046256 for ; Sun, 31 Jan 2021 17:37:56 -0800 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: intel.com, ip: 192.55.52.151, mailfrom: heng.luo@intel.com) IronPort-SDR: vJKds2OSHBsxpYCA4VILBE01YZinnwfP1U3Erkg4YGrDm0hl5Jy6t+AvuuhUy1M/bjxQxYs+4f /IocBvSzuOmw== X-IronPort-AV: E=McAfee;i="6000,8403,9881"; a="160388128" X-IronPort-AV: E=Sophos;i="5.79,391,1602572400"; d="scan'208";a="160388128" Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 31 Jan 2021 17:37:55 -0800 IronPort-SDR: tooVa58A6yCe32ws0h1ABnDVw6YBMpzB1Xehxs49hH5sNDvAEA2S5iBbcRHMQvVSNQJQn6NP0z du9Z/a3+X79Q== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.79,391,1602572400"; d="scan'208";a="368718837" Received: from hengluo-dev.ccr.corp.intel.com ([10.239.153.154]) by fmsmga008.fm.intel.com with ESMTP; 31 Jan 2021 17:37:52 -0800 From: "Heng Luo" To: devel@edk2.groups.io Cc: Sai Chaganty , Nate DeSimone Subject: [PATCH 36/40] TigerlakeSiliconPkg/Pch: Add Pch modules Date: Mon, 1 Feb 2021 09:36:53 +0800 Message-Id: <20210201013657.1833-36-heng.luo@intel.com> X-Mailer: git-send-email 2.24.0.windows.2 In-Reply-To: <20210201013657.1833-1-heng.luo@intel.com> References: <20210201013657.1833-1-heng.luo@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D3171 Adds the following files: * Pch/PchInit/Dxe * Pch/PchInit/Smm * Pch/PchSmiDispatcher/Smm * Pch/SmmControl/RuntimeDxe Cc: Sai Chaganty Cc: Nate DeSimone Signed-off-by: Heng Luo --- Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c = | 494 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchCnviAcpi.c = | 41 ++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c = | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c = | 314 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h = | 122 ++++++++++++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c = | 354 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeTgl.inf = | 96 ++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c = | 89 ++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c = | 33 +++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c = | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/GbeSxSmm.c = | 266 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c = | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchHdaSxSmm.c = | 33 +++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c = | 285 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h = | 254 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf = | 110 +++++++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c = | 451 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c = | 67 +++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.c = | 1284 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.h = | 226 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatch.= c | 2442 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatche= r.inf | 116 ++++++++++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelper.h = | 40 +++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelperCli= ent.c | 57 ++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h = | 1043 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCore.c = | 926 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi.c = | 1588 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi.h = | 341 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi.c = | 263 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.c= | 332 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.h= | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeriodicT= imer.c | 667 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPowerButt= on.c | 81 +++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.c = | 381 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c = | 224 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb.c = | 230 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.= c | 778 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.= h | 107 ++++++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl.inf= | 54 +++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriv= er.c | 394 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++ Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriv= er.h | 130 +++++++++++++++++++++++++++++++++++++++++++++++++ 41 files changed, 15340 insertions(+) diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c b/= Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c new file mode 100644 index 0000000000..e88afa5ded --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c @@ -0,0 +1,494 @@ +/** @file=0D + This is the driver that initializes the Intel PCH.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include "PchInit.h"=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +//=0D +// Module variables=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED PCH_NVS_AREA_PROTOCOL mPchNvsAreaProtocol= ;=0D +=0D +/**=0D + Retrieve interrupt information about a PCH device from policy=0D +=0D + @param[in] UartNumber Uart number=0D +=0D + @retval PCH_DEVICE_INTERRUPT_CONFIG structure with device's interrupt = information=0D +**/=0D +PCH_DEVICE_INTERRUPT_CONFIG=0D +GetUartInterrupt (=0D + IN UINT8 UartNumber=0D + )=0D +{=0D + PCH_DEVICE_INTERRUPT_CONFIG EmptyRecord;=0D + UINT8 DevNum;=0D + UINT8 FuncNum;=0D + UINT8 Index;=0D +=0D + ZeroMem (&EmptyRecord, sizeof (PCH_DEVICE_INTERRUPT_CONFIG));=0D + DevNum =3D SerialIoUartDevNumber (UartNumber);=0D + FuncNum =3D SerialIoUartFuncNumber (UartNumber);=0D +=0D + for (Index =3D 0; Index < mPchConfigHob->Interrupt.NumOfDevIntConfig; In= dex++) {=0D + if ((mPchConfigHob->Interrupt.DevIntConfig[Index].Device =3D=3D DevNum= ) &&=0D + (mPchConfigHob->Interrupt.DevIntConfig[Index].Function =3D=3D Func= Num)) {=0D + return mPchConfigHob->Interrupt.DevIntConfig[Index];=0D + }=0D + }=0D + return EmptyRecord;=0D +}=0D +=0D +/**=0D + Update ASL definitions for SerialIo devices.=0D +=0D +**/=0D +VOID=0D +UpdateSerialIoAcpiData (=0D + VOID=0D + )=0D +{=0D + UINT8 Index;=0D +=0D + for (Index =3D 0; Index < GetPchMaxSerialIoSpiControllersNum (); Index++= ) {=0D + mPchNvsAreaProtocol.Area->SM0[Index] =3D mPchConfigHob->SerialIo.SpiDe= viceConfig[Index].Mode;=0D + mPchNvsAreaProtocol.Area->SC0[Index] =3D GetSerialIoSpiPciCfg (Index);= =0D + }=0D + for (Index =3D 0; Index < GetPchMaxSerialIoI2cControllersNum (); Index++= ) {=0D + mPchNvsAreaProtocol.Area->IM0[Index] =3D mPchConfigHob->SerialIo.I2cDe= viceConfig[Index].Mode;=0D + mPchNvsAreaProtocol.Area->IC0[Index] =3D GetSerialIoI2cPciCfg (Index);= =0D + }=0D + for (Index =3D 0; Index < GetPchMaxSerialIoUartControllersNum (); Index+= +) {=0D + mPchNvsAreaProtocol.Area->UM0[Index] =3D mPchConfigHob->SerialIo.UartD= eviceConfig[Index].Mode;=0D + mPchNvsAreaProtocol.Area->UC0[Index] =3D GetSerialIoUartPciCfg (Index)= ;=0D + mPchNvsAreaProtocol.Area->UD0[Index] =3D mPchConfigHob->SerialIo.UartD= eviceConfig[Index].DmaEnable;=0D + mPchNvsAreaProtocol.Area->UP0[Index] =3D mPchConfigHob->SerialIo.UartD= eviceConfig[Index].PowerGating;=0D + mPchNvsAreaProtocol.Area->UI0[Index] =3D (GetUartInterrupt (Index)).Ir= q;=0D + }=0D +}=0D +=0D +#if FixedPcdGet8(PcdEmbeddedEnable) =3D=3D 0x1=0D +/**=0D + Update NVS Area for Timed GPIO devices.=0D +**/=0D +VOID=0D +UpdateTimedGpioSetup (=0D + VOID=0D + )=0D +{=0D + mPchNvsAreaProtocol.Area->EnableTimedGpio0 =3D (UINT8)mPchConfigHob->Pm.= EnableTimedGpio0;=0D + mPchNvsAreaProtocol.Area->EnableTimedGpio1 =3D (UINT8)mPchConfigHob->Pm.= EnableTimedGpio1;=0D +}=0D +#endif=0D +=0D +/**=0D + Update NVS Area after RST PCIe Storage Remapping and before Boot=0D +=0D + @retval EFI_SUCCESS The function completed successfully=0D + @retval EFI_NOT_FOUND Couldn't fetch RstHob=0D +**/=0D +EFI_STATUS=0D +PchUpdateNvsAreaAfterRemapping (=0D + VOID=0D + )=0D +{=0D + UINTN Index;=0D + VOID *Hob;=0D + PCH_RST_HOB *RstHob;=0D +=0D + Hob =3D GetFirstGuidHob (&gPchRstHobGuid);=0D + if (Hob =3D=3D NULL) {=0D + return EFI_NOT_FOUND;=0D + }=0D +=0D + RstHob =3D (PCH_RST_HOB *) GET_GUID_HOB_DATA (Hob);=0D +=0D + for (Index =3D 0; Index < PCH_MAX_RST_PCIE_STORAGE_CR; Index++) {=0D + mPchNvsAreaProtocol.Area->RstPcieStorageInterfaceType[Index] = =3D RstHob->RstCrConfiguration[Index].DeviceInterface;=0D + mPchNvsAreaProtocol.Area->RstPcieStoragePmCapPtr[Index] = =3D RstHob->SavedRemapedDeviceConfigSpace[Index].PmCapPtr;=0D + mPchNvsAreaProtocol.Area->RstPcieStoragePcieCapPtr[Index] = =3D RstHob->SavedRemapedDeviceConfigSpace[Index].PcieCapPtr;=0D + mPchNvsAreaProtocol.Area->RstPcieStorageL1ssCapPtr[Index] = =3D RstHob->SavedRemapedDeviceConfigSpace[Index].L1ssCapPtr;=0D + mPchNvsAreaProtocol.Area->RstPcieStorageEpL1ssControl2[Index] = =3D RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointL1ssControl2;=0D + mPchNvsAreaProtocol.Area->RstPcieStorageEpL1ssControl1[Index] = =3D RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointL1ssControl1;=0D + mPchNvsAreaProtocol.Area->RstPcieStorageLtrCapPtr[Index] = =3D RstHob->SavedRemapedDeviceConfigSpace[Index].LtrCapPtr;=0D + mPchNvsAreaProtocol.Area->RstPcieStorageEpLtrData[Index] = =3D RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointLtrData;=0D + mPchNvsAreaProtocol.Area->RstPcieStorageEpLctlData16[Index] = =3D RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointLctlData16;=0D + mPchNvsAreaProtocol.Area->RstPcieStorageEpDctlData16[Index] = =3D RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointDctlData16;=0D + mPchNvsAreaProtocol.Area->RstPcieStorageEpDctl2Data16[Index] = =3D RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointDctl2Data16;=0D + mPchNvsAreaProtocol.Area->RstPcieStorageRpDctl2Data16[Index] = =3D RstHob->SavedRemapedDeviceConfigSpace[Index].RootPortDctl2Data16;=0D + mPchNvsAreaProtocol.Area->RstPcieStorageUniqueTableBar[Index] = =3D RstHob->RstCrConfiguration[Index].EndPointUniqueMsixTableBar;=0D + mPchNvsAreaProtocol.Area->RstPcieStorageUniqueTableBarValue[Index] = =3D RstHob->RstCrConfiguration[Index].EndPointUniqueMsixTableBarValue;=0D + mPchNvsAreaProtocol.Area->RstPcieStorageUniquePbaBar[Index] = =3D RstHob->RstCrConfiguration[Index].EndPointUniqueMsixPbaBar;=0D + mPchNvsAreaProtocol.Area->RstPcieStorageUniquePbaBarValue[Index] = =3D RstHob->RstCrConfiguration[Index].EndPointUniqueMsixPbaBarValue;=0D + mPchNvsAreaProtocol.Area->RstPcieStorageRootPortNum[Index] = =3D RstHob->RstCrConfiguration[Index].RootPortNum;=0D + }=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Update the Hybrid storage location NVS Area if Hybrid Storage device is = present=0D +**/=0D +EFI_STATUS=0D +UpdateHybridStorageLocation (=0D + VOID=0D + )=0D +{=0D + VOID *Hob;=0D + PCH_HYBRIDSTORAGE_HOB *HybridStorageHob;=0D +=0D + Hob =3D GetFirstGuidHob (&gHybridStorageHobGuid);=0D + if (Hob =3D=3D NULL) {=0D + return EFI_NOT_FOUND;=0D + }=0D +=0D + HybridStorageHob =3D (PCH_HYBRIDSTORAGE_HOB *) GET_GUID_HOB_DATA (Hob);= =0D + mPchNvsAreaProtocol.Area->HybridStorageLocation =3D HybridStorageHob->Hy= bridStorageLocation;=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + PCH ACPI initialization before Boot Sript Table is closed=0D + It update ACPI table and ACPI NVS area.=0D +=0D + @param[in] Event A pointer to the Event that triggered th= e callback.=0D + @param[in] Context A pointer to private data registered wit= h the callback function.=0D +**/=0D +VOID=0D +EFIAPI=0D +PchAcpiOnEndOfDxe (=0D + IN EFI_EVENT Event,=0D + IN VOID *Context=0D + )=0D +{=0D + DEBUG ((DEBUG_INFO, "PchAcpiOnEndOfDxe() Start\n"));=0D +=0D + ///=0D + /// Closed the event to avoid call twice when launch shell=0D + ///=0D + gBS->CloseEvent (Event);=0D +=0D + //=0D + // Init HDA Audio ACPI tables=0D + //=0D + PchHdAudioAcpiInit ();=0D + //=0D + // Update ASL definitions for SerialIo devices.=0D + //=0D + UpdateSerialIoAcpiData ();=0D + UpdateCnviAcpiData ();=0D +#if FixedPcdGet8(PcdEmbeddedEnable) =3D=3D 0x1=0D + UpdateTimedGpioSetup();=0D +#endif=0D +=0D + //=0D + // Update Pch Nvs Area=0D + //=0D + PchUpdateNvsArea ();=0D +=0D + DEBUG ((DEBUG_INFO, "PchAcpiOnEndOfDxe() End\n"));=0D +=0D + return;=0D +}=0D +=0D +/**=0D + Initialize Pch acpi=0D + @param[in] ImageHandle Handle for the image of this driver=0D +=0D + @retval EFI_SUCCESS The function completed successfully=0D + @retval EFI_OUT_OF_RESOURCES Do not have enough resources to initiali= ze the driver=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchAcpiInit (=0D + IN EFI_HANDLE ImageHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_EVENT EndOfDxeEvent;=0D +=0D + DEBUG ((DEBUG_INFO, "Install PCH NVS protocol\n"));=0D +=0D + Status =3D (gBS->AllocatePool) (EfiACPIMemoryNVS, sizeof (PCH_NVS_AREA),= (VOID **) &mPchNvsAreaProtocol.Area);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + ZeroMem ((VOID *) mPchNvsAreaProtocol.Area, sizeof (PCH_NVS_AREA));=0D + Status =3D gBS->InstallMultipleProtocolInterfaces (=0D + &ImageHandle,=0D + &gPchNvsAreaProtocolGuid,=0D + &mPchNvsAreaProtocol,=0D + NULL=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + ///=0D + /// Update the NVS Area after RST PCIe Storage Remapping=0D + ///=0D + PchUpdateNvsAreaAfterRemapping ();=0D +=0D + UpdateHybridStorageLocation ();=0D + //=0D + // Register an end of DXE event for PCH ACPI to do tasks before invoking= any UEFI drivers,=0D + // applications, or connecting consoles,...=0D + //=0D + Status =3D gBS->CreateEventEx (=0D + EVT_NOTIFY_SIGNAL,=0D + TPL_CALLBACK,=0D + PchAcpiOnEndOfDxe,=0D + NULL,=0D + &gEfiEndOfDxeEventGroupGuid,=0D + &EndOfDxeEvent=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + return Status;=0D +}=0D +=0D +=0D +/**=0D + Update NVS area for PCIe root ports.=0D +**/=0D +STATIC=0D +VOID=0D +PcieRpUpdateNvsArea (=0D + VOID=0D + )=0D +{=0D + UINT32 Index;=0D +=0D + for (Index =3D 0; Index < PCH_MAX_PCIE_CLOCKS; Index++) {=0D + mPchNvsAreaProtocol.Area->ClockToRootPortMap[Index] =3D mPchConfigHob-= >PcieRp.PcieClock[Index].Usage;=0D + }=0D +}=0D +=0D +/**=0D + Update ASL object before Boot=0D +=0D + @retval EFI_STATUS=0D + @retval EFI_NOT_READY The Acpi protocols are not ready.=0D +**/=0D +EFI_STATUS=0D +PchUpdateNvsArea (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINTN Index;=0D + UINT32 HpetBaseAdress;=0D + GPIO_GROUP GroupToGpeDwX[3];=0D + UINT32 GroupDw[3];=0D + UINTN RpDev;=0D + UINTN RpFun;=0D + UINT32 Data32;=0D + PCH_POLICY_PROTOCOL *PchPolicy;=0D + GPIO_DXE_CONFIG *GpioDxeConfig;=0D + UINT64 XdciPciBase;=0D + UINT64 XdciBar;=0D + UINT16 PciMemConfig;=0D + UINT16 TcoBase;=0D + UINT8 ClearXdciBar =3D FALSE;=0D +=0D + ///=0D + /// Get PCH Policy Protocol=0D + ///=0D + Status =3D gBS->LocateProtocol (&gPchPolicyProtocolGuid, NULL, (VOID **)= &PchPolicy);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + ///=0D + /// Get GPIO DXE Config Block=0D + ///=0D + Status =3D GetConfigBlock ((VOID *)PchPolicy, &gGpioDxeConfigGuid, (VOID= *)&GpioDxeConfig);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + //=0D + // Update ASL PCIE port address according to root port device and functi= on=0D + //=0D + for (Index =3D 0; Index < GetPchMaxPciePortNum (); Index++) {=0D + RpDev =3D PchPcieRpDevNumber (Index);=0D + RpFun =3D PchPcieRpFuncNumber (Index);=0D + Data32 =3D ((UINT8) RpDev << 16) | (UINT8) RpFun;=0D + mPchNvsAreaProtocol.Area->RpAddress[Index] =3D Data32;=0D +=0D + //=0D + // Update Maximum Snoop Latency and Maximum No-Snoop Latency values fo= r PCIE=0D + //=0D + mPchNvsAreaProtocol.Area->PcieLtrMaxSnoopLatency[Index] =3D mPchConf= igHob->PcieRp.RootPort[Index].PcieRpCommonConfig.PcieRpLtrConfig.LtrMaxSnoo= pLatency;=0D + mPchNvsAreaProtocol.Area->PcieLtrMaxNoSnoopLatency[Index] =3D mPchConf= igHob->PcieRp.RootPort[Index].PcieRpCommonConfig.PcieRpLtrConfig.LtrMaxNoSn= oopLatency;=0D + }=0D +=0D + //=0D + // Update PCHS.=0D + //=0D + mPchNvsAreaProtocol.Area->PchSeries =3D PchSeries ();=0D + //=0D + // Update PCHG.=0D + //=0D + mPchNvsAreaProtocol.Area->PchGeneration =3D (UINT16) PchGeneration ();=0D + //=0D + // Update PSTP.=0D + //=0D + mPchNvsAreaProtocol.Area->PchStepping =3D (UINT16) PchStepping ();=0D + //=0D + // Update HPET base address.=0D + //=0D + PchHpetBaseGet (&HpetBaseAdress);=0D + mPchNvsAreaProtocol.Area->HPTE =3D TRUE; // @todo remove the N= VS, since it's always enabled.=0D + mPchNvsAreaProtocol.Area->HPTB =3D HpetBaseAdress;=0D + //=0D + // Update SBREG_BAR.=0D + //=0D + mPchNvsAreaProtocol.Area->SBRG =3D PCH_PCR_BASE_ADDRESS;=0D +=0D + //=0D + // Update base address=0D + //=0D + mPchNvsAreaProtocol.Area->PMBS =3D PmcGetAcpiBase ();=0D + mPchNvsAreaProtocol.Area->PWRM =3D PmcGetPwrmBase ();=0D + PchTcoBaseGet (&TcoBase);=0D + mPchNvsAreaProtocol.Area->TcoBase =3D TcoBase;=0D +=0D + //=0D + // Update PCH PID info=0D + //=0D + mPchNvsAreaProtocol.Area->IclkPid =3D PchPcrGetPid (PchIpIclk);=0D +=0D + //=0D + // Update GPIO device ACPI variables=0D + //=0D + mPchNvsAreaProtocol.Area->SGIR =3D mPchConfigHob->Interrupt.GpioIrqRoute= ;=0D + mPchNvsAreaProtocol.Area->GPHD =3D (UINT8)GpioDxeConfig->HideGpioAcpiDev= ice;=0D +=0D + //=0D + // Update GPP_X to GPE_DWX mapping.=0D + //=0D + GpioGetGroupDwToGpeDwX (=0D + &GroupToGpeDwX[0], &GroupDw[0],=0D + &GroupToGpeDwX[1], &GroupDw[1],=0D + &GroupToGpeDwX[2], &GroupDw[2]=0D + );=0D +=0D + //=0D + // GEI0/1/2 and GED0/1/2 are objects for informing how GPIO groups are m= apped to GPE0.=0D + // If Group is mapped to 1-Tier GPE information is also stored on what G= roup DW=0D + // is mapped to GPE_DWx. Because GPE_DWx register is 32 bits large if gr= oups have more than=0D + // 32 pads only part of it can be mapped.=0D + //=0D + // GEIx - GroupIndex mapped to GPE0_DWx=0D + // GEDx - DoubleWorld part of Group: 0 - pins 31-0, 1 - pins 63-32, ...= =0D + //=0D + mPchNvsAreaProtocol.Area->GEI0 =3D (UINT8) GpioGetGroupIndexFromGroup (G= roupToGpeDwX[0]);=0D + mPchNvsAreaProtocol.Area->GEI1 =3D (UINT8) GpioGetGroupIndexFromGroup (G= roupToGpeDwX[1]);=0D + mPchNvsAreaProtocol.Area->GEI2 =3D (UINT8) GpioGetGroupIndexFromGroup (G= roupToGpeDwX[2]);=0D + mPchNvsAreaProtocol.Area->GED0 =3D (UINT8) GroupDw[0];=0D + mPchNvsAreaProtocol.Area->GED1 =3D (UINT8) GroupDw[1];=0D + mPchNvsAreaProtocol.Area->GED2 =3D (UINT8) GroupDw[2];=0D +=0D + //=0D + // SCS Configuration=0D + //=0D +=0D + PcieRpUpdateNvsArea ();=0D +=0D + //=0D + // SATA configuration.=0D + //=0D + mPchNvsAreaProtocol.Area->SataPortPresence =3D GetSataPortPresentStatus = (0);=0D + DEBUG ((DEBUG_INFO, "SataPortPresence: 0x%x\n", mPchNvsAreaProtocol.Area= ->SataPortPresence));=0D +=0D + //=0D + // CPU SKU=0D + //=0D + mPchNvsAreaProtocol.Area->CpuSku =3D 0;=0D + mPchNvsAreaProtocol.Area->PsOnEnable =3D (UINT8)mPchConfigHob= ->Pm.PsOnEnable;=0D +=0D + for (Index =3D 0; Index < GetPchMaxPciePortNum (); Index++) {=0D + mPchNvsAreaProtocol.Area->LtrEnable[Index] =3D (UINT8)mPchConfigHob->= PcieRp.RootPort[Index].PcieRpCommonConfig.LtrEnable;=0D + }=0D +=0D + mPchNvsAreaProtocol.Area->GBES =3D IsGbePresent ();=0D +=0D + //=0D + // Update PCH Trace Hub Mode=0D + //=0D + mPchNvsAreaProtocol.Area->PchTraceHubMode =3D (UINT8) mPchConfigHob-= >PchTraceHub.PchTraceHubMode;=0D +=0D + //=0D + // Saving GCTL value into PCH NVS area=0D + //=0D +=0D + XdciPciBase =3D PchXdciPciCfgBase ();=0D +=0D + //=0D + // Determine Base address for Base address register (Offset 0x10)=0D + //=0D + if (PciSegmentRead32 (XdciPciBase) !=3D 0xFFFFFFFF) {=0D +=0D + XdciBar =3D PciSegmentRead32 (XdciPciBase + PCI_BASE_ADDRESSREG_OFFSET= ) & 0xFFFFFFF0;=0D +=0D + if ((PciSegmentRead32 (XdciPciBase + PCI_BASE_ADDRESSREG_OFFSET) & B_P= CI_BAR_MEMORY_TYPE_MASK) =3D=3D B_PCI_BAR_MEMORY_TYPE_64) {=0D + XdciBar +=3D (UINT64)PciSegmentRead32 (XdciPciBase + (PCI_BASE_ADDRE= SSREG_OFFSET + 4)) << 32;=0D + }=0D +=0D + if (XdciBar =3D=3D 0x0) {=0D + ClearXdciBar =3D TRUE;=0D + PciSegmentWrite32 ((XdciPciBase + PCI_BASE_ADDRESSREG_OFFSET), PcdGe= t32 (PcdSiliconInitTempMemBaseAddr));=0D + XdciBar =3D PciSegmentRead32 (XdciPciBase + PCI_BASE_ADDRESSREG_OFFS= ET) & 0xFFFFFFF0;=0D +=0D + if ((PciSegmentRead32 (XdciPciBase + PCI_BASE_ADDRESSREG_OFFSET) & B= _PCI_BAR_MEMORY_TYPE_MASK) =3D=3D B_PCI_BAR_MEMORY_TYPE_64) {=0D + XdciBar +=3D (UINT64)PciSegmentRead32 (XdciPciBase + (PCI_BASE_ADD= RESSREG_OFFSET + 4)) << 32;=0D + }=0D + }=0D +=0D + //=0D + // Enable Pci Memconfig to read the correct value for GCTL register=0D + //=0D + PciMemConfig =3D PciSegmentRead16 (XdciPciBase + PCI_COMMAND_OFFSET);= =0D + PciSegmentWrite16 (XdciPciBase + PCI_COMMAND_OFFSET, PciMemConfig | (E= FI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));=0D +=0D + mPchNvsAreaProtocol.Area->PchxDCIPwrDnScale =3D MmioRead32(XdciBar + R= _XDCI_MEM_GCTL);=0D + DEBUG ((DEBUG_INFO, "PchxDCIPwrDnScale 0x%x\n", (UINT64)mPchNvsAreaPr= otocol.Area->PchxDCIPwrDnScale));=0D + //=0D + // Disable Pci Memconfig & clear Base address=0D + //=0D + PciSegmentWrite16(XdciPciBase + PCI_COMMAND_OFFSET, PciMemConfig);=0D +=0D + if (ClearXdciBar =3D=3D TRUE) {=0D + PciSegmentWrite32 ((XdciPciBase + PCI_BASE_ADDRESSREG_OFFSET), 0x0);= =0D + PciSegmentWrite32 ((XdciPciBase + (PCI_BASE_ADDRESSREG_OFFSET + 4)),= 0x0);=0D + }=0D + }=0D +=0D + return Status;=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchCnviAcpi.= c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchCnviAcpi.c new file mode 100644 index 0000000000..5c8e1ce5b4 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchCnviAcpi.c @@ -0,0 +1,41 @@ +/** @file=0D + Initializes PCH CNVi device ACPI data.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +=0D +#include =0D +#include =0D +#include =0D +#include "PchInit.h"=0D +#include =0D +=0D +/**=0D + Update ASL definitions for CNVi device.=0D +=0D + @retval EFI_SUCCESS The function completed successfully=0D +**/=0D +EFI_STATUS=0D +UpdateCnviAcpiData (=0D + VOID=0D + )=0D +{=0D + EFI_PEI_HOB_POINTERS HobPtr;=0D + CNVI_CONFIG_HOB *CnviConfigHob;=0D +=0D + DEBUG ((DEBUG_INFO, "UpdateCnviAcpiData() Start\n"));=0D +=0D + // Get CNVi Config HOB.=0D + HobPtr.Guid =3D GetFirstGuidHob (&gCnviConfigHobGuid);=0D + if (HobPtr.Guid !=3D NULL) {=0D + CnviConfigHob =3D (CNVI_CONFIG_HOB *) GET_GUID_HOB_DATA (HobPtr.Guid);= =0D + mPchNvsAreaProtocol.Area->CnviMode =3D (UINT8)CnviConfigHob-= >Mode;=0D + mPchNvsAreaProtocol.Area->CnviBtCore =3D (UINT8)CnviConfigHob-= >BtCore;=0D + mPchNvsAreaProtocol.Area->CnviBtAudioOffload =3D (UINT8)CnviConfigHob-= >BtAudioOffload;=0D + }=0D + mPchNvsAreaProtocol.Area->CnviPortId =3D PID_CNVI;=0D + DEBUG ((DEBUG_INFO, "UpdateCnviAcpiData() End\n"));=0D +=0D + return EFI_SUCCESS;=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c= b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c new file mode 100644 index 0000000000..dbdb028483 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c @@ -0,0 +1,201 @@ +=0D +/** @file=0D + Initializes the PCH HD Audio ACPI Tables.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include "PchInit.h"=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#define XTAL_FREQ_38P4MHZ 1=0D +=0D +/**=0D + Retrieves address of NHLT table from XSDT/RSDT.=0D +=0D + @retval NHLT_ACPI_TABLE* Pointer to NHLT table if found=0D + @retval NULL NHLT could not be found=0D +**/=0D +NHLT_ACPI_TABLE *=0D +LocateNhltAcpiTable (=0D + VOID=0D + )=0D +{=0D + EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;=0D + EFI_ACPI_DESCRIPTION_HEADER *Xsdt;=0D + NHLT_ACPI_TABLE *Nhlt;=0D + UINTN Index;=0D + UINT64 Data64;=0D + EFI_STATUS Status;=0D + Rsdp =3D NULL;=0D + Xsdt =3D NULL;=0D + Nhlt =3D NULL;=0D +=0D + ///=0D + /// Find the AcpiSupport protocol returns RSDP (or RSD PTR) address.=0D + ///=0D + DEBUG ((DEBUG_INFO, "LocateNhltAcpiTable() Start\n"));=0D +=0D + Status =3D EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid, (VOID *) = &Rsdp);=0D + if (EFI_ERROR (Status) || (Rsdp =3D=3D NULL)) {=0D + DEBUG ((DEBUG_ERROR, "EFI_ERROR or Rsdp =3D=3D NULL\n"));=0D + return NULL;=0D + }=0D +=0D + Xsdt =3D (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->XsdtAddress;=0D + if (Xsdt =3D=3D NULL || Xsdt->Signature !=3D EFI_ACPI_5_0_EXTENDED_SYSTE= M_DESCRIPTION_TABLE_SIGNATURE) {=0D + // If XSDT has not been found, check RSDT=0D + Xsdt =3D (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->RsdtAddress;=0D + if (Xsdt =3D=3D NULL || Xsdt->Signature !=3D EFI_ACPI_5_0_ROOT_SYSTEM_= DESCRIPTION_TABLE_SIGNATURE) {=0D + DEBUG ((DEBUG_ERROR, "XSDT/RSDT =3D=3D NULL or wrong signature\n"));= =0D + return NULL;=0D + }=0D + }=0D +=0D + for (Index =3D sizeof (EFI_ACPI_DESCRIPTION_HEADER); Index < Xsdt->Lengt= h; Index =3D Index + sizeof (UINT64)) {=0D + Data64 =3D *(UINT64 *) ((UINT8 *) Xsdt + Index);=0D + Nhlt =3D (NHLT_ACPI_TABLE *) (UINTN) Data64;=0D + if (Nhlt !=3D NULL && Nhlt->Header.Signature =3D=3D NHLT_ACPI_TABLE_SI= GNATURE) {=0D + break;=0D + }=0D + Nhlt =3D NULL;=0D + }=0D +=0D + if (Nhlt =3D=3D NULL || Nhlt->Header.Signature !=3D NHLT_ACPI_TABLE_SIGN= ATURE) {=0D + DEBUG ((DEBUG_ERROR, "Nhlt =3D=3D NULL or wrong signature\n"));=0D + return NULL;=0D + }=0D +=0D + DEBUG ((DEBUG_INFO, "Found NhltTable, Address =3D 0x%016x\n", Nhlt));=0D +=0D + return Nhlt;=0D +}=0D +=0D +/**=0D + Sets NVS ACPI variables for HDAS._DSM and SNDW._DSD accordingly to polic= y.=0D +=0D + @param[in] NhltAcpiTableAddress=0D + @param[in] NhltAcpiTableLength=0D + @param[in] *HdAudioConfigHob=0D + @param[in] *HdAudioDxeConfig=0D +**/=0D +VOID=0D +UpdateHdaAcpiData (=0D + IN UINT64 NhltAcpiTableAddress,=0D + IN UINT32 NhltAcpiTableLength,=0D + IN CONST HDAUDIO_HOB *HdAudioConfigHob,=0D + IN CONST HDAUDIO_DXE_CONFIG *HdAudioDxeConfig=0D + )=0D +{=0D + DEBUG ((DEBUG_INFO, "UpdateHdaAcpiData():\n NHLT Address =3D 0x%016x, Le= ngth =3D 0x%08x\n", NhltAcpiTableAddress, NhltAcpiTableLength));=0D + DEBUG ((DEBUG_INFO, " FeatureMask =3D 0x%08x\n", HdAudioDxeConfig->DspFe= atureMask));=0D +=0D + mPchNvsAreaProtocol.Area->XTAL =3D XTAL_FREQ_38P4MHZ;=0D + mPchNvsAreaProtocol.Area->NHLA =3D NhltAcpiTableAddress;=0D + mPchNvsAreaProtocol.Area->NHLL =3D NhltAcpiTableLength;=0D + mPchNvsAreaProtocol.Area->ADFM =3D HdAudioDxeConfig->DspFeatureMask;=0D +=0D + if (HdAudioConfigHob->DspEnable || HdAudioConfigHob->DspUaaCompliance = =3D=3D FALSE) {=0D + mPchNvsAreaProtocol.Area->SWQ0 =3D HdAudioConfigHob->AudioLinkSndw1 ? = 0 : BIT1;=0D + mPchNvsAreaProtocol.Area->SWQ1 =3D HdAudioConfigHob->AudioLinkSndw2 ? = 0 : BIT1;=0D + mPchNvsAreaProtocol.Area->SWQ2 =3D HdAudioConfigHob->AudioLinkSndw3 ? = 0 : BIT1;=0D + mPchNvsAreaProtocol.Area->SWQ3 =3D HdAudioConfigHob->AudioLinkSndw4 ? = 0 : BIT1;=0D + } else {=0D + mPchNvsAreaProtocol.Area->SWQ0 =3D BIT1;=0D + mPchNvsAreaProtocol.Area->SWQ1 =3D BIT1;=0D + mPchNvsAreaProtocol.Area->SWQ2 =3D BIT1;=0D + mPchNvsAreaProtocol.Area->SWQ3 =3D BIT1;=0D + }=0D +=0D + mPchNvsAreaProtocol.Area->SWMC =3D GetPchHdaMaxSndwLinkNum ();=0D +=0D + mPchNvsAreaProtocol.Area->ACS0 =3D (UINT8)HdAudioDxeConfig->SndwConfig[0= ].AutonomousClockStop;=0D + mPchNvsAreaProtocol.Area->ACS1 =3D (UINT8)HdAudioDxeConfig->SndwConfig[1= ].AutonomousClockStop;=0D + mPchNvsAreaProtocol.Area->ACS2 =3D (UINT8)HdAudioDxeConfig->SndwConfig[2= ].AutonomousClockStop;=0D + mPchNvsAreaProtocol.Area->ACS3 =3D (UINT8)HdAudioDxeConfig->SndwConfig[3= ].AutonomousClockStop;=0D +=0D + mPchNvsAreaProtocol.Area->DAI0 =3D (UINT8)HdAudioDxeConfig->SndwConfig[0= ].DataOnActiveIntervalSelect;=0D + mPchNvsAreaProtocol.Area->DAI1 =3D (UINT8)HdAudioDxeConfig->SndwConfig[1= ].DataOnActiveIntervalSelect;=0D + mPchNvsAreaProtocol.Area->DAI2 =3D (UINT8)HdAudioDxeConfig->SndwConfig[2= ].DataOnActiveIntervalSelect;=0D + mPchNvsAreaProtocol.Area->DAI3 =3D (UINT8)HdAudioDxeConfig->SndwConfig[3= ].DataOnActiveIntervalSelect;=0D +=0D + mPchNvsAreaProtocol.Area->DOD0 =3D (UINT8)HdAudioDxeConfig->SndwConfig[0= ].DataOnDelaySelect;=0D + mPchNvsAreaProtocol.Area->DOD1 =3D (UINT8)HdAudioDxeConfig->SndwConfig[1= ].DataOnDelaySelect;=0D + mPchNvsAreaProtocol.Area->DOD2 =3D (UINT8)HdAudioDxeConfig->SndwConfig[2= ].DataOnDelaySelect;=0D + mPchNvsAreaProtocol.Area->DOD3 =3D (UINT8)HdAudioDxeConfig->SndwConfig[3= ].DataOnDelaySelect;=0D +}=0D +=0D +/**=0D + Initialize Intel High Definition Audio ACPI Tables=0D +=0D + @retval EFI_SUCCESS The function completed successfully=0D + @retval EFI_LOAD_ERROR ACPI table cannot be installed=0D + @retval EFI_UNSUPPORTED ACPI table not set because DSP is disabl= ed=0D +**/=0D +EFI_STATUS=0D +PchHdAudioAcpiInit (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINT64 HdaPciBase;=0D + CONST HDAUDIO_HOB *HdAudioConfigHob;=0D + PCH_POLICY_PROTOCOL *PchPolicy;=0D + HDAUDIO_DXE_CONFIG *HdAudioDxeConfig;=0D + NHLT_ACPI_TABLE *NhltTable;=0D +=0D +=0D + DEBUG ((DEBUG_INFO, "PchHdAudioAcpiInit() Start\n"));=0D +=0D + HdAudioConfigHob =3D &mPchConfigHob->HdAudio;=0D +=0D + ///=0D + /// Get PCH Policy Protocol=0D + ///=0D + Status =3D gBS->LocateProtocol (&gPchPolicyProtocolGuid, NULL, (VOID **)= &PchPolicy);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + ///=0D + /// Get HD Audio DXE Config Block=0D + ///=0D + Status =3D GetConfigBlock ((VOID *)PchPolicy, &gHdAudioDxeConfigGuid, (V= OID *)&HdAudioDxeConfig);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + HdaPciBase =3D HdaPciCfgBase ();=0D +=0D + if ((PciSegmentRead16 (HdaPciBase + PCI_VENDOR_ID_OFFSET) =3D=3D 0xFFFF)= || (HdAudioConfigHob->DspEnable =3D=3D FALSE)) {=0D + // Do not set ACPI tables if HDAudio is Function disabled or DSP is di= sabled=0D + DEBUG ((DEBUG_INFO, "AudioDSP: Non-HDAudio ACPI Table (NHLT) not set!\= n"));=0D + return EFI_UNSUPPORTED;=0D + }=0D +=0D + NhltTable =3D LocateNhltAcpiTable ();=0D + if (NhltTable =3D=3D NULL) {=0D + return EFI_LOAD_ERROR;=0D + }=0D +=0D + UpdateHdaAcpiData ((UINT64) (UINTN) NhltTable, (UINT32) (NhltTable->Head= er.Length), HdAudioConfigHob, HdAudioDxeConfig);=0D + DEBUG_CODE ( NhltAcpiTableDump (NhltTable); );=0D +=0D + DEBUG ((DEBUG_INFO, "PchHdAudioAcpiInit() End - Status =3D %r\n", Status= ));=0D + return Status;=0D +}=0D +=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c b/= Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c new file mode 100644 index 0000000000..734d4e295a --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c @@ -0,0 +1,314 @@ +/** @file=0D + This is the Common driver that initializes the Intel PCH.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include "PchInit.h"=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +//=0D +// Module variables=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED PCH_CONFIG_HOB *mPchConfigHob;=0D +=0D +//=0D +// EFI_EVENT=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED EFI_EVENT mHeciEvent;=0D +=0D +/**=0D + Common PchInit Module Entry Point=0D +**/=0D +VOID=0D +PchInitEntryPointCommon (=0D + VOID=0D + )=0D +{=0D + EFI_PEI_HOB_POINTERS HobPtr;=0D +=0D + DEBUG ((DEBUG_INFO, "PchInitEntryPointCommon() Start\n"));=0D +=0D + //=0D + // Get PCH Config HOB.=0D + //=0D + HobPtr.Guid =3D GetFirstGuidHob (&gPchConfigHobGuid);=0D + ASSERT (HobPtr.Guid !=3D NULL);=0D + mPchConfigHob =3D (PCH_CONFIG_HOB *) GET_GUID_HOB_DATA (HobPtr.Guid);=0D +=0D + DEBUG ((DEBUG_INFO, "PchInitEntryPointCommon() End\n"));=0D +=0D + return;=0D +}=0D +=0D +/**=0D + Lock SPI register before boot=0D +**/=0D +VOID=0D +LockSpiConfiguration (=0D + VOID=0D + )=0D +{=0D + UINTN Index;=0D + UINT16 Data16;=0D + UINT16 Data16And;=0D + UINT16 Data16Or;=0D + UINT32 Data32;=0D + UINT32 DlockValue;=0D + UINT64 PciSpiRegBase;=0D + UINT32 PchSpiBar0;=0D + UINT32 Timer;=0D +=0D + PciSpiRegBase =3D SpiPciCfgBase ();=0D +=0D + //=0D + // Check for SPI controller presence before programming=0D + //=0D + if (PciSegmentRead16 (PciSpiRegBase + PCI_VENDOR_ID_OFFSET) =3D=3D 0xFFF= F) {=0D + return;=0D + }=0D +=0D + //=0D + // Make sure SPI BAR0 has fixed address before writing to boot script.=0D + // The same base address is set in PEI and will be used during resume.=0D + //=0D + PchSpiBar0 =3D PCH_SPI_BASE_ADDRESS;=0D +=0D + PciSegmentAnd8 (PciSpiRegBase + PCI_COMMAND_OFFSET, (UINT8) ~EFI_PCI_= COMMAND_MEMORY_SPACE);=0D + PciSegmentWrite32 (PciSpiRegBase + R_SPI_CFG_BAR0, PchSpiBar0);=0D + PciSegmentOr8 (PciSpiRegBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_M= EMORY_SPACE);=0D +=0D + //=0D + // Locking for security reasons only if Extended BIOS Range Decode is su= pported=0D + //=0D + if (IsExtendedBiosRangeDecodeSupported ()) {=0D + //=0D + // Before setting FLOCKDN lock Extended BIOS Range configuration=0D + // All configuration of this feature shall be done already at this mom= ent=0D + //=0D + PciSegmentOr32 (PciSpiRegBase + R_SPI_CFG_BC, BIT28);=0D + S3BootScriptSavePciCfgWrite (=0D + S3BootScriptWidthUint32,=0D + (UINTN) PciSpiRegBase + R_SPI_CFG_BC,=0D + 1,=0D + (VOID *) (UINTN) (PciSpiRegBase + R_SPI_CFG_BC)=0D + );=0D + }=0D +=0D + //=0D + // Program the Flash Protection Range Register based on policy=0D + //=0D + DlockValue =3D MmioRead32 (PchSpiBar0 + R_SPI_MEM_DLOCK);=0D + for (Index =3D 0; Index < PCH_FLASH_PROTECTED_RANGES; ++Index) {=0D + if ((mPchConfigHob->ProtectRange[Index].WriteProtectionEnable ||=0D + mPchConfigHob->ProtectRange[Index].ReadProtectionEnable) !=3D TRU= E) {=0D + continue;=0D + }=0D +=0D + //=0D + // Proceed to program the register after ensure it is enabled=0D + //=0D + Data32 =3D 0;=0D + Data32 |=3D (mPchConfigHob->ProtectRange[Index].WriteProtectionEnable = =3D=3D TRUE) ? B_SPI_MEM_PRX_WPE : 0;=0D + Data32 |=3D (mPchConfigHob->ProtectRange[Index].ReadProtectionEnable = =3D=3D TRUE) ? B_SPI_MEM_PRX_RPE : 0;=0D + Data32 |=3D ((UINT32) mPchConfigHob->ProtectRange[Index].ProtectedRang= eLimit << N_SPI_MEM_PRX_PRL) & B_SPI_MEM_PRX_PRL_MASK;=0D + Data32 |=3D ((UINT32) mPchConfigHob->ProtectRange[Index].ProtectedRang= eBase << N_SPI_MEM_PRX_PRB) & B_SPI_MEM_PRX_PRB_MASK;=0D + DEBUG ((DEBUG_INFO, "Protected range %d: 0x%08x \n", Index, Data32));= =0D +=0D + DlockValue |=3D (UINT32) (B_SPI_MEM_DLOCK_PR0LOCKDN << Index);=0D + MmioWrite32 ((UINTN) (PchSpiBar0 + (R_SPI_MEM_PR0 + (Index * S_SPI_MEM= _PRX))), Data32);=0D + S3BootScriptSaveMemWrite (=0D + S3BootScriptWidthUint32,=0D + (UINTN) (PchSpiBar0 + (R_SPI_MEM_PR0 + (Index * S_SPI_MEM_PRX))),=0D + 1,=0D + (VOID *) (UINTN) (PchSpiBar0 + (R_SPI_MEM_PR0 + (Index * S_SPI_MEM_P= RX)))=0D + );=0D + }=0D + //=0D + // Program DLOCK register=0D + //=0D + MmioWrite32 ((UINTN) (PchSpiBar0 + R_SPI_MEM_DLOCK), DlockValue);=0D + S3BootScriptSaveMemWrite (=0D + S3BootScriptWidthUint32,=0D + (UINTN) (PchSpiBar0 + R_SPI_MEM_DLOCK),=0D + 1,=0D + (VOID *) (UINTN) (PchSpiBar0 + R_SPI_MEM_DLOCK)=0D + );=0D +=0D + ///=0D + /// PCH BIOS Spec Section 3.6 Flash Security Recommendation=0D + /// In PCH SPI controller the BIOS should set the Flash Configuration Lo= ck-Down bit=0D + /// (SPI_BAR0 + 04[15]) at end of post. When set to 1, those Flash Prog= ram Registers=0D + /// that are locked down by this FLOCKDN bit cannot be written.=0D + /// Please refer to the EDS for which program registers are impacted.=0D + /// Additionally BIOS must program SPI_BAR0 + 0x04 BIT11 (WRSDIS) to dis= able Write Status in HW sequencing=0D + ///=0D +=0D + //=0D + // Ensure there is no pending SPI trasaction before setting lock bits=0D + //=0D + Timer =3D 0;=0D + while (MmioRead16 (PchSpiBar0 + R_SPI_MEM_HSFSC) & B_SPI_MEM_HSFSC_SCIP)= {=0D + if (Timer > SPI_WAIT_TIME) {=0D + //=0D + // SPI transaction is pending too long at this point, exit with erro= r.=0D + //=0D + DEBUG ((DEBUG_ERROR, "SPI Cycle timeout\n"));=0D + ASSERT (FALSE);=0D + break;=0D + }=0D + MicroSecondDelay (SPI_WAIT_PERIOD);=0D + Timer +=3D SPI_WAIT_PERIOD;=0D + }=0D +=0D + Data16And =3D B_SPI_MEM_HSFSC_SCIP;=0D + Data16 =3D 0;=0D + S3BootScriptSaveMemPoll (=0D + S3BootScriptWidthUint16,=0D + PchSpiBar0 + R_SPI_MEM_HSFSC,=0D + &Data16And,=0D + &Data16,=0D + SPI_WAIT_PERIOD,=0D + SPI_WAIT_TIME / SPI_WAIT_PERIOD=0D + );=0D +=0D + //=0D + // Clear any outstanding status=0D + //=0D + Data16Or =3D B_SPI_MEM_HSFSC_SAF_DLE=0D + | B_SPI_MEM_HSFSC_SAF_ERROR=0D + | B_SPI_MEM_HSFSC_AEL=0D + | B_SPI_MEM_HSFSC_FCERR=0D + | B_SPI_MEM_HSFSC_FDONE;=0D + Data16And =3D 0xFFFF;=0D + MmioAndThenOr16 (PchSpiBar0 + R_SPI_MEM_HSFSC, Data16And, Data16Or);=0D + S3BootScriptSaveMemReadWrite (=0D + S3BootScriptWidthUint16,=0D + PchSpiBar0 + R_SPI_MEM_HSFSC,=0D + &Data16Or,=0D + &Data16And=0D + );=0D +=0D + //=0D + // Set WRSDIS=0D + //=0D + Data16Or =3D B_SPI_MEM_HSFSC_WRSDIS;=0D + Data16And =3D 0xFFFF;=0D + MmioAndThenOr16 (PchSpiBar0 + R_SPI_MEM_HSFSC, Data16And, Data16Or);=0D + S3BootScriptSaveMemReadWrite (=0D + S3BootScriptWidthUint16,=0D + PchSpiBar0 + R_SPI_MEM_HSFSC,=0D + &Data16Or,=0D + &Data16And=0D + );=0D +=0D + //=0D + // Set FLOCKDN=0D + //=0D + Data16Or =3D B_SPI_MEM_HSFSC_FLOCKDN;=0D + Data16And =3D 0xFFFF;=0D + MmioAndThenOr16 (PchSpiBar0 + R_SPI_MEM_HSFSC, Data16And, Data16Or);=0D + S3BootScriptSaveMemReadWrite (=0D + S3BootScriptWidthUint16,=0D + PchSpiBar0 + R_SPI_MEM_HSFSC,=0D + &Data16Or,=0D + &Data16And=0D + );=0D +=0D + ///=0D + /// SPI Flash Programming Guide Section 5.5.2 Vendor Component Lock=0D + /// It is strongly recommended that BIOS sets the Vendor Component Lock = (VCL) bits. VCL applies=0D + /// the lock to both VSCC0 and VSCC1 even if VSCC0 is not used. Without = the VCL bits set, it is=0D + /// possible to make Host/GbE VSCC register(s) changes in that can cause= undesired host and=0D + /// integrated GbE Serial Flash functionality.=0D + ///=0D + MmioOr32 ((UINTN) (PchSpiBar0 + R_SPI_MEM_SFDP0_VSCC0), B_SPI_MEM_SFDP0_= VSCC0_VCL);=0D + S3BootScriptSaveMemWrite (=0D + S3BootScriptWidthUint32,=0D + (UINTN) (PchSpiBar0 + R_SPI_MEM_SFDP0_VSCC0),=0D + 1,=0D + (VOID *) (UINTN) (PchSpiBar0 + R_SPI_MEM_SFDP0_VSCC0)=0D + );=0D +}=0D +=0D +/**=0D + Set HD Audio PME bit=0D +**/=0D +VOID=0D +ConfigureHdAudioPme (=0D + VOID=0D + )=0D +{=0D + UINT64 HdaPciBase;=0D +=0D + HdaPciBase =3D HdaPciCfgBase ();=0D +=0D + if (PciSegmentRead16 (HdaPciBase + PCI_VENDOR_ID_OFFSET) =3D=3D 0xFFFF) = {=0D + return;=0D + }=0D +=0D + ///=0D + /// PME Enable for Audio controller=0D + ///=0D + if (mPchConfigHob->HdAudio.Pme =3D=3D TRUE) {=0D + PciSegmentOr32 (HdaPciBase + R_HDA_CFG_PCS, (UINT32) B_HDA_CFG_PCS_PME= E);=0D + }=0D +}=0D +=0D +/**=0D + Set eSPI BME bit=0D +**/=0D +VOID=0D +ConfigureEspiBme (=0D + VOID=0D + )=0D +{=0D + UINT64 EspiPciBase;=0D +=0D + EspiPciBase =3D EspiPciCfgBase ();=0D +=0D + if (PciSegmentRead16 (EspiPciBase + PCI_VENDOR_ID_OFFSET) =3D=3D 0xFFFF)= {=0D + return;=0D + }=0D + if ((PciSegmentRead32 (EspiPciBase + R_ESPI_CFG_PCBC) & B_ESPI_CFG_PCBC_= ESPI_EN) =3D=3D 0) {=0D + return;=0D + }=0D +=0D + //=0D + // Refer to PCH BWG.=0D + // To enable eSPI bus mastering BIOS must enable BME in eSPI controller= =0D + // and also set BME bit in the respective slave devices through Configur= ation=0D + // and Capabilities register of each slave using Get_Configuration and S= et_Configuration functionality.=0D + //=0D + // NOTE: The setting is also done in PEI, but might be cleared by PCI bu= s during PCI enumeration.=0D + // Therefore, reeable it after PCI enumeration done.=0D + //=0D + if (mPchConfigHob->Espi.BmeMasterSlaveEnabled =3D=3D TRUE) {=0D + PciSegmentOr8 (EspiPciBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_BUS_M= ASTER);=0D + }=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h b/= Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h new file mode 100644 index 0000000000..0d6647e3f3 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h @@ -0,0 +1,122 @@ +/** @file=0D + Header file for PCH Initialization Driver.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#ifndef _PCH_INIT_DXE_H_=0D +#define _PCH_INIT_DXE_H_=0D +=0D +#include =0D +#include =0D +#include =0D +=0D +//=0D +// Data definitions=0D +//=0D +extern EFI_HANDLE mImageHandle;=0D +=0D +//=0D +// Pch NVS area definition=0D +//=0D +extern PCH_NVS_AREA_PROTOCOL mPchNvsAreaProtocol;=0D +=0D +extern PCH_CONFIG_HOB *mPchConfigHob;=0D +extern SI_CONFIG_HOB_DATA *mSiConfigHobData;=0D +=0D +//=0D +// Function Prototype=0D +//=0D +=0D +//=0D +// Local function prototypes=0D +//=0D +/**=0D + Common PchInit Module Entry Point=0D +**/=0D +VOID=0D +PchInitEntryPointCommon (=0D + VOID=0D + );=0D +=0D +/**=0D + Calls Boot Os Hand off routine for each Serial IO Controller=0D +**/=0D +VOID=0D +ConfigureSerialIoAtBoot (=0D + VOID=0D + );=0D +=0D +/**=0D + Puts all SerialIo controllers (except UARTs in debug mode) in D3.=0D + Clears MemoryEnable for all PCI-mode controllers on S3 resume=0D +**/=0D +VOID=0D +ConfigureSerialIoAtS3Resume (=0D + VOID=0D + );=0D +=0D +/**=0D + Add Serial Io UART Hidden Handles=0D +**/=0D +VOID=0D +CreateSerialIoUartHiddenHandle (=0D + VOID=0D + );=0D +=0D +/**=0D + Initialize Intel High Definition Audio ACPI Tables=0D +=0D + @retval EFI_SUCCESS The function completed successfully=0D + @retval EFI_LOAD_ERROR ACPI table cannot be installed=0D + @retval EFI_UNSUPPORTED ACPI table not set because DSP is disabl= ed=0D +**/=0D +EFI_STATUS=0D +PchHdAudioAcpiInit (=0D + VOID=0D + );=0D +=0D +/**=0D + Perform the remaining configuration on SATA to perform device detection,= =0D + then set the SATA SPD and PxE corresponding, and set the Register Lock o= n PCH SATA=0D +**/=0D +VOID=0D +ConfigureSataOnEndOfDxe (=0D + VOID=0D + );=0D +=0D +/**=0D + Update ASL data for CNVI Device.=0D +=0D + @retval EFI_SUCCESS The function completed successfully=0D +**/=0D +EFI_STATUS=0D +UpdateCnviAcpiData (=0D + VOID=0D + );=0D +=0D +/**=0D + Initialize Pch acpi=0D + @param[in] ImageHandle Handle for the image of this driver=0D +=0D + @retval EFI_SUCCESS The function completed successfully=0D + @retval EFI_OUT_OF_RESOURCES Do not have enough resources to initiali= ze the driver=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchAcpiInit (=0D + IN EFI_HANDLE ImageHandle=0D + );=0D +=0D +/**=0D + Update ASL object before Boot=0D +=0D + @retval EFI_STATUS=0D + @retval EFI_NOT_READY The Acpi protocols are not ready.=0D +**/=0D +EFI_STATUS=0D +PchUpdateNvsArea (=0D + VOID=0D + );=0D +=0D +#endif // _PCH_INIT_DXE_H_=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c= b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c new file mode 100644 index 0000000000..1d4f08a86c --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c @@ -0,0 +1,354 @@ +/** @file=0D + This is the Uefi driver that initializes the Intel PCH.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include "PchInit.h"=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED EFI_HANDLE mImageHandle;=0D +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPcieIoTrapAddress;= =0D +=0D +VOID=0D +EFIAPI=0D +PchOnBootToOs (=0D + IN EFI_EVENT Event,=0D + IN VOID *Context=0D + );=0D +=0D +=0D +VOID=0D +EFIAPI=0D +PchOnExitBootServices (=0D + IN EFI_EVENT Event,=0D + IN VOID *Context=0D + );=0D +=0D +=0D +VOID=0D +EFIAPI=0D +PchOnReadyToBoot (=0D + IN EFI_EVENT Event,=0D + IN VOID *Context=0D + );=0D +=0D +/**=0D + Process all the lock downs=0D +**/=0D +VOID=0D +ProcessSmiLocks (=0D + VOID=0D + )=0D +{=0D + UINT32 Data32And;=0D + UINT32 Data32Or;=0D + UINT16 ABase;=0D +=0D + ///=0D + /// PCH BIOS Spec Section 3.6 Flash Security Recommendation=0D + /// BIOS needs to enables SMI_LOCK (PMC PCI offset A0h[4] =3D 1b) which = prevent writes=0D + /// to the Global SMI Enable bit (GLB_SMI_EN ABASE + 30h[0]). Enabling t= his bit will=0D + /// mitigate malicious software attempts to gain system management mode = privileges.=0D + ///=0D + if (mPchConfigHob->LockDown.GlobalSmi =3D=3D TRUE) {=0D + ///=0D + /// Save Global SMI Enable bit setting before BIOS enables SMI_LOCK du= ring S3 resume=0D + ///=0D + ABase =3D PmcGetAcpiBase ();=0D + Data32Or =3D IoRead32 ((UINTN) (ABase + R_ACPI_IO_SMI_EN));=0D + if ((Data32Or & B_ACPI_IO_SMI_EN_GBL_SMI) !=3D 0) {=0D + Data32And =3D 0xFFFFFFFF;=0D + Data32Or |=3D B_ACPI_IO_SMI_EN_GBL_SMI;=0D + S3BootScriptSaveIoReadWrite (=0D + S3BootScriptWidthUint32,=0D + (UINTN) (ABase + R_ACPI_IO_SMI_EN),=0D + &Data32Or, // Data to be ORed=0D + &Data32And // Data to be ANDed=0D + );=0D + }=0D + PmcLockSmiWithS3BootScript ();=0D + }=0D +}=0D +=0D +/**=0D + Do PCIE power management while resume from S3=0D +**/=0D +VOID=0D +ReconfigurePciePowerManagementForS3 (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINT32 Data32;=0D + PCH_PCIE_IOTRAP_PROTOCOL *PchPcieIoTrapProtocol;=0D +=0D + Status =3D gBS->LocateProtocol (&gPchPcieIoTrapProtocolGuid, NULL, (VOID= **) &PchPcieIoTrapProtocol);=0D + if (EFI_ERROR (Status)) {=0D + return;=0D + }=0D + mPcieIoTrapAddress =3D PchPcieIoTrapProtocol->PcieTrapAddress;=0D + DEBUG ((DEBUG_INFO, "PcieIoTrapAddress: %0x\n", mPcieIoTrapAddress));=0D +=0D + if (mPcieIoTrapAddress !=3D 0) {=0D + //=0D + // Save PCH PCIE IoTrap address to re-config PCIE power management set= ting after resume from S3=0D + //=0D + Data32 =3D PchPciePmTrap;=0D + S3BootScriptSaveIoWrite (=0D + S3BootScriptWidthUint32,=0D + (UINTN) (mPcieIoTrapAddress),=0D + 1,=0D + &Data32=0D + );=0D + } else {=0D + ASSERT (FALSE);=0D + }=0D +}=0D +=0D +/**=0D + This is the callback function for PCI ENUMERATION COMPLETE.=0D +**/=0D +VOID=0D +EFIAPI=0D +PchOnPciEnumComplete (=0D + IN EFI_EVENT Event,=0D + IN VOID *Context=0D + )=0D +{=0D + EFI_STATUS Status;=0D + VOID *ProtocolPointer;=0D +=0D + ///=0D + /// Check if this is first time called by EfiCreateProtocolNotifyEvent()= or not,=0D + /// if it is, we will skip it until real event is triggered=0D + ///=0D + Status =3D gBS->LocateProtocol (&gEfiPciEnumerationCompleteProtocolGuid,= NULL, (VOID **) &ProtocolPointer);=0D + if (EFI_SUCCESS !=3D Status) {=0D + return;=0D + }=0D + gBS->CloseEvent (Event);=0D +=0D + ReconfigurePciePowerManagementForS3 ();=0D + ProcessSmiLocks ();=0D + ConfigureSerialIoAtS3Resume ();=0D +}=0D +=0D +/**=0D + Register callback functions for PCH DXE.=0D +**/=0D +VOID=0D +PchRegisterNotifications (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_EVENT ReadyToBoot;=0D + EFI_EVENT LegacyBootEvent;=0D + EFI_EVENT ExitBootServicesEvent;=0D + VOID *Registration;=0D +=0D + ///=0D + /// Create PCI Enumeration Completed callback for PCH=0D + ///=0D + EfiCreateProtocolNotifyEvent (=0D + &gEfiPciEnumerationCompleteProtocolGuid,=0D + TPL_CALLBACK,=0D + PchOnPciEnumComplete,=0D + NULL,=0D + &Registration=0D + );=0D +=0D + //=0D + // Register a Ready to boot event to config PCIE power management settin= g after OPROM executed=0D + //=0D + Status =3D EfiCreateEventReadyToBootEx (=0D + TPL_CALLBACK,=0D + PchOnReadyToBoot,=0D + NULL,=0D + &ReadyToBoot=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + //=0D + // Create events for PCH to do the task before ExitBootServices/LegacyBo= ot.=0D + // It is guaranteed that only one of two events below will be signalled= =0D + //=0D + Status =3D gBS->CreateEvent (=0D + EVT_SIGNAL_EXIT_BOOT_SERVICES,=0D + TPL_CALLBACK,=0D + PchOnExitBootServices,=0D + NULL,=0D + &ExitBootServicesEvent=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Status =3D EfiCreateEventLegacyBootEx (=0D + TPL_CALLBACK,=0D + PchOnBootToOs,=0D + NULL,=0D + &LegacyBootEvent=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +}=0D +=0D +/**=0D + PchInit DXE Module Entry Point\n=0D + - Introduction\n=0D + The PchInit module is a DXE driver that initializes the Intel Platfo= rm Controller Hub=0D + following the PCH BIOS specification and EDS requirements and recomm= endations. It consumes=0D + the PCH_POLICY_HOB SI_POLICY_HOB for expected configurations per pol= icy.=0D + This is the standard EFI driver point that detects whether there is = an supported PCH in=0D + the system and if so, initializes the chipset.=0D +=0D + - Details\n=0D + This module is required for initializing the Intel Platform Controller= Hub to=0D + follow the PCH BIOS specification and EDS.=0D + This includes some initialization sequences, enabling and disabling PC= H devices,=0D + configuring clock gating, RST PCIe Storage Remapping, SATA controller,= ASPM of PCIE devices. Right before end of DXE,=0D + it's responsible to lock down registers for security requirement.=0D +=0D + - @pre=0D + - PCH PCR base address configured=0D + - EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL=0D + - This is to ensure that PCI MMIO and IO resource has been prepared = and available for this driver to allocate.=0D +=0D + - @result=0D + - Publishes the @link _PCH_INFO_PROTOCOL PCH_INFO_PROTOCOL @endlink=0D + - Publishes the @link _PCH_EMMC_TUNING_PROTOCOL PCH_EMMC_TUNING_PROTOC= OL @endlink=0D +=0D + - References\n=0D + - @link _PCH_POLICY PCH_POLICY_HOB @endlink.=0D + - @link _SI_POLICY_STRUCT SI_POLICY_HOB @endlink.=0D +=0D + - Integration Checklists\n=0D + - Verify prerequisites are met. Porting Recommendations.=0D + - No modification of this module should be necessary=0D + - Any modification of this module should follow the PCH BIOS Specifica= tion and EDS=0D +=0D + @param[in] ImageHandle Handle for the image of this driver=0D + @param[in] SystemTable Pointer to the EFI System Table=0D +=0D + @retval EFI_SUCCESS The function completed successfully=0D + @retval EFI_OUT_OF_RESOURCES Do not have enough resources to initiali= ze the driver=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchInitEntryPointDxe (=0D + IN EFI_HANDLE ImageHandle,=0D + IN EFI_SYSTEM_TABLE *SystemTable=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + DEBUG ((DEBUG_INFO, "PchInitEntryPointDxe() Start\n"));=0D +=0D + mImageHandle =3D ImageHandle;=0D +=0D + PchInitEntryPointCommon ();=0D +=0D + Status =3D PchAcpiInit (ImageHandle);=0D +=0D + PchRegisterNotifications ();=0D +=0D + CreateSerialIoUartHiddenHandle ();=0D +=0D + DEBUG ((DEBUG_INFO, "PchInitEntryPointDxe() End\n"));=0D +=0D + return Status;=0D +}=0D +=0D +/**=0D + PCH initialization before ExitBootServices / LegacyBoot events=0D + Useful for operations which must happen later than at EndOfPost event=0D +=0D + @param[in] Event A pointer to the Event that triggered th= e callback.=0D + @param[in] Context A pointer to private data registered wit= h the callback function.=0D +**/=0D +VOID=0D +EFIAPI=0D +PchOnBootToOs (=0D + IN EFI_EVENT Event,=0D + IN VOID *Context=0D + )=0D +{=0D + ///=0D + /// Closed the event to avoid call twice=0D + ///=0D + if (Event !=3D NULL) {=0D + gBS->CloseEvent (Event);=0D + }=0D +=0D + ConfigureSerialIoAtBoot ();=0D +=0D + return;=0D +}=0D +=0D +/**=0D + PCH initialization on ExitBootService. This event is used if only ExitBo= otService is used=0D + and not in legacy boot=0D +=0D + @param[in] Event A pointer to the Event that triggered th= e callback.=0D + @param[in] Context A pointer to private data registered wit= h the callback function.=0D +=0D + @retval None=0D +**/=0D +VOID=0D +EFIAPI=0D +PchOnExitBootServices (=0D + IN EFI_EVENT Event,=0D + IN VOID *Context=0D + )=0D +{=0D + PchOnBootToOs (NULL, NULL);=0D +=0D + return;=0D +}=0D +=0D +/**=0D + PCH initialization before boot to OS=0D +=0D + @param[in] Event A pointer to the Event that triggered th= e callback.=0D + @param[in] Context A pointer to private data registered wit= h the callback function.=0D +**/=0D +VOID=0D +EFIAPI=0D +PchOnReadyToBoot (=0D + IN EFI_EVENT Event,=0D + IN VOID *Context=0D + )=0D +{=0D + DEBUG ((DEBUG_INFO, "Uefi PchOnReadyToBoot() Start\n"));=0D +=0D + if (Event !=3D NULL) {=0D + gBS->CloseEvent (Event);=0D + }=0D +=0D + //=0D + // Trigger an Iotrap SMI to config PCIE power management setting after P= CI enumrate is done=0D + //=0D + if (mPcieIoTrapAddress !=3D 0) {=0D + IoWrite32 ((UINTN) mPcieIoTrapAddress, PchPciePmTrap);=0D + } else {=0D + ASSERT (FALSE);=0D + }=0D +=0D + DEBUG ((DEBUG_INFO, "Uefi PchOnReadyToBoot() End\n"));=0D +}=0D +=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeTg= l.inf b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeTgl.inf new file mode 100644 index 0000000000..4941ff0f49 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeTgl.inf @@ -0,0 +1,96 @@ +## @file=0D +# Component description file for Pch Initialization driver=0D +#=0D +# Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +=0D +[Defines]=0D +INF_VERSION =3D 0x00010017=0D +BASE_NAME =3D PchInitDxeTgl=0D +FILE_GUID =3D 4BD0EB2F-3A2D-442E-822D-753516F75424=0D +VERSION_STRING =3D 1.0=0D +MODULE_TYPE =3D DXE_DRIVER=0D +ENTRY_POINT =3D PchInitEntryPointDxe=0D +=0D +=0D +[LibraryClasses]=0D +S3BootScriptLib=0D +PchCycleDecodingLib=0D +PchPcieRpLib=0D +PchPcrLib=0D +PchInfoLib=0D +PciExpressHelpersLib=0D +UefiBootServicesTableLib=0D +DebugLib=0D +IoLib=0D +TimerLib=0D +HobLib=0D +BaseMemoryLib=0D +MemoryAllocationLib=0D +UefiLib=0D +DxeServicesTableLib=0D +UefiDriverEntryPoint=0D +UefiRuntimeServicesTableLib=0D +GpioLib=0D +SerialIoAccessLib=0D +ConfigBlockLib=0D +PmcLib=0D +PmcPrivateLibWithS3=0D +SataLib=0D +PchDmiWithS3Lib=0D +GbeLib=0D +SiScheduleResetLib=0D +DxeHdaNhltLib=0D +SpiAccessPrivateLib=0D +PchPciBdfLib=0D +=0D +[Packages]=0D +MdePkg/MdePkg.dec=0D +TigerlakeSiliconPkg/SiPkg.dec=0D +=0D +=0D +[Pcd]=0D +gSiPkgTokenSpaceGuid.PcdSiPciExpressBaseAddress=0D +gSiPkgTokenSpaceGuid.PcdSiliconInitTempMemBaseAddr ## CONSUMES=0D +gSiPkgTokenSpaceGuid.PcdEmbeddedEnable ## CONSUMES=0D +=0D +[Sources]=0D +PchInitDxe.c=0D +PchInit.h=0D +PchInit.c=0D +PchSata.c=0D +PchSerialIo.c=0D +PchSerialIoDxe.c=0D +PchHdaAcpi.c=0D +PchCnviAcpi.c=0D +PchAcpi.c=0D +=0D +=0D +[Protocols]=0D +gPchNvsAreaProtocolGuid ## PRODUCES=0D +gEfiPciIoProtocolGuid ## CONSUMES=0D +gEfiAcpiTableProtocolGuid ## CONSUMES=0D +gEfiBlockIoProtocolGuid ## CONSUMES=0D +gHeciProtocolGuid=0D +gEfiPciEnumerationCompleteProtocolGuid ## CONSUMES=0D +gPchPcieIoTrapProtocolGuid ## CONSUMES=0D +gPchPolicyProtocolGuid ## CONSUMES=0D +=0D +=0D +[Guids]=0D +gEfiEndOfDxeEventGroupGuid=0D +gEfiAcpiTableGuid=0D +gEmmcDxeConfigGuid ## CONSUMES=0D +gSiConfigHobGuid ## CONSUMES=0D +gPchConfigHobGuid ## CONSUMES=0D +gPchRstHobGuid ## CONSUMES=0D +gHdAudioDxeConfigGuid ## CONSUMES=0D +gGpioDxeConfigGuid ## CONSUMES=0D +gCnviConfigHobGuid ## CONSUMES=0D +gHybridStorageHobGuid ## CONSUMES=0D +=0D +[Depex]=0D +gEfiPciHostBridgeResourceAllocationProtocolGuid ## This is to ensure that = PCI MMIO and IO resource has been prepared and available for this driver to= allocate.=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c b/= Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c new file mode 100644 index 0000000000..886f3b4bc0 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c @@ -0,0 +1,89 @@ +/** @file=0D + Perform related functions for PCH Sata in DXE phase=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +=0D +#include =0D +#include =0D +#include =0D +=0D +#include "PchInit.h"=0D +#include =0D +#include =0D +#include =0D +=0D +/**=0D + Perform the remaining configuration on SATA to perform device detection,= =0D + then set the SATA SPD and PxE corresponding, and set the Register Lock o= n PCH SATA=0D +=0D + @retval None=0D +**/=0D +VOID=0D +ConfigureSataOnEndOfDxe (=0D + VOID=0D + )=0D +{=0D + UINT64 PciSataRegBase;=0D + UINT16 SataPortsEnabled;=0D + UINT32 DwordReg;=0D + UINTN Index;=0D + UINT32 SataCtrlIndex;=0D +=0D + for (SataCtrlIndex =3D 0; SataCtrlIndex < MaxSataControllerNum (); SataC= trlIndex++) {=0D + ///=0D + /// SATA PCS: Enable the port in any of below condition:=0D + /// i.) Hot plug is enabled=0D + /// ii.) A device is attached=0D + /// iii.) Test mode is enabled=0D + /// iv.) Configured as eSATA port=0D + ///=0D + PciSataRegBase =3D SataPciCfgBase (SataCtrlIndex);=0D + SataPortsEnabled =3D 0;=0D +=0D + DwordReg =3D PciSegmentRead32 (PciSataRegBase + R_SATA_CFG_PCS);=0D + for (Index =3D 0; Index < MaxSataPortNum (SataCtrlIndex); Index++) {=0D + if ((mPchConfigHob->Sata[SataCtrlIndex].PortSettings[Index].HotPlug = =3D=3D TRUE) ||=0D + (DwordReg & (B_SATA_CFG_PCS_P0P << Index)) ||=0D + (mPchConfigHob->Sata[SataCtrlIndex].TestMode =3D=3D TRUE) ||=0D + (mPchConfigHob->Sata[SataCtrlIndex].PortSettings[Index].Extern= al =3D=3D TRUE)) {=0D + SataPortsEnabled |=3D (mPchConfigHob->Sata[SataCtrlIndex].PortSe= ttings[Index].Enable << Index);=0D + }=0D + }=0D +=0D + ///=0D + /// Set MAP."Sata PortX Disable", SATA PCI offset 90h[23:16] to 1b if = SATA Port 0/1/2/3/4/5/6/7 is disabled=0D + ///=0D + PciSegmentOr32 (PciSataRegBase + R_SATA_CFG_MAP, (~SataPortsEnabled <<= N_SATA_CFG_MAP_SPD));=0D + S3BootScriptSaveMemWrite (=0D + S3BootScriptWidthUint32,=0D + PcdGet64 (PcdSiPciExpressBaseAddress) + PciSataRegBase + R_SATA_CFG_= MAP,=0D + 1,=0D + (VOID *) (UINTN) (PcdGet64 (PcdSiPciExpressBaseAddress) + PciSataReg= Base + R_SATA_CFG_MAP)=0D + );=0D +=0D + ///=0D + /// Program PCS "Port X Enabled", SATA PCI offset 94h[7:0] =3D Port 0~= 7 Enabled bit as per SataPortsEnabled value.=0D + ///=0D + PciSegmentOr16 (PciSataRegBase + R_SATA_CFG_PCS, SataPortsEnabled);=0D + S3BootScriptSaveMemWrite (=0D + S3BootScriptWidthUint16,=0D + PcdGet64 (PcdSiPciExpressBaseAddress) + PciSataRegBase + R_SATA_CFG_= PCS,=0D + 1,=0D + (VOID *) (UINTN) (PcdGet64 (PcdSiPciExpressBaseAddress) + PciSataReg= Base + R_SATA_CFG_PCS)=0D + );=0D +=0D + ///=0D + /// Step 14=0D + /// Program SATA PCI offset 9Ch [31] to 1b=0D + ///=0D + PciSegmentOr32 ((UINTN) (PciSataRegBase + R_SATA_CFG_SATAGC), BIT31);= =0D + S3BootScriptSaveMemWrite (=0D + S3BootScriptWidthUint32,=0D + PcdGet64 (PcdSiPciExpressBaseAddress) + PciSataRegBase + R_SATA_CFG_= SATAGC,=0D + 1,=0D + (VOID *) (UINTN) (PcdGet64 (PcdSiPciExpressBaseAddress) + PciSataReg= Base + R_SATA_CFG_SATAGC)=0D + );=0D + }=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.= c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c new file mode 100644 index 0000000000..9409a9a387 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c @@ -0,0 +1,33 @@ +/** @file=0D + Initializes Serial IO Controllers.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include "PchInit.h"=0D +#include =0D +#include =0D +=0D +/**=0D + Calls Boot Os Hand off routine for each Serial IO Controller=0D +**/=0D +VOID=0D +ConfigureSerialIoAtBoot (=0D + VOID=0D + )=0D +{=0D + UINT8 Index;=0D +=0D + for (Index =3D 0; Index < GetPchMaxSerialIoSpiControllersNum (); Index++= ) {=0D + SerialIoSpiBootHandler (Index, &mPchConfigHob->SerialIo.SpiDeviceConfi= g[Index]);=0D + }=0D +=0D + for (Index =3D 0; Index < GetPchMaxSerialIoI2cControllersNum (); Index++= ) {=0D + SerialIoI2cBootHandler (Index, &mPchConfigHob->SerialIo.I2cDeviceConfi= g[Index]);=0D + }=0D +=0D + for (Index =3D 0; Index < GetPchMaxSerialIoUartControllersNum (); Index+= +) {=0D + SerialIoUartBootHandler (Index, &mPchConfigHob->SerialIo.UartDeviceCon= fig[Index]);=0D + }=0D +}=0D +=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoD= xe.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c new file mode 100644 index 0000000000..fde7da6b96 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c @@ -0,0 +1,134 @@ +/** @file=0D + Initializes Serial IO Controllers.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +typedef struct {=0D + ACPI_HID_DEVICE_PATH RootPort;=0D + ACPI_EXTENDED_HID_DEVICE_PATH AcpiDev;=0D + CHAR8 HidString[8];=0D + UINT16 DeviceId;=0D + UINT8 UartIndex;=0D + EFI_DEVICE_PATH_PROTOCOL End;=0D +} SERIALIO_UART_DEVICE_PATH;=0D +=0D +#define mPciRootBridge {{ACPI_DEVICE_PATH, ACPI_DP, {(UINT8)(sizeof (ACPI_= HID_DEVICE_PATH)), 0}}, EISA_PNP_ID (0x0A03), 0}=0D +#define mAcpiDev {{ACPI_DEVICE_PATH, ACPI_EXTENDED_DP, {(UINT8)(sizeof (AC= PI_EXTENDED_HID_DEVICE_PATH) + (sizeof(CHAR8) * 8) + sizeof (UINT16) + size= of (UINT8)), 0}},0,0,0}=0D +#define mEndEntire {END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, = {END_DEVICE_PATH_LENGTH, 0}}=0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED SERIALIO_UART_DEVICE_PATH mSerialIoUartPath = =3D {=0D + mPciRootBridge,=0D + mAcpiDev,=0D + "UART\0\0\0",=0D + 0xFFFF,=0D + 0xFF,=0D + mEndEntire=0D +};=0D +=0D +/**=0D + Add Serial Io UART Hidden Handles=0D +**/=0D +VOID=0D +CreateSerialIoUartHiddenHandle (=0D + VOID=0D + )=0D +{=0D + EFI_HANDLE NewHandle;=0D + EFI_DEVICE_PATH_PROTOCOL *NewPath;=0D + EFI_STATUS Status;=0D + UINT8 Index;=0D + UINT16 DeviceId;=0D +=0D + DEBUG ((DEBUG_INFO, "CreateSerialIoUartHandle\n"));=0D +=0D + for (Index =3D 0; Index < GetPchMaxSerialIoUartControllersNum (); Index+= +) {=0D + DEBUG ((DEBUG_INFO, "UART Index: %d Mode: %d\n", Index, mPchConfigHob-= >SerialIo.UartDeviceConfig[Index].Mode));=0D + if (mPchConfigHob->SerialIo.UartDeviceConfig[Index].Mode =3D=3D Serial= IoUartHidden) {=0D + NewHandle =3D NULL;=0D + DeviceId =3D MmioRead16 (GetSerialIoUartFixedPciCfgAddress (Index) += PCI_DEVICE_ID_OFFSET);=0D + DEBUG ((DEBUG_INFO, "Creating Handle for UART DEVICE_ID: 0x%X \n", D= eviceId));=0D + mSerialIoUartPath.AcpiDev.HID =3D 0x5432 + (Index << 16); //UAR=0D + mSerialIoUartPath.HidString[4] =3D (CHAR8)('0' + Index);=0D + mSerialIoUartPath.DeviceId =3D DeviceId;=0D + mSerialIoUartPath.UartIndex =3D Index;=0D + NewPath =3D DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL*) &mSeria= lIoUartPath);=0D + Status =3D gBS->InstallMultipleProtocolInterfaces (=0D + &NewHandle,=0D + &gEfiDevicePathProtocolGuid,=0D + NewPath,=0D + NULL=0D + );=0D + DEBUG ((DEBUG_INFO, "CreateSerialIoUartHandle Status: %r\n", Status)= );=0D + }=0D + }=0D +}=0D +=0D +/**=0D + Stores Pme Control Status and Command register values in S3 Boot Script= =0D +=0D + @param[in] S3PciCfgBase S3 Boot Script Pci Config Base=0D + @param[in] Command Pci Command register data to save=0D + @param[in] Pme Pci Pme Control register data to save=0D +=0D +**/=0D +VOID=0D +STATIC=0D +SerialIoS3Save (=0D + IN UINTN S3PciCfgBase,=0D + IN UINTN Command,=0D + IN UINTN Pme=0D + )=0D +{=0D + if (S3PciCfgBase !=3D 0) {=0D + S3BootScriptSavePciCfgWrite (S3BootScriptWidthUint32, S3PciCfgBase + R= _SERIAL_IO_CFG_PME_CTRL_STS, 1, &Pme);=0D + S3BootScriptSavePciCfgWrite (S3BootScriptWidthUint32, S3PciCfgBase + P= CI_COMMAND_OFFSET, 1, &Command);=0D + }=0D +}=0D +=0D +/**=0D + Puts all SerialIo controllers (except UARTs in debug mode) in D3.=0D + Clears MemoryEnable for all PCI-mode controllers on S3 resume=0D +**/=0D +VOID=0D +ConfigureSerialIoAtS3Resume (=0D + VOID=0D + )=0D +{=0D + UINT8 Index;=0D + UINTN S3PciCfgBase;=0D + UINT32 Command;=0D + UINT32 Pme;=0D +=0D + S3PciCfgBase =3D 0;=0D + for (Index =3D 0; Index < GetPchMaxSerialIoSpiControllersNum (); Index++= ) {=0D + SerialIoSpiS3Handler (Index, &mPchConfigHob->SerialIo.SpiDeviceConfig[= Index], &S3PciCfgBase, &Command, &Pme);=0D + SerialIoS3Save (S3PciCfgBase, Command, Pme);=0D + }=0D +=0D + S3PciCfgBase =3D 0;=0D + for (Index =3D 0; Index < GetPchMaxSerialIoI2cControllersNum (); Index++= ) {=0D + SerialIoI2cS3Handler (Index, &mPchConfigHob->SerialIo.I2cDeviceConfig[= Index], &S3PciCfgBase, &Command, &Pme);=0D + SerialIoS3Save (S3PciCfgBase, Command, Pme);=0D + }=0D +=0D + S3PciCfgBase =3D 0;=0D + for (Index =3D 0; Index < GetPchMaxSerialIoUartControllersNum (); Index+= +) {=0D + SerialIoUartS3Handler (Index, &mPchConfigHob->SerialIo.UartDeviceConfi= g[Index], &S3PciCfgBase, &Command, &Pme);=0D + SerialIoS3Save (S3PciCfgBase, Command, Pme);=0D + }=0D +}=0D +=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/GbeSxSmm.c b= /Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/GbeSxSmm.c new file mode 100644 index 0000000000..786ce13915 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/GbeSxSmm.c @@ -0,0 +1,266 @@ +/** @file=0D + Gbe Sx handler implementation.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +=0D +#include =0D +#include "PchInitSmm.h"=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +=0D +/**=0D + Configure WOL during Sx entry.=0D +=0D + @param [in] GbeBar GbE MMIO space=0D +**/=0D +VOID=0D +GbeWolWorkaround (=0D + IN UINT32 GbeBar=0D + )=0D +{=0D + UINT32 RAL0;=0D + UINT32 RAH0;=0D + UINT16 WUC;=0D + EFI_STATUS Status;=0D + UINT16 Data16;=0D +=0D + //=0D + // 1. Set page to 769 Port Control Registers=0D + // 2. Wait 4 mSec=0D + //=0D + Status =3D GbeMdiSetPage (GbeBar, PHY_MDI_PAGE_769_PORT_CONTROL_REGISTER= S);=0D + if (EFI_ERROR (Status)) return;=0D +=0D + //=0D + // 3. Set registry to 17 Port General Configuration=0D + // 4. Copy all settings from Port General Configuration=0D + //=0D + Status =3D GbeMdiRead (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, MDI_REG_SHIFT (= R_PHY_MDI_PAGE_769_REGISETER_17_PGC), &Data16);=0D + if (EFI_ERROR (Status)) return;=0D +=0D + //=0D + // 5. Modify BIT 4 and BIT 2 to disable host wake up and set MACPD=0D + //=0D + Status =3D GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, MDI_REG_SHIFT = (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), (Data16 | B_PHY_MDI_PAGE_769_REGISET= ER_17_PGC_MACPD_ENABLE) & (~B_PHY_MDI_PAGE_769_REGISETER_17_PGC_HOST_WAKE_U= P));=0D + if (EFI_ERROR (Status)) return;=0D +=0D + //=0D + // 6. Read Receive Address Low and Receive Address High from MMIO=0D + //=0D + RAL0 =3D MmioRead32 (GbeBar + R_GBE_MEM_CSR_RAL);=0D + RAH0 =3D MmioRead32 (GbeBar + R_GBE_MEM_CSR_RAH);=0D +=0D + //=0D + // 7. Set page to 800 Wake Up Registers=0D + // 8. Wait 4 mSec=0D + //=0D + Status =3D GbeMdiSetPage (GbeBar, PHY_MDI_PAGE_800_WAKE_UP_REGISTERS);=0D + if (EFI_ERROR (Status)) return;=0D +=0D + //=0D + // 9. Set registry to 16 Receive Address Low 1/2=0D + //=0D + Status =3D GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_800_REGISETER_16_RA= L0);=0D + if (EFI_ERROR (Status)) return;=0D +=0D + //=0D + // 10. Program first 16 bits [0:15] out of 48 in Receive Address Low 1/2= =0D + //=0D + Status =3D GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_= REG_DATA_READ_WRITE, (RAL0 & 0xFFFF));=0D + if (EFI_ERROR (Status)) return;=0D +=0D + //=0D + // 11. Set registry to 17 Receive Address Low 2/2=0D + //=0D + Status =3D GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_800_REGISETER_17_RA= L1);=0D + if (EFI_ERROR (Status)) return;=0D +=0D + //=0D + // 12. Program second 16 bits [16:31] out of 48 in Receive Address Low 2= /2=0D + //=0D + Status =3D GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_= REG_DATA_READ_WRITE, (RAL0 >> 16));=0D + if (EFI_ERROR (Status)) return;=0D +=0D + //=0D + // 13. Set registry to 18 Receive Address High 1/2=0D + //=0D + Status =3D GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_800_REGISETER_18_RA= H0);=0D + if (EFI_ERROR (Status)) return;=0D +=0D + //=0D + // 14. Program last 16 bits [32:47] out of 48=0D + //=0D + Status =3D GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_= REG_DATA_READ_WRITE, (RAH0 & B_GBE_MEM_CSR_RAH_RAH));=0D + if (EFI_ERROR (Status)) return;=0D +=0D + //=0D + // 15. Set registry to 19 Receive Address High 2/2=0D + //=0D + Status =3D GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_800_REGISETER_19_RA= H1);=0D + if (EFI_ERROR (Status)) return;=0D +=0D + //=0D + // 16. Set Address Valid=0D + //=0D + Status =3D GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_= REG_DATA_READ_WRITE, B_PHY_MDI_PAGE_800_REGISETER_19_RAH1_ADDRESS_VALID);=0D + if (EFI_ERROR (Status)) return;=0D +=0D + //=0D + // 17. Set Wake Up Control Register 1=0D + //=0D + Status =3D GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_800_REGISETER_1_WUC= );=0D + if (EFI_ERROR (Status)) return;=0D +=0D + //=0D + // 18. Copy WakeUp Control from MAC MMIO=0D + //=0D + WUC =3D (UINT16) MmioRead32 (GbeBar + R_GBE_MEM_CSR_WUC);=0D +=0D + //=0D + // 19. Store WakeUp Contorl into LCD=0D + // Modify APME bit to enable APM wake up=0D + //=0D + Status =3D GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_= REG_DATA_READ_WRITE, (WUC & 0xFFFF));=0D + if (EFI_ERROR (Status)) return;=0D +=0D + //=0D + // 20. Set page to 803 Host Wol Packet=0D + // 21. Wait 4 mSec=0D + //=0D + Status =3D GbeMdiSetPage (GbeBar, PHY_MDI_PAGE_803_HOST_WOL_PACKET);=0D + if (EFI_ERROR (Status)) return;=0D +=0D + //=0D + // 22. Set registry to 66 Host WoL Packet Clear=0D + //=0D + Status =3D GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_803_REGISETER_66_HW= PC);=0D + if (EFI_ERROR (Status)) return;=0D +=0D + //=0D + // 23. Clear WOL Packet=0D + //=0D + Status =3D GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_= REG_DATA_READ_WRITE, 0);=0D + if (EFI_ERROR (Status)) return;=0D + //=0D + // 24. Set page to 769 Port Control Registers=0D + // 25. Wait 4 mSec=0D + //=0D + Status =3D GbeMdiSetPage (GbeBar, PHY_MDI_PAGE_769_PORT_CONTROL_REGISTER= S);=0D + if (EFI_ERROR (Status)) return;=0D +=0D + //=0D + // 26. Set registry to 17 Port General Configuration=0D + //=0D + Status =3D GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_769_REGISETER_17_PG= C);=0D + if (EFI_ERROR (Status)) return;=0D +=0D + //=0D + // 27. Copy all settings from Port General Configuration=0D + //=0D + Status =3D GbeMdiRead (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, MDI_REG_SHIFT (= R_PHY_MDI_PAGE_769_REGISETER_17_PGC), &Data16);=0D + if (EFI_ERROR (Status)) return;=0D +=0D + //=0D + // 28. Modify BIT 4 and BIT 2 to enable host wake up and clear MACPD=0D + //=0D + Status =3D GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, MDI_REG_SHIFT = (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), (Data16 | B_PHY_MDI_PAGE_769_REGISET= ER_17_PGC_HOST_WAKE_UP) & (~B_PHY_MDI_PAGE_769_REGISETER_17_PGC_MACPD_ENABL= E));=0D + if (EFI_ERROR (Status)) return;=0D +}=0D +=0D +/**=0D + Additional Internal GbE Controller special cases WOL Support.=0D +=0D + System BIOS is required perform additional steps upon S0 to S3,4,5 trans= ition=0D + when ME is off and GbE device in D0. This is needed to enable LAN wake=0D + in particular when platform is shut-down from EFI.=0D +**/=0D +VOID=0D +GbeSxWorkaround (=0D + VOID=0D + )=0D +{=0D + UINT64 LanRegBase;=0D + UINT32 GbeBar;=0D + EFI_STATUS Status;=0D +=0D + LanRegBase =3D GbePciCfgBase ();=0D +=0D + if (PciSegmentRead16 (LanRegBase + PCI_VENDOR_ID_OFFSET) =3D=3D 0xFFFF) = {=0D + return;=0D + }=0D +=0D + //=0D + // Check if GbE device is in D0=0D + //=0D + if ((PciSegmentRead16 (LanRegBase + R_GBE_CFG_PMCS) & B_GBE_CFG_PMCS_PS)= !=3D V_GBE_CFG_PMCS_PS0) {=0D + return;=0D + }=0D +=0D + ASSERT (mResvMmioSize >=3D (1 << N_GBE_CFG_MBARA_ALIGN));=0D + GbeBar =3D (UINT32) mResvMmioBaseAddr;=0D + if (GbeBar =3D=3D 0) {=0D + ASSERT (FALSE);=0D + return;=0D + }=0D +=0D + //=0D + // Enable MMIO decode using reserved range.=0D + //=0D + PciSegmentAnd16 (LanRegBase + PCI_COMMAND_OFFSET, (UINT16) ~EFI_PCI_COMM= AND_MEMORY_SPACE);=0D + PciSegmentWrite32 (LanRegBase + R_GBE_CFG_MBARA, GbeBar);=0D + PciSegmentOr16 (LanRegBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_= SPACE);=0D +=0D + //=0D + // If MBARA offset 5800h [0] =3D 1b then proceed with the w/a=0D + //=0D + if (MmioRead32 (GbeBar + R_GBE_MEM_CSR_WUC) & B_GBE_MEM_CSR_WUC_APME) {= =0D + Status =3D GbeMdiAcquireMdio (GbeBar);=0D + ASSERT_EFI_ERROR (Status);=0D + if (!EFI_ERROR (Status)) {=0D + GbeWolWorkaround (GbeBar);=0D + GbeMdiReleaseMdio (GbeBar);=0D + }=0D + }=0D +=0D + //=0D + // Disable MMIO decode.=0D + //=0D + PciSegmentAnd16 (LanRegBase + PCI_COMMAND_OFFSET, (UINT16) ~EFI_PCI_COMM= AND_MEMORY_SPACE);=0D + PciSegmentWrite32 (LanRegBase + R_GBE_CFG_MBARA, 0);=0D +}=0D +=0D +/**=0D + Enable platform wake from LAN when in DeepSx if platform supports it.=0D + Called upon Sx entry.=0D +**/=0D +VOID=0D +GbeConfigureDeepSxWake (=0D + VOID=0D + )=0D +{=0D + if (PmcIsLanDeepSxWakeEnabled ()) {=0D + IoOr32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_GPE0_EN_127_96), (UINT32) B= _ACPI_IO_GPE0_EN_127_96_LAN_WAKE);=0D + }=0D +}=0D +=0D +/**=0D + GbE Sx entry handler=0D +**/=0D +VOID=0D +PchLanSxCallback (=0D + VOID=0D + )=0D +{=0D + if (IsGbeEnabled ()) {=0D + GbeSxWorkaround ();=0D + GbeConfigureDeepSxWake ();=0D +=0D + }=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchBiosWrite= Protect.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteP= rotect.c new file mode 100644 index 0000000000..f435af434a --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect= .c @@ -0,0 +1,137 @@ +/** @file=0D + PCH BIOS Write Protect Driver.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include "PchInitSmm.h"=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +//=0D +// Global variables=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED PCH_TCO_SMI_DISPATCH_PROTOCOL *mPchTcoSm= iDispatchProtocol;=0D +GLOBAL_REMOVE_IF_UNREFERENCED PCH_ESPI_SMI_DISPATCH_PROTOCOL *mEspiSmmD= ispatchProtocol;=0D +GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mLpcRegBas= e;=0D +=0D +/**=0D + This hardware SMI handler will be run every time the BIOS Write Enable b= it is set.=0D +=0D + @param[in] DispatchHandle Not used=0D +**/=0D +VOID=0D +EFIAPI=0D +PchSpiBiosWpCallback (=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + SpiClearBiosWriteProtectDisable ();=0D +}=0D +=0D +/**=0D + This hardware SMI handler will be run every time the BIOS Write Enable b= it is set.=0D +=0D + @param[in] DispatchHandle Not used=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +PchLpcBiosWpCallback (=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + //=0D + // Disable BIOSWE bit to protect BIOS=0D + //=0D + PciSegmentAnd8 ((UINTN) (mLpcRegBase + R_LPC_CFG_BC), (UINT8) ~B_LPC_CFG= _BC_WPD);=0D +}=0D +=0D +/**=0D + Entry point for Pch Bios Write Protect driver.=0D +=0D + @param[in] ImageHandle Image handle of this driver.=0D + @param[in] SystemTable Global system service table.=0D +=0D + @retval EFI_SUCCESS Initialization complete.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +InstallPchBiosWriteProtect (=0D + IN EFI_HANDLE ImageHandle,=0D + IN EFI_SYSTEM_TABLE *SystemTable=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_HANDLE Handle;=0D +=0D + DEBUG ((DEBUG_INFO, "InstallPchBiosWriteProtect()\n"));=0D +=0D + if (mPchConfigHob->LockDown.BiosLock !=3D TRUE) {=0D + return EFI_SUCCESS;=0D + }=0D +=0D + mLpcRegBase =3D LpcPciCfgBase ();=0D +=0D + DEBUG ((DEBUG_INFO, "Installing BIOS Write Protect SMI handler\n"));=0D + //=0D + // Get the PCH TCO SMM dispatch protocol=0D + //=0D + mPchTcoSmiDispatchProtocol =3D NULL;=0D + Status =3D gSmst->SmmLocateProtocol (&gPchTcoSmiDispatchProtocolGuid, NU= LL, (VOID **) &mPchTcoSmiDispatchProtocol);=0D + ASSERT_EFI_ERROR (Status);=0D + //=0D + // Always register an SPI BiosWp callback function to handle TCO BIOSWR = SMI=0D + // NOTE: No matter the BIOS resides behind SPI or not, it needs to handl= e the SPI BIOS WP SMI=0D + // to avoid SMI deadloop on SPI WPD write.=0D + //=0D + Handle =3D NULL;=0D + Status =3D mPchTcoSmiDispatchProtocol->SpiBiosWpRegister (=0D + mPchTcoSmiDispatchProtocol,=0D + PchSpiBiosWpCallback,=0D + &Handle=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + //=0D + // Always register an LPC/eSPI BiosWp callback function to handle TCO BI= OSWR SMI=0D + // NOTE: No matter the BIOS resides behind LPC/eSPI or not, it needs to = handle the BIOS WP SMI=0D + // to avoid SMI deadloop on LPC/eSPI WPD write.=0D + //=0D + if (IsEspiEnabled ()) {=0D + //=0D + // Get the PCH ESPI SMM dispatch protocol=0D + //=0D + mEspiSmmDispatchProtocol =3D NULL;=0D + Status =3D gSmst->SmmLocateProtocol (&gPchEspiSmiDispatchProtocolGuid,= NULL, (VOID **) &mEspiSmmDispatchProtocol);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + //=0D + // Register an ESpiBiosWp callback function to handle BIOSWR SMI=0D + //=0D + Handle =3D NULL;=0D + Status =3D mEspiSmmDispatchProtocol->BiosWrProtectRegister (=0D + mEspiSmmDispatchProtocol,=0D + PchLpcBiosWpCallback,=0D + &Handle=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D + } else {=0D + //=0D + // Register an LPC BiosWp callback function to handle TCO BIOSWR SMI=0D + //=0D + Handle =3D NULL;=0D + Status =3D mPchTcoSmiDispatchProtocol->LpcBiosWpRegister (=0D + mPchTcoSmiDispatchProtocol,=0D + PchLpcBiosWpCallback,=0D + &Handle=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchHdaSxSmm.= c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchHdaSxSmm.c new file mode 100644 index 0000000000..f3d11ab204 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchHdaSxSmm.c @@ -0,0 +1,33 @@ +/** @file=0D + PCH HD Audio Sx handler implementation.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +=0D +#include "PchInitSmm.h"=0D +#include =0D +#include =0D +#include =0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mHdaPciBase;=0D +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mHdaCodecSxWakeCapability =3D FALSE;= =0D +=0D +/**=0D + Updates Codec Sx Wake Capability setting: disabled/enabled=0D +**/=0D +VOID=0D +UpdateHdaCodecSxWakeCapabilitySetting (=0D + VOID=0D + )=0D +{=0D + mHdaPciBase =3D HdaPciCfgBase ();=0D +=0D + if ((mPchConfigHob->HdAudio.CodecSxWakeCapability =3D=3D FALSE) ||=0D + (PciSegmentRead16 (mHdaPciBase + PCI_VENDOR_ID_OFFSET) =3D=3D 0xFFFF= )) {=0D + mHdaCodecSxWakeCapability =3D FALSE;=0D + } else {=0D + mHdaCodecSxWakeCapability =3D TRUE;=0D + }=0D +}=0D +=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c= b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c new file mode 100644 index 0000000000..9c2475e3a1 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c @@ -0,0 +1,285 @@ +/** @file=0D + PCH Init Smm module for PCH specific SMI handlers.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include "PchInitSmm.h"=0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *m= PchIoTrap;=0D +GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_SX_DISPATCH2_PROTOCOL *m= SxDispatch;=0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED PCH_NVS_AREA *m= PchNvsArea;=0D +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mA= cpiBaseAddr;=0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED FIVR_EXT_RAIL_CONFIG mF= ivrExtVnnRailSxConfig;=0D +=0D +//=0D +// NOTE: The module variables of policy here are only valid in post time, = but not runtime time.=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED PCH_CONFIG_HOB *m= PchConfigHob;=0D +=0D +//=0D +// The reserved MMIO range to be used in Sx handler=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS mR= esvMmioBaseAddr;=0D +GLOBAL_REMOVE_IF_UNREFERENCED UINTN mR= esvMmioSize;=0D +=0D +/**=0D + SMBUS Sx entry SMI handler.=0D +**/=0D +VOID=0D +SmbusSxCallback (=0D + VOID=0D + )=0D +{=0D + UINT64 SmbusRegBase;=0D + UINT16 SmbusIoBase;=0D +=0D + SmbusRegBase =3D SmbusPciCfgBase ();=0D +=0D + if (PciSegmentRead32 (SmbusRegBase) =3D=3D 0xFFFFFFFF) {=0D + return;=0D + }=0D +=0D + SmbusIoBase =3D PciSegmentRead16 (SmbusRegBase + R_SMBUS_CFG_BASE) & B_S= MBUS_CFG_BASE_BAR;=0D + if (SmbusIoBase =3D=3D 0) {=0D + return;=0D + }=0D +=0D + PciSegmentOr8 (SmbusRegBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_IO_SPA= CE);=0D + //=0D + // Clear SMBUS status and SMB_WAK_STS of GPE0=0D + //=0D + IoWrite8 (SmbusIoBase + R_SMBUS_IO_HSTS, B_SMBUS_IO_SMBALERT_STS);=0D + IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96, B_ACPI_IO_GPE0_STS= _127_96_SMB_WAK);=0D +}=0D +=0D +/*=0D + PCH xHCI Sx entry SMI handler=0D +*/=0D +VOID=0D +PchXhciSxCallback (=0D + VOID=0D + )=0D +{=0D + UINTN XhciPciBase;=0D +=0D + XhciPciBase =3D PchXhciPciCfgBase ();=0D +=0D + //=0D + // Safety check for xHCI existense=0D + //=0D + if (PciSegmentRead32 (XhciPciBase) =3D=3D 0xFFFFFFFF) {=0D + return;=0D + }=0D +=0D + //=0D + // If xHCI is in D0 that means OS didn't put it to D3 during Sx entry i.= e. USB kernel debug is enabled.=0D + // Unless it is put manually to D3, USB wake functionality will not work= .=0D + //=0D + if ((PciSegmentRead8 (XhciPciBase + R_XHCI_CFG_PWR_CNTL_STS) & V_XHCI_CF= G_PWR_CNTL_STS_PWR_STS_D3) =3D=3D 0) {=0D + //=0D + // Put device to D3 to enable wake functionality for USB devices=0D + //=0D + PciSegmentOr8 (XhciPciBase + R_XHCI_CFG_PWR_CNTL_STS, (UINT8)(B_XHCI_C= FG_PWR_CNTL_STS_PWR_STS));=0D + }=0D +}=0D +=0D +/**=0D + Cache PCH FIVR policy.=0D +**/=0D +VOID=0D +UpdatePchFivrSettings (=0D + VOID=0D + )=0D +{=0D + CopyMem (=0D + &mFivrExtVnnRailSxConfig,=0D + &mPchConfigHob->Fivr.ExtVnnRailSx,=0D + sizeof (mFivrExtVnnRailSxConfig)=0D + );=0D +}=0D +=0D +/**=0D + PCH Sx entry SMI handler.=0D +=0D + @param[in] Handle Handle of the callback=0D + @param[in] Context The dispatch context=0D + @param[in,out] CommBuffer A pointer to a collection of data in memo= ry that will=0D + be conveyed from a non-SMM environment in= to an SMM environment.=0D + @param[in,out] CommBufferSize The size of the CommBuffer.=0D +=0D + @retval EFI_SUCCESS=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchSxHandler (=0D + IN EFI_HANDLE Handle,=0D + IN CONST VOID *Context OPTIONAL,=0D + IN OUT VOID *CommBuffer OPTIONAL,=0D + IN OUT UINTN *CommBufferSize OPTIONAL=0D + )=0D +{=0D + PchLanSxCallback ();=0D + PchXhciSxCallback ();=0D +=0D + SmbusSxCallback ();=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Initialize PCH Sx entry SMI handler.=0D +=0D + @param[in] ImageHandle - Handle for the image of this driver=0D +**/=0D +VOID=0D +InitializeSxHandler (=0D + IN EFI_HANDLE ImageHandle=0D + )=0D +{=0D + EFI_SMM_SX_REGISTER_CONTEXT SxDispatchContext;=0D + EFI_HANDLE SxDispatchHandle;=0D + EFI_SLEEP_TYPE SxType;=0D + EFI_STATUS Status;=0D +=0D + DEBUG ((DEBUG_INFO, "InitializeSxHandler() Start\n"));=0D +=0D + //=0D + // Register the callback for S3/S4/S5 entry=0D + //=0D + SxDispatchContext.Phase =3D SxEntry;=0D + for (SxType =3D SxS3; SxType <=3D SxS5; SxType++) {=0D + SxDispatchContext.Type =3D SxType;=0D + Status =3D mSxDispatch->Register (=0D + mSxDispatch,=0D + PchSxHandler,=0D + &SxDispatchContext,=0D + &SxDispatchHandle=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D + }=0D +=0D + DEBUG ((DEBUG_INFO, "InitializeSxHandler() End\n"));=0D +}=0D +=0D +/**=0D + Allocates reserved MMIO for Sx SMI handler use.=0D +**/=0D +VOID=0D +AllocateReservedMmio (=0D + VOID=0D + )=0D +{=0D + mResvMmioBaseAddr =3D PcdGet32 (PcdSiliconInitTempMemBaseAddr);=0D + mResvMmioSize =3D PcdGet32 (PcdSiliconInitTempMemSize);=0D + DEBUG ((DEBUG_INFO, "mResvMmioBaseAddr %x, mResvMmioSize %x\n", mResvMmi= oBaseAddr, mResvMmioSize));=0D +}=0D +=0D +/**=0D + Initializes the PCH SMM handler for for PCIE hot plug support=0D + PchInit SMM Module Entry Point\n=0D + - Introduction\n=0D + The PchInitSmm module is a SMM driver that initializes the Intel Pla= tform Controller Hub=0D + SMM requirements and services. It consumes the PCH_POLICY_HOB and SI= _POLICY_HOB for expected=0D + configurations per policy.=0D +=0D + - Details\n=0D + This module provides SMI handlers to services PCIE HotPlug SMI, LinkAc= tive SMI, and LinkEq SMI.=0D + And also provides port 0x61 emulation support, registers BIOS WP handl= er to process BIOSWP status,=0D + and registers SPI Async SMI handler to handler SPI Async SMI.=0D + This module also registers Sx SMI callback function to detail with GPI= O Sx Isolation and LAN requirement.=0D +=0D + - @pre=0D + - PCH PCR base address configured=0D + - EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL=0D + - This is to ensure that PCI MMIO and IO resource has been prepared = and available for this driver to allocate.=0D + - EFI_SMM_BASE2_PROTOCOL=0D + - EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL=0D + - EFI_SMM_SX_DISPATCH2_PROTOCOL=0D + - EFI_SMM_CPU_PROTOCOL=0D + - @link _PCH_SMM_IO_TRAP_CONTROL_PROTOCOL PCH_SMM_IO_TRAP_CONTROL_PROT= OCOL @endlink=0D + - @link _PCH_SMI_DISPATCH_PROTOCOL PCH_SMI_DISPATCH_PROTOCOL @endlink= =0D + - @link _PCH_PCIE_SMI_DISPATCH_PROTOCOL PCH_PCIE_SMI_DISPATCH_PROTOCOL= @endlink=0D + - @link _PCH_TCO_SMI_DISPATCH_PROTOCOL PCH_TCO_SMI_DISPATCH_PROTOCOL @= endlink=0D + - @link _PCH_ESPI_SMI_DISPATCH_PROTOCOL PCH_ESPI_SMI_DISPATCH_PROTOCOL= @endlink=0D +=0D + - References\n=0D + - @link _PCH_POLICY PCH_POLICY_HOB @endlink.=0D + - @link _SI_POLICY_STRUCT SI_POLICY_HOB @endlink.=0D +=0D + - Integration Checklists\n=0D + - Verify prerequisites are met. Porting Recommendations.=0D + - No modification of this module should be necessary=0D + - Any modification of this module should follow the PCH BIOS Specifica= tion and EDS=0D +=0D + @param[in] ImageHandle - Handle for the image of this driver=0D + @param[in] SystemTable - Pointer to the EFI System Table=0D +=0D + @retval EFI_SUCCESS - PCH SMM handler was installed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchInitSmmEntryPoint (=0D + IN EFI_HANDLE ImageHandle,=0D + IN EFI_SYSTEM_TABLE *SystemTable=0D + )=0D +{=0D + EFI_STATUS Status;=0D + PCH_NVS_AREA_PROTOCOL *PchNvsAreaProtocol;=0D + EFI_PEI_HOB_POINTERS HobPtr;=0D +=0D + DEBUG ((DEBUG_INFO, "PchInitSmmEntryPoint()\n"));=0D +=0D + Status =3D gSmst->SmmLocateProtocol (=0D + &gEfiSmmIoTrapDispatch2ProtocolGuid,=0D + NULL,=0D + (VOID **) &mPchIoTrap=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Status =3D gSmst->SmmLocateProtocol (=0D + &gEfiSmmSxDispatch2ProtocolGuid,=0D + NULL,=0D + (VOID**) &mSxDispatch=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Status =3D gBS->LocateProtocol (&gPchNvsAreaProtocolGuid, NULL, (VOID **= ) &PchNvsAreaProtocol);=0D + ASSERT_EFI_ERROR (Status);=0D + mPchNvsArea =3D PchNvsAreaProtocol->Area;=0D +=0D + //=0D + // Get PCH Data HOB.=0D + //=0D + HobPtr.Guid =3D GetFirstGuidHob (&gPchConfigHobGuid);=0D + ASSERT (HobPtr.Guid !=3D NULL);=0D + mPchConfigHob =3D (PCH_CONFIG_HOB *) GET_GUID_HOB_DATA (HobPtr.Guid);=0D +=0D + mAcpiBaseAddr =3D PmcGetAcpiBase ();=0D +=0D + AllocateReservedMmio ();=0D +=0D + InitializeSxHandler (ImageHandle);=0D +=0D + Status =3D InitializePchPcieSmm (ImageHandle, SystemTable);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Status =3D InstallPchBiosWriteProtect (ImageHandle, SystemTable);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Status =3D InstallPchSpiAsyncSmiHandler ();=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + UpdateHdaCodecSxWakeCapabilitySetting ();=0D +=0D + UpdatePchFivrSettings ();=0D +=0D +=0D + return EFI_SUCCESS;=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h= b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h new file mode 100644 index 0000000000..c2a09acd11 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h @@ -0,0 +1,254 @@ +/** @file=0D + Header file for PCH Init SMM Handler=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +=0D +#ifndef _PCH_INIT_SMM_H_=0D +#define _PCH_INIT_SMM_H_=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +extern EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *mPchIoTrap;=0D +extern EFI_SMM_SX_DISPATCH2_PROTOCOL *mSxDispatch;=0D +=0D +extern PCH_NVS_AREA *mPchNvsArea;=0D +extern UINT16 mAcpiBaseAddr;=0D +=0D +extern EFI_PHYSICAL_ADDRESS mResvMmioBaseAddr;=0D +extern UINTN mResvMmioSize;=0D +=0D +//=0D +// NOTE: The module variables of policy here are only valid in post time, = but not runtime time.=0D +//=0D +extern PCH_CONFIG_HOB *mPchConfigHob;=0D +extern SI_CONFIG_HOB_DATA *mSiConfigHobData;=0D +=0D +/**=0D + Register PCIE Hotplug SMI dispatch function to handle Hotplug enabling=0D +=0D + @param[in] ImageHandle The image handle of this module=0D + @param[in] SystemTable The EFI System Table=0D +=0D + @retval EFI_SUCCESS The function completes successfully=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +InitializePchPcieSmm (=0D + IN EFI_HANDLE ImageHandle,=0D + IN EFI_SYSTEM_TABLE *SystemTable=0D + );=0D +=0D +/**=0D + Program Common Clock and ASPM of Downstream Devices=0D +=0D + @param[in] PortIndex Pcie Root Port Number=0D + @param[in] RpDevice Pcie Root Pci Device Number=0D + @param[in] RpFunction Pcie Root Pci Function Number=0D +=0D + @retval EFI_SUCCESS Root port complete successfully=0D + @retval EFI_UNSUPPORTED PMC has invalid vendor ID=0D +**/=0D +EFI_STATUS=0D +PchPcieSmi (=0D + IN UINT8 PortIndex,=0D + IN UINT8 RpDevice,=0D + IN UINT8 RpFunction=0D + );=0D +=0D +/**=0D + PCIE Hotplug SMI call back function for each Root port=0D +=0D + @param[in] DispatchHandle Handle of this dispatch function=0D + @param[in] RpContext Rootport context, which contains R= ootPort Index,=0D + and RootPort PCI BDF.=0D +**/=0D +VOID=0D +EFIAPI=0D +PchPcieSmiRpHandlerFunction (=0D + IN EFI_HANDLE DispatchHandle,=0D + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext=0D + );=0D +=0D +/**=0D + PCIE Link Active State Change Hotplug SMI call back function for all Roo= t ports=0D +=0D + @param[in] DispatchHandle Handle of this dispatch function=0D + @param[in] RpContext Rootport context, which contains R= ootPort Index,=0D + and RootPort PCI BDF.=0D +**/=0D +VOID=0D +EFIAPI=0D +PchPcieLinkActiveStateChange (=0D + IN EFI_HANDLE DispatchHandle,=0D + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext=0D + );=0D +=0D +/**=0D + PCIE Link Equalization Request SMI call back function for all Root ports= =0D +=0D + @param[in] DispatchHandle Handle of this dispatch function=0D + @param[in] RpContext Rootport context, which contains R= ootPort Index,=0D + and RootPort PCI BDF.=0D +**/=0D +VOID=0D +EFIAPI=0D +PchPcieLinkEqHandlerFunction (=0D + IN EFI_HANDLE DispatchHandle,=0D + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext=0D + );=0D +=0D +/**=0D + An IoTrap callback to config PCIE power management settings=0D +=0D + @param[in] DispatchHandle - The handle of this callback, obtained when = registering=0D + @param[in] DispatchContext - Pointer to the EFI_SMM_IO_TRAP_DISPATCH_CAL= LBACK_CONTEXT=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +PchPcieIoTrapSmiCallback (=0D + IN EFI_HANDLE DispatchHandle,=0D + IN EFI_SMM_IO_TRAP_CONTEXT *CallbackContext,=0D + IN OUT VOID *CommBuffer,=0D + IN OUT UINTN *CommBufferSize=0D + );=0D +=0D +/**=0D + Initializes the PCH SMM handler for PCH save and restore=0D +=0D + @param[in] ImageHandle - Handle for the image of this driver=0D + @param[in] SystemTable - Pointer to the EFI System Table=0D +=0D + @retval EFI_SUCCESS - PCH SMM handler was installed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchInitLateSmm (=0D + IN EFI_HANDLE ImageHandle,=0D + IN EFI_SYSTEM_TABLE *SystemTable=0D + );=0D +=0D +/**=0D + Initialize PCH Sx entry SMI handler.=0D +=0D + @param[in] ImageHandle - Handle for the image of this driver=0D +**/=0D +VOID=0D +InitializeSxHandler (=0D + IN EFI_HANDLE ImageHandle=0D + );=0D +=0D +/**=0D + PCH Sx entry SMI handler.=0D +=0D + @param[in] Handle Handle of the callback=0D + @param[in] Context The dispatch context=0D + @param[in,out] CommBuffer A pointer to a collection of data in memo= ry that will=0D + be conveyed from a non-SMM environment in= to an SMM environment.=0D + @param[in,out] CommBufferSize The size of the CommBuffer.=0D +=0D + @retval EFI_SUCCESS=0D +**/=0D +=0D +EFI_STATUS=0D +EFIAPI=0D +PchSxHandler (=0D + IN EFI_HANDLE Handle,=0D + IN CONST VOID *Context OPTIONAL,=0D + IN OUT VOID *CommBuffer OPTIONAL,=0D + IN OUT UINTN *CommBufferSize OPTIONAL=0D + );=0D +=0D +/**=0D + GbE Sx entry handler=0D +**/=0D +VOID=0D +PchLanSxCallback (=0D + VOID=0D + );=0D +=0D +/**=0D + Updates Codec Sx Wake Capability setting: disabled/enabled=0D +**/=0D +VOID=0D +UpdateHdaCodecSxWakeCapabilitySetting (=0D + VOID=0D + );=0D +=0D +/**=0D + Register dispatch function to handle GPIO pads Sx isolation=0D +**/=0D +VOID=0D +InitializeGpioSxIsolationSmm (=0D + VOID=0D + );=0D +=0D +/**=0D + Entry point for Pch Bios Write Protect driver.=0D +=0D + @param[in] ImageHandle Image handle of this driver.=0D + @param[in] SystemTable Global system service table.=0D +=0D + @retval EFI_SUCCESS Initialization complete.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +InstallPchBiosWriteProtect (=0D + IN EFI_HANDLE ImageHandle,=0D + IN EFI_SYSTEM_TABLE *SystemTable=0D + );=0D +=0D +/**=0D + This fuction install SPI ASYNC SMI handler.=0D +=0D + @retval EFI_SUCCESS Initialization complete.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +InstallPchSpiAsyncSmiHandler (=0D + VOID=0D + );=0D +=0D +=0D +=0D +=0D +=0D +#endif=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.i= nf b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf new file mode 100644 index 0000000000..aaf36a7b2a --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf @@ -0,0 +1,110 @@ +## @file=0D +# Component description file for PchInitSmm driver=0D +#=0D +# Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +=0D +[Defines]=0D +INF_VERSION =3D 0x00010017=0D +BASE_NAME =3D PchInitSmm=0D +FILE_GUID =3D D7B10D4E-67E6-4C74-83E9-F9AF0ACC33CC=0D +VERSION_STRING =3D 1.0=0D +MODULE_TYPE =3D DXE_SMM_DRIVER=0D +PI_SPECIFICATION_VERSION =3D 1.10=0D +ENTRY_POINT =3D PchInitSmmEntryPoint=0D +#=0D +# The following information is for reference only and not required by the = build tools.=0D +#=0D +# VALID_ARCHITECTURES =3D IA32 X64=0D +#=0D +=0D +=0D +[LibraryClasses]=0D +UefiBootServicesTableLib=0D +UefiDriverEntryPoint=0D +DxeServicesTableLib=0D +IoLib=0D +DebugLib=0D +BaseLib=0D +BaseMemoryLib=0D +S3BootScriptLib=0D +PciExpressHelpersLib=0D +SmmServicesTableLib=0D +PciSegmentLib=0D +HobLib=0D +GpioLib=0D +GpioPrivateLib=0D +ReportStatusCodeLib=0D +DevicePathLib=0D +PmcLib=0D +PchPcieRpLib=0D +PchInfoLib=0D +EspiLib=0D +TimerLib=0D +ConfigBlockLib=0D +PmcPrivateLib=0D +SataLib=0D +GbeLib=0D +GbeMdiLib=0D +SpiAccessPrivateLib=0D +PchPciBdfLib=0D +=0D +[Packages]=0D +MdePkg/MdePkg.dec=0D +TigerlakeSiliconPkg/SiPkg.dec=0D +=0D +=0D +[Pcd]=0D +gSiPkgTokenSpaceGuid.PcdSiPciExpressBaseAddress=0D +gSiPkgTokenSpaceGuid.PcdSiliconInitTempPciBusMin=0D +gSiPkgTokenSpaceGuid.PcdSiliconInitTempPciBusMax=0D +gSiPkgTokenSpaceGuid.PcdSiliconInitTempMemBaseAddr=0D +gSiPkgTokenSpaceGuid.PcdSiliconInitTempMemSize=0D +=0D +=0D +[Sources]=0D +PchInitSmm.c=0D +PchPcieSmm.c=0D +GbeSxSmm.c=0D +PchInitSmm.h=0D +PchBiosWriteProtect.c=0D +PchSpiAsync.c=0D +PchHdaSxSmm.c=0D +=0D +=0D +[Protocols]=0D +gEfiSmmIoTrapDispatch2ProtocolGuid ## CONSUMES=0D +gEfiSmmSxDispatch2ProtocolGuid ## CONSUMES=0D +gPchSmmIoTrapControlGuid ## CONSUMES=0D +gEfiSmmCpuProtocolGuid ## CONSUMES=0D +gPchNvsAreaProtocolGuid ## CONSUMES=0D +gPchPcieSmiDispatchProtocolGuid ## CONSUMES=0D +gPchTcoSmiDispatchProtocolGuid ## CONSUMES=0D +gPchSmiDispatchProtocolGuid ## CONSUMES=0D +gPchEspiSmiDispatchProtocolGuid ## CONSUMES=0D +gPchPcieIoTrapProtocolGuid ## PRODUCES=0D +gPchPolicyProtocolGuid ##CONSUMES=0D +=0D +=0D +[Guids]=0D +gSiConfigHobGuid ## CONSUMES=0D +gPchConfigHobGuid ## CONSUMES=0D +gPchDeviceTableHobGuid=0D +gPchPcieRpDxeConfigGuid ## CONSUMES=0D +=0D +=0D +[Depex]=0D +gEfiSmmIoTrapDispatch2ProtocolGuid AND=0D +gEfiSmmSxDispatch2ProtocolGuid AND=0D +gPchSmmIoTrapControlGuid AND=0D +gPchPcieSmiDispatchProtocolGuid AND=0D +gPchTcoSmiDispatchProtocolGuid AND=0D +gEfiSmmCpuProtocolGuid AND=0D +gPchNvsAreaProtocolGuid AND=0D +gEfiPciHostBridgeResourceAllocationProtocolGuid AND # This is to ensure th= at PCI MMIO resource has been prepared and available for this driver to all= ocate.=0D +gEfiSmmBase2ProtocolGuid AND # This is for SmmServicesTableLib=0D +gPchPolicyProtocolGuid=0D +=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c= b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c new file mode 100644 index 0000000000..e885a342a7 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c @@ -0,0 +1,451 @@ +/** @file=0D + PCH Pcie SMM Driver Entry=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include "PchInitSmm.h"=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED PCH_PCIE_DEVICE_OVERRIDE *mDevAspmOverr= ide;=0D +GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mNumOfDevAspmO= verride;=0D +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mPchBusNumber;= =0D +//=0D +// @note:=0D +// These temp bus numbers cannot be used in runtime (hot-plug).=0D +// These can be used only during boot.=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mTempRootPortB= usNumMin;=0D +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mTempRootPortB= usNumMax;=0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED PCH_PCIE_ROOT_PORT_CONFIG mPcieRootPortC= onfig[PCH_MAX_PCIE_ROOT_PORTS];=0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mPchPciePmTrap= Executed =3D FALSE;=0D +=0D +extern EFI_GUID gPchDeviceTableHobGuid;=0D +=0D +/**=0D + Program Common Clock and ASPM of Downstream Devices=0D +=0D + @param[in] PortIndex Pcie Root Port Number=0D + @param[in] RpDevice Pcie Root Pci Device Number=0D + @param[in] RpFunction Pcie Root Pci Function Number=0D +=0D + @retval EFI_SUCCESS Root port complete successfully=0D + @retval EFI_UNSUPPORTED PMC has invalid vendor ID=0D +**/=0D +EFI_STATUS=0D +PchPcieSmi (=0D + IN UINT8 PortIndex,=0D + IN UINT8 RpDevice,=0D + IN UINT8 RpFunction=0D + )=0D +{=0D + UINT8 SecBus;=0D + UINT8 SubBus;=0D + UINT64 RpBase;=0D + UINT64 EpBase;=0D + UINT8 EpPcieCapPtr;=0D + UINT8 EpMaxSpeed;=0D + BOOLEAN DownstreamDevicePresent;=0D + UINT32 Timeout;=0D +=0D + RpBase =3D PCI_SEGMENT_LIB_ADDRESS (=0D + DEFAULT_PCI_SEGMENT_NUMBER_PCH,=0D + mPchBusNumber,=0D + (UINT32) RpDevice,=0D + (UINT32) RpFunction,=0D + 0=0D + );=0D +=0D + if (PciSegmentRead16 (RpBase + PCI_VENDOR_ID_OFFSET) =3D=3D 0xFFFF) {=0D + return EFI_SUCCESS;=0D + }=0D + //=0D + // Check presence detect state. Here the endpoint must be detected using= PDS rather than=0D + // the usual LinkActive check, because PDS changes immediately and LA ta= kes a few milliseconds to stabilize=0D + //=0D + DownstreamDevicePresent =3D !!(PciSegmentRead16 (RpBase + R_PCH_PCIE_CFG= _SLSTS) & B_PCIE_SLSTS_PDS);=0D +=0D + if (DownstreamDevicePresent) {=0D + ///=0D + /// Make sure the link is active before trying to talk to device behin= d it=0D + /// Wait up to 100ms, according to PCIE spec chapter 6.7.3.3=0D + ///=0D + Timeout =3D 100 * 1000;=0D + while ((PciSegmentRead16 (RpBase + R_PCH_PCIE_CFG_LSTS) & B_PCIE_LSTS_= LA) =3D=3D 0 ) {=0D + MicroSecondDelay (10);=0D + Timeout-=3D10;=0D + if (Timeout =3D=3D 0) {=0D + return EFI_NOT_FOUND;=0D + }=0D + }=0D + SecBus =3D PciSegmentRead8 (RpBase + PCI_BRIDGE_SECONDARY_BUS_REGISTE= R_OFFSET);=0D + SubBus =3D PciSegmentRead8 (RpBase + PCI_BRIDGE_SUBORDINATE_BUS_REGIS= TER_OFFSET);=0D + ASSERT (SecBus !=3D 0 && SubBus !=3D 0);=0D + RootportDownstreamConfiguration (=0D + DEFAULT_PCI_SEGMENT_NUMBER_PCH,=0D + DEFAULT_PCI_BUS_NUMBER_PCH,=0D + RpDevice,=0D + RpFunction,=0D + mTempRootPortBusNumMin,=0D + mTempRootPortBusNumMax,=0D + EnumPchPcie=0D + );=0D + RootportDownstreamPmConfiguration (=0D + DEFAULT_PCI_SEGMENT_NUMBER_PCH,=0D + DEFAULT_PCI_BUS_NUMBER_PCH,=0D + RpDevice,=0D + RpFunction,=0D + mTempRootPortBusNumMin,=0D + mTempRootPortBusNumMax,=0D + &mPcieRootPortConfig[PortIndex].PcieRpCommonConfig,=0D + mNumOfDevAspmOverride,=0D + mDevAspmOverride=0D + );=0D + //=0D + // Perform Equalization=0D + //=0D + EpBase =3D PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, Se= cBus, 0, 0, 0);=0D + EpPcieCapPtr =3D PcieFindCapId (DEFAULT_PCI_SEGMENT_NUMBER_PCH, SecBus= , 0, 0, EFI_PCI_CAPABILITY_ID_PCIEXP);=0D + EpMaxSpeed =3D PciSegmentRead8 (EpBase + EpPcieCapPtr + R_PCIE_LCAP_OF= FSET) & B_PCIE_LCAP_MLS;=0D + if (EpMaxSpeed >=3D 3) {=0D + PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_EX_LCTL3, B_PCIE_EX_LCTL3_PE= );=0D + PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_LCTL, B_PCIE_LCTL_RL);=0D + }=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + PCIE Hotplug SMI call back function for each Root port=0D +=0D + @param[in] DispatchHandle Handle of this dispatch function=0D + @param[in] RpContext Rootport context, which contains R= ootPort Index,=0D + and RootPort PCI BDF.=0D +**/=0D +VOID=0D +EFIAPI=0D +PchPcieSmiRpHandlerFunction (=0D + IN EFI_HANDLE DispatchHandle,=0D + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext=0D + )=0D +{=0D + PchPcieSmi (RpContext->RpIndex, RpContext->DevNum, RpContext->FuncNum);= =0D +}=0D +=0D +/**=0D + PCIE Link Active State Change Hotplug SMI call back function for all Roo= t ports=0D +=0D + @param[in] DispatchHandle Handle of this dispatch function=0D + @param[in] RpContext Rootport context, which contains R= ootPort Index,=0D + and RootPort PCI BDF.=0D +**/=0D +VOID=0D +EFIAPI=0D +PchPcieLinkActiveStateChange (=0D + IN EFI_HANDLE DispatchHandle,=0D + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext=0D + )=0D +{=0D + return;=0D +}=0D +=0D +/**=0D + PCIE Link Equalization Request SMI call back function for all Root ports= =0D +=0D + @param[in] DispatchHandle Handle of this dispatch function=0D + @param[in] RpContext Rootport context, which contains R= ootPort Index,=0D + and RootPort PCI BDF.=0D +**/=0D +VOID=0D +EFIAPI=0D +PchPcieLinkEqHandlerFunction (=0D + IN EFI_HANDLE DispatchHandle,=0D + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext=0D + )=0D +{=0D + ///=0D + /// From PCI Express specification, the PCIe device can request for Link= Equalization. When the=0D + /// Link Equalization is requested by the device, an SMI will be generat= ed by PCIe RP when=0D + /// enabled and the SMI subroutine would invoke the Software Preset/Coef= ficient Search=0D + /// software to re-equalize the link.=0D + ///=0D +=0D + return;=0D +=0D +}=0D +=0D +/**=0D + An IoTrap callback to config PCIE power management settings=0D +**/=0D +VOID=0D +PchPciePmIoTrapSmiCallback (=0D + VOID=0D + )=0D +{=0D + UINT32 PortIndex;=0D + UINT64 RpBase;=0D + UINT8 MaxPciePortNum;=0D +=0D + MaxPciePortNum =3D GetPchMaxPciePortNum ();=0D +=0D + for (PortIndex =3D 0; PortIndex < MaxPciePortNum; PortIndex++) {=0D + RpBase =3D PchPcieRpPciCfgBase (PortIndex);=0D +=0D + if (PciSegmentRead16 (RpBase) !=3D 0xFFFF) {=0D + RootportDownstreamPmConfiguration (=0D + DEFAULT_PCI_SEGMENT_NUMBER_PCH,=0D + DEFAULT_PCI_BUS_NUMBER_PCH,=0D + PchPcieRpDevNumber (PortIndex),=0D + PchPcieRpFuncNumber (PortIndex),=0D + mTempRootPortBusNumMin,=0D + mTempRootPortBusNumMax,=0D + &mPcieRootPortConfig[PortIndex].PcieRpCommonConfig,=0D + mNumOfDevAspmOverride,=0D + mDevAspmOverride=0D + );=0D +=0D + }=0D + }=0D +}=0D +=0D +/**=0D + An IoTrap callback to config PCIE power management settings=0D +=0D + @param[in] DispatchHandle - The handle of this callback, obtained when = registering=0D + @param[in] DispatchContext - Pointer to the EFI_SMM_IO_TRAP_DISPATCH_CAL= LBACK_CONTEXT=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +PchPcieIoTrapSmiCallback (=0D + IN EFI_HANDLE DispatchHandle,=0D + IN EFI_SMM_IO_TRAP_CONTEXT *CallbackContext,=0D + IN OUT VOID *CommBuffer,=0D + IN OUT UINTN *CommBufferSize=0D + )=0D +{=0D + if (CallbackContext->WriteData =3D=3D PchPciePmTrap) {=0D + if (mPchPciePmTrapExecuted =3D=3D FALSE) {=0D + PchPciePmIoTrapSmiCallback ();=0D + mPchPciePmTrapExecuted =3D TRUE;=0D + }=0D + } else {=0D + ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);=0D + }=0D +}=0D +=0D +/**=0D + This function clear the Io trap executed flag before enter S3=0D +=0D + @param[in] Handle Handle of the callback=0D + @param[in] Context The dispatch context=0D +=0D + @retval EFI_SUCCESS PCH register saved=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchPcieS3EntryCallBack (=0D + IN EFI_HANDLE Handle,=0D + IN CONST VOID *Context OPTIONAL,=0D + IN OUT VOID *CommBuffer OPTIONAL,=0D + IN OUT UINTN *CommBufferSize OPTIONAL=0D + )=0D +{=0D + mPchPciePmTrapExecuted =3D FALSE;=0D + return EFI_SUCCESS;=0D +}=0D +/**=0D + Register PCIE Hotplug SMI dispatch function to handle Hotplug enabling=0D +=0D + @param[in] ImageHandle The image handle of this module=0D + @param[in] SystemTable The EFI System Table=0D +=0D + @retval EFI_SUCCESS The function completes successfully=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +InitializePchPcieSmm (=0D + IN EFI_HANDLE ImageHandle,=0D + IN EFI_SYSTEM_TABLE *SystemTable=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINT8 PortIndex;=0D + UINT8 Data8;=0D + UINT32 Data32Or;=0D + UINT32 Data32And;=0D + UINT64 RpBase;=0D + EFI_HANDLE PcieHandle;=0D + PCH_PCIE_SMI_DISPATCH_PROTOCOL *PchPcieSmiDispatchProtocol;=0D + EFI_HANDLE PchIoTrapHandle;=0D + EFI_SMM_IO_TRAP_REGISTER_CONTEXT PchIoTrapContext;=0D + EFI_SMM_SX_REGISTER_CONTEXT SxDispatchContext;=0D + PCH_PCIE_IOTRAP_PROTOCOL *PchPcieIoTrapProtocol;=0D + EFI_HANDLE SxDispatchHandle;=0D + UINT8 MaxPciePortNum;=0D + PCH_POLICY_PROTOCOL *PchPolicy;=0D + PCIE_RP_DXE_CONFIG *PchPcieRpDxeConfig;=0D + UINTN PcieDeviceTableSize;=0D + PCH_PCIE_DEVICE_OVERRIDE *DevAspmOverride;=0D + UINTN Count;=0D +=0D + DEBUG ((DEBUG_INFO, "InitializePchPcieSmm () Start\n"));=0D +=0D + MaxPciePortNum =3D GetPchMaxPciePortNum ();=0D +=0D + //=0D + // Locate Pch Pcie Smi Dispatch Protocol=0D + //=0D + Status =3D gSmst->SmmLocateProtocol (&gPchPcieSmiDispatchProtocolGuid, N= ULL, (VOID**) &PchPcieSmiDispatchProtocol);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + mPchBusNumber =3D DEFAULT_PCI_BUS_NUMBER_PCH;=0D + mTempRootPortBusNumMin =3D PcdGet8 (PcdSiliconInitTempPciBusMin);=0D + mTempRootPortBusNumMax =3D PcdGet8 (PcdSiliconInitTempPciBusMax);=0D +=0D + ASSERT (sizeof mPcieRootPortConfig =3D=3D sizeof mPchConfigHob->PcieRp.R= ootPort);=0D + CopyMem (=0D + mPcieRootPortConfig,=0D + &(mPchConfigHob->PcieRp.RootPort),=0D + sizeof (mPcieRootPortConfig)=0D + );=0D +=0D + DevAspmOverride =3D NULL;=0D + mDevAspmOverride =3D NULL;=0D + mNumOfDevAspmOverride =3D 0;=0D +=0D + Status =3D gBS->LocateProtocol (&gPchPolicyProtocolGuid, NULL, (VOID **)= &PchPolicy);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Status =3D GetConfigBlock ((VOID*) PchPolicy, &gPchPcieRpDxeConfigGuid, = (VOID*) &PchPcieRpDxeConfig);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + DevAspmOverride =3D PchPcieRpDxeConfig->PcieDeviceOverrideTablePtr;=0D +=0D + Count =3D 0;=0D + if (DevAspmOverride !=3D NULL) {=0D + for (Count =3D 0; DevAspmOverride[Count].DeviceId !=3D 0; Count++) {}= =0D + }=0D +=0D + if (Count !=3D0) {=0D + PcieDeviceTableSize =3D Count * sizeof (PCH_PCIE_DEVICE_OVERRIDE);=0D + Status =3D gSmst->SmmAllocatePool (=0D + EfiRuntimeServicesData,=0D + PcieDeviceTableSize,=0D + (VOID **) &mDevAspmOverride=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D + CopyMem (mDevAspmOverride, DevAspmOverride, PcieDeviceTableSize);=0D + mNumOfDevAspmOverride =3D (UINT32) Count;=0D + }=0D + //=0D + // Throught all PCIE root port function and register the SMI Handler for= enabled ports.=0D + //=0D + for (PortIndex =3D 0; PortIndex < MaxPciePortNum; PortIndex++) {=0D + RpBase =3D PchPcieRpPciCfgBase (PortIndex);=0D + //=0D + // Skip the root port function which is not enabled=0D + //=0D + if (PciSegmentRead32 (RpBase) =3D=3D 0xFFFFFFFF) {=0D + continue;=0D + }=0D +=0D + //=0D + // Register SMI Handlers for Hot Plug and Link Active State Change=0D + //=0D + Data8 =3D PciSegmentRead8 (RpBase + R_PCH_PCIE_CFG_SLCAP);=0D + if (Data8 & B_PCIE_SLCAP_HPC) {=0D + PcieHandle =3D NULL;=0D + Status =3D PchPcieSmiDispatchProtocol->HotPlugRegister (=0D + PchPcieSmiDispatchProtocol,=0D + PchPcieSmiRpHandlerFunction,= =0D + PortIndex,=0D + &PcieHandle=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Status =3D PchPcieSmiDispatchProtocol->LinkActiveRegister (=0D + PchPcieSmiDispatchProtocol,=0D + PchPcieLinkActiveStateChange,= =0D + PortIndex,=0D + &PcieHandle=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Data32Or =3D B_PCH_PCIE_CFG_MPC_HPME;=0D + Data32And =3D (UINT32) ~B_PCH_PCIE_CFG_MPC_HPME;=0D + PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_MPC, Data32Or);=0D + S3BootScriptSaveMemReadWrite (=0D + S3BootScriptWidthUint32,=0D + PcdGet64 (PcdSiPciExpressBaseAddress) + RpBase + R_PCH_PCIE_CFG_MP= C,=0D + &Data32Or, /// Data to be ORed=0D + &Data32And /// Data to be ANDed=0D + );=0D + }=0D +=0D + //=0D + // Register SMI Handler for Link Equalization Request from Gen 3 Devic= es.=0D + //=0D + Data8 =3D PciSegmentRead8 (RpBase + R_PCH_PCIE_CFG_LCAP);=0D + if ((Data8 & B_PCIE_LCAP_MLS) =3D=3D V_PCIE_LCAP_MLS_GEN3) {=0D + Status =3D PchPcieSmiDispatchProtocol->LinkEqRegister (=0D + PchPcieSmiDispatchProtocol,=0D + PchPcieLinkEqHandlerFunction,= =0D + PortIndex,=0D + &PcieHandle=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D + }=0D + }=0D +=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + PchIoTrapContext.Type =3D WriteTrap;=0D + PchIoTrapContext.Length =3D 4;=0D + PchIoTrapContext.Address =3D 0;=0D + Status =3D mPchIoTrap->Register (=0D + mPchIoTrap,=0D + (EFI_SMM_HANDLER_ENTRY_POINT2) PchPcieIoTrapSmiCa= llback,=0D + &PchIoTrapContext,=0D + &PchIoTrapHandle=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + //=0D + // Install the PCH Pcie IoTrap protocol=0D + //=0D + (gBS->AllocatePool) (EfiBootServicesData, sizeof (PCH_PCIE_IOTRAP_PROTOC= OL), (VOID **)&PchPcieIoTrapProtocol);=0D + PchPcieIoTrapProtocol->PcieTrapAddress =3D PchIoTrapContext.Address;=0D +=0D + Status =3D gBS->InstallMultipleProtocolInterfaces (=0D + &ImageHandle,=0D + &gPchPcieIoTrapProtocolGuid,=0D + PchPcieIoTrapProtocol,=0D + NULL=0D + );=0D +=0D + //=0D + // Register the callback for S3 entry=0D + //=0D + SxDispatchContext.Type =3D SxS3;=0D + SxDispatchContext.Phase =3D SxEntry;=0D + Status =3D mSxDispatch->Register (=0D + mSxDispatch,=0D + PchPcieS3EntryCallBack,=0D + &SxDispatchContext,=0D + &SxDispatchHandle=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + DEBUG ((DEBUG_INFO, "InitializePchPcieSmm, IoTrap @ %x () End\n", PchIoT= rapContext.Address));=0D +=0D + return EFI_SUCCESS;=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.= c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c new file mode 100644 index 0000000000..bdae6fe918 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c @@ -0,0 +1,67 @@ +/** @file=0D + PCH SPI Async SMI handler.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include "PchInitSmm.h"=0D +=0D +///=0D +/// Global variables=0D +///=0D +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMI_DISPATCH_PROTOCOL *mPchSmiDispat= chProtocol;=0D +=0D +/**=0D + This hardware SMI handler will be run every time the flash write/earse h= appens.=0D +=0D + @param[in] DispatchHandle Not used=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +PchSpiAsyncCallback (=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + //=0D + // Dummy SMI handler=0D + //=0D +}=0D +=0D +/**=0D + This fuction install SPI ASYNC SMI handler.=0D +=0D + @retval EFI_SUCCESS Initialization complete.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +InstallPchSpiAsyncSmiHandler (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_HANDLE Handle;=0D +=0D + DEBUG ((DEBUG_INFO, "InstallPchSpiAsyncSmiHandler()\n"));=0D +=0D + ///=0D + /// Get the PCH SMM dispatch protocol=0D + ///=0D + mPchSmiDispatchProtocol =3D NULL;=0D + Status =3D gSmst->SmmLocateProtocol (&gPchSmiDispatchProtocolGuid, NULL,= (VOID **) &mPchSmiDispatchProtocol);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + ///=0D + /// Register an SpiAsync callback function=0D + ///=0D + Handle =3D NULL;=0D + Status =3D mPchSmiDispatchProtocol->SpiAsyncRegister (=0D + mPchSmiDispatchProtocol,=0D + PchSpiAsyncCallback,=0D + &Handle=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoT= rap.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.c new file mode 100644 index 0000000000..54a1575f2c --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.c @@ -0,0 +1,1284 @@ +/** @file=0D + Main implementation source file for the Io Trap SMM driver=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include "PchSmmHelpers.h"=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#define GENERIC_IOTRAP_SIZE 0x100=0D +=0D +//=0D +// Module global variables=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED EFI_HANDLE mDriverImage= Handle;=0D +GLOBAL_REMOVE_IF_UNREFERENCED EFI_HANDLE mIoTrapHandl= e;=0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED IO_TRAP_INSTANCE mIoTrapData;= =0D +GLOBAL_REMOVE_IF_UNREFERENCED IO_TRAP_RECORD *mIoTrapReco= rd;=0D +GLOBAL_REMOVE_IF_UNREFERENCED PCH_NVS_AREA *mPchNvsArea= ;=0D +=0D +=0D +static CONST UINT16 mLengthTable[10] =3D { 1, 2, 3, 4, 8, 16, = 32, 64, 128, 256 };=0D +=0D +/**=0D + Helper function that encapsulates IoTrap register access.=0D + IO trap related register updates must be made in 2 registers, IOTRAP and= DMI source decode.=0D +=0D + @param[in] TrapHandlerNum trap number (0-3)=0D + @param[in] Value value to be written in both registers=0D + @param[in] SaveToBootscript if true, this register write will be saved = to bootscript=0D +=0D +**/=0D +VOID=0D +SetIoTrapLowDword (=0D + IN UINT8 TrapHandlerNum,=0D + IN UINT32 Value,=0D + IN BOOLEAN SaveToBootscript=0D + )=0D +{=0D + UINT32 BitMask;=0D + UINT32 BitValue;=0D + //=0D + // To provide sequentially consistent programming model for IO trap=0D + // all pending IO cycles must be flushed before enabling and before disa= bling a trap.=0D + // Without this the trap may trigger due to IO cycle issued before the t= rap is enabled or a cycle issued before the trap is disabled might be misse= d.=0D + // a. Issues a MemRd to PSTH IO Trap Enable bit -> This serves to flush = all previous IO cycles.=0D + // b. Then only issues a MemWr to PSTH IO Trap Enable =3D=3D Value=0D + // c. Issues another MemRd to PSTH IO Trap Enable bit -> This serves to = push the MemWr to PSTH and confirmed that IO Trap is in fact enabled=0D + //=0D + PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8);=0D + PchPcrWrite32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8, Value)= ;=0D + PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8);=0D +=0D + PchPcrWrite32 (PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8, Value);= =0D + //=0D + // Read back DMI IOTRAP register to enforce ordering so DMI write is com= pleted before any IO reads=0D + // from other threads which may occur after this point (after SMI exit).= =0D + //=0D + PchPcrRead32 (PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8);=0D + if (SaveToBootscript) {=0D + //=0D + // Ignore the value check of PCH_PCR_BOOT_SCRIPT_READ=0D + //=0D + BitMask =3D 0;=0D + BitValue =3D 0;=0D +=0D + PCH_PCR_BOOT_SCRIPT_READ (S3BootScriptWidthUint32, PID_PSTH, R_PSTH_PC= R_TRPREG0 + TrapHandlerNum * 8, &BitMask, &BitValue);=0D + PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_PSTH, R_PSTH_P= CR_TRPREG0 + TrapHandlerNum * 8, 1, &Value);=0D + PCH_PCR_BOOT_SCRIPT_READ (S3BootScriptWidthUint32, PID_PSTH, R_PSTH_PC= R_TRPREG0 + TrapHandlerNum * 8, &BitMask, &BitValue);=0D + PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_DMI, R_PCH_DMI= _PCR_IOT1 + TrapHandlerNum * 8, 1, &Value);=0D + }=0D +}=0D +=0D +/**=0D + Helper function that encapsulates IoTrap register access.=0D + IO trap related register updates must be made in 2 registers, IOTRAP and= DMI source decode.=0D +=0D + @param[in] TrapHandlerNum trap number (0-3)=0D + @param[in] Value value to be written in both registers=0D + @param[in] SaveToBootscript if true, this register write will be saved = to bootscript=0D +=0D +**/=0D +VOID=0D +SetIoTrapHighDword (=0D + IN UINT8 TrapHandlerNum,=0D + IN UINT32 Value,=0D + IN BOOLEAN SaveToBootscript=0D + )=0D +{=0D + PchPcrWrite32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8 + 4, Va= lue);=0D + PchPcrWrite32 (PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8 + 4, Val= ue);=0D + if (SaveToBootscript) {=0D + PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_PSTH, R_PSTH_P= CR_TRPREG0 + TrapHandlerNum * 8 + 4, 1, &Value);=0D + PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_DMI, R_PCH_DMI= _PCR_IOT1 + TrapHandlerNum * 8 + 4, 1, &Value);=0D + }=0D +}=0D +=0D +/**=0D + Clear pending IOTRAP status.=0D + If IOTRAP status is pending and IOTRAP is disabled, then BIOS will not f= ind a match SMI source=0D + and will not dispatch any SMI handler for it. The pending status will le= ad to SMI storm.=0D + This prevents that IOTRAP gets triggered by pending IO cycles even after= it's disabled.=0D +=0D + @param[in] TrapHandlerNum trap number (0-3)=0D +=0D +**/=0D +VOID=0D +ClearPendingIoTrapStatus (=0D + IN UINT8 TrapHandlerNum=0D + )=0D +{=0D + PchPcrWrite32 (PID_PSTH, R_PSTH_PCR_TRPST, (UINT32)(1 << TrapHandlerNum)= );=0D +}=0D +=0D +/**=0D + IO resources allocated to IO traps need to be reported to OS so that the= y don't get reused.=0D + This function makes IO trap allocation data available to ACPI=0D +=0D + @param[in] TrapHandlerNum trap number (0-3)=0D + @param[in] BaseAddress address of allocated IO resource=0D + @param[in] Track TRUE =3D resource allocated, FALSE =3D resour= ce freed=0D +=0D +**/=0D +VOID=0D +UpdateIoTrapAcpiResources (=0D + IN UINT8 TrapHandlerNum,=0D + IN EFI_PHYSICAL_ADDRESS BaseAddress,=0D + IN BOOLEAN Track=0D + )=0D +{=0D +=0D + if (Track =3D=3D TRUE) {=0D + mPchNvsArea->IoTrapAddress[TrapHandlerNum] =3D (UINT16) BaseAddress;=0D + mPchNvsArea->IoTrapStatus[TrapHandlerNum] =3D 1;=0D + } else {=0D + mPchNvsArea->IoTrapStatus[TrapHandlerNum] =3D 0;=0D + }=0D +}=0D +=0D +/**=0D + Get address from IOTRAP low dword.=0D +=0D + @param[in] IoTrapRegLowDword IOTRAP register low dword=0D +=0D + @retval Address of IOTRAP setting.=0D +**/=0D +STATIC=0D +UINT16=0D +AddressFromLowDword (=0D + UINT32 IoTrapRegLowDword=0D + )=0D +{=0D + return (UINT16) (IoTrapRegLowDword & B_PSTH_PCR_TRPREG_AD);=0D +}=0D +=0D +/**=0D + Get length from IOTRAP low dword.=0D +=0D + @param[in] IoTrapRegLowDword IOTRAP register low dword=0D +=0D + @retval Length of IOTRAP setting.=0D +**/=0D +STATIC=0D +UINT16=0D +LengthFromLowDword (=0D + UINT32 IoTrapRegLowDword=0D + )=0D +{=0D + return (UINT16) (((IoTrapRegLowDword >> 16) & 0xFC) + 4);=0D +}=0D +=0D +/**=0D + Get ByteEnable from IOTRAP high dword.=0D +=0D + @param[in] IoTrapRegHighDword IOTRAP register high dword=0D +=0D + @retval ByteEnable of IOTRAP setting.=0D +**/=0D +STATIC=0D +UINT8=0D +ByteEnableFromHighDword (=0D + UINT32 IoTrapRegHighDword=0D + )=0D +{=0D + return (UINT8) (IoTrapRegHighDword & 0x0F);=0D +}=0D +=0D +/**=0D + Get ByteEnableMask from IOTRAP high dword.=0D +=0D + @param[in] IoTrapRegHighDword IOTRAP register high dword=0D +=0D + @retval ByteEnableMask of IOTRAP setting.=0D +**/=0D +STATIC=0D +UINT8=0D +ByteEnableMaskFromHighDword (=0D + UINT32 IoTrapRegHighDword=0D + )=0D +{=0D + return (UINT8) ((IoTrapRegHighDword & 0xF0) >> 4);=0D +}=0D +=0D +/**=0D + Check the IoTrap register matches the IOTRAP EX content.=0D +=0D + @param[in] IoTrapRecord IOTRAP registration record structure=0D + @param[in] IoTrapRegLowDword IOTRAP register low dword=0D + @param[in] IoTrapRegHighDword IOTRAP register high dword=0D +=0D + @retval TRUE Content matched=0D + FALSE Content mismatched=0D +**/=0D +STATIC=0D +BOOLEAN=0D +IsIoTrapExContentMatched (=0D + IO_TRAP_RECORD *IoTrapRecord,=0D + UINT32 IoTrapRegLowDword,=0D + UINT32 IoTrapRegHighDword=0D + )=0D +{=0D + if ((IoTrapRecord->Context.Address =3D=3D AddressFromLowDword (IoTrapReg= LowDword)) &&=0D + (IoTrapRecord->Context.Length =3D=3D LengthFromLowDword (IoTrapRegLo= wDword)) &&=0D + (IoTrapRecord->Context.ByteEnable =3D=3D ByteEnableFromHighDword (Io= TrapRegHighDword)) &&=0D + (IoTrapRecord->Context.ByteEnableMask =3D=3D ByteEnableMaskFromHighD= word (IoTrapRegHighDword)))=0D + {=0D + return TRUE;=0D + }=0D + return FALSE;=0D +}=0D +=0D +=0D +/**=0D + The helper function for IoTrap callback dispacther=0D +=0D + @param[in] TrapHandlerNum trap number (0-3)=0D +**/=0D +VOID=0D +IoTrapDispatcherHelper (=0D + UINTN TrapHandlerNum=0D + )=0D +{=0D + IO_TRAP_RECORD *RecordInDb;=0D + LIST_ENTRY *LinkInDb;=0D + EFI_SMM_IO_TRAP_REGISTER_CONTEXT CurrentIoTrapRegisterData;=0D + EFI_SMM_IO_TRAP_CONTEXT CurrentIoTrapContextData;=0D + UINT16 BaseAddress;=0D + UINT16 StartAddress;=0D + UINT16 EndAddress;=0D + UINT32 Data32;=0D + UINT8 ActiveHighByteEnable;=0D + BOOLEAN ReadCycle;=0D + UINT32 WriteData;=0D +=0D + if (!IsListEmpty (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase))= ) {=0D + Data32 =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPC);=0D + WriteData =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPD);=0D +=0D + BaseAddress =3D (UINT16) (Data32 & B_PSTH_PCR_TRPC_IOA);=0D + ActiveHighByteEnable =3D (UINT8)((Data32 & B_PSTH_PCR_TRPC_AHBE) >> 1= 6);=0D + ReadCycle =3D (BOOLEAN) ((Data32 & B_PSTH_PCR_TRPC_RW) =3D= =3D B_PSTH_PCR_TRPC_RW);=0D + //=0D + // StartAddress and EndAddress will be equal if it's byte access=0D + //=0D + EndAddress =3D (UINT16) (HighBitSet32 ((UINT32) (ActiveHighByteEnab= le))) + BaseAddress;=0D + StartAddress =3D (UINT16) (LowBitSet32 ((UINT32) (ActiveHighByteEnabl= e))) + BaseAddress;=0D +=0D + CurrentIoTrapRegisterData.Type =3D (EFI_SMM_IO_TRAP_DISPATCH_TYPE)Read= Cycle;=0D + CurrentIoTrapContextData.WriteData =3D WriteData;=0D +=0D + LinkInDb =3D GetFirstNode (&(mIoTrapData.Entry[TrapHandlerNum].Callbac= kDataBase));=0D +=0D + while (!IsNull (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase),= LinkInDb)) {=0D + RecordInDb =3D IO_TRAP_RECORD_FROM_LINK (LinkInDb);=0D +=0D + //=0D + // If MergeDisable is TRUE, no need to check the address range, disp= atch the callback function directly.=0D + //=0D + if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable) {=0D + if (RecordInDb->IoTrapCallback !=3D NULL) {=0D + RecordInDb->IoTrapCallback (&RecordInDb->Link, &CurrentIoTrapCon= textData, NULL, NULL);=0D + }=0D + if (RecordInDb->IoTrapExCallback !=3D NULL) {=0D + RecordInDb->IoTrapExCallback (BaseAddress, ActiveHighByteEnable,= !ReadCycle, WriteData);=0D + }=0D + //=0D + // Expect only one callback available. So break immediately.=0D + //=0D + break;=0D + //=0D + // If MergeDisable is FALSE, check the address range and trap type.= =0D + //=0D + } else {=0D + if ((RecordInDb->Context.Address <=3D StartAddress) &&=0D + (RecordInDb->Context.Address + RecordInDb->Context.Length > En= dAddress)) {=0D + if ((RecordInDb->Context.Type =3D=3D IoTrapExTypeReadWrite) || (= RecordInDb->Context.Type =3D=3D (IO_TRAP_EX_DISPATCH_TYPE) CurrentIoTrapReg= isterData.Type)) {=0D + //=0D + // Pass the IO trap context information=0D + //=0D + RecordInDb->IoTrapCallback (&RecordInDb->Link, &CurrentIoTrapC= ontextData, NULL, NULL);=0D + }=0D + //=0D + // Break if the address is match=0D + //=0D + break;=0D + } else {=0D + LinkInDb =3D GetNextNode (&(mIoTrapData.Entry[TrapHandlerNum].Ca= llbackDataBase), &RecordInDb->Link);=0D + if (IsNull (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase= ), LinkInDb)) {=0D + //=0D + // An IO access was trapped that does not have a handler regis= tered.=0D + // This indicates an error condition.=0D + //=0D + ASSERT (FALSE);=0D + }=0D + }=0D + } // end of if else block=0D + } // end of while loop=0D + } // end of if else block=0D +}=0D +=0D +/**=0D + IoTrap dispatcher for IoTrap register 0.=0D +=0D + @param[in] DispatchHandle Handle of dispatch function=0D +**/=0D +VOID=0D +EFIAPI=0D +IoTrapDispatcher0 (=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + IoTrapDispatcherHelper (0);=0D +}=0D +=0D +/**=0D + IoTrap dispatcher for IoTrap register 1.=0D +=0D + @param[in] DispatchHandle Handle of dispatch function=0D +**/=0D +VOID=0D +EFIAPI=0D +IoTrapDispatcher1 (=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + IoTrapDispatcherHelper (1);=0D +}=0D +=0D +/**=0D + IoTrap dispatcher for IoTrap register 2.=0D +=0D + @param[in] DispatchHandle Handle of dispatch function=0D +**/=0D +VOID=0D +EFIAPI=0D +IoTrapDispatcher2 (=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + IoTrapDispatcherHelper (2);=0D +}=0D +=0D +/**=0D + IoTrap dispatcher for IoTrap register 3.=0D +=0D + @param[in] DispatchHandle Handle of dispatch function=0D +**/=0D +VOID=0D +EFIAPI=0D +IoTrapDispatcher3 (=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + IoTrapDispatcherHelper (3);=0D +}=0D +=0D +/**=0D + IoTrap registratrion helper fucntion.=0D +=0D + @param[in] DispatchHandle Handle of dispatch function=0D + @param[in] IoTrapDispatchFunction Dispatch function of IoTrapDispatc= h2Protocol.=0D + This could be NULL if it's not fro= m IoTrapDispatch2Protocol.=0D + @param[in] IoTrapExDispatchFunction Dispatch function of IoTrapExDispa= tchProtocol.=0D + This could be NULL if it's not fro= m IoTrapExDispatchProtocol.=0D + @param[in out] Address The pointer of IO Address.=0D + If the input Addres is 0, it will = return the address assigned=0D + by registration to this caller.=0D + @param[in] Length Length of IO address range.=0D + @param[in] Type Read/Write type of IO trap.=0D + @param[in] ByteEnable Bitmap to enable trap for each byt= e of every dword alignment address.=0D + @param[in] ByteEnableMask ByteEnableMask bitwise to ignore t= he ByteEnable setting.=0D +=0D + @retval EFI_INVALID_PARAMETER If Type is invalid,=0D + If Length is invalid,=0D + If Address is invalid,=0D + EFI_ACCESS_DENIED If the SmmReadyToLock event has be= en triggered,=0D + EFI_OUT_OF_RESOURCES If run out of IoTrap register reso= urce,=0D + If run out of SMM memory pool,=0D + EFI_SUCCESS IoTrap register successfully.=0D +**/=0D +EFI_STATUS=0D +IoTrapRegisterHelper (=0D + OUT EFI_HANDLE *DispatchHandle,=0D + IN EFI_SMM_HANDLER_ENTRY_POINT2 IoTrapDispatchFunction,= =0D + IN IO_TRAP_EX_DISPATCH_CALLBACK IoTrapExDispatchFunctio= n,=0D + IN OUT UINT16 *Address,=0D + IN UINT16 Length,=0D + IN IO_TRAP_EX_DISPATCH_TYPE Type,=0D + IN UINT8 ByteEnable,=0D + IN UINT8 ByteEnableMask=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_PHYSICAL_ADDRESS BaseAddress;=0D + UINT32 UsedLength;=0D + UINT8 TrapHandlerNum;=0D + UINT32 IoTrapRegLowDword;=0D + UINT32 IoTrapRegHighDword;=0D + BOOLEAN TempMergeDisable;=0D +=0D + DEBUG ((DEBUG_INFO, "IoTrapRegisterHelper\n"));=0D + DEBUG ((DEBUG_INFO, "Address:%x \n", *Address));=0D + DEBUG ((DEBUG_INFO, "Length:%x \n", Length));=0D + DEBUG ((DEBUG_INFO, "Type:%x \n", Type));=0D + DEBUG ((DEBUG_INFO, "ByteEnable:%x \n", ByteEnable));=0D + DEBUG ((DEBUG_INFO, "ByteEnableMask:%x \n", ByteEnableMask));=0D +=0D + //=0D + // Return error if the type is invalid=0D + //=0D + if (Type >=3D IoTrapExTypeMaximum) {=0D + DEBUG ((DEBUG_ERROR, "The Dispatch Type %0X is invalid! \n", Type));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D + //=0D + // Return error if the Length is invalid=0D + //=0D + if (Length < 1 || Length > GENERIC_IOTRAP_SIZE) {=0D + DEBUG ((DEBUG_ERROR, "The Dispatch Length %0X is invalid! \n", Length)= );=0D + return EFI_INVALID_PARAMETER;=0D + }=0D + //=0D + // Return error if the address is invalid=0D + // PCH supports non-aligned address but (Address % 4 + Length) must not = be more than 4=0D + //=0D + if (((Length & (Length - 1)) !=3D 0) && (Length !=3D 3)) {=0D + DEBUG ((DEBUG_ERROR, "The Dispatch Length is not power of 2 \n"));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + if (((Length >=3D 4) && (*Address & 0x3)) ||=0D + ((Length < 4) && (((*Address & 0x3) + Length) > 4))) {=0D + DEBUG ((DEBUG_ERROR, "PCH does not support Dispatch Address %0X and Le= ngth %0X combination \n", *Address, Length));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + if ((Length >=3D 4) && ((*Address & (Length - 1)) !=3D 0)) {=0D + DEBUG ((DEBUG_ERROR, "Dispatch Address %0X is not aligned to the Lengt= h %0X \n", *Address, Length));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + if (*Address) {=0D + TempMergeDisable =3D TRUE;=0D + }else {=0D + TempMergeDisable =3D FALSE;=0D + }=0D + //=0D + // Loop through the first IO Trap handler, looking for the suitable hand= ler=0D + //=0D + for (TrapHandlerNum =3D 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; TrapHan= dlerNum++) {=0D + //=0D + // Get information from Io Trap handler register=0D + //=0D + IoTrapRegLowDword =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + Tra= pHandlerNum * 8);=0D +=0D + //=0D + // Check if the IO Trap handler is not used=0D + //=0D + if (AddressFromLowDword (IoTrapRegLowDword) =3D=3D 0) {=0D + //=0D + // Search available IO address and allocate it if the IO address is= 0=0D + //=0D + BaseAddress =3D *Address;=0D + if (BaseAddress =3D=3D 0) {=0D + //=0D + // Allocate 256 byte range from GCD for common pool usage=0D + //=0D + if ((PcdGet8 (PcdEfiGcdAllocateType) =3D=3D EfiGcdAllocateMaxAddre= ssSearchBottomUp) || (PcdGet8 (PcdEfiGcdAllocateType) =3D=3D EfiGcdAllocate= MaxAddressSearchTopDown)) {=0D + BaseAddress =3D 0xFFFF;=0D + }=0D + Status =3D gDS->AllocateIoSpace (=0D + PcdGet8 (PcdEfiGcdAllocateType),=0D + EfiGcdIoTypeIo,=0D + 8,=0D + GENERIC_IOTRAP_SIZE,=0D + &BaseAddress,=0D + mDriverImageHandle,=0D + NULL=0D + );=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((DEBUG_ERROR, "Can't find any available IO address! \n"))= ;=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D +=0D + *Address =3D (UINT16) BaseAddress;=0D + UsedLength =3D GENERIC_IOTRAP_SIZE;=0D + mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength =3D Length;=0D + mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource =3D TRUE;= =0D + UpdateIoTrapAcpiResources (TrapHandlerNum, BaseAddress, TRUE);=0D + } else {=0D + BaseAddress &=3D B_PSTH_PCR_TRPREG_AD;=0D + UsedLength =3D Length;=0D + }=0D +=0D + Status =3D PchInternalIoTrapSmiRegister (=0D + mIoTrapData.Entry[TrapHandlerNum].CallbackDispatcher,=0D + TrapHandlerNum,=0D + &mIoTrapHandle=0D + );=0D +=0D + ASSERT_EFI_ERROR (Status);=0D + mIoTrapData.Entry[TrapHandlerNum].IoTrapHandle =3D mIoTrapHandle;=0D +=0D + //=0D + // Fill in the Length, address and Enable the IO Trap SMI=0D + //=0D + IoTrapRegLowDword =3D (UINT32) (((UsedLength - 1) & ~(BIT1 + BIT0)) = << 16) |=0D + (UINT16) BaseAddress |=0D + B_PSTH_PCR_TRPREG_TSE;=0D +=0D + if (UsedLength < 4) {=0D + //=0D + // The 4 bits is the Byte Enable Mask bits to indicate which byte = that are trapped.=0D + // The input ByteEnable and ByteEnableMask are ignored in this cas= e.=0D + //=0D + IoTrapRegHighDword =3D (((1 << UsedLength) - 1) << ((*Address & 0= x3) + (N_PSTH_PCR_TRPREG_BEM - 32))) |=0D + (UINT32) (Type << N_PSTH_PCR_TRPREG_RWIO);=0D + } else {=0D + //=0D + // Fill in the ByteEnable, ByteEnableMask, and Type of Io Trap reg= ister=0D + //=0D + IoTrapRegHighDword =3D ((ByteEnableMask & 0xF) << (N_PSTH_PCR_TRP= REG_BEM - 32)) |=0D + ((ByteEnable & 0xF) << (N_PSTH_PCR_TRPREG_BE - 32)) |=0D + (UINT32) (Type << N_PSTH_PCR_TRPREG_RWIO);=0D + }=0D + SetIoTrapHighDword (TrapHandlerNum, IoTrapRegHighDword, TRUE);=0D + SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, TRUE);=0D + //=0D + // Set MergeDisable flag of the registered IoTrap=0D + //=0D + mIoTrapData.Entry[TrapHandlerNum].MergeDisable =3D TempMergeDisable;= =0D + } else {=0D + //=0D + // Check next handler if MergeDisable is TRUE or the registered IoTr= ap if MergeDisable is TRUE=0D + // If the Io Trap register is used by IoTrapEx protocol, then the Me= rgeDisable will be FALSE.=0D + //=0D + if ((TempMergeDisable =3D=3D TRUE) || (mIoTrapData.Entry[TrapHandler= Num].MergeDisable =3D=3D TRUE)) {=0D + continue;=0D + }=0D + //=0D + // The IO Trap handler is used, calculate the Length=0D + //=0D + UsedLength =3D LengthFromLowDword (IoTrapRegLowDword);=0D + BaseAddress =3D AddressFromLowDword (IoTrapRegLowDword);=0D + //=0D + // Assign an addfress from common pool if the caller's address is 0= =0D + //=0D + if (*Address =3D=3D 0) {=0D + //=0D + // Check next handler if it's fully used=0D + //=0D + if (mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength >=3D GENERIC_= IOTRAP_SIZE) {=0D + continue;=0D + }=0D + //=0D + // Check next handler if it's not for a common pool=0D + //=0D + if (UsedLength < GENERIC_IOTRAP_SIZE) {=0D + continue;=0D + }=0D + //=0D + // Check next handler if the size is too big=0D + //=0D + if (Length >=3D (UINT16) GENERIC_IOTRAP_SIZE - mIoTrapData.Entry[T= rapHandlerNum].TrapUsedLength) {=0D + continue;=0D + }=0D + //=0D + // For common pool, we don't need to change the BaseAddress and Us= edLength=0D + //=0D + *Address =3D (UINT16) (BaseAddress + mIoTrapData.Entry[TrapHandler= Num].TrapUsedLength);=0D + mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength +=3D Length;=0D + }=0D + //=0D + // Only set RWM bit when we need both read and write cycles.=0D + //=0D + IoTrapRegHighDword =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + = TrapHandlerNum * 8 + 4);=0D + if ((IoTrapRegHighDword & B_PSTH_PCR_TRPREG_RWM) =3D=3D 0 &&=0D + (UINT32) ((IoTrapRegHighDword & B_PSTH_PCR_TRPREG_RWIO) >> N_PST= H_PCR_TRPREG_RWIO) !=3D=0D + (UINT32) Type) {=0D + IoTrapRegHighDword =3D ((IoTrapRegHighDword | B_PSTH_PCR_TRPREG_RW= M) & ~B_PSTH_PCR_TRPREG_RWIO);=0D + SetIoTrapHighDword (TrapHandlerNum, IoTrapRegHighDword, TRUE);=0D + }=0D + }=0D + break;=0D + }=0D +=0D + if (TrapHandlerNum >=3D IO_TRAP_HANDLER_NUM) {=0D + DEBUG ((DEBUG_ERROR, "All IO Trap handler is used, no available IO Tra= p handler! \n"));=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D + //=0D + // Create database record and add to database=0D + //=0D + Status =3D gSmst->SmmAllocatePool (=0D + EfiRuntimeServicesData,=0D + sizeof (IO_TRAP_RECORD),=0D + (VOID **) &mIoTrapRecord=0D + );=0D +=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((DEBUG_ERROR, "Failed to allocate memory for mIoTrapRecord! \n"= ));=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D + //=0D + // Gather information about the registration request=0D + //=0D + mIoTrapRecord->Signature =3D IO_TRAP_RECORD_SIGNATURE;=0D + mIoTrapRecord->Context.Address =3D *Address;=0D + mIoTrapRecord->Context.Length =3D Length;=0D + mIoTrapRecord->Context.Type =3D Type;=0D + mIoTrapRecord->Context.ByteEnable =3D ByteEnable;=0D + mIoTrapRecord->Context.ByteEnableMask =3D ByteEnableMask;=0D + mIoTrapRecord->IoTrapCallback =3D IoTrapDispatchFunction;=0D + mIoTrapRecord->IoTrapExCallback =3D IoTrapExDispatchFunction;=0D + mIoTrapRecord->IoTrapNumber =3D TrapHandlerNum;=0D +=0D + InsertTailList (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase), &= mIoTrapRecord->Link);=0D +=0D + //=0D + // Child's handle will be the address linked list link in the record=0D + //=0D + *DispatchHandle =3D (EFI_HANDLE) (&mIoTrapRecord->Link);=0D +=0D + DEBUG ((DEBUG_INFO, "Result Address:%x \n", *Address));=0D + DEBUG ((DEBUG_INFO, "Result Length:%x \n", Length));=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + IoTrap unregistratrion helper fucntion.=0D +=0D + @param[in] DispatchHandle Handle of dispatch function=0D +=0D + @retval EFI_INVALID_PARAMETER If DispatchHandle is invalid,=0D + EFI_ACCESS_DENIED If the SmmReadyToLock event has be= en triggered,=0D + EFI_SUCCESS IoTrap unregister successfully.=0D +**/=0D +EFI_STATUS=0D +IoTrapUnRegisterHelper (=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + IO_TRAP_RECORD *RecordToDelete;=0D + UINT32 IoTrapRegLowDword;=0D + EFI_PHYSICAL_ADDRESS BaseAddress;=0D + UINT32 UsedLength;=0D + UINT8 TrapHandlerNum;=0D + UINT8 LengthIndex;=0D + BOOLEAN RequireToDisableIoTrapHandler;=0D +=0D + if (DispatchHandle =3D=3D 0) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock = event has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + RecordToDelete =3D IO_TRAP_RECORD_FROM_LINK (DispatchHandle);=0D + //=0D + // Take the entry out of the linked list=0D + //=0D + if (RecordToDelete->Link.ForwardLink =3D=3D (LIST_ENTRY *) EFI_BAD_POINT= ER) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + RequireToDisableIoTrapHandler =3D FALSE;=0D + //=0D + // Loop through the first IO Trap handler, looking for the suitable hand= ler=0D + //=0D + TrapHandlerNum =3D RecordToDelete->IoTrapNumber;=0D +=0D + if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable) {=0D + //=0D + // Disable the IO Trap handler if it's the only child of the Trap hand= ler=0D + //=0D + RequireToDisableIoTrapHandler =3D TRUE;=0D + } else {=0D + //=0D + // Get information from Io Trap handler register=0D + //=0D + IoTrapRegLowDword =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + Tra= pHandlerNum * 8);=0D +=0D + //=0D + // Check next Io Trap handler if the IO Trap handler is not used=0D + //=0D + if (AddressFromLowDword (IoTrapRegLowDword) !=3D 0) {=0D +=0D + UsedLength =3D LengthFromLowDword (IoTrapRegLowDword);=0D + BaseAddress =3D AddressFromLowDword (IoTrapRegLowDword);=0D +=0D + //=0D + // Check if it's the maximum address of the Io Trap handler=0D + //=0D + if ((UINTN)(BaseAddress + UsedLength) =3D=3D (UINTN)(RecordToDelete-= >Context.Address + RecordToDelete->Context.Length)) {=0D +=0D + if (BaseAddress =3D=3D RecordToDelete->Context.Address) {=0D + //=0D + // Disable the IO Trap handler if it's the only child of the Tra= p handler=0D + //=0D + RequireToDisableIoTrapHandler =3D TRUE;=0D + } else {=0D + //=0D + // Calculate the new IO Trap handler Length=0D + //=0D + UsedLength =3D UsedLength - RecordToDelete->Context.Length;=0D + //=0D + // Check the alignment is dword * power of 2 or not=0D + //=0D + for (LengthIndex =3D 0; LengthIndex < sizeof (mLengthTable) / si= zeof (UINT16); LengthIndex++) {=0D + if (UsedLength =3D=3D mLengthTable[LengthIndex]) {=0D + break;=0D + }=0D + }=0D + //=0D + // Do not decrease the length if the alignment is not dword * po= wer of 2=0D + //=0D + if (LengthIndex < sizeof (mLengthTable) / sizeof (UINT16)) {=0D + //=0D + // Decrease the length to prevent the IO trap SMI=0D + //=0D + IoTrapRegLowDword =3D (UINT32) ((((UsedLength - 1) &~(BIT1 + B= IT0)) << 16) | BaseAddress | B_PSTH_PCR_TRPREG_TSE);=0D + }=0D + SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, TRUE);=0D + }=0D + }=0D + }=0D + }=0D +=0D + if (RequireToDisableIoTrapHandler) {=0D + mIoTrapHandle =3D mIoTrapData.Entry[TrapHandlerNum].IoTrapHandle;=0D + Status =3D PchInternalIoTrapSmiUnRegister (mIoTrapHandle);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + SetIoTrapLowDword (TrapHandlerNum, 0, TRUE);=0D + SetIoTrapHighDword (TrapHandlerNum, 0, TRUE);=0D + //=0D + // Also clear pending IOTRAP status.=0D + //=0D + ClearPendingIoTrapStatus (TrapHandlerNum);=0D +=0D + mIoTrapData.Entry[TrapHandlerNum].IoTrapHandle =3D 0;=0D + mIoTrapData.Entry[TrapHandlerNum].MergeDisable =3D FALSE;=0D + if (mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource =3D=3D TR= UE) {=0D + mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource =3D FALSE;= =0D + UpdateIoTrapAcpiResources (TrapHandlerNum, 0, FALSE);=0D + }=0D + }=0D +=0D + RemoveEntryList (&RecordToDelete->Link);=0D + Status =3D gSmst->SmmFreePool (RecordToDelete);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Register a new IO Trap SMI dispatch function with a parent SMM driver.=0D + The caller will provide information about the IO trap characteristics vi= a=0D + the context. This includes base address, length, read vs. r/w, etc.=0D + This function will autoallocate IO base address from a common pool if th= e base address is 0,=0D + and the RegisterContext Address field will be updated.=0D + The service will not perform GCD allocation if the base address is non-z= ero.=0D + In this case, the caller is responsible for the existence and allocation= of the=0D + specific IO range.=0D + This function looks for the suitable handler and Register a new IoTrap h= andler=0D + if the IO Trap handler is not used. It also enable the IO Trap Range to = generate=0D + SMI.=0D +=0D + @param[in] This Pointer to the EFI_SMM_IO_TRAP_DISPATCH2= _PROTOCOL instance.=0D + @param[in] DispatchFunction Pointer to dispatch function to be invok= ed for=0D + this SMI source.=0D + @param[in, out] RegisterContext Pointer to the dispatch function's conte= xt.=0D + The caller fills this context in before = calling=0D + the register function to indicate to the= register=0D + function the IO trap SMI source for whic= h the dispatch=0D + function should be invoked. This may no= t be NULL.=0D + If the registration address is not 0, it= 's caller's responsibility=0D + to reserve the IO resource in ACPI.=0D + @param[out] DispatchHandle Handle of dispatch function, for when in= terfacing=0D + with the parent SMM driver, will be the = address of linked=0D + list link in the call back record. This= may not be NULL.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been successfu= lly=0D + registered and the SMI source has been e= nabled.=0D + @retval EFI_DEVICE_ERROR The driver was unable to enable the SMI = source.=0D + @retval EFI_OUT_OF_RESOURCES Insufficient resources are available=0D + @retval EFI_INVALID_PARAMETER Address requested is already in use.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLo= ck event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IoTrapRegister (=0D + IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *This,=0D + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,=0D + IN OUT EFI_SMM_IO_TRAP_REGISTER_CONTEXT *RegisterContext,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + DEBUG ((DEBUG_INFO, "IoTrapRegister\n"));=0D + Status =3D IoTrapRegisterHelper (=0D + DispatchHandle,=0D + DispatchFunction,=0D + NULL,=0D + &(RegisterContext->Address),=0D + RegisterContext->Length,=0D + (IO_TRAP_EX_DISPATCH_TYPE) RegisterContext->Type,=0D + 0x00,=0D + 0x0F);=0D +=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileRegisterHandler (=0D + &gEfiSmmIoTrapDispatch2ProtocolGuid,=0D + DispatchFunction,=0D + (UINTN)RETURN_ADDRESS (0),=0D + RegisterContext,=0D + sizeof (EFI_SMM_IO_TRAP_REGISTER_CONTEXT)=0D + );=0D + }=0D + return Status;=0D +}=0D +=0D +/**=0D + Unregister a child SMI source dispatch function with a parent SMM driver= .=0D +=0D + @param[in] This Pointer to the EFI_SMM_IO_TRAP_DISPATCH2= _PROTOCOL instance.=0D + @param[in] DispatchHandle Handle of dispatch function to deregiste= r.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been successfu= lly=0D + unregistered and the SMI source has been= disabled=0D + if there are no other registered child d= ispatch=0D + functions for this SMI source.=0D + @retval EFI_INVALID_PARAMETER Handle is invalid.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLo= ck event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IoTrapUnRegister (=0D + IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *This,=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + IO_TRAP_RECORD *RecordToDelete;=0D +=0D + RecordToDelete =3D IO_TRAP_RECORD_FROM_LINK (DispatchHandle);=0D + SmiHandlerProfileUnregisterHandler (=0D + &gIoTrapExDispatchProtocolGuid,=0D + RecordToDelete->IoTrapCallback,=0D + &RecordToDelete->Context,=0D + sizeof (EFI_SMM_IO_TRAP_REGISTER_CONTEXT)=0D + );=0D + return IoTrapUnRegisterHelper (DispatchHandle);=0D +}=0D +=0D +/**=0D + Register a new IO Trap Ex SMI dispatch function.=0D +=0D + @param[in] This Pointer to the IO_TRAP_EX_DISPATCH_PROTO= COL instance.=0D + @param[in] DispatchFunction Pointer to dispatch function to be invok= ed for=0D + this SMI source.=0D + @param[in] RegisterContext Pointer to the dispatch function's conte= xt.=0D + The caller fills this context in before = calling=0D + the register function to indicate to the= register=0D + function the IO trap Ex SMI source for w= hich the dispatch=0D + function should be invoked. This MUST n= ot be NULL.=0D + @param[out] DispatchHandle Handle of dispatch function.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been successfu= lly=0D + registered and the SMI source has been e= nabled.=0D + @retval EFI_OUT_OF_RESOURCES Insufficient resources are available=0D + @retval EFI_INVALID_PARAMETER Address requested is already in use.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLo= ck event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IoTrapExRegister (=0D + IN IO_TRAP_EX_DISPATCH_PROTOCOL *This,=0D + IN IO_TRAP_EX_DISPATCH_CALLBACK DispatchFunction,=0D + IN IO_TRAP_EX_REGISTER_CONTEXT *RegisterContext,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + DEBUG ((DEBUG_INFO, "PchSmmIoTrapExRegister\n"));=0D + //=0D + // Return error if length is less than 4 and not power of 2.=0D + //=0D + if ((RegisterContext->Length < 4) || ((RegisterContext->Length & (Regist= erContext->Length - 1)) !=3D 0)) {=0D + DEBUG ((DEBUG_ERROR, "The Dispatch Length is not power of 2 \n"));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + Status =3D IoTrapRegisterHelper (=0D + DispatchHandle,=0D + NULL,=0D + DispatchFunction,=0D + &(RegisterContext->Address),=0D + RegisterContext->Length,=0D + RegisterContext->Type,=0D + RegisterContext->ByteEnable,=0D + RegisterContext->ByteEnableMask);=0D +=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileRegisterHandler (=0D + &gIoTrapExDispatchProtocolGuid,=0D + (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,=0D + (UINTN)RETURN_ADDRESS (0),=0D + RegisterContext,=0D + sizeof (*RegisterContext)=0D + );=0D + }=0D + return Status;=0D +}=0D +=0D +/**=0D + Unregister a SMI source dispatch function.=0D + This function is unsupported.=0D +=0D + @param[in] This Pointer to the IO_TRAP_EX_DISPATCH_PROTO= COL instance.=0D + @param[in] DispatchHandle Handle of dispatch function to deregiste= r.=0D +=0D + @retval EFI_UNSUPPORTED The function is unsupported.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IoTrapExUnRegister (=0D + IN IO_TRAP_EX_DISPATCH_PROTOCOL *This,=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + IO_TRAP_RECORD *RecordToDelete;=0D +=0D + RecordToDelete =3D IO_TRAP_RECORD_FROM_LINK (DispatchHandle);=0D + SmiHandlerProfileUnregisterHandler (=0D + &gIoTrapExDispatchProtocolGuid,=0D + RecordToDelete->IoTrapCallback,=0D + &RecordToDelete->Context,=0D + sizeof (RecordToDelete->Context)=0D + );=0D + return IoTrapUnRegisterHelper (DispatchHandle);=0D +}=0D +=0D +/**=0D + Pause IoTrap callback function.=0D +=0D + This function disables the SMI enable of IoTrap according to the Dispatc= hHandle,=0D + which is returned by IoTrap callback registration. It only supports the = DispatchHandle=0D + with MergeDisable TRUE and address not zero.=0D +=0D + NOTE: This call does not guarantee all pending IO cycles to be synchroni= zed=0D + and pending IO cycles issued before this call might not be trapped= .=0D +=0D + @param[in] This Pointer to the PCH_SMM_IO_TRAP_CONTROL_P= ROTOCOL instance.=0D + @param[in] DispatchHandle Handle of the child service to change st= ate.=0D +=0D + @retval EFI_SUCCESS This operation is complete.=0D + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid.=0D + @retval EFI_ACCESS_DENIED The SMI status is alrady PAUSED.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IoTrapControlPause (=0D + IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL *This,=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + IO_TRAP_RECORD *IoTrapRecord;=0D + UINT32 IoTrapRegLowDword;=0D + UINT32 IoTrapRegHighDword;=0D + EFI_PHYSICAL_ADDRESS BaseAddress;=0D + UINT32 UsedLength;=0D + UINT8 TrapHandlerNum;=0D + BOOLEAN TempMergeDisable;=0D + BOOLEAN DisableIoTrap;=0D +=0D + if (DispatchHandle =3D=3D 0) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + IoTrapRecord =3D IO_TRAP_RECORD_FROM_LINK (DispatchHandle);=0D +=0D + if (IoTrapRecord->Context.Address) {=0D + TempMergeDisable =3DTRUE;=0D + }else {=0D + TempMergeDisable =3D FALSE;=0D + }=0D +=0D + if ((IoTrapRecord->Signature !=3D IO_TRAP_RECORD_SIGNATURE) ||=0D + (TempMergeDisable !=3D TRUE) ||=0D + (IoTrapRecord->Context.Address =3D=3D 0) ||=0D + (IoTrapRecord->Context.Length =3D=3D 0)) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + for (TrapHandlerNum =3D 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; TrapHan= dlerNum++) {=0D + //=0D + // This IoTrap register should be merge disabled.=0D + //=0D + if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable !=3D TRUE) {=0D + continue;=0D + }=0D + IoTrapRegLowDword =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + Tra= pHandlerNum * 8);=0D + IoTrapRegHighDword =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + Tr= apHandlerNum * 8 + 4);=0D + //=0D + // Depending on the usage, we will obtain the UsedLength and BaseAddre= ss differently=0D + // If the registered trap length is less than 4, we obtain the length = from Byte Enable Mask=0D + // In the other hand, we obtain the length from Address Mask=0D + //=0D + if (ByteEnableMaskFromHighDword (IoTrapRegHighDword) !=3D 0xF) {=0D + UsedLength =3D (UINT32) (HighBitSet32 (IoTrapRegHighDword & 0xF0) - = LowBitSet32 (IoTrapRegHighDword & 0xF0) + 1);=0D + BaseAddress =3D AddressFromLowDword (IoTrapRegLowDword) + LowBitSet3= 2 (ByteEnableMaskFromHighDword (IoTrapRegHighDword));=0D + } else {=0D + UsedLength =3D LengthFromLowDword (IoTrapRegLowDword);=0D + BaseAddress =3D AddressFromLowDword (IoTrapRegLowDword);=0D + }=0D +=0D + //=0D + // The address and length of record matches the IoTrap register's.=0D + //=0D + DisableIoTrap =3D FALSE;=0D + if ((IoTrapRecord->IoTrapExCallback !=3D NULL) &&=0D + IsIoTrapExContentMatched (IoTrapRecord, IoTrapRegLowDword, IoTrapR= egHighDword)) {=0D + DisableIoTrap =3D TRUE;=0D + } else if ((BaseAddress =3D=3D IoTrapRecord->Context.Address) &&=0D + (UsedLength =3D=3D IoTrapRecord->Context.Length )) {=0D + DisableIoTrap =3D TRUE;=0D + }=0D +=0D + if (DisableIoTrap) {=0D + //=0D + // Check if status matched.=0D + // If this is already Paused, return warning status.=0D + //=0D + if ((IoTrapRegLowDword & B_PSTH_PCR_TRPREG_TSE) =3D=3D 0) {=0D + return EFI_ACCESS_DENIED;=0D + }=0D + //=0D + // Clear IoTrap register SMI enable bit=0D + //=0D + IoTrapRegLowDword &=3D (~B_PSTH_PCR_TRPREG_TSE);=0D + SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, FALSE);=0D + //=0D + // Also clear pending IOTRAP status.=0D + //=0D + ClearPendingIoTrapStatus (TrapHandlerNum);=0D + return EFI_SUCCESS;=0D + }=0D + }=0D + return EFI_INVALID_PARAMETER;=0D +}=0D +=0D +/**=0D + Resume IoTrap callback function.=0D +=0D + This function enables the SMI enable of IoTrap according to the Dispatch= Handle,=0D + which is returned by IoTrap callback registration. It only supports the = DispatchHandle=0D + with MergeDisable TRUE and address not zero.=0D +=0D + @param[in] This Pointer to the PCH_SMM_IO_TRAP_CONTROL_P= ROTOCOL instance.=0D + @param[in] DispatchHandle Handle of the child service to change st= ate.=0D +=0D + @retval EFI_SUCCESS This operation is complete.=0D + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid.=0D + @retval EFI_ACCESS_DENIED The SMI status is alrady RESUMED.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IoTrapControlResume (=0D + IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL *This,=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + IO_TRAP_RECORD *IoTrapRecord;=0D + UINT32 IoTrapRegLowDword;=0D + UINT32 IoTrapRegHighDword;=0D + EFI_PHYSICAL_ADDRESS BaseAddress;=0D + UINT32 UsedLength;=0D + UINT8 TrapHandlerNum;=0D + BOOLEAN TempMergeDisable;=0D + BOOLEAN EnableIoTrap;=0D +=0D + if (DispatchHandle =3D=3D 0) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D + IoTrapRecord =3D IO_TRAP_RECORD_FROM_LINK (DispatchHandle);=0D +=0D + if (IoTrapRecord->Context.Address) {=0D + TempMergeDisable =3D TRUE;=0D + }else {=0D + TempMergeDisable =3D FALSE;=0D + }=0D +=0D + if ((IoTrapRecord->Signature !=3D IO_TRAP_RECORD_SIGNATURE) ||=0D + (TempMergeDisable !=3D TRUE) ||=0D + (IoTrapRecord->Context.Address =3D=3D 0) ||=0D + (IoTrapRecord->Context.Length =3D=3D 0)) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + for (TrapHandlerNum =3D 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; TrapHan= dlerNum++) {=0D + //=0D + // This IoTrap register should be merge disabled.=0D + //=0D + if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable !=3D TRUE) {=0D + continue;=0D + }=0D + IoTrapRegLowDword =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + Tra= pHandlerNum * 8);=0D + IoTrapRegHighDword =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + Tr= apHandlerNum * 8 + 4);=0D + //=0D + // Depending on the usage, we will obtain the UsedLength and BaseAddre= ss differently=0D + // If the registered trap length is less than 4, we obtain the length = from Byte Enable Mask=0D + // In the other hand, we obtain the length from Address Mask=0D + //=0D + if (ByteEnableMaskFromHighDword (IoTrapRegHighDword) !=3D 0xF) {=0D + UsedLength =3D (UINT32) (HighBitSet32 (IoTrapRegHighDword & 0xF0) -= LowBitSet32 (IoTrapRegHighDword & 0xF0) + 1);=0D + BaseAddress =3D AddressFromLowDword (IoTrapRegLowDword) + LowBitSet3= 2 (ByteEnableMaskFromHighDword (IoTrapRegHighDword));=0D + } else {=0D + UsedLength =3D LengthFromLowDword (IoTrapRegLowDword);=0D + BaseAddress =3D AddressFromLowDword (IoTrapRegLowDword);=0D + }=0D +=0D + //=0D + // The address and length of record matches the IoTrap register's.=0D + //=0D + EnableIoTrap =3D FALSE;=0D + if ((IoTrapRecord->IoTrapExCallback !=3D NULL) &&=0D + IsIoTrapExContentMatched (IoTrapRecord, IoTrapRegLowDword, IoTrapR= egHighDword)) {=0D + EnableIoTrap =3D TRUE;=0D + } else if ((BaseAddress =3D=3D IoTrapRecord->Context.Address) &&=0D + (UsedLength =3D=3D IoTrapRecord->Context.Length )) {=0D + EnableIoTrap =3D TRUE;=0D + }=0D +=0D + if (EnableIoTrap) {=0D + //=0D + // Check if status matched.=0D + // If this is already Resume, return warning status.=0D + //=0D + if ((IoTrapRegLowDword & B_PSTH_PCR_TRPREG_TSE) !=3D 0) {=0D + return EFI_ACCESS_DENIED;=0D + }=0D + //=0D + // Set IoTrap register SMI enable bit=0D + //=0D + IoTrapRegLowDword |=3D (B_PSTH_PCR_TRPREG_TSE);=0D + SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, FALSE);=0D + return EFI_SUCCESS;=0D + }=0D + }=0D + return EFI_INVALID_PARAMETER;=0D +}=0D +=0D +/**=0D + The IoTrap module abstracts PCH I/O trapping capabilities for other driv= ers.=0D + This driver manages the limited I/O trap resources.=0D +=0D + @param[in] ImageHandle Image handle for this driver image= =0D +=0D + @retval EFI_SUCCESS Driver initialization completed su= ccessfully=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +InstallIoTrap (=0D + IN EFI_HANDLE ImageHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + PCH_NVS_AREA_PROTOCOL *PchNvsAreaProtocol;=0D + UINTN TrapHandlerNum;=0D +=0D + //=0D + // Initialize the EFI SMM driver library=0D + //=0D + mDriverImageHandle =3D ImageHandle;=0D +=0D + //=0D + // Initialize the IO TRAP protocol we produce=0D + //=0D + mIoTrapData.Signature =3D IO_TRAP_INSTANCE_SIGNATURE;=0D + mIoTrapData.EfiSmmIoTrapDispatchProtocol.Register =3D IoTrapRegister;= =0D + mIoTrapData.EfiSmmIoTrapDispatchProtocol.UnRegister =3D IoTrapUnRegister= ;=0D +=0D + //=0D + // Initialize the IO TRAP EX protocol=0D + //=0D + mIoTrapData.IoTrapExDispatchProtocol.Register =3D IoTrapExRegister= ;=0D + mIoTrapData.IoTrapExDispatchProtocol.UnRegister =3D IoTrapExUnRegist= er;=0D +=0D + //=0D + // Initialize the IO TRAP control protocol.=0D + //=0D + mIoTrapData.PchSmmIoTrapControlProtocol.Pause =3D IoTrapControlPau= se;=0D + mIoTrapData.PchSmmIoTrapControlProtocol.Resume =3D IoTrapControlRes= ume;=0D +=0D + for (TrapHandlerNum =3D 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; TrapHan= dlerNum++) {=0D + //=0D + // Initialize IO TRAP Callback DataBase=0D + //=0D + InitializeListHead (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBa= se));=0D + }=0D + mIoTrapData.Entry[0].CallbackDispatcher =3D IoTrapDispatcher0;=0D + mIoTrapData.Entry[1].CallbackDispatcher =3D IoTrapDispatcher1;=0D + mIoTrapData.Entry[2].CallbackDispatcher =3D IoTrapDispatcher2;=0D + mIoTrapData.Entry[3].CallbackDispatcher =3D IoTrapDispatcher3;=0D +=0D + //=0D + // Get address of PchNvs structure for later use=0D + //=0D + Status =3D gBS->LocateProtocol (&gPchNvsAreaProtocolGuid, NULL, (VOID **= ) &PchNvsAreaProtocol);=0D + ASSERT_EFI_ERROR (Status);=0D + mPchNvsArea =3D PchNvsAreaProtocol->Area;=0D +=0D + //=0D + // Install protocol interface=0D + //=0D + mIoTrapData.Handle =3D NULL;=0D + Status =3D gSmst->SmmInstallProtocolInterface (=0D + &mIoTrapData.Handle,=0D + &gEfiSmmIoTrapDispatch2ProtocolGuid,=0D + EFI_NATIVE_INTERFACE,=0D + &mIoTrapData.EfiSmmIoTrapDispatchProtocol=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Status =3D gSmst->SmmInstallProtocolInterface (=0D + &mIoTrapData.Handle,=0D + &gIoTrapExDispatchProtocolGuid,=0D + EFI_NATIVE_INTERFACE,=0D + &mIoTrapData.IoTrapExDispatchProtocol=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Status =3D gSmst->SmmInstallProtocolInterface (=0D + &mIoTrapData.Handle,=0D + &gPchSmmIoTrapControlGuid,=0D + EFI_NATIVE_INTERFACE,=0D + &mIoTrapData.PchSmmIoTrapControlProtocol=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + return EFI_SUCCESS;=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoT= rap.h b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.h new file mode 100644 index 0000000000..e69d2e2d4d --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.h @@ -0,0 +1,226 @@ +/** @file=0D + Defines and prototypes for the IoTrap SMM driver=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#ifndef _IO_TRAP_H_=0D +#define _IO_TRAP_H_=0D +=0D +//=0D +// Include files=0D +//=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#define IO_TRAP_HANDLER_NUM 4=0D +=0D +//=0D +// Driver private data=0D +//=0D +#define IO_TRAP_INSTANCE_SIGNATURE SIGNATURE_32 ('I', 'O', 'T', 'P')=0D +=0D +typedef struct {=0D + EFI_HANDLE IoTrapHandle;=0D + /**=0D + The callback linked list for all "merged" IoTrap callbacks.=0D + **/=0D + LIST_ENTRY CallbackDataBase;=0D + /**=0D + The IoTrap IO range used length tracking for "merged" IoTrap register.= =0D + **/=0D + UINT32 TrapUsedLength;=0D + /**=0D + Determine if IoTrap can be merged with other IoTrap callbacks.=0D + If MergeDisable is TRUE, then there is only one callback function for = one IoTrap register.=0D + If MergeDisable is FALSE, then there are multiple callbacks in the "Ca= llbackDataBase" for one IoTrap register.=0D + **/=0D + BOOLEAN MergeDisable;=0D + /**=0D + Indicator of the resource tracking in ACPI.=0D + If the registration address is not 0, it's caller's responsibility to = reserve the IO resource in ACPI.=0D + **/=0D + BOOLEAN ReservedAcpiIoResource;=0D + /**=0D + Dispatcher for each IoTrap register.=0D + **/=0D + PCH_SMI_DISPATCH_CALLBACK CallbackDispatcher;=0D +} IO_TRAP_ENTRY_ATTRIBUTES;=0D +=0D +typedef struct {=0D + UINT32 Signature;=0D + EFI_HANDLE Handle;=0D + EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL EfiSmmIoTrapDispatchProtocol;=0D + PCH_SMM_IO_TRAP_CONTROL_PROTOCOL PchSmmIoTrapControlProtocol; = ///< Protocol for runtime control the IoTrap state=0D + IO_TRAP_EX_DISPATCH_PROTOCOL IoTrapExDispatchProtocol; = ///< Protocol for IoTrap Extension=0D + IO_TRAP_ENTRY_ATTRIBUTES Entry[IO_TRAP_HANDLER_NUM];=0D +} IO_TRAP_INSTANCE;=0D +=0D +#define IO_TRAP_INSTANCE_FROM_THIS(a) CR (a, IO_TRAP_INSTANCE, EfiSmmIoTra= pDispatchProtocol, IO_TRAP_INSTANCE_SIGNATURE)=0D +=0D +///=0D +/// "IOTRAP" RECORD=0D +/// Linked list data structures=0D +///=0D +#define IO_TRAP_RECORD_SIGNATURE SIGNATURE_32 ('I', 'T', 'R', 'C')=0D +=0D +typedef struct _IO_TRAP_RECORD {=0D + UINT32 Signature;=0D + LIST_ENTRY Link;=0D + IO_TRAP_EX_REGISTER_CONTEXT Context;=0D + /**=0D + The callback function of IoTrap protocol.=0D + This also indicate it's the record for IoTrapProtocol.=0D + Only one of IoTrapCallback or IoTrapExCallback is valid at a time.=0D + **/=0D + EFI_SMM_HANDLER_ENTRY_POINT2 IoTrapCallback;=0D + /**=0D + The callback function of IoTrapEx protocol=0D + This also indicate it's the record for IoTrapExProtocol.=0D + Only one of IoTrapCallback or IoTrapExCallback is valid at a time.=0D + **/=0D + IO_TRAP_EX_DISPATCH_CALLBACK IoTrapExCallback;=0D + UINT8 IoTrapNumber;=0D +} IO_TRAP_RECORD;=0D +=0D +#define IO_TRAP_RECORD_FROM_LINK(_record) CR (_record, IO_TRAP_RECORD, Lin= k, IO_TRAP_RECORD_SIGNATURE)=0D +=0D +//=0D +// Prototypes=0D +//=0D +/**=0D + The IoTrap module abstracts PCH I/O trapping capabilities for other driv= ers.=0D + This driver manages the limited I/O trap resources.=0D +=0D + @param[in] ImageHandle Image handle for this driver image= =0D +=0D + @retval EFI_SUCCESS Driver initialization completed su= ccessfully=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +InstallIoTrap (=0D + IN EFI_HANDLE ImageHandle=0D + );=0D +=0D +/**=0D + Register a new IO Trap SMI dispatch function with a parent SMM driver.=0D + The caller will provide information about the IO trap characteristics vi= a=0D + the context. This includes base address, length, read vs. r/w, etc.=0D + This function will autoallocate IO base address from a common pool if th= e base address is 0,=0D + and the RegisterContext Address field will be updated.=0D + The service will not perform GCD allocation if the base address is non-z= ero.=0D + In this case, the caller is responsible for the existence and allocation= of the=0D + specific IO range.=0D + This function looks for the suitable handler and Register a new IoTrap h= andler=0D + if the IO Trap handler is not used. It also enable the IO Trap Range to = generate=0D + SMI.=0D +=0D + @param[in] This Pointer to the EFI_SMM_IO_TRAP_DISPATCH= 2_PROTOCOL instance.=0D + @param[in] DispatchFunction Pointer to dispatch function to be invok= ed for=0D + this SMI source.=0D + @param[in, out] RegisterContext Pointer to the dispatch function's conte= xt.=0D + The caller fills this context in before = calling=0D + the register function to indicate to the= register=0D + function the IO trap SMI source for whic= h the dispatch=0D + function should be invoked. This may no= t be NULL.=0D + If the registration address is not 0, it= 's caller's responsibility=0D + to reserve the IO resource in ACPI.=0D + @param[out] DispatchHandle Handle of dispatch function, for when in= terfacing=0D + with the parent SMM driver, will be the = address of linked=0D + list link in the call back record. This= may not be NULL.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been successfu= lly=0D + registered and the SMI source has been e= nabled.=0D + @retval EFI_DEVICE_ERROR The driver was unable to enable the SMI = source.=0D + @retval EFI_OUT_OF_RESOURCES Insufficient resources are available=0D + @retval EFI_INVALID_PARAMETER Address requested is already in use.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLo= ck event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IoTrapRegister (=0D + IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *This,=0D + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,=0D + IN OUT EFI_SMM_IO_TRAP_REGISTER_CONTEXT *RegisterContext,=0D + OUT EFI_HANDLE *DispatchHandle=0D + );=0D +=0D +/**=0D + Unregister a child SMI source dispatch function with a parent SMM driver= .=0D +=0D + @param[in] This Pointer to the EFI_SMM_IO_TRAP_DISPATCH= 2_PROTOCOL instance.=0D + @param[in] DispatchHandle Handle of dispatch function to deregiste= r.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been successfu= lly=0D + unregistered and the SMI source has been= disabled=0D + if there are no other registered child d= ispatch=0D + functions for this SMI source.=0D + @retval EFI_INVALID_PARAMETER Handle is invalid.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLo= ck event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IoTrapUnRegister (=0D + IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *This,=0D + IN EFI_HANDLE DispatchHandle=0D + );=0D +=0D +/**=0D + This I/O Trap SMI handler invokes the ACPI reference code to handle the = SMI.=0D + It currently assumes it owns all of the IO trap SMI.=0D +=0D + @param[in] DispatchHandle Not used=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +IoTrapCallback (=0D + IN EFI_HANDLE DispatchHandle=0D + );=0D +=0D +/**=0D + Pause IoTrap callback function.=0D +=0D + This function disables the SMI enable of IoTrap according to the Dispatc= hHandle,=0D + which is returned by IoTrap callback registration. It only supports the = DispatchHandle=0D + with MergeDisable TRUE and address not zero.=0D +=0D + @param[in] This Pointer to the PCH_SMM_IO_TRAP_CONTROL_P= ROTOCOL instance.=0D + @param[in] DispatchHandle Handle of the child service to change st= ate.=0D +=0D + @retval EFI_SUCCESS This operation is complete.=0D + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid.=0D + @retval EFI_ACCESS_DENIED The SMI status is alrady PAUSED.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IoTrapControlPause (=0D + IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL * This,=0D + IN EFI_HANDLE DispatchHandle=0D + );=0D +=0D +/**=0D + Resume IoTrap callback function.=0D +=0D + This function enables the SMI enable of IoTrap according to the Dispatch= Handle,=0D + which is returned by IoTrap callback registration. It only supports the = DispatchHandle=0D + with MergeDisable TRUE and address not zero.=0D +=0D + @param[in] This Pointer to the PCH_SMM_IO_TRAP_CONTROL_P= ROTOCOL instance.=0D + @param[in] DispatchHandle Handle of the child service to change st= ate.=0D +=0D + @retval EFI_SUCCESS This operation is complete.=0D + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid.=0D + @retval EFI_ACCESS_DENIED The SMI status is alrady RESUMED.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IoTrapControlResume (=0D + IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL * This,=0D + IN EFI_HANDLE DispatchHandle=0D + );=0D +=0D +#endif=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmiDispatch.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/= PchSmiDispatch.c new file mode 100644 index 0000000000..affbe94eb7 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDisp= atch.c @@ -0,0 +1,2442 @@ +/** @file=0D + This function handle the register/unregister of PCH specific SMI events.= =0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include "PchSmmHelpers.h"=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include "PchSmiHelper.h"=0D +=0D +/**=0D + The internal function used to create and insert a database record=0D + for SMI record of Pch Smi types.=0D +=0D + @param[in] SrcDesc The pointer to the SMI source desc= ription=0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[in] PchSmiType Specific SMI type of PCH SMI=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D +**/=0D +EFI_STATUS=0D +PchSmiRecordInsert (=0D + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc,=0D + IN PCH_SMI_CALLBACK_FUNCTIONS DispatchFunction,=0D + IN PCH_SMI_TYPES PchSmiType,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + DATABASE_RECORD Record;=0D +=0D + if (SrcDesc =3D=3D NULL) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + ZeroMem (&Record, sizeof (DATABASE_RECORD));=0D + //=0D + // Gather information about the registration request=0D + //=0D + Record.Signature =3D DATABASE_RECORD_SIGNATURE;=0D + Record.PchSmiCallback =3D DispatchFunction;=0D + Record.ProtocolType =3D PchSmiDispatchType;=0D + Record.PchSmiType =3D PchSmiType;=0D +=0D + CopyMem (&Record.SrcDesc, SrcDesc, sizeof (PCH_SMM_SOURCE_DESC));=0D + Status =3D SmmCoreInsertRecord (=0D + &Record,=0D + DispatchHandle=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +=0D +//=0D +// TCO_STS bit that needs to be cleared=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mDescSrcTcoSts =3D= {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + NULL_BIT_DESC_INITIALIZER,=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_TCO=0D + }=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D +};=0D +=0D +/**=0D + Clear the TCO SMI status bit and block after the SMI handling is done=0D +=0D + @param[in] SrcDesc Pointer to the PCH SMI source desc= ription table=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +PchTcoSmiClearSourceAndBlock (=0D + CONST PCH_SMM_SOURCE_DESC *SrcDesc=0D + )=0D +{=0D + PchSmmClearSourceAndBlock (SrcDesc);=0D + //=0D + // Any TCO-based status bits require special handling.=0D + // SMI_STS.TCO_STS must be cleared in addition to the status bit in the = TCO registers=0D + //=0D + PchSmmClearSource (&mDescSrcTcoSts);=0D +}=0D +=0D +/**=0D + Clear the TCO SMI status bit after the SMI handling is done=0D +=0D + @param[in] SrcDesc Pointer to the PCH SMI source desc= ription table=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +PchTcoSmiClearSource (=0D + CONST PCH_SMM_SOURCE_DESC *SrcDesc=0D + )=0D +{=0D + PchSmmClearSource (SrcDesc);=0D + //=0D + // Any TCO-based status bits require special handling.=0D + // SMI_STS.TCO_STS must be cleared in addition to the status bit in the = TCO registers=0D + //=0D + PchSmmClearSource (&mDescSrcTcoSts);=0D +}=0D +=0D +/**=0D + Initialize Source descriptor structure=0D +=0D + @param[in] SrcDesc Pointer to the PCH SMI source des= cription table=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +NullInitSourceDesc (=0D + PCH_SMM_SOURCE_DESC *SrcDesc=0D + )=0D +{=0D + ZeroMem (SrcDesc, sizeof (PCH_SMM_SOURCE_DESC));=0D + SrcDesc->En[0].Reg.Type =3D PCH_SMM_ADDR_TYPE_NULL;=0D + SrcDesc->En[1].Reg.Type =3D PCH_SMM_ADDR_TYPE_NULL;=0D + SrcDesc->Sts[0].Reg.Type =3D PCH_SMM_ADDR_TYPE_NULL;=0D + SrcDesc->PmcSmiSts.Reg.Type =3D PCH_SMM_ADDR_TYPE_NULL;=0D +}=0D +=0D +//=0D +// Mch srcdesc=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescMch =3D {= =0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_EN}=0D + },=0D + S_ACPI_IO_SMI_EN,=0D + N_ACPI_IO_SMI_EN_TCO=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + TCO_ADDR_TYPE,=0D + {R_TCO_IO_TCO1_STS}=0D + },=0D + S_TCO_IO_TCO1_STS,=0D + N_TCO_IO_TCO1_STS_DMISMI=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_TCO=0D + }=0D +};=0D +=0D +/**=0D + The register function used to register SMI handler of MCH event.=0D +=0D + @param[in] This The pointer to the protocol itself= =0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchTcoSmiMchRegister (=0D + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + DATABASE_RECORD *Record;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D PchSmiRecordInsert (=0D + &mSrcDescMch,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchTcoSmiMchType,=0D + DispatchHandle=0D + );=0D + if (!EFI_ERROR (Status)) {=0D + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle);=0D + Record->ClearSource =3D PchTcoSmiClearSource;=0D + PchSmmClearSource (&Record->SrcDesc);=0D + PchSmmEnableSource (&Record->SrcDesc);=0D + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EF= I_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NUL= L, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +//=0D +// TcoTimeout srcdesc=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescTcoTimeout= =3D {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_EN}=0D + },=0D + S_ACPI_IO_SMI_EN,=0D + N_ACPI_IO_SMI_EN_TCO=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + TCO_ADDR_TYPE,=0D + {R_TCO_IO_TCO1_STS}=0D + },=0D + S_TCO_IO_TCO1_STS,=0D + N_TCO_IO_TCO1_STS_TIMEOUT=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_TCO=0D + }=0D +};=0D +=0D +/**=0D + The register function used to register SMI handler of TcoTimeout event.= =0D +=0D + @param[in] This The pointer to the protocol itself= =0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchTcoSmiTcoTimeoutRegister (=0D + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + DATABASE_RECORD *Record;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D PchSmiRecordInsert (=0D + &mSrcDescTcoTimeout,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchTcoSmiTcoTimeoutType,=0D + DispatchHandle=0D + );=0D + if (!EFI_ERROR (Status)) {=0D + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle);=0D + Record->ClearSource =3D PchTcoSmiClearSource;=0D + PchSmmClearSource (&Record->SrcDesc);=0D + PchSmmEnableSource (&Record->SrcDesc);=0D + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EF= I_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NUL= L, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +//=0D +// OsTco srcdesc=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescOsTco =3D = {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_EN}=0D + },=0D + S_ACPI_IO_SMI_EN,=0D + N_ACPI_IO_SMI_EN_TCO=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + TCO_ADDR_TYPE,=0D + {R_TCO_IO_TCO1_STS}=0D + },=0D + S_TCO_IO_TCO1_STS,=0D + N_TCO_IO_TCO1_STS_SW_TCO_SMI=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_TCO=0D + }=0D +};=0D +=0D +/**=0D + The register function used to register SMI handler of OS TCO event.=0D +=0D + @param[in] This The pointer to the protocol itself= =0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchTcoSmiOsTcoRegister (=0D + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + DATABASE_RECORD *Record;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D PchSmiRecordInsert (=0D + &mSrcDescOsTco,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchTcoSmiOsTcoType,=0D + DispatchHandle=0D + );=0D + if (!EFI_ERROR (Status)) {=0D + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle);=0D + Record->ClearSource =3D PchTcoSmiClearSource;=0D + PchSmmClearSource (&Record->SrcDesc);=0D + PchSmmEnableSource (&Record->SrcDesc);=0D + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EF= I_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NUL= L, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +//=0D +// Nmi=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescNmi =3D {= =0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + TCO_ADDR_TYPE,=0D + {R_TCO_IO_TCO1_CNT}=0D + },=0D + S_TCO_IO_TCO1_CNT,=0D + N_TCO_IO_TCO1_CNT_NMI2SMI_EN=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + TCO_ADDR_TYPE,=0D + {R_TCO_IO_TCO1_STS}=0D + },=0D + S_TCO_IO_TCO1_STS,=0D + N_TCO_IO_TCO1_STS_NMI2SMI=0D + }=0D + },=0D + //=0D + // NOTE: The status of NMI2SMI won't reflect to PMC SMI_STS.=0D + // So skip the top level status check and check the TCO1_STS direc= tly.=0D + //=0D + NULL_BIT_DESC_INITIALIZER=0D +};=0D +=0D +/**=0D + The register function used to register SMI handler of NMI event.=0D +=0D + @param[in] This The pointer to the protocol itself= =0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchTcoSmiNmiRegister (=0D + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + DATABASE_RECORD *Record;=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D PchSmiRecordInsert (=0D + &mSrcDescNmi,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchTcoSmiNmiType,=0D + DispatchHandle=0D + );=0D + if (!EFI_ERROR (Status)) {=0D + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle);=0D + Record->ClearSource =3D PchTcoSmiClearSource;=0D + PchSmmClearSource (&Record->SrcDesc);=0D + PchSmmEnableSource (&Record->SrcDesc);=0D + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EF= I_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NUL= L, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +//=0D +// IntruderDetect srcdesc=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescIntruderDe= t =3D {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_EN}=0D + },=0D + S_ACPI_IO_SMI_EN,=0D + N_ACPI_IO_SMI_EN_TCO=0D + },=0D + {=0D + {=0D + TCO_ADDR_TYPE,=0D + {R_TCO_IO_TCO2_CNT}=0D + },=0D + S_TCO_IO_TCO2_CNT,=0D + N_TCO_IO_TCO2_CNT_INTRD_SEL=0D + }=0D + },=0D + {=0D + {=0D + {=0D + TCO_ADDR_TYPE,=0D + {R_TCO_IO_TCO2_STS}=0D + },=0D + S_TCO_IO_TCO2_STS,=0D + N_TCO_IO_TCO2_STS_INTRD_DET=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_TCO=0D + }=0D +};=0D +=0D +/**=0D + The register function used to register SMI handler of Intruder Detect ev= ent.=0D +=0D + @param[in] This The pointer to the protocol itself= =0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchTcoSmiIntruderDetRegister (=0D + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + DATABASE_RECORD *Record;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D PchSmiRecordInsert (=0D + &mSrcDescIntruderDet,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchTcoSmiIntruderDetectType,=0D + DispatchHandle=0D + );=0D + if (!EFI_ERROR (Status)) {=0D + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle);=0D + Record->ClearSource =3D PchTcoSmiClearSourceAndBlock;=0D + PchSmmClearSource (&Record->SrcDesc);=0D + PchSmmEnableSource (&Record->SrcDesc);=0D + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EF= I_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NUL= L, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +//=0D +// SpiBiosWp srcdesc=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescSpiBiosWp = =3D {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_EN}=0D + },=0D + S_ACPI_IO_SMI_EN,=0D + N_ACPI_IO_SMI_EN_TCO=0D + },=0D + {=0D + {=0D + PCIE_ADDR_TYPE,=0D + { (=0D + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |=0D + (PCI_DEVICE_NUMBER_PCH_SPI << 19) |=0D + (PCI_FUNCTION_NUMBER_PCH_SPI << 16) |=0D + R_SPI_CFG_BC=0D + ) }=0D + },=0D + S_SPI_CFG_BC,=0D + N_SPI_CFG_BC_BLE=0D + },=0D + },=0D + {=0D + {=0D + {=0D + PCIE_ADDR_TYPE,=0D + { (=0D + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |=0D + (PCI_DEVICE_NUMBER_PCH_SPI << 19) |=0D + (PCI_FUNCTION_NUMBER_PCH_SPI << 16) |=0D + R_SPI_CFG_BC=0D + ) }=0D + },=0D + S_SPI_CFG_BC,=0D + N_SPI_CFG_BC_SYNC_SS=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_TCO=0D + }=0D +};=0D +=0D +/**=0D + Special handling for SPI Write Protect=0D +=0D + @param[in] SrcDesc Not used=0D +**/=0D +VOID=0D +EFIAPI=0D +PchTcoSpiWpClearSource (=0D + CONST PCH_SMM_SOURCE_DESC *SrcDesc=0D + )=0D +{=0D + UINT64 SpiRegBase;=0D + UINT32 BiosControl;=0D + UINT32 Timeout;=0D +=0D + SpiRegBase =3D SpiPciCfgBase ();=0D + PciSegmentAndThenOr32 (=0D + SpiRegBase + R_SPI_CFG_BC,=0D + (UINT32) ~B_SPI_CFG_BC_ASYNC_SS,=0D + B_SPI_CFG_BC_SYNC_SS=0D + );=0D + //=0D + // Ensure the SYNC is cleared=0D + //=0D + Timeout =3D 1000;=0D + do {=0D + BiosControl =3D PciSegmentRead32 (SpiRegBase + R_SPI_CFG_BC);=0D + Timeout--;=0D + } while ((BiosControl & B_SPI_CFG_BC_SYNC_SS) && (Timeout > 0));=0D +=0D + //=0D + // Any TCO-based status bits require special handling.=0D + // SMI_STS.TCO_STS must be cleared in addition to the status bit in the = TCO registers=0D + //=0D + PchSmmClearSource (&mDescSrcTcoSts);=0D +}=0D +=0D +/**=0D + Set SMI_EN_TCO to enable TCO SMI.=0D +**/=0D +STATIC=0D +VOID=0D +PchSetSmiEnTco (=0D + VOID=0D + )=0D +{=0D + IoOr32 (mAcpiBaseAddr + R_ACPI_IO_SMI_EN, B_ACPI_IO_SMI_EN_TCO);=0D +}=0D +=0D +/**=0D + The register function used to register SMI handler of BIOS write protect= event.=0D +=0D + @param[in] This The pointer to the protocol itself= =0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchTcoSmiSpiBiosWpRegister (=0D + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + DATABASE_RECORD *Record;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D PchSmiRecordInsert (=0D + &mSrcDescSpiBiosWp,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchTcoSmiSpiBiosWpType,=0D + DispatchHandle=0D + );=0D + if (!EFI_ERROR (Status)) {=0D + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle);=0D + Record->ClearSource =3D PchTcoSpiWpClearSource;=0D + PchTcoSpiWpClearSource (NULL);=0D + //=0D + // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE.=0D + // Only enable SMI_EN_TCO.=0D + //=0D + PchSetSmiEnTco ();=0D + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EF= I_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NUL= L, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +//=0D +// LpcBiosWp srcdesc=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescLpcBiosWp = =3D {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_EN}=0D + },=0D + S_ACPI_IO_SMI_EN,=0D + N_ACPI_IO_SMI_EN_TCO=0D + },=0D + {=0D + {=0D + PCIE_ADDR_TYPE,=0D + { (=0D + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |=0D + (PCI_DEVICE_NUMBER_PCH_LPC << 19) |=0D + (PCI_FUNCTION_NUMBER_PCH_LPC << 16) |=0D + R_LPC_CFG_BC=0D + ) }=0D + },=0D + S_LPC_CFG_BC,=0D + N_LPC_CFG_BC_LE=0D + }=0D + },=0D + {=0D + {=0D + {=0D + TCO_ADDR_TYPE,=0D + {R_TCO_IO_TCO1_STS}=0D + },=0D + S_TCO_IO_TCO1_STS,=0D + N_TCO_IO_TCO1_STS_BIOSWR=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_TCO=0D + }=0D +};=0D +=0D +/**=0D + The register function used to register SMI handler of LPC BIOS write pro= tect event.=0D +=0D + @param[in] This The pointer to the protocol itself= =0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchTcoSmiLpcBiosWpRegister (=0D + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + DATABASE_RECORD *Record;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + if (IsEspiEnabled ()) {=0D + //=0D + // Status is D31F0's PCBC.BWPDS=0D + //=0D + ASSERT (FALSE);=0D + return EFI_UNSUPPORTED;=0D + }=0D +=0D + Status =3D PchSmiRecordInsert (=0D + &mSrcDescLpcBiosWp,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchTcoSmiLpcBiosWpType,=0D + DispatchHandle=0D + );=0D + if (!EFI_ERROR (Status)) {=0D + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle);=0D + Record->ClearSource =3D PchTcoSmiClearSource;=0D + PchSmmClearSource (&Record->SrcDesc);=0D + //=0D + // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE.=0D + // Only enable SMI_EN_TCO.=0D + //=0D + PchSetSmiEnTco ();=0D + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EF= I_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NUL= L, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +//=0D +// NEWCENTURY_STS bit that needs to be cleared=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescNewCentury= =3D {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_EN}=0D + },=0D + S_ACPI_IO_SMI_EN,=0D + N_ACPI_IO_SMI_EN_TCO=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + TCO_ADDR_TYPE,=0D + {R_TCO_IO_TCO1_STS}=0D + },=0D + S_TCO_IO_TCO1_STS,=0D + N_TCO_IO_TCO1_STS_NEWCENTURY=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_TCO=0D + }=0D +};=0D +=0D +/**=0D + The register function used to register SMI handler of NEW CENTURY event.= =0D +=0D + @param[in] This The pointer to the protocol itself= =0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchTcoSmiNewCenturyRegister (=0D + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + DATABASE_RECORD *Record;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D PchSmiRecordInsert (=0D + &mSrcDescNewCentury,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchTcoSmiNewCenturyType,=0D + DispatchHandle=0D + );=0D + if (!EFI_ERROR (Status)) {=0D + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle);=0D + Record->ClearSource =3D PchTcoSmiClearSourceAndBlock;=0D + PchSmmClearSource (&Record->SrcDesc);=0D + PchSmmEnableSource (&Record->SrcDesc);=0D + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EF= I_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NUL= L, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +/**=0D + Unregister a child SMI source dispatch function with a parent SMM driver= =0D +=0D + @param[in] This Protocol instance pointer.=0D + @param[in] DispatchHandle Handle of dispatch function to der= egister.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been suc= cessfully=0D + unregistered and the SMI source ha= s been disabled=0D + if there are no other registered c= hild dispatch=0D + functions for this SMI source.=0D + @retval EFI_INVALID_PARAMETER Handle is invalid.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchTcoSmiUnRegister (=0D + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This,=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + DATABASE_RECORD *Record;=0D + EFI_STATUS Status;=0D +=0D + Record =3D DATABASE_RECORD_FROM_LINK (DispatchHandle);=0D + if ((Record->SrcDesc.En[1].Reg.Type =3D=3D ACPI_ADDR_TYPE) &&=0D + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Dev =3D=3D SpiDevNumber = ()) &&=0D + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Fnc =3D=3D SpiFuncNumber= ()) &&=0D + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Reg =3D=3D R_SPI_CFG_BC)= &&=0D + (Record->SrcDesc.En[1].Bit =3D=3D N_SPI_CFG_BC_BLE)) {=0D + //=0D + // SPI Write Protect cannot be disabled=0D + //=0D + return EFI_ACCESS_DENIED;=0D + } else if ((Record->SrcDesc.En[1].Reg.Type =3D=3D ACPI_ADDR_TYPE) &&=0D + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Dev =3D=3D LpcDev= Number ()) &&=0D + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Fnc =3D=3D LpcFun= cNumber ()) &&=0D + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Reg =3D=3D R_LPC_= CFG_BC) &&=0D + (Record->SrcDesc.En[1].Bit =3D=3D N_LPC_CFG_BC_LE)) {=0D + //=0D + // eSPI/LPC Write Protect cannot be disabled=0D + //=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D PchSmmCoreUnRegister (NULL, DispatchHandle);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileUnregisterHandler (&gPchTcoSmiDispatchProtocolGuid, R= ecord->Callback, NULL, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +=0D +//=0D +// PcieRpHotPlug srcdesc=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC PchPcieSmiRpHotPlugTempl= ate =3D {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + PCIE_ADDR_TYPE,=0D + {R_PCH_PCIE_CFG_MPC}=0D + },=0D + S_PCH_PCIE_CFG_MPC,=0D + N_PCH_PCIE_CFG_MPC_HPME=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + PCIE_ADDR_TYPE,=0D + {R_PCH_PCIE_CFG_SMSCS}=0D + },=0D + S_PCH_PCIE_CFG_SMSCS,=0D + N_PCH_PCIE_CFG_SMSCS_HPPDM=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_PCI_EXP=0D + }=0D +};=0D +=0D +/**=0D + The register function used to register SMI handler of PCIE RP hotplug ev= ent.=0D +=0D + @param[in] This The pointer to the protocol itself= =0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[in] RpIndex Refer PCIE_COMBINED_RPINDEX for PC= H RP index and CPU RP index.=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchPcieSmiHotPlugRegister (=0D + IN PCH_PCIE_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction,=0D + IN UINTN RpIndex,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINTN RpDev;=0D + UINTN RpFun;=0D + PCH_SMM_PCIE_REGISTER_CONTEXT Context;=0D + DATABASE_RECORD *Record;=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D + GetPcieRpDevFun (RpIndex, &RpDev, &RpFun);=0D +=0D + PchPcieSmiRpHotPlugTemplate.En[0].Reg.Data.pcie.Fields.Dev =3D (UINT8) R= pDev;=0D + PchPcieSmiRpHotPlugTemplate.En[0].Reg.Data.pcie.Fields.Fnc =3D (UINT8) R= pFun;=0D + PchPcieSmiRpHotPlugTemplate.Sts[0].Reg.Data.pcie.Fields.Dev =3D (UINT8) = RpDev;=0D + PchPcieSmiRpHotPlugTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc =3D (UINT8) = RpFun;=0D +=0D + Status =3D PchSmiRecordInsert (=0D + &PchPcieSmiRpHotPlugTemplate,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchPcieSmiRpHotplugType,=0D + DispatchHandle=0D + );=0D + if (!EFI_ERROR (Status)) {=0D + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle);=0D + Record->ChildContext.Pcie.PchSmiType =3D PchPcieSmiRpHotplugType;=0D + Record->ChildContext.Pcie.RpIndex =3D RpIndex;=0D + Record->ContextSize =3D sizeof (PCH_SMM_PCIE_REGISTER_CONTEXT);=0D + SmiHandlerProfileRegisterHandler (=0D + &gPchPcieSmiDispatchProtocolGuid,=0D + (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,=0D + (UINTN)RETURN_ADDRESS (0),=0D + &Context,=0D + sizeof (Context)=0D + );=0D + }=0D + PchSmmClearSource (&PchPcieSmiRpHotPlugTemplate);=0D + PchSmmEnableSource (&PchPcieSmiRpHotPlugTemplate);=0D +=0D + return Status;=0D +}=0D +=0D +//=0D +// PcieRpLinkActive srcdesc=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC PchPcieSmiRpLinkActiveTe= mplate =3D {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + PCIE_ADDR_TYPE,=0D + {R_PCH_PCIE_CFG_MPC}=0D + },=0D + S_PCH_PCIE_CFG_MPC,=0D + N_PCH_PCIE_CFG_MPC_HPME=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + PCIE_ADDR_TYPE,=0D + {R_PCH_PCIE_CFG_SMSCS}=0D + },=0D + S_PCH_PCIE_CFG_SMSCS,=0D + N_PCH_PCIE_CFG_SMSCS_HPLAS=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_PCI_EXP=0D + }=0D +};=0D +=0D +/**=0D + The register function used to register SMI handler of PCIE RP link activ= e event.=0D +=0D + @param[in] This The pointer to the protocol itself= =0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[in] RpIndex Refer PCIE_COMBINED_RPINDEX for PC= H RP index and CPU RP index.=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchPcieSmiLinkActiveRegister (=0D + IN PCH_PCIE_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction,=0D + IN UINTN RpIndex,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINTN RpDev;=0D + UINTN RpFun;=0D + PCH_SMM_PCIE_REGISTER_CONTEXT Context;=0D + DATABASE_RECORD *Record;=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + GetPcieRpDevFun (RpIndex, &RpDev, &RpFun);=0D +=0D +=0D + PchPcieSmiRpLinkActiveTemplate.En[0].Reg.Data.pcie.Fields.Dev =3D (UINT8= ) RpDev;=0D + PchPcieSmiRpLinkActiveTemplate.En[0].Reg.Data.pcie.Fields.Fnc =3D (UINT8= ) RpFun;=0D + PchPcieSmiRpLinkActiveTemplate.Sts[0].Reg.Data.pcie.Fields.Dev =3D (UINT= 8) RpDev;=0D + PchPcieSmiRpLinkActiveTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc =3D (UINT= 8) RpFun;=0D +=0D + Status =3D PchSmiRecordInsert (=0D + &PchPcieSmiRpLinkActiveTemplate,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchPcieSmiRpLinkActiveType,=0D + DispatchHandle=0D + );=0D + if (!EFI_ERROR (Status)) {=0D + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle);=0D + Record->ChildContext.Pcie.PchSmiType =3D PchPcieSmiRpLinkActiveType;=0D + Record->ChildContext.Pcie.RpIndex =3D RpIndex;=0D + Record->ContextSize =3D sizeof (PCH_SMM_PCIE_REGISTER_CONTEXT);=0D + SmiHandlerProfileRegisterHandler (=0D + &gPchPcieSmiDispatchProtocolGuid,=0D + (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,=0D + (UINTN)RETURN_ADDRESS (0),=0D + &Context,=0D + sizeof (Context)=0D + );=0D + }=0D + PchSmmClearSource (&PchPcieSmiRpLinkActiveTemplate);=0D + PchSmmEnableSource (&PchPcieSmiRpLinkActiveTemplate);=0D +=0D + return Status;=0D +}=0D +=0D +//=0D +// PcieRpLinkEq srcdesc=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC PchPcieSmiRpLinkEqTempla= te =3D {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + PCIE_ADDR_TYPE,=0D + {R_PCH_PCIE_CFG_EQCFG1}=0D + },=0D + S_PCH_PCIE_CFG_EQCFG1,=0D + N_PCH_PCIE_CFG_EQCFG1_LERSMIE=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + PCIE_ADDR_TYPE,=0D + {R_PCH_PCIE_CFG_SMSCS}=0D + },=0D + S_PCH_PCIE_CFG_SMSCS,=0D + N_PCH_PCIE_CFG_SMSCS_LERSMIS=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_PCI_EXP=0D + }=0D +};=0D +/**=0D + The register function used to register SMI handler of PCIE RP Link Equal= ization Request event.=0D +=0D + @param[in] This The pointer to the protocol itself= =0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[in] RpIndex Refer PCIE_COMBINED_RPINDEX for PC= H RP index and CPU RP index.=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchPcieSmiLinkEqRegister (=0D + IN PCH_PCIE_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction,=0D + IN UINTN RpIndex,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + UINTN RpDev;=0D + UINTN RpFun;=0D + EFI_STATUS Status;=0D + PCH_SMM_PCIE_REGISTER_CONTEXT Context;=0D + DATABASE_RECORD *Record;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + GetPcieRpDevFun (RpIndex, &RpDev, &RpFun);=0D +=0D + //=0D + // Patch the RP device number and function number of srcdesc.=0D + //=0D + PchPcieSmiRpLinkEqTemplate.En[0].Reg.Data.pcie.Fields.Dev =3D (UINT8) Rp= Dev;=0D + PchPcieSmiRpLinkEqTemplate.En[0].Reg.Data.pcie.Fields.Fnc =3D (UINT8) Rp= Fun;=0D + PchPcieSmiRpLinkEqTemplate.Sts[0].Reg.Data.pcie.Fields.Dev =3D (UINT8) R= pDev;=0D + PchPcieSmiRpLinkEqTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc =3D (UINT8) R= pFun;=0D +=0D + Status =3D PchSmiRecordInsert (=0D + &PchPcieSmiRpLinkEqTemplate,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchPcieSmiRpLinkEqType,=0D + DispatchHandle=0D + );=0D + if (!EFI_ERROR (Status)) {=0D + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle);=0D + Record->ChildContext.Pcie.PchSmiType =3D PchPcieSmiRpLinkEqType;=0D + Record->ChildContext.Pcie.RpIndex =3D RpIndex;=0D + Record->ContextSize =3D sizeof (PCH_SMM_PCIE_REGISTER_CONTEXT);=0D + SmiHandlerProfileRegisterHandler (=0D + &gPchPcieSmiDispatchProtocolGuid,=0D + (EFI_SMM_HANDLER_ENTRY_POINT2) DispatchFunction,=0D + (UINTN)RETURN_ADDRESS (0),=0D + &Context,=0D + sizeof (Context)=0D + );=0D + }=0D + return Status;=0D +}=0D +=0D +/**=0D + Unregister a child SMI source dispatch function with a parent SMM driver= =0D +=0D + @param[in] This Protocol instance pointer.=0D + @param[in] DispatchHandle Handle of dispatch function to der= egister.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been suc= cessfully=0D + unregistered and the SMI source ha= s been disabled=0D + if there are no other registered c= hild dispatch=0D + functions for this SMI source.=0D + @retval EFI_INVALID_PARAMETER Handle is invalid.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchPcieSmiUnRegister (=0D + IN PCH_PCIE_SMI_DISPATCH_PROTOCOL *This,=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + DATABASE_RECORD *RecordToDelete;=0D + EFI_STATUS Status;=0D +=0D + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle);=0D + Status =3D PchSmmCoreUnRegister (NULL, DispatchHandle);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileUnregisterHandler (=0D + &gPchPcieSmiDispatchProtocolGuid,=0D + RecordToDelete->Callback,=0D + &RecordToDelete->ChildContext,=0D + sizeof (RecordToDelete->ContextSize)=0D + );=0D + }=0D + return Status;=0D +}=0D +=0D +//=0D +// Pme srcdesc=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescPme =3D {= =0D + PCH_SMM_SCI_EN_DEPENDENT,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_GPE0_EN_127_96}=0D + },=0D + S_ACPI_IO_GPE0_EN_127_96,=0D + N_ACPI_IO_GPE0_EN_127_96_PME=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_GPE0_STS_127_96}=0D + },=0D + S_ACPI_IO_GPE0_STS_127_96,=0D + N_ACPI_IO_GPE0_STS_127_96_PME=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_GPE0=0D + }=0D +};=0D +=0D +/**=0D + The register function used to register SMI handler of PME event.=0D +=0D + @param[in] This The pointer to the protocol itself= =0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchAcpiSmiPmeRegister (=0D + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D PchSmiRecordInsert (=0D + &mSrcDescPme,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchAcpiSmiPmeType,=0D + DispatchHandle=0D + );=0D + PchSmmClearSource (&mSrcDescPme);=0D + PchSmmEnableSource (&mSrcDescPme);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (E= FI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NU= LL, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +//=0D +// PmeB0 srcdesc=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescPmeB0 =3D = {=0D + PCH_SMM_SCI_EN_DEPENDENT,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_GPE0_EN_127_96}=0D + },=0D + S_ACPI_IO_GPE0_EN_127_96,=0D + N_ACPI_IO_GPE0_EN_127_96_PME_B0=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_GPE0_STS_127_96}=0D + },=0D + S_ACPI_IO_GPE0_STS_127_96,=0D + N_ACPI_IO_GPE0_STS_127_96_PME_B0=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_GPE0=0D + }=0D +};=0D +/**=0D + The register function used to register SMI handler of PME B0 event.=0D +=0D + @param[in] This The pointer to the protocol itself= =0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchAcpiSmiPmeB0Register (=0D + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D PchSmiRecordInsert (=0D + &mSrcDescPmeB0,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchAcpiSmiPmeB0Type,=0D + DispatchHandle=0D + );=0D + PchSmmClearSource (&mSrcDescPmeB0);=0D + PchSmmEnableSource (&mSrcDescPmeB0);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (E= FI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NU= LL, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +//=0D +// RtcAlarm srcdesc=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescRtcAlarm = =3D {=0D + PCH_SMM_SCI_EN_DEPENDENT,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_PM1_EN}=0D + },=0D + S_ACPI_IO_PM1_EN,=0D + N_ACPI_IO_PM1_EN_RTC=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_PM1_STS}=0D + },=0D + S_ACPI_IO_PM1_STS,=0D + N_ACPI_IO_PM1_STS_RTC=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_PM1_STS_REG=0D + }=0D +};=0D +=0D +/**=0D + The register function used to register SMI handler of RTC alarm event.=0D +=0D + @param[in] This The pointer to the protocol itself= =0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchAcpiSmiRtcAlarmRegister (=0D + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D PchSmiRecordInsert (=0D + &mSrcDescRtcAlarm,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchAcpiSmiRtcAlarmType,=0D + DispatchHandle=0D + );=0D +=0D + PchSmmClearSource (&mSrcDescRtcAlarm);=0D + PchSmmEnableSource (&mSrcDescRtcAlarm);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (E= FI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NU= LL, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +//=0D +// TmrOverflow srcdesc=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescTmrOverflo= w =3D {=0D + PCH_SMM_SCI_EN_DEPENDENT,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_PM1_EN}=0D + },=0D + S_ACPI_IO_PM1_EN,=0D + N_ACPI_IO_PM1_EN_TMROF=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_PM1_STS}=0D + },=0D + S_ACPI_IO_PM1_STS,=0D + N_ACPI_IO_PM1_STS_TMROF=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_PM1_STS_REG=0D + }=0D +};=0D +=0D +/**=0D + The register function used to register SMI handler of Timer Overflow eve= nt.=0D +=0D + @param[in] This The pointer to the protocol itself= =0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchAcpiSmiTmrOverflowRegister (=0D + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D PchSmiRecordInsert (=0D + &mSrcDescTmrOverflow,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchAcpiSmiTmrOverflowType,=0D + DispatchHandle=0D + );=0D + PchSmmClearSource (&mSrcDescTmrOverflow);=0D + PchSmmEnableSource (&mSrcDescTmrOverflow);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (E= FI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NU= LL, 0);=0D + }=0D +=0D + return Status;=0D +}=0D +=0D +/**=0D + Unregister a child SMI source dispatch function with a parent SMM driver= =0D +=0D + @param[in] This Protocol instance pointer.=0D + @param[in] DispatchHandle Handle of dispatch function to der= egister.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been suc= cessfully=0D + unregistered and the SMI source ha= s been disabled=0D + if there are no other registered c= hild dispatch=0D + functions for this SMI source.=0D + @retval EFI_INVALID_PARAMETER Handle is invalid.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchAcpiSmiUnRegister (=0D + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + DATABASE_RECORD *RecordToDelete;=0D + EFI_STATUS Status;=0D +=0D + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle);=0D + Status =3D PchSmmCoreUnRegister (NULL, DispatchHandle);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileUnregisterHandler (&gPchAcpiSmiDispatchProtocolGuid, = RecordToDelete->Callback, NULL, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +//=0D +// SerialIrq srcdesc=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescSerialIrq = =3D {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + NULL_BIT_DESC_INITIALIZER,=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_SERIRQ=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_SERIRQ=0D + }=0D +};=0D +=0D +/**=0D + The register function used to register SMI handler of Serial IRQ event.= =0D +=0D + @param[in] This The pointer to the protocol itself= =0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchSmiSerialIrqRegister (=0D + IN PCH_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D PchSmiRecordInsert (=0D + &mSrcDescSerialIrq,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchSmiSerialIrqType,=0D + DispatchHandle=0D + );=0D + PchSmmClearSource (&mSrcDescSerialIrq);=0D + PchSmmEnableSource (&mSrcDescSerialIrq);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_= SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL,= 0);=0D + }=0D + return Status;=0D +}=0D +=0D +//=0D +// McSmi srcdesc=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescMcSmi =3D = {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_EN}=0D + },=0D + S_ACPI_IO_SMI_EN,=0D + N_ACPI_IO_SMI_EN_MCSMI=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_MCSMI=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_MCSMI=0D + }=0D +};=0D +=0D +/**=0D + The register function used to register SMI handler of MCSMI event.=0D +=0D + @param[in] This The pointer to the protocol itself= =0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchSmiMcSmiRegister (=0D + IN PCH_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D PchSmiRecordInsert (=0D + &mSrcDescMcSmi,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchSmiMcSmiType,=0D + DispatchHandle=0D + );=0D + PchSmmClearSource (&mSrcDescMcSmi);=0D + PchSmmEnableSource (&mSrcDescMcSmi);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_S= MM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, = 0);=0D + }=0D + return Status;=0D +}=0D +=0D +//=0D +// SmBus srcdesc=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescSmbus =3D = {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + NULL_BIT_DESC_INITIALIZER,=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_SMBUS=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_SMBUS=0D + }=0D +};=0D +=0D +/**=0D + The register function used to register SMI handler of SMBUS event.=0D +=0D + @param[in] This The pointer to the protocol itself= =0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchSmiSmbusRegister (=0D + IN PCH_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D PchSmiRecordInsert (=0D + &mSrcDescSmbus,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchSmiSmBusType,=0D + DispatchHandle=0D + );=0D + PchSmmClearSource (&mSrcDescSmbus);=0D + PchSmmEnableSource (&mSrcDescSmbus);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_S= MM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, = 0);=0D + }=0D + return Status;=0D +}=0D +=0D +//=0D +// SpiAsyncSmi srcdesc=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescSpiAsyncSm= i =3D {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + PCIE_ADDR_TYPE,=0D + { (=0D + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |=0D + (PCI_DEVICE_NUMBER_PCH_SPI << 19) |=0D + (PCI_FUNCTION_NUMBER_PCH_SPI << 16) |=0D + R_SPI_CFG_BC=0D + ) }=0D + },=0D + S_SPI_CFG_BC,=0D + N_SPI_CFG_BC_ASE_BWP=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + PCIE_ADDR_TYPE,=0D + { (=0D + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |=0D + (PCI_DEVICE_NUMBER_PCH_SPI << 19) |=0D + (PCI_FUNCTION_NUMBER_PCH_SPI << 16) |=0D + R_SPI_CFG_BC=0D + ) }=0D + },=0D + S_SPI_CFG_BC,=0D + N_SPI_CFG_BC_ASYNC_SS=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_SPI=0D + }=0D +};=0D +=0D +/**=0D + Special handling for SPI Asynchronous SMI.=0D + If SPI ASYNC SMI is enabled, De-assert SMI is sent when Flash Cycle Done= =0D + transitions from 1 to 0 or when the SMI enable becomes false.=0D +=0D + @param[in] SrcDesc Not used=0D +**/=0D +VOID=0D +EFIAPI=0D +PchSmiSpiAsyncClearSource (=0D + CONST PCH_SMM_SOURCE_DESC *SrcDesc=0D + )=0D +{=0D + UINT64 SpiRegBase;=0D + UINT32 SpiBar0;=0D +=0D + SpiRegBase =3D SpiPciCfgBase ();=0D + SpiBar0 =3D PciSegmentRead32 (SpiRegBase + R_SPI_CFG_BAR0) & ~(B_SPI_CFG= _BAR0_MASK);=0D + if (SpiBar0 !=3D PCH_SPI_BASE_ADDRESS) {=0D + //=0D + // Temporary disable MSE, and override with SPI reserved MMIO address,= then enable MSE.=0D + //=0D + SpiBar0 =3D PCH_SPI_BASE_ADDRESS;=0D + PciSegmentAnd8 (SpiRegBase + PCI_COMMAND_OFFSET, (UINT8) ~EFI_PCI_COMM= AND_MEMORY_SPACE);=0D + PciSegmentWrite32 (SpiRegBase + R_SPI_CFG_BAR0, SpiBar0);=0D + PciSegmentOr8 (SpiRegBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY= _SPACE);=0D + }=0D +=0D + MmioOr32 (SpiBar0 + R_SPI_MEM_HSFSC, B_SPI_MEM_HSFSC_FDONE);=0D +}=0D +=0D +/**=0D + Special handling to enable SPI Asynchronous SMI=0D +**/=0D +VOID=0D +PchSmiSpiAsyncEnableSource (=0D + VOID=0D + )=0D +{=0D + UINT64 SpiRegBase;=0D + UINT32 Data32And;=0D + UINT32 Data32Or;=0D +=0D + SpiRegBase =3D SpiPciCfgBase ();=0D + Data32And =3D (UINT32) ~B_SPI_CFG_BC_SYNC_SS;=0D + Data32Or =3D B_SPI_CFG_BC_ASE_BWP;=0D +=0D + PciSegmentAndThenOr32 (=0D + SpiRegBase + R_SPI_CFG_BC,=0D + Data32And,=0D + Data32Or=0D + );=0D + S3BootScriptSavePciCfgReadWrite (=0D + S3BootScriptWidthUint32,=0D + SpiRegBase + R_SPI_CFG_BC,=0D + (VOID*) &Data32Or,=0D + (VOID*) &Data32And=0D + );=0D +=0D + //=0D + // Clear the source=0D + //=0D + PchSmiSpiAsyncClearSource (NULL);=0D +}=0D +=0D +/**=0D + The register function used to register SMI handler of SPI Asynchronous e= vent.=0D +=0D + @param[in] This The pointer to the protocol itself= =0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchSmiSpiAsyncRegister (=0D + IN PCH_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + DATABASE_RECORD *Record;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D PchSmiRecordInsert (=0D + &mSrcDescSpiAsyncSmi,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchSmiSpiAsyncType,=0D + DispatchHandle=0D + );=0D +=0D + if (!EFI_ERROR (Status)) {=0D + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle);=0D + Record->ClearSource =3D PchSmiSpiAsyncClearSource;=0D + PchSmiSpiAsyncClearSource (NULL);=0D + PchSmiSpiAsyncEnableSource ();=0D + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_S= MM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, = 0);=0D + }=0D + return Status;=0D +}=0D +=0D +/**=0D + Unregister a child SMI source dispatch function with a parent SMM driver= =0D +=0D + @param[in] This Protocol instance pointer.=0D + @param[in] DispatchHandle Handle of dispatch function to der= egister.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been suc= cessfully=0D + unregistered and the SMI source ha= s been disabled=0D + if there are no other registered c= hild dispatch=0D + functions for this SMI source.=0D + @retval EFI_INVALID_PARAMETER Handle is invalid.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D + @retval EFI_ACCESS_DENIED Return access denied since SPI ayn= c SMI handler is not able to disabled.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchSmiUnRegister (=0D + IN PCH_SMI_DISPATCH_PROTOCOL *This,=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + DATABASE_RECORD *Record;=0D + UINT64 SpiRegBase;=0D + EFI_STATUS Status;=0D +=0D + Record =3D DATABASE_RECORD_FROM_LINK (DispatchHandle);=0D + if ((Record->SrcDesc.En[0].Reg.Type =3D=3D PCIE_ADDR_TYPE) &&=0D + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Dev =3D=3D SpiDevNumber = ()) &&=0D + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Fnc =3D=3D SpiFuncNumber= ()) &&=0D + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Reg =3D=3D R_SPI_CFG_BC)= &&=0D + (Record->SrcDesc.En[0].Bit =3D=3D N_SPI_CFG_BC_ASE_BWP)) {=0D + SpiRegBase =3D SpiPciCfgBase ();=0D + if (PciSegmentRead8 (SpiRegBase + R_SPI_CFG_BC) & B_SPI_CFG_BC_BILD) {= =0D + //=0D + // SPI Asynchronous SMI cannot be disabled=0D + //=0D + return EFI_ACCESS_DENIED;=0D + }=0D + }=0D + Status =3D PchSmmCoreUnRegister (NULL, DispatchHandle);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileUnregisterHandler (&gPchSmiDispatchProtocolGuid, Reco= rd->Callback, NULL, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +=0D +/**=0D + Declaration of PCH TCO SMI DISPATCH PROTOCOL instance=0D +**/=0D +PCH_TCO_SMI_DISPATCH_PROTOCOL mPchTcoSmiDispatchProtocol =3D {=0D + PCH_TCO_SMI_DISPATCH_REVISION, // Revision=0D + PchTcoSmiUnRegister, // Unregister=0D + PchTcoSmiMchRegister, // Mch=0D + PchTcoSmiTcoTimeoutRegister, // TcoTimeout=0D + PchTcoSmiOsTcoRegister, // OsTco=0D + PchTcoSmiNmiRegister, // Nmi=0D + PchTcoSmiIntruderDetRegister, // IntruderDectect=0D + PchTcoSmiSpiBiosWpRegister, // SpiBiosWp=0D + PchTcoSmiLpcBiosWpRegister, // LpcBiosWp=0D + PchTcoSmiNewCenturyRegister // NewCentury=0D +};=0D +=0D +/**=0D + Declaration of PCH PCIE SMI DISPATCH PROTOCOL instance=0D +**/=0D +PCH_PCIE_SMI_DISPATCH_PROTOCOL mPchPcieSmiDispatchProtocol =3D {=0D + PCH_PCIE_SMI_DISPATCH_REVISION, // Revision=0D + PchPcieSmiUnRegister, // Unregister=0D + PchPcieSmiHotPlugRegister, // PcieRpXHotPlug=0D + PchPcieSmiLinkActiveRegister, // PcieRpXLinkActive=0D + PchPcieSmiLinkEqRegister // PcieRpXLinkEq=0D +};=0D +=0D +/**=0D + Declaration of PCH ACPI SMI DISPATCH PROTOCOL instance=0D +**/=0D +PCH_ACPI_SMI_DISPATCH_PROTOCOL mPchAcpiSmiDispatchProtocol =3D {=0D + PCH_ACPI_SMI_DISPATCH_REVISION, // Revision=0D + PchAcpiSmiUnRegister, // Unregister=0D + PchAcpiSmiPmeRegister, // Pme=0D + PchAcpiSmiPmeB0Register, // PmeB0=0D + PchAcpiSmiRtcAlarmRegister, // RtcAlarm=0D + PchAcpiSmiTmrOverflowRegister // TmrOverflow=0D +};=0D +=0D +/**=0D + Declaration of MISC PCH SMI DISPATCH PROTOCOL instance=0D +**/=0D +PCH_SMI_DISPATCH_PROTOCOL mPchSmiDispatchProtocol =3D {=0D + PCH_SMI_DISPATCH_REVISION, // Revision=0D + PchSmiUnRegister, // Unregister=0D + PchSmiSerialIrqRegister, // SerialIrq=0D + PchSmiMcSmiRegister, // McSmi=0D + PchSmiSmbusRegister, // SmBus=0D + PchSmiSpiAsyncRegister // SpiAsync=0D +};=0D +=0D +/**=0D + Install protocols of PCH specifics SMI types, including=0D + PCH TCO SMI types, PCH PCIE SMI types, PCH ACPI SMI types, PCH MISC SMI = types.=0D +=0D + @retval the result of protocol installatio= n=0D +**/=0D +EFI_STATUS=0D +InstallPchSmiDispatchProtocols (=0D + VOID=0D + )=0D +{=0D + EFI_HANDLE Handle;=0D + EFI_STATUS Status;=0D +=0D + Handle =3D NULL;=0D + Status =3D gSmst->SmmInstallProtocolInterface (=0D + &Handle,=0D + &gPchTcoSmiDispatchProtocolGuid,=0D + EFI_NATIVE_INTERFACE,=0D + &mPchTcoSmiDispatchProtocol=0D + );=0D + Status =3D gSmst->SmmInstallProtocolInterface (=0D + &Handle,=0D + &gPchPcieSmiDispatchProtocolGuid,=0D + EFI_NATIVE_INTERFACE,=0D + &mPchPcieSmiDispatchProtocol=0D + );=0D + Status =3D gSmst->SmmInstallProtocolInterface (=0D + &Handle,=0D + &gPchAcpiSmiDispatchProtocolGuid,=0D + EFI_NATIVE_INTERFACE,=0D + &mPchAcpiSmiDispatchProtocol=0D + );=0D + Status =3D gSmst->SmmInstallProtocolInterface (=0D + &Handle,=0D + &gPchSmiDispatchProtocolGuid,=0D + EFI_NATIVE_INTERFACE,=0D + &mPchSmiDispatchProtocol=0D + );=0D +=0D + return Status;=0D +}=0D +=0D +/**=0D + The function to dispatch all callback function of PCH SMI types.=0D +=0D + @retval EFI_SUCCESS Function successfully completed=0D + @retval EFI_UNSUPPORTED no=0D +**/=0D +EFI_STATUS=0D +PchSmiTypeCallbackDispatcher (=0D + IN DATABASE_RECORD *Record=0D + )=0D +{=0D + EFI_STATUS Status;=0D + PCH_SMI_TYPES PchSmiType;=0D + UINTN RpIndex;=0D + PCH_PCIE_SMI_RP_CONTEXT RpContext;=0D +=0D + PchSmiType =3D Record->PchSmiType;=0D + Status =3D EFI_SUCCESS;=0D +=0D + switch (PchSmiType) {=0D + case PchTcoSmiMchType:=0D + case PchTcoSmiTcoTimeoutType:=0D + case PchTcoSmiOsTcoType:=0D + case PchTcoSmiNmiType:=0D + case PchTcoSmiIntruderDetectType:=0D + case PchTcoSmiSpiBiosWpType:=0D + case PchTcoSmiLpcBiosWpType:=0D + case PchTcoSmiNewCenturyType:=0D + ((PCH_TCO_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HAN= DLE)&Record->Link);=0D + break;=0D + case PchPcieSmiRpHotplugType:=0D + case PchPcieSmiRpLinkActiveType:=0D + case PchPcieSmiRpLinkEqType:=0D + RpContext.BusNum =3D DEFAULT_PCI_BUS_NUMBER_PCH;=0D + RpContext.DevNum =3D (UINT8) Record->SrcDesc.En[0].Reg.Data.pcie.Fi= elds.Dev;=0D + RpContext.FuncNum =3D (UINT8) Record->SrcDesc.En[0].Reg.Data.pcie.Fi= elds.Fnc;=0D + GetPcieRpNumber (RpContext.DevNum, RpContext.FuncNum, &RpIndex);=0D + RpContext.RpIndex =3D (UINT8) RpIndex;=0D + ((PCH_PCIE_SMI_RP_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI= _HANDLE)&Record->Link, &RpContext);=0D + break;=0D + case PchAcpiSmiPmeType:=0D + case PchAcpiSmiPmeB0Type:=0D + case PchAcpiSmiRtcAlarmType:=0D + case PchAcpiSmiTmrOverflowType:=0D + ((PCH_ACPI_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HA= NDLE)&Record->Link);=0D + break;=0D + case PchEspiSmiEspiSlaveType:=0D + ((PCH_ESPI_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HA= NDLE)&Record->Link);=0D + break;=0D + case PchSmiSerialIrqType:=0D + case PchSmiMcSmiType:=0D + case PchSmiSmBusType:=0D + case PchSmiSpiAsyncType:=0D + case PchIoTrapSmiType: ///< internal type for IoTrap=0D + ((PCH_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HANDLE)= &Record->Link);=0D + break;=0D + default:=0D + Status =3D EFI_UNSUPPORTED;=0D + break;=0D + }=0D +=0D + return Status;=0D +}=0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescIoTrap[4] = =3D {=0D + //=0D + // PCH I/O Trap register 0 monitor=0D + //=0D + {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + PCR_ADDR_TYPE,=0D + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG0) }=0D + },=0D + 4,=0D + 0=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + PCR_ADDR_TYPE,=0D + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) }=0D + },=0D + 1,=0D + 0=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_MONITOR=0D + }=0D + },=0D + //=0D + // PCH I/O Trap register 1 monitor=0D + //=0D + {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + PCR_ADDR_TYPE,=0D + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG1) }=0D + },=0D + 4,=0D + 0=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + PCR_ADDR_TYPE,=0D + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) }=0D + },=0D + 1,=0D + 1=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_MONITOR=0D + }=0D + },=0D + //=0D + // PCH I/O Trap register 2 monitor=0D + //=0D + {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + PCR_ADDR_TYPE,=0D + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG2) }=0D + },=0D + 4,=0D + 0=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + PCR_ADDR_TYPE,=0D + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) }=0D + },=0D + 1,=0D + 2=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_MONITOR=0D + }=0D + },=0D + //=0D + // PCH I/O Trap register 3 monitor,=0D + //=0D + {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + PCR_ADDR_TYPE,=0D + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG3) }=0D + },=0D + 4,=0D + 0=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + PCR_ADDR_TYPE,=0D + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) }=0D + },=0D + 1,=0D + 3=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_MONITOR=0D + }=0D + }=0D +};=0D +=0D +/**=0D + The register function used to register SMI handler of IoTrap event.=0D + This is internal function and only used by Iotrap module.=0D +=0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[in] IoTrapIndex Index number of IOTRAP register=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D +**/=0D +EFI_STATUS=0D +PchInternalIoTrapSmiRegister (=0D + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + IN UINTN IoTrapIndex,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + Status =3D PchSmiRecordInsert (=0D + &mSrcDescIoTrap[IoTrapIndex],=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchIoTrapSmiType,=0D + DispatchHandle=0D + );=0D + PchSmmClearSource (&mSrcDescIoTrap[IoTrapIndex]);=0D + PchSmmEnableSource (&mSrcDescIoTrap[IoTrapIndex]);=0D + return Status;=0D +}=0D +=0D +/**=0D + Unregister a child SMI source dispatch function with a parent SMM driver= =0D +=0D + @param[in] DispatchHandle Handle of dispatch function to der= egister.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been suc= cessfully=0D + unregistered and the SMI source ha= s been disabled=0D + if there are no other registered c= hild dispatch=0D + functions for this SMI source.=0D + @retval EFI_INVALID_PARAMETER Handle is invalid.=0D +**/=0D +EFI_STATUS=0D +PchInternalIoTrapSmiUnRegister (=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + return PchSmmCoreUnRegister (NULL, DispatchHandle);=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmiDispatcher.inf b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/= Smm/PchSmiDispatcher.inf new file mode 100644 index 0000000000..97ad2f457e --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDisp= atcher.inf @@ -0,0 +1,116 @@ +## @file=0D +# Component description file for the Pch SMI Dispatch Handlers module=0D +#=0D +# Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +=0D +[Defines]=0D +INF_VERSION =3D 0x00010017=0D +BASE_NAME =3D PchSmiDispatcher=0D +FILE_GUID =3D B0D6ED53-B844-43f5-BD2F-61095264E77E=0D +VERSION_STRING =3D 1.0=0D +MODULE_TYPE =3D DXE_SMM_DRIVER=0D +PI_SPECIFICATION_VERSION =3D 1.10=0D +ENTRY_POINT =3D InitializePchSmmDispatcher=0D +=0D +=0D +[LibraryClasses]=0D +UefiBootServicesTableLib=0D +UefiDriverEntryPoint=0D +IoLib=0D +DebugLib=0D +PcdLib=0D +BaseLib=0D +BaseMemoryLib=0D +HobLib=0D +DevicePathLib=0D +PchCycleDecodingLib=0D +PchPcieRpLib=0D +PchPcrLib=0D +SmmServicesTableLib=0D +ReportStatusCodeLib=0D +PerformanceLib=0D +DxeServicesTableLib=0D +GpioLib=0D +GpioPrivateLib=0D +EspiLib=0D +S3BootScriptLib=0D +ConfigBlockLib=0D +PmcPrivateLib=0D +PmcLib=0D +SmiHandlerProfileLib=0D +CpuPcieRpLib=0D +PchPciBdfLib=0D +PmcPrivateLibWithS3=0D +CpuPcieInfoFruLib=0D +=0D +[Packages]=0D +MdePkg/MdePkg.dec=0D +TigerlakeSiliconPkg/SiPkg.dec=0D +=0D +=0D +[Pcd]=0D +# Progress Code for S3 Suspend start.=0D +# PROGRESS_CODE_S3_SUSPEND_START =3D (EFI_SOFTWARE_SMM_DRIVER | (EFI_OEM_S= PECIFIC | 0x00000000)) =3D 0x03078000=0D +gSiPkgTokenSpaceGuid.PcdProgressCodeS3SuspendStart=0D +# Progress Code for S3 Suspend end.=0D +# PROGRESS_CODE_S3_SUSPEND_END =3D (EFI_SOFTWARE_SMM_DRIVER | (EFI_OEM_S= PECIFIC | 0x00000001)) =3D 0x03078001=0D +gSiPkgTokenSpaceGuid.PcdProgressCodeS3SuspendEnd=0D +gSiPkgTokenSpaceGuid.PcdEfiGcdAllocateType=0D +=0D +=0D +[Sources]=0D +PchSmm.h=0D +PchSmmCore.c=0D +PchSmmHelpers.h=0D +PchSmmHelpers.c=0D +PchxSmmHelpers.h=0D +PchxSmmHelpers.c=0D +PchSmmUsb.c=0D +PchSmmGpi.c=0D +PchSmmPowerButton.c=0D +PchSmmSw.c=0D +PchSmmSx.c=0D +PchSmmPeriodicTimer.c=0D +IoTrap.c=0D +PchSmiDispatch.c=0D +PchSmmEspi.c=0D +PchSmiHelperClient.c=0D +=0D +=0D +[Protocols]=0D +gEfiPciRootBridgeIoProtocolGuid ## CONSUMES=0D +gEfiSmmGpiDispatch2ProtocolGuid ## PRODUCES=0D +gEfiSmmSxDispatch2ProtocolGuid ## PRODUCES=0D +gEfiSmmSwDispatch2ProtocolGuid ## PRODUCES=0D +gEfiSmmUsbDispatch2ProtocolGuid ## PRODUCES=0D +gEfiSmmPowerButtonDispatch2ProtocolGuid ## PRODUCES=0D +gEfiSmmPeriodicTimerDispatch2ProtocolGuid ## PRODUCES=0D +gEfiSmmBase2ProtocolGuid ## CONSUMES=0D +gEfiSmmCpuProtocolGuid ## CONSUMES=0D +gEfiSmmReadyToLockProtocolGuid ## CONSUMES=0D +gEfiSmmIoTrapDispatch2ProtocolGuid ## PRODUCES=0D +gPchSmmIoTrapControlGuid ## PRODUCES=0D +gPchTcoSmiDispatchProtocolGuid ## PRODUCES=0D +gPchPcieSmiDispatchProtocolGuid ## PRODUCES=0D +gPchAcpiSmiDispatchProtocolGuid ## PRODUCES=0D +gPchSmiDispatchProtocolGuid ## PRODUCES=0D +gPchEspiSmiDispatchProtocolGuid ## PRODUCES=0D +gPchSmmPeriodicTimerControlGuid ## PRODUCES=0D +gIoTrapExDispatchProtocolGuid ## PRODUCES=0D +gPchNvsAreaProtocolGuid ## CONSUMES=0D +=0D +=0D +[Guids]=0D +=0D +=0D +[Depex]=0D +gEfiPciRootBridgeIoProtocolGuid AND=0D +gEfiPciHostBridgeResourceAllocationProtocolGuid AND ## This is to ensure t= hat PCI MMIO resource has been prepared and available for this driver to al= locate.=0D +gEfiSmmCpuProtocolGuid AND=0D +gEfiSmmBase2ProtocolGuid AND ## This is for SmmServicesTableLib=0D +gPchNvsAreaProtocolGuid=0D +=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmiHelper.h b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pc= hSmiHelper.h new file mode 100644 index 0000000000..189197f4a2 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelp= er.h @@ -0,0 +1,40 @@ +/** @file=0D + eSPI SMI Dispatch header=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +=0D +#ifndef _PCH_SMI_HELPER_H_=0D +#define _PCH_SMI_HELPER_H_=0D +#include =0D +=0D +/**=0D + Get Root Port physical Number by CPU or PCH Pcie Root Port Device and Fu= nction Number=0D +=0D + @param[in] RpDev Root port device number.=0D + @param[in] RpFun Root port function number.=0D + @param[out] RpNumber Return corresponding physical Root Por= t index (0-based)=0D +**/=0D +VOID=0D +GetPcieRpNumber (=0D + IN UINTN RpDev,=0D + IN UINTN RpFun,=0D + OUT UINTN *RpNumber=0D + );=0D +=0D +/**=0D + Get CPU or PCH Pcie Root Port Device and Function Number by Root Port ph= ysical Number=0D +=0D + @param[in] RpNumber Root port physical number. (0-based)=0D + @param[out] RpDev Return corresponding root port device = number.=0D + @param[out] RpFun Return corresponding root port functio= n number.=0D +**/=0D +VOID=0D +GetPcieRpDevFun (=0D + IN UINTN RpIndex,=0D + OUT UINTN *RpDev,=0D + OUT UINTN *RpFun=0D + );=0D +=0D +#endif=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmiHelperClient.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/= Smm/PchSmiHelperClient.c new file mode 100644 index 0000000000..7693e76683 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelp= erClient.c @@ -0,0 +1,57 @@ +/** @file=0D + This file provides function to handle client-server differences.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include "PchSmmHelpers.h"=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +/**=0D + Get Root Port physical Number by CPU or PCH Pcie Root Port Device and Fu= nction Number=0D +=0D + @param[in] RpDev Root port device number.=0D + @param[in] RpFun Root port function number.=0D + @param[out] RpNumber Return corresponding physical Root Por= t index (0-based)=0D +**/=0D +VOID=0D +GetPcieRpNumber (=0D + IN UINTN RpDev,=0D + IN UINTN RpFun,=0D + OUT UINTN *RpNumber=0D + )=0D +{=0D + UINT64 RpBase;=0D + RpBase =3D PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_MC_BUS, RpDev, RpFun,= 0);=0D + GetPchPcieRpNumber (RpDev, RpFun, RpNumber);=0D +}=0D +=0D +/**=0D + Get CPU or PCH Pcie Root Port Device and Function Number by Root Port ph= ysical Number=0D +=0D + @param[in] RpNumber Root port physical number. (0-based)=0D + @param[out] RpDev Return corresponding root port device = number.=0D + @param[out] RpFun Return corresponding root port functio= n number.=0D +**/=0D +VOID=0D +GetPcieRpDevFun (=0D + IN UINTN RpIndex,=0D + OUT UINTN *RpDev,=0D + OUT UINTN *RpFun=0D + )=0D +{=0D + if (RpIndex >=3D CpuRpIndex0 && RpIndex <=3D CpuRpIndex3) {=0D + GetCpuPcieRpDevFun ((RpIndex - CpuRpIndex0), RpDev, RpFun);=0D + } else {=0D + *RpDev =3D PchPcieRpDevNumber (RpIndex);=0D + *RpFun =3D PchPcieRpFuncNumber (RpIndex);=0D + }=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= Smm.h b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h new file mode 100644 index 0000000000..6a23de2bc9 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h @@ -0,0 +1,1043 @@ +/** @file=0D + Prototypes and defines for the PCH SMM Dispatcher.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#ifndef _PCH_SMM_H_=0D +#define _PCH_SMM_H_=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include "IoTrap.h"=0D +=0D +#define EFI_BAD_POINTER 0xAFAFAFAFAFAFAFAFULL=0D +=0D +extern BOOLEAN mReadyToLock;=0D +=0D +///=0D +/// Define an enumeration for all the supported protocols=0D +///=0D +#define PCH_SMM_PROTOCOL_TYPE_MAX 6=0D +=0D +typedef enum {=0D + UsbType,=0D + SxType,=0D + SwType,=0D + GpiType,=0D + PowerButtonType,=0D + PeriodicTimerType,=0D + PchSmiDispatchType,=0D + PchSmmProtocolTypeMax=0D +} PCH_SMM_PROTOCOL_TYPE;=0D +=0D +///=0D +/// Define all the supported types of PCH SMI=0D +///=0D +typedef enum {=0D + PchTcoSmiMchType,=0D + PchTcoSmiTcoTimeoutType,=0D + PchTcoSmiOsTcoType,=0D + PchTcoSmiNmiType,=0D + PchTcoSmiIntruderDetectType,=0D + PchTcoSmiSpiBiosWpType,=0D + PchTcoSmiLpcBiosWpType,=0D + PchTcoSmiNewCenturyType,=0D + PchPcieSmiRpHotplugType,=0D + PchPcieSmiRpLinkActiveType,=0D + PchPcieSmiRpLinkEqType,=0D + PchAcpiSmiPmeType,=0D + PchAcpiSmiPmeB0Type,=0D + PchAcpiSmiRtcAlarmType,=0D + PchAcpiSmiTmrOverflowType,=0D + PchEspiSmiEspiSlaveType,=0D + PchSmiSerialIrqType,=0D + PchSmiMcSmiType,=0D + PchSmiSmBusType,=0D + PchSmiSpiAsyncType,=0D + PchIoTrapSmiType ///< internal SMI type=0D +} PCH_SMI_TYPES;=0D +=0D +///=0D +/// Generic funciton pointer to cover all Pch SMI function pointer types=0D +///=0D +typedef=0D +VOID=0D +(EFIAPI *PCH_SMI_CALLBACK_FUNCTIONS) (=0D + IN EFI_HANDLE DispatchHandle,=0D + ...=0D + );=0D +=0D +=0D +///=0D +/// SPECIFYING A REGISTER=0D +/// We want a general way of referring to addresses. For this case, we'll= only=0D +/// need addresses in the ACPI table (and the TCO entries within the ACPI = table).=0D +/// However, it's interesting to consider what it would take to support ot= her types=0D +/// of addresses. To address Will's concern, I think it prudent to accomm= odate it=0D +/// early on in the design.=0D +///=0D +/// Addresses we need to consider:=0D +///=0D +/// Type: Required:=0D +/// I/O Yes=0D +/// ACPI (special case of I/O) Only if we want to=0D +/// TCO (special case of I/O) Only if we want to=0D +/// GPIO (special case of MMIO) Only if we want to=0D +/// Memory (or Memory Mapped I/O) Only if we want to=0D +/// PCIE Yes, for BiosWp=0D +///=0D +typedef enum {=0D + ///=0D + /// IO_ADDR_TYPE, /// unimplemented=0D + ///=0D + ACPI_ADDR_TYPE,=0D + TCO_ADDR_TYPE,=0D + ///=0D + /// MEMORY_ADDR_TYPE, /// unimplemented=0D + ///=0D + GPIO_ADDR_TYPE,=0D + MEMORY_MAPPED_IO_ADDRESS_TYPE,=0D + PCIE_ADDR_TYPE,=0D + PCR_ADDR_TYPE,=0D + NUM_ADDR_TYPES, ///< count of items in this enum=0D + PCH_SMM_ADDR_TYPE_NULL =3D -1 ///< sentinel to indicate NULL or = to signal end of arrays=0D +} ADDR_TYPE;=0D +=0D +//=0D +// Assumption: 32-bits -- enum's evaluate to integer=0D +// Assumption: This code will only run on IA-32. Justification: IA-64 doe= sn't have SMIs.=0D +// We don't have to worry about 64-bit addresses.=0D +// Typedef the size of addresses in case the numbers I'm using are wrong o= r in case=0D +// this changes. This is a good idea because PCI_ADDR will change, for ex= ample, when=0D +// we add support for PciExpress.=0D +//=0D +typedef UINT16 IO_ADDR;=0D +typedef IO_ADDR ACPI_ADDR; ///< can omit=0D +typedef IO_ADDR TCO_ADDR; ///< can omit=0D +typedef UINTN MEM_ADDR;=0D +typedef MEM_ADDR *MEMORY_MAPPED_IO_ADDRESS;=0D +typedef MEM_ADDR *GPIO_ADDR;=0D +typedef union {=0D + UINT32 Raw;=0D + struct {=0D + UINT32 Reg: 16;=0D + UINT32 Fnc: 3;=0D + UINT32 Dev: 5;=0D + UINT32 Bus: 8;=0D + } Fields;=0D +} PCIE_ADDR;=0D +=0D +typedef union {=0D + UINT32 Raw;=0D + struct {=0D + UINT16 Offset;=0D + UINT8 Pid;=0D + UINT8 Base;=0D + } Fields;=0D +} PCR_ADDR;=0D +=0D +typedef struct {=0D + ADDR_TYPE Type;=0D + union {=0D + ///=0D + /// used to initialize during declaration/definition=0D + ///=0D + UINT32 raw;=0D +=0D + ///=0D + /// used to access useful data=0D + ///=0D + IO_ADDR io;=0D + ACPI_ADDR acpi;=0D + TCO_ADDR tco;=0D + GPIO_ADDR gpio;=0D + MEM_ADDR mem;=0D + MEMORY_MAPPED_IO_ADDRESS Mmio;=0D + PCIE_ADDR pcie;=0D + PCR_ADDR Pcr;=0D +=0D + } Data;=0D +=0D +} PCH_SMM_ADDRESS;=0D +=0D +///=0D +/// SPECIFYING BITS WITHIN A REGISTER=0D +/// Here's a struct that helps us specify a source or enable bit.=0D +///=0D +typedef struct {=0D + PCH_SMM_ADDRESS Reg;=0D + UINT8 SizeInBytes; ///< of the register=0D + UINT8 Bit;=0D +} PCH_SMM_BIT_DESC;=0D +=0D +//=0D +// Sometimes, we'll have bit descriptions that are unused. It'd be great = to have a=0D +// way to easily identify them:=0D +//=0D +#define IS_BIT_DESC_NULL(BitDesc) ((BitDesc).Reg.Type =3D=3D PCH_SMM_ADD= R_TYPE_NULL) ///< "returns" true when BitDesc is NULL=0D +#define NULL_THIS_BIT_DESC(BitDesc) ((BitDesc).Reg.Type =3D PCH_SMM_ADDR_T= YPE_NULL) ///< will "return" an integer w/ value of 0=0D +#define NULL_BIT_DESC_INITIALIZER \=0D + { \=0D + { \=0D + PCH_SMM_ADDR_TYPE_NULL, \=0D + { \=0D + 0 \=0D + } \=0D + }, \=0D + 0, 0 \=0D + }=0D +//=0D +// I'd like a type to specify the callback's Sts & En bits because they'll= =0D +// be commonly used together:=0D +//=0D +#define NUM_EN_BITS 2=0D +#define NUM_STS_BITS 1=0D +=0D +//=0D +// Flags=0D +//=0D +typedef UINT8 PCH_SMM_SOURCE_FLAGS;=0D +=0D +//=0D +// Flags required to describe the event source=0D +//=0D +#define PCH_SMM_NO_FLAGS 0=0D +#define PCH_SMM_SCI_EN_DEPENDENT 1=0D +=0D +typedef struct {=0D + PCH_SMM_SOURCE_FLAGS Flags;=0D + PCH_SMM_BIT_DESC En[NUM_EN_BITS]; ///< Describes the enable bit(= s) for the SMI event=0D + PCH_SMM_BIT_DESC Sts[NUM_STS_BITS]; ///< Describes the secondary s= tatus bit for the SMI event. Might be the same as TopLevelSmi=0D + PCH_SMM_BIT_DESC PmcSmiSts; ///< Refereing to the top leve= l status bit in PMC SMI_STS, i.e. R_PCH_SMI_STS=0D +} PCH_SMM_SOURCE_DESC;=0D +=0D +///=0D +/// Used to initialize null source descriptor=0D +///=0D +#define NULL_SOURCE_DESC_INITIALIZER \=0D + { \=0D + PCH_SMM_NO_FLAGS, \=0D + { \=0D + NULL_BIT_DESC_INITIALIZER, NULL_BIT_DESC_INITIALIZER \=0D + }, \=0D + { \=0D + NULL_BIT_DESC_INITIALIZER \=0D + }, \=0D + NULL_BIT_DESC_INITIALIZER \=0D + }=0D +=0D +///=0D +/// Define a PCIE RP event context for SmiProfileHandlerInfo tool=0D +///=0D +typedef struct {=0D + PCH_SMI_TYPES PchSmiType;=0D + UINTN RpIndex;=0D +} PCH_SMM_PCIE_REGISTER_CONTEXT;=0D +=0D +///=0D +/// CHILD CONTEXTS=0D +/// To keep consistent w/ the architecture, we'll need to provide the cont= ext=0D +/// to the child when we call its callback function. After talking with W= ill,=0D +/// we agreed that we'll need functions to "dig" the context out of the ha= rdware=0D +/// in many cases (Sx, Trap, Gpi, etc), and we'll need a function to compa= re those=0D +/// contexts to prevent unnecessary dispatches. I'd like a general type f= or these=0D +/// "GetContext" functions, so I'll need a union of all the protocol conte= xts for=0D +/// our internal use:=0D +///=0D +typedef union {=0D + //=0D + // (in no particular order)=0D + //=0D + EFI_SMM_SX_REGISTER_CONTEXT Sx;=0D + EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT PeriodicTimer;=0D + EFI_SMM_SW_REGISTER_CONTEXT Sw;=0D + EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT PowerButton;=0D + EFI_SMM_USB_REGISTER_CONTEXT Usb;=0D + EFI_SMM_GPI_REGISTER_CONTEXT Gpi;=0D + PCH_SMM_PCIE_REGISTER_CONTEXT Pcie;=0D +} PCH_SMM_CONTEXT;=0D +=0D +///=0D +/// Misc data for PchDispatcher usage.=0D +/// For PeriodicTimer, since the ElapsedTime is removed from EFI_SMM_PERIO= DIC_TIMER_REGISTER_CONTEXT of EDKII,=0D +/// and PchDispatcher needs it for every record. Thus move it here to supp= ort ElapsedTime.=0D +///=0D +typedef struct {=0D + UINTN ElapsedTime;=0D + ///=0D + /// A switch to control periodic timer SMI enabling=0D + ///=0D + BOOLEAN TimerSmiEnabled;=0D +} PCH_SMM_MISC_DATA;=0D +=0D +//=0D +// Assumption: PeriodicTimer largest at 3x64-bits or 24 bytes=0D +//=0D +typedef struct _DATABASE_RECORD DATABASE_RECORD;=0D +=0D +///=0D +/// Assumption: the GET_CONTEXT function will be as small and simple as po= ssible.=0D +/// Assumption: We don't need to pass in an enumeration for the protocol b= ecause each=0D +/// GET_CONTEXT function is written for only one protocol.=0D +/// We also need a function to compare contexts to see if the child should= be dispatched=0D +/// In addition, we need a function to acquire CommBuffer and CommBufferSi= ze for=0D +/// dispatch callback function of EDKII native support.=0D +///=0D +typedef=0D +VOID=0D +(EFIAPI *GET_CONTEXT) (=0D + IN DATABASE_RECORD * Record,=0D + OUT PCH_SMM_CONTEXT * Context=0D + );=0D +=0D +typedef=0D +BOOLEAN=0D +(EFIAPI *CMP_CONTEXT) (=0D + IN PCH_SMM_CONTEXT * Context1,=0D + IN PCH_SMM_CONTEXT * Context2=0D + );=0D +=0D +typedef=0D +VOID=0D +(EFIAPI *GET_COMMBUFFER) (=0D + IN DATABASE_RECORD * Record,=0D + OUT VOID **CommBuffer,=0D + OUT UINTN * CommBufferSize=0D + );=0D +=0D +///=0D +/// Finally, every protocol will require a "Get Context" and "Compare Cont= ext" call, so=0D +/// we may as well wrap that up in a table, too.=0D +///=0D +typedef struct {=0D + GET_CONTEXT GetContext;=0D + CMP_CONTEXT CmpContext;=0D + GET_COMMBUFFER GetCommBuffer;=0D +} CONTEXT_FUNCTIONS;=0D +=0D +extern CONTEXT_FUNCTIONS ContextFunctions[PCH_SMM_PROTOCOL_TYPE_M= AX];=0D +=0D +///=0D +/// MAPPING CONTEXT TO BIT DESCRIPTIONS=0D +/// I'd like to have a general approach to mapping contexts to bit descrip= tions.=0D +/// Sometimes, we'll find that we can use table lookups or constant assign= ments;=0D +/// other times, we'll find that we'll need to use a function to perform t= he mapping.=0D +/// If we define a macro to mask that process, we'll never have to change = the code.=0D +/// I don't know if this is desirable or not -- if it isn't, then we can g= et rid=0D +/// of the macros and just use function calls or variable assignments. Do= esn't matter=0D +/// to me.=0D +/// Mapping complex contexts requires a function=0D +///=0D +=0D +/**=0D + Maps a USB context to a source description.=0D +=0D + @param[in] Context The context we need to map. Type must b= e USB.=0D + @param[out] SrcDesc The source description that corresponds = to the given context.=0D +=0D +**/=0D +VOID=0D +MapUsbToSrcDesc (=0D + IN PCH_SMM_CONTEXT *Context,=0D + OUT PCH_SMM_SOURCE_DESC *SrcDesc=0D + );=0D +=0D +/**=0D + Figure out which timer the child is requesting and=0D + send back the source description=0D +=0D + @param[in] DispatchContext The pointer to the Dispatch Context inst= ances=0D + @param[out] SrcDesc The pointer to the source description=0D +=0D +**/=0D +VOID=0D +MapPeriodicTimerToSrcDesc (=0D + IN PCH_SMM_CONTEXT *DispatchCon= text,=0D + OUT PCH_SMM_SOURCE_DESC *SrcDesc=0D + );=0D +=0D +//=0D +// Mapping simple contexts can be done by assignment or lookup table=0D +//=0D +extern CONST PCH_SMM_SOURCE_DESC mSxSourceDesc;=0D +extern CONST PCH_SMM_SOURCE_DESC mPowerButtonSourceDesc;=0D +extern CONST PCH_SMM_SOURCE_DESC mSrcDescNewCentury;=0D +extern CONST PCH_SMM_SOURCE_DESC mGpiSourceDescTemplate;=0D +=0D +///=0D +/// For PCHx, APMC is UINT8 port, so the MAX SWI Value is 0xFF.=0D +///=0D +#define MAXIMUM_SWI_VALUE 0xFF=0D +///=0D +/// Open: Need to make sure this kind of type cast will actually work.=0D +/// May need an intermediate form w/ two VOID* arguments. I'll figure=0D +/// that out when I start compiling.=0D +///=0D +typedef=0D +VOID=0D +(EFIAPI *PCH_SMM_CLEAR_SOURCE) (=0D + CONST PCH_SMM_SOURCE_DESC * SrcDesc=0D + );=0D +=0D +///=0D +/// "DATABASE" RECORD=0D +/// Linked list data structures=0D +///=0D +#define DATABASE_RECORD_SIGNATURE SIGNATURE_32 ('D', 'B', 'R', 'C')=0D +=0D +struct _DATABASE_RECORD {=0D + UINT32 Signature;=0D + LIST_ENTRY Link;=0D + BOOLEAN Processed;=0D + ///=0D + /// Status and Enable bit description=0D + ///=0D + PCH_SMM_SOURCE_DESC SrcDesc;=0D +=0D + ///=0D + /// Callback function=0D + ///=0D + EFI_SMM_HANDLER_ENTRY_POINT2 Callback;=0D + PCH_SMM_CONTEXT ChildContext;=0D + UINTN ContextSize;=0D +=0D + ///=0D + /// Special handling hooks -- init them to NULL if unused/unneeded=0D + ///=0D + PCH_SMM_CLEAR_SOURCE ClearSource;=0D +=0D + ///=0D + /// Functions required to make callback code general=0D + ///=0D + CONTEXT_FUNCTIONS ContextFunctions;=0D +=0D + ///=0D + /// The protocol that this record dispatches=0D + ///=0D + PCH_SMM_PROTOCOL_TYPE ProtocolType;=0D +=0D + ///=0D + /// Misc data for private usage=0D + ///=0D + PCH_SMM_MISC_DATA MiscData;=0D +=0D + ///=0D + /// PCH SMI callback function=0D + ///=0D + PCH_SMI_CALLBACK_FUNCTIONS PchSmiCallback;=0D + ///=0D + /// Indicate the PCH SMI types.=0D + ///=0D + PCH_SMI_TYPES PchSmiType;=0D +};=0D +=0D +#define DATABASE_RECORD_FROM_LINK(_record) CR (_record, DATABASE_RECORD, = Link, DATABASE_RECORD_SIGNATURE)=0D +#define DATABASE_RECORD_FROM_CHILDCONTEXT(_record) CR (_record, DATABASE_= RECORD, ChildContext, DATABASE_RECORD_SIGNATURE)=0D +=0D +///=0D +/// HOOKING INTO THE ARCHITECTURE=0D +///=0D +typedef=0D +EFI_STATUS=0D +(EFIAPI *PCH_SMM_GENERIC_REGISTER) (=0D + IN VOID **This,=0D + IN VOID *DispatchFunction,=0D + IN VOID *DispatchContext,=0D + OUT EFI_HANDLE *DispatchHandle=0D + );=0D +typedef=0D +EFI_STATUS=0D +(EFIAPI *PCH_SMM_GENERIC_UNREGISTER) (=0D + IN VOID **This,=0D + IN EFI_HANDLE DispatchHandle=0D + );=0D +=0D +///=0D +/// Define a memory "stamp" equivalent in size and function to most of the= protocols=0D +///=0D +typedef struct {=0D + PCH_SMM_GENERIC_REGISTER Register;=0D + PCH_SMM_GENERIC_UNREGISTER Unregister;=0D + UINTN Extra1;=0D + UINTN Extra2; ///< may not need this one=0D +} PCH_SMM_GENERIC_PROTOCOL;=0D +=0D +/**=0D + Register a child SMI dispatch function with a parent SMM driver.=0D +=0D + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL = instance.=0D + @param[in] DispatchFunction Pointer to dispatch function to be invok= ed for this SMI source.=0D + @param[in] DispatchContext Pointer to the dispatch function's conte= xt.=0D + @param[out] DispatchHandle Handle of dispatch function, for when in= terfacing=0D + with the parent SMM driver, will be the = address of linked=0D + list link in the call back record.=0D +=0D + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create databas= e record=0D + @retval EFI_INVALID_PARAMETER The input parameter is invalid=0D + @retval EFI_SUCCESS The dispatch function has been successfu= lly=0D + registered and the SMI source has been e= nabled.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchPiSmmCoreRegister (=0D + IN PCH_SMM_GENERIC_PROTOCOL *This,=0D + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,= =0D + IN PCH_SMM_CONTEXT *DispatchContext,= =0D + OUT EFI_HANDLE *DispatchHandle=0D + );=0D +=0D +/**=0D + Unregister a child SMI source dispatch function with a parent SMM driver= =0D +=0D + @param[in] This Protocol instance pointer.=0D + @param[in] DispatchHandle Handle of dispatch function to der= egister.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been suc= cessfully=0D + unregistered and the SMI source ha= s been disabled=0D + if there are no other registered c= hild dispatch=0D + functions for this SMI source.=0D + @retval EFI_INVALID_PARAMETER Handle is invalid.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchPiSmmCoreUnRegister (=0D + IN PCH_SMM_GENERIC_PROTOCOL *This,=0D + IN EFI_HANDLE *DispatchHandle=0D + );=0D +=0D +=0D +/**=0D + Unregister a child SMI source dispatch function with a parent SMM driver= .=0D +=0D + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL = instance.=0D + @param[in] DispatchHandle Handle of dispatch function to deregiste= r.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been successfu= lly=0D + unregistered and the SMI source has been= disabled=0D + if there are no other registered child d= ispatch=0D + functions for this SMI source.=0D + @retval EFI_INVALID_PARAMETER Handle is invalid.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchSmmCoreUnRegister (=0D + IN PCH_SMM_GENERIC_PROTOCOL *This,=0D + IN EFI_HANDLE *DispatchHandle=0D + );=0D +=0D +typedef union {=0D + PCH_SMM_GENERIC_PROTOCOL Generic;=0D + EFI_SMM_USB_DISPATCH2_PROTOCOL Usb;=0D + EFI_SMM_SX_DISPATCH2_PROTOCOL Sx;=0D + EFI_SMM_SW_DISPATCH2_PROTOCOL Sw;=0D + EFI_SMM_GPI_DISPATCH2_PROTOCOL Gpi;=0D + EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL PowerButton;=0D + EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL PeriodicTimer;=0D +} PCH_SMM_PROTOCOL;=0D +=0D +///=0D +/// Define a structure to help us identify the generic protocol=0D +///=0D +#define PROTOCOL_SIGNATURE SIGNATURE_32 ('P', 'R', 'O', 'T')=0D +=0D +typedef struct {=0D + UINTN Signature;=0D +=0D + PCH_SMM_PROTOCOL_TYPE Type;=0D + EFI_GUID *Guid;=0D + PCH_SMM_PROTOCOL Protocols;=0D +} PCH_SMM_QUALIFIED_PROTOCOL;=0D +=0D +#define QUALIFIED_PROTOCOL_FROM_GENERIC(_generic) \=0D + CR ( \=0D + _generic, \=0D + PCH_SMM_QUALIFIED_PROTOCOL, \=0D + Protocols, \=0D + PROTOCOL_SIGNATURE \=0D + )=0D +=0D +///=0D +/// Create private data for the protocols that we'll publish=0D +///=0D +typedef struct {=0D + LIST_ENTRY CallbackDataBase;=0D + EFI_HANDLE SmiHandle;=0D + EFI_HANDLE InstallMultProtHandle;=0D + PCH_SMM_QUALIFIED_PROTOCOL Protocols[PCH_SMM_PROTOCOL_TYPE_MAX];=0D +} PRIVATE_DATA;=0D +=0D +extern PRIVATE_DATA mPrivateData;=0D +extern UINT16 mAcpiBaseAddr;=0D +extern UINT16 mTcoBaseAddr;=0D +=0D +/**=0D + The internal function used to create and insert a database record=0D +=0D + @param[in] InsertRecord Record to insert to database.=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D +**/=0D +EFI_STATUS=0D +SmmCoreInsertRecord (=0D + IN DATABASE_RECORD *NewRecord,=0D + OUT EFI_HANDLE *DispatchHandle=0D + );=0D +=0D +/**=0D + Get the Sleep type=0D +=0D + @param[in] Record No use=0D + @param[out] Context The context that includes SLP_TYP bits t= o be filled=0D +**/=0D +VOID=0D +EFIAPI=0D +SxGetContext (=0D + IN DATABASE_RECORD *Record,=0D + OUT PCH_SMM_CONTEXT *Context=0D + );=0D +=0D +/**=0D + Register a child SMI source dispatch function for the specified software= SMI.=0D +=0D + This service registers a function (DispatchFunction) which will be calle= d when the software=0D + SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On r= eturn,=0D + DispatchHandle contains a unique handle which may be used later to unreg= ister the function=0D + using UnRegister().=0D +=0D + @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PRO= TOCOL instance.=0D + @param[in] DispatchFunction Function to register for handler when t= he specified software=0D + SMI is generated.=0D + @param[in, out] RegisterContext Pointer to the dispatch function's cont= ext.=0D + The caller fills this context in before= calling=0D + the register function to indicate to th= e register=0D + function which Software SMI input value= the=0D + dispatch function should be invoked for= .=0D + @param[out] DispatchHandle Handle generated by the dispatcher to t= rack the=0D + function instance.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been successful= ly=0D + registered and the SMI source has been en= abled.=0D + @retval EFI_DEVICE_ERROR The SW driver was unable to enable the SM= I source.=0D + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The SW SMI in= put value=0D + is not within a valid range or is already= in use.=0D + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM= ) to manage this=0D + child.=0D + @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not be = assigned=0D + for this dispatch.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchSwSmiRegister (=0D + IN EFI_SMM_SW_DISPATCH2_PROTOCOL *This,=0D + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,=0D + IN EFI_SMM_SW_REGISTER_CONTEXT *DispatchContext,=0D + OUT EFI_HANDLE *DispatchHandle=0D + );=0D +=0D +/**=0D + Unregister a child SMI source dispatch function for the specified softwa= re SMI.=0D +=0D + This service removes the handler associated with DispatchHandle so that = it will no longer be=0D + called in response to a software SMI.=0D +=0D + @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTO= COL instance.=0D + @param[in] DispatchHandle Handle of dispatch function to deregister= .=0D +=0D + @retval EFI_SUCCESS The dispatch function has been successful= ly unregistered.=0D + @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchSwSmiUnRegister (=0D + IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This,=0D + IN EFI_HANDLE DispatchHandle=0D + );=0D +=0D +/**=0D + Init required protocol for Pch Sw Dispatch protocol.=0D +**/=0D +VOID=0D +PchSwDispatchInit (=0D + VOID=0D + );=0D +=0D +/**=0D + Check whether sleep type of two contexts match=0D +=0D + @param[in] Context1 Context 1 that includes sleep type 1=0D + @param[in] Context2 Context 2 that includes sleep type 2=0D +=0D + @retval FALSE Sleep types match=0D + @retval TRUE Sleep types don't match=0D +**/=0D +BOOLEAN=0D +EFIAPI=0D +SxCmpContext (=0D + IN PCH_SMM_CONTEXT *Context1,=0D + IN PCH_SMM_CONTEXT *Context2=0D + );=0D +=0D +/**=0D + Update the elapsed time from the Interval data of DATABASE_RECORD=0D +=0D + @param[in] Record The pointer to the DATABASE_RECORD.=0D + @param[out] HwContext The Context to be updated.=0D +**/=0D +VOID=0D +EFIAPI=0D +PeriodicTimerGetContext (=0D + IN DATABASE_RECORD *Record,=0D + OUT PCH_SMM_CONTEXT *Context=0D + );=0D +=0D +/**=0D + Check whether Periodic Timer of two contexts match=0D +=0D + @param[in] Context1 Context 1 that includes Periodic Timer = 1=0D + @param[in] Context2 Context 2 that includes Periodic Timer = 2=0D +=0D + @retval FALSE Periodic Timer match=0D + @retval TRUE Periodic Timer don't match=0D +**/=0D +BOOLEAN=0D +EFIAPI=0D +PeriodicTimerCmpContext (=0D + IN PCH_SMM_CONTEXT *Context1,=0D + IN PCH_SMM_CONTEXT *Context2=0D + );=0D +=0D +/**=0D + Gather the CommBuffer information of SmmPeriodicTimerDispatch2.=0D +=0D + @param[in] Record No use=0D + @param[out] CommBuffer Point to the CommBuffer structure=0D + @param[out] CommBufferSize Point to the Size of CommBuffer structur= e=0D +**/=0D +VOID=0D +EFIAPI=0D +PeriodicTimerGetCommBuffer (=0D + IN DATABASE_RECORD *Record,=0D + OUT VOID **CommBuffer,=0D + OUT UINTN *CommBufferSize=0D + );=0D +=0D +/**=0D + Get the power button status.=0D +=0D + @param[in] Record The pointer to the DATABASE_RECORD.=0D + @param[out] Context Calling context from the hardware, will = be updated with the current power button status.=0D +**/=0D +VOID=0D +EFIAPI=0D +PowerButtonGetContext (=0D + IN DATABASE_RECORD *Record,=0D + OUT PCH_SMM_CONTEXT *Context=0D + );=0D +=0D +/**=0D + Check whether Power Button status of two contexts match=0D +=0D + @param[in] Context1 Context 1 that includes Power Button sta= tus 1=0D + @param[in] Context2 Context 2 that includes Power Button sta= tus 2=0D +=0D + @retval FALSE Power Button status match=0D + @retval TRUE Power Button status don't match=0D +**/=0D +BOOLEAN=0D +EFIAPI=0D +PowerButtonCmpContext (=0D + IN PCH_SMM_CONTEXT *Context1,=0D + IN PCH_SMM_CONTEXT *Context2=0D + );=0D +=0D +/**=0D + This function is responsible for calculating and enabling any timers tha= t are required=0D + to dispatch messages to children. The SrcDesc argument isn't acutally us= ed.=0D +=0D + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC insta= nce.=0D +**/=0D +VOID=0D +EFIAPI=0D +PchSmmPeriodicTimerClearSource (=0D + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc=0D + );=0D +=0D +/**=0D + This services returns the next SMI tick period that is supported by the = chipset.=0D + The order returned is from longest to shortest interval period.=0D +=0D + @param[in] This Pointer to the EFI_SMM_PERIODIC_TIMER_DI= SPATCH2_PROTOCOL instance.=0D + @param[in, out] SmiTickInterval Pointer to pointer of the next shorter S= MI interval period that is supported by the child.=0D +=0D + @retval EFI_SUCCESS The service returned successfully.=0D + @retval EFI_INVALID_PARAMETER The parameter SmiTickInterval is invalid= .=0D +**/=0D +EFI_STATUS=0D +PchSmmPeriodicTimerDispatchGetNextShorterInterval (=0D + IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This,=0D + IN OUT UINT64 **SmiTickInterval= =0D + );=0D +=0D +/**=0D + Install PCH SMM periodic timer control protocol=0D +=0D + @param[in] Handle handle for this driver=0D +=0D + @retval EFI_SUCCESS Driver initialization completed su= ccessfully=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +InstallPchSmmPeriodicTimerControlProtocol (=0D + IN EFI_HANDLE Handle=0D + );=0D +=0D +/**=0D + When we get an SMI that indicates that we are transitioning to a sleep s= tate,=0D + we need to actually transition to that state. We do this by disabling t= he=0D + "SMI on sleep enable" feature, which generates an SMI when the operating= system=0D + tries to put the system to sleep, and then physically putting the system= to sleep.=0D +**/=0D +VOID=0D +PchSmmSxGoToSleep (=0D + VOID=0D + );=0D +=0D +/**=0D + Install protocols of PCH specifics SMI types, including=0D + PCH TCO SMI types, PCH PCIE SMI types, PCH ACPI SMI types, PCH MISC SMI = types.=0D +=0D + @retval the result of protocol installatio= n=0D +**/=0D +EFI_STATUS=0D +InstallPchSmiDispatchProtocols (=0D + VOID=0D + );=0D +=0D +/**=0D + The function to dispatch all callback function of PCH SMI types.=0D +=0D + @retval EFI_SUCCESS Function successfully completed=0D + @retval EFI_UNSUPPORTED no=0D +**/=0D +EFI_STATUS=0D +PchSmiTypeCallbackDispatcher (=0D + IN DATABASE_RECORD *Record=0D + );=0D +=0D +/**=0D + The register function used to register SMI handler of IoTrap event.=0D + This is internal function and only used by Iotrap module.=0D +=0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[in] IoTrapIndex Index number of IOTRAP register=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D +**/=0D +EFI_STATUS=0D +PchInternalIoTrapSmiRegister (=0D + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + IN UINTN IoTrapIndex,=0D + OUT EFI_HANDLE *DispatchHandle=0D + );=0D +=0D +/**=0D + Unregister a child SMI source dispatch function with a parent SMM driver= =0D +=0D + @param[in] DispatchHandle Handle of dispatch function to der= egister.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been suc= cessfully=0D + unregistered and the SMI source ha= s been disabled=0D + if there are no other registered c= hild dispatch=0D + functions for this SMI source.=0D + @retval EFI_INVALID_PARAMETER Handle is invalid.=0D +**/=0D +EFI_STATUS=0D +PchInternalIoTrapSmiUnRegister (=0D + IN EFI_HANDLE DispatchHandle=0D + );=0D +=0D +/**=0D + Register an eSPI SMI handler based on the type=0D +=0D + @param[in] DispatchFunction Callback in an event of eSPI SMI=0D + @param[in] PchSmiTypes The eSPI type published by PchSmiDis= patch=0D + @param[out] DispatchHandle The callback handle=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descripti= on=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database r= ecord=0D + @retval EFI_SUCCESS Registration is successful.=0D +**/=0D +EFI_STATUS=0D +PchInternalEspiSmiRegister (=0D + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + IN PCH_SMI_TYPES PchSmiTypes,=0D + OUT EFI_HANDLE *DispatchHandle=0D + );=0D +=0D +/**=0D + Unregister an eSPI SMI handler=0D +=0D + @param[in] DispatchHandle Handle of dispatch function to der= egister.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been suc= cessfully=0D + unregistered and the SMI source ha= s been disabled=0D + if there are no other registered c= hild dispatch=0D + functions for this SMI source.=0D + @retval EFI_INVALID_PARAMETER Handle is invalid.=0D +**/=0D +EFI_STATUS=0D +PchInternalEspiSmiUnRegister (=0D + IN EFI_HANDLE DispatchHandle=0D + );=0D +=0D +/**=0D + The internal function used to create and insert a database record=0D + for SMI record of Pch Smi types.=0D +=0D + @param[in] SrcDesc The pointer to the SMI source desc= ription=0D + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source=0D + @param[in] PchSmiType Specific SMI type of PCH SMI=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D +**/=0D +EFI_STATUS=0D +PchSmiRecordInsert (=0D + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc,=0D + IN PCH_SMI_CALLBACK_FUNCTIONS DispatchFunction,=0D + IN PCH_SMI_TYPES PchSmiType,=0D + OUT EFI_HANDLE *DispatchHandle=0D + );=0D +=0D +extern CONST PCH_SMM_SOURCE_DESC mSrcDescSerialIrq;=0D +extern CONST PCH_SMM_SOURCE_DESC mSrcDescLpcBiosWp;=0D +=0D +/**=0D + Clear the TCO SMI status bit and block after the SMI handling is done=0D +=0D + @param[in] SrcDesc Pointer to the PCH SMI source desc= ription table=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +PchTcoSmiClearSourceAndBlock (=0D + CONST PCH_SMM_SOURCE_DESC *SrcDesc=0D + );=0D +=0D +/**=0D + Clear the TCO SMI status bit after the SMI handling is done=0D +=0D + @param[in] SrcDesc Pointer to the PCH SMI source desc= ription table=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +PchTcoSmiClearSource (=0D + CONST PCH_SMM_SOURCE_DESC *SrcDesc=0D + );=0D +=0D +/**=0D + Initialize Source descriptor structure=0D +=0D + @param[in] SrcDesc Pointer to the PCH SMI source desc= ription table=0D +**/=0D +VOID=0D +EFIAPI=0D +NullInitSourceDesc (=0D + PCH_SMM_SOURCE_DESC *SrcDesc=0D + );=0D +=0D +/**=0D + The register function used to register SMI handler of GPI SMI event.=0D +=0D + @param[in] This Pointer to the EFI_SMM_GPI_DISPATCH2_PROT= OCOL instance.=0D + @param[in] DispatchFunction Function to register for handler when the= specified GPI causes an SMI.=0D + @param[in] RegisterContext Pointer to the dispatch function's contex= t.=0D + The caller fills this context in before c= alling=0D + the register function to indicate to the = register=0D + function the GPI(s) for which the dispatc= h function=0D + should be invoked.=0D + @param[out] DispatchHandle Handle generated by the dispatcher to tra= ck the=0D + function instance.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been successful= ly=0D + registered and the SMI source has been en= abled.=0D + @retval EFI_ACCESS_DENIED Register is not allowed=0D + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The GPI input= value=0D + is not within valid range.=0D + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM= ) to manage this child.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchGpiSmiRegister (=0D + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This,=0D + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,=0D + IN EFI_SMM_GPI_REGISTER_CONTEXT *RegisterContext,=0D + OUT EFI_HANDLE *DispatchHandle=0D + );=0D +=0D +/**=0D + Unregister a GPI SMI source dispatch function with a parent SMM driver=0D +=0D + @param[in] This Pointer to the EFI_SMM_GPI_DISPATCH2_PRO= TOCOL instance.=0D + @param[in] DispatchHandle Handle of dispatch function to deregiste= r.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been successfu= lly=0D + unregistered and the SMI source has been= disabled=0D + if there are no other registered child d= ispatch=0D + functions for this SMI source.=0D + @retval EFI_INVALID_PARAMETER Handle is invalid.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchGpiSmiUnRegister (=0D + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This,=0D + IN EFI_HANDLE DispatchHandle=0D + );=0D +=0D +#endif=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmmCore.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchS= mmCore.c new file mode 100644 index 0000000000..b2e76a8b72 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCore= .c @@ -0,0 +1,926 @@ +/** @file=0D + This driver is responsible for the registration of child drivers=0D + and the abstraction of the PCH SMI sources.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include "PchSmm.h"=0D +#include "PchSmmHelpers.h"=0D +#include "PchSmmEspi.h"=0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#define PROGRESS_CODE_S3_SUSPEND_START PcdGet32 (PcdProgressCodeS3Suspend= Start)=0D +//=0D +// MODULE / GLOBAL DATA=0D +//=0D +// Module variables used by the both the main dispatcher and the source di= spatchers=0D +// Declared in PchSmm.h=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mAcpiBaseAddr;=0D +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mTcoBaseAddr;=0D +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mReadyToLock;=0D +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mS3SusStart;=0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED PRIVATE_DATA mPrivateData =3D {=0D + {=0D + NULL,=0D + NULL=0D + }, // CallbackDataBase linked list he= ad=0D + NULL, // EFI handle returned when callin= g InstallMultipleProtocolInterfaces=0D + NULL, //=0D + { // protocol arrays=0D + //=0D + // elements within the array=0D + //=0D + {=0D + PROTOCOL_SIGNATURE,=0D + UsbType,=0D + &gEfiSmmUsbDispatch2ProtocolGuid,=0D + {{=0D + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister,=0D + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister=0D + }}=0D + },=0D + {=0D + PROTOCOL_SIGNATURE,=0D + SxType,=0D + &gEfiSmmSxDispatch2ProtocolGuid,=0D + {{=0D + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister,=0D + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister=0D + }}=0D + },=0D + {=0D + PROTOCOL_SIGNATURE,=0D + SwType,=0D + &gEfiSmmSwDispatch2ProtocolGuid,=0D + {{=0D + (PCH_SMM_GENERIC_REGISTER) PchSwSmiRegister,=0D + (PCH_SMM_GENERIC_UNREGISTER) PchSwSmiUnRegister,=0D + (UINTN) MAXIMUM_SWI_VALUE=0D + }}=0D + },=0D + {=0D + PROTOCOL_SIGNATURE,=0D + GpiType,=0D + &gEfiSmmGpiDispatch2ProtocolGuid,=0D + {{=0D + (PCH_SMM_GENERIC_REGISTER) PchGpiSmiRegister,=0D + (PCH_SMM_GENERIC_UNREGISTER) PchGpiSmiUnRegister,=0D + (UINTN) PCH_GPIO_NUM_SUPPORTED_GPIS=0D + }}=0D + },=0D + {=0D + PROTOCOL_SIGNATURE,=0D + PowerButtonType,=0D + &gEfiSmmPowerButtonDispatch2ProtocolGuid,=0D + {{=0D + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister,=0D + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister=0D + }}=0D + },=0D + {=0D + PROTOCOL_SIGNATURE,=0D + PeriodicTimerType,=0D + &gEfiSmmPeriodicTimerDispatch2ProtocolGuid,=0D + {{=0D + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister,=0D + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister,=0D + (UINTN) PchSmmPeriodicTimerDispatchGetNextShorterInterval=0D + }}=0D + },=0D + }=0D +};=0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONTEXT_FUNCTIONS mContextFunctions[PCH_= SMM_PROTOCOL_TYPE_MAX] =3D {=0D + {=0D + NULL,=0D + NULL,=0D + NULL=0D + },=0D + {=0D + SxGetContext,=0D + SxCmpContext,=0D + NULL=0D + },=0D + {=0D + NULL,=0D + NULL,=0D + NULL=0D + },=0D + {=0D + NULL,=0D + NULL,=0D + NULL=0D + },=0D + {=0D + PowerButtonGetContext,=0D + PowerButtonCmpContext,=0D + NULL=0D + },=0D + {=0D + PeriodicTimerGetContext,=0D + PeriodicTimerCmpContext,=0D + PeriodicTimerGetCommBuffer=0D + },=0D +};=0D +=0D +//=0D +// PROTOTYPES=0D +//=0D +// Functions use only in this file=0D +//=0D +EFI_STATUS=0D +EFIAPI=0D +PchSmmCoreDispatcher (=0D + IN EFI_HANDLE SmmImageHandle,=0D + IN CONST VOID *PchSmmCore, OPTIONAL=0D + IN OUT VOID *CommunicationBuffer,=0D + IN OUT UINTN *SourceSize=0D + );=0D +=0D +//=0D +// FUNCTIONS=0D +//=0D +/**=0D + SMM ready to lock notification event handler.=0D +=0D + @param Protocol Points to the protocol's unique identifier=0D + @param Interface Points to the interface instance=0D + @param Handle The handle on which the interface was installed=0D +=0D + @retval EFI_SUCCESS SmmReadyToLockCallback runs successfully=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +SmmReadyToLockCallback (=0D + IN CONST EFI_GUID *Protocol,=0D + IN VOID *Interface,=0D + IN EFI_HANDLE Handle=0D + )=0D +{=0D + mReadyToLock =3D TRUE;=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + PchSmiDispatcher SMM Module Entry Point\n=0D + - Introduction\n=0D + The PchSmiDispatcher module is an SMM driver which provides SMI handl= er registration=0D + services for PCH generated SMIs.=0D +=0D + - Details\n=0D + This module provides SMI handler registration servicies for PCH SMIs.= =0D + NOTE: All the register/unregister functions will be locked after SMM r= eady to boot signal event.=0D + Please make sure no handler is installed after that.=0D +=0D + - @pre=0D + - EFI_SMM_BASE2_PROTOCOL=0D + - Documented in the System Management Mode Core Interface Specificat= ion=0D + - EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL=0D + - Documented in the UEFI 2.0 Specification and above=0D + - EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL=0D + - This is to ensure that PCI MMIO and IO resource has been prepared = and available for this driver to allocate.=0D + - EFI_SMM_CPU_PROTOCOL=0D +=0D + - @result=0D + The PchSmiDispatcher driver produces:=0D + - EFI_SMM_USB_DISPATCH2_PROTOCOL=0D + - EFI_SMM_SX_DISPATCH2_PROTOCOL=0D + - EFI_SMM_SW_DISPATCH2_PROTOCOL=0D + - EFI_SMM_GPI_DISPATCH2_PROTOCOL=0D + - EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL=0D + - EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL=0D + - EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL=0D + - @link _PCH_SMM_IO_TRAP_CONTROL_PROTOCOL PCH_SMM_IO_TRAP_CONTROL_PROT= OCOL @endlink=0D + - @link _PCH_PCIE_SMI_DISPATCH_PROTOCOL PCH_PCIE_SMI_DISPATCH_PROTOCOL= @endlink=0D + - @link _PCH_TCO_SMI_DISPATCH_PROTOCOL PCH_TCO_SMI_DISPATCH_PROTOCOL @= endlink=0D + - @link _PCH_ACPI_SMI_DISPATCH_PROTOCOL PCH_ACPI_SMI_DISPATCH_PROTOCOL= @endlink=0D + - @link _PCH_SMI_DISPATCH_PROTOCOL PCH_SMI_DISPATCH_PROTOCOL @endlink= =0D + - @link _PCH_ESPI_SMI_DISPATCH_PROTOCOL PCH_ESPI_SMI_DISPATCH_PROTOCOL= @endlink=0D +=0D + @param[in] ImageHandle Pointer to the loaded image protocol for= this driver=0D + @param[in] SystemTable Pointer to the EFI System Table=0D +=0D + @retval EFI_SUCCESS PchSmmDispatcher Initialization complete= d.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +InitializePchSmmDispatcher (=0D + IN EFI_HANDLE ImageHandle,=0D + IN EFI_SYSTEM_TABLE *SystemTable=0D + )=0D +{=0D + EFI_STATUS Status;=0D + VOID *SmmReadyToLockRegistration;=0D +=0D + mS3SusStart =3D FALSE;=0D + //=0D + // Access ACPI Base Addresses Register=0D + //=0D +=0D + mAcpiBaseAddr =3D PmcGetAcpiBase ();=0D + ASSERT (mAcpiBaseAddr !=3D 0);=0D +=0D + //=0D + // Access TCO Base Addresses Register=0D + //=0D + PchTcoBaseGet (&mTcoBaseAddr);=0D + ASSERT (mTcoBaseAddr !=3D 0);=0D +=0D + //=0D + // Register a callback function to handle subsequent SMIs. This callbac= k=0D + // will be called by SmmCoreDispatcher.=0D + //=0D + Status =3D gSmst->SmiHandlerRegister (PchSmmCoreDispatcher, NULL, &mPriv= ateData.SmiHandle);=0D + ASSERT_EFI_ERROR (Status);=0D + //=0D + // Initialize Callback DataBase=0D + //=0D + InitializeListHead (&mPrivateData.CallbackDataBase);=0D +=0D + //=0D + // Enable SMIs on the PCH now that we have a callback=0D + //=0D + PchSmmInitHardware ();=0D +=0D + //=0D + // Install and initialize all the needed protocols=0D + //=0D + PchSwDispatchInit ();=0D + PchSmmPublishDispatchProtocols ();=0D + InstallPchSmiDispatchProtocols ();=0D + InstallIoTrap (ImageHandle);=0D + InstallEspiSmi (ImageHandle);=0D + InstallPchSmmPeriodicTimerControlProtocol (mPrivateData.InstallMultProtH= andle);=0D +=0D + //=0D + // Register EFI_SMM_READY_TO_LOCK_PROTOCOL_GUID notify function.=0D + //=0D + Status =3D gSmst->SmmRegisterProtocolNotify (=0D + &gEfiSmmReadyToLockProtocolGuid,=0D + SmmReadyToLockCallback,=0D + &SmmReadyToLockRegistration=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + The internal function used to create and insert a database record=0D +=0D + @param[in] InsertRecord Record to insert to database.=0D + @param[out] DispatchHandle Handle of dispatch function to reg= ister.=0D +=0D + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion=0D + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record=0D + @retval EFI_SUCCESS The database record is created suc= cessfully.=0D +**/=0D +EFI_STATUS=0D +SmmCoreInsertRecord (=0D + IN DATABASE_RECORD *NewRecord,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + DATABASE_RECORD *Record;=0D +=0D + if ((NewRecord =3D=3D NULL) ||=0D + (NewRecord->Signature !=3D DATABASE_RECORD_SIGNATURE))=0D + {=0D + ASSERT (FALSE);=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + Status =3D gSmst->SmmAllocatePool (EfiRuntimeServicesData, sizeof (DATAB= ASE_RECORD), (VOID **) &Record);=0D + if (EFI_ERROR (Status)) {=0D + ASSERT (FALSE);=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D + CopyMem (Record, NewRecord, sizeof (DATABASE_RECORD));=0D +=0D + //=0D + // After ensuring the source of event is not null, we will insert the re= cord into the database=0D + //=0D + InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);=0D +=0D + //=0D + // Child's handle will be the address linked list link in the record=0D + //=0D + *DispatchHandle =3D (EFI_HANDLE) (&Record->Link);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Unregister a child SMI source dispatch function with a parent SMM driver= =0D +=0D + @param[in] This Protocol instance pointer.=0D + @param[in] DispatchHandle Handle of dispatch function to der= egister.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been suc= cessfully=0D + unregistered and the SMI source ha= s been disabled=0D + if there are no other registered c= hild dispatch=0D + functions for this SMI source.=0D + @retval EFI_INVALID_PARAMETER Handle is invalid.=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchPiSmmCoreUnRegister (=0D + IN PCH_SMM_GENERIC_PROTOCOL *This,=0D + IN EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + DATABASE_RECORD *RecordToDelete;=0D + EFI_STATUS Status;=0D + PCH_SMM_QUALIFIED_PROTOCOL *Qualified;=0D +=0D + Qualified =3D QUALIFIED_PROTOCOL_FROM_GENERIC (This);=0D + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle);=0D + Status =3D PchSmmCoreUnRegister (NULL, DispatchHandle);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileUnregisterHandler (=0D + Qualified->Guid,=0D + RecordToDelete->Callback,=0D + &RecordToDelete->ChildContext,=0D + RecordToDelete->ContextSize=0D + );=0D + }=0D + return Status;=0D +}=0D +=0D +/**=0D + Register a child SMI dispatch function with a parent SMM driver.=0D +=0D + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL = instance.=0D + @param[in] DispatchFunction Pointer to dispatch function to be invok= ed for this SMI source.=0D + @param[in] DispatchContext Pointer to the dispatch function's conte= xt.=0D + @param[out] DispatchHandle Handle of dispatch function, for when in= terfacing=0D + with the parent SMM driver, will be the = address of linked=0D + list link in the call back record.=0D +=0D + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create databas= e record=0D + @retval EFI_INVALID_PARAMETER The input parameter is invalid=0D + @retval EFI_SUCCESS The dispatch function has been successfu= lly=0D + registered and the SMI source has been e= nabled.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchPiSmmCoreRegister (=0D + IN PCH_SMM_GENERIC_PROTOCOL *This,=0D + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,= =0D + IN PCH_SMM_CONTEXT *DispatchContext,= =0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + DATABASE_RECORD Record;=0D + PCH_SMM_QUALIFIED_PROTOCOL *Qualified;=0D + PCH_SMM_SOURCE_DESC NullSourceDesc;=0D +=0D + //=0D + // Initialize NullSourceDesc=0D + //=0D + NullInitSourceDesc (&NullSourceDesc);=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the EndOfDxe event ha= s been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + ZeroMem (&Record, sizeof (DATABASE_RECORD));=0D +=0D + //=0D + // Gather information about the registration request=0D + //=0D + Record.Callback =3D DispatchFunction;=0D +=0D + Qualified =3D QUALIFIED_PROTOCOL_FROM_GENERIC (This);=0D +=0D + Record.ProtocolType =3D Qualified->Type;=0D +=0D + Record.ContextFunctions =3D mContextFunctions[Qualified->Type];=0D + //=0D + // Perform linked list housekeeping=0D + //=0D + Record.Signature =3D DATABASE_RECORD_SIGNATURE;=0D +=0D + switch (Qualified->Type) {=0D + //=0D + // By the end of this switch statement, we'll know the=0D + // source description the child is registering for=0D + //=0D + case UsbType:=0D + Record.ContextSize =3D sizeof (EFI_SMM_USB_REGISTER_CONTEXT);=0D + CopyMem (&Record.ChildContext, DispatchContext, Record.ContextSize);= =0D + //=0D + // Check the validity of Context Type=0D + //=0D + if ((Record.ChildContext.Usb.Type < UsbLegacy) || (Record.ChildConte= xt.Usb.Type > UsbWake)) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + MapUsbToSrcDesc (DispatchContext, &Record.SrcDesc);=0D + Record.ClearSource =3D NULL;=0D + //=0D + // use default clear source function=0D + //=0D + break;=0D +=0D + case SxType:=0D + Record.ContextSize =3D sizeof (EFI_SMM_SX_REGISTER_CONTEXT);=0D + CopyMem (&Record.ChildContext, DispatchContext, Record.ContextSize);= =0D + //=0D + // Check the validity of Context Type and Phase=0D + //=0D + if ((Record.ChildContext.Sx.Type < SxS0) ||=0D + (Record.ChildContext.Sx.Type >=3D EfiMaximumSleepType) ||=0D + (Record.ChildContext.Sx.Phase < SxEntry) ||=0D + (Record.ChildContext.Sx.Phase >=3D EfiMaximumPhase)=0D + ) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + CopyMem (&Record.SrcDesc, &mSxSourceDesc, sizeof (PCH_SMM_SOURCE_DES= C));=0D + Record.ClearSource =3D NULL;=0D + //=0D + // use default clear source function=0D + //=0D + break;=0D +=0D + case PowerButtonType:=0D + Record.ContextSize =3D sizeof (EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT= );=0D + CopyMem (&Record.ChildContext, DispatchContext, Record.ContextSize);= =0D + //=0D + // Check the validity of Context Phase=0D + //=0D + if ((Record.ChildContext.PowerButton.Phase < EfiPowerButtonEntry) ||= =0D + (Record.ChildContext.PowerButton.Phase > EfiPowerButtonExit))=0D + {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + CopyMem (&Record.SrcDesc, &mPowerButtonSourceDesc, sizeof (PCH_SMM_S= OURCE_DESC));=0D + Record.ClearSource =3D NULL;=0D + //=0D + // use default clear source function=0D + //=0D + break;=0D +=0D + case PeriodicTimerType:=0D + Record.ContextSize =3D sizeof (EFI_SMM_PERIODIC_TIMER_REGISTER_CONTE= XT);=0D + CopyMem (&Record.ChildContext, DispatchContext, Record.ContextSize);= =0D + //=0D + // Check the validity of timer value=0D + //=0D + if (DispatchContext->PeriodicTimer.SmiTickInterval <=3D 0) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + MapPeriodicTimerToSrcDesc (DispatchContext, &Record.SrcDesc);=0D + Record.MiscData.TimerSmiEnabled =3D TRUE;=0D + Record.ClearSource =3D PchSmmPeriodicTimerClearSource;=0D + break;=0D +=0D + default:=0D + return EFI_INVALID_PARAMETER;=0D + break;=0D + }=0D +=0D + if (CompareSources (&Record.SrcDesc, &NullSourceDesc)) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + //=0D + // After ensuring the source of event is not null, we will insert the re= cord into the database=0D + // Child's handle will be the address linked list link in the record=0D + //=0D + Status =3D SmmCoreInsertRecord (=0D + &Record,=0D + DispatchHandle=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + if (Record.ClearSource =3D=3D NULL) {=0D + //=0D + // Clear the SMI associated w/ the source using the default function=0D + //=0D + PchSmmClearSource (&Record.SrcDesc);=0D + } else {=0D + //=0D + // This source requires special handling to clear=0D + //=0D + Record.ClearSource (&Record.SrcDesc);=0D + }=0D +=0D + PchSmmEnableSource (&Record.SrcDesc);=0D + SmiHandlerProfileRegisterHandler (=0D + Qualified->Guid,=0D + DispatchFunction,=0D + (UINTN)RETURN_ADDRESS (0),=0D + DispatchContext,=0D + Record.ContextSize=0D + );=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Unregister a child SMI source dispatch function with a parent SMM driver= .=0D +=0D + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL = instance.=0D + @param[in] DispatchHandle Handle of dispatch function to deregiste= r.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been successfu= lly=0D + unregistered and the SMI source has been= disabled=0D + if there are no other registered child d= ispatch=0D + functions for this SMI source.=0D + @retval EFI_INVALID_PARAMETER Handle is invalid.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchSmmCoreUnRegister (=0D + IN PCH_SMM_GENERIC_PROTOCOL *This,=0D + IN EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + BOOLEAN NeedClearEnable;=0D + UINTN DescIndex;=0D + DATABASE_RECORD *RecordToDelete;=0D + DATABASE_RECORD *RecordInDb;=0D + LIST_ENTRY *LinkInDb;=0D +=0D + if (DispatchHandle =3D=3D NULL) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock = event has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle);=0D +=0D + //=0D + // Take the entry out of the linked list=0D + //=0D + if (RecordToDelete->Link.ForwardLink =3D=3D (LIST_ENTRY *) EFI_BAD_POINT= ER) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + RemoveEntryList (&RecordToDelete->Link);=0D +=0D + //=0D + // Loop through all the souces in record linked list to see if any sourc= e enable is equal.=0D + // If any source enable is equal, we do not want to disable it.=0D + //=0D + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; ++DescIndex) {=0D + if (IS_BIT_DESC_NULL (RecordToDelete->SrcDesc.En[DescIndex])) {=0D + continue;=0D + }=0D + NeedClearEnable =3D TRUE;=0D + LinkInDb =3D GetFirstNode (&mPrivateData.CallbackDataBase);=0D + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {=0D + RecordInDb =3D DATABASE_RECORD_FROM_LINK (LinkInDb);=0D + if (IsBitEqualToAnySourceEn (&RecordToDelete->SrcDesc.En[DescIndex],= &RecordInDb->SrcDesc)) {=0D + NeedClearEnable =3D FALSE;=0D + break;=0D + }=0D + LinkInDb =3D GetNextNode (&mPrivateData.CallbackDataBase, &RecordInD= b->Link);=0D + }=0D + if (NeedClearEnable =3D=3D FALSE) {=0D + continue;=0D + }=0D + WriteBitDesc (&RecordToDelete->SrcDesc.En[DescIndex], 0, FALSE);=0D + }=0D + Status =3D gSmst->SmmFreePool (RecordToDelete);=0D + if (EFI_ERROR (Status)) {=0D + ASSERT (FALSE);=0D + return Status;=0D + }=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + This function clears the pending SMI status before set EOS.=0D + NOTE: This only clears the pending SMI with known reason.=0D + Please do not clear unknown pending SMI status since that will hid= e potential issues.=0D +=0D + @param[in] SmiStsValue SMI status=0D + @param[in] SciEn Sci Enable status=0D +**/=0D +STATIC=0D +VOID=0D +ClearPendingSmiStatus (=0D + UINT32 SmiStsValue,=0D + BOOLEAN SciEn=0D + )=0D +{=0D + //=0D + // Clear NewCentury status if it's not handled.=0D + //=0D + if (SmiStsValue & B_ACPI_IO_SMI_STS_TCO) {=0D + if (IoRead16 (mTcoBaseAddr + R_TCO_IO_TCO1_STS) & B_TCO_IO_TCO1_STS_NE= WCENTURY) {=0D + PchTcoSmiClearSourceAndBlock (&mSrcDescNewCentury);=0D + }=0D + }=0D + // Clear PWRBTNOR_STS if it's not handled.=0D + //=0D + if (IoRead16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS) & B_ACPI_IO_PM1_STS_PRB= TNOR) {=0D + IoWrite16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS, B_ACPI_IO_PM1_STS_PRBTNO= R);=0D + }=0D + //=0D + // Clear WADT_STS if this is triggered by WADT timer.=0D + //=0D + if (!SciEn) {=0D + if (IoRead32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96) & B_ACPI_IO_G= PE0_STS_127_96_WADT) {=0D + IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96, B_ACPI_IO_GPE0= _STS_127_96_WADT);=0D + }=0D + }=0D + //=0D + // Clear GPIO_UNLOCK_SMI_STS in case it is set as GPIO Unlock SMI is not= supported=0D + //=0D + if (SmiStsValue & B_ACPI_IO_SMI_STS_GPIO_UNLOCK) {=0D + IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_SMI_STS, B_ACPI_IO_SMI_STS_GPIO_U= NLOCK);=0D + }=0D +}=0D +=0D +/**=0D + The callback function to handle subsequent SMIs. This callback will be = called by SmmCoreDispatcher.=0D +=0D + @param[in] SmmImageHandle Not used=0D + @param[in] PchSmmCore Not used=0D + @param[in, out] CommunicationBuffer Not used=0D + @param[in, out] SourceSize Not used=0D +=0D + @retval EFI_SUCCESS Function successfully completed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchSmmCoreDispatcher (=0D + IN EFI_HANDLE SmmImageHandle,=0D + IN CONST VOID *PchSmmCore,=0D + IN OUT VOID *CommunicationBuffer,=0D + IN OUT UINTN *SourceSize=0D + )=0D +{=0D + //=0D + // Used to prevent infinite loops=0D + //=0D + UINTN EscapeCount;=0D +=0D + BOOLEAN ContextsMatch;=0D + BOOLEAN EosSet;=0D + BOOLEAN SxChildWasDispatched;=0D +=0D + DATABASE_RECORD *RecordInDb;=0D + LIST_ENTRY *LinkInDb;=0D + DATABASE_RECORD *RecordToExhaust;=0D + LIST_ENTRY *LinkToExhaust;=0D +=0D + PCH_SMM_CONTEXT Context;=0D + VOID *CommBuffer;=0D + UINTN CommBufferSize;=0D +=0D + EFI_STATUS Status;=0D + BOOLEAN SciEn;=0D + UINT32 SmiEnValue;=0D + UINT32 SmiStsValue;=0D + UINT8 Port74Save;=0D + UINT8 Port76Save;=0D +=0D + PCH_SMM_SOURCE_DESC ActiveSource;=0D +=0D + //=0D + // Initialize ActiveSource=0D + //=0D + NullInitSourceDesc (&ActiveSource);=0D +=0D + EscapeCount =3D 3;=0D + ContextsMatch =3D FALSE;=0D + EosSet =3D FALSE;=0D + SxChildWasDispatched =3D FALSE;=0D + Status =3D EFI_SUCCESS;=0D +=0D + //=0D + // Save IO index registers=0D + // @note: Save/Restore port 70h directly might break NMI_EN# setting,=0D + // then save/restore 74h/76h instead.=0D + // @note: CF8 is not saved. Prefer method is to use MMIO instead of CF8= =0D + //=0D + Port76Save =3D IoRead8 (R_RTC_IO_EXT_INDEX_ALT);=0D + Port74Save =3D IoRead8 (R_RTC_IO_INDEX_ALT);=0D +=0D + if (!IsListEmpty (&mPrivateData.CallbackDataBase)) {=0D + //=0D + // We have children registered w/ us -- continue=0D + //=0D + while ((!EosSet) && (EscapeCount > 0)) {=0D + EscapeCount--;=0D +=0D + LinkInDb =3D GetFirstNode (&mPrivateData.CallbackDataBase);=0D +=0D + //=0D + // Cache SciEn, SmiEnValue and SmiStsValue to determine if source is= active=0D + //=0D + SciEn =3D PchSmmGetSciEn ();=0D + SmiEnValue =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN)= );=0D + SmiStsValue =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_STS= ));=0D +=0D + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {=0D + RecordInDb =3D DATABASE_RECORD_FROM_LINK (LinkInDb);=0D +=0D + //=0D + // look for the first active source=0D + //=0D + if (!SourceIsActive (&RecordInDb->SrcDesc, SciEn, SmiEnValue, SmiS= tsValue)) {=0D + //=0D + // Didn't find the source yet, keep looking=0D + //=0D + LinkInDb =3D GetNextNode (&mPrivateData.CallbackDataBase, &Recor= dInDb->Link);=0D +=0D + //=0D + // if it's the last one, try to clear EOS=0D + //=0D + if (IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {=0D + //=0D + // Clear pending SMI status before EOS=0D + //=0D + ClearPendingSmiStatus (SmiStsValue, SciEn);=0D + EosSet =3D PchSmmSetAndCheckEos ();=0D + }=0D + } else {=0D + //=0D + // We found a source. If this is a sleep type, we have to go to= =0D + // appropriate sleep state anyway.No matter there is sleep child= or not=0D + //=0D + if (RecordInDb->ProtocolType =3D=3D SxType) {=0D + SxChildWasDispatched =3D TRUE;=0D + }=0D + //=0D + // "cache" the source description and don't query I/O anymore=0D + //=0D + CopyMem ((VOID *) &ActiveSource, (VOID *) &(RecordInDb->SrcDesc)= , sizeof (PCH_SMM_SOURCE_DESC));=0D + LinkToExhaust =3D LinkInDb;=0D +=0D + //=0D + // exhaust the rest of the queue looking for the same source=0D + //=0D + while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)) = {=0D + RecordToExhaust =3D DATABASE_RECORD_FROM_LINK (LinkToExhaust);= =0D + //=0D + // RecordToExhaust->Link might be removed (unregistered) by Ca= llback function, and then the=0D + // system will hang in ASSERT() while calling GetNextNode().=0D + // To prevent the issue, we need to get next record in DB here= (before Callback function).=0D + //=0D + LinkToExhaust =3D GetNextNode (&mPrivateData.CallbackDataBase,= &RecordToExhaust->Link);=0D +=0D + if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource))= {=0D + //=0D + // These source descriptions are equal, so this callback sho= uld be=0D + // dispatched.=0D + //=0D + if (RecordToExhaust->ContextFunctions.GetContext !=3D NULL) = {=0D + //=0D + // This child requires that we get a calling context from= =0D + // hardware and compare that context to the one supplied=0D + // by the child.=0D + //=0D + ASSERT (RecordToExhaust->ContextFunctions.CmpContext !=3D = NULL);=0D +=0D + //=0D + // Make sure contexts match before dispatching event to ch= ild=0D + //=0D + RecordToExhaust->ContextFunctions.GetContext (RecordToExha= ust, &Context);=0D + ContextsMatch =3D RecordToExhaust->ContextFunctions.CmpCon= text (&Context, &RecordToExhaust->ChildContext);=0D +=0D + } else {=0D + //=0D + // This child doesn't require any more calling context bey= ond what=0D + // it supplied in registration. Simply pass back what it = gave us.=0D + //=0D + Context =3D RecordToExhaust->ChildContext;=0D + ContextsMatch =3D TRUE;=0D + }=0D +=0D + if (ContextsMatch) {=0D + if (RecordToExhaust->ProtocolType =3D=3D PchSmiDispatchTyp= e) {=0D + //=0D + // For PCH SMI dispatch protocols=0D + //=0D + PchSmiTypeCallbackDispatcher (RecordToExhaust);=0D + } else {=0D + if ((RecordToExhaust->ProtocolType =3D=3D SxType) && (Co= ntext.Sx.Type =3D=3D SxS3) && (Context.Sx.Phase =3D=3D SxEntry) && !mS3SusS= tart) {=0D + REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PROGRESS_CODE_S= 3_SUSPEND_START);=0D + mS3SusStart =3D TRUE;=0D + }=0D + //=0D + // For EFI standard SMI dispatch protocols=0D + //=0D + if (RecordToExhaust->Callback !=3D NULL) {=0D + if (RecordToExhaust->ContextFunctions.GetCommBuffer != =3D NULL) {=0D + //=0D + // This callback function needs CommBuffer and CommB= ufferSize.=0D + // Get those from child and then pass to callback fu= nction.=0D + //=0D + RecordToExhaust->ContextFunctions.GetCommBuffer (Rec= ordToExhaust, &CommBuffer, &CommBufferSize);=0D + } else {=0D + //=0D + // Child doesn't support the CommBuffer and CommBuff= erSize.=0D + // Just pass NULL value to callback function.=0D + //=0D + CommBuffer =3D NULL;=0D + CommBufferSize =3D 0;=0D + }=0D +=0D + PERF_START_EX (NULL, "SmmFunction", NULL, AsmReadTsc (= ), RecordToExhaust->ProtocolType);=0D + RecordToExhaust->Callback ((EFI_HANDLE) & RecordToExha= ust->Link, &Context, CommBuffer, &CommBufferSize);=0D + PERF_END_EX (NULL, "SmmFunction", NULL, AsmReadTsc (),= RecordToExhaust->ProtocolType);=0D + if (RecordToExhaust->ProtocolType =3D=3D SxType) {=0D + SxChildWasDispatched =3D TRUE;=0D + }=0D + } else {=0D + ASSERT (FALSE);=0D + }=0D + }=0D + }=0D + }=0D + }=0D +=0D + if (RecordInDb->ClearSource =3D=3D NULL) {=0D + //=0D + // Clear the SMI associated w/ the source using the default fu= nction=0D + //=0D + PchSmmClearSource (&ActiveSource);=0D + } else {=0D + //=0D + // This source requires special handling to clear=0D + //=0D + RecordInDb->ClearSource (&ActiveSource);=0D + }=0D + //=0D + // Clear pending SMI status before EOS=0D + //=0D + ClearPendingSmiStatus (SmiStsValue, SciEn);=0D + //=0D + // Also, try to clear EOS=0D + //=0D + EosSet =3D PchSmmSetAndCheckEos ();=0D + //=0D + // Queue is empty, reset the search=0D + //=0D + break;=0D + }=0D + }=0D + }=0D + }=0D + //=0D + // If you arrive here, there are two possible reasons:=0D + // (1) you've got problems with clearing the SMI status bits in the=0D + // ACPI table. If you don't properly clear the SMI bits, then you won't= be able to set the=0D + // EOS bit. If this happens too many times, the loop exits.=0D + // (2) there was a SMM communicate for callback messages that was receiv= ed prior=0D + // to this driver.=0D + // If there is an asynchronous SMI that occurs while processing the Call= back, let=0D + // all of the drivers (including this one) have an opportunity to scan f= or the SMI=0D + // and handle it.=0D + // If not, we don't want to exit and have the foreground app. clear EOS = without letting=0D + // these other sources get serviced.=0D + //=0D + // This assert is not valid with CSM legacy solution because it generate= s software SMI=0D + // to test for legacy USB support presence.=0D + // This may not be illegal, so we cannot assert at this time.=0D + //=0D + // ASSERT (EscapeCount > 0);=0D + //=0D + if (SxChildWasDispatched) {=0D + //=0D + // A child of the SmmSxDispatch protocol was dispatched during this ca= ll;=0D + // put the system to sleep.=0D + //=0D + PchSmmSxGoToSleep ();=0D + }=0D + //=0D + // Restore IO index registers=0D + // @note: Save/Restore port 70h directly might break NMI_EN# setting,=0D + // then save/restore 74h/76h instead.=0D + //=0D + IoWrite8 (R_RTC_IO_EXT_INDEX_ALT, Port76Save);=0D + IoWrite8 (R_RTC_IO_INDEX_ALT, Port74Save);=0D +=0D + return Status;=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmmEspi.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchS= mmEspi.c new file mode 100644 index 0000000000..9ce4072e37 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi= .c @@ -0,0 +1,1588 @@ +/** @file=0D + eSPI SMI implementation=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +=0D +#include "PchSmmEspi.h"=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED ESPI_SMI_INSTANCE mEspiSmiInstance =3D {=0D + //=0D + // Signature=0D + //=0D + ESPI_SMI_INSTANCE_SIGNATURE,=0D + //=0D + // Handle=0D + //=0D + NULL,=0D + //=0D + // PchEspiSmiDispatchProtocol=0D + //=0D + {=0D + PCH_ESPI_SMI_DISPATCH_REVISION,=0D + EspiSmiUnRegister,=0D + BiosWrProtectRegister,=0D + BiosWrReportRegister,=0D + PcNonFatalErrRegister,=0D + PcFatalErrRegister,=0D + VwNonFatalErrRegister,=0D + VwFatalErrRegister,=0D + FlashNonFatalErrRegister,=0D + FlashFatalErrRegister,=0D + LnkType1ErrRegister,=0D + EspiSlaveSmiRegister=0D + },=0D + //=0D + // PchSmiEspiHandle[EspiTopLevelTypeMax]=0D + //=0D + {=0D + NULL, NULL, NULL=0D + },=0D + //=0D + // CallbackDataBase[EspiSmiTypeMax]=0D + //=0D + {=0D + {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL},= =0D + {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL}=0D + },=0D + //=0D + // EspiSmiEventCounter[EspiSmiTypeMax]=0D + //=0D + {=0D + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0=0D + },=0D + //=0D + // Barrier[EspiTopLevelTypeMax]=0D + //=0D + {=0D + {=0D + BiosWrProtect,=0D + BiosWrProtect=0D + },=0D + {=0D + BiosWrReport,=0D + LnkType1Err=0D + },=0D + {=0D + EspiSlaveSmi,=0D + EspiSlaveSmi=0D + }=0D + }=0D +};=0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST ESPI_DESCRIPTOR mEspiDescriptor[EspiSm= iTypeMax] =3D {=0D + //=0D + // BiosWrProtect=0D + //=0D + {=0D + {=0D + PCIE_ADDR_TYPE,=0D + { (=0D + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |=0D + (PCI_DEVICE_NUMBER_PCH_LPC << 19) |=0D + (PCI_FUNCTION_NUMBER_PCH_LPC << 16) |=0D + R_ESPI_CFG_PCBC=0D + ) }=0D + },=0D + //=0D + // SourceIsActiveAndMask and SourceIsActiveValue=0D + //=0D + B_ESPI_CFG_PCBC_BWPDS | B_ESPI_CFG_PCBC_LE,=0D + B_ESPI_CFG_PCBC_BWPDS | B_ESPI_CFG_PCBC_LE,=0D + //=0D + // ClearStatusAndMask and ClearStatusOrMask=0D + //=0D + (UINT32) ~B_ESPI_CFG_PCBC_BWRS,=0D + B_ESPI_CFG_PCBC_BWPDS=0D + },=0D + //=0D + // BiosWrReport=0D + //=0D + {=0D + {=0D + PCIE_ADDR_TYPE,=0D + { (=0D + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |=0D + (PCI_DEVICE_NUMBER_PCH_LPC << 19) |=0D + (PCI_FUNCTION_NUMBER_PCH_LPC << 16) |=0D + R_ESPI_CFG_PCBC=0D + ) }=0D + },=0D + B_ESPI_CFG_PCBC_BWRS | B_ESPI_CFG_PCBC_BWRE,=0D + B_ESPI_CFG_PCBC_BWRS | B_ESPI_CFG_PCBC_BWRE,=0D + (UINT32) ~B_ESPI_CFG_PCBC_BWPDS,=0D + B_ESPI_CFG_PCBC_BWRS=0D + },=0D + //=0D + // PcNonFatalErr=0D + //=0D + {=0D + {=0D + PCR_ADDR_TYPE,=0D + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_PCERR_SLV0) }=0D + },=0D + (B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XNFEE),=0D + (B_ESPI_PCR_XERR_XNFES | (V_ESPI_PCR_XERR_XNFEE_SMI << N_ESPI_PCR_XERR= _XNFEE)),=0D + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | B_ESPI_PCR_XERR_XFES),=0D + B_ESPI_PCR_XERR_XNFES=0D + },=0D + //=0D + // PcFatalErr=0D + //=0D + {=0D + {=0D + PCR_ADDR_TYPE,=0D + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_PCERR_SLV0) }=0D + },=0D + (B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE),=0D + (B_ESPI_PCR_XERR_XFES | (V_ESPI_PCR_XERR_XFEE_SMI << N_ESPI_PCR_XERR_X= FEE)),=0D + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | B_ESPI_PCR_XERR_XNFES),=0D + B_ESPI_PCR_XERR_XFES=0D + },=0D + //=0D + // VwNonFatalErr=0D + //=0D + {=0D + {=0D + PCR_ADDR_TYPE,=0D + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_VWERR_SLV0) }=0D + },=0D + (B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XNFEE),=0D + (B_ESPI_PCR_XERR_XNFES | (V_ESPI_PCR_XERR_XNFEE_SMI << N_ESPI_PCR_XERR= _XNFEE)),=0D + (UINT32) ~B_ESPI_PCR_XERR_XFES,=0D + B_ESPI_PCR_XERR_XNFES=0D + },=0D + //=0D + // VwFatalErr=0D + //=0D + {=0D + {=0D + PCR_ADDR_TYPE,=0D + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_VWERR_SLV0) }=0D + },=0D + (B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE),=0D + (B_ESPI_PCR_XERR_XFES | (V_ESPI_PCR_XERR_XFEE_SMI << N_ESPI_PCR_XERR_X= FEE)),=0D + (UINT32) ~B_ESPI_PCR_XERR_XNFES,=0D + B_ESPI_PCR_XERR_XFES=0D + },=0D + //=0D + // FlashNonFatalErr=0D + //=0D + {=0D + {=0D + PCR_ADDR_TYPE,=0D + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_FCERR_SLV0) }=0D + },=0D + (B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XNFEE),=0D + (B_ESPI_PCR_XERR_XNFES | (V_ESPI_PCR_XERR_XNFEE_SMI << N_ESPI_PCR_XERR= _XNFEE)),=0D + (UINT32) ~B_ESPI_PCR_XERR_XFES,=0D + B_ESPI_PCR_XERR_XNFES=0D + },=0D + //=0D + // FlashFatalErr=0D + //=0D + {=0D + {=0D + PCR_ADDR_TYPE,=0D + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_FCERR_SLV0) }=0D + },=0D + (B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE),=0D + (B_ESPI_PCR_XERR_XFES | (V_ESPI_PCR_XERR_XFEE_SMI << N_ESPI_PCR_XERR_X= FEE)),=0D + (UINT32) ~B_ESPI_PCR_XERR_XNFES,=0D + B_ESPI_PCR_XERR_XFES=0D + },=0D + //=0D + // LnkType1Err=0D + //=0D + {=0D + {=0D + PCR_ADDR_TYPE,=0D + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_LNKERR_SLV0) }=0D + },=0D + B_ESPI_PCR_LNKERR_SLV0_LFET1S | B_ESPI_PCR_LNKERR_SLV0_LFET1E,=0D + B_ESPI_PCR_LNKERR_SLV0_LFET1S | (V_ESPI_PCR_LNKERR_SLV0_LFET1E_SMI << = N_ESPI_PCR_LNKERR_SLV0_LFET1E),=0D + (UINT32) ~B_ESPI_PCR_LNKERR_SLV0_SLCRR,=0D + B_ESPI_PCR_LNKERR_SLV0_LFET1S=0D + },=0D +};=0D +=0D +/**=0D + Enable eSPI SMI source=0D +=0D + @param[in] EspiSmiType Type based on ESPI_SMI_TYPE=0D +**/=0D +STATIC=0D +VOID=0D +EspiSmiEnableSource (=0D + IN CONST ESPI_SMI_TYPE EspiSmiType=0D + )=0D +{=0D + UINT64 PciBaseAddress;=0D +=0D + switch (EspiSmiType) {=0D + case BiosWrProtect:=0D + //=0D + // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE.= =0D + //=0D + break;=0D + case BiosWrReport:=0D + PciBaseAddress =3D EspiPciCfgBase ();=0D + PciSegmentAndThenOr32 (=0D + PciBaseAddress + R_ESPI_CFG_PCBC,=0D + (UINT32) ~(B_ESPI_CFG_PCBC_BWRS | B_ESPI_CFG_PCBC_BWPDS),=0D + B_ESPI_CFG_PCBC_BWRE=0D + );=0D + break;=0D + case PcNonFatalErr:=0D + PchPcrAndThenOr32 (=0D + PID_ESPISPI,=0D + (UINT16) R_ESPI_PCR_PCERR_SLV0,=0D + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | B_ESPI_PCR_XERR_XNFES | B= _ESPI_PCR_XERR_XFES),=0D + B_ESPI_PCR_XERR_XNFEE=0D + );=0D + break;=0D +=0D + case PcFatalErr:=0D + PchPcrAndThenOr32 (=0D + PID_ESPISPI,=0D + (UINT16) R_ESPI_PCR_PCERR_SLV0,=0D + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | B_ESPI_PCR_XERR_XNFES | B= _ESPI_PCR_XERR_XFES),=0D + B_ESPI_PCR_XERR_XFEE=0D + );=0D + break;=0D +=0D + case VwNonFatalErr:=0D + PchPcrAndThenOr32 (=0D + PID_ESPISPI,=0D + (UINT16) R_ESPI_PCR_VWERR_SLV0,=0D + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),=0D + B_ESPI_PCR_XERR_XNFEE=0D + );=0D + break;=0D +=0D + case VwFatalErr:=0D + PchPcrAndThenOr32 (=0D + PID_ESPISPI,=0D + (UINT16) R_ESPI_PCR_VWERR_SLV0,=0D + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),=0D + B_ESPI_PCR_XERR_XFEE=0D + );=0D + break;=0D +=0D + case FlashNonFatalErr:=0D + PchPcrAndThenOr32 (=0D + PID_ESPISPI,=0D + (UINT16) R_ESPI_PCR_FCERR_SLV0,=0D + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),=0D + B_ESPI_PCR_XERR_XNFEE=0D + );=0D + break;=0D +=0D + case FlashFatalErr:=0D + PchPcrAndThenOr32 (=0D + PID_ESPISPI,=0D + (UINT16) R_ESPI_PCR_FCERR_SLV0,=0D + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),=0D + B_ESPI_PCR_XERR_XFEE=0D + );=0D + break;=0D +=0D + case LnkType1Err:=0D + PchPcrAndThenOr32 (=0D + PID_ESPISPI,=0D + (UINT16) R_ESPI_PCR_LNKERR_SLV0,=0D + (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR | B_ESPI_PCR_LNKERR_SLV0_L= FET1S),=0D + (UINT32) (V_ESPI_PCR_LNKERR_SLV0_LFET1E_SMI << N_ESPI_PCR_LNKERR_S= LV0_LFET1E)=0D + );=0D +=0D + if (IsEspiSecondSlaveSupported ()) {=0D + PchPcrAndThenOr32 (=0D + PID_ESPISPI,=0D + (UINT16) R_ESPI_PCR_LNKERR_SLV1,=0D + (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR | B_ESPI_PCR_LNKERR_SLV0= _LFET1S),=0D + (UINT32) (V_ESPI_PCR_LNKERR_SLV0_LFET1E_SMI << N_ESPI_PCR_LNKERR= _SLV0_LFET1E)=0D + );=0D + }=0D + break;=0D +=0D + default:=0D + DEBUG ((DEBUG_ERROR, "Unsupported EspiSmiType \n"));=0D + ASSERT (FALSE);=0D + break;=0D + }=0D +}=0D +=0D +=0D +/**=0D + Disable eSPI SMI source=0D +=0D + @param[in] EspiSmiType Type based on ESPI_SMI_TYPE=0D +**/=0D +STATIC=0D +VOID=0D +EspiSmiDisableSource (=0D + IN CONST ESPI_SMI_TYPE EspiSmiType=0D + )=0D +{=0D +=0D + switch (EspiSmiType) {=0D + case BiosWrProtect:=0D + case BiosWrReport:=0D + DEBUG ((DEBUG_ERROR, "Bit is write lock, thus BWRE/BWPDS source cann= ot be disabled \n"));=0D + ASSERT (FALSE);=0D + break;=0D + case PcNonFatalErr:=0D + PchPcrAndThenOr32 (=0D + PID_ESPISPI,=0D + (UINT16) R_ESPI_PCR_PCERR_SLV0,=0D + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | B_ESPI_PCR_XERR_XNFES | B= _ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XNFEE),=0D + 0=0D + );=0D + break;=0D +=0D + case PcFatalErr:=0D + PchPcrAndThenOr32 (=0D + PID_ESPISPI,=0D + (UINT16) R_ESPI_PCR_PCERR_SLV0,=0D + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | B_ESPI_PCR_XERR_XNFES | B= _ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE),=0D + 0=0D + );=0D + break;=0D +=0D + case VwNonFatalErr:=0D + PchPcrAndThenOr32 (=0D + PID_ESPISPI,=0D + (UINT16) R_ESPI_PCR_VWERR_SLV0,=0D + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | B_ESPI_P= CR_XERR_XNFEE),=0D + 0=0D + );=0D + break;=0D +=0D + case VwFatalErr:=0D + PchPcrAndThenOr32 (=0D + PID_ESPISPI,=0D + (UINT16) R_ESPI_PCR_VWERR_SLV0,=0D + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | B_ESPI_P= CR_XERR_XFEE),=0D + 0=0D + );=0D + break;=0D +=0D + case FlashNonFatalErr:=0D + PchPcrAndThenOr32 (=0D + PID_ESPISPI,=0D + (UINT16) R_ESPI_PCR_FCERR_SLV0,=0D + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | B_ESPI_P= CR_XERR_XNFEE),=0D + 0=0D + );=0D + break;=0D +=0D + case FlashFatalErr:=0D + PchPcrAndThenOr32 (=0D + PID_ESPISPI,=0D + (UINT16) R_ESPI_PCR_FCERR_SLV0,=0D + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | B_ESPI_PC= R_XERR_XFEE),=0D + 0=0D + );=0D + break;=0D +=0D + case LnkType1Err:=0D + PchPcrAndThenOr32 (=0D + PID_ESPISPI,=0D + (UINT16) R_ESPI_PCR_LNKERR_SLV0,=0D + (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR | B_ESPI_PCR_LNKERR_SLV0_L= FET1S),=0D + 0=0D + );=0D +=0D + if (IsEspiSecondSlaveSupported ()) {=0D + PchPcrAndThenOr32 (=0D + PID_ESPISPI,=0D + (UINT16) R_ESPI_PCR_LNKERR_SLV1,=0D + (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR | B_ESPI_PCR_LNKERR_SLV0= _LFET1S),=0D + 0=0D + );=0D + }=0D + break;=0D +=0D + default:=0D + DEBUG ((DEBUG_ERROR, "Unsupported EspiSmiType \n"));=0D + ASSERT (FALSE);=0D + break;=0D + }=0D +}=0D +=0D +/**=0D + Clear a status for the SMI event=0D +=0D + @param[in] EspiSmiType Type based on ESPI_SMI_TYPE=0D +**/=0D +STATIC=0D +VOID=0D +EspiSmiClearStatus (=0D + IN CONST ESPI_SMI_TYPE EspiSmiType=0D + )=0D +{=0D + UINT32 PciBus;=0D + UINT32 PciDev;=0D + UINT32 PciFun;=0D + UINT32 PciReg;=0D + UINT64 PciBaseAddress;=0D + CONST ESPI_DESCRIPTOR *Desc;=0D +=0D + Desc =3D &mEspiDescriptor[EspiSmiType];=0D +=0D + switch (Desc->Address.Type) {=0D + case PCIE_ADDR_TYPE:=0D + PciBus =3D Desc->Address.Data.pcie.Fields.Bus;=0D + PciDev =3D Desc->Address.Data.pcie.Fields.Dev;=0D + PciFun =3D Desc->Address.Data.pcie.Fields.Fnc;=0D + PciReg =3D Desc->Address.Data.pcie.Fields.Reg;=0D + PciBaseAddress =3D PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMB= ER_PCH, PciBus, PciDev, PciFun, 0);=0D + PciSegmentAndThenOr32 (PciBaseAddress + PciReg, Desc->ClearStatusAnd= Mask, Desc->ClearStatusOrMask);=0D + break;=0D + case PCR_ADDR_TYPE:=0D + PchPcrAndThenOr32 (=0D + Desc->Address.Data.Pcr.Fields.Pid,=0D + Desc->Address.Data.Pcr.Fields.Offset,=0D + Desc->ClearStatusAndMask,=0D + Desc->ClearStatusOrMask=0D + );=0D + break;=0D + default:=0D + DEBUG ((DEBUG_ERROR, "Address type for eSPI SMI is invalid \n"));=0D + ASSERT (FALSE);=0D + break;=0D + }=0D +}=0D +=0D +/**=0D + Checks if a source is active by looking at the enable and status bits=0D +=0D + @param[in] EspiSmiType Type based on ESPI_SMI_TYPE=0D +**/=0D +STATIC=0D +BOOLEAN=0D +EspiSmiSourceIsActive (=0D + IN CONST ESPI_SMI_TYPE EspiSmiType=0D + )=0D +{=0D + BOOLEAN Active;=0D + UINT32 PciBus;=0D + UINT32 PciDev;=0D + UINT32 PciFun;=0D + UINT32 PciReg;=0D + UINT64 PciBaseAddress;=0D + UINT32 Data32;=0D + CONST ESPI_DESCRIPTOR *Desc;=0D +=0D + Desc =3D &mEspiDescriptor[EspiSmiType];=0D +=0D + Active =3D FALSE;=0D + switch (Desc->Address.Type) {=0D + case PCIE_ADDR_TYPE:=0D + PciBus =3D Desc->Address.Data.pcie.Fields.Bus;=0D + PciDev =3D Desc->Address.Data.pcie.Fields.Dev;=0D + PciFun =3D Desc->Address.Data.pcie.Fields.Fnc;=0D + PciReg =3D Desc->Address.Data.pcie.Fields.Reg;=0D + PciBaseAddress =3D PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMB= ER_PCH, PciBus, PciDev, PciFun, 0);=0D + Data32 =3D PciSegmentRead32 (PciBaseAddress + PciReg);=0D + break;=0D +=0D + case PCR_ADDR_TYPE:=0D + Data32 =3D PchPcrRead32 (=0D + Desc->Address.Data.Pcr.Fields.Pid,=0D + Desc->Address.Data.Pcr.Fields.Offset=0D + );=0D + break;=0D +=0D + default:=0D + Data32 =3D 0;=0D + DEBUG ((DEBUG_ERROR, "Address type for eSPI SMI is invalid \n"));=0D + ASSERT (FALSE);=0D + break;=0D + }=0D +=0D + if ((Data32 & Desc->SourceIsActiveAndMask) =3D=3D Desc->SourceIsActiveVa= lue) {=0D + Active =3D TRUE;=0D + }=0D +=0D + return Active;=0D +}=0D +=0D +/**=0D + Insert a handler into the corresponding linked list based on EspiSmiType= =0D +=0D + @param[in] DispatchFunction The callback to execute=0D + @param[in] EspiSmiType Type based on ESPI_SMI_TYPE to determi= ne which linked list to use=0D + @param[out] DispatchHandle The link to the record in the database= =0D +=0D + @retval EFI_SUCCESS Record was successfully inserted into = master database=0D + @retval EFI_OUT_OF_RESOURCES Cannot allocate pool to insert record= =0D +**/=0D +STATIC=0D +EFI_STATUS=0D +InsertEspiRecord (=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + IN ESPI_SMI_TYPE EspiSmiType,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + ESPI_SMI_RECORD *Record;=0D +=0D + Status =3D gSmst->SmmAllocatePool (EfiRuntimeServicesData, sizeof (ESPI_= SMI_RECORD), (VOID **) &Record);=0D + if (EFI_ERROR (Status)) {=0D + ASSERT (FALSE);=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D + SetMem (Record, sizeof (ESPI_SMI_RECORD), 0);=0D +=0D + Record->Callback =3D DispatchFunction;=0D + Record->Signature =3D ESPI_SMI_RECORD_SIGNATURE;=0D +=0D + InsertTailList (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], &Record= ->Link);=0D + EspiSmiClearStatus (EspiSmiType);=0D + EspiSmiEnableSource (EspiSmiType);=0D +=0D + ++mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType];=0D +=0D + *DispatchHandle =3D (EFI_HANDLE) (&Record->Link);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + This callback is registered to PchSmiDispatch=0D +=0D + @param[in] DispatchHandle Used to determine which source have been tri= ggered=0D +**/=0D +VOID=0D +EspiSmiCallback (=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + DATABASE_RECORD *PchSmiRecord;=0D + ESPI_TOP_LEVEL_TYPE EspiTopLevelType;=0D + ESPI_SMI_TYPE EspiSmiType;=0D + ESPI_SMI_RECORD *RecordInDb;=0D + LIST_ENTRY *LinkInDb;=0D +=0D + PchSmiRecord =3D DATABASE_RECORD_FROM_LINK (DispatchHandle);=0D +=0D + if (PchSmiRecord->PchSmiType =3D=3D PchTcoSmiLpcBiosWpType) {=0D + EspiTopLevelType =3D EspiBiosWrProtect;=0D + } else if (PchSmiRecord->PchSmiType =3D=3D PchSmiSerialIrqType) {=0D + EspiTopLevelType =3D EspiSerialIrq;=0D + } else {=0D + DEBUG ((DEBUG_ERROR, "EspiSmiCallback was dispatched with a wrong Disp= atchHandle"));=0D + ASSERT (FALSE);=0D + return;=0D + }=0D +=0D + for (EspiSmiType =3D mEspiSmiInstance.Barrier[EspiTopLevelType].Start; E= spiSmiType <=3D mEspiSmiInstance.Barrier[EspiTopLevelType].End; ++EspiSmiTy= pe) {=0D + if (!EspiSmiSourceIsActive (EspiSmiType)) {=0D + continue;=0D + }=0D + //=0D + // The source is active, so walk the callback database and dispatch=0D + //=0D + if (!IsListEmpty (&mEspiSmiInstance.CallbackDataBase[EspiSmiType])) {= =0D + //=0D + // We have children registered w/ us -- continue=0D + //=0D + LinkInDb =3D GetFirstNode (&mEspiSmiInstance.CallbackDataBase[EspiSm= iType]);=0D +=0D + while (!IsNull (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], Lin= kInDb)) {=0D + RecordInDb =3D ESPI_RECORD_FROM_LINK (LinkInDb);=0D +=0D + //=0D + // RecordInDb->Link might be removed (unregistered) by Callback fu= nction, and then the=0D + // system will hang in ASSERT() while calling GetNextNode().=0D + // To prevent the issue, we need to get next record in DB here (be= fore Callback function).=0D + //=0D + LinkInDb =3D GetNextNode (&mEspiSmiInstance.CallbackDataBase[EspiS= miType], &RecordInDb->Link);=0D +=0D + //=0D + // Callback=0D + //=0D + if (RecordInDb->Callback !=3D NULL) {=0D + RecordInDb->Callback ((EFI_HANDLE) &RecordInDb->Link);=0D + } else {=0D + ASSERT (FALSE);=0D + }=0D + }=0D + } else if (EspiSmiType =3D=3D LnkType1Err) {=0D + //=0D + // If no proper handler registered for Link Type 1 Error=0D + // Call default SMI handler recover otherwise=0D + //=0D + EspiDefaultFatalErrorHandler ();=0D + }=0D +=0D + //=0D + // Finish walking the linked list for the EspiSmiType, so clear status= =0D + //=0D + EspiSmiClearStatus (EspiSmiType);=0D + }=0D +}=0D +=0D +//=0D +// EspiBiosWp srcdesc=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescEspiBiosWp= =3D {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_EN}=0D + },=0D + S_ACPI_IO_SMI_EN,=0D + N_ACPI_IO_SMI_EN_TCO=0D + },=0D + {=0D + {=0D + PCIE_ADDR_TYPE,=0D + { (=0D + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |=0D + (PCI_DEVICE_NUMBER_PCH_LPC << 19) |=0D + (PCI_FUNCTION_NUMBER_PCH_LPC << 16) |=0D + R_ESPI_CFG_PCBC=0D + ) }=0D + },=0D + S_ESPI_CFG_PCBC,=0D + N_ESPI_CFG_PCBC_LE=0D + }=0D + },=0D + {=0D + {=0D + {=0D + PCIE_ADDR_TYPE,=0D + { (=0D + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |=0D + (PCI_DEVICE_NUMBER_PCH_LPC << 19) |=0D + (PCI_FUNCTION_NUMBER_PCH_LPC << 16) |=0D + R_ESPI_CFG_PCBC=0D + ) }=0D + },=0D + S_ESPI_CFG_PCBC,=0D + N_ESPI_CFG_PCBC_BWPDS=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_TCO=0D + }=0D +};=0D +=0D +/**=0D + This function will register EspiSmiCallback with mSrcDescEspiBiosWp sour= ce decriptor=0D + This function make sure there is only one BIOS WP SMI handler is registe= red.=0D + While any ESPI sub BIOS WP SMI type is registered, all the BIOS WP SMI=0D + will go to callback function EspiSmiCallback first, and then dispatchs t= he callbacks=0D + recorded in mEspiSmiInstance.=0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval others Registration failed=0D +**/=0D +STATIC=0D +EFI_STATUS=0D +RegisterBiosWrProtectIfNull (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D + DATABASE_RECORD *Record;=0D +=0D + if (mEspiSmiInstance.PchSmiEspiHandle[EspiBiosWrProtect] =3D=3D NULL) {= =0D + Status =3D PchSmiRecordInsert (=0D + &mSrcDescEspiBiosWp,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) EspiSmiCallback,=0D + PchTcoSmiLpcBiosWpType,=0D + &mEspiSmiInstance.PchSmiEspiHandle[EspiBiosWrProtect]=0D + );=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((DEBUG_ERROR, "Fail to register BIOS WP SMI handler \n"));=0D + return Status;=0D + }=0D + Record =3D DATABASE_RECORD_FROM_LINK (mEspiSmiInstance.PchSmiEspiHandl= e[EspiBiosWrProtect]);=0D + Record->ClearSource =3D PchTcoSmiClearSource;=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + This function will register EspiSmiCallback with mSrcDescSerialIrq sourc= e decriptor=0D + This function make sure there is only one Serial IRQ SMI handler is regi= stered.=0D + While any ESPI sub Serial IRQ SMI type is registered, all the Serial IRQ= SMI=0D + will go to callback function EspiSmiCallback first, and then dispatchs t= he callbacks=0D + recorded in mEspiSmiInstance.=0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval others Registration failed=0D +**/=0D +STATIC=0D +EFI_STATUS=0D +RegisterSerialIrqIfNull (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + if (mEspiSmiInstance.PchSmiEspiHandle[EspiSerialIrq] =3D=3D NULL) {=0D + Status =3D PchSmiRecordInsert (=0D + &mSrcDescSerialIrq,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) EspiSmiCallback,=0D + PchSmiSerialIrqType,=0D + &mEspiSmiInstance.PchSmiEspiHandle[EspiSerialIrq]=0D + );=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((DEBUG_ERROR, "Fail to register Serial IRQ SMI handler \n"));= =0D + return Status;=0D + }=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Installs and initialize this protocol=0D +=0D + @param[in] ImageHandle Not used=0D +=0D + @retval EFI_SUCCESS Installation succeed=0D + @retval others Installation failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +InstallEspiSmi (=0D + IN EFI_HANDLE ImageHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + ESPI_SMI_TYPE EspiSmiType;=0D +=0D + DEBUG ((DEBUG_INFO, "[InstallEspiSmi] Enter\n"));=0D +=0D + //=0D + // InitializeListHead for mEspiSmiInstance.CallBackDataBase[EspiTopLevel= TypeMax]=0D + //=0D + for (EspiSmiType =3D 0; EspiSmiType < EspiSmiTypeMax; ++EspiSmiType) {=0D + InitializeListHead (&mEspiSmiInstance.CallbackDataBase[EspiSmiType]);= =0D + }=0D +=0D + //=0D + // Install EfiEspiSmiDispatchProtocol=0D + //=0D + Status =3D gSmst->SmmInstallProtocolInterface (=0D + &mEspiSmiInstance.Handle,=0D + &gPchEspiSmiDispatchProtocolGuid,=0D + EFI_NATIVE_INTERFACE,=0D + &mEspiSmiInstance.PchEspiSmiDispatchProtocol=0D + );=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((DEBUG_ERROR, "Failed to install eSPI SMI Dispatch Protocol\n")= );=0D + ASSERT (FALSE);=0D + return Status;=0D + }=0D +=0D + // Register eSPI SMM callback to enable Fatal Error handling by default = handler=0D + Status =3D RegisterSerialIrqIfNull ();=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D +=0D + // Enable LnkType1Err SMI generation for default handler=0D + EspiSmiClearStatus (LnkType1Err);=0D + EspiSmiEnableSource (LnkType1Err);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to register a BIOS Write Protect eve= nt=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchFunction The callback to execute=0D + @param[out] DispatchHandle The handle for this callback registration= =0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock= event has been triggered=0D + @retval others Registration failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +BiosWrProtectRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D RegisterBiosWrProtectIfNull ();=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D + //=0D + // Insert a record=0D + //=0D + Status =3D InsertEspiRecord (DispatchFunction, BiosWrProtect, DispatchHa= ndle);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (E= FI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NU= LL, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to register a BIOS Write Report even= t=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchFunction The callback to execute=0D + @param[out] DispatchHandle The handle for this callback registration= =0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock= event has been triggered=0D + @retval others Registration failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +BiosWrReportRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D RegisterSerialIrqIfNull ();=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D + //=0D + // Insert a record=0D + //=0D + Status =3D InsertEspiRecord (DispatchFunction, BiosWrReport, DispatchHan= dle);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (E= FI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NU= LL, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to register a Peripheral Channel Non= Fatal Error event=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchFunction The callback to execute=0D + @param[out] DispatchHandle The handle for this callback registration= =0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock= event has been triggered=0D + @retval others Registration failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PcNonFatalErrRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D RegisterSerialIrqIfNull ();=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D + //=0D + // Insert a record=0D + //=0D + Status =3D InsertEspiRecord (DispatchFunction, PcNonFatalErr, DispatchHa= ndle);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (E= FI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NU= LL, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to register a Peripheral Channel Fat= al Error event=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchFunction The callback to execute=0D + @param[out] DispatchHandle The handle for this callback registration= =0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock= event has been triggered=0D + @retval others Registration failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PcFatalErrRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D RegisterSerialIrqIfNull ();=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D + //=0D + // Insert a record=0D + //=0D + Status =3D InsertEspiRecord (DispatchFunction, PcFatalErr, DispatchHandl= e);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (E= FI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NU= LL, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to register a Virtual Wire Non Fatal= Error event=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchFunction The callback to execute=0D + @param[out] DispatchHandle The handle for this callback registration= =0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock= event has been triggered=0D + @retval others Registration failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +VwNonFatalErrRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D RegisterSerialIrqIfNull ();=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D + //=0D + // Insert a record=0D + //=0D + Status =3D InsertEspiRecord (DispatchFunction, VwNonFatalErr, DispatchHa= ndle);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (E= FI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NU= LL, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to register a Virtual Wire Fatal Err= or event=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchFunction The callback to execute=0D + @param[out] DispatchHandle The handle for this callback registration= =0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock= event has been triggered=0D + @retval others Registration failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +VwFatalErrRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D RegisterSerialIrqIfNull ();=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D + //=0D + // Insert a record=0D + //=0D + Status =3D InsertEspiRecord (DispatchFunction, VwFatalErr, DispatchHandl= e);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (E= FI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NU= LL, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to register a Flash Channel Non Fata= l Error event=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchFunction The callback to execute=0D + @param[out] DispatchHandle The handle for this callback registration= =0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock= event has been triggered=0D + @retval others Registration failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +FlashNonFatalErrRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D RegisterSerialIrqIfNull ();=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D + //=0D + // Insert a record=0D + //=0D + Status =3D InsertEspiRecord (DispatchFunction, FlashNonFatalErr, Dispatc= hHandle);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (E= FI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NU= LL, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to register a Flash Channel Fatal Er= ror event=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchFunction The callback to execute=0D + @param[out] DispatchHandle The handle for this callback registration= =0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock= event has been triggered=0D + @retval others Registration failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +FlashFatalErrRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D RegisterSerialIrqIfNull ();=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D + //=0D + // Insert a record=0D + //=0D + Status =3D InsertEspiRecord (DispatchFunction, FlashFatalErr, DispatchHa= ndle);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (E= FI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NU= LL, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to register a Link Error event=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchFunction The callback to execute=0D + @param[out] DispatchHandle The handle for this callback registration= =0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock= event has been triggered=0D + @retval others Registration failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +LnkType1ErrRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D RegisterSerialIrqIfNull ();=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D + //=0D + // Insert a record=0D + //=0D + Status =3D InsertEspiRecord (DispatchFunction, LnkType1Err, DispatchHand= le);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (E= FI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NU= LL, 0);=0D + }=0D + return Status;=0D +}=0D +=0D +//=0D +// EspiSlave srcdesc=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescEspiSlave = =3D {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_EN}=0D + },=0D + S_ACPI_IO_SMI_EN,=0D + N_ACPI_IO_SMI_EN_ESPI=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_ESPI=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_ESPI=0D + }=0D +};=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to register a eSPI slave SMI=0D + This routine will also lock down ESPI_SMI_LOCK bit after registration an= d prevent=0D + this handler from unregistration.=0D + On platform that supports more than 1 device through another chip select= (SPT-H),=0D + the SMI handler itself needs to inspect both the eSPI devices' interrupt= status registers=0D + (implementation specific for each Slave) in order to identify and servic= e the cause.=0D + After servicing it, it has to clear the Slaves' internal SMI# status reg= isters=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchFunction The callback to execute=0D + @param[out] DispatchHandle The handle for this callback regis= tration=0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D + @retval EFI_ACCESS_DENIED The ESPI_SMI_LOCK is set and regis= ter is blocked.=0D + @retval others Registration failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +EspiSlaveSmiRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + //=0D + // If ESPI_SMI_LOCK is set, the register is blocked.=0D + //=0D + if (PmcIsEspiSmiLockSet ()) {=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + //=0D + // @note: This service doesn't utilize the data base of mEspiSmiInstance= .=0D + // While SMI is triggered it directly goes to the registing Dispa= tchFunction=0D + // instead of EspiSmiCallback.=0D + //=0D + Status =3D PchSmiRecordInsert (=0D + &mSrcDescEspiSlave,=0D + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,=0D + PchEspiSmiEspiSlaveType,=0D + DispatchHandle=0D + );=0D + PchSmmClearSource (&mSrcDescEspiSlave);=0D + PchSmmEnableSource (&mSrcDescEspiSlave);=0D +=0D + //=0D + // Lock down the ESPI_SMI_LOCK after ESPI SMI is enabled.=0D + //=0D + PmcLockEspiSmiWithS3BootScript ();=0D + //=0D + // Keep the DispatchHandle which will be used for unregister function.=0D + //=0D + mEspiSmiInstance.PchSmiEspiHandle[EspiPmc] =3D *DispatchHandle;=0D +=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (E= FI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NU= LL, 0);=0D + }=0D +=0D + return Status;=0D +}=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to unregister a callback based on ha= ndle=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchHandle Handle acquired during registration= =0D +=0D + @retval EFI_SUCCESS Unregister successful=0D + @retval EFI_INVALID_PARAMETER DispatchHandle is null=0D + @retval EFI_INVALID_PARAMETER DispatchHandle's forward link has ba= d pointer=0D + @retval EFI_INVALID_PARAMETER DispatchHandle does not exist in dat= abase=0D + @retval EFI_ACCESS_DENIED Unregistration is done after end of = DXE=0D + @retval EFI_ACCESS_DENIED DispatchHandle is not allowed to unr= egistered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +EspiSmiUnRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + ESPI_TOP_LEVEL_TYPE EspiTopLevelType;=0D + ESPI_SMI_TYPE EspiSmiType;=0D + BOOLEAN SafeToDisable;=0D + LIST_ENTRY *LinkInDb;=0D + ESPI_SMI_RECORD *RecordPointer;=0D + DATABASE_RECORD *RecordToDelete;=0D +=0D + if (DispatchHandle =3D=3D NULL) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock = event has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + if (((LIST_ENTRY *) DispatchHandle)->ForwardLink =3D=3D (LIST_ENTRY *) E= FI_BAD_POINTER) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + //=0D + // For DispatchHandle belongs to Espi Slave SMI, refuses the request of = unregistration.=0D + //=0D + if (mEspiSmiInstance.PchSmiEspiHandle[EspiPmc] =3D=3D DispatchHandle) {= =0D + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed for ESPI Slave SMI han= dle! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + //=0D + // Iterate through all the database to find the record=0D + //=0D + for (EspiSmiType =3D 0; EspiSmiType < EspiSmiTypeMax; ++EspiSmiType) {=0D + LinkInDb =3D GetFirstNode (&mEspiSmiInstance.CallbackDataBase[EspiSmiT= ype]);=0D +=0D + while (!IsNull (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], LinkI= nDb)) {=0D + if (LinkInDb !=3D (LIST_ENTRY *) DispatchHandle) {=0D + LinkInDb =3D GetNextNode (&mEspiSmiInstance.CallbackDataBase[EspiS= miType], LinkInDb);=0D +=0D + } else {=0D + //=0D + // Found the source to be from this list=0D + //=0D + RemoveEntryList (LinkInDb);=0D + RecordPointer =3D (ESPI_RECORD_FROM_LINK (LinkInDb));=0D +=0D + if (mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] !=3D 0) {=0D + if (--mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] =3D=3D 0= ) {=0D + EspiSmiDisableSource (EspiSmiType);=0D + }=0D + }=0D +=0D + Status =3D gSmst->SmmFreePool (RecordPointer);=0D + if (EFI_ERROR (Status)) {=0D + ASSERT (FALSE);=0D + }=0D +=0D + goto EspiSmiUnRegisterEnd;=0D + }=0D + }=0D + }=0D + //=0D + // If the code reach here, the handle passed in cannot be found=0D + //=0D + DEBUG ((DEBUG_ERROR, "eSPI SMI handle is not in record database \n"));=0D + ASSERT (FALSE);=0D + return EFI_INVALID_PARAMETER;=0D +=0D +EspiSmiUnRegisterEnd:=0D +=0D + //=0D + // Unregister and clear the handle from PchSmiDispatch=0D + //=0D + for (EspiTopLevelType =3D 0; EspiTopLevelType < EspiTopLevelTypeMax; ++E= spiTopLevelType) {=0D + SafeToDisable =3D TRUE;=0D + //=0D + // Checks all the child events that belongs to a top level status in P= MC=0D + //=0D + for (EspiSmiType =3D mEspiSmiInstance.Barrier[EspiTopLevelType].Start;= EspiSmiType <=3D mEspiSmiInstance.Barrier[EspiTopLevelType].End; ++EspiSmi= Type) {=0D + if (mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] !=3D 0) {=0D + SafeToDisable =3D FALSE;=0D + }=0D + }=0D + //=0D + // Finally, disable the top level event in PMC=0D + //=0D + if (SafeToDisable) {=0D + if (mEspiSmiInstance.PchSmiEspiHandle[EspiTopLevelType] !=3D NULL) {= =0D + Status =3D PchSmmCoreUnRegister (NULL, mEspiSmiInstance.PchSmiEspi= Handle[EspiTopLevelType]);=0D + ASSERT_EFI_ERROR (Status);=0D + mEspiSmiInstance.PchSmiEspiHandle[EspiTopLevelType] =3D NULL;=0D + }=0D + }=0D + }=0D + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle);=0D + if (!EFI_ERROR (Status)) {=0D + SmiHandlerProfileUnregisterHandler (&gPchEspiSmiDispatchProtocolGuid, = RecordToDelete->Callback, NULL, 0);=0D + }=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Returns AND maks for clearing eSPI channel registers errors statuses=0D + In addition to common status bit we add channel specific erro bits to av= oid clearing them=0D +=0D + @param[in] ChannelNumber Channel number (0 for PC, 1 for VW, = 2 for OOB, 3 for FA)=0D +=0D + @retval UINT32 AND mask with all the status bit mas= ked to not clear them by mistake=0D +**/=0D +UINT32=0D +GetEspiChannelStatusClearMask (=0D + UINT8 ChannelNumber=0D + )=0D +{=0D + UINT32 Data32;=0D +=0D + // Common error status bits for all channel registers=0D + Data32 =3D B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES;=0D +=0D + // Check channels for channel specific status bits=0D + switch(ChannelNumber) {=0D + case 0: // Peripheral Channel specific status bits=0D + Data32 |=3D B_ESPI_PCR_PCERR_PCURD;=0D + break;=0D + case 3: // Flash Access Channel specific status bits=0D + Data32 |=3D B_ESPI_PCR_FCERR_SAFBLK;=0D + break;=0D + }=0D +=0D + // Return the expected AND mask=0D + return (UINT32)~(Data32);=0D +}=0D +=0D +/**=0D + Checks if channel error register data has Fatal Error bit set=0D + If yes then reset the channel on slave=0D +=0D + @param[in] ChannelBaseAddress Base address=0D + @param[in] ChannelNumber Channel number (0 for PC, 1 for VW, = 2 for OOB, 3 for FA)=0D + @param[in] SlaveId Slave ID of which channel is to be r= eset=0D +**/=0D +VOID=0D +CheckSlaveChannelErrorAndReset (=0D + UINT16 ChannelBaseAddress,=0D + UINT8 ChannelNumber,=0D + UINT8 SlaveId=0D + )=0D +{=0D + UINT32 Data32;=0D + UINT16 ChannelAddress;=0D + EFI_STATUS Status;=0D +=0D + if (ChannelNumber =3D=3D 2) {=0D + DEBUG ((DEBUG_INFO, "Channel %d is not supported by this function due = to lack of error register\n", ChannelNumber));=0D + return;=0D + }=0D +=0D + if (!IsEspiSlaveChannelSupported (SlaveId, ChannelNumber)) {=0D + DEBUG ((DEBUG_WARN, "Channel %d is not supported by slave device\n", C= hannelNumber));=0D + return;=0D + }=0D +=0D + // Calculate channel address based on slave id=0D + ChannelAddress =3D (UINT16) (ChannelBaseAddress + (SlaveId * S_ESPI_PCR_= XERR));=0D +=0D + // Reading channel error register data=0D + Data32 =3D PchPcrRead32 (PID_ESPISPI, ChannelAddress);=0D +=0D + DEBUG ((DEBUG_INFO, "eSPI channel error register (0x%4X) has value 0x%8X= \n", ChannelAddress, Data32));=0D +=0D + // Check Fatal Error status bit in channel error register data=0D + if ((Data32 & B_ESPI_PCR_XERR_XFES) !=3D 0) {=0D + Status =3D PchEspiSlaveChannelReset (SlaveId, ChannelNumber);=0D +=0D + if (EFI_ERROR (Status)) {=0D + switch (Status) {=0D + case EFI_UNSUPPORTED:=0D + DEBUG ((DEBUG_ERROR, "Slave doesn't support channel %d\n", Chann= elNumber));=0D + break;=0D + case EFI_TIMEOUT:=0D + DEBUG ((DEBUG_ERROR, "Timeout occured during channel %d reset on= slave %d\n", ChannelNumber, SlaveId));=0D + break;=0D + default:=0D + DEBUG ((DEBUG_ERROR, "Error occured during channel %d reset\n", = ChannelNumber));=0D + break;=0D + }=0D + } else {=0D + DEBUG ((DEBUG_INFO, "eSPI Slave %d channel %d reset ended successful= ly\n", SlaveId, ChannelNumber));=0D + // If channel reset was successfull clear the fatal error flag by wr= iting one=0D + // we should be aware not to clear other status bits by mistake and = mask them=0D + PchPcrAndThenOr32 (=0D + PID_ESPISPI,=0D + ChannelAddress,=0D + GetEspiChannelStatusClearMask (ChannelNumber),=0D + B_ESPI_PCR_XERR_XFES=0D + );=0D + }=0D + }=0D +}=0D +=0D +/**=0D + eSPI SMI handler for Fatal Error recovery flow=0D +**/=0D +VOID=0D +EspiDefaultFatalErrorHandler (=0D + VOID=0D + )=0D +{=0D + UINT32 Data32;=0D + UINT8 SlaveId;=0D + UINT8 MaxSlavesCount;=0D +=0D + DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] Enter\n"));=0D +=0D + MaxSlavesCount =3D IsEspiSecondSlaveSupported () ? 2 : 1;=0D +=0D + DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] MaxSlavesCount %d\n", M= axSlavesCount));=0D +=0D + for (SlaveId =3D 0; SlaveId < MaxSlavesCount; ++SlaveId) {=0D + //=0D + // Check if slave has SLCRR bit set. If it does it means it needs reco= very.=0D + //=0D + Data32 =3D PchPcrRead32 (PID_ESPISPI, (UINT16) (R_ESPI_PCR_LNKERR_SLV0= + (SlaveId * S_ESPI_PCR_XERR)));=0D +=0D + DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] Slave %d LNKERR reg 0= x%8X\n", SlaveId, Data32));=0D + //=0D + // If SLCRR[31] bit is set we need to recover that slave=0D + //=0D + if ((Data32 & B_ESPI_PCR_LNKERR_SLV0_SLCRR) !=3D 0) {=0D + // 1. Perform in-band reset=0D + PchEspiSlaveInBandReset (SlaveId);=0D +=0D + // 2. Channels reset=0D + CheckSlaveChannelErrorAndReset (R_ESPI_PCR_PCERR_SLV0, 0, SlaveId); = // Peripheral channel reset=0D + CheckSlaveChannelErrorAndReset (R_ESPI_PCR_VWERR_SLV0, 1, SlaveId); = // Virtual Wire channel reset=0D +=0D + // Flash Access channel is not supported for CS1#=0D + if (SlaveId =3D=3D 0) {=0D + CheckSlaveChannelErrorAndReset (R_ESPI_PCR_PCERR_SLV0, 3, SlaveId)= ; // Flash Access channel reset=0D + }=0D +=0D + // Clear SLCRR bit of slave after all channels recovery was done=0D + PchPcrAndThenOr32 (=0D + PID_ESPISPI,=0D + (UINT16) (R_ESPI_PCR_LNKERR_SLV0 + (SlaveId * S_ESPI_PCR_XERR)),=0D + (UINT32)~(B_ESPI_PCR_LNKERR_SLV0_LFET1S),=0D + (UINT32) (B_ESPI_PCR_LNKERR_SLV0_SLCRR)=0D + );=0D + }=0D + }=0D +=0D + DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] Exit\n"));=0D +}=0D +=0D +=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmmEspi.h b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchS= mmEspi.h new file mode 100644 index 0000000000..4903464fae --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi= .h @@ -0,0 +1,341 @@ +/** @file=0D + eSPI SMI Dispatch header=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +=0D +#ifndef _PCH_SMM_ESPI_H_=0D +#define _PCH_SMM_ESPI_H_=0D +=0D +#include "PchSmmHelpers.h"=0D +=0D +#define ESPI_SMI_INSTANCE_SIGNATURE SIGNATURE_32 ('E', 'S', 'P', 'I'= )=0D +#define ESPI_SMI_RECORD_SIGNATURE SIGNATURE_32 ('E', 'S', 'R', 'C'= )=0D +=0D +#define ESPI_INSTANCE_FROM_THIS(_this) CR (_this, ESPI_SMI_INSTANCE, = EfiEspiSmiDispatchProtocol, ESPI_SMI_INSTANCE_SIGNATURE)=0D +#define ESPI_RECORD_FROM_LINK(_link) CR (_link, ESPI_SMI_RECORD, Li= nk, ESPI_SMI_RECORD_SIGNATURE)=0D +=0D +typedef enum {=0D + EspiBiosWrProtect, ///< BIOS Write Protect=0D + EspiSerialIrq, ///< eSPI Master Asserted SMI=0D + EspiPmc, ///< eSPI PMC SMI=0D + EspiTopLevelTypeMax=0D +} ESPI_TOP_LEVEL_TYPE;=0D +=0D +typedef enum {=0D + BiosWrProtect, ///< BIOS Write Protect=0D + BiosWrReport, ///< Peripheral Channel BIOS Write Protect=0D + PcNonFatalErr, ///< Peripheral Channel Non Fatal Error=0D + PcFatalErr, ///< Peripheral Channel Fatal Error=0D + VwNonFatalErr, ///< Virtual Wire Non Fatal Error=0D + VwFatalErr, ///< Virtual Wire Fatal Error=0D + FlashNonFatalErr, ///< Flash Channel Non Fatal Error=0D + FlashFatalErr, ///< Flash Channel Fatal Error=0D + LnkType1Err, ///< Link Error=0D + EspiSlaveSmi, ///< Espi Slave SMI=0D + EspiSmiTypeMax=0D +} ESPI_SMI_TYPE;=0D +=0D +///=0D +/// This is used to classify ESPI_SMI_TYPE to ESPI_TOP_LEVEL_TYPE.=0D +/// Used during dispatching and unregistering=0D +///=0D +typedef struct {=0D + ESPI_SMI_TYPE Start;=0D + ESPI_SMI_TYPE End;=0D +} ESPI_SMI_TYPE_BARRIER;=0D +=0D +typedef struct _ESPI_SMI_INSTANCE {=0D + ///=0D + /// Signature associated with this instance=0D + ///=0D + UINT32 Signature;=0D + ///=0D + /// EFI_HANDLE acquired when installing PchEspiSmiDispatchProtocol=0D + ///=0D + EFI_HANDLE Handle;=0D + ///=0D + /// The protocol to register or unregister eSPI SMI callbacks=0D + ///=0D + PCH_ESPI_SMI_DISPATCH_PROTOCOL PchEspiSmiDispatchProtocol;=0D + ///=0D + /// The handle acquired when registering eSPI SMI callback to PchSmiDisp= atch=0D + ///=0D + EFI_HANDLE PchSmiEspiHandle[EspiTopLevelTypeMax];=0D + ///=0D + /// The linked list for record database.=0D + ///=0D + LIST_ENTRY CallbackDataBase[EspiSmiTypeMax];=0D + ///=0D + /// This is an internal counter to track the number of eSPI master event= s have been registered.=0D + /// When unregistering, we can disable the SMI if the counter is zero=0D + ///=0D + UINTN EspiSmiEventCounter[EspiSmiTypeMax];=0D + ///=0D + /// Instance of barrier=0D + ///=0D + CONST ESPI_SMI_TYPE_BARRIER Barrier[EspiTopLevelTypeMax];=0D +} ESPI_SMI_INSTANCE;=0D +=0D +typedef struct _ESPI_DESCRIPTOR {=0D + PCH_SMM_ADDRESS Address;=0D + UINT32 SourceIsActiveAndMask;=0D + UINT32 SourceIsActiveValue;=0D + UINT32 ClearStatusAndMask;=0D + UINT32 ClearStatusOrMask;=0D +} ESPI_DESCRIPTOR;=0D +=0D +///=0D +/// A simple record to store the callbacks associated with an eSPI SMI sou= rce=0D +///=0D +typedef struct _ESPI_SMI_RECORD {=0D + UINT32 Signature;=0D + LIST_ENTRY Link;=0D + PCH_ESPI_SMI_DISPATCH_CALLBACK Callback;=0D +} ESPI_SMI_RECORD;=0D +=0D +/**=0D + Installs and initialize this protocol=0D +=0D + @param[in] ImageHandle Not used=0D +=0D + @retval EFI_SUCCESS Installation succeed=0D + @retval others Installation failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +InstallEspiSmi (=0D + IN EFI_HANDLE ImageHandle=0D + );=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to register a BIOS Write Protect eve= nt=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchFunction The callback to execute=0D + @param[out] DispatchHandle The handle for this callback registration= =0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock= event has been triggered=0D + @retval others Registration failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +BiosWrProtectRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + );=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to register a BIOS Write Report even= t=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchFunction The callback to execute=0D + @param[out] DispatchHandle The handle for this callback registration= =0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock= event has been triggered=0D + @retval others Registration failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +BiosWrReportRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + );=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to register a Peripheral Channel Non= Fatal Error event=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchFunction The callback to execute=0D + @param[out] DispatchHandle The handle for this callback registration= =0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock= event has been triggered=0D + @retval others Registration failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PcNonFatalErrRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + );=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to register a Peripheral Channel Fat= al Error event=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchFunction The callback to execute=0D + @param[out] DispatchHandle The handle for this callback registration= =0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock= event has been triggered=0D + @retval others Registration failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PcFatalErrRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + );=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to register a Virtual Wire Non Fatal= Error event=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchFunction The callback to execute=0D + @param[out] DispatchHandle The handle for this callback registration= =0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock= event has been triggered=0D + @retval others Registration failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +VwNonFatalErrRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + );=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to register a Virtual Wire Fatal Err= or event=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchFunction The callback to execute=0D + @param[out] DispatchHandle The handle for this callback registration= =0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock= event has been triggered=0D + @retval others Registration failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +VwFatalErrRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + );=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to register a Flash Channel Non Fata= l Error event=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchFunction The callback to execute=0D + @param[out] DispatchHandle The handle for this callback registration= =0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock= event has been triggered=0D + @retval others Registration failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +FlashNonFatalErrRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + );=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to register a Flash Channel Fatal Er= ror event=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchFunction The callback to execute=0D + @param[out] DispatchHandle The handle for this callback registration= =0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock= event has been triggered=0D + @retval others Registration failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +FlashFatalErrRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + );=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to register a Link Error event=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchFunction The callback to execute=0D + @param[out] DispatchHandle The handle for this callback registration= =0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock= event has been triggered=0D + @retval others Registration failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +LnkType1ErrRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + );=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to register a eSPI slave SMI=0D + NOTE: The register function is not available when the ESPI_SMI_LOCK bit = is set.=0D + This runtine will also lock donw ESPI_SMI_LOCK bit after registrat= ion and=0D + prevent this handler from unregistration.=0D + On platform that supports more than 1 device through another chip select= (SPT-H),=0D + the SMI handler itself needs to inspect both the eSPI devices' interrupt= status registers=0D + (implementation specific for each Slave) in order to identify and servic= e the cause.=0D + After servicing it, it has to clear the Slaves' internal SMI# status reg= isters=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchFunction The callback to execute=0D + @param[out] DispatchHandle The handle for this callback regis= tration=0D +=0D + @retval EFI_SUCCESS Registration succeed=0D + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered=0D + @retval EFI_ACCESS_DENIED The ESPI_SMI_LOCK is set and regis= ter is blocked.=0D + @retval others Registration failed=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +EspiSlaveSmiRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,=0D + OUT EFI_HANDLE *DispatchHandle=0D + );=0D +=0D +/**=0D + eSPI SMI Dispatch Protocol instance to unregister a callback based on ha= ndle=0D +=0D + @param[in] This Not used=0D + @param[in] DispatchHandle Handle acquired during registration= =0D +=0D + @retval EFI_SUCCESS Unregister successful=0D + @retval EFI_INVALID_PARAMETER DispatchHandle is null=0D + @retval EFI_INVALID_PARAMETER DispatchHandle's forward link has ba= d pointer=0D + @retval EFI_INVALID_PARAMETER DispatchHandle does not exist in dat= abase=0D + @retval EFI_ACCESS_DENIED Unregistration is done after end of = DXE=0D + @retval EFI_ACCESS_DENIED DispatchHandle is not allowed to unr= egistered=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +EspiSmiUnRegister (=0D + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,=0D + IN EFI_HANDLE DispatchHandle=0D + );=0D +=0D +/**=0D + eSPI SMI handler for Fatal Error recovery flow=0D +=0D + @param[in] DispatchHandle Handle acquired during registration= =0D +**/=0D +VOID=0D +EspiDefaultFatalErrorHandler (=0D + VOID=0D + );=0D +=0D +=0D +#endif=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmmGpi.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSm= mGpi.c new file mode 100644 index 0000000000..61f925c860 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi.c @@ -0,0 +1,263 @@ +/** @file=0D + File to contain all the hardware specific stuff for the Smm Gpi dispatch= protocol.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include "PchSmm.h"=0D +#include "PchSmmHelpers.h"=0D +#include =0D +#include =0D +#include =0D +=0D +//=0D +// Structure for GPI SMI is a template which needs to have=0D +// GPI Smi bit offset and Smi Status & Enable registers updated (according= ly=0D +// to choosen group and pad number) after adding it to SMM Callback databa= se=0D +//=0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mPchGpiSourceDescT= emplate =3D {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + NULL_BIT_DESC_INITIALIZER,=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + GPIO_ADDR_TYPE, {0x0}=0D + },=0D + S_GPIO_PCR_GP_SMI_STS, 0x0,=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_GPIO_SMI=0D + }=0D +};=0D +=0D +/**=0D + The register function used to register SMI handler of GPI SMI event.=0D +=0D + @param[in] This Pointer to the EFI_SMM_GPI_DISPATCH2_PROT= OCOL instance.=0D + @param[in] DispatchFunction Function to register for handler when the= specified GPI causes an SMI.=0D + @param[in] RegisterContext Pointer to the dispatch function's contex= t.=0D + The caller fills this context in before c= alling=0D + the register function to indicate to the = register=0D + function the GPI(s) for which the dispatc= h function=0D + should be invoked.=0D + @param[out] DispatchHandle Handle generated by the dispatcher to tra= ck the=0D + function instance.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been successful= ly=0D + registered and the SMI source has been en= abled.=0D + @retval EFI_ACCESS_DENIED Register is not allowed=0D + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The GPI input= value=0D + is not within valid range.=0D + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM= ) to manage this child.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchGpiSmiRegister (=0D + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This,=0D + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,=0D + IN EFI_SMM_GPI_REGISTER_CONTEXT *RegisterContext,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + DATABASE_RECORD Record;=0D + GPIO_PAD GpioPad;=0D + UINT8 GpiSmiBitOffset;=0D + UINT32 GpiHostSwOwnRegAddress;=0D + UINT32 GpiSmiStsRegAddress;=0D + UINT32 Data32Or;=0D + UINT32 Data32And;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the EndOfDxe event ha= s been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + Status =3D GpioGetPadAndSmiRegs (=0D + (UINT32) RegisterContext->GpiNum,=0D + &GpioPad,=0D + &GpiSmiBitOffset,=0D + &GpiHostSwOwnRegAddress,=0D + &GpiSmiStsRegAddress=0D + );=0D +=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D +=0D + ZeroMem (&Record, sizeof (DATABASE_RECORD));=0D +=0D + //=0D + // Gather information about the registration request=0D + //=0D + Record.Callback =3D DispatchFunction;=0D + Record.ChildContext.Gpi =3D *RegisterContext;=0D + Record.ProtocolType =3D GpiType;=0D + Record.Signature =3D DATABASE_RECORD_SIGNATURE;=0D +=0D + CopyMem (&Record.SrcDesc, &mPchGpiSourceDescTemplate, sizeof (PCH_SMM_SO= URCE_DESC) );=0D +=0D + Record.SrcDesc.Sts[0].Reg.Data.raw =3D GpiSmiStsRegAddress; // GPI SMI = Status register=0D + Record.SrcDesc.Sts[0].Bit =3D GpiSmiBitOffset; // Bit posi= tion for selected pad=0D +=0D + //=0D + // Insert GpiSmi handler to PchSmmCore database=0D + //=0D + *DispatchHandle =3D NULL;=0D +=0D + Status =3D SmmCoreInsertRecord (=0D + &Record,=0D + DispatchHandle=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + SmiHandlerProfileRegisterHandler (=0D + &gEfiSmmGpiDispatch2ProtocolGuid,=0D + (EFI_SMM_HANDLER_ENTRY_POINT2) DispatchFunction,=0D + (UINTN)RETURN_ADDRESS (0),=0D + RegisterContext,=0D + sizeof(*RegisterContext)=0D + );=0D +=0D + //=0D + // Enable GPI SMI=0D + // HOSTSW_OWN with respect to generating GPI SMI has negative logic:=0D + // - 0 (ACPI mode) - GPIO pad will be capable of generating SMI/NMI/SCI= =0D + // - 1 (GPIO mode) - GPIO pad will not generate SMI/NMI/SCI=0D + //=0D + Data32And =3D (UINT32)~(1u << GpiSmiBitOffset);=0D + MmioAnd32 (GpiHostSwOwnRegAddress, Data32And);=0D +=0D + //=0D + // Add HOSTSW_OWN programming into S3 boot script=0D + //=0D + Data32Or =3D 0;=0D + S3BootScriptSaveMemReadWrite (S3BootScriptWidthUint32, GpiHostSwOwnRegAd= dress, &Data32Or, &Data32And);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Unregister a GPI SMI source dispatch function with a parent SMM driver=0D +=0D + @param[in] This Pointer to the EFI_SMM_GPI_DISPATCH2_PRO= TOCOL instance.=0D + @param[in] DispatchHandle Handle of dispatch function to deregiste= r.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been successfu= lly=0D + unregistered and the SMI source has been= disabled=0D + if there are no other registered child d= ispatch=0D + functions for this SMI source.=0D + @retval EFI_INVALID_PARAMETER Handle is invalid.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchGpiSmiUnRegister (=0D + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This,=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + DATABASE_RECORD *RecordToDelete;=0D + DATABASE_RECORD *RecordInDb;=0D + LIST_ENTRY *LinkInDb;=0D + GPIO_PAD GpioPad;=0D + UINT8 GpiSmiBitOffset;=0D + UINT32 GpiHostSwOwnRegAddress;=0D + UINT32 GpiSmiStsRegAddress;=0D + UINT32 Data32Or;=0D + UINT32 Data32And;=0D + BOOLEAN DisableGpiSmiSource;=0D +=0D +=0D + if (DispatchHandle =3D=3D NULL) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle);=0D + if ((RecordToDelete->Signature !=3D DATABASE_RECORD_SIGNATURE) ||=0D + (RecordToDelete->ProtocolType !=3D GpiType)) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock = event has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + DisableGpiSmiSource =3D TRUE;=0D + //=0D + // Loop through all sources in record linked list to see if any other GP= I SMI=0D + // is installed on the same pin. If no then disable GPI SMI capability o= n this pad=0D + //=0D + LinkInDb =3D GetFirstNode (&mPrivateData.CallbackDataBase);=0D + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {=0D + RecordInDb =3D DATABASE_RECORD_FROM_LINK (LinkInDb);=0D + LinkInDb =3D GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb-= >Link);=0D + //=0D + // If this is the record to delete skip it=0D + //=0D + if (RecordInDb =3D=3D RecordToDelete) {=0D + continue;=0D + }=0D + //=0D + // Check if record is GPI SMI type=0D + //=0D + if (RecordInDb->ProtocolType =3D=3D GpiType) {=0D + //=0D + // Check if same GPIO pad is the source of this SMI=0D + //=0D + if (RecordInDb->ChildContext.Gpi.GpiNum =3D=3D RecordToDelete->Child= Context.Gpi.GpiNum) {=0D + DisableGpiSmiSource =3D FALSE;=0D + break;=0D + }=0D + }=0D + }=0D +=0D + if (DisableGpiSmiSource) {=0D + GpioGetPadAndSmiRegs (=0D + (UINT32) RecordToDelete->ChildContext.Gpi.GpiNum,=0D + &GpioPad,=0D + &GpiSmiBitOffset,=0D + &GpiHostSwOwnRegAddress,=0D + &GpiSmiStsRegAddress=0D + );=0D +=0D + Data32Or =3D 1u << GpiSmiBitOffset;=0D + Data32And =3D 0xFFFFFFFF;=0D + MmioOr32 (GpiHostSwOwnRegAddress, Data32Or);=0D + S3BootScriptSaveMemReadWrite (S3BootScriptWidthUint32, GpiHostSwOwnReg= Address, &Data32Or, &Data32And);=0D + }=0D +=0D +=0D + RemoveEntryList (&RecordToDelete->Link);=0D + ZeroMem (RecordToDelete, sizeof (DATABASE_RECORD));=0D + Status =3D gSmst->SmmFreePool (RecordToDelete);=0D +=0D + if (EFI_ERROR (Status)) {=0D + ASSERT (FALSE);=0D + return Status;=0D + }=0D + SmiHandlerProfileUnregisterHandler (=0D + &gEfiSmmGpiDispatch2ProtocolGuid,=0D + RecordToDelete->Callback,=0D + &RecordToDelete->ChildContext,=0D + RecordToDelete->ContextSize=0D + );=0D + return EFI_SUCCESS;=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmmHelpers.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/P= chSmmHelpers.c new file mode 100644 index 0000000000..6bbf9ea8e8 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelp= ers.c @@ -0,0 +1,332 @@ +/** @file=0D + Helper functions for PCH SMM dispatcher.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include "PchSmmHelpers.h"=0D +#include =0D +=0D +///=0D +/// #define BIT_ZERO 0x00000001=0D +///=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT32 BIT_ZERO =3D 0x00000001;=0D +=0D +///=0D +/// SUPPORT / HELPER FUNCTIONS (PCH version-independent)=0D +///=0D +=0D +/**=0D + Compare 2 SMM source descriptors' enable settings.=0D +=0D + @param[in] Src1 Pointer to the PCH SMI source descriptio= n table 1=0D + @param[in] Src2 Pointer to the PCH SMI source descriptio= n table 2=0D +=0D + @retval TRUE The enable settings of the 2 SMM source = descriptors are identical.=0D + @retval FALSE The enable settings of the 2 SMM source = descriptors are not identical.=0D +**/=0D +BOOLEAN=0D +CompareEnables (=0D + CONST IN PCH_SMM_SOURCE_DESC *Src1,=0D + CONST IN PCH_SMM_SOURCE_DESC *Src2=0D + )=0D +{=0D + BOOLEAN IsEqual;=0D + UINTN DescIndex;=0D +=0D + IsEqual =3D TRUE;=0D + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; DescIndex++) {=0D + ///=0D + /// It's okay to compare a NULL bit description to a non-NULL bit desc= ription.=0D + /// They are unequal and these tests will generate the correct result.= =0D + ///=0D + if (Src1->En[DescIndex].Bit !=3D Src2->En[DescIndex].Bit ||=0D + Src1->En[DescIndex].Reg.Type !=3D Src2->En[DescIndex].Reg.Type ||= =0D + Src1->En[DescIndex].Reg.Data.raw !=3D Src2->En[DescIndex].Reg.Data= .raw=0D + ) {=0D + IsEqual =3D FALSE;=0D + break;=0D + ///=0D + /// out of for loop=0D + ///=0D + }=0D + }=0D +=0D + return IsEqual;=0D +}=0D +=0D +/**=0D + Compare a bit descriptor to the enables of source descriptor. Includes n= ull address type.=0D +=0D + @param[in] BitDesc Pointer to the PCH SMI bit descriptor=0D + @param[in] Src Pointer to the PCH SMI source descriptio= n table 2=0D +=0D + @retval TRUE The bit desc is equal to any of the enab= les in source descriptor=0D + @retval FALSE The bid desc is not equal to all of the = enables in source descriptor=0D +**/=0D +BOOLEAN=0D +IsBitEqualToAnySourceEn (=0D + CONST IN PCH_SMM_BIT_DESC *BitDesc,=0D + CONST IN PCH_SMM_SOURCE_DESC *Src=0D + )=0D +{=0D + BOOLEAN IsEqual;=0D + UINTN DescIndex;=0D +=0D + IsEqual =3D FALSE;=0D +=0D + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; ++DescIndex) {=0D + if ((BitDesc->Reg.Type =3D=3D Src->En[DescIndex].Reg.Type) &&=0D + (BitDesc->Reg.Data.raw =3D=3D Src->En[DescIndex].Reg.Data.raw) &&= =0D + (BitDesc->Bit =3D=3D Src->En[DescIndex].Bit)) {=0D + IsEqual =3D TRUE;=0D + break;=0D + }=0D + }=0D + return IsEqual;=0D +}=0D +=0D +/**=0D + Compare 2 SMM source descriptors' statuses.=0D +=0D + @param[in] Src1 Pointer to the PCH SMI source descriptio= n table 1=0D + @param[in] Src2 Pointer to the PCH SMI source descriptio= n table 2=0D +=0D + @retval TRUE The statuses of the 2 SMM source descrip= tors are identical.=0D + @retval FALSE The statuses of the 2 SMM source descrip= tors are not identical.=0D +**/=0D +BOOLEAN=0D +CompareStatuses (=0D + CONST IN PCH_SMM_SOURCE_DESC *Src1,=0D + CONST IN PCH_SMM_SOURCE_DESC *Src2=0D + )=0D +{=0D + BOOLEAN IsEqual;=0D + UINTN DescIndex;=0D +=0D + IsEqual =3D TRUE;=0D +=0D + for (DescIndex =3D 0; DescIndex < NUM_STS_BITS; DescIndex++) {=0D + ///=0D + /// It's okay to compare a NULL bit description to a non-NULL bit desc= ription.=0D + /// They are unequal and these tests will generate the correct result.= =0D + ///=0D + if (Src1->Sts[DescIndex].Bit !=3D Src2->Sts[DescIndex].Bit ||=0D + Src1->Sts[DescIndex].Reg.Type !=3D Src2->Sts[DescIndex].Reg.Type |= |=0D + Src1->Sts[DescIndex].Reg.Data.raw !=3D Src2->Sts[DescIndex].Reg.Da= ta.raw=0D + ) {=0D + IsEqual =3D FALSE;=0D + break;=0D + ///=0D + /// out of for loop=0D + ///=0D + }=0D + }=0D +=0D + return IsEqual;=0D +}=0D +=0D +/**=0D + Compare 2 SMM source descriptors, based on Enable settings and Status se= ttings of them.=0D +=0D + @param[in] Src1 Pointer to the PCH SMI source descriptio= n table 1=0D + @param[in] Src2 Pointer to the PCH SMI source descriptio= n table 2=0D +=0D + @retval TRUE The 2 SMM source descriptors are identic= al.=0D + @retval FALSE The 2 SMM source descriptors are not ide= ntical.=0D +**/=0D +BOOLEAN=0D +CompareSources (=0D + CONST IN PCH_SMM_SOURCE_DESC *Src1,=0D + CONST IN PCH_SMM_SOURCE_DESC *Src2=0D + )=0D +{=0D + return (BOOLEAN) (CompareEnables (Src1, Src2) && CompareStatuses (Src1, = Src2));=0D +}=0D +=0D +/**=0D + Check if an SMM source is active.=0D +=0D + @param[in] Src Pointer to the PCH SMI source descriptio= n table=0D + @param[in] SciEn Indicate if SCI is enabled or not=0D + @param[in] SmiEnValue Value from R_ACPI_IO_SMI_EN=0D + @param[in] SmiStsValue Value from R_ACPI_IO_SMI_STS=0D +=0D + @retval TRUE It is active.=0D + @retval FALSE It is inactive.=0D +**/=0D +BOOLEAN=0D +SourceIsActive (=0D + CONST IN PCH_SMM_SOURCE_DESC *Src,=0D + CONST IN BOOLEAN SciEn,=0D + CONST IN UINT32 SmiEnValue,=0D + CONST IN UINT32 SmiStsValue=0D + )=0D +{=0D + UINTN DescIndex;=0D +=0D + ///=0D + /// This source is dependent on SciEn, and SciEn =3D=3D 1. An ACPI OS i= s present,=0D + /// so we shouldn't do anything w/ this source until SciEn =3D=3D 0.=0D + ///=0D + if ((Src->Flags =3D=3D PCH_SMM_SCI_EN_DEPENDENT) && (SciEn)) {=0D + return FALSE;=0D + }=0D +=0D + ///=0D + /// Checking top level SMI status. If the status is not active, return f= alse immediately=0D + ///=0D + if (!IS_BIT_DESC_NULL (Src->PmcSmiSts)) {=0D + if ((Src->PmcSmiSts.Reg.Type =3D=3D ACPI_ADDR_TYPE) &&=0D + (Src->PmcSmiSts.Reg.Data.acpi =3D=3D R_ACPI_IO_SMI_STS) &&=0D + ((SmiStsValue & (1u << Src->PmcSmiSts.Bit)) =3D=3D 0)) {=0D + return FALSE;=0D + }=0D + }=0D +=0D + ///=0D + /// Read each bit desc from hardware and make sure it's a one=0D + ///=0D + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; DescIndex++) {=0D + if (!IS_BIT_DESC_NULL (Src->En[DescIndex])) {=0D + if ((Src->En[DescIndex].Reg.Type =3D=3D ACPI_ADDR_TYPE) &&=0D + (Src->En[DescIndex].Reg.Data.acpi =3D=3D R_ACPI_IO_SMI_EN) &&=0D + ((SmiEnValue & (1u << Src->En[DescIndex].Bit)) =3D=3D 0)) {=0D + return FALSE;=0D + } else if (ReadBitDesc (&Src->En[DescIndex]) =3D=3D 0) {=0D + return FALSE;=0D + }=0D + }=0D + }=0D +=0D + ///=0D + /// Read each bit desc from hardware and make sure it's a one=0D + ///=0D + for (DescIndex =3D 0; DescIndex < NUM_STS_BITS; DescIndex++) {=0D + if (!IS_BIT_DESC_NULL (Src->Sts[DescIndex])) {=0D + if ((Src->Sts[DescIndex].Reg.Type =3D=3D ACPI_ADDR_TYPE) &&=0D + (Src->Sts[DescIndex].Reg.Data.acpi =3D=3D R_ACPI_IO_SMI_STS) &&= =0D + ((SmiStsValue & (1u << Src->Sts[DescIndex].Bit)) =3D=3D 0)) {=0D + return FALSE;=0D + } else if (ReadBitDesc (&Src->Sts[DescIndex]) =3D=3D 0) {=0D + return FALSE;=0D + }=0D + }=0D + }=0D +=0D + return TRUE;=0D +}=0D +=0D +/**=0D + Enable the SMI source event by set the SMI enable bit, this function wou= ld also clear SMI=0D + status bit to make initial state is correct=0D +=0D + @param[in] SrcDesc Pointer to the PCH SMI source descriptio= n table=0D +=0D +**/=0D +VOID=0D +PchSmmEnableSource (=0D + CONST PCH_SMM_SOURCE_DESC *SrcDesc=0D + )=0D +{=0D + UINTN DescIndex;=0D +=0D + ///=0D + /// Set enables to 1 by writing a 1=0D + ///=0D + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; DescIndex++) {=0D + if (!IS_BIT_DESC_NULL (SrcDesc->En[DescIndex])) {=0D + WriteBitDesc (&SrcDesc->En[DescIndex], 1, FALSE);=0D + }=0D + }=0D + ///=0D + /// Clear statuses to 0 by writing a 1=0D + ///=0D + for (DescIndex =3D 0; DescIndex < NUM_STS_BITS; DescIndex++) {=0D + if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) {=0D + WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE);=0D + }=0D + }=0D +}=0D +=0D +/**=0D + Disable the SMI source event by clear the SMI enable bit=0D +=0D + @param[in] SrcDesc Pointer to the PCH SMI source descriptio= n table=0D +=0D +**/=0D +VOID=0D +PchSmmDisableSource (=0D + CONST PCH_SMM_SOURCE_DESC *SrcDesc=0D + )=0D +{=0D + UINTN DescIndex;=0D +=0D + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; DescIndex++) {=0D + if (!IS_BIT_DESC_NULL (SrcDesc->En[DescIndex])) {=0D + WriteBitDesc (&SrcDesc->En[DescIndex], 0, FALSE);=0D + }=0D + }=0D +}=0D +=0D +/**=0D + Clear the SMI status bit by set the source bit of SMI status register=0D +=0D + @param[in] SrcDesc Pointer to the PCH SMI source descriptio= n table=0D +=0D +**/=0D +VOID=0D +PchSmmClearSource (=0D + CONST PCH_SMM_SOURCE_DESC *SrcDesc=0D + )=0D +{=0D + UINTN DescIndex;=0D +=0D + for (DescIndex =3D 0; DescIndex < NUM_STS_BITS; DescIndex++) {=0D + if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) {=0D + WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE);=0D + }=0D + }=0D +}=0D +=0D +/**=0D + Sets the source to a 1 and then waits for it to clear.=0D + Be very careful when calling this function -- it will not=0D + ASSERT. An acceptable case to call the function is when=0D + waiting for the NEWCENTURY_STS bit to clear (which takes=0D + 3 RTCCLKs).=0D +=0D + @param[in] SrcDesc Pointer to the PCH SMI source descriptio= n table=0D +=0D +**/=0D +VOID=0D +PchSmmClearSourceAndBlock (=0D + CONST PCH_SMM_SOURCE_DESC *SrcDesc=0D + )=0D +{=0D + UINTN DescIndex;=0D + BOOLEAN IsSet;=0D +=0D + for (DescIndex =3D 0; DescIndex < NUM_STS_BITS; DescIndex++) {=0D +=0D + if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) {=0D + ///=0D + /// Write the bit=0D + ///=0D + WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE);=0D +=0D + ///=0D + /// Don't return until the bit actually clears.=0D + ///=0D + IsSet =3D TRUE;=0D + while (IsSet) {=0D + IsSet =3D ReadBitDesc (&SrcDesc->Sts[DescIndex]);=0D + ///=0D + /// IsSet will eventually clear -- or else we'll have=0D + /// an infinite loop.=0D + ///=0D + }=0D + }=0D + }=0D +}=0D +=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmmHelpers.h b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/P= chSmmHelpers.h new file mode 100644 index 0000000000..db7713fa02 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelp= ers.h @@ -0,0 +1,155 @@ +/** @file=0D + Helper functions for PCH SMM=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#ifndef PCH_SMM_HELPERS_H=0D +#define PCH_SMM_HELPERS_H=0D +=0D +#include "PchSmm.h"=0D +#include "PchxSmmHelpers.h"=0D +//=0D +// ///////////////////////////////////////////////////////////////////////= ////////////////////////////////////////////=0D +// SUPPORT / HELPER FUNCTIONS (PCH version-independent)=0D +//=0D +=0D +/**=0D + Publish SMI Dispatch protocols.=0D +=0D +=0D +**/=0D +VOID=0D +PchSmmPublishDispatchProtocols (=0D + VOID=0D + );=0D +=0D +/**=0D + Compare 2 SMM source descriptors' enable settings.=0D +=0D + @param[in] Src1 Pointer to the PCH SMI source descriptio= n table 1=0D + @param[in] Src2 Pointer to the PCH SMI source descriptio= n table 2=0D +=0D + @retval TRUE The enable settings of the 2 SMM source = descriptors are identical.=0D + @retval FALSE The enable settings of the 2 SMM source = descriptors are not identical.=0D +**/=0D +BOOLEAN=0D +CompareEnables (=0D + CONST IN PCH_SMM_SOURCE_DESC *Src1,=0D + CONST IN PCH_SMM_SOURCE_DESC *Src2=0D + );=0D +=0D +/**=0D + Compare a bit descriptor to the enables of source descriptor. Includes n= ull address type.=0D +=0D + @param[in] BitDesc Pointer to the PCH SMI bit descriptor=0D + @param[in] Src Pointer to the PCH SMI source descriptio= n table 2=0D +=0D + @retval TRUE The bit desc is equal to any of the enab= les in source descriptor=0D + @retval FALSE The bid desc is not equal to all of the = enables in source descriptor=0D +**/=0D +BOOLEAN=0D +IsBitEqualToAnySourceEn (=0D + CONST IN PCH_SMM_BIT_DESC *BitDesc,=0D + CONST IN PCH_SMM_SOURCE_DESC *Src=0D + );=0D +=0D +/**=0D + Compare 2 SMM source descriptors' statuses.=0D +=0D + @param[in] Src1 Pointer to the PCH SMI source descriptio= n table 1=0D + @param[in] Src2 Pointer to the PCH SMI source descriptio= n table 2=0D +=0D + @retval TRUE The statuses of the 2 SMM source descrip= tors are identical.=0D + @retval FALSE The statuses of the 2 SMM source descrip= tors are not identical.=0D +**/=0D +BOOLEAN=0D +CompareStatuses (=0D + CONST IN PCH_SMM_SOURCE_DESC *Src1,=0D + CONST IN PCH_SMM_SOURCE_DESC *Src2=0D + );=0D +=0D +/**=0D + Compare 2 SMM source descriptors, based on Enable settings and Status se= ttings of them.=0D +=0D + @param[in] Src1 Pointer to the PCH SMI source descriptio= n table 1=0D + @param[in] Src2 Pointer to the PCH SMI source descriptio= n table 2=0D +=0D + @retval TRUE The 2 SMM source descriptors are identic= al.=0D + @retval FALSE The 2 SMM source descriptors are not ide= ntical.=0D +**/=0D +BOOLEAN=0D +CompareSources (=0D + CONST IN PCH_SMM_SOURCE_DESC *Src1,=0D + CONST IN PCH_SMM_SOURCE_DESC *Src2=0D + );=0D +=0D +/**=0D + Check if an SMM source is active.=0D +=0D + @param[in] Src Pointer to the PCH SMI source descriptio= n table=0D + @param[in] SciEn Indicate if SCI is enabled or not=0D + @param[in] SmiEnValue Value from R_PCH_SMI_EN=0D + @param[in] SmiStsValue Value from R_PCH_SMI_STS=0D +=0D + @retval TRUE It is active.=0D + @retval FALSE It is inactive.=0D +**/=0D +BOOLEAN=0D +SourceIsActive (=0D + CONST IN PCH_SMM_SOURCE_DESC *Src,=0D + CONST IN BOOLEAN SciEn,=0D + CONST IN UINT32 SmiEnValue,=0D + CONST IN UINT32 SmiStsValue=0D + );=0D +=0D +/**=0D + Enable the SMI source event by set the SMI enable bit, this function wou= ld also clear SMI=0D + status bit to make initial state is correct=0D +=0D + @param[in] SrcDesc Pointer to the PCH SMI source descriptio= n table=0D +=0D +**/=0D +VOID=0D +PchSmmEnableSource (=0D + CONST PCH_SMM_SOURCE_DESC *SrcDesc=0D + );=0D +=0D +/**=0D + Disable the SMI source event by clear the SMI enable bit=0D +=0D + @param[in] SrcDesc Pointer to the PCH SMI source descriptio= n table=0D +=0D +**/=0D +VOID=0D +PchSmmDisableSource (=0D + CONST PCH_SMM_SOURCE_DESC *SrcDesc=0D + );=0D +=0D +/**=0D + Clear the SMI status bit by set the source bit of SMI status register=0D +=0D + @param[in] SrcDesc Pointer to the PCH SMI source descriptio= n table=0D +=0D +**/=0D +VOID=0D +PchSmmClearSource (=0D + CONST PCH_SMM_SOURCE_DESC *SrcDesc=0D + );=0D +=0D +/**=0D + Sets the source to a 1 and then waits for it to clear.=0D + Be very careful when calling this function -- it will not=0D + ASSERT. An acceptable case to call the function is when=0D + waiting for the NEWCENTURY_STS bit to clear (which takes=0D + 3 RTCCLKs).=0D +=0D + @param[in] SrcDesc Pointer to the PCH SMI source descriptio= n table=0D +=0D +**/=0D +VOID=0D +PchSmmClearSourceAndBlock (=0D + CONST PCH_SMM_SOURCE_DESC *SrcDesc=0D + );=0D +=0D +#endif=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmmPeriodicTimer.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher= /Smm/PchSmmPeriodicTimer.c new file mode 100644 index 0000000000..3c3e638cbf --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeri= odicTimer.c @@ -0,0 +1,667 @@ +/** @file=0D + File to contain all the hardware specific stuff for the Periodical Timer= dispatch protocol.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include "PchSmmHelpers.h"=0D +#include =0D +#include =0D +=0D +//=0D +// There is only one instance for PeriodicTimerCommBuffer.=0D +// It's safe in SMM since there is no re-entry for the function.=0D +//=0D +GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_PERIODIC_TIMER_CONTEXT mPch= PeriodicTimerCommBuffer;=0D +=0D +typedef enum {=0D + PERIODIC_TIMER=3D 0,=0D + SWSMI_TIMER,=0D + NUM_TIMERS=0D +} SUPPORTED_TIMER;=0D +=0D +typedef struct _TIMER_INTERVAL {=0D + UINT64 Interval;=0D + UINT8 AssociatedTimer;=0D +} TIMER_INTERVAL;=0D +=0D +#define NUM_INTERVALS 8=0D +=0D +//=0D +// Time constants, in 100 nano-second units=0D +//=0D +#define TIME_64s 640000000 ///< 64 s=0D +#define TIME_32s 320000000 ///< 32 s=0D +#define TIME_16s 160000000 ///< 16 s=0D +#define TIME_8s 80000000 ///< 8 s=0D +#define TIME_64ms 640000 ///< 64 ms=0D +#define TIME_32ms 320000 ///< 32 ms=0D +#define TIME_16ms 160000 ///< 16 ms=0D +#define TIME_1_5ms 15000 ///< 1.5 ms=0D +=0D +typedef enum {=0D + INDEX_TIME_64s =3D 0,=0D + INDEX_TIME_32s,=0D + INDEX_TIME_16s,=0D + INDEX_TIME_8s,=0D + INDEX_TIME_64ms,=0D + INDEX_TIME_32ms,=0D + INDEX_TIME_16ms,=0D + INDEX_TIME_1_5ms,=0D + INDEX_TIME_MAX=0D +} TIMER_INTERVAL_INDEX;=0D +=0D +static TIMER_INTERVAL mSmmPeriodicTimerIntervals[NUM_INTERVALS] =3D {=0D + {=0D + TIME_64s,=0D + PERIODIC_TIMER=0D + },=0D + {=0D + TIME_32s,=0D + PERIODIC_TIMER=0D + },=0D + {=0D + TIME_16s,=0D + PERIODIC_TIMER=0D + },=0D + {=0D + TIME_8s,=0D + PERIODIC_TIMER=0D + },=0D + {=0D + TIME_64ms,=0D + SWSMI_TIMER=0D + },=0D + {=0D + TIME_32ms,=0D + SWSMI_TIMER=0D + },=0D + {=0D + TIME_16ms,=0D + SWSMI_TIMER=0D + },=0D + {=0D + TIME_1_5ms,=0D + SWSMI_TIMER=0D + },=0D +};=0D +=0D +typedef struct _TIMER_INFO {=0D + UINTN NumChildren; ///< number of children using this timer=0D + UINT64 MinReqInterval; ///< minimum interval required by children=0D + UINTN CurrentSetting; ///< interval this timer is set at right now= (index into interval table)=0D +} TIMER_INFO;=0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED TIMER_INFO mTimers[NUM_TIMERS];=0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mTimerSourceDesc[N= UM_TIMERS] =3D {=0D + {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_EN}=0D + },=0D + S_ACPI_IO_SMI_EN,=0D + N_ACPI_IO_SMI_EN_PERIODIC=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_PERIODIC=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_PERIODIC=0D + }=0D + },=0D + {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_EN}=0D + },=0D + S_ACPI_IO_SMI_EN,=0D + N_ACPI_IO_SMI_EN_SWSMI_TMR=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_SWSMI_TMR=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_SWSMI_TMR=0D + }=0D + }=0D +};=0D +=0D +/**=0D + Program Smm Periodic Timer=0D +=0D + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC insta= nce.=0D +**/=0D +VOID=0D +PchSmmPeriodicTimerProgramTimers (=0D + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc=0D + );=0D +=0D +/**=0D + Convert the dispatch context to the timer interval, this function will a= ssert if then either:=0D + (1) The context contains an invalid interval=0D + (2) The timer interval table is corrupt=0D +=0D + @param[in] DispatchContext The pointer to the Dispatch Context=0D +=0D + @retval TIMER_INTERVAL The timer interval of input dispatch con= text=0D +**/=0D +TIMER_INTERVAL *=0D +ContextToTimerInterval (=0D + IN PCH_SMM_CONTEXT *DispatchContext=0D + )=0D +{=0D + UINTN loopvar;=0D +=0D + ///=0D + /// Determine which timer this child is using=0D + ///=0D + for (loopvar =3D 0; loopvar < NUM_INTERVALS; loopvar++) {=0D + if (((DispatchContext->PeriodicTimer.SmiTickInterval =3D=3D 0) &&=0D + (DispatchContext->PeriodicTimer.Period >=3D mSmmPeriodicTimerInte= rvals[loopvar].Interval)) ||=0D + (DispatchContext->PeriodicTimer.SmiTickInterval =3D=3D mSmmPeriodi= cTimerIntervals[loopvar].Interval)) {=0D + return &mSmmPeriodicTimerIntervals[loopvar];=0D + }=0D + }=0D + ///=0D + /// If this assertion fires, then either:=0D + /// (1) the context contains an invalid interval=0D + /// (2) the timer interval table is corrupt=0D + ///=0D + ASSERT (FALSE);=0D +=0D + return NULL;=0D +}=0D +=0D +/**=0D + Figure out which timer the child is requesting and=0D + send back the source description=0D +=0D + @param[in] DispatchContext The pointer to the Dispatch Context inst= ances=0D + @param[out] SrcDesc The pointer to the source description=0D +=0D +**/=0D +VOID=0D +MapPeriodicTimerToSrcDesc (=0D + IN PCH_SMM_CONTEXT *DispatchContext,=0D + OUT PCH_SMM_SOURCE_DESC *SrcDesc=0D + )=0D +{=0D + TIMER_INTERVAL *TimerInterval;=0D +=0D + ///=0D + /// Figure out which timer the child is requesting and=0D + /// send back the source description=0D + ///=0D + TimerInterval =3D ContextToTimerInterval (DispatchContext);=0D + if (TimerInterval =3D=3D NULL) {=0D + return;=0D + }=0D +=0D + CopyMem (=0D + (VOID *) SrcDesc,=0D + (VOID *) (&mTimerSourceDesc[TimerInterval->AssociatedTimer]),=0D + sizeof (PCH_SMM_SOURCE_DESC)=0D + );=0D +=0D + ///=0D + /// Program the value of the interval into hardware=0D + ///=0D + PchSmmPeriodicTimerProgramTimers (SrcDesc);=0D +}=0D +=0D +/**=0D + Update the elapsed time from the Interval data of DATABASE_RECORD=0D +=0D + @param[in] Record The pointer to the DATABASE_RECORD.=0D + @param[out] HwContext The Context to be updated.=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +PeriodicTimerGetContext (=0D + IN DATABASE_RECORD *Record,=0D + OUT PCH_SMM_CONTEXT *HwContext=0D + )=0D +{=0D + TIMER_INTERVAL *TimerInterval;=0D +=0D + ASSERT (Record->ProtocolType =3D=3D PeriodicTimerType);=0D +=0D + TimerInterval =3D ContextToTimerInterval (&Record->ChildContext);=0D + if (TimerInterval =3D=3D NULL) {=0D + return;=0D + }=0D + ///=0D + /// Ignore the hardware context. It's not required for this protocol.=0D + /// Instead, just increment the child's context.=0D + /// Update the elapsed time w/ the data from our tables=0D + ///=0D + Record->MiscData.ElapsedTime +=3D mTimers[TimerInterval->AssociatedTimer= ].MinReqInterval;=0D + *HwContext =3D Record->ChildContext;=0D +}=0D +=0D +/**=0D + Check whether Periodic Timer of two contexts match=0D +=0D + @param[in] Context1 Context 1 that includes Periodic Timer = 1=0D + @param[in] Context2 Context 2 that includes Periodic Timer = 2=0D +=0D + @retval FALSE Periodic Timer match=0D + @retval TRUE Periodic Timer don't match=0D +**/=0D +BOOLEAN=0D +EFIAPI=0D +PeriodicTimerCmpContext (=0D + IN PCH_SMM_CONTEXT *HwContext,=0D + IN PCH_SMM_CONTEXT *ChildContext=0D + )=0D +{=0D + DATABASE_RECORD *Record;=0D + Record =3D DATABASE_RECORD_FROM_CHILDCONTEXT (ChildContext);=0D +=0D + if (!Record->MiscData.TimerSmiEnabled) {=0D + return FALSE;=0D + }=0D + if (Record->MiscData.ElapsedTime >=3D ChildContext->PeriodicTimer.Period= ) {=0D + ///=0D + /// For EDKII, the ElapsedTime is reset when PeriodicTimerGetCommBuffe= r=0D + ///=0D + return TRUE;=0D + } else {=0D + return FALSE;=0D + }=0D +}=0D +=0D +/**=0D + Gather the CommBuffer information of SmmPeriodicTimerDispatch2.=0D +=0D + @param[in] Record No use=0D + @param[out] CommBuffer Point to the CommBuffer structure=0D + @param[out] CommBufferSize Point to the Size of CommBuffer structur= e=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +PeriodicTimerGetCommBuffer (=0D + IN DATABASE_RECORD *Record,=0D + OUT VOID **CommBuffer,=0D + OUT UINTN *CommBufferSize=0D + )=0D +{=0D + ASSERT (Record->ProtocolType =3D=3D PeriodicTimerType);=0D +=0D + mPchPeriodicTimerCommBuffer.ElapsedTime =3D Record->MiscData.ElapsedTime= ;=0D +=0D + ///=0D + /// For EDKII, the ElapsedTime is reset here=0D + ///=0D + Record->MiscData.ElapsedTime =3D 0;=0D +=0D + ///=0D + /// Return the CommBuffer=0D + ///=0D + *CommBuffer =3D (VOID *) &mPchPeriodicTimerCommBuffer;=0D + *CommBufferSize =3D sizeof (EFI_SMM_PERIODIC_TIMER_CONTEXT);=0D +}=0D +=0D +/**=0D + Program Smm Periodic Timer=0D +=0D + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC insta= nce.=0D +**/=0D +VOID=0D +PchSmmPeriodicTimerProgramTimers (=0D + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc=0D + )=0D +{=0D + SUPPORTED_TIMER Timer;=0D + DATABASE_RECORD *RecordInDb;=0D + LIST_ENTRY *LinkInDb;=0D + TIMER_INTERVAL *TimerInterval;=0D +=0D + ///=0D + /// Find the minimum required interval for each timer=0D + ///=0D + for (Timer =3D 0; Timer < NUM_TIMERS; Timer++) {=0D + mTimers[Timer].MinReqInterval =3D ~ (UINT64) 0x0;=0D + mTimers[Timer].NumChildren =3D 0;=0D + }=0D +=0D + LinkInDb =3D GetFirstNode (&mPrivateData.CallbackDataBase);=0D + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {=0D + RecordInDb =3D DATABASE_RECORD_FROM_LINK (LinkInDb);=0D + if (RecordInDb->ProtocolType =3D=3D PeriodicTimerType) {=0D + if (RecordInDb->MiscData.TimerSmiEnabled) {=0D + ///=0D + /// This child is registerd with the PeriodicTimer protocol=0D + ///=0D + TimerInterval =3D ContextToTimerInterval (&RecordInDb->ChildContex= t);=0D + if (TimerInterval =3D=3D NULL) {=0D + return;=0D + }=0D +=0D + Timer =3D TimerInterval->AssociatedTimer;=0D + if (Timer < 0 || Timer >=3D NUM_TIMERS) {=0D + ASSERT (FALSE);=0D + CpuDeadLoop ();=0D + return;=0D + }=0D + if (mTimers[Timer].MinReqInterval > RecordInDb->ChildContext.Perio= dicTimer.SmiTickInterval) {=0D + mTimers[Timer].MinReqInterval =3D RecordInDb->ChildContext.Perio= dicTimer.SmiTickInterval;=0D + }=0D + mTimers[Timer].NumChildren++;=0D + }=0D + }=0D + LinkInDb =3D GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb-= >Link);=0D + }=0D + ///=0D + /// Program the hardware=0D + ///=0D + if (mTimers[PERIODIC_TIMER].NumChildren > 0) {=0D + switch (mTimers[PERIODIC_TIMER].MinReqInterval) {=0D + case TIME_64s:=0D + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate64s);=0D + mTimers[PERIODIC_TIMER].CurrentSetting =3D INDEX_TIME_64s;=0D + break;=0D +=0D + case TIME_32s:=0D + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate32s);=0D + mTimers[PERIODIC_TIMER].CurrentSetting =3D INDEX_TIME_32s;=0D + break;=0D +=0D + case TIME_16s:=0D + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate16s);=0D + mTimers[PERIODIC_TIMER].CurrentSetting =3D INDEX_TIME_16s;=0D + break;=0D +=0D + case TIME_8s:=0D + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate8s);=0D + mTimers[PERIODIC_TIMER].CurrentSetting =3D INDEX_TIME_8s;=0D + break;=0D +=0D + default:=0D + ASSERT (FALSE);=0D + break;=0D + }=0D +=0D + ///=0D + /// Restart the timer here, just need to clear the SMI=0D + ///=0D + if (SrcDesc->Sts[0].Bit =3D=3D N_ACPI_IO_SMI_STS_PERIODIC) {=0D + PchSmmClearSource (&mTimerSourceDesc[PERIODIC_TIMER]);=0D + }=0D + } else {=0D + PchSmmDisableSource (&mTimerSourceDesc[PERIODIC_TIMER]);=0D + }=0D +=0D + if (mTimers[SWSMI_TIMER].NumChildren > 0) {=0D + switch (mTimers[SWSMI_TIMER].MinReqInterval) {=0D + case TIME_64ms:=0D + PmcSetSwSmiRate (PmcSwSmiRate64ms);=0D + mTimers[SWSMI_TIMER].CurrentSetting =3D INDEX_TIME_64ms;=0D + break;=0D +=0D + case TIME_32ms:=0D + PmcSetSwSmiRate (PmcSwSmiRate32ms);=0D + mTimers[SWSMI_TIMER].CurrentSetting =3D INDEX_TIME_32ms;=0D + break;=0D +=0D + case TIME_16ms:=0D + PmcSetSwSmiRate (PmcSwSmiRate16ms);=0D + mTimers[SWSMI_TIMER].CurrentSetting =3D INDEX_TIME_16ms;=0D + break;=0D +=0D + case TIME_1_5ms:=0D + PmcSetSwSmiRate (PmcSwSmiRate1p5ms);=0D + mTimers[SWSMI_TIMER].CurrentSetting =3D INDEX_TIME_1_5ms;=0D + break;=0D +=0D + default:=0D + ASSERT (FALSE);=0D + break;=0D + }=0D +=0D + ///=0D + /// Restart the timer here, need to disable, clear, then enable to res= tart this timer=0D + ///=0D + if (SrcDesc->Sts[0].Bit =3D=3D N_ACPI_IO_SMI_STS_SWSMI_TMR) {=0D + PchSmmDisableSource (&mTimerSourceDesc[SWSMI_TIMER]);=0D + PchSmmClearSource (&mTimerSourceDesc[SWSMI_TIMER]);=0D + PchSmmEnableSource (&mTimerSourceDesc[SWSMI_TIMER]);=0D + }=0D + } else {=0D + PchSmmDisableSource (&mTimerSourceDesc[SWSMI_TIMER]);=0D + }=0D +}=0D +=0D +/**=0D + This services returns the next SMI tick period that is supported by the = chipset.=0D + The order returned is from longest to shortest interval period.=0D +=0D + @param[in] This Pointer to the EFI_SMM_PERIODIC_TIMER_DI= SPATCH2_PROTOCOL instance.=0D + @param[in, out] SmiTickInterval Pointer to pointer of the next shorter S= MI interval period that is supported by the child.=0D +=0D + @retval EFI_SUCCESS The service returned successfully.=0D + @retval EFI_INVALID_PARAMETER The parameter SmiTickInterval is invalid= .=0D +**/=0D +EFI_STATUS=0D +PchSmmPeriodicTimerDispatchGetNextShorterInterval (=0D + IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This,=0D + IN OUT UINT64 **SmiTickInterval=0D + )=0D +{=0D + TIMER_INTERVAL *IntervalPointer;=0D +=0D + ASSERT (SmiTickInterval !=3D NULL);=0D +=0D + IntervalPointer =3D (TIMER_INTERVAL *) *SmiTickInterval;=0D +=0D + if (IntervalPointer =3D=3D NULL) {=0D + ///=0D + /// The first time child requesting an interval=0D + ///=0D + IntervalPointer =3D &mSmmPeriodicTimerIntervals[0];=0D + } else if (IntervalPointer =3D=3D &mSmmPeriodicTimerIntervals[NUM_INTERV= ALS - 1]) {=0D + ///=0D + /// At end of the list=0D + ///=0D + IntervalPointer =3D NULL;=0D + } else {=0D + if ((IntervalPointer >=3D &mSmmPeriodicTimerIntervals[0]) &&=0D + (IntervalPointer < &mSmmPeriodicTimerIntervals[NUM_INTERVALS - 1])= =0D + ) {=0D + ///=0D + /// Get the next interval in the list=0D + ///=0D + IntervalPointer++;=0D + } else {=0D + ///=0D + /// Input is out of range=0D + ///=0D + return EFI_INVALID_PARAMETER;=0D + }=0D + }=0D +=0D + if (IntervalPointer !=3D NULL) {=0D + *SmiTickInterval =3D &IntervalPointer->Interval;=0D + } else {=0D + *SmiTickInterval =3D NULL;=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + This function is responsible for calculating and enabling any timers tha= t are required=0D + to dispatch messages to children. The SrcDesc argument isn't acutally us= ed.=0D +=0D + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC insta= nce.=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +PchSmmPeriodicTimerClearSource (=0D + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc=0D + )=0D +{=0D + PchSmmPeriodicTimerProgramTimers (SrcDesc);=0D +}=0D +=0D +=0D +/**=0D + Check if the handle is in type of PeriodicTimer=0D +=0D + @retval TRUE The handle is in type of PeriodicT= imer.=0D + @retval FALSE The handle is not in type of Perio= dicTimer.=0D +**/=0D +BOOLEAN=0D +IsSmmPeriodicTimerHandle (=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + DATABASE_RECORD *RecordInDb;=0D + LIST_ENTRY *LinkInDb;=0D +=0D + LinkInDb =3D GetFirstNode (&mPrivateData.CallbackDataBase);=0D + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {=0D + if (DispatchHandle =3D=3D (EFI_HANDLE) LinkInDb) {=0D + RecordInDb =3D DATABASE_RECORD_FROM_LINK (LinkInDb);=0D + if (RecordInDb->ProtocolType =3D=3D PeriodicTimerType) {=0D + return TRUE;=0D + }=0D + }=0D + LinkInDb =3D GetNextNode (&mPrivateData.CallbackDataBase, LinkInDb);=0D + }=0D + return FALSE;=0D +}=0D +=0D +/**=0D + Pause SMM periodic timer callback function.=0D +=0D + This function disable the SMI enable of SMI timer according to the Dispa= tchHandle,=0D + which is returned by SMM periodic timer callback registration.=0D +=0D + @retval EFI_SUCCESS This operation is complete.=0D + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchSmmPeriodicTimerControlPause (=0D + IN PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL *This,=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + DATABASE_RECORD *RecordInDb;=0D +=0D + if (IsSmmPeriodicTimerHandle (DispatchHandle) =3D=3D FALSE) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + RecordInDb =3D DATABASE_RECORD_FROM_LINK (DispatchHandle);=0D + RecordInDb->MiscData.TimerSmiEnabled =3D FALSE;=0D + //=0D + // reset the timer interval per SMI trigger due to stop a periodic timer= SMI=0D + //=0D + PchSmmPeriodicTimerProgramTimers (&RecordInDb->SrcDesc);=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Resume SMM periodic timer callback function.=0D +=0D + This function enable the SMI enable of SMI timer according to the Dispat= chHandle,=0D + which is returned by SMM periodic timer callback registration.=0D +=0D + @retval EFI_SUCCESS This operation is complete.=0D + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchSmmPeriodicTimerControlResume (=0D + IN PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL *This,=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + DATABASE_RECORD *RecordInDb;=0D +=0D + if (IsSmmPeriodicTimerHandle (DispatchHandle) =3D=3D FALSE) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D + RecordInDb =3D DATABASE_RECORD_FROM_LINK (DispatchHandle);=0D + RecordInDb->MiscData.TimerSmiEnabled =3D TRUE;=0D + //=0D + // reset the timer interval per SMI trigger due to resume a periodic tim= er SMI=0D + //=0D + PchSmmPeriodicTimerProgramTimers (&RecordInDb->SrcDesc);=0D + return EFI_SUCCESS;=0D +}=0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL mPch= SmmPeriodicTimerControlProtocol =3D {=0D + PchSmmPeriodicTimerControlPause,=0D + PchSmmPeriodicTimerControlResume=0D +};=0D +=0D +/**=0D + Install PCH SMM periodic timer control protocol=0D +=0D + @param[in] Handle handle for this driver=0D +=0D + @retval EFI_SUCCESS Driver initialization completed su= ccessfully=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +InstallPchSmmPeriodicTimerControlProtocol (=0D + IN EFI_HANDLE Handle=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Install protocol interface=0D + //=0D + Status =3D gSmst->SmmInstallProtocolInterface (=0D + &Handle,=0D + &gPchSmmPeriodicTimerControlGuid,=0D + EFI_NATIVE_INTERFACE,=0D + &mPchSmmPeriodicTimerControlProtocol=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmmPowerButton.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/S= mm/PchSmmPowerButton.c new file mode 100644 index 0000000000..bfed944848 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPowe= rButton.c @@ -0,0 +1,81 @@ +/** @file=0D + File to contain all the hardware specific stuff for the Smm Power Button= dispatch protocol.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include =0D +#include =0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mPowerButtonSource= Desc =3D {=0D + PCH_SMM_SCI_EN_DEPENDENT,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_PM1_EN}=0D + },=0D + S_ACPI_IO_PM1_EN,=0D + N_ACPI_IO_PM1_EN_PWRBTN=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_PM1_STS}=0D + },=0D + S_ACPI_IO_PM1_STS,=0D + N_ACPI_IO_PM1_STS_PWRBTN=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_PM1_STS_REG=0D + }=0D +};=0D +=0D +/**=0D + Get the power button status.=0D +=0D + @param[in] Record The pointer to the DATABASE_RECORD.=0D + @param[out] Context Calling context from the hardware, will = be updated with the current power button status.=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +PowerButtonGetContext (=0D + IN DATABASE_RECORD *Record,=0D + OUT PCH_SMM_CONTEXT *Context=0D + )=0D +{=0D + if (PmcGetPwrBtnLevel ()) {=0D + Context->PowerButton.Phase =3D EfiPowerButtonExit;=0D + } else {=0D + Context->PowerButton.Phase =3D EfiPowerButtonEntry;=0D + }=0D +}=0D +=0D +/**=0D + Check whether Power Button status of two contexts match=0D +=0D + @param[in] Context1 Context 1 that includes Power Button sta= tus 1=0D + @param[in] Context2 Context 2 that includes Power Button sta= tus 2=0D +=0D + @retval FALSE Power Button status match=0D + @retval TRUE Power Button status don't match=0D +**/=0D +BOOLEAN=0D +EFIAPI=0D +PowerButtonCmpContext (=0D + IN PCH_SMM_CONTEXT *Context1,=0D + IN PCH_SMM_CONTEXT *Context2=0D + )=0D +{=0D + return (BOOLEAN) (Context1->PowerButton.Phase =3D=3D Context2->PowerButt= on.Phase);=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmmSw.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm= Sw.c new file mode 100644 index 0000000000..9b13bf6308 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.c @@ -0,0 +1,381 @@ +/** @file=0D + File to contain all the hardware specific stuff for the Smm Sw dispatch = protocol.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include "PchSmmHelpers.h"=0D +#include =0D +#include =0D +#include =0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_CPU_PROTOCOL *mSmmCpuProtoc= ol;=0D +=0D +STATIC LIST_ENTRY mSwSmiCallbackDataBase;=0D +=0D +//=0D +// "SWSMI" RECORD=0D +// Linked list data structures=0D +//=0D +#define SW_SMI_RECORD_SIGNATURE SIGNATURE_32 ('S', 'W', 'S', 'M')= =0D +=0D +#define SW_SMI_RECORD_FROM_LINK(_record) CR (_record, SW_SMI_RECORD, Link= , SW_SMI_RECORD_SIGNATURE)=0D +=0D +typedef struct {=0D + UINT32 Signature;=0D + LIST_ENTRY Link;=0D + EFI_SMM_SW_REGISTER_CONTEXT Context;=0D + EFI_SMM_HANDLER_ENTRY_POINT2 Callback;=0D +} SW_SMI_RECORD;=0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSwSourceDesc =3D = {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_EN}=0D + },=0D + S_ACPI_IO_SMI_EN,=0D + N_ACPI_IO_SMI_EN_APMC=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_APM=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_APM=0D + }=0D +};=0D +=0D +/**=0D + Check the SwSmiInputValue to see if there is a duplicated one in the dat= abase=0D +=0D + @param[in] SwSmiInputValue SwSmiInputValue=0D +=0D + @retval EFI_SUCCESS There is no duplicated SwSmiInputValue=0D + @retval EFI_INVALID_PARAMETER There is a duplicated SwSmiInputValue=0D +**/=0D +EFI_STATUS=0D +SmiInputValueDuplicateCheck (=0D + IN UINTN SwSmiInputValue=0D + )=0D +{=0D + SW_SMI_RECORD *SwSmiRecord;=0D + LIST_ENTRY *LinkInDb;=0D +=0D + LinkInDb =3D GetFirstNode (&mSwSmiCallbackDataBase);=0D + while (!IsNull (&mSwSmiCallbackDataBase, LinkInDb)) {=0D + SwSmiRecord =3D SW_SMI_RECORD_FROM_LINK (LinkInDb);=0D + if (SwSmiRecord->Context.SwSmiInputValue =3D=3D SwSmiInputValue) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D + LinkInDb =3D GetNextNode (&mSwSmiCallbackDataBase, &SwSmiRecord->Link)= ;=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Register a child SMI source dispatch function for the specified software= SMI.=0D +=0D + This service registers a function (DispatchFunction) which will be calle= d when the software=0D + SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On r= eturn,=0D + DispatchHandle contains a unique handle which may be used later to unreg= ister the function=0D + using UnRegister().=0D +=0D + @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PRO= TOCOL instance.=0D + @param[in] DispatchFunction Function to register for handler when t= he specified software=0D + SMI is generated.=0D + @param[in, out] RegisterContext Pointer to the dispatch function's cont= ext.=0D + The caller fills this context in before= calling=0D + the register function to indicate to th= e register=0D + function which Software SMI input value= the=0D + dispatch function should be invoked for= .=0D + @param[out] DispatchHandle Handle generated by the dispatcher to t= rack the=0D + function instance.=0D +=0D + @retval EFI_SUCCESS The dispatch function has been successful= ly=0D + registered and the SMI source has been en= abled.=0D + @retval EFI_DEVICE_ERROR The SW driver was unable to enable the SM= I source.=0D + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The SW SMI in= put value=0D + is not within a valid range or is already= in use.=0D + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM= ) to manage this=0D + child.=0D + @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not be = assigned=0D + for this dispatch.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchSwSmiRegister (=0D + IN EFI_SMM_SW_DISPATCH2_PROTOCOL *This,=0D + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,=0D + IN EFI_SMM_SW_REGISTER_CONTEXT *DispatchContext,=0D + OUT EFI_HANDLE *DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + SW_SMI_RECORD *SwSmiRecord;=0D + UINTN Index;=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + //=0D + // Find available SW SMI value if the input is -1=0D + //=0D + if (DispatchContext->SwSmiInputValue =3D=3D (UINTN) -1) {=0D + for (Index =3D 1; Index < MAXIMUM_SWI_VALUE; Index++) {=0D + if (!EFI_ERROR (SmiInputValueDuplicateCheck (Index))) {=0D + DispatchContext->SwSmiInputValue =3D Index;=0D + break;=0D + }=0D + }=0D + if (DispatchContext->SwSmiInputValue =3D=3D (UINTN) -1) {=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D + }=0D + //=0D + // Check if it's a valid SW SMI value.=0D + // The value must not bigger than 0xFF.=0D + // And the value must not be 0xFF sincie it's used for SmmControll proto= col.=0D + //=0D + if (DispatchContext->SwSmiInputValue >=3D MAXIMUM_SWI_VALUE) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + if (EFI_ERROR (SmiInputValueDuplicateCheck (DispatchContext->SwSmiInputV= alue))) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + //=0D + // Create database record and add to database=0D + //=0D + Status =3D gSmst->SmmAllocatePool (=0D + EfiRuntimeServicesData,=0D + sizeof (SW_SMI_RECORD),=0D + (VOID **) &SwSmiRecord=0D + );=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((DEBUG_ERROR, "Failed to allocate memory for SwSmiRecord! \n"))= ;=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D + //=0D + // Gather information about the registration request=0D + //=0D + SwSmiRecord->Signature =3D SW_SMI_RECORD_SIGNATURE;=0D + SwSmiRecord->Context.SwSmiInputValue =3D DispatchContext->SwSmiInputValu= e;=0D + SwSmiRecord->Callback =3D DispatchFunction;=0D + //=0D + // Publish the S/W SMI numbers in Serial logs used for Debug build.=0D + //=0D + DEBUG ((DEBUG_INFO, "SW SMI NUM %x Sw Record at Address 0x%X\n", SwSmiR= ecord->Context.SwSmiInputValue, SwSmiRecord));=0D +=0D + InsertTailList (&mSwSmiCallbackDataBase, &SwSmiRecord->Link);=0D +=0D + //=0D + // Child's handle will be the address linked list link in the record=0D + //=0D + *DispatchHandle =3D (EFI_HANDLE) (&SwSmiRecord->Link);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Unregister a child SMI source dispatch function for the specified softwa= re SMI.=0D +=0D + This service removes the handler associated with DispatchHandle so that = it will no longer be=0D + called in response to a software SMI.=0D +=0D + @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTO= COL instance.=0D + @param[in] DispatchHandle Handle of dispatch function to deregister= .=0D +=0D + @retval EFI_SUCCESS The dispatch function has been successful= ly unregistered.=0D + @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchSwSmiUnRegister (=0D + IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This,=0D + IN EFI_HANDLE DispatchHandle=0D + )=0D +{=0D + EFI_STATUS Status;=0D + SW_SMI_RECORD *RecordToDelete;=0D +=0D + if (DispatchHandle =3D=3D 0) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + //=0D + // Return access denied if the SmmReadyToLock event has been triggered=0D + //=0D + if (mReadyToLock =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock = event has been triggered! \n"));=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + RecordToDelete =3D SW_SMI_RECORD_FROM_LINK (DispatchHandle);=0D + //=0D + // Take the entry out of the linked list=0D + //=0D + if (RecordToDelete->Signature !=3D SW_SMI_RECORD_SIGNATURE) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + RemoveEntryList (&RecordToDelete->Link);=0D + ZeroMem (RecordToDelete, sizeof (SW_SMI_RECORD));=0D + Status =3D gSmst->SmmFreePool (RecordToDelete);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Main entry point for an SMM handler dispatch or communicate-based callba= ck.=0D +=0D + @param[in] DispatchHandle The unique handle assigned to this handle= r by SmiHandlerRegister().=0D + @param[in] Context Points to an optional handler context whi= ch was specified when the=0D + handler was registered.=0D + @param[in,out] CommBuffer A pointer to a collection of data in memo= ry that will=0D + be conveyed from a non-SMM environment in= to an SMM environment.=0D + @param[in,out] CommBufferSize The size of the CommBuffer.=0D +=0D + @retval EFI_SUCCESS The interrupt was handled an= d quiesced. No other handlers=0D + should still be called.=0D + @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quies= ced but other handlers should=0D + still be called.=0D + @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pendi= ng and other handlers should still=0D + be called.=0D + @retval EFI_INTERRUPT_PENDING The interrupt could not be q= uiesced.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PchSwSmiDispatcher (=0D + IN EFI_HANDLE DispatchHandle,=0D + IN CONST VOID *Context,=0D + IN OUT VOID *CommBuffer,=0D + IN OUT UINTN *CommBufferSize=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_SMM_SAVE_STATE_IO_INFO SmiIoInfo;=0D + UINTN CpuIndex;=0D + SW_SMI_RECORD *SwSmiRecord;=0D + LIST_ENTRY *LinkInDb;=0D + EFI_SMM_SW_CONTEXT SwSmiCommBuffer;=0D + UINTN SwSmiCommBufferSize;=0D +=0D + SwSmiCommBufferSize =3D sizeof (EFI_SMM_SW_CONTEXT);=0D + //=0D + // The value in DataPort might not be accurate in multiple thread enviro= nment.=0D + // There might be racing condition for R_PCH_IO_APM_STS port.=0D + // Therefor, this is just for reference.=0D + //=0D + SwSmiCommBuffer.DataPort =3D IoRead8 (R_PCH_IO_APM_STS);=0D +=0D + for (CpuIndex =3D 0; CpuIndex < gSmst->NumberOfCpus; CpuIndex++) {=0D + Status =3D mSmmCpuProtocol->ReadSaveState (=0D + mSmmCpuProtocol,=0D + sizeof (EFI_SMM_SAVE_STATE_IO_INFO),=0D + EFI_SMM_SAVE_STATE_REGISTER_IO,=0D + CpuIndex,=0D + &SmiIoInfo=0D + );=0D + //=0D + // If this is not the SMI source, skip it.=0D + //=0D + if (EFI_ERROR (Status)) {=0D + continue;=0D + }=0D + //=0D + // If the IO address is not "BYTE" "WRITE" to "R_PCH_IO_APM_CNT (0xB2)= ", skip it.=0D + //=0D + if ((SmiIoInfo.IoPort !=3D R_PCH_IO_APM_CNT) ||=0D + (SmiIoInfo.IoType !=3D EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT) ||=0D + (SmiIoInfo.IoWidth !=3D EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8))=0D + {=0D + continue;=0D + }=0D + //=0D + // If the IO data is used for SmmControl protocol, skip it.=0D + //=0D + if (SmiIoInfo.IoData =3D=3D 0xFF) {=0D + continue;=0D + }=0D +=0D + SwSmiCommBuffer.SwSmiCpuIndex =3D CpuIndex;=0D + SwSmiCommBuffer.CommandPort =3D (UINT8) SmiIoInfo.IoData;=0D +=0D + LinkInDb =3D GetFirstNode (&mSwSmiCallbackDataBase);=0D + while (!IsNull (&mSwSmiCallbackDataBase, LinkInDb)) {=0D + SwSmiRecord =3D SW_SMI_RECORD_FROM_LINK (LinkInDb);=0D + if (SwSmiRecord->Context.SwSmiInputValue =3D=3D SmiIoInfo.IoData) {= =0D + SwSmiRecord->Callback ((EFI_HANDLE) &SwSmiRecord->Link, &SwSmiReco= rd->Context, &SwSmiCommBuffer, &SwSmiCommBufferSize);=0D + }=0D + LinkInDb =3D GetNextNode (&mSwSmiCallbackDataBase, &SwSmiRecord->Lin= k);=0D + }=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Init required protocol for Pch Sw Dispatch protocol.=0D +**/=0D +VOID=0D +PchSwDispatchInit (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_HANDLE DispatchHandle;=0D + DATABASE_RECORD Record;=0D +=0D + //=0D + // Locate PI SMM CPU protocol=0D + //=0D + Status =3D gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOI= D **)&mSmmCpuProtocol);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + //=0D + // Initialize SW SMI Callback DataBase=0D + //=0D + InitializeListHead (&mSwSmiCallbackDataBase);=0D +=0D + //=0D + // Insert SwSmi handler to PchSmmCore database=0D + // There will always be one SwType record in PchSmmCore database=0D + //=0D + ZeroMem (&Record, sizeof (DATABASE_RECORD));=0D + Record.Signature =3D DATABASE_RECORD_SIGNATURE;=0D + Record.Callback =3D PchSwSmiDispatcher;=0D + Record.ProtocolType =3D SwType;=0D +=0D + CopyMem (&Record.SrcDesc, &mSwSourceDesc, sizeof (PCH_SMM_SOURCE_DESC));= =0D +=0D + DispatchHandle =3D NULL;=0D + Status =3D SmmCoreInsertRecord (=0D + &Record,=0D + &DispatchHandle=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmmSx.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm= Sx.c new file mode 100644 index 0000000000..7d79f21dbd --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c @@ -0,0 +1,224 @@ +/** @file=0D + File to contain all the hardware specific stuff for the Smm Sx dispatch = protocol.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include "PchSmmHelpers.h"=0D +#include =0D +#include =0D +#include =0D +#include "PchSmiHelper.h"=0D +=0D +extern BOOLEAN mS3SusStart;=0D +#define PROGRESS_CODE_S3_SUSPEND_END PcdGet32 (PcdProgressCodeS3SuspendEn= d)=0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSxSourceDesc =3D = {=0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_EN}=0D + },=0D + S_ACPI_IO_SMI_EN,=0D + N_ACPI_IO_SMI_EN_ON_SLP_EN=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_ON_SLP_EN=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_ON_SLP_EN=0D + }=0D +};=0D +=0D +/**=0D + Get the Sleep type=0D +=0D + @param[in] Record No use=0D + @param[out] Context The context that includes SLP_TYP bits t= o be filled=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +SxGetContext (=0D + IN DATABASE_RECORD *Record,=0D + OUT PCH_SMM_CONTEXT *Context=0D + )=0D +{=0D + UINT32 Pm1Cnt;=0D +=0D + Pm1Cnt =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT));=0D +=0D + ///=0D + /// By design, the context phase will always be ENTRY=0D + ///=0D + Context->Sx.Phase =3D SxEntry;=0D +=0D + ///=0D + /// Map the PM1_CNT register's SLP_TYP bits to the context type=0D + ///=0D + switch (Pm1Cnt & B_ACPI_IO_PM1_CNT_SLP_TYP) {=0D + case V_ACPI_IO_PM1_CNT_S0:=0D + Context->Sx.Type =3D SxS0;=0D + break;=0D +=0D + case V_ACPI_IO_PM1_CNT_S1:=0D + Context->Sx.Type =3D SxS1;=0D + break;=0D +=0D + case V_ACPI_IO_PM1_CNT_S3:=0D + Context->Sx.Type =3D SxS3;=0D + break;=0D +=0D + case V_ACPI_IO_PM1_CNT_S4:=0D + Context->Sx.Type =3D SxS4;=0D + break;=0D +=0D + case V_ACPI_IO_PM1_CNT_S5:=0D + Context->Sx.Type =3D SxS5;=0D + break;=0D +=0D + default:=0D + ASSERT (FALSE);=0D + break;=0D + }=0D +}=0D +=0D +/**=0D + Check whether sleep type of two contexts match=0D +=0D + @param[in] Context1 Context 1 that includes sleep type 1=0D + @param[in] Context2 Context 2 that includes sleep type 2=0D +=0D + @retval FALSE Sleep types match=0D + @retval TRUE Sleep types don't match=0D +**/=0D +BOOLEAN=0D +EFIAPI=0D +SxCmpContext (=0D + IN PCH_SMM_CONTEXT *Context1,=0D + IN PCH_SMM_CONTEXT *Context2=0D + )=0D +{=0D + return (BOOLEAN) (Context1->Sx.Type =3D=3D Context2->Sx.Type);=0D +}=0D +=0D +/**=0D + For each PCIE RP clear PME SCI status and disable SCI, then PCIEXP_WAKE_= STS from PMC.=0D + This prevents platform from waking more than one time due to a single PC= IE wake event.=0D + Normally it's up to OS to clear SCI statuses. But in a scenario where pl= atform wakes=0D + and goes to S5 instead of booting to OS, the SCI status would remain set= and would trigger another wake.=0D +**/=0D +VOID=0D +ClearPcieSci (=0D + VOID=0D + )=0D +{=0D + UINT32 MaxPorts;=0D + UINT32 RpIndex;=0D + UINT64 RpBase;=0D +=0D + MaxPorts =3D GetPchMaxPciePortNum ();=0D + for (RpIndex =3D 0; RpIndex < MaxPorts; RpIndex++) {=0D + RpBase =3D PchPcieRpPciCfgBase (RpIndex);=0D + if (PciSegmentRead16 (RpBase + PCI_VENDOR_ID_OFFSET) !=3D 0xFFFF) {=0D + PciSegmentAnd8 ((RpBase + R_PCH_PCIE_CFG_MPC + 3), (UINT8)~((UINT8)(= B_PCH_PCIE_CFG_MPC_PMCE >> 24)));=0D + PciSegmentWrite32 (RpBase + R_PCH_PCIE_CFG_SMSCS, B_PCH_PCIE_CFG_SMS= CS_PMCS);=0D + }=0D + }=0D + IoWrite16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS, B_ACPI_IO_PM1_STS_PCIEXP_W= AKE_STS);=0D +}=0D +=0D +=0D +/**=0D + When we get an SMI that indicates that we are transitioning to a sleep s= tate,=0D + we need to actually transition to that state. We do this by disabling t= he=0D + "SMI on sleep enable" feature, which generates an SMI when the operating= system=0D + tries to put the system to sleep, and then physically putting the system= to sleep.=0D +=0D +=0D +**/=0D +VOID=0D +PchSmmSxGoToSleep (=0D + VOID=0D + )=0D +{=0D + UINT32 Pm1Cnt;=0D +=0D + ClearPcieSci ();=0D +=0D + ///=0D + /// Disable SMIs=0D + ///=0D + PchSmmClearSource (&mSxSourceDesc);=0D + PchSmmDisableSource (&mSxSourceDesc);=0D +=0D + ///=0D + /// Get Power Management 1 Control Register Value=0D + ///=0D + Pm1Cnt =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT));=0D +=0D + ///=0D + /// Record S3 suspend performance data=0D + ///=0D + if ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SLP_TYP) =3D=3D V_ACPI_IO_PM1_CNT_S3) {= =0D + ///=0D + /// Report status code before goto S3 sleep=0D + ///=0D + REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PROGRESS_CODE_S3_SUSPEND_END);= =0D + mS3SusStart =3D FALSE;=0D + ///=0D + /// Write back cache into memory and invalidate cache before going to = sleep.=0D + ///=0D + AsmWbinvd ();=0D + }=0D +=0D + ///=0D + /// Now that SMIs are disabled, write to the SLP_EN bit again to trigger= the sleep=0D + ///=0D + Pm1Cnt |=3D B_ACPI_IO_PM1_CNT_SLP_EN;=0D +=0D + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT), Pm1Cnt);=0D +=0D + ///=0D + /// Should only proceed if wake event is generated.=0D + ///=0D + if ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SLP_TYP) =3D=3D V_ACPI_IO_PM1_CNT_S1) {= =0D + while (((IoRead16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_STS))) & B_A= CPI_IO_PM1_STS_WAK) =3D=3D 0x0);=0D + } else {=0D + CpuDeadLoop ();=0D + }=0D + ///=0D + /// The system just went to sleep. If the sleep state was S1, then code = execution will resume=0D + /// here when the system wakes up.=0D + ///=0D + Pm1Cnt =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT));=0D +=0D + if ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) =3D=3D 0) {=0D + ///=0D + /// An ACPI OS isn't present, clear the sleep information=0D + ///=0D + Pm1Cnt &=3D ~B_ACPI_IO_PM1_CNT_SLP_TYP;=0D + Pm1Cnt |=3D V_ACPI_IO_PM1_CNT_S0;=0D +=0D + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT), Pm1Cnt);=0D + }=0D +=0D + PchSmmClearSource (&mSxSourceDesc);=0D + PchSmmEnableSource (&mSxSourceDesc);=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmmUsb.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSm= mUsb.c new file mode 100644 index 0000000000..a0c67bd959 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb.c @@ -0,0 +1,230 @@ +/** @file=0D + File to contain all the hardware specific stuff for the Smm USB dispatch= protocol.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include "PchSmmHelpers.h"=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mUsb1Legacy =3D {= =0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_EN}=0D + },=0D + S_ACPI_IO_SMI_EN,=0D + N_ACPI_IO_SMI_EN_LEGACY_USB=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_LEGACY_USB=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_LEGACY_USB=0D + }=0D +};=0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mUsb3Legacy =3D {= =0D + PCH_SMM_NO_FLAGS,=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_EN}=0D + },=0D + S_ACPI_IO_SMI_EN,=0D + N_ACPI_IO_SMI_EN_LEGACY_USB3=0D + },=0D + NULL_BIT_DESC_INITIALIZER=0D + },=0D + {=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_LEGACY_USB3=0D + }=0D + },=0D + {=0D + {=0D + ACPI_ADDR_TYPE,=0D + {R_ACPI_IO_SMI_STS}=0D + },=0D + S_ACPI_IO_SMI_STS,=0D + N_ACPI_IO_SMI_STS_LEGACY_USB3=0D + }=0D +};=0D +=0D +typedef enum {=0D + PchUsbControllerLpc0 =3D 0,=0D + PchUsbControllerXhci,=0D + PchUsbControllerTypeMax=0D +} PCH_USB_CONTROLLER_TYPE;=0D +=0D +typedef struct {=0D + UINT8 Function;=0D + UINT8 Device;=0D + PCH_USB_CONTROLLER_TYPE UsbConType;=0D +} USB_CONTROLLER;=0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED USB_CONTROLLER mUsbControllersMap[] =3D {=0D + {=0D + PCI_FUNCTION_NUMBER_PCH_LPC,=0D + PCI_DEVICE_NUMBER_PCH_LPC,=0D + PchUsbControllerLpc0=0D + },=0D + {=0D + PCI_FUNCTION_NUMBER_PCH_XHCI,=0D + PCI_DEVICE_NUMBER_PCH_XHCI,=0D + PchUsbControllerXhci=0D + }=0D +};=0D +=0D +/**=0D + Find the handle that best matches the input Device Path and return the U= SB controller type=0D +=0D + @param[in] DevicePath Pointer to the device Path table=0D + @param[out] Controller Returned with the USB controller type of= the input device path=0D +=0D + @retval EFI_SUCCESS Find the handle that best matches the in= put Device Path=0D + @exception EFI_UNSUPPORTED Invalid device Path table or can't find = any match USB device path=0D + PCH_USB_CONTROLLER_TYPE The USB controll= er type of the input=0D + device path=0D +**/=0D +EFI_STATUS=0D +DevicePathToSupportedController (=0D + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,=0D + OUT PCH_USB_CONTROLLER_TYPE *Controller=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_HANDLE DeviceHandle;=0D + ACPI_HID_DEVICE_PATH *AcpiNode;=0D + PCI_DEVICE_PATH *PciNode;=0D + EFI_DEVICE_PATH_PROTOCOL *RemaingDevicePath;=0D + UINT8 UsbIndex;=0D + ///=0D + /// Find the handle that best matches the Device Path. If it is only a=0D + /// partial match the remaining part of the device path is returned in=0D + /// RemainingDevicePath.=0D + ///=0D + RemaingDevicePath =3D DevicePath;=0D + Status =3D gBS->LocateDevicePath (=0D + &gEfiPciRootBridgeIoProtocolGuid,=0D + &DevicePath,=0D + &DeviceHandle=0D + );=0D + if (EFI_ERROR (Status)) {=0D + return EFI_UNSUPPORTED;=0D + }=0D +=0D + DevicePath =3D RemaingDevicePath;=0D +=0D + ///=0D + /// Get first node: Acpi Node=0D + ///=0D + AcpiNode =3D (ACPI_HID_DEVICE_PATH *) RemaingDevicePath;=0D +=0D + if (AcpiNode->Header.Type !=3D ACPI_DEVICE_PATH ||=0D + AcpiNode->Header.SubType !=3D ACPI_DP ||=0D + DevicePathNodeLength (&AcpiNode->Header) !=3D sizeof (ACPI_HID_DEVIC= E_PATH) ||=0D + AcpiNode->HID !=3D EISA_PNP_ID (0x0A03) ||=0D + AcpiNode->UID !=3D 0=0D + ) {=0D + return EFI_UNSUPPORTED;=0D + } else {=0D + ///=0D + /// Get the next node: Pci Node=0D + ///=0D + RemaingDevicePath =3D NextDevicePathNode (RemaingDevicePath);=0D + PciNode =3D (PCI_DEVICE_PATH *) RemaingDevicePath;=0D + if (PciNode->Header.Type !=3D HARDWARE_DEVICE_PATH ||=0D + PciNode->Header.SubType !=3D HW_PCI_DP ||=0D + DevicePathNodeLength (&PciNode->Header) !=3D sizeof (PCI_DEVICE_PA= TH)=0D + ) {=0D + return EFI_UNSUPPORTED;=0D + }=0D +=0D + for (UsbIndex =3D 0; UsbIndex < sizeof (mUsbControllersMap) / sizeof (= USB_CONTROLLER); UsbIndex++) {=0D + if ((PciNode->Device =3D=3D mUsbControllersMap[UsbIndex].Device) &&= =0D + (PciNode->Function =3D=3D mUsbControllersMap[UsbIndex].Function)= ) {=0D + *Controller =3D mUsbControllersMap[UsbIndex].UsbConType;=0D + return EFI_SUCCESS;=0D + }=0D + }=0D +=0D + return EFI_UNSUPPORTED;=0D + }=0D +}=0D +=0D +/**=0D + Maps a USB context to a source description.=0D +=0D + @param[in] Context The context we need to map. Type must b= e USB.=0D + @param[in] SrcDesc The source description that corresponds = to the given context.=0D +=0D +**/=0D +VOID=0D +MapUsbToSrcDesc (=0D + IN PCH_SMM_CONTEXT *Context,=0D + OUT PCH_SMM_SOURCE_DESC *SrcDesc=0D + )=0D +{=0D + PCH_USB_CONTROLLER_TYPE Controller;=0D + EFI_STATUS Status;=0D +=0D + Status =3D DevicePathToSupportedController (Context->Usb.Device, &Contro= ller);=0D + ///=0D + /// Either the device path passed in by the child is incorrect or=0D + /// the ones stored here internally are incorrect.=0D + ///=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + switch (Context->Usb.Type) {=0D + case UsbLegacy:=0D + switch (Controller) {=0D + case PchUsbControllerLpc0:=0D + CopyMem ((VOID *) SrcDesc, (VOID *) (&mUsb1Legacy), sizeof (PCH_= SMM_SOURCE_DESC));=0D + break;=0D +=0D + case PchUsbControllerXhci:=0D + CopyMem ((VOID *) SrcDesc, (VOID *) (&mUsb3Legacy), sizeof (PCH_= SMM_SOURCE_DESC));=0D + break;=0D +=0D + default:=0D + ASSERT (FALSE);=0D + break;=0D + }=0D + break;=0D +=0D + case UsbWake:=0D + ASSERT (FALSE);=0D + break;=0D +=0D + default:=0D + ASSERT (FALSE);=0D + break;=0D + }=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= xSmmHelpers.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/= PchxSmmHelpers.c new file mode 100644 index 0000000000..a0b7e37d46 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHel= pers.c @@ -0,0 +1,778 @@ +/** @file=0D + This driver is responsible for the registration of child drivers=0D + and the abstraction of the PCH SMI sources.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include "PchSmmHelpers.h"=0D +#include =0D +#include =0D +=0D +//=0D +// Help handle porting bit shifts to IA-64.=0D +//=0D +#define BIT_ZERO 0x00000001=0D +=0D +/**=0D + Publish SMI Dispatch protocols.=0D +=0D +=0D +**/=0D +VOID=0D +PchSmmPublishDispatchProtocols (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status =3D EFI_SUCCESS;=0D + UINTN Index;=0D + //=0D + // Install protocol interfaces.=0D + //=0D + for (Index =3D 0; Index < PCH_SMM_PROTOCOL_TYPE_MAX; Index++) {=0D + Status =3D gSmst->SmmInstallProtocolInterface (=0D + &mPrivateData.InstallMultProtHandle,=0D + mPrivateData.Protocols[Index].Guid,=0D + EFI_NATIVE_INTERFACE,=0D + &mPrivateData.Protocols[Index].Protocols.Generic=0D + );=0D + }=0D + ASSERT_EFI_ERROR (Status);=0D +}=0D +=0D +/**=0D + Initialize bits that aren't necessarily related to an SMI source.=0D +=0D +=0D + @retval EFI_SUCCESS SMI source initialization completed.=0D + @retval Asserts Global Smi Bit is not enabled successful= ly.=0D +**/=0D +EFI_STATUS=0D +PchSmmInitHardware (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Clear all SMIs=0D + //=0D + PchSmmClearSmi ();=0D +=0D + Status =3D PchSmmEnableGlobalSmiBit ();=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + //=0D + // Be *really* sure to clear all SMIs=0D + //=0D + PchSmmClearSmi ();=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Enables the PCH to generate SMIs. Note that no SMIs will be generated=0D + if no SMI sources are enabled. Conversely, no enabled SMI source will=0D + generate SMIs if SMIs are not globally enabled. This is the main=0D + switchbox for SMI generation.=0D +=0D +=0D + @retval EFI_SUCCESS Enable Global Smi Bit completed=0D +**/=0D +EFI_STATUS=0D +PchSmmEnableGlobalSmiBit (=0D + VOID=0D + )=0D +{=0D + UINT32 SmiEn;=0D +=0D + SmiEn =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN));=0D +=0D + //=0D + // Set the "global smi enable" bit=0D + //=0D + SmiEn |=3D B_ACPI_IO_SMI_EN_GBL_SMI;=0D +=0D + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN), SmiEn);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Clears the SMI after all SMI source have been processed.=0D + Note that this function will not work correctly (as it is=0D + written) unless all SMI sources have been processed.=0D + A revision of this function could manually clear all SMI=0D + status bits to guarantee success.=0D +=0D +=0D + @retval EFI_SUCCESS Clears the SMIs completed=0D + @retval Asserts EOS was not set to a 1=0D +**/=0D +EFI_STATUS=0D +PchSmmClearSmi (=0D + VOID=0D + )=0D +{=0D + BOOLEAN EosSet;=0D + BOOLEAN SciEn;=0D + UINT32 Pm1Cnt;=0D + UINT16 Pm1Sts;=0D + UINT32 Gpe0Sts;=0D + UINT32 SmiSts;=0D + UINT16 DevActSts;=0D + UINT16 Tco1Sts;=0D +=0D + Gpe0Sts =3D 0;=0D + //=0D + // Determine whether an ACPI OS is present (via the SCI_EN bit)=0D + //=0D + Pm1Cnt =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT));=0D + SciEn =3D (BOOLEAN) ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) =3D=3D B_ACPI_= IO_PM1_CNT_SCI_EN);=0D + if (!SciEn) {=0D + //=0D + // Clear any SMIs that double as SCIs (when SCI_EN=3D=3D0)=0D + //=0D + Pm1Sts =3D IoRead16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_STS));=0D + Gpe0Sts =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127= _96));=0D +=0D + Pm1Sts |=3D=0D + (=0D + B_ACPI_IO_PM1_STS_WAK |=0D + B_ACPI_IO_PM1_STS_PRBTNOR |=0D + B_ACPI_IO_PM1_STS_RTC |=0D + B_ACPI_IO_PM1_STS_PWRBTN |=0D + B_ACPI_IO_PM1_STS_GBL |=0D + B_ACPI_IO_PM1_STS_TMROF=0D + );=0D +=0D + Gpe0Sts |=3D=0D + (=0D + B_ACPI_IO_GPE0_STS_127_96_WADT |=0D + B_ACPI_IO_GPE0_STS_127_96_USB_CON_DSX_STS |=0D + B_ACPI_IO_GPE0_STS_127_96_LAN_WAKE |=0D + B_ACPI_IO_GPE0_STS_127_96_PME_B0 |=0D + B_ACPI_IO_GPE0_STS_127_96_PME |=0D + B_ACPI_IO_GPE0_STS_127_96_BATLOW |=0D + B_ACPI_IO_GPE0_STS_127_96_RI |=0D + B_ACPI_IO_GPE0_STS_127_96_SWGPE=0D + );=0D +=0D + IoWrite16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_STS), (UINT16) Pm1St= s);=0D + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96), (UINT3= 2) Gpe0Sts);=0D + }=0D + //=0D + // Clear all SMIs that are unaffected by SCI_EN=0D + //=0D + SmiSts =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_STS))= ;=0D + DevActSts =3D IoRead16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_DEVACT_ST= S));=0D + Tco1Sts =3D IoRead16 ((UINTN) (mTcoBaseAddr + R_TCO_IO_TCO1_STS));= =0D +=0D + SmiSts |=3D=0D + (=0D + B_ACPI_IO_SMI_STS_SMBUS |=0D + B_ACPI_IO_SMI_STS_PERIODIC |=0D + B_ACPI_IO_SMI_STS_TCO |=0D + B_ACPI_IO_SMI_STS_MCSMI |=0D + B_ACPI_IO_SMI_STS_SWSMI_TMR |=0D + B_ACPI_IO_SMI_STS_APM |=0D + B_ACPI_IO_SMI_STS_ON_SLP_EN |=0D + B_ACPI_IO_SMI_STS_BIOS=0D + );=0D + DevActSts |=3D=0D + (=0D + B_ACPI_IO_DEVACT_STS_KBC |=0D + B_ACPI_IO_DEVACT_STS_PIRQDH |=0D + B_ACPI_IO_DEVACT_STS_PIRQCG |=0D + B_ACPI_IO_DEVACT_STS_PIRQBF |=0D + B_ACPI_IO_DEVACT_STS_PIRQAE=0D + );=0D + Tco1Sts |=3D=0D + (=0D + B_TCO_IO_TCO1_STS_DMISERR |=0D + B_TCO_IO_TCO1_STS_DMISMI |=0D + B_TCO_IO_TCO1_STS_DMISCI |=0D + B_TCO_IO_TCO1_STS_BIOSWR |=0D + B_TCO_IO_TCO1_STS_NEWCENTURY |=0D + B_TCO_IO_TCO1_STS_TIMEOUT |=0D + B_TCO_IO_TCO1_STS_TCO_INT |=0D + B_TCO_IO_TCO1_STS_SW_TCO_SMI=0D + );=0D +=0D + GpioClearAllGpiSmiSts ();=0D +=0D + IoWrite16 ((UINTN) (mTcoBaseAddr + R_TCO_IO_TCO1_STS), Tco1Sts);=0D +=0D + //=0D + // We do not want to write 1 to clear INTRD_DET bit.=0D + //=0D + IoWrite16 ((UINTN) (mTcoBaseAddr + R_TCO_IO_TCO2_STS), (UINT16) ~B_TCO_I= O_TCO2_STS_INTRD_DET);=0D +=0D + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_STS), SmiSts);=0D +=0D + IoWrite16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_DEVACT_STS), DevActSts);=0D +=0D + //=0D + // Try to clear the EOS bit. ASSERT on an error=0D + //=0D + EosSet =3D PchSmmSetAndCheckEos ();=0D + ASSERT (EosSet);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Set the SMI EOS bit after all SMI source have been processed.=0D +=0D +=0D + @retval FALSE EOS was not set to a 1; this is an error= =0D + @retval TRUE EOS was correctly set to a 1=0D +**/=0D +BOOLEAN=0D +PchSmmSetAndCheckEos (=0D + VOID=0D + )=0D +{=0D + UINT32 SmiEn;=0D +=0D + SmiEn =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN));=0D +=0D + //=0D + // Reset the PCH to generate subsequent SMIs=0D + //=0D + SmiEn |=3D B_ACPI_IO_SMI_EN_EOS;=0D +=0D + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN), SmiEn);=0D +=0D + //=0D + // Double check that the assert worked=0D + //=0D + SmiEn =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN));=0D +=0D + //=0D + // Return TRUE if EOS is set correctly=0D + //=0D + if ((SmiEn & B_ACPI_IO_SMI_EN_EOS) =3D=3D 0) {=0D + //=0D + // EOS was not set to a 1; this is an error=0D + //=0D + return FALSE;=0D + } else {=0D + //=0D + // EOS was correctly set to a 1=0D + //=0D + return TRUE;=0D + }=0D +}=0D +=0D +/**=0D + Determine whether an ACPI OS is present (via the SCI_EN bit)=0D +=0D +=0D + @retval TRUE ACPI OS is present=0D + @retval FALSE ACPI OS is not present=0D +**/=0D +BOOLEAN=0D +PchSmmGetSciEn (=0D + VOID=0D + )=0D +{=0D + BOOLEAN SciEn;=0D + UINT32 Pm1Cnt;=0D +=0D + //=0D + // Determine whether an ACPI OS is present (via the SCI_EN bit)=0D + //=0D + Pm1Cnt =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT));=0D + SciEn =3D (BOOLEAN) ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) =3D=3D B_ACPI= _IO_PM1_CNT_SCI_EN);=0D +=0D + return SciEn;=0D +}=0D +=0D +/**=0D + Read a specifying bit with the register=0D + These may or may not need to change w/ the PCH version; they're highly I= A-32 dependent, though.=0D +=0D + @param[in] BitDesc The struct that includes register addres= s, size in byte and bit number=0D +=0D + @retval TRUE The bit is enabled=0D + @retval FALSE The bit is disabled=0D +**/=0D +BOOLEAN=0D +ReadBitDesc (=0D + CONST PCH_SMM_BIT_DESC *BitDesc=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINT64 Register;=0D + UINT32 PciBus;=0D + UINT32 PciDev;=0D + UINT32 PciFun;=0D + UINT32 PciReg;=0D + UINTN RegSize;=0D + BOOLEAN BitWasOne;=0D + UINTN ShiftCount;=0D + UINTN RegisterOffset;=0D + UINT32 BaseAddr;=0D + UINT64 PciBaseAddress;=0D +=0D + ASSERT (BitDesc !=3D NULL);=0D + ASSERT (!IS_BIT_DESC_NULL (*BitDesc));=0D +=0D + RegSize =3D 0;=0D + Register =3D 0;=0D + ShiftCount =3D 0;=0D + BitWasOne =3D FALSE;=0D +=0D + switch (BitDesc->Reg.Type) {=0D +=0D + case ACPI_ADDR_TYPE:=0D + case TCO_ADDR_TYPE:=0D + if (BitDesc->Reg.Type =3D=3D ACPI_ADDR_TYPE) {=0D + RegisterOffset =3D BitDesc->Reg.Data.acpi;=0D + BaseAddr =3D mAcpiBaseAddr;=0D + } else {=0D + RegisterOffset =3D BitDesc->Reg.Data.tco;=0D + BaseAddr =3D mTcoBaseAddr;=0D + }=0D + switch (BitDesc->SizeInBytes) {=0D +=0D + case 0:=0D + //=0D + // Chances are that this field didn't get initialized.=0D + // Check your assignments to bit descriptions.=0D + //=0D + ASSERT (FALSE);=0D + break;=0D +=0D + case 1:=0D + RegSize =3D SMM_IO_UINT8;=0D + break;=0D +=0D + case 2:=0D + RegSize =3D SMM_IO_UINT16;=0D + break;=0D +=0D + case 4:=0D + RegSize =3D SMM_IO_UINT32;=0D + break;=0D +=0D + case 8:=0D + RegSize =3D SMM_IO_UINT64;=0D + break;=0D +=0D + default:=0D + //=0D + // Unsupported or invalid register size=0D + //=0D + ASSERT (FALSE);=0D + break;=0D + }=0D + //=0D + // Double check that we correctly read in the acpi base address=0D + //=0D + ASSERT ((BaseAddr !=3D 0x0) && ((BaseAddr & 0x1) !=3D 0x1));=0D +=0D + ShiftCount =3D BitDesc->Bit;=0D + //=0D + // As current CPU Smm Io can only support at most=0D + // 32-bit read/write,if Operation is 64 bit,=0D + // we do a 32 bit operation according to BitDesc->Bit=0D + //=0D + if (RegSize =3D=3D SMM_IO_UINT64) {=0D + RegSize =3D SMM_IO_UINT32;=0D + //=0D + // If the operation is for high 32 bits=0D + //=0D + if (BitDesc->Bit >=3D 32) {=0D + RegisterOffset +=3D 4;=0D + ShiftCount -=3D 32;=0D + }=0D + }=0D +=0D + Status =3D gSmst->SmmIo.Io.Read (=0D + &gSmst->SmmIo,=0D + RegSize,=0D + BaseAddr + RegisterOffset,=0D + 1,=0D + &Register=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + if ((Register & (LShiftU64 (BIT_ZERO, ShiftCount))) !=3D 0) {=0D + BitWasOne =3D TRUE;=0D + } else {=0D + BitWasOne =3D FALSE;=0D + }=0D + break;=0D +=0D + case GPIO_ADDR_TYPE:=0D + case MEMORY_MAPPED_IO_ADDRESS_TYPE:=0D + //=0D + // Read the register, and it with the bit to read=0D + //=0D + switch (BitDesc->SizeInBytes) {=0D + case 1:=0D + Register =3D (UINT64) MmioRead8 ((UINTN) BitDesc->Reg.Data.Mmio)= ;=0D + break;=0D +=0D + case 2:=0D + Register =3D (UINT64) MmioRead16 ((UINTN) BitDesc->Reg.Data.Mmio= );=0D + break;=0D +=0D + case 4:=0D + Register =3D (UINT64) MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio= );=0D + break;=0D +=0D + case 8:=0D + Register =3D (UINT64) MmioRead32 ((UINTN) B= itDesc->Reg.Data.Mmio);=0D + *((UINT32 *) (&Register) + 1) =3D MmioRead32 ((UINTN) BitDesc->R= eg.Data.Mmio + 4);=0D + break;=0D +=0D + default:=0D + //=0D + // Unsupported or invalid register size=0D + //=0D + ASSERT (FALSE);=0D + break;=0D + }=0D +=0D + Register =3D Register & (LShiftU64 (BIT0, BitDesc->Bit));=0D + if (Register) {=0D + BitWasOne =3D TRUE;=0D + } else {=0D + BitWasOne =3D FALSE;=0D + }=0D + break;=0D +=0D + case PCIE_ADDR_TYPE:=0D + PciBus =3D BitDesc->Reg.Data.pcie.Fields.Bus;=0D + PciDev =3D BitDesc->Reg.Data.pcie.Fields.Dev;=0D + PciFun =3D BitDesc->Reg.Data.pcie.Fields.Fnc;=0D + PciReg =3D BitDesc->Reg.Data.pcie.Fields.Reg;=0D + PciBaseAddress =3D PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMB= ER_PCH, PciBus, PciDev, PciFun, 0);=0D + switch (BitDesc->SizeInBytes) {=0D +=0D + case 0:=0D + //=0D + // Chances are that this field didn't get initialized.=0D + // Check your assignments to bit descriptions.=0D + //=0D + ASSERT (FALSE);=0D + break;=0D +=0D + case 1:=0D + Register =3D (UINT64) PciSegmentRead8 (PciBaseAddress + PciReg);= =0D + break;=0D +=0D + case 2:=0D + Register =3D (UINT64) PciSegmentRead16 (PciBaseAddress + PciReg)= ;=0D + break;=0D +=0D + case 4:=0D + Register =3D (UINT64) PciSegmentRead32 (PciBaseAddress + PciReg)= ;=0D + break;=0D +=0D + default:=0D + //=0D + // Unsupported or invalid register size=0D + //=0D + ASSERT (FALSE);=0D + break;=0D + }=0D +=0D + if ((Register & (LShiftU64 (BIT_ZERO, BitDesc->Bit))) !=3D 0) {=0D + BitWasOne =3D TRUE;=0D + } else {=0D + BitWasOne =3D FALSE;=0D + }=0D + break;=0D +=0D + case PCR_ADDR_TYPE:=0D + //=0D + // Read the register, and it with the bit to read=0D + //=0D + switch (BitDesc->SizeInBytes) {=0D + case 1:=0D + Register =3D PchPcrRead8 (BitDesc->Reg.Data.Pcr.Fields.Pid, Bit= Desc->Reg.Data.Pcr.Fields.Offset);=0D + break;=0D +=0D + case 2:=0D + Register =3D PchPcrRead16 (BitDesc->Reg.Data.Pcr.Fields.Pid, Bit= Desc->Reg.Data.Pcr.Fields.Offset);=0D + break;=0D +=0D + case 4:=0D + Register =3D PchPcrRead32 (BitDesc->Reg.Data.Pcr.Fields.Pid, Bit= Desc->Reg.Data.Pcr.Fields.Offset);=0D + break;=0D +=0D + default:=0D + //=0D + // Unsupported or invalid register size=0D + //=0D + ASSERT (FALSE);=0D + break;=0D + }=0D +=0D + Register =3D Register & (LShiftU64 (BIT0, BitDesc->Bit));=0D + if (Register) {=0D + BitWasOne =3D TRUE;=0D + } else {=0D + BitWasOne =3D FALSE;=0D + }=0D + break;=0D +=0D + default:=0D + //=0D + // This address type is not yet implemented=0D + //=0D + ASSERT (FALSE);=0D + break;=0D + }=0D +=0D + return BitWasOne;=0D +}=0D +=0D +/**=0D + Write a specifying bit with the register=0D +=0D + @param[in] BitDesc The struct that includes register addres= s, size in byte and bit number=0D + @param[in] ValueToWrite The value to be wrote=0D + @param[in] WriteClear If the rest bits of the register is writ= e clear=0D +=0D +**/=0D +VOID=0D +WriteBitDesc (=0D + CONST PCH_SMM_BIT_DESC *BitDesc,=0D + CONST BOOLEAN ValueToWrite,=0D + CONST BOOLEAN WriteClear=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINT64 Register;=0D + UINT64 AndVal;=0D + UINT64 OrVal;=0D + UINT32 RegSize;=0D + UINT32 PciBus;=0D + UINT32 PciDev;=0D + UINT32 PciFun;=0D + UINT32 PciReg;=0D + UINTN RegisterOffset;=0D + UINT32 BaseAddr;=0D + UINT64 PciBaseAddress;=0D +=0D + ASSERT (BitDesc !=3D NULL);=0D + ASSERT (!IS_BIT_DESC_NULL (*BitDesc));=0D +=0D + RegSize =3D 0;=0D + Register =3D 0;=0D +=0D + if (WriteClear) {=0D + AndVal =3D LShiftU64 (BIT_ZERO, BitDesc->Bit);=0D + } else {=0D + AndVal =3D ~(LShiftU64 (BIT_ZERO, BitDesc->Bit));=0D + }=0D +=0D + OrVal =3D (LShiftU64 ((UINT32) ValueToWrite, BitDesc->Bit));=0D +=0D + switch (BitDesc->Reg.Type) {=0D +=0D + case ACPI_ADDR_TYPE:=0D + case TCO_ADDR_TYPE:=0D + if (BitDesc->Reg.Type =3D=3D ACPI_ADDR_TYPE) {=0D + RegisterOffset =3D BitDesc->Reg.Data.acpi;=0D + BaseAddr =3D mAcpiBaseAddr;=0D + } else {=0D + RegisterOffset =3D BitDesc->Reg.Data.tco;=0D + BaseAddr =3D mTcoBaseAddr;=0D + }=0D +=0D + switch (BitDesc->SizeInBytes) {=0D +=0D + case 0:=0D + //=0D + // Chances are that this field didn't get initialized.=0D + // Check your assignments to bit descriptions.=0D + //=0D + ASSERT (FALSE);=0D + break;=0D +=0D + case 1:=0D + RegSize =3D SMM_IO_UINT8;=0D + break;=0D +=0D + case 2:=0D + RegSize =3D SMM_IO_UINT16;=0D + break;=0D +=0D + case 4:=0D + RegSize =3D SMM_IO_UINT32;=0D + break;=0D +=0D + case 8:=0D + RegSize =3D SMM_IO_UINT64;=0D + break;=0D +=0D + default:=0D + //=0D + // Unsupported or invalid register size=0D + //=0D + ASSERT (FALSE);=0D + break;=0D + }=0D + //=0D + // Double check that we correctly read in the acpi base address=0D + //=0D + ASSERT ((BaseAddr !=3D 0x0) && ((BaseAddr & 0x1) !=3D 0x1));=0D +=0D + //=0D + // As current CPU Smm Io can only support at most=0D + // 32-bit read/write,if Operation is 64 bit,=0D + // we do a 32 bit operation according to BitDesc->Bit=0D + //=0D + if (RegSize =3D=3D SMM_IO_UINT64) {=0D + RegSize =3D SMM_IO_UINT32;=0D + //=0D + // If the operation is for high 32 bits=0D + //=0D + if (BitDesc->Bit >=3D 32) {=0D + RegisterOffset +=3D 4;=0D +=0D + if (WriteClear) {=0D + AndVal =3D LShiftU64 (BIT_ZERO, BitDesc->Bit - 32);=0D + } else {=0D + AndVal =3D ~(LShiftU64 (BIT_ZERO, BitDesc->Bit - 32));=0D + }=0D +=0D + OrVal =3D LShiftU64 ((UINT32) ValueToWrite, BitDesc->Bit - 32);= =0D + }=0D + }=0D +=0D + Status =3D gSmst->SmmIo.Io.Read (=0D + &gSmst->SmmIo,=0D + RegSize,=0D + BaseAddr + RegisterOffset,=0D + 1,=0D + &Register=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Register &=3D AndVal;=0D + Register |=3D OrVal;=0D +=0D + Status =3D gSmst->SmmIo.Io.Write (=0D + &gSmst->SmmIo,=0D + RegSize,=0D + BaseAddr + RegisterOffset,=0D + 1,=0D + &Register=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D + break;=0D +=0D + case GPIO_ADDR_TYPE:=0D + case MEMORY_MAPPED_IO_ADDRESS_TYPE:=0D + //=0D + // Read the register, or it with the bit to set, then write it back.= =0D + //=0D + switch (BitDesc->SizeInBytes) {=0D + case 1:=0D + MmioAndThenOr8 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT8) AndVal= , (UINT8) OrVal);=0D + break;=0D +=0D + case 2:=0D + MmioAndThenOr16 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT16) AndVal= , (UINT16) OrVal);=0D + break;=0D +=0D + case 4:=0D + MmioAndThenOr32 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT32) AndVal= , (UINT32) OrVal);=0D + break;=0D +=0D + case 8:=0D + Register =3D (UINT64) MmioRead32 ((UINTN) B= itDesc->Reg.Data.Mmio);=0D + *((UINT32 *) (&Register) + 1) =3D MmioRead32 ((UINTN) BitDesc->R= eg.Data.Mmio + 4);=0D + Register &=3D AndVal;=0D + Register |=3D OrVal;=0D + MmioWrite32 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT32) Register);= =0D + MmioWrite32 ((UINTN) BitDesc->Reg.Data.Mmio + 4, *((UINT32 *) (&= Register) + 1));=0D + break;=0D +=0D + default:=0D + //=0D + // Unsupported or invalid register size=0D + //=0D + ASSERT (FALSE);=0D + break;=0D + }=0D + break;=0D +=0D + case PCIE_ADDR_TYPE:=0D + PciBus =3D BitDesc->Reg.Data.pcie.Fields.Bus;=0D + PciDev =3D BitDesc->Reg.Data.pcie.Fields.Dev;=0D + PciFun =3D BitDesc->Reg.Data.pcie.Fields.Fnc;=0D + PciReg =3D BitDesc->Reg.Data.pcie.Fields.Reg;=0D + PciBaseAddress =3D PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMB= ER_PCH, PciBus, PciDev, PciFun, 0);=0D + switch (BitDesc->SizeInBytes) {=0D +=0D + case 0:=0D + //=0D + // Chances are that this field didn't get initialized -- check y= our assignments=0D + // to bit descriptions.=0D + //=0D + ASSERT (FALSE);=0D + break;=0D +=0D + case 1:=0D + PciSegmentAndThenOr8 (PciBaseAddress + PciReg, (UINT8) AndVal, (= UINT8) OrVal);=0D + break;=0D +=0D + case 2:=0D + PciSegmentAndThenOr16 (PciBaseAddress + PciReg, (UINT16) AndVal,= (UINT16) OrVal);=0D + break;=0D +=0D + case 4:=0D + PciSegmentAndThenOr32 (PciBaseAddress + PciReg, (UINT32) AndVal,= (UINT32) OrVal);=0D + break;=0D +=0D + default:=0D + //=0D + // Unsupported or invalid register size=0D + //=0D + ASSERT (FALSE);=0D + break;=0D + }=0D + break;=0D +=0D + case PCR_ADDR_TYPE:=0D + //=0D + // Read the register, or it with the bit to set, then write it back.= =0D + //=0D + switch (BitDesc->SizeInBytes) {=0D + case 1:=0D + PchPcrAndThenOr8 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pi= d, (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT8) AndVal, (UINT8) = OrVal);=0D + break;=0D +=0D + case 2:=0D + PchPcrAndThenOr16 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pi= d, (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT16) AndVal, (UINT16) = OrVal);=0D + break;=0D +=0D + case 4:=0D + PchPcrAndThenOr32 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pi= d, (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT32) AndVal, (UINT32) = OrVal);=0D + break;=0D +=0D + default:=0D + //=0D + // Unsupported or invalid register size=0D + //=0D + ASSERT (FALSE);=0D + break;=0D + }=0D + break;=0D +=0D + default:=0D + //=0D + // This address type is not yet implemented=0D + //=0D + ASSERT (FALSE);=0D + break;=0D + }=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= xSmmHelpers.h b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/= PchxSmmHelpers.h new file mode 100644 index 0000000000..6dd6f2027d --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHel= pers.h @@ -0,0 +1,107 @@ +/** @file=0D + This driver is responsible for the registration of child drivers=0D + and the abstraction of the PCH SMI sources.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#ifndef _PCHX_SMM_HELPERS_H_=0D +#define _PCHX_SMM_HELPERS_H_=0D +=0D +#include "PchSmm.h"=0D +=0D +/**=0D + Initialize bits that aren't necessarily related to an SMI source.=0D +=0D +=0D + @retval EFI_SUCCESS SMI source initialization completed.=0D + @retval Asserts Global Smi Bit is not enabled successful= ly.=0D +**/=0D +EFI_STATUS=0D +PchSmmInitHardware (=0D + VOID=0D + );=0D +=0D +/**=0D + Enables the PCH to generate SMIs. Note that no SMIs will be generated=0D + if no SMI sources are enabled. Conversely, no enabled SMI source will=0D + generate SMIs if SMIs are not globally enabled. This is the main=0D + switchbox for SMI generation.=0D +=0D +=0D + @retval EFI_SUCCESS Enable Global Smi Bit completed=0D +**/=0D +EFI_STATUS=0D +PchSmmEnableGlobalSmiBit (=0D + VOID=0D + );=0D +=0D +/**=0D + Clears the SMI after all SMI source have been processed.=0D + Note that this function will not work correctly (as it is=0D + written) unless all SMI sources have been processed.=0D + A revision of this function could manually clear all SMI=0D + status bits to guarantee success.=0D +=0D +=0D + @retval EFI_SUCCESS Clears the SMIs completed=0D + @retval Asserts EOS was not set to a 1=0D +**/=0D +EFI_STATUS=0D +PchSmmClearSmi (=0D + VOID=0D + );=0D +=0D +/**=0D + Set the SMI EOS bit after all SMI source have been processed.=0D +=0D +=0D + @retval FALSE EOS was not set to a 1; this is an error= =0D + @retval TRUE EOS was correctly set to a 1=0D +**/=0D +BOOLEAN=0D +PchSmmSetAndCheckEos (=0D + VOID=0D + );=0D +=0D +/**=0D + Determine whether an ACPI OS is present (via the SCI_EN bit)=0D +=0D +=0D + @retval TRUE ACPI OS is present=0D + @retval FALSE ACPI OS is not present=0D +**/=0D +BOOLEAN=0D +PchSmmGetSciEn (=0D + VOID=0D + );=0D +=0D +/**=0D + Read a specifying bit with the register=0D +=0D + @param[in] BitDesc The struct that includes register addres= s, size in byte and bit number=0D +=0D + @retval TRUE The bit is enabled=0D + @retval FALSE The bit is disabled=0D +**/=0D +BOOLEAN=0D +ReadBitDesc (=0D + CONST PCH_SMM_BIT_DESC *BitDesc=0D + );=0D +=0D +/**=0D + Write a specifying bit with the register=0D +=0D + @param[in] BitDesc The struct that includes register addres= s, size in byte and bit number=0D + @param[in] ValueToWrite The value to be wrote=0D + @param[in] WriteClear If the rest bits of the register is writ= e clear=0D +=0D +**/=0D +VOID=0D +WriteBitDesc (=0D + CONST PCH_SMM_BIT_DESC *BitDesc,=0D + CONST BOOLEAN ValueToWrite,=0D + CONST BOOLEAN WriteClear=0D + );=0D +=0D +#endif=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/Sm= mControl.inf b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/= SmmControl.inf new file mode 100644 index 0000000000..a142cfa95a --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContro= l.inf @@ -0,0 +1,54 @@ +## @file=0D +# Component description file for SmmControl module=0D +#=0D +# Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +=0D +[Defines]=0D +INF_VERSION =3D 0x00010017=0D +BASE_NAME =3D SmmControl=0D +FILE_GUID =3D A0BAD9F7-AB78-491b-B583-C52B7F84B9E0=0D +VERSION_STRING =3D 1.0=0D +MODULE_TYPE =3D DXE_RUNTIME_DRIVER=0D +ENTRY_POINT =3D SmmControlDriverEntryInit=0D +#=0D +# The following information is for reference only and not required by the = build tools.=0D +#=0D +# VALID_ARCHITECTURES =3D IA32 X64=0D +#=0D +=0D +=0D +=0D +[LibraryClasses]=0D +IoLib=0D +UefiDriverEntryPoint=0D +DebugLib=0D +UefiBootServicesTableLib=0D +UefiRuntimeServicesTableLib=0D +PmcLib=0D +GpioLib=0D +=0D +=0D +[Packages]=0D +MdePkg/MdePkg.dec=0D +TigerlakeSiliconPkg/SiPkg.dec=0D +=0D +=0D +[Sources]=0D +SmmControlDriver.h=0D +SmmControlDriver.c=0D +=0D +=0D +[Protocols]=0D +gEfiSmmControl2ProtocolGuid ## PRODUCES=0D +=0D +=0D +[Guids]=0D +gEfiEventVirtualAddressChangeGuid=0D +=0D +=0D +[Depex]=0D +TRUE=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/Sm= mControlDriver.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/Runtime= Dxe/SmmControlDriver.c new file mode 100644 index 0000000000..5822f42165 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContro= lDriver.c @@ -0,0 +1,394 @@ +/** @file=0D + This is the driver that publishes the SMM Control Protocol.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include "SmmControlDriver.h"=0D +=0D +STATIC SMM_CONTROL_PRIVATE_DATA mSmmControl;=0D +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mABase;=0D +=0D +VOID=0D +EFIAPI=0D +DisablePendingSmis (=0D + VOID=0D + );=0D +=0D +/**=0D + Fixup internal data pointers so that the services can be called in virtu= al mode.=0D +=0D + @param[in] Event The event registered.=0D + @param[in] Context Event context.=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +SmmControlVirtualAddressChangeEvent (=0D + IN EFI_EVENT Event,=0D + IN VOID *Context=0D + )=0D +{=0D + gRT->ConvertPointer (0, (VOID *) &(mSmmControl.SmmControl.Trigger));=0D + gRT->ConvertPointer (0, (VOID *) &(mSmmControl.SmmControl.Clear));=0D +}=0D +=0D +/**=0D + SmmControl DXE RUNTIME Module Entry Point\n=0D + - Introduction\n=0D + The SmmControl module is a DXE RUNTIME driver that provides a standard= way=0D + for other drivers to trigger software SMIs.=0D +=0D + - @pre=0D + - PCH Power Management I/O space base address has already been program= med.=0D + If SmmControl Runtime DXE driver is run before Status Code Runtime P= rotocol=0D + is installed and there is the need to use Status code in the driver,= it will=0D + be necessary to add EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID to the dep= endency file.=0D + - EFI_SMM_BASE2_PROTOCOL=0D + - Documented in the System Management Mode Core Interface Specificat= ion.=0D +=0D + - @result=0D + The SmmControl driver produces the EFI_SMM_CONTROL_PROTOCOL documented= in=0D + System Management Mode Core Interface Specification.=0D +=0D + @param[in] ImageHandle Handle for the image of this driver=0D + @param[in] SystemTable Pointer to the EFI System Table=0D +=0D + @retval EFI_STATUS Results of the installation of the SMM C= ontrol Protocol=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +SmmControlDriverEntryInit (=0D + IN EFI_HANDLE ImageHandle,=0D + IN EFI_SYSTEM_TABLE *SystemTable=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_EVENT Event;=0D +=0D + DEBUG ((DEBUG_INFO, "SmmControlDriverEntryInit() Start\n"));=0D +=0D + //=0D + // Get the Power Management I/O space base address. We assume that=0D + // this base address has already been programmed if this driver is=0D + // being run.=0D + //=0D + mABase =3D PmcGetAcpiBase ();=0D +=0D + Status =3D EFI_SUCCESS;=0D + if (mABase !=3D 0) {=0D + //=0D + // Install the instance of the protocol=0D + //=0D + mSmmControl.Signature =3D SMM_CONTROL_PRIVATE_DA= TA_SIGNATURE;=0D + mSmmControl.Handle =3D ImageHandle;=0D +=0D + mSmmControl.SmmControl.Trigger =3D Activate;=0D + mSmmControl.SmmControl.Clear =3D Deactivate;=0D + mSmmControl.SmmControl.MinimumTriggerPeriod =3D 0;=0D +=0D + //=0D + // Install our protocol interfaces on the device's handle=0D + //=0D + Status =3D gBS->InstallMultipleProtocolInterfaces (=0D + &mSmmControl.Handle,=0D + &gEfiSmmControl2ProtocolGuid,=0D + &mSmmControl.SmmControl,=0D + NULL=0D + );=0D + } else {=0D + Status =3D EFI_DEVICE_ERROR;=0D + return Status;=0D + }=0D +=0D + Status =3D gBS->CreateEventEx (=0D + EVT_NOTIFY_SIGNAL,=0D + TPL_NOTIFY,=0D + SmmControlVirtualAddressChangeEvent,=0D + NULL,=0D + &gEfiEventVirtualAddressChangeGuid,=0D + &Event=0D + );=0D + //=0D + // Disable any PCH SMIs that, for whatever reason, are asserted after th= e boot.=0D + //=0D + DisablePendingSmis ();=0D +=0D + DEBUG ((DEBUG_INFO, "SmmControlDriverEntryInit() End\n"));=0D +=0D + return Status;=0D +}=0D +=0D +/**=0D + Trigger the software SMI=0D +=0D + @param[in] Data The value to be set on the software SMI = data port=0D +=0D + @retval EFI_SUCCESS Function completes successfully=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +SmmTrigger (=0D + IN UINT8 Data=0D + )=0D +{=0D + UINT32 OutputData;=0D + UINT32 OutputPort;=0D +=0D + //=0D + // Enable the APMC SMI=0D + //=0D + OutputPort =3D mABase + R_ACPI_IO_SMI_EN;=0D + OutputData =3D IoRead32 ((UINTN) OutputPort);=0D + OutputData |=3D (B_ACPI_IO_SMI_EN_APMC | B_ACPI_IO_SMI_EN_GBL_SMI);=0D + DEBUG (=0D + (DEBUG_VERBOSE,=0D + "The SMI Control Port at address %x will be written to %x.\n",=0D + OutputPort,=0D + OutputData)=0D + );=0D + IoWrite32 (=0D + (UINTN) OutputPort,=0D + (UINT32) (OutputData)=0D + );=0D +=0D + OutputPort =3D R_PCH_IO_APM_CNT;=0D + OutputData =3D Data;=0D +=0D + //=0D + // Generate the APMC SMI=0D + //=0D + IoWrite8 (=0D + (UINTN) OutputPort,=0D + (UINT8) (OutputData)=0D + );=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Clear the SMI status=0D +=0D +=0D + @retval EFI_SUCCESS The function completes successfully=0D + @retval EFI_DEVICE_ERROR Something error occurred=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +SmmClear (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINT32 OutputData;=0D + UINT32 OutputPort;=0D +=0D + Status =3D EFI_SUCCESS;=0D +=0D + //=0D + // Clear the Power Button Override Status Bit, it gates EOS from being s= et.=0D + //=0D + OutputPort =3D mABase + R_ACPI_IO_PM1_STS;=0D + OutputData =3D B_ACPI_IO_PM1_STS_PRBTNOR;=0D + DEBUG (=0D + (DEBUG_VERBOSE,=0D + "The PM1 Status Port at address %x will be written to %x.\n",=0D + OutputPort,=0D + OutputData)=0D + );=0D + IoWrite16 (=0D + (UINTN) OutputPort,=0D + (UINT16) (OutputData)=0D + );=0D +=0D + //=0D + // Clear the APM SMI Status Bit=0D + //=0D + OutputPort =3D mABase + R_ACPI_IO_SMI_STS;=0D + OutputData =3D B_ACPI_IO_SMI_STS_APM;=0D + DEBUG (=0D + (DEBUG_VERBOSE,=0D + "The SMI Status Port at address %x will be written to %x.\n",=0D + OutputPort,=0D + OutputData)=0D + );=0D + IoWrite32 (=0D + (UINTN) OutputPort,=0D + (UINT32) (OutputData)=0D + );=0D +=0D + //=0D + // Set the EOS Bit=0D + //=0D + OutputPort =3D mABase + R_ACPI_IO_SMI_EN;=0D + OutputData =3D IoRead32 ((UINTN) OutputPort);=0D + OutputData |=3D B_ACPI_IO_SMI_EN_EOS;=0D + DEBUG (=0D + (DEBUG_VERBOSE,=0D + "The SMI Control Port at address %x will be written to %x.\n",=0D + OutputPort,=0D + OutputData)=0D + );=0D + IoWrite32 (=0D + (UINTN) OutputPort,=0D + (UINT32) (OutputData)=0D + );=0D +=0D + //=0D + // There is no need to read EOS back and check if it is set.=0D + // This can lead to a reading of zero if an SMI occurs right after the S= MI_EN port read=0D + // but before the data is returned to the CPU.=0D + // SMM Dispatcher should make sure that EOS is set after all SMI sources= are processed.=0D + //=0D + return Status;=0D +}=0D +=0D +/**=0D + This routine generates an SMI=0D +=0D + @param[in] This The EFI SMM Control protocol insta= nce=0D + @param[in, out] CommandPort The buffer contains data to the co= mmand port=0D + @param[in, out] DataPort The buffer contains data to the da= ta port=0D + @param[in] Periodic Periodic or not=0D + @param[in] ActivationInterval Interval of periodic SMI=0D +=0D + @retval EFI Status Describing the result of the opera= tion=0D + @retval EFI_INVALID_PARAMETER Some parameter value passed is not= supported=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +Activate (=0D + IN CONST EFI_SMM_CONTROL2_PROTOCOL * This,=0D + IN OUT UINT8 *CommandPort = OPTIONAL,=0D + IN OUT UINT8 *DataPort = OPTIONAL,=0D + IN BOOLEAN Periodic = OPTIONAL,=0D + IN UINTN ActivationInterval= OPTIONAL=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINT8 Data;=0D +=0D + if (Periodic) {=0D + DEBUG ((DEBUG_WARN, "Invalid parameter\n"));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + if (CommandPort =3D=3D NULL) {=0D + Data =3D 0xFF;=0D + } else {=0D + Data =3D *CommandPort;=0D + }=0D + //=0D + // Clear any pending the APM SMI=0D + //=0D + Status =3D SmmClear ();=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D +=0D + return SmmTrigger (Data);=0D +}=0D +=0D +/**=0D + This routine clears an SMI=0D +=0D + @param[in] This The EFI SMM Control protocol instance=0D + @param[in] Periodic Periodic or not=0D +=0D + @retval EFI Status Describing the result of the operation=0D + @retval EFI_INVALID_PARAMETER Some parameter value passed is not suppo= rted=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +Deactivate (=0D + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,=0D + IN BOOLEAN Periodic OPTIONAL=0D + )=0D +{=0D + if (Periodic) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + return SmmClear ();=0D +}=0D +/**=0D + Disable all pending SMIs=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +DisablePendingSmis (=0D + VOID=0D + )=0D +{=0D + UINT32 Data;=0D + BOOLEAN SciEn;=0D +=0D + //=0D + // Determine whether an ACPI OS is present (via the SCI_EN bit)=0D + //=0D + Data =3D IoRead16 ((UINTN) mABase + R_ACPI_IO_PM1_CNT);=0D + SciEn =3D (BOOLEAN) ((Data & B_ACPI_IO_PM1_CNT_SCI_EN) =3D=3D B_ACPI= _IO_PM1_CNT_SCI_EN);=0D +=0D + if (!SciEn) {=0D + //=0D + // Clear any SMIs that double as SCIs (when SCI_EN=3D=3D0)=0D + //=0D + IoWrite16 ((UINTN) mABase + R_ACPI_IO_PM1_STS, 0xFFFF);=0D + IoWrite16 ((UINTN) mABase + R_ACPI_IO_PM1_EN, 0);=0D + IoWrite16 ((UINTN) mABase + R_ACPI_IO_PM1_CNT, 0);=0D + IoWrite32 (=0D + (UINTN) mABase + R_ACPI_IO_GPE0_STS_127_96,=0D + (UINT32)( B_ACPI_IO_GPE0_STS_127_96_WADT |=0D + B_ACPI_IO_GPE0_STS_127_96_USB_CON_DSX_STS |=0D + B_ACPI_IO_GPE0_STS_127_96_LAN_WAKE |=0D + B_ACPI_IO_GPE0_STS_127_96_PME_B0 |=0D + B_ACPI_IO_GPE0_STS_127_96_PME |=0D + B_ACPI_IO_GPE0_STS_127_96_BATLOW |=0D + B_ACPI_IO_GPE0_STS_127_96_RI |=0D + B_ACPI_IO_GPE0_STS_127_96_SWGPE)=0D + );=0D + IoWrite32 ((UINTN) mABase + R_ACPI_IO_GPE0_EN_127_96, (UINT32) B_ACPI_= IO_GPE0_EN_127_96_WADT);=0D + }=0D + //=0D + // Clear and disable all SMIs that are unaffected by SCI_EN=0D + //=0D + GpioDisableAllGpiSmi ();=0D +=0D + GpioClearAllGpiSmiSts ();=0D +=0D + IoWrite32 ((UINTN) mABase + R_ACPI_IO_DEVACT_STS, 0x0000FFFF);=0D +=0D + IoWrite32 ((UINTN) mABase + R_ACPI_IO_SMI_STS, ~0u);=0D +=0D + //=0D + // (Make sure to write this register last -- EOS re-enables SMIs for the= PCH)=0D + //=0D + Data =3D IoRead32 ((UINTN) mABase + R_ACPI_IO_SMI_EN);=0D + //=0D + // clear all bits except those tied to SCI_EN=0D + //=0D + Data &=3D B_ACPI_IO_SMI_EN_BIOS_RLS;=0D + //=0D + // enable SMIs and specifically enable writes to APM_CNT.=0D + //=0D + Data |=3D B_ACPI_IO_SMI_EN_GBL_SMI | B_ACPI_IO_SMI_EN_APMC;=0D + //=0D + // NOTE: Default value of EOS is set in PCH, it will be automatically c= leared Once the PCH asserts SMI# low,=0D + // we don't need to do anything to clear it=0D + //=0D + IoWrite32 ((UINTN) mABase + R_ACPI_IO_SMI_EN, Data);=0D +}=0D +=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/Sm= mControlDriver.h b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/Runtime= Dxe/SmmControlDriver.h new file mode 100644 index 0000000000..af368e6945 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContro= lDriver.h @@ -0,0 +1,130 @@ +/** @file=0D + Header file for SMM Control Driver.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#ifndef _SMM_CONTROL_DRIVER_H_=0D +#define _SMM_CONTROL_DRIVER_H_=0D +=0D +#include =0D +=0D +=0D +#define SMM_CONTROL_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('i', '4', 's', '= c')=0D +=0D +typedef struct {=0D + UINTN Signature;=0D + EFI_HANDLE Handle;=0D + EFI_SMM_CONTROL2_PROTOCOL SmmControl;=0D +} SMM_CONTROL_PRIVATE_DATA;=0D +=0D +#define SMM_CONTROL_PRIVATE_DATA_FROM_THIS(a) CR (a, SMM_CONTROL_PRIVATE_D= ATA, SmmControl, SMM_CONTROL_DEV_SIGNATURE)=0D +=0D +//=0D +// Prototypes=0D +//=0D +=0D +/**=0D + SmmControl DXE RUNTIME Module Entry Point\n=0D + - Introduction\n=0D + The SmmControl module is a DXE RUNTIME driver that provides a standard= way=0D + for other drivers to trigger software SMIs.=0D +=0D + - @pre=0D + - PCH Power Management I/O space base address has already been program= med.=0D + If SmmControl Runtime DXE driver is run before Status Code Runtime P= rotocol=0D + is installed and there is the need to use Status code in the driver,= it will=0D + be necessary to add EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID to the dep= endency file.=0D + - EFI_SMM_BASE2_PROTOCOL=0D + - Documented in the System Management Mode Core Interface Specificat= ion.=0D +=0D + - @result=0D + The SmmControl driver produces the EFI_SMM_CONTROL_PROTOCOL documented= in=0D + System Management Mode Core Interface Specification.=0D +=0D + @param[in] ImageHandle Handle for the image of this driver=0D + @param[in] SystemTable Pointer to the EFI System Table=0D +=0D + @retval EFI_STATUS Results of the installation of the SMM C= ontrol Protocol=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +SmmControlDriverEntryInit (=0D + IN EFI_HANDLE ImageHandle,=0D + IN EFI_SYSTEM_TABLE *SystemTable=0D + );=0D +=0D +/**=0D + Trigger the software SMI=0D +=0D + @param[in] Data The value to be set on the software SMI = data port=0D +=0D + @retval EFI_SUCCESS Function completes successfully=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +SmmTrigger (=0D + UINT8 Data=0D + );=0D +=0D +/**=0D + Clear the SMI status=0D +=0D +=0D + @retval EFI_SUCCESS The function completes successfully=0D + @retval EFI_DEVICE_ERROR Something error occurred=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +SmmClear (=0D + VOID=0D + );=0D +=0D +/**=0D + This routine generates an SMI=0D +=0D + @param[in] This The EFI SMM Control protocol insta= nce=0D + @param[in, out] ArgumentBuffer The buffer of argument=0D + @param[in, out] ArgumentBufferSize The size of the argument buffer=0D + @param[in] Periodic Periodic or not=0D + @param[in] ActivationInterval Interval of periodic SMI=0D +=0D + @retval EFI Status Describing the result of the opera= tion=0D + @retval EFI_INVALID_PARAMETER Some parameter value passed is not= supported=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +Activate (=0D + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,=0D + IN OUT UINT8 *ArgumentBuffer OPTIONAL,=0D + IN OUT UINT8 *ArgumentBufferSize OPTIONAL,=0D + IN BOOLEAN Periodic OPTIONAL,=0D + IN UINTN ActivationInterval OPTIONAL=0D + );=0D +=0D +/**=0D + This routine clears an SMI=0D +=0D + @param[in] This The EFI SMM Control protocol instance=0D + @param[in] Periodic Periodic or not=0D +=0D + @retval EFI Status Describing the result of the operation=0D + @retval EFI_INVALID_PARAMETER Some parameter value passed is not suppo= rted=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +Deactivate (=0D + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,=0D + IN BOOLEAN Periodic OPTIONAL=0D + );=0D +/**=0D + Disable all pending SMIs=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +DisablePendingSmis (=0D + VOID=0D + );=0D +=0D +#endif=0D --=20 2.24.0.windows.2