From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: intel.com, ip: 134.134.136.20, mailfrom: chasel.chiu@intel.com) Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by groups.io with SMTP; Fri, 16 Aug 2019 18:15:47 -0700 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Aug 2019 18:15:47 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.64,395,1559545200"; d="scan'208";a="188974582" Received: from pgsmsx113.gar.corp.intel.com ([10.108.55.202]) by orsmga002.jf.intel.com with ESMTP; 16 Aug 2019 18:15:41 -0700 Received: from pgsmsx111.gar.corp.intel.com ([169.254.2.22]) by pgsmsx113.gar.corp.intel.com ([169.254.6.14]) with mapi id 14.03.0439.000; Sat, 17 Aug 2019 09:15:40 +0800 From: "Chiu, Chasel" To: "Kubacki, Michael A" , "devel@edk2.groups.io" CC: "Chaganty, Rangasai V" , "Desimone, Nathaniel L" , "Gao, Liming" , "Kinney, Michael D" , "Sinha, Ankit" Subject: Re: [edk2-platforms][PATCH V1 27/37] CoffeelakeSiliconPkg/Pch: Add PchSmiDispatcher Thread-Topic: [edk2-platforms][PATCH V1 27/37] CoffeelakeSiliconPkg/Pch: Add PchSmiDispatcher Thread-Index: AQHVVJEdKhcHsfHWEEqVP0T2sHxROqb+iVsg Date: Sat, 17 Aug 2019 01:15:40 +0000 Message-ID: <3C3EFB470A303B4AB093197B6777CCEC504623EC@PGSMSX111.gar.corp.intel.com> References: <20190817001603.30632-1-michael.a.kubacki@intel.com> <20190817001603.30632-28-michael.a.kubacki@intel.com> In-Reply-To: <20190817001603.30632-28-michael.a.kubacki@intel.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: dlp-product: dlpe-windows dlp-version: 11.2.0.6 dlp-reaction: no-action x-titus-metadata-40: eyJDYXRlZ29yeUxhYmVscyI6IiIsIk1ldGFkYXRhIjp7Im5zIjoiaHR0cDpcL1wvd3d3LnRpdHVzLmNvbVwvbnNcL0ludGVsMyIsImlkIjoiZDVjMmQ2NTgtNWNlNC00OWU1LTkxYmYtNzhjYTEzM2M1MTc1IiwicHJvcHMiOlt7Im4iOiJDVFBDbGFzc2lmaWNhdGlvbiIsInZhbHMiOlt7InZhbHVlIjoiQ1RQX05UIn1dfV19LCJTdWJqZWN0TGFiZWxzIjpbXSwiVE1DVmVyc2lvbiI6IjE3LjEwLjE4MDQuNDkiLCJUcnVzdGVkTGFiZWxIYXNoIjoiVkpTaFFTSFlsa2EybmF2TGs1YnFKWkt3XC9cL0RMWmdxdHlUNytTV3Z1TDRMUDFxSXBQXC9mbnJxN2dRcGZqclJ2YiJ9 x-ctpclassification: CTP_NT x-originating-ip: [172.30.20.206] MIME-Version: 1.0 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Reviewed-by: Chasel Chiu > -----Original Message----- > From: Kubacki, Michael A > Sent: Saturday, August 17, 2019 8:16 AM > To: devel@edk2.groups.io > Cc: Chaganty, Rangasai V ; Chiu, Chasel > ; Desimone, Nathaniel L > ; Gao, Liming ; > Kinney, Michael D ; Sinha, Ankit > > Subject: [edk2-platforms][PATCH V1 27/37] CoffeelakeSiliconPkg/Pch: Add > PchSmiDispatcher >=20 > REF:https://bugzilla.tianocore.org/show_bug.cgi?id=3D2082 >=20 > Adds the PchSmiDispatcher module. Dispatches PCH SMIs to appropriate > SMI handlers registered in various SMM modules. >=20 > Cc: Sai Chaganty > Cc: Chasel Chiu > Cc: Nate DeSimone > Cc: Liming Gao > Cc: Michael D Kinney > Cc: Ankit Sinha > Signed-off-by: Michael Kubacki > --- >=20 > Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispat > cher.inf | 109 + > Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.h > | 228 ++ > Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h > | 1031 ++++++++ >=20 > Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi. > h | 342 +++ >=20 > Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelp > ers.h | 157 ++ >=20 > Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHel > pers.h | 105 + > Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.c > | 1264 ++++++++++ >=20 > Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispat > ch.c | 2452 ++++++++++++++++++++ >=20 > Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCore > .c | 911 ++++++++ >=20 > Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi. > c | 1595 +++++++++++++ >=20 > Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi.c > | 254 ++ >=20 > Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelp > ers.c | 358 +++ >=20 > Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPerio > dicTimer.c | 675 ++++++ >=20 > Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPow > erButton.c | 83 + > Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.c > | 385 +++ > Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c > | 229 ++ >=20 > Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb. > c | 231 ++ >=20 > Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHel > pers.c | 764 ++++++ > 18 files changed, 11173 insertions(+) >=20 > diff --git > a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDisp > atcher.inf > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDis > patcher.inf > new file mode 100644 > index 0000000000..38d5dbeebf > --- /dev/null > +++ > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDis > patcher.inf > @@ -0,0 +1,109 @@ > +## @file > +# Component description file for the Pch SMI Dispatch Handlers module > +# > +# Copyright (c) 2019 Intel Corporation. All rights reserved.
> +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > +INF_VERSION =3D 0x00010017 > +BASE_NAME =3D PchSmiDispatcher > +FILE_GUID =3D B0D6ED53-B844-43f5-BD2F-61095264E77E > +VERSION_STRING =3D 1.0 > +MODULE_TYPE =3D DXE_SMM_DRIVER > +PI_SPECIFICATION_VERSION =3D 1.10 > +ENTRY_POINT =3D InitializePchSmmDispatcher > + > + > +[LibraryClasses] > +UefiBootServicesTableLib > +UefiDriverEntryPoint > +IoLib > +DebugLib > +PcdLib > +BaseLib > +BaseMemoryLib > +HobLib > +DevicePathLib > +PchCycleDecodingLib > +PchPcieRpLib > +PchPcrLib > +SmmServicesTableLib > +ReportStatusCodeLib > +PerformanceLib > +DxeServicesTableLib > +GpioLib > +GpioPrivateLib > +PchEspiLib > +S3BootScriptLib > +ConfigBlockLib > +PmcPrivateLib > +PmcLib > +SmiHandlerProfileLib > + > + > +[Packages] > +MdePkg/MdePkg.dec > +CoffeelakeSiliconPkg/SiPkg.dec > + > + > +[Pcd] > +# Progress Code for S3 Suspend end. > +# PROGRESS_CODE_S3_SUSPEND_END =3D (EFI_SOFTWARE_SMM_DRIVER | > (EFI_OEM_SPECIFIC | 0x00000001)) =3D 0x03078001 > +gSiPkgTokenSpaceGuid.PcdProgressCodeS3SuspendEnd > +gSiPkgTokenSpaceGuid.PcdEfiGcdAllocateType > + > + > +[Sources] > +PchSmm.h > +PchSmmCore.c > +PchSmmHelpers.h > +PchSmmHelpers.c > +PchxSmmHelpers.h > +PchxSmmHelpers.c > +PchSmmUsb.c > +PchSmmGpi.c > +PchSmmPowerButton.c > +PchSmmSw.c > +PchSmmSx.c > +PchSmmPeriodicTimer.c > +IoTrap.c > +PchSmiDispatch.c > +PchSmmEspi.c > + > + > +[Protocols] > +gEfiPciRootBridgeIoProtocolGuid ## CONSUMES > +gEfiSmmGpiDispatch2ProtocolGuid ## PRODUCES > +gEfiSmmSxDispatch2ProtocolGuid ## PRODUCES > +gEfiSmmSwDispatch2ProtocolGuid ## PRODUCES > +gEfiSmmUsbDispatch2ProtocolGuid ## PRODUCES > +gEfiSmmPowerButtonDispatch2ProtocolGuid ## PRODUCES > +gEfiSmmPeriodicTimerDispatch2ProtocolGuid ## PRODUCES > +gEfiSmmBase2ProtocolGuid ## CONSUMES > +gEfiSmmCpuProtocolGuid ## CONSUMES > +gEfiSmmReadyToLockProtocolGuid ## CONSUMES > +gEfiSmmIoTrapDispatch2ProtocolGuid ## PRODUCES > +gPchSmmIoTrapControlGuid ## PRODUCES > +gPchTcoSmiDispatchProtocolGuid ## PRODUCES > +gPchPcieSmiDispatchProtocolGuid ## PRODUCES > +gPchAcpiSmiDispatchProtocolGuid ## PRODUCES > +gPchSmiDispatchProtocolGuid ## PRODUCES > +gPchEspiSmiDispatchProtocolGuid ## PRODUCES > +gPchSmmPeriodicTimerControlGuid ## PRODUCES > +gIoTrapExDispatchProtocolGuid ## PRODUCES > +gPchNvsAreaProtocolGuid ## CONSUMES > + > + > +[Guids] > + > + > +[Depex] > +gEfiPciRootBridgeIoProtocolGuid AND > +gEfiPciHostBridgeResourceAllocationProtocolGuid AND ## This is to ensure > that PCI MMIO resource has been prepared and available for this driver to > allocate. > +gEfiSmmCpuProtocolGuid AND > +gEfiSmmBase2ProtocolGuid AND ## This is for SmmServicesTableLib > +gPchNvsAreaProtocolGuid > + > diff --git > a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.h > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.h > new file mode 100644 > index 0000000000..9d6a459ff3 > --- /dev/null > +++ > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.h > @@ -0,0 +1,228 @@ > +/** @file > + Defines and prototypes for the IoTrap SMM driver > + > + Copyright (c) 2019 Intel Corporation. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#ifndef _IO_TRAP_H_ > +#define _IO_TRAP_H_ > + > +// > +// Include files > +// > +#include > +#include > +#include > +#include > +#include > + > +#define IO_TRAP_HANDLER_NUM 4 > + > +// > +// Driver private data > +// > +#define IO_TRAP_INSTANCE_SIGNATURE SIGNATURE_32 ('I', 'O', 'T', 'P') > + > +typedef struct { > + EFI_HANDLE IoTrapHandle; > + /** > + The callback linked list for all "merged" IoTrap callbacks. > + **/ > + LIST_ENTRY CallbackDataBase; > + /** > + The IoTrap IO range used length tracking for "merged" IoTrap registe= r. > + **/ > + UINT32 TrapUsedLength; > + /** > + Determine if IoTrap can be merged with other IoTrap callbacks. > + If MergeDisable is TRUE, then there is only one callback function fo= r one > IoTrap register. > + If MergeDisable is FALSE, then there are multiple callbacks in the > "CallbackDataBase" for one IoTrap register. > + **/ > + BOOLEAN MergeDisable; > + /** > + Indicator of the resource tracking in ACPI. > + If the registration address is not 0, it's caller's responsibility t= o reserve the > IO resource in ACPI. > + **/ > + BOOLEAN ReservedAcpiIoResource; > + /** > + Dispatcher for each IoTrap register. > + **/ > + PCH_SMI_DISPATCH_CALLBACK CallbackDispatcher; > +} IO_TRAP_ENTRY_ATTRIBUTES; > + > +typedef struct { > + UINT32 Signature; > + EFI_HANDLE Handle; > + EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL > EfiSmmIoTrapDispatchProtocol; > + PCH_SMM_IO_TRAP_CONTROL_PROTOCOL > PchSmmIoTrapControlProtocol; ///< Protocol for runtime control the > IoTrap state > + IO_TRAP_EX_DISPATCH_PROTOCOL IoTrapExDispatchProtocol; > ///< Protocol for IoTrap Extension > + IO_TRAP_ENTRY_ATTRIBUTES Entry[IO_TRAP_HANDLER_NUM]; > +} IO_TRAP_INSTANCE; > + > +#define IO_TRAP_INSTANCE_FROM_THIS(a) CR (a, IO_TRAP_INSTANCE, > EfiSmmIoTrapDispatchProtocol, IO_TRAP_INSTANCE_SIGNATURE) > + > +/// > +/// "IOTRAP" RECORD > +/// Linked list data structures > +/// > +#define IO_TRAP_RECORD_SIGNATURE SIGNATURE_32 ('I', 'T', 'R', 'C') > + > +typedef struct _IO_TRAP_RECORD { > + UINT32 Signature; > + LIST_ENTRY Link; > + IO_TRAP_EX_REGISTER_CONTEXT Context; > + /** > + The callback function of IoTrap protocol. > + This also indicate it's the record for IoTrapProtocol. > + Only one of IoTrapCallback or IoTrapExCallback is valid at a time. > + **/ > + EFI_SMM_HANDLER_ENTRY_POINT2 IoTrapCallback; > + /** > + The callback function of IoTrapEx protocol > + This also indicate it's the record for IoTrapExProtocol. > + Only one of IoTrapCallback or IoTrapExCallback is valid at a time. > + **/ > + IO_TRAP_EX_DISPATCH_CALLBACK IoTrapExCallback; > + UINT8 IoTrapNumber; > +} IO_TRAP_RECORD; > + > +#define IO_TRAP_RECORD_FROM_LINK(_record) CR (_record, > IO_TRAP_RECORD, Link, IO_TRAP_RECORD_SIGNATURE) > + > +// > +// Prototypes > +// > +/** > + The IoTrap module abstracts PCH I/O trapping capabilities for other dr= ivers. > + This driver manages the limited I/O trap resources. > + > + @param[in] ImageHandle Image handle for this driver ima= ge > + > + @retval EFI_SUCCESS Driver initialization completed > successfully > +**/ > +EFI_STATUS > +EFIAPI > +InstallIoTrap ( > + IN EFI_HANDLE ImageHandle > + ); > + > +/** > + Register a new IO Trap SMI dispatch function with a parent SMM driver. > + The caller will provide information about the IO trap characteristics = via > + the context. This includes base address, length, read vs. r/w, etc. > + This function will autoallocate IO base address from a common pool if = the > base address is 0, > + and the RegisterContext Address field will be updated. > + The service will not perform GCD allocation if the base address is non= -zero. > + In this case, the caller is responsible for the existence and allocati= on of the > + specific IO range. > + This function looks for the suitable handler and Register a new IoTrap > handler > + if the IO Trap handler is not used. It also enable the IO Trap Range t= o > generate > + SMI. > + > + @param[in] This Pointer to the > EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL instance. > + @param[in] DispatchFunction Pointer to dispatch function to be > invoked for > + this SMI source. > + @param[in, out] RegisterContext Pointer to the dispatch function's con= text. > + The caller fills this context in befor= e calling > + the register function to indicate to t= he register > + function the IO trap SMI source for wh= ich the > dispatch > + function should be invoked. This may = not be NULL. > + If the registration address is not 0, = it's caller's > responsibility > + to reserve the IO resource in ACPI. > + @param[out] DispatchHandle Handle of dispatch function, for when > interfacing > + with the parent SMM driver, will be th= e address of > linked > + list link in the call back record. Th= is may not be > NULL. > + > + @retval EFI_SUCCESS The dispatch function has been success= fully > + registered and the SMI source has been= enabled. > + @retval EFI_DEVICE_ERROR The driver was unable to enable the SM= I > source. > + @retval EFI_OUT_OF_RESOURCES Insufficient resources are available > + @retval EFI_INVALID_PARAMETER Address requested is already in use. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +IoTrapRegister ( > + IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *This, > + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, > + IN OUT EFI_SMM_IO_TRAP_REGISTER_CONTEXT *RegisterContext, > + OUT EFI_HANDLE *DispatchHandle > + ); > + > +/** > + Unregister a child SMI source dispatch function with a parent SMM driv= er. > + > + @param[in] This Pointer to the > EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL instance. > + @param[in] DispatchHandle Handle of dispatch function to deregis= ter. > + > + @retval EFI_SUCCESS The dispatch function has been success= fully > + unregistered and the SMI source has be= en disabled > + if there are no other registered child= dispatch > + functions for this SMI source. > + @retval EFI_INVALID_PARAMETER Handle is invalid. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +IoTrapUnRegister ( > + IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *This, > + IN EFI_HANDLE DispatchHandle > + ); > + > +/** > + This I/O Trap SMI handler invokes the ACPI reference code to handle th= e SMI. > + It currently assumes it owns all of the IO trap SMI. > + > + @param[in] DispatchHandle Not used > + > +**/ > +VOID > +EFIAPI > +IoTrapCallback ( > + IN EFI_HANDLE DispatchHandle > + ); > + > +/** > + Pause IoTrap callback function. > + > + This function disables the SMI enable of IoTrap according to the > DispatchHandle, > + which is returned by IoTrap callback registration. It only supports th= e > DispatchHandle > + with MergeDisable TRUE and address not zero. > + > + @param[in] This Pointer to the > PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance. > + @param[in] DispatchHandle Handle of the child service to change > state. > + > + @retval EFI_SUCCESS This operation is complete. > + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. > + @retval EFI_ACCESS_DENIED The SMI status is alrady PAUSED. > +**/ > +EFI_STATUS > +EFIAPI > +IoTrapControlPause ( > + IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL * This, > + IN EFI_HANDLE DispatchHandle > + ); > + > +/** > + Resume IoTrap callback function. > + > + This function enables the SMI enable of IoTrap according to the > DispatchHandle, > + which is returned by IoTrap callback registration. It only supports th= e > DispatchHandle > + with MergeDisable TRUE and address not zero. > + > + @param[in] This Pointer to the > PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance. > + @param[in] DispatchHandle Handle of the child service to change > state. > + > + @retval EFI_SUCCESS This operation is complete. > + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. > + @retval EFI_ACCESS_DENIED The SMI status is alrady RESUMED. > +**/ > +EFI_STATUS > +EFIAPI > +IoTrapControlResume ( > + IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL * This, > + IN EFI_HANDLE DispatchHandle > + ); > + > +#endif > diff --git > a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h > new file mode 100644 > index 0000000000..1906e32b5a > --- /dev/null > +++ > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h > @@ -0,0 +1,1031 @@ > +/** @file > + Prototypes and defines for the PCH SMM Dispatcher. > + > + Copyright (c) 2019 Intel Corporation. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#ifndef _PCH_SMM_H_ > +#define _PCH_SMM_H_ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include "IoTrap.h" > + > +#define EFI_BAD_POINTER 0xAFAFAFAFAFAFAFAFULL > + > +extern BOOLEAN mReadyToLock; > + > +/// > +/// Define an enumeration for all the supported protocols > +/// > +#define PCH_SMM_PROTOCOL_TYPE_MAX 6 > + > +typedef enum { > + UsbType, > + SxType, > + SwType, > + GpiType, > + PowerButtonType, > + PeriodicTimerType, > + PchSmiDispatchType, > + PchSmmProtocolTypeMax > +} PCH_SMM_PROTOCOL_TYPE; > + > +/// > +/// Define all the supported types of PCH SMI > +/// > +typedef enum { > + PchTcoSmiMchType, > + PchTcoSmiTcoTimeoutType, > + PchTcoSmiOsTcoType, > + PchTcoSmiNmiType, > + PchTcoSmiIntruderDetectType, > + PchTcoSmiSpiBiosWpType, > + PchTcoSmiLpcBiosWpType, > + PchTcoSmiNewCenturyType, > + PchPcieSmiRpHotplugType, > + PchPcieSmiRpLinkActiveType, > + PchPcieSmiRpLinkEqType, > + PchAcpiSmiPmeType, > + PchAcpiSmiPmeB0Type, > + PchAcpiSmiRtcAlarmType, > + PchAcpiSmiTmrOverflowType, > + PchEspiSmiEspiSlaveType, > + PchSmiSerialIrqType, > + PchSmiMcSmiType, > + PchSmiSmBusType, > + PchSmiSpiAsyncType, > + PchIoTrapSmiType ///< internal SMI type > +} PCH_SMI_TYPES; > + > +/// > +/// Generic funciton pointer to cover all Pch SMI function pointer types > +/// > +typedef > +VOID > +(EFIAPI *PCH_SMI_CALLBACK_FUNCTIONS) ( > + IN EFI_HANDLE DispatchHandle, > + ... > + ); > + > + > +/// > +/// SPECIFYING A REGISTER > +/// We want a general way of referring to addresses. For this case, we'= ll only > +/// need addresses in the ACPI table (and the TCO entries within the ACP= I > table). > +/// However, it's interesting to consider what it would take to support = other > types > +/// of addresses. To address Will's concern, I think it prudent to > accommodate it > +/// early on in the design. > +/// > +/// Addresses we need to consider: > +/// > +/// Type: Required: > +/// I/O Yes > +/// ACPI (special case of I/O) Only if we want to > +/// TCO (special case of I/O) Only if we want to > +/// GPIO (special case of MMIO) Only if we want to > +/// Memory (or Memory Mapped I/O) Only if we want to > +/// PCIE Yes, for BiosWp > +/// > +typedef enum { > + /// > + /// IO_ADDR_TYPE, /// unimplemented > + /// > + ACPI_ADDR_TYPE, > + TCO_ADDR_TYPE, > + /// > + /// MEMORY_ADDR_TYPE, /// unimplemented > + /// > + GPIO_ADDR_TYPE, > + MEMORY_MAPPED_IO_ADDRESS_TYPE, > + PCIE_ADDR_TYPE, > + PCR_ADDR_TYPE, > + NUM_ADDR_TYPES, ///< count of items in this enum > + PCH_SMM_ADDR_TYPE_NULL =3D -1 ///< sentinel to indicate NULL o= r to > signal end of arrays > +} ADDR_TYPE; > + > +// > +// Assumption: 32-bits -- enum's evaluate to integer > +// Assumption: This code will only run on IA-32. Justification: IA-64 d= oesn't > have SMIs. > +// We don't have to worry about 64-bit addresses. > +// Typedef the size of addresses in case the numbers I'm using are wrong= or in > case > +// this changes. This is a good idea because PCI_ADDR will change, for > example, when > +// we add support for PciExpress. > +// > +typedef UINT16 IO_ADDR; > +typedef IO_ADDR ACPI_ADDR; ///< can omit > +typedef IO_ADDR TCO_ADDR; ///< can omit > +typedef UINTN MEM_ADDR; > +typedef MEM_ADDR *MEMORY_MAPPED_IO_ADDRESS; > +typedef MEM_ADDR *GPIO_ADDR; > +typedef union { > + UINT32 Raw; > + struct { > + UINT32 Reg: 16; > + UINT32 Fnc: 3; > + UINT32 Dev: 5; > + UINT32 Bus: 8; > + } Fields; > +} PCIE_ADDR; > + > +typedef union { > + UINT32 Raw; > + struct { > + UINT16 Offset; > + UINT8 Pid; > + UINT8 Base; > + } Fields; > +} PCR_ADDR; > + > +typedef struct { > + ADDR_TYPE Type; > + union { > + /// > + /// used to initialize during declaration/definition > + /// > + UINT32 raw; > + > + /// > + /// used to access useful data > + /// > + IO_ADDR io; > + ACPI_ADDR acpi; > + TCO_ADDR tco; > + GPIO_ADDR gpio; > + MEM_ADDR mem; > + MEMORY_MAPPED_IO_ADDRESS Mmio; > + PCIE_ADDR pcie; > + PCR_ADDR Pcr; > + > + } Data; > + > +} PCH_SMM_ADDRESS; > + > +/// > +/// SPECIFYING BITS WITHIN A REGISTER > +/// Here's a struct that helps us specify a source or enable bit. > +/// > +typedef struct { > + PCH_SMM_ADDRESS Reg; > + UINT8 SizeInBytes; ///< of the register > + UINT8 Bit; > +} PCH_SMM_BIT_DESC; > + > +// > +// Sometimes, we'll have bit descriptions that are unused. It'd be grea= t to > have a > +// way to easily identify them: > +// > +#define IS_BIT_DESC_NULL(BitDesc) ((BitDesc).Reg.Type =3D=3D > PCH_SMM_ADDR_TYPE_NULL) ///< "returns" true when BitDesc is NULL > +#define NULL_THIS_BIT_DESC(BitDesc) ((BitDesc).Reg.Type =3D > PCH_SMM_ADDR_TYPE_NULL) ///< will "return" an integer w/ value of 0 > +#define NULL_BIT_DESC_INITIALIZER \ > + { \ > + { \ > + PCH_SMM_ADDR_TYPE_NULL, \ > + { \ > + 0 \ > + } \ > + }, \ > + 0, 0 \ > + } > +// > +// I'd like a type to specify the callback's Sts & En bits because they'= ll > +// be commonly used together: > +// > +#define NUM_EN_BITS 2 > +#define NUM_STS_BITS 1 > + > +// > +// Flags > +// > +typedef UINT8 PCH_SMM_SOURCE_FLAGS; > + > +// > +// Flags required to describe the event source > +// > +#define PCH_SMM_NO_FLAGS 0 > +#define PCH_SMM_SCI_EN_DEPENDENT 1 > + > +typedef struct { > + PCH_SMM_SOURCE_FLAGS Flags; > + PCH_SMM_BIT_DESC En[NUM_EN_BITS]; ///< Describes the enable > bit(s) for the SMI event > + PCH_SMM_BIT_DESC Sts[NUM_STS_BITS]; ///< Describes the > secondary status bit for the SMI event. Might be the same as TopLevelSmi > + PCH_SMM_BIT_DESC PmcSmiSts; ///< Refereing to the top le= vel > status bit in PMC SMI_STS, i.e. R_PCH_SMI_STS > +} PCH_SMM_SOURCE_DESC; > + > +/// > +/// Used to initialize null source descriptor > +/// > +#define NULL_SOURCE_DESC_INITIALIZER \ > + { \ > + PCH_SMM_NO_FLAGS, \ > + { \ > + NULL_BIT_DESC_INITIALIZER, NULL_BIT_DESC_INITIALIZER \ > + }, \ > + { \ > + NULL_BIT_DESC_INITIALIZER \ > + }, \ > + NULL_BIT_DESC_INITIALIZER \ > + } > + > +/// > +/// CHILD CONTEXTS > +/// To keep consistent w/ the architecture, we'll need to provide the co= ntext > +/// to the child when we call its callback function. After talking with= Will, > +/// we agreed that we'll need functions to "dig" the context out of the > hardware > +/// in many cases (Sx, Trap, Gpi, etc), and we'll need a function to com= pare > those > +/// contexts to prevent unnecessary dispatches. I'd like a general type= for > these > +/// "GetContext" functions, so I'll need a union of all the protocol con= texts for > +/// our internal use: > +/// > +typedef union { > + // > + // (in no particular order) > + // > + EFI_SMM_SX_REGISTER_CONTEXT Sx; > + EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT PeriodicTimer; > + EFI_SMM_SW_REGISTER_CONTEXT Sw; > + EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT PowerButton; > + EFI_SMM_USB_REGISTER_CONTEXT Usb; > + EFI_SMM_GPI_REGISTER_CONTEXT Gpi; > +} PCH_SMM_CONTEXT; > + > +/// > +/// Misc data for PchDispatcher usage. > +/// For PeriodicTimer, since the ElapsedTime is removed from > EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT of EDKII, > +/// and PchDispatcher needs it for every record. Thus move it here to su= pport > ElapsedTime. > +/// > +typedef union { > + UINTN ElapsedTime; > +} PCH_SMM_MISC_DATA; > + > +// > +// Assumption: PeriodicTimer largest at 3x64-bits or 24 bytes > +// > +typedef struct _DATABASE_RECORD DATABASE_RECORD; > + > +/// > +/// Assumption: the GET_CONTEXT function will be as small and simple as > possible. > +/// Assumption: We don't need to pass in an enumeration for the protocol > because each > +/// GET_CONTEXT function is written for only one protocol. > +/// We also need a function to compare contexts to see if the child shou= ld be > dispatched > +/// In addition, we need a function to acquire CommBuffer and > CommBufferSize for > +/// dispatch callback function of EDKII native support. > +/// > +typedef > +VOID > +(EFIAPI *GET_CONTEXT) ( > + IN DATABASE_RECORD * Record, > + OUT PCH_SMM_CONTEXT * Context > + ); > + > +typedef > +BOOLEAN > +(EFIAPI *CMP_CONTEXT) ( > + IN PCH_SMM_CONTEXT * Context1, > + IN PCH_SMM_CONTEXT * Context2 > + ); > + > +typedef > +VOID > +(EFIAPI *GET_COMMBUFFER) ( > + IN DATABASE_RECORD * Record, > + OUT VOID **CommBuffer, > + OUT UINTN * CommBufferSize > + ); > + > +/// > +/// Finally, every protocol will require a "Get Context" and "Compare > Context" call, so > +/// we may as well wrap that up in a table, too. > +/// > +typedef struct { > + GET_CONTEXT GetContext; > + CMP_CONTEXT CmpContext; > + GET_COMMBUFFER GetCommBuffer; > +} CONTEXT_FUNCTIONS; > + > +extern CONTEXT_FUNCTIONS > ContextFunctions[PCH_SMM_PROTOCOL_TYPE_MAX]; > + > +/// > +/// MAPPING CONTEXT TO BIT DESCRIPTIONS > +/// I'd like to have a general approach to mapping contexts to bit descr= iptions. > +/// Sometimes, we'll find that we can use table lookups or constant > assignments; > +/// other times, we'll find that we'll need to use a function to perform= the > mapping. > +/// If we define a macro to mask that process, we'll never have to chang= e the > code. > +/// I don't know if this is desirable or not -- if it isn't, then we can= get rid > +/// of the macros and just use function calls or variable assignments. = Doesn't > matter > +/// to me. > +/// Mapping complex contexts requires a function > +/// > + > +/** > + Maps a USB context to a source description. > + > + @param[in] Context The context we need to map. Type must= be > USB. > + @param[out] SrcDesc The source description that correspond= s to > the given context. > + > +**/ > +VOID > +MapUsbToSrcDesc ( > + IN PCH_SMM_CONTEXT *Context, > + OUT PCH_SMM_SOURCE_DESC *SrcDesc > + ); > + > +/** > + Figure out which timer the child is requesting and > + send back the source description > + > + @param[in] DispatchContext The pointer to the Dispatch Context > instances > + @param[out] SrcDesc The pointer to the source description > + > +**/ > +VOID > +MapPeriodicTimerToSrcDesc ( > + IN PCH_SMM_CONTEXT *DispatchC= ontext, > + OUT PCH_SMM_SOURCE_DESC *SrcDesc > + ); > + > +// > +// Mapping simple contexts can be done by assignment or lookup table > +// > +extern CONST PCH_SMM_SOURCE_DESC mSxSourceDesc; > +extern CONST PCH_SMM_SOURCE_DESC mPowerButtonSourceDesc; > +extern CONST PCH_SMM_SOURCE_DESC mSrcDescNewCentury; > +extern CONST PCH_SMM_SOURCE_DESC mGpiSourceDescTemplate; > + > +/// > +/// For PCHx, APMC is UINT8 port, so the MAX SWI Value is 0xFF. > +/// > +#define MAXIMUM_SWI_VALUE 0xFF > +/// > +/// Open: Need to make sure this kind of type cast will actually work. > +/// May need an intermediate form w/ two VOID* arguments. I'll figure > +/// that out when I start compiling. > +/// > +typedef > +VOID > +(EFIAPI *PCH_SMM_CLEAR_SOURCE) ( > + CONST PCH_SMM_SOURCE_DESC * SrcDesc > + ); > + > +/// > +/// "DATABASE" RECORD > +/// Linked list data structures > +/// > +#define DATABASE_RECORD_SIGNATURE SIGNATURE_32 ('D', 'B', 'R', 'C') > + > +struct _DATABASE_RECORD { > + UINT32 Signature; > + LIST_ENTRY Link; > + BOOLEAN Processed; > + /// > + /// Status and Enable bit description > + /// > + PCH_SMM_SOURCE_DESC SrcDesc; > + > + /// > + /// Callback function > + /// > + EFI_SMM_HANDLER_ENTRY_POINT2 Callback; > + PCH_SMM_CONTEXT ChildContext; > + UINTN ContextSize; > + > + /// > + /// Special handling hooks -- init them to NULL if unused/unneeded > + /// > + PCH_SMM_CLEAR_SOURCE ClearSource; > + > + /// > + /// Functions required to make callback code general > + /// > + CONTEXT_FUNCTIONS ContextFunctions; > + > + /// > + /// The protocol that this record dispatches > + /// > + PCH_SMM_PROTOCOL_TYPE ProtocolType; > + > + /// > + /// Misc data for private usage > + /// > + PCH_SMM_MISC_DATA MiscData; > + > + /// > + /// PCH SMI callback function > + /// > + PCH_SMI_CALLBACK_FUNCTIONS PchSmiCallback; > + /// > + /// Indicate the PCH SMI types. > + /// > + PCH_SMI_TYPES PchSmiType; > +}; > + > +#define DATABASE_RECORD_FROM_LINK(_record) CR (_record, > DATABASE_RECORD, Link, DATABASE_RECORD_SIGNATURE) > +#define DATABASE_RECORD_FROM_CHILDCONTEXT(_record) CR (_record, > DATABASE_RECORD, ChildContext, DATABASE_RECORD_SIGNATURE) > + > +/// > +/// HOOKING INTO THE ARCHITECTURE > +/// > +typedef > +EFI_STATUS > +(EFIAPI *PCH_SMM_GENERIC_REGISTER) ( > + IN VOID **This, > + IN VOID *DispatchFunction, > + IN VOID *DispatchContext, > + OUT EFI_HANDLE *DispatchHandle > + ); > +typedef > +EFI_STATUS > +(EFIAPI *PCH_SMM_GENERIC_UNREGISTER) ( > + IN VOID **This, > + IN EFI_HANDLE DispatchHandle > + ); > + > +/// > +/// Define a memory "stamp" equivalent in size and function to most of t= he > protocols > +/// > +typedef struct { > + PCH_SMM_GENERIC_REGISTER Register; > + PCH_SMM_GENERIC_UNREGISTER Unregister; > + UINTN Extra1; > + UINTN Extra2; ///< may not need this one > +} PCH_SMM_GENERIC_PROTOCOL; > + > +/** > + Register a child SMI dispatch function with a parent SMM driver. > + > + @param[in] This Pointer to the > PCH_SMM_GENERIC_PROTOCOL instance. > + @param[in] DispatchFunction Pointer to dispatch function to be > invoked for this SMI source. > + @param[in] DispatchContext Pointer to the dispatch function's > context. > + @param[out] DispatchHandle Handle of dispatch function, for when > interfacing > + with the parent SMM driver, will be th= e address of > linked > + list link in the call back record. > + > + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create > database record > + @retval EFI_INVALID_PARAMETER The input parameter is invalid > + @retval EFI_SUCCESS The dispatch function has been success= fully > + registered and the SMI source has been= enabled. > +**/ > +EFI_STATUS > +EFIAPI > +PchPiSmmCoreRegister ( > + IN PCH_SMM_GENERIC_PROTOCOL *This, > + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction= , > + IN PCH_SMM_CONTEXT *DispatchContext= , > + OUT EFI_HANDLE *DispatchHandle > + ); > + > +/** > + Unregister a child SMI source dispatch function with a parent SMM driv= er > + > + @param[in] This Protocol instance pointer. > + @param[in] DispatchHandle Handle of dispatch function to > deregister. > + > + @retval EFI_SUCCESS The dispatch function has been > successfully > + unregistered and the SMI source = has been > disabled > + if there are no other registered= child dispatch > + functions for this SMI source. > + @retval EFI_INVALID_PARAMETER Handle is invalid. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchPiSmmCoreUnRegister ( > + IN PCH_SMM_GENERIC_PROTOCOL *This, > + IN EFI_HANDLE *DispatchHandle > + ); > + > +/** > + Unregister a child SMI source dispatch function with a parent SMM driv= er. > + > + @param[in] This Pointer to the > PCH_SMM_GENERIC_PROTOCOL instance. > + @param[in] DispatchHandle Handle of dispatch function to deregis= ter. > + > + @retval EFI_SUCCESS The dispatch function has been success= fully > + unregistered and the SMI source has be= en disabled > + if there are no other registered child= dispatch > + functions for this SMI source. > + @retval EFI_INVALID_PARAMETER Handle is invalid. > +**/ > +EFI_STATUS > +EFIAPI > +PchSmmCoreUnRegister ( > + IN PCH_SMM_GENERIC_PROTOCOL *This, > + IN EFI_HANDLE *DispatchHandle > + ); > + > +typedef union { > + PCH_SMM_GENERIC_PROTOCOL Generic; > + EFI_SMM_USB_DISPATCH2_PROTOCOL Usb; > + EFI_SMM_SX_DISPATCH2_PROTOCOL Sx; > + EFI_SMM_SW_DISPATCH2_PROTOCOL Sw; > + EFI_SMM_GPI_DISPATCH2_PROTOCOL Gpi; > + EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL PowerButton; > + EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL PeriodicTimer; > +} PCH_SMM_PROTOCOL; > + > +/// > +/// Define a structure to help us identify the generic protocol > +/// > +#define PROTOCOL_SIGNATURE SIGNATURE_32 ('P', 'R', 'O', 'T') > + > +typedef struct { > + UINTN Signature; > + > + PCH_SMM_PROTOCOL_TYPE Type; > + EFI_GUID *Guid; > + PCH_SMM_PROTOCOL Protocols; > +} PCH_SMM_QUALIFIED_PROTOCOL; > + > +#define QUALIFIED_PROTOCOL_FROM_GENERIC(_generic) \ > + CR ( \ > + _generic, \ > + PCH_SMM_QUALIFIED_PROTOCOL, \ > + Protocols, \ > + PROTOCOL_SIGNATURE \ > + ) > + > +/// > +/// Create private data for the protocols that we'll publish > +/// > +typedef struct { > + LIST_ENTRY CallbackDataBase; > + EFI_HANDLE SmiHandle; > + EFI_HANDLE InstallMultProtHandle; > + PCH_SMM_QUALIFIED_PROTOCOL > Protocols[PCH_SMM_PROTOCOL_TYPE_MAX]; > +} PRIVATE_DATA; > + > +extern PRIVATE_DATA mPrivateData; > +extern UINT16 mAcpiBaseAddr; > +extern UINT16 mTcoBaseAddr; > + > +/** > + The internal function used to create and insert a database record > + > + @param[in] InsertRecord Record to insert to database. > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > +**/ > +EFI_STATUS > +SmmCoreInsertRecord ( > + IN DATABASE_RECORD *NewRecord, > + OUT EFI_HANDLE *DispatchHandle > + ); > + > +/** > + Get the Sleep type > + > + @param[in] Record No use > + @param[out] Context The context that includes SLP_TYP bits= to be > filled > +**/ > +VOID > +EFIAPI > +SxGetContext ( > + IN DATABASE_RECORD *Record, > + OUT PCH_SMM_CONTEXT *Context > + ); > + > +/** > + Register a child SMI source dispatch function for the specified softwa= re SMI. > + > + This service registers a function (DispatchFunction) which will be cal= led > when the software > + SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On > return, > + DispatchHandle contains a unique handle which may be used later to > unregister the function > + using UnRegister(). > + > + @param[in] This Pointer to the > EFI_SMM_SW_DISPATCH2_PROTOCOL instance. > + @param[in] DispatchFunction Function to register for handler when > the specified software > + SMI is generated. > + @param[in, out] RegisterContext Pointer to the dispatch function's > context. > + The caller fills this context in befo= re calling > + the register function to indicate to = the register > + function which Software SMI input val= ue the > + dispatch function should be invoked f= or. > + @param[out] DispatchHandle Handle generated by the dispatcher to > track the > + function instance. > + > + @retval EFI_SUCCESS The dispatch function has been successf= ully > + registered and the SMI source has been = enabled. > + @retval EFI_DEVICE_ERROR The SW driver was unable to enable the > SMI source. > + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The SW SMI > input value > + is not within a valid range or is alrea= dy in use. > + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or > SMM) to manage this > + child. > + @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not > be assigned > + for this dispatch. > +**/ > +EFI_STATUS > +EFIAPI > +PchSwSmiRegister ( > + IN EFI_SMM_SW_DISPATCH2_PROTOCOL *This, > + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, > + IN EFI_SMM_SW_REGISTER_CONTEXT *DispatchContext, > + OUT EFI_HANDLE *DispatchHandle > + ); > + > +/** > + Unregister a child SMI source dispatch function for the specified soft= ware > SMI. > + > + This service removes the handler associated with DispatchHandle so tha= t it > will no longer be > + called in response to a software SMI. > + > + @param[in] This Pointer to the > EFI_SMM_SW_DISPATCH2_PROTOCOL instance. > + @param[in] DispatchHandle Handle of dispatch function to deregist= er. > + > + @retval EFI_SUCCESS The dispatch function has been successf= ully > unregistered. > + @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid. > +**/ > +EFI_STATUS > +EFIAPI > +PchSwSmiUnRegister ( > + IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This, > + IN EFI_HANDLE DispatchHandle > + ); > + > +/** > + Init required protocol for Pch Sw Dispatch protocol. > +**/ > +VOID > +PchSwDispatchInit ( > + VOID > + ); > + > +/** > + Check whether sleep type of two contexts match > + > + @param[in] Context1 Context 1 that includes sleep type 1 > + @param[in] Context2 Context 2 that includes sleep type 2 > + > + @retval FALSE Sleep types match > + @retval TRUE Sleep types don't match > +**/ > +BOOLEAN > +EFIAPI > +SxCmpContext ( > + IN PCH_SMM_CONTEXT *Context1, > + IN PCH_SMM_CONTEXT *Context2 > + ); > + > +/** > + Update the elapsed time from the Interval data of DATABASE_RECORD > + > + @param[in] Record The pointer to the DATABASE_RECORD. > + @param[out] HwContext The Context to be updated. > +**/ > +VOID > +EFIAPI > +PeriodicTimerGetContext ( > + IN DATABASE_RECORD *Record, > + OUT PCH_SMM_CONTEXT *Context > + ); > + > +/** > + Check whether Periodic Timer of two contexts match > + > + @param[in] Context1 Context 1 that includes Periodic Timer= 1 > + @param[in] Context2 Context 2 that includes Periodic Timer= 2 > + > + @retval FALSE Periodic Timer match > + @retval TRUE Periodic Timer don't match > +**/ > +BOOLEAN > +EFIAPI > +PeriodicTimerCmpContext ( > + IN PCH_SMM_CONTEXT *Context1, > + IN PCH_SMM_CONTEXT *Context2 > + ); > + > +/** > + Gather the CommBuffer information of SmmPeriodicTimerDispatch2. > + > + @param[in] Record No use > + @param[out] CommBuffer Point to the CommBuffer structure > + @param[out] CommBufferSize Point to the Size of CommBuffer > structure > +**/ > +VOID > +EFIAPI > +PeriodicTimerGetCommBuffer ( > + IN DATABASE_RECORD *Record, > + OUT VOID **CommBuffer, > + OUT UINTN *CommBufferSize > + ); > + > +/** > + Get the power button status. > + > + @param[in] Record The pointer to the DATABASE_RECORD. > + @param[out] Context Calling context from the hardware, wil= l be > updated with the current power button status. > +**/ > +VOID > +EFIAPI > +PowerButtonGetContext ( > + IN DATABASE_RECORD *Record, > + OUT PCH_SMM_CONTEXT *Context > + ); > + > +/** > + Check whether Power Button status of two contexts match > + > + @param[in] Context1 Context 1 that includes Power Button s= tatus > 1 > + @param[in] Context2 Context 2 that includes Power Button s= tatus > 2 > + > + @retval FALSE Power Button status match > + @retval TRUE Power Button status don't match > +**/ > +BOOLEAN > +EFIAPI > +PowerButtonCmpContext ( > + IN PCH_SMM_CONTEXT *Context1, > + IN PCH_SMM_CONTEXT *Context2 > + ); > + > +/** > + This function is responsible for calculating and enabling any timers t= hat are > required > + to dispatch messages to children. The SrcDesc argument isn't acutally = used. > + > + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC > instance. > +**/ > +VOID > +EFIAPI > +PchSmmPeriodicTimerClearSource ( > + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc > + ); > + > +/** > + This services returns the next SMI tick period that is supported by th= e > chipset. > + The order returned is from longest to shortest interval period. > + > + @param[in] This Pointer to the > EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL instance. > + @param[in, out] SmiTickInterval Pointer to pointer of the next shorter= SMI > interval period that is supported by the child. > + > + @retval EFI_SUCCESS The service returned successfully. > + @retval EFI_INVALID_PARAMETER The parameter SmiTickInterval is > invalid. > +**/ > +EFI_STATUS > +PchSmmPeriodicTimerDispatchGetNextShorterInterval ( > + IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This, > + IN OUT UINT64 **SmiTickInterva= l > + ); > + > +/** > + Install PCH SMM periodic timer control protocol > + > + @param[in] Handle handle for this driver > + > + @retval EFI_SUCCESS Driver initialization completed > successfully > +**/ > +EFI_STATUS > +EFIAPI > +InstallPchSmmPeriodicTimerControlProtocol ( > + IN EFI_HANDLE Handle > + ); > + > +/** > + When we get an SMI that indicates that we are transitioning to a sleep= state, > + we need to actually transition to that state. We do this by disabling= the > + "SMI on sleep enable" feature, which generates an SMI when the operati= ng > system > + tries to put the system to sleep, and then physically putting the syst= em to > sleep. > +**/ > +VOID > +PchSmmSxGoToSleep ( > + VOID > + ); > + > +/** > + Install protocols of PCH specifics SMI types, including > + PCH TCO SMI types, PCH PCIE SMI types, PCH ACPI SMI types, PCH MISC SM= I > types. > + > + @retval the result of protocol installat= ion > +**/ > +EFI_STATUS > +InstallPchSmiDispatchProtocols ( > + VOID > + ); > + > +/** > + The function to dispatch all callback function of PCH SMI types. > + > + @retval EFI_SUCCESS Function successfully completed > + @retval EFI_UNSUPPORTED no > +**/ > +EFI_STATUS > +PchSmiTypeCallbackDispatcher ( > + IN DATABASE_RECORD *Record > + ); > + > +/** > + The register function used to register SMI handler of IoTrap event. > + This is internal function and only used by Iotrap module. > + > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[in] IoTrapIndex Index number of IOTRAP register > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > +**/ > +EFI_STATUS > +PchInternalIoTrapSmiRegister ( > + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, > + IN UINTN IoTrapIndex, > + OUT EFI_HANDLE *DispatchHandle > + ); > + > +/** > + Unregister a child SMI source dispatch function with a parent SMM driv= er > + > + @param[in] DispatchHandle Handle of dispatch function to > deregister. > + > + @retval EFI_SUCCESS The dispatch function has been > successfully > + unregistered and the SMI source = has been > disabled > + if there are no other registered= child dispatch > + functions for this SMI source. > + @retval EFI_INVALID_PARAMETER Handle is invalid. > +**/ > +EFI_STATUS > +PchInternalIoTrapSmiUnRegister ( > + IN EFI_HANDLE DispatchHandle > + ); > + > +/** > + Register an eSPI SMI handler based on the type > + > + @param[in] DispatchFunction Callback in an event of eSPI SMI > + @param[in] PchSmiTypes The eSPI type published by > PchSmiDispatch > + @param[out] DispatchHandle The callback handle > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database > record > + @retval EFI_SUCCESS Registration is successful. > +**/ > +EFI_STATUS > +PchInternalEspiSmiRegister ( > + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, > + IN PCH_SMI_TYPES PchSmiTypes, > + OUT EFI_HANDLE *DispatchHandle > + ); > + > +/** > + Unregister an eSPI SMI handler > + > + @param[in] DispatchHandle Handle of dispatch function to > deregister. > + > + @retval EFI_SUCCESS The dispatch function has been > successfully > + unregistered and the SMI source = has been > disabled > + if there are no other registered= child dispatch > + functions for this SMI source. > + @retval EFI_INVALID_PARAMETER Handle is invalid. > +**/ > +EFI_STATUS > +PchInternalEspiSmiUnRegister ( > + IN EFI_HANDLE DispatchHandle > + ); > + > +/** > + The internal function used to create and insert a database record > + for SMI record of Pch Smi types. > + > + @param[in] SrcDesc The pointer to the SMI source > description > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[in] PchSmiType Specific SMI type of PCH SMI > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > +**/ > +EFI_STATUS > +PchSmiRecordInsert ( > + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc, > + IN PCH_SMI_CALLBACK_FUNCTIONS DispatchFunction, > + IN PCH_SMI_TYPES PchSmiType, > + OUT EFI_HANDLE *DispatchHandle > + ); > + > +extern CONST PCH_SMM_SOURCE_DESC mSrcDescSerialIrq; > +extern CONST PCH_SMM_SOURCE_DESC mSrcDescLpcBiosWp; > + > +/** > + Clear the TCO SMI status bit and block after the SMI handling is done > + > + @param[in] SrcDesc Pointer to the PCH SMI source > description table > + > +**/ > +VOID > +EFIAPI > +PchTcoSmiClearSourceAndBlock ( > + CONST PCH_SMM_SOURCE_DESC *SrcDesc > + ); > + > +/** > + Clear the TCO SMI status bit after the SMI handling is done > + > + @param[in] SrcDesc Pointer to the PCH SMI source > description table > + > +**/ > +VOID > +EFIAPI > +PchTcoSmiClearSource ( > + CONST PCH_SMM_SOURCE_DESC *SrcDesc > + ); > + > +/** > + Initialize Source descriptor structure > + > + @param[in] SrcDesc Pointer to the PCH SMI source > description table > +**/ > +VOID > +EFIAPI > +NullInitSourceDesc ( > + PCH_SMM_SOURCE_DESC *SrcDesc > + ); > + > +/** > + The register function used to register SMI handler of GPI SMI event. > + > + @param[in] This Pointer to the > EFI_SMM_GPI_DISPATCH2_PROTOCOL instance. > + @param[in] DispatchFunction Function to register for handler when t= he > specified GPI causes an SMI. > + @param[in] RegisterContext Pointer to the dispatch function's cont= ext. > + The caller fills this context in before= calling > + the register function to indicate to th= e register > + function the GPI(s) for which the dispa= tch function > + should be invoked. > + @param[out] DispatchHandle Handle generated by the dispatcher to > track the > + function instance. > + > + @retval EFI_SUCCESS The dispatch function has been successf= ully > + registered and the SMI source has been = enabled. > + @retval EFI_ACCESS_DENIED Register is not allowed > + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The GPI inp= ut > value > + is not within valid range. > + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or > SMM) to manage this child. > +**/ > +EFI_STATUS > +EFIAPI > +PchGpiSmiRegister ( > + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This, > + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, > + IN CONST EFI_SMM_GPI_REGISTER_CONTEXT *RegisterContext, > + OUT EFI_HANDLE *DispatchHandle > + ); > + > +/** > + Unregister a GPI SMI source dispatch function with a parent SMM driver > + > + @param[in] This Pointer to the > EFI_SMM_GPI_DISPATCH2_PROTOCOL instance. > + @param[in] DispatchHandle Handle of dispatch function to deregis= ter. > + > + @retval EFI_SUCCESS The dispatch function has been success= fully > + unregistered and the SMI source has be= en disabled > + if there are no other registered child= dispatch > + functions for this SMI source. > + @retval EFI_INVALID_PARAMETER Handle is invalid. > +**/ > +EFI_STATUS > +EFIAPI > +PchGpiSmiUnRegister ( > + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This, > + IN EFI_HANDLE DispatchHandle > + ); > + > +#endif > diff --git > a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEs > pi.h > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEs > pi.h > new file mode 100644 > index 0000000000..193eed6bac > --- /dev/null > +++ > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEs > pi.h > @@ -0,0 +1,342 @@ > +/** @file > + eSPI SMI Dispatch header > + > + Copyright (c) 2019 Intel Corporation. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#ifndef _PCH_SMM_ESPI_H_ > +#define _PCH_SMM_ESPI_H_ > + > +#include "PchSmmHelpers.h" > + > +#define ESPI_SMI_INSTANCE_SIGNATURE SIGNATURE_32 ('E', 'S', 'P', '= I') > +#define ESPI_SMI_RECORD_SIGNATURE SIGNATURE_32 ('E', 'S', 'R', '= C') > + > +#define ESPI_INSTANCE_FROM_THIS(_this) CR (_this, > ESPI_SMI_INSTANCE, EfiEspiSmiDispatchProtocol, > ESPI_SMI_INSTANCE_SIGNATURE) > +#define ESPI_RECORD_FROM_LINK(_link) CR (_link, ESPI_SMI_RECORD, > Link, ESPI_SMI_RECORD_SIGNATURE) > + > +typedef enum { > + EspiBiosWrProtect, ///< BIOS Write Protect > + EspiSerialIrq, ///< eSPI Master Asserted SMI > + EspiPmc, ///< eSPI PMC SMI > + EspiTopLevelTypeMax > +} ESPI_TOP_LEVEL_TYPE; > + > +typedef enum { > + BiosWrProtect, ///< BIOS Write Protect > + BiosWrReport, ///< Peripheral Channel BIOS Write Protect > + PcNonFatalErr, ///< Peripheral Channel Non Fatal Error > + PcFatalErr, ///< Peripheral Channel Fatal Error > + VwNonFatalErr, ///< Virtual Wire Non Fatal Error > + VwFatalErr, ///< Virtual Wire Fatal Error > + FlashNonFatalErr, ///< Flash Channel Non Fatal Error > + FlashFatalErr, ///< Flash Channel Fatal Error > + LnkType1Err, ///< Link Error > + EspiSlaveSmi, ///< Espi Slave SMI > + EspiSmiTypeMax > +} ESPI_SMI_TYPE; > + > +/// > +/// This is used to classify ESPI_SMI_TYPE to ESPI_TOP_LEVEL_TYPE. > +/// Used during dispatching and unregistering > +/// > +typedef struct { > + ESPI_SMI_TYPE Start; > + ESPI_SMI_TYPE End; > +} ESPI_SMI_TYPE_BARRIER; > + > +typedef struct _ESPI_SMI_INSTANCE { > + /// > + /// Signature associated with this instance > + /// > + UINT32 Signature; > + /// > + /// EFI_HANDLE acquired when installing PchEspiSmiDispatchProtocol > + /// > + EFI_HANDLE Handle; > + /// > + /// The protocol to register or unregister eSPI SMI callbacks > + /// > + PCH_ESPI_SMI_DISPATCH_PROTOCOL PchEspiSmiDispatchProtocol; > + /// > + /// The handle acquired when registering eSPI SMI callback to > PchSmiDispatch > + /// > + EFI_HANDLE PchSmiEspiHandle[EspiTopLevelTypeMax]; > + /// > + /// The linked list for record database. > + /// > + LIST_ENTRY CallbackDataBase[EspiSmiTypeMax]; > + /// > + /// This is an internal counter to track the number of eSPI master eve= nts > have been registered. > + /// When unregistering, we can disable the SMI if the counter is zero > + /// > + UINTN EspiSmiEventCounter[EspiSmiTypeMax]; > + /// > + /// Instance of barrier > + /// > + CONST ESPI_SMI_TYPE_BARRIER Barrier[EspiTopLevelTypeMax]; > +} ESPI_SMI_INSTANCE; > + > +typedef struct _ESPI_DESCRIPTOR { > + PCH_SMM_ADDRESS Address; > + UINT32 SourceIsActiveAndMask; > + UINT32 SourceIsActiveValue; > + UINT32 ClearStatusAndMask; > + UINT32 ClearStatusOrMask; > +} ESPI_DESCRIPTOR; > + > +/// > +/// A simple record to store the callbacks associated with an eSPI SMI s= ource > +/// > +typedef struct _ESPI_SMI_RECORD { > + UINT32 Signature; > + LIST_ENTRY Link; > + PCH_ESPI_SMI_DISPATCH_CALLBACK Callback; > +} ESPI_SMI_RECORD; > + > +/** > + Installs and initialize this protocol > + > + @param[in] ImageHandle Not used > + > + @retval EFI_SUCCESS Installation succeed > + @retval others Installation failed > +**/ > +EFI_STATUS > +EFIAPI > +InstallEspiSmi ( > + IN EFI_HANDLE ImageHandle > + ); > + > +/** > + eSPI SMI Dispatch Protocol instance to register a BIOS Write Protect e= vent > + > + @param[in] This Not used > + @param[in] DispatchFunction The callback to execute > + @param[out] DispatchHandle The handle for this callback registratio= n > + > + @retval EFI_SUCCESS Registration succeed > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval others Registration failed > +**/ > +EFI_STATUS > +EFIAPI > +BiosWrProtectRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ); > + > +/** > + eSPI SMI Dispatch Protocol instance to register a BIOS Write Report ev= ent > + > + @param[in] This Not used > + @param[in] DispatchFunction The callback to execute > + @param[out] DispatchHandle The handle for this callback registratio= n > + > + @retval EFI_SUCCESS Registration succeed > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval others Registration failed > +**/ > +EFI_STATUS > +EFIAPI > +BiosWrReportRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ); > + > +/** > + eSPI SMI Dispatch Protocol instance to register a Peripheral Channel N= on > Fatal Error event > + > + @param[in] This Not used > + @param[in] DispatchFunction The callback to execute > + @param[out] DispatchHandle The handle for this callback registratio= n > + > + @retval EFI_SUCCESS Registration succeed > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval others Registration failed > +**/ > +EFI_STATUS > +EFIAPI > +PcNonFatalErrRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ); > + > +/** > + eSPI SMI Dispatch Protocol instance to register a Peripheral Channel F= atal > Error event > + > + @param[in] This Not used > + @param[in] DispatchFunction The callback to execute > + @param[out] DispatchHandle The handle for this callback registratio= n > + > + @retval EFI_SUCCESS Registration succeed > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval others Registration failed > +**/ > +EFI_STATUS > +EFIAPI > +PcFatalErrRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ); > + > +/** > + eSPI SMI Dispatch Protocol instance to register a Virtual Wire Non Fat= al Error > event > + > + @param[in] This Not used > + @param[in] DispatchFunction The callback to execute > + @param[out] DispatchHandle The handle for this callback registratio= n > + > + @retval EFI_SUCCESS Registration succeed > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval others Registration failed > +**/ > +EFI_STATUS > +EFIAPI > +VwNonFatalErrRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ); > + > +/** > + eSPI SMI Dispatch Protocol instance to register a Virtual Wire Fatal E= rror > event > + > + @param[in] This Not used > + @param[in] DispatchFunction The callback to execute > + @param[out] DispatchHandle The handle for this callback registratio= n > + > + @retval EFI_SUCCESS Registration succeed > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval others Registration failed > +**/ > +EFI_STATUS > +EFIAPI > +VwFatalErrRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ); > + > +/** > + eSPI SMI Dispatch Protocol instance to register a Flash Channel Non Fa= tal > Error event > + > + @param[in] This Not used > + @param[in] DispatchFunction The callback to execute > + @param[out] DispatchHandle The handle for this callback registratio= n > + > + @retval EFI_SUCCESS Registration succeed > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval others Registration failed > +**/ > +EFI_STATUS > +EFIAPI > +FlashNonFatalErrRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ); > + > +/** > + eSPI SMI Dispatch Protocol instance to register a Flash Channel Fatal = Error > event > + > + @param[in] This Not used > + @param[in] DispatchFunction The callback to execute > + @param[out] DispatchHandle The handle for this callback registratio= n > + > + @retval EFI_SUCCESS Registration succeed > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval others Registration failed > +**/ > +EFI_STATUS > +EFIAPI > +FlashFatalErrRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ); > + > +/** > + eSPI SMI Dispatch Protocol instance to register a Link Error event > + > + @param[in] This Not used > + @param[in] DispatchFunction The callback to execute > + @param[out] DispatchHandle The handle for this callback registratio= n > + > + @retval EFI_SUCCESS Registration succeed > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval others Registration failed > +**/ > +EFI_STATUS > +EFIAPI > +LnkType1ErrRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ); > + > +/** > + eSPI SMI Dispatch Protocol instance to register a eSPI slave SMI > + NOTE: The register function is not available when the ESPI_SMI_LOCK bi= t is > set. > + This runtine will also lock donw ESPI_SMI_LOCK bit after registr= ation > and > + prevent this handler from unregistration. > + On platform that supports more than 1 device through another chip sele= ct > (SPT-H), > + the SMI handler itself needs to inspect both the eSPI devices' interru= pt > status registers > + (implementation specific for each Slave) in order to identify and serv= ice the > cause. > + After servicing it, it has to clear the Slaves' internal SMI# status r= egisters > + > + @param[in] This Not used > + @param[in] DispatchFunction The callback to execute > + @param[out] DispatchHandle The handle for this callback > registration > + > + @retval EFI_SUCCESS Registration succeed > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval EFI_ACCESS_DENIED The ESPI_SMI_LOCK is set and > register is blocked. > + @retval others Registration failed > +**/ > +EFI_STATUS > +EFIAPI > +EspiSlaveSmiRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ); > + > +/** > + eSPI SMI Dispatch Protocol instance to unregister a callback based on = handle > + > + @param[in] This Not used > + @param[in] DispatchHandle Handle acquired during registratio= n > + > + @retval EFI_SUCCESS Unregister successful > + @retval EFI_INVALID_PARAMETER DispatchHandle is null > + @retval EFI_INVALID_PARAMETER DispatchHandle's forward link has > bad pointer > + @retval EFI_INVALID_PARAMETER DispatchHandle does not exist in > database > + @retval EFI_ACCESS_DENIED Unregistration is done after end o= f > DXE > + @retval EFI_ACCESS_DENIED DispatchHandle is not allowed to > unregistered > +**/ > +EFI_STATUS > +EFIAPI > +EspiSmiUnRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN EFI_HANDLE DispatchHandle > + ); > + > +/** > + eSPI SMI handler for Fatal Error recovery flow > + > + @param[in] DispatchHandle Handle acquired during registratio= n > +**/ > +VOID > +EspiDefaultFatalErrorHandler ( > + VOID > + ); > + > + > +#endif > diff --git > a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHe > lpers.h > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHe > lpers.h > new file mode 100644 > index 0000000000..24e0975025 > --- /dev/null > +++ > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHe > lpers.h > @@ -0,0 +1,157 @@ > +/** @file > + Helper functions for PCH SMM > + > + Copyright (c) 2019 Intel Corporation. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#ifndef PCH_SMM_HELPERS_H > +#define PCH_SMM_HELPERS_H > + > +#include "PchSmm.h" > +#include "PchxSmmHelpers.h" > +// > +// > /////////////////////////////////////////////////////////////////////////= /////// > /////////////////////////////////// > +// SUPPORT / HELPER FUNCTIONS (PCH version-independent) > +// > + > +/** > + Publish SMI Dispatch protocols. > + > + > +**/ > +VOID > +PchSmmPublishDispatchProtocols ( > + VOID > + ); > + > +/** > + Compare 2 SMM source descriptors' enable settings. > + > + @param[in] Src1 Pointer to the PCH SMI source descript= ion > table 1 > + @param[in] Src2 Pointer to the PCH SMI source descript= ion > table 2 > + > + @retval TRUE The enable settings of the 2 SMM sourc= e > descriptors are identical. > + @retval FALSE The enable settings of the 2 SMM sourc= e > descriptors are not identical. > +**/ > +BOOLEAN > +CompareEnables ( > + CONST IN PCH_SMM_SOURCE_DESC *Src1, > + CONST IN PCH_SMM_SOURCE_DESC *Src2 > + ); > + > +/** > + Compare a bit descriptor to the enables of source descriptor. Includes= null > address type. > + > + @param[in] BitDesc Pointer to the PCH SMI bit descriptor > + @param[in] Src Pointer to the PCH SMI source descript= ion > table 2 > + > + @retval TRUE The bit desc is equal to any of the en= ables in > source descriptor > + @retval FALSE The bid desc is not equal to all of th= e enables in > source descriptor > +**/ > +BOOLEAN > +IsBitEqualToAnySourceEn ( > + CONST IN PCH_SMM_BIT_DESC *BitDesc, > + CONST IN PCH_SMM_SOURCE_DESC *Src > + ); > + > +/** > + Compare 2 SMM source descriptors' statuses. > + > + @param[in] Src1 Pointer to the PCH SMI source descript= ion > table 1 > + @param[in] Src2 Pointer to the PCH SMI source descript= ion > table 2 > + > + @retval TRUE The statuses of the 2 SMM source descr= iptors > are identical. > + @retval FALSE The statuses of the 2 SMM source descr= iptors > are not identical. > +**/ > +BOOLEAN > +CompareStatuses ( > + CONST IN PCH_SMM_SOURCE_DESC *Src1, > + CONST IN PCH_SMM_SOURCE_DESC *Src2 > + ); > + > +/** > + Compare 2 SMM source descriptors, based on Enable settings and Status > settings of them. > + > + @param[in] Src1 Pointer to the PCH SMI source descript= ion > table 1 > + @param[in] Src2 Pointer to the PCH SMI source descript= ion > table 2 > + > + @retval TRUE The 2 SMM source descriptors are ident= ical. > + @retval FALSE The 2 SMM source descriptors are not i= dentical. > +**/ > +BOOLEAN > +CompareSources ( > + CONST IN PCH_SMM_SOURCE_DESC *Src1, > + CONST IN PCH_SMM_SOURCE_DESC *Src2 > + ); > + > +/** > + Check if an SMM source is active. > + > + @param[in] Src Pointer to the PCH SMI source descript= ion > table > + @param[in] SciEn Indicate if SCI is enabled or not > + @param[in] SmiEnValue Value from R_PCH_SMI_EN > + @param[in] SmiStsValue Value from R_PCH_SMI_STS > + > + @retval TRUE It is active. > + @retval FALSE It is inactive. > +**/ > +BOOLEAN > +SourceIsActive ( > + CONST IN PCH_SMM_SOURCE_DESC *Src, > + CONST IN BOOLEAN SciEn, > + CONST IN UINT32 SmiEnValue, > + CONST IN UINT32 SmiStsValue > + ); > + > +/** > + Enable the SMI source event by set the SMI enable bit, this function w= ould > also clear SMI > + status bit to make initial state is correct > + > + @param[in] SrcDesc Pointer to the PCH SMI source descript= ion > table > + > +**/ > +VOID > +PchSmmEnableSource ( > + CONST PCH_SMM_SOURCE_DESC *SrcDesc > + ); > + > +/** > + Disable the SMI source event by clear the SMI enable bit > + > + @param[in] SrcDesc Pointer to the PCH SMI source descript= ion > table > + > +**/ > +VOID > +PchSmmDisableSource ( > + CONST PCH_SMM_SOURCE_DESC *SrcDesc > + ); > + > +/** > + Clear the SMI status bit by set the source bit of SMI status register > + > + @param[in] SrcDesc Pointer to the PCH SMI source descript= ion > table > + > +**/ > +VOID > +PchSmmClearSource ( > + CONST PCH_SMM_SOURCE_DESC *SrcDesc > + ); > + > +/** > + Sets the source to a 1 and then waits for it to clear. > + Be very careful when calling this function -- it will not > + ASSERT. An acceptable case to call the function is when > + waiting for the NEWCENTURY_STS bit to clear (which takes > + 3 RTCCLKs). > + > + @param[in] SrcDesc Pointer to the PCH SMI source descript= ion > table > + > +**/ > +VOID > +PchSmmClearSourceAndBlock ( > + CONST PCH_SMM_SOURCE_DESC *SrcDesc > + ); > + > +#endif > diff --git > a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmH > elpers.h > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmH > elpers.h > new file mode 100644 > index 0000000000..ba7ad42c9d > --- /dev/null > +++ > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmH > elpers.h > @@ -0,0 +1,105 @@ > +/** @file > + This driver is responsible for the registration of child drivers > + and the abstraction of the PCH SMI sources. > + > + Copyright (c) 2019 Intel Corporation. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#ifndef _PCHX_SMM_HELPERS_H_ > +#define _PCHX_SMM_HELPERS_H_ > + > +#include "PchSmm.h" > + > +/** > + Initialize bits that aren't necessarily related to an SMI source. > + > + > + @retval EFI_SUCCESS SMI source initialization completed. > + @retval Asserts Global Smi Bit is not enabled successf= ully. > +**/ > +EFI_STATUS > +PchSmmInitHardware ( > + VOID > + ); > + > +/** > + Enables the PCH to generate SMIs. Note that no SMIs will be generated > + if no SMI sources are enabled. Conversely, no enabled SMI source will > + generate SMIs if SMIs are not globally enabled. This is the main > + switchbox for SMI generation. > + > + > + @retval EFI_SUCCESS Enable Global Smi Bit completed > +**/ > +EFI_STATUS > +PchSmmEnableGlobalSmiBit ( > + VOID > + ); > + > +/** > + Clears the SMI after all SMI source have been processed. > + Note that this function will not work correctly (as it is > + written) unless all SMI sources have been processed. > + A revision of this function could manually clear all SMI > + status bits to guarantee success. > +**/ > +VOID > +PchSmmClearSmi ( > + VOID > + ); > + > +/** > + Set the SMI EOS bit after all SMI source have been processed. > + > + > + @retval FALSE EOS was not set to a 1; this is an err= or > + @retval TRUE EOS was correctly set to a 1 > +**/ > +BOOLEAN > +PchSmmSetAndCheckEos ( > + VOID > + ); > + > +/** > + Determine whether an ACPI OS is present (via the SCI_EN bit) > + > + > + @retval TRUE ACPI OS is present > + @retval FALSE ACPI OS is not present > +**/ > +BOOLEAN > +PchSmmGetSciEn ( > + VOID > + ); > + > +/** > + Read a specifying bit with the register > + > + @param[in] BitDesc The struct that includes register addr= ess, size > in byte and bit number > + > + @retval TRUE The bit is enabled > + @retval FALSE The bit is disabled > +**/ > +BOOLEAN > +ReadBitDesc ( > + CONST PCH_SMM_BIT_DESC *BitDesc > + ); > + > +/** > + Write a specifying bit with the register > + > + @param[in] BitDesc The struct that includes register addr= ess, size > in byte and bit number > + @param[in] ValueToWrite The value to be wrote > + @param[in] WriteClear If the rest bits of the register is wr= ite clear > + > +**/ > +VOID > +WriteBitDesc ( > + CONST PCH_SMM_BIT_DESC *BitDesc, > + CONST BOOLEAN ValueToWrite, > + CONST BOOLEAN WriteClear > + ); > + > +#endif > diff --git > a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.c > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.c > new file mode 100644 > index 0000000000..ddab2fc378 > --- /dev/null > +++ > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.c > @@ -0,0 +1,1264 @@ > +/** @file > + Main implementation source file for the Io Trap SMM driver > + > + Copyright (c) 2019 Intel Corporation. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#include "PchSmmHelpers.h" > +#include > +#include > +#include > +#include > +#include > + > +#define GENERIC_IOTRAP_SIZE 0x100 > + > +// > +// Module global variables > +// > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_HANDLE > mDriverImageHandle; > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_HANDLE > mIoTrapHandle; > + > +GLOBAL_REMOVE_IF_UNREFERENCED IO_TRAP_INSTANCE > mIoTrapData; > +GLOBAL_REMOVE_IF_UNREFERENCED IO_TRAP_RECORD > *mIoTrapRecord; > +GLOBAL_REMOVE_IF_UNREFERENCED PCH_NVS_AREA > *mPchNvsArea; > + > + > +static CONST UINT16 mLengthTable[10] =3D { 1, 2, 3, 4, 8, 16= , 32, 64, 128, > 256 }; > + > +/** > + Helper function that encapsulates IoTrap register access. > + IO trap related register updates must be made in 2 registers, IOTRAP a= nd > DMI source decode. > + > + @param[in] TrapHandlerNum trap number (0-3) > + @param[in] Value value to be written in both registers > + @param[in] SaveToBootscript if true, this register write will be save= d to > bootscript > + > +**/ > +VOID > +SetIoTrapLowDword ( > + IN UINT8 TrapHandlerNum, > + IN UINT32 Value, > + IN BOOLEAN SaveToBootscript > + ) > +{ > + UINT32 BitMask; > + UINT32 BitValue; > + // > + // To provide sequentially consistent programming model for IO trap > + // all pending IO cycles must be flushed before enabling and before > disabling a trap. > + // Without this the trap may trigger due to IO cycle issued before the= trap is > enabled or a cycle issued before the trap is disabled might be missed. > + // a. Issues a MemRd to PSTH IO Trap Enable bit -> This serves to flus= h all > previous IO cycles. > + // b. Then only issues a MemWr to PSTH IO Trap Enable =3D=3D Value > + // c. Issues another MemRd to PSTH IO Trap Enable bit -> This serves t= o push > the MemWr to PSTH and confirmed that IO Trap is in fact enabled > + // > + PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8); > + PchPcrWrite32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8, > Value); > + PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8); > + > + PchPcrWrite32 (PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8, > Value); > + // > + // Read back DMI IOTRAP register to enforce ordering so DMI write is > completed before any IO reads > + // from other threads which may occur after this point (after SMI exit= ). > + // > + PchPcrRead32 (PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8); > + if (SaveToBootscript) { > + // > + // Ignore the value check of PCH_PCR_BOOT_SCRIPT_READ > + // > + BitMask =3D 0; > + BitValue =3D 0; > + > + PCH_PCR_BOOT_SCRIPT_READ (S3BootScriptWidthUint32, PID_PSTH, > R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8, &BitMask, &BitValue); > + PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_PSTH, > R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8, 1, &Value); > + PCH_PCR_BOOT_SCRIPT_READ (S3BootScriptWidthUint32, PID_PSTH, > R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8, &BitMask, &BitValue); > + PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_DMI, > R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8, 1, &Value); > + } > +} > + > +/** > + Helper function that encapsulates IoTrap register access. > + IO trap related register updates must be made in 2 registers, IOTRAP a= nd > DMI source decode. > + > + @param[in] TrapHandlerNum trap number (0-3) > + @param[in] Value value to be written in both registers > + @param[in] SaveToBootscript if true, this register write will be save= d to > bootscript > + > +**/ > +VOID > +SetIoTrapHighDword ( > + IN UINT8 TrapHandlerNum, > + IN UINT32 Value, > + IN BOOLEAN SaveToBootscript > + ) > +{ > + PchPcrWrite32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8 + 4, > Value); > + PchPcrWrite32 (PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8 + 4, > Value); > + if (SaveToBootscript) { > + PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_PSTH, > R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8 + 4, 1, &Value); > + PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_DMI, > R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8 + 4, 1, &Value); > + } > +} > + > +/** > + Clear pending IOTRAP status. > + If IOTRAP status is pending and IOTRAP is disabled, then BIOS will not= find a > match SMI source > + and will not dispatch any SMI handler for it. The pending status will = lead to > SMI storm. > + This prevents that IOTRAP gets triggered by pending IO cycles even aft= er it's > disabled. > + > + @param[in] TrapHandlerNum trap number (0-3) > + > +**/ > +VOID > +ClearPendingIoTrapStatus ( > + IN UINT8 TrapHandlerNum > + ) > +{ > + PchPcrWrite32 (PID_PSTH, R_PSTH_PCR_TRPST, (UINT32)(1 << > TrapHandlerNum)); > +} > + > +/** > + IO resources allocated to IO traps need to be reported to OS so that t= hey > don't get reused. > + This function makes IO trap allocation data available to ACPI > + > + @param[in] TrapHandlerNum trap number (0-3) > + @param[in] BaseAddress address of allocated IO resource > + @param[in] Track TRUE =3D resource allocated, FALSE =3D reso= urce freed > + > +**/ > +VOID > +UpdateIoTrapAcpiResources ( > + IN UINT8 TrapHandlerNum, > + IN EFI_PHYSICAL_ADDRESS BaseAddress, > + IN BOOLEAN Track > + ) > +{ > + > + if (Track =3D=3D TRUE) { > + mPchNvsArea->IoTrapAddress[TrapHandlerNum] =3D (UINT16) > BaseAddress; > + mPchNvsArea->IoTrapStatus[TrapHandlerNum] =3D 1; > + } else { > + mPchNvsArea->IoTrapStatus[TrapHandlerNum] =3D 0; > + } > +} > + > +/** > + Get address from IOTRAP low dword. > + > + @param[in] IoTrapRegLowDword IOTRAP register low dword > + > + @retval Address of IOTRAP setting. > +**/ > +STATIC > +UINT16 > +AddressFromLowDword ( > + UINT32 IoTrapRegLowDword > + ) > +{ > + return (UINT16) (IoTrapRegLowDword & B_PSTH_PCR_TRPREG_AD); > +} > + > +/** > + Get length from IOTRAP low dword. > + > + @param[in] IoTrapRegLowDword IOTRAP register low dword > + > + @retval Length of IOTRAP setting. > +**/ > +STATIC > +UINT16 > +LengthFromLowDword ( > + UINT32 IoTrapRegLowDword > + ) > +{ > + return (UINT16) (((IoTrapRegLowDword >> 16) & 0xFC) + 4); > +} > + > +/** > + Get ByteEnable from IOTRAP high dword. > + > + @param[in] IoTrapRegHighDword IOTRAP register high dword > + > + @retval ByteEnable of IOTRAP setting. > +**/ > +STATIC > +UINT8 > +ByteEnableFromHighDword ( > + UINT32 IoTrapRegHighDword > + ) > +{ > + return (UINT8) (IoTrapRegHighDword & 0x0F); > +} > + > +/** > + Get ByteEnableMask from IOTRAP high dword. > + > + @param[in] IoTrapRegHighDword IOTRAP register high dword > + > + @retval ByteEnableMask of IOTRAP setting. > +**/ > +STATIC > +UINT8 > +ByteEnableMaskFromHighDword ( > + UINT32 IoTrapRegHighDword > + ) > +{ > + return (UINT8) ((IoTrapRegHighDword & 0xF0) >> 4); > +} > + > +/** > + Check the IoTrap register matches the IOTRAP EX content. > + > + @param[in] IoTrapRecord IOTRAP registration record structure > + @param[in] IoTrapRegLowDword IOTRAP register low dword > + @param[in] IoTrapRegHighDword IOTRAP register high dword > + > + @retval TRUE Content matched > + FALSE Content mismatched > +**/ > +STATIC > +BOOLEAN > +IsIoTrapExContentMatched ( > + IO_TRAP_RECORD *IoTrapRecord, > + UINT32 IoTrapRegLowDword, > + UINT32 IoTrapRegHighDword > + ) > +{ > + if ((IoTrapRecord->Context.Address =3D=3D AddressFromLowDword > (IoTrapRegLowDword)) && > + (IoTrapRecord->Context.Length =3D=3D LengthFromLowDword > (IoTrapRegLowDword)) && > + (IoTrapRecord->Context.ByteEnable =3D=3D ByteEnableFromHighDword > (IoTrapRegHighDword)) && > + (IoTrapRecord->Context.ByteEnableMask =3D=3D > ByteEnableMaskFromHighDword (IoTrapRegHighDword))) > + { > + return TRUE; > + } > + return FALSE; > +} > + > + > +/** > + The helper function for IoTrap callback dispacther > + > + @param[in] TrapHandlerNum trap number (0-3) > +**/ > +VOID > +IoTrapDispatcherHelper ( > + UINTN TrapHandlerNum > + ) > +{ > + IO_TRAP_RECORD *RecordInDb; > + LIST_ENTRY *LinkInDb; > + EFI_SMM_IO_TRAP_REGISTER_CONTEXT > CurrentIoTrapRegisterData; > + EFI_SMM_IO_TRAP_CONTEXT CurrentIoTrapContextData; > + UINT16 BaseAddress; > + UINT16 StartAddress; > + UINT16 EndAddress; > + UINT32 Data32; > + UINT8 ActiveHighByteEnable; > + BOOLEAN ReadCycle; > + UINT32 WriteData; > + > + if (!IsListEmpty > (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase))) { > + Data32 =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPC); > + WriteData =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPD); > + > + BaseAddress =3D (UINT16) (Data32 & B_PSTH_PCR_TRPC_IOA); > + ActiveHighByteEnable =3D (UINT8)((Data32 & B_PSTH_PCR_TRPC_AHBE) >> > 16); > + ReadCycle =3D (BOOLEAN) ((Data32 & B_PSTH_PCR_TRPC_RW) = =3D=3D > B_PSTH_PCR_TRPC_RW); > + // > + // StartAddress and EndAddress will be equal if it's byte access > + // > + EndAddress =3D (UINT16) (HighBitSet32 ((UINT32) > (ActiveHighByteEnable))) + BaseAddress; > + StartAddress =3D (UINT16) (LowBitSet32 ((UINT32) (ActiveHighByteEna= ble))) > + BaseAddress; > + > + CurrentIoTrapRegisterData.Type =3D > (EFI_SMM_IO_TRAP_DISPATCH_TYPE)ReadCycle; > + CurrentIoTrapContextData.WriteData =3D WriteData; > + > + LinkInDb =3D GetFirstNode > (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase)); > + > + while (!IsNull > (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase), LinkInDb)) { > + RecordInDb =3D IO_TRAP_RECORD_FROM_LINK (LinkInDb); > + > + // > + // If MergeDisable is TRUE, no need to check the address range, di= spatch > the callback function directly. > + // > + if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable) { > + if (RecordInDb->IoTrapCallback !=3D NULL) { > + RecordInDb->IoTrapCallback (&RecordInDb->Link, > &CurrentIoTrapContextData, NULL, NULL); > + } > + if (RecordInDb->IoTrapExCallback !=3D NULL) { > + RecordInDb->IoTrapExCallback (BaseAddress, > ActiveHighByteEnable, !ReadCycle, WriteData); > + } > + // > + // Expect only one callback available. So break immediately. > + // > + break; > + // > + // If MergeDisable is FALSE, check the address range and trap type= . > + // > + } else { > + if ((RecordInDb->Context.Address <=3D StartAddress) && > + (RecordInDb->Context.Address + RecordInDb->Context.Length > > EndAddress)) { > + if ((RecordInDb->Context.Type =3D=3D IoTrapExTypeReadWrite) || > (RecordInDb->Context.Type =3D=3D (IO_TRAP_EX_DISPATCH_TYPE) > CurrentIoTrapRegisterData.Type)) { > + // > + // Pass the IO trap context information > + // > + RecordInDb->IoTrapCallback (&RecordInDb->Link, > &CurrentIoTrapContextData, NULL, NULL); > + } > + // > + // Break if the address is match > + // > + break; > + } else { > + LinkInDb =3D GetNextNode > (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase), > &RecordInDb->Link); > + if (IsNull (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBa= se), > LinkInDb)) { > + // > + // An IO access was trapped that does not have a handler reg= istered. > + // This indicates an error condition. > + // > + ASSERT (FALSE); > + } > + } > + } // end of if else block > + } // end of while loop > + } // end of if else block > +} > + > +/** > + IoTrap dispatcher for IoTrap register 0. > + > + @param[in] DispatchHandle Handle of dispatch function > +**/ > +VOID > +EFIAPI > +IoTrapDispatcher0 ( > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + IoTrapDispatcherHelper (0); > +} > + > +/** > + IoTrap dispatcher for IoTrap register 1. > + > + @param[in] DispatchHandle Handle of dispatch function > +**/ > +VOID > +EFIAPI > +IoTrapDispatcher1 ( > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + IoTrapDispatcherHelper (1); > +} > + > +/** > + IoTrap dispatcher for IoTrap register 2. > + > + @param[in] DispatchHandle Handle of dispatch function > +**/ > +VOID > +EFIAPI > +IoTrapDispatcher2 ( > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + IoTrapDispatcherHelper (2); > +} > + > +/** > + IoTrap dispatcher for IoTrap register 3. > + > + @param[in] DispatchHandle Handle of dispatch function > +**/ > +VOID > +EFIAPI > +IoTrapDispatcher3 ( > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + IoTrapDispatcherHelper (3); > +} > + > +/** > + IoTrap registratrion helper fucntion. > + > + @param[in] DispatchHandle Handle of dispatch function > + @param[in] IoTrapDispatchFunction Dispatch function of > IoTrapDispatch2Protocol. > + This could be NULL if it's not f= rom > IoTrapDispatch2Protocol. > + @param[in] IoTrapExDispatchFunction Dispatch function of > IoTrapExDispatchProtocol. > + This could be NULL if it's not f= rom > IoTrapExDispatchProtocol. > + @param[in out] Address The pointer of IO Address. > + If the input Addres is 0, it wil= l return the address > assigned > + by registration to this caller. > + @param[in] Length Length of IO address range. > + @param[in] Type Read/Write type of IO trap. > + @param[in] ByteEnable Bitmap to enable trap for each b= yte of > every dword alignment address. > + @param[in] ByteEnableMask ByteEnableMask bitwise to ignore > the ByteEnable setting. > + > + @retval EFI_INVALID_PARAMETER If Type is invalid, > + If Length is invalid, > + If Address is invalid, > + EFI_ACCESS_DENIED If the SmmReadyToLock event has = been > triggered, > + EFI_OUT_OF_RESOURCES If run out of IoTrap register re= source, > + If run out of SMM memory pool, > + EFI_SUCCESS IoTrap register successfully. > +**/ > +EFI_STATUS > +IoTrapRegisterHelper ( > + OUT EFI_HANDLE *DispatchHandle, > + IN EFI_SMM_HANDLER_ENTRY_POINT2 > IoTrapDispatchFunction, > + IN IO_TRAP_EX_DISPATCH_CALLBACK > IoTrapExDispatchFunction, > + IN OUT UINT16 *Address, > + IN UINT16 Length, > + IN IO_TRAP_EX_DISPATCH_TYPE Type, > + IN UINT8 ByteEnable, > + IN UINT8 ByteEnableMask > + ) > +{ > + EFI_STATUS Status; > + EFI_PHYSICAL_ADDRESS BaseAddress; > + UINT32 UsedLength; > + UINT8 TrapHandlerNum; > + UINT32 IoTrapRegLowDword; > + UINT32 IoTrapRegHighDword; > + BOOLEAN TempMergeDisable; > + > + DEBUG ((DEBUG_INFO, "IoTrapRegisterHelper\n")); > + DEBUG ((DEBUG_INFO, "Address:%x \n", *Address)); > + DEBUG ((DEBUG_INFO, "Length:%x \n", Length)); > + DEBUG ((DEBUG_INFO, "Type:%x \n", Type)); > + DEBUG ((DEBUG_INFO, "ByteEnable:%x \n", ByteEnable)); > + DEBUG ((DEBUG_INFO, "ByteEnableMask:%x \n", ByteEnableMask)); > + > + // > + // Return error if the type is invalid > + // > + if (Type >=3D IoTrapExTypeMaximum) { > + DEBUG ((DEBUG_ERROR, "The Dispatch Type %0X is invalid! \n", Type)); > + return EFI_INVALID_PARAMETER; > + } > + // > + // Return error if the Length is invalid > + // > + if (Length < 1 || Length > GENERIC_IOTRAP_SIZE) { > + DEBUG ((DEBUG_ERROR, "The Dispatch Length %0X is invalid! \n", > Length)); > + return EFI_INVALID_PARAMETER; > + } > + // > + // Return error if the address is invalid > + // PCH supports non-aligned address but (Address % 4 + Length) must no= t be > more than 4 > + // > + if (((Length & (Length - 1)) !=3D 0) && (Length !=3D 3)) { > + DEBUG ((DEBUG_ERROR, "The Dispatch Length is not power of 2 \n")); > + return EFI_INVALID_PARAMETER; > + } > + > + if (((Length >=3D 4) && (*Address & 0x3)) || > + ((Length < 4) && (((*Address & 0x3) + Length) > 4))) { > + DEBUG ((DEBUG_ERROR, "PCH does not support Dispatch Address %0X > and Length %0X combination \n", *Address, Length)); > + return EFI_INVALID_PARAMETER; > + } > + > + if ((Length >=3D 4) && ((*Address & (Length - 1)) !=3D 0)) { > + DEBUG ((DEBUG_ERROR, "Dispatch Address %0X is not aligned to the > Length %0X \n", *Address, Length)); > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + if (*Address) { > + TempMergeDisable =3D TRUE; > + }else { > + TempMergeDisable =3D FALSE; > + } > + // > + // Loop through the first IO Trap handler, looking for the suitable ha= ndler > + // > + for (TrapHandlerNum =3D 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; > TrapHandlerNum++) { > + // > + // Get information from Io Trap handler register > + // > + IoTrapRegLowDword =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + > TrapHandlerNum * 8); > + > + // > + // Check if the IO Trap handler is not used > + // > + if (AddressFromLowDword (IoTrapRegLowDword) =3D=3D 0) { > + // > + // Search available IO address and allocate it if the IO address = is 0 > + // > + BaseAddress =3D *Address; > + if (BaseAddress =3D=3D 0) { > + // > + // Allocate 256 byte range from GCD for common pool usage > + // > + if ((PcdGet8 (PcdEfiGcdAllocateType) =3D=3D > EfiGcdAllocateMaxAddressSearchBottomUp) || (PcdGet8 > (PcdEfiGcdAllocateType) =3D=3D EfiGcdAllocateMaxAddressSearchTopDown)) { > + BaseAddress =3D 0xFFFF; > + } > + Status =3D gDS->AllocateIoSpace ( > + PcdGet8 (PcdEfiGcdAllocateType), > + EfiGcdIoTypeIo, > + 8, > + GENERIC_IOTRAP_SIZE, > + &BaseAddress, > + mDriverImageHandle, > + NULL > + ); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "Can't find any available IO address! \n"= )); > + return EFI_OUT_OF_RESOURCES; > + } > + > + *Address =3D (UINT16) BaseAddress; > + UsedLength =3D GENERIC_IOTRAP_SIZE; > + mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength =3D Length; > + mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource =3D > TRUE; > + UpdateIoTrapAcpiResources (TrapHandlerNum, BaseAddress, TRUE); > + } else { > + BaseAddress &=3D B_PSTH_PCR_TRPREG_AD; > + UsedLength =3D Length; > + } > + > + Status =3D PchInternalIoTrapSmiRegister ( > + mIoTrapData.Entry[TrapHandlerNum].CallbackDispatcher, > + TrapHandlerNum, > + &mIoTrapHandle > + ); > + > + ASSERT_EFI_ERROR (Status); > + mIoTrapData.Entry[TrapHandlerNum].IoTrapHandle =3D mIoTrapHandle; > + > + // > + // Fill in the Length, address and Enable the IO Trap SMI > + // > + IoTrapRegLowDword =3D (UINT32) (((UsedLength - 1) & ~(BIT1 + BIT0)= ) << 16) > | > + (UINT16) BaseAddress | > + B_PSTH_PCR_TRPREG_TSE; > + > + if (UsedLength < 4) { > + // > + // The 4 bits is the Byte Enable Mask bits to indicate which byt= e that are > trapped. > + // The input ByteEnable and ByteEnableMask are ignored in this c= ase. > + // > + IoTrapRegHighDword =3D (((1 << UsedLength) - 1) << ((*Address &= 0x3) + > (N_PSTH_PCR_TRPREG_BEM - 32))) | > + (UINT32) (Type << N_PSTH_PCR_TRPREG_RWIO); > + } else { > + // > + // Fill in the ByteEnable, ByteEnableMask, and Type of Io Trap r= egister > + // > + IoTrapRegHighDword =3D ((ByteEnableMask & 0xF) << > (N_PSTH_PCR_TRPREG_BEM - 32)) | > + ((ByteEnable & 0xF) << (N_PSTH_PCR_TRPREG_BE - 32)) | > + (UINT32) (Type << N_PSTH_PCR_TRPREG_RWIO); > + } > + SetIoTrapHighDword (TrapHandlerNum, IoTrapRegHighDword, TRUE); > + SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, TRUE); > + // > + // Set MergeDisable flag of the registered IoTrap > + // > + mIoTrapData.Entry[TrapHandlerNum].MergeDisable =3D > TempMergeDisable; > + } else { > + // > + // Check next handler if MergeDisable is TRUE or the registered Io= Trap if > MergeDisable is TRUE > + // If the Io Trap register is used by IoTrapEx protocol, then the > MergeDisable will be FALSE. > + // > + if ((TempMergeDisable =3D=3D TRUE) || > (mIoTrapData.Entry[TrapHandlerNum].MergeDisable =3D=3D TRUE)) { > + continue; > + } > + // > + // The IO Trap handler is used, calculate the Length > + // > + UsedLength =3D LengthFromLowDword (IoTrapRegLowDword); > + BaseAddress =3D AddressFromLowDword (IoTrapRegLowDword); > + // > + // Assign an addfress from common pool if the caller's address is= 0 > + // > + if (*Address =3D=3D 0) { > + // > + // Check next handler if it's fully used > + // > + if (mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength >=3D > GENERIC_IOTRAP_SIZE) { > + continue; > + } > + // > + // Check next handler if it's not for a common pool > + // > + if (UsedLength < GENERIC_IOTRAP_SIZE) { > + continue; > + } > + // > + // Check next handler if the size is too big > + // > + if (Length >=3D (UINT16) GENERIC_IOTRAP_SIZE - > mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength) { > + continue; > + } > + // > + // For common pool, we don't need to change the BaseAddress and > UsedLength > + // > + *Address =3D (UINT16) (BaseAddress + > mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength); > + mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength +=3D Length; > + } > + // > + // Only set RWM bit when we need both read and write cycles. > + // > + IoTrapRegHighDword =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 > + TrapHandlerNum * 8 + 4); > + if ((IoTrapRegHighDword & B_PSTH_PCR_TRPREG_RWM) =3D=3D 0 && > + (UINT32) ((IoTrapRegHighDword & B_PSTH_PCR_TRPREG_RWIO) >> > N_PSTH_PCR_TRPREG_RWIO) !=3D > + (UINT32) Type) { > + IoTrapRegHighDword =3D ((IoTrapRegHighDword | > B_PSTH_PCR_TRPREG_RWM) & ~B_PSTH_PCR_TRPREG_RWIO); > + SetIoTrapHighDword (TrapHandlerNum, IoTrapRegHighDword, TRUE); > + } > + } > + break; > + } > + > + if (TrapHandlerNum >=3D IO_TRAP_HANDLER_NUM) { > + DEBUG ((DEBUG_ERROR, "All IO Trap handler is used, no available IO T= rap > handler! \n")); > + return EFI_OUT_OF_RESOURCES; > + } > + // > + // Create database record and add to database > + // > + Status =3D gSmst->SmmAllocatePool ( > + EfiRuntimeServicesData, > + sizeof (IO_TRAP_RECORD), > + (VOID **) &mIoTrapRecord > + ); > + > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "Failed to allocate memory for mIoTrapRecord! > \n")); > + return EFI_OUT_OF_RESOURCES; > + } > + // > + // Gather information about the registration request > + // > + mIoTrapRecord->Signature =3D IO_TRAP_RECORD_SIGNATURE; > + mIoTrapRecord->Context.Address =3D *Address; > + mIoTrapRecord->Context.Length =3D Length; > + mIoTrapRecord->Context.Type =3D Type; > + mIoTrapRecord->Context.ByteEnable =3D ByteEnable; > + mIoTrapRecord->Context.ByteEnableMask =3D ByteEnableMask; > + mIoTrapRecord->IoTrapCallback =3D IoTrapDispatchFunction; > + mIoTrapRecord->IoTrapExCallback =3D IoTrapExDispatchFunction; > + mIoTrapRecord->IoTrapNumber =3D TrapHandlerNum; > + > + InsertTailList (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase), > &mIoTrapRecord->Link); > + > + // > + // Child's handle will be the address linked list link in the record > + // > + *DispatchHandle =3D (EFI_HANDLE) (&mIoTrapRecord->Link); > + > + DEBUG ((DEBUG_INFO, "Result Address:%x \n", *Address)); > + DEBUG ((DEBUG_INFO, "Result Length:%x \n", Length)); > + > + return EFI_SUCCESS; > +} > + > +/** > + IoTrap unregistratrion helper fucntion. > + > + @param[in] DispatchHandle Handle of dispatch function > + > + @retval EFI_INVALID_PARAMETER If DispatchHandle is invalid, > + EFI_ACCESS_DENIED If the SmmReadyToLock event has = been > triggered, > + EFI_SUCCESS IoTrap unregister successfully. > +**/ > +EFI_STATUS > +IoTrapUnRegisterHelper ( > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + IO_TRAP_RECORD *RecordToDelete; > + UINT32 IoTrapRegLowDword; > + EFI_PHYSICAL_ADDRESS BaseAddress; > + UINT32 UsedLength; > + UINT8 TrapHandlerNum; > + UINT8 LengthIndex; > + BOOLEAN RequireToDisableIoTrapHandler; > + > + if (DispatchHandle =3D=3D 0) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the > SmmReadyToLock event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + RecordToDelete =3D IO_TRAP_RECORD_FROM_LINK (DispatchHandle); > + // > + // Take the entry out of the linked list > + // > + if (RecordToDelete->Link.ForwardLink =3D=3D (LIST_ENTRY *) EFI_BAD_POI= NTER) > { > + return EFI_INVALID_PARAMETER; > + } > + > + RequireToDisableIoTrapHandler =3D FALSE; > + // > + // Loop through the first IO Trap handler, looking for the suitable ha= ndler > + // > + TrapHandlerNum =3D RecordToDelete->IoTrapNumber; > + > + if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable) { > + // > + // Disable the IO Trap handler if it's the only child of the Trap ha= ndler > + // > + RequireToDisableIoTrapHandler =3D TRUE; > + } else { > + // > + // Get information from Io Trap handler register > + // > + IoTrapRegLowDword =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + > TrapHandlerNum * 8); > + > + // > + // Check next Io Trap handler if the IO Trap handler is not used > + // > + if (AddressFromLowDword (IoTrapRegLowDword) !=3D 0) { > + > + UsedLength =3D LengthFromLowDword (IoTrapRegLowDword); > + BaseAddress =3D AddressFromLowDword (IoTrapRegLowDword); > + > + // > + // Check if it's the maximum address of the Io Trap handler > + // > + if ((UINTN)(BaseAddress + UsedLength) =3D=3D > (UINTN)(RecordToDelete->Context.Address + > RecordToDelete->Context.Length)) { > + > + if (BaseAddress =3D=3D RecordToDelete->Context.Address) { > + // > + // Disable the IO Trap handler if it's the only child of the T= rap handler > + // > + RequireToDisableIoTrapHandler =3D TRUE; > + } else { > + // > + // Calculate the new IO Trap handler Length > + // > + UsedLength =3D UsedLength - RecordToDelete->Context.Length; > + // > + // Check the alignment is dword * power of 2 or not > + // > + for (LengthIndex =3D 0; LengthIndex < sizeof (mLengthTable) / = sizeof > (UINT16); LengthIndex++) { > + if (UsedLength =3D=3D mLengthTable[LengthIndex]) { > + break; > + } > + } > + // > + // Do not decrease the length if the alignment is not dword * = power of > 2 > + // > + if (LengthIndex < sizeof (mLengthTable) / sizeof (UINT16)) { > + // > + // Decrease the length to prevent the IO trap SMI > + // > + IoTrapRegLowDword =3D (UINT32) ((((UsedLength - 1) &~(BIT1 += BIT0)) > << 16) | BaseAddress | B_PSTH_PCR_TRPREG_TSE); > + } > + SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, TRUE); > + } > + } > + } > + } > + > + if (RequireToDisableIoTrapHandler) { > + mIoTrapHandle =3D mIoTrapData.Entry[TrapHandlerNum].IoTrapHandle; > + Status =3D PchInternalIoTrapSmiUnRegister (mIoTrapHandle); > + ASSERT_EFI_ERROR (Status); > + > + SetIoTrapLowDword (TrapHandlerNum, 0, TRUE); > + SetIoTrapHighDword (TrapHandlerNum, 0, TRUE); > + // > + // Also clear pending IOTRAP status. > + // > + ClearPendingIoTrapStatus (TrapHandlerNum); > + > + mIoTrapData.Entry[TrapHandlerNum].IoTrapHandle =3D 0; > + mIoTrapData.Entry[TrapHandlerNum].MergeDisable =3D FALSE; > + if (mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource =3D=3D > TRUE) { > + mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource =3D FALSE= ; > + UpdateIoTrapAcpiResources (TrapHandlerNum, 0, FALSE); > + } > + } > + > + RemoveEntryList (&RecordToDelete->Link); > + Status =3D gSmst->SmmFreePool (RecordToDelete); > + ASSERT_EFI_ERROR (Status); > + > + return EFI_SUCCESS; > +} > + > +/** > + Register a new IO Trap SMI dispatch function with a parent SMM driver. > + The caller will provide information about the IO trap characteristics = via > + the context. This includes base address, length, read vs. r/w, etc. > + This function will autoallocate IO base address from a common pool if = the > base address is 0, > + and the RegisterContext Address field will be updated. > + The service will not perform GCD allocation if the base address is non= -zero. > + In this case, the caller is responsible for the existence and allocati= on of the > + specific IO range. > + This function looks for the suitable handler and Register a new IoTrap > handler > + if the IO Trap handler is not used. It also enable the IO Trap Range t= o > generate > + SMI. > + > + @param[in] This Pointer to the > EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL instance. > + @param[in] DispatchFunction Pointer to dispatch function to be > invoked for > + this SMI source. > + @param[in, out] RegisterContext Pointer to the dispatch function's con= text. > + The caller fills this context in befor= e calling > + the register function to indicate to t= he register > + function the IO trap SMI source for wh= ich the > dispatch > + function should be invoked. This may = not be NULL. > + If the registration address is not 0, = it's caller's > responsibility > + to reserve the IO resource in ACPI. > + @param[out] DispatchHandle Handle of dispatch function, for when > interfacing > + with the parent SMM driver, will be th= e address of > linked > + list link in the call back record. Th= is may not be > NULL. > + > + @retval EFI_SUCCESS The dispatch function has been success= fully > + registered and the SMI source has been= enabled. > + @retval EFI_DEVICE_ERROR The driver was unable to enable the SM= I > source. > + @retval EFI_OUT_OF_RESOURCES Insufficient resources are available > + @retval EFI_INVALID_PARAMETER Address requested is already in use. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +IoTrapRegister ( > + IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *This, > + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, > + IN OUT EFI_SMM_IO_TRAP_REGISTER_CONTEXT *RegisterContext, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + > + DEBUG ((DEBUG_INFO, "IoTrapRegister\n")); > + Status =3D IoTrapRegisterHelper ( > + DispatchHandle, > + DispatchFunction, > + NULL, > + &(RegisterContext->Address), > + RegisterContext->Length, > + (IO_TRAP_EX_DISPATCH_TYPE) RegisterContext->Type, > + 0x00, > + 0x0F); > + > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler > (&gEfiSmmIoTrapDispatch2ProtocolGuid, DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +/** > + Unregister a child SMI source dispatch function with a parent SMM driv= er. > + > + @param[in] This Pointer to the > EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL instance. > + @param[in] DispatchHandle Handle of dispatch function to deregis= ter. > + > + @retval EFI_SUCCESS The dispatch function has been success= fully > + unregistered and the SMI source has be= en disabled > + if there are no other registered child= dispatch > + functions for this SMI source. > + @retval EFI_INVALID_PARAMETER Handle is invalid. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +IoTrapUnRegister ( > + IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *This, > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + IO_TRAP_RECORD *RecordToDelete; > + > + RecordToDelete =3D IO_TRAP_RECORD_FROM_LINK (DispatchHandle); > + SmiHandlerProfileUnregisterHandler > (&gEfiSmmIoTrapDispatch2ProtocolGuid, RecordToDelete->IoTrapCallback, > NULL, 0); > + return IoTrapUnRegisterHelper (DispatchHandle); > +} > + > +/** > + Register a new IO Trap Ex SMI dispatch function. > + > + @param[in] This Pointer to the > IO_TRAP_EX_DISPATCH_PROTOCOL instance. > + @param[in] DispatchFunction Pointer to dispatch function to be > invoked for > + this SMI source. > + @param[in] RegisterContext Pointer to the dispatch function's con= text. > + The caller fills this context in befor= e calling > + the register function to indicate to t= he register > + function the IO trap Ex SMI source for= which the > dispatch > + function should be invoked. This MUST= not be > NULL. > + @param[out] DispatchHandle Handle of dispatch function. > + > + @retval EFI_SUCCESS The dispatch function has been success= fully > + registered and the SMI source has been= enabled. > + @retval EFI_OUT_OF_RESOURCES Insufficient resources are available > + @retval EFI_INVALID_PARAMETER Address requested is already in use. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +IoTrapExRegister ( > + IN IO_TRAP_EX_DISPATCH_PROTOCOL *This, > + IN IO_TRAP_EX_DISPATCH_CALLBACK DispatchFunction, > + IN IO_TRAP_EX_REGISTER_CONTEXT *RegisterContext, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + > + DEBUG ((DEBUG_INFO, "PchSmmIoTrapExRegister\n")); > + // > + // Return error if length is less than 4 and not power of 2. > + // > + if ((RegisterContext->Length < 4) || ((RegisterContext->Length & > (RegisterContext->Length - 1)) !=3D 0)) { > + DEBUG ((DEBUG_ERROR, "The Dispatch Length is not power of 2 \n")); > + return EFI_INVALID_PARAMETER; > + } > + > + Status =3D IoTrapRegisterHelper ( > + DispatchHandle, > + NULL, > + DispatchFunction, > + &(RegisterContext->Address), > + RegisterContext->Length, > + RegisterContext->Type, > + RegisterContext->ByteEnable, > + RegisterContext->ByteEnableMask); > + > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gIoTrapExDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +/** > + Unregister a SMI source dispatch function. > + This function is unsupported. > + > + @param[in] This Pointer to the > IO_TRAP_EX_DISPATCH_PROTOCOL instance. > + @param[in] DispatchHandle Handle of dispatch function to deregis= ter. > + > + @retval EFI_UNSUPPORTED The function is unsupported. > +**/ > +EFI_STATUS > +EFIAPI > +IoTrapExUnRegister ( > + IN IO_TRAP_EX_DISPATCH_PROTOCOL *This, > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + IO_TRAP_RECORD *RecordToDelete; > + > + RecordToDelete =3D IO_TRAP_RECORD_FROM_LINK (DispatchHandle); > + SmiHandlerProfileUnregisterHandler (&gIoTrapExDispatchProtocolGuid, > RecordToDelete->IoTrapCallback, NULL, 0); > + return IoTrapUnRegisterHelper (DispatchHandle); > +} > + > +/** > + Pause IoTrap callback function. > + > + This function disables the SMI enable of IoTrap according to the > DispatchHandle, > + which is returned by IoTrap callback registration. It only supports th= e > DispatchHandle > + with MergeDisable TRUE and address not zero. > + > + NOTE: This call does not guarantee all pending IO cycles to be synchro= nized > + and pending IO cycles issued before this call might not be trapp= ed. > + > + @param[in] This Pointer to the > PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance. > + @param[in] DispatchHandle Handle of the child service to change > state. > + > + @retval EFI_SUCCESS This operation is complete. > + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. > + @retval EFI_ACCESS_DENIED The SMI status is alrady PAUSED. > +**/ > +EFI_STATUS > +EFIAPI > +IoTrapControlPause ( > + IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL *This, > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + IO_TRAP_RECORD *IoTrapRecord; > + UINT32 IoTrapRegLowDword; > + UINT32 IoTrapRegHighDword; > + EFI_PHYSICAL_ADDRESS BaseAddress; > + UINT32 UsedLength; > + UINT8 TrapHandlerNum; > + BOOLEAN TempMergeDisable; > + BOOLEAN DisableIoTrap; > + > + if (DispatchHandle =3D=3D 0) { > + return EFI_INVALID_PARAMETER; > + } > + > + IoTrapRecord =3D IO_TRAP_RECORD_FROM_LINK (DispatchHandle); > + > + if (IoTrapRecord->Context.Address) { > + TempMergeDisable =3DTRUE; > + }else { > + TempMergeDisable =3D FALSE; > + } > + > + if ((IoTrapRecord->Signature !=3D IO_TRAP_RECORD_SIGNATURE) || > + (TempMergeDisable !=3D TRUE) || > + (IoTrapRecord->Context.Address =3D=3D 0) || > + (IoTrapRecord->Context.Length =3D=3D 0)) { > + return EFI_INVALID_PARAMETER; > + } > + > + for (TrapHandlerNum =3D 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; > TrapHandlerNum++) { > + // > + // This IoTrap register should be merge disabled. > + // > + if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable !=3D TRUE) { > + continue; > + } > + IoTrapRegLowDword =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + > TrapHandlerNum * 8); > + IoTrapRegHighDword =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + > TrapHandlerNum * 8 + 4); > + // > + // Depending on the usage, we will obtain the UsedLength and > BaseAddress differently > + // If the registered trap length is less than 4, we obtain the lengt= h from Byte > Enable Mask > + // In the other hand, we obtain the length from Address Mask > + // > + if (ByteEnableMaskFromHighDword (IoTrapRegHighDword) !=3D 0xF) { > + UsedLength =3D (UINT32) (HighBitSet32 (IoTrapRegHighDword & 0xF0) = - > LowBitSet32 (IoTrapRegHighDword & 0xF0) + 1); > + BaseAddress =3D AddressFromLowDword (IoTrapRegLowDword) + > LowBitSet32 (ByteEnableMaskFromHighDword (IoTrapRegHighDword)); > + } else { > + UsedLength =3D LengthFromLowDword (IoTrapRegLowDword); > + BaseAddress =3D AddressFromLowDword (IoTrapRegLowDword); > + } > + > + // > + // The address and length of record matches the IoTrap register's. > + // > + DisableIoTrap =3D FALSE; > + if ((IoTrapRecord->IoTrapExCallback !=3D NULL) && > + IsIoTrapExContentMatched (IoTrapRecord, IoTrapRegLowDword, > IoTrapRegHighDword)) { > + DisableIoTrap =3D TRUE; > + } else if ((BaseAddress =3D=3D IoTrapRecord->Context.Address) && > + (UsedLength =3D=3D IoTrapRecord->Context.Length )) { > + DisableIoTrap =3D TRUE; > + } > + > + if (DisableIoTrap) { > + // > + // Check if status matched. > + // If this is already Paused, return warning status. > + // > + if ((IoTrapRegLowDword & B_PSTH_PCR_TRPREG_TSE) =3D=3D 0) { > + return EFI_ACCESS_DENIED; > + } > + // > + // Clear IoTrap register SMI enable bit > + // > + IoTrapRegLowDword &=3D (~B_PSTH_PCR_TRPREG_TSE); > + SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, FALSE); > + // > + // Also clear pending IOTRAP status. > + // > + ClearPendingIoTrapStatus (TrapHandlerNum); > + return EFI_SUCCESS; > + } > + } > + return EFI_INVALID_PARAMETER; > +} > + > +/** > + Resume IoTrap callback function. > + > + This function enables the SMI enable of IoTrap according to the > DispatchHandle, > + which is returned by IoTrap callback registration. It only supports th= e > DispatchHandle > + with MergeDisable TRUE and address not zero. > + > + @param[in] This Pointer to the > PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance. > + @param[in] DispatchHandle Handle of the child service to change > state. > + > + @retval EFI_SUCCESS This operation is complete. > + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. > + @retval EFI_ACCESS_DENIED The SMI status is alrady RESUMED. > +**/ > +EFI_STATUS > +EFIAPI > +IoTrapControlResume ( > + IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL *This, > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + IO_TRAP_RECORD *IoTrapRecord; > + UINT32 IoTrapRegLowDword; > + UINT32 IoTrapRegHighDword; > + EFI_PHYSICAL_ADDRESS BaseAddress; > + UINT32 UsedLength; > + UINT8 TrapHandlerNum; > + BOOLEAN TempMergeDisable; > + BOOLEAN EnableIoTrap; > + > + if (DispatchHandle =3D=3D 0) { > + return EFI_INVALID_PARAMETER; > + } > + IoTrapRecord =3D IO_TRAP_RECORD_FROM_LINK (DispatchHandle); > + > + if (IoTrapRecord->Context.Address) { > + TempMergeDisable =3D TRUE; > + }else { > + TempMergeDisable =3D FALSE; > + } > + > + if ((IoTrapRecord->Signature !=3D IO_TRAP_RECORD_SIGNATURE) || > + (TempMergeDisable !=3D TRUE) || > + (IoTrapRecord->Context.Address =3D=3D 0) || > + (IoTrapRecord->Context.Length =3D=3D 0)) { > + return EFI_INVALID_PARAMETER; > + } > + > + for (TrapHandlerNum =3D 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; > TrapHandlerNum++) { > + // > + // This IoTrap register should be merge disabled. > + // > + if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable !=3D TRUE) { > + continue; > + } > + IoTrapRegLowDword =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + > TrapHandlerNum * 8); > + IoTrapRegHighDword =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + > TrapHandlerNum * 8 + 4); > + // > + // Depending on the usage, we will obtain the UsedLength and > BaseAddress differently > + // If the registered trap length is less than 4, we obtain the lengt= h from Byte > Enable Mask > + // In the other hand, we obtain the length from Address Mask > + // > + if (ByteEnableMaskFromHighDword (IoTrapRegHighDword) !=3D 0xF) { > + UsedLength =3D (UINT32) (HighBitSet32 (IoTrapRegHighDword & 0xF0)= - > LowBitSet32 (IoTrapRegHighDword & 0xF0) + 1); > + BaseAddress =3D AddressFromLowDword (IoTrapRegLowDword) + > LowBitSet32 (ByteEnableMaskFromHighDword (IoTrapRegHighDword)); > + } else { > + UsedLength =3D LengthFromLowDword (IoTrapRegLowDword); > + BaseAddress =3D AddressFromLowDword (IoTrapRegLowDword); > + } > + > + // > + // The address and length of record matches the IoTrap register's. > + // > + EnableIoTrap =3D FALSE; > + if ((IoTrapRecord->IoTrapExCallback !=3D NULL) && > + IsIoTrapExContentMatched (IoTrapRecord, IoTrapRegLowDword, > IoTrapRegHighDword)) { > + EnableIoTrap =3D TRUE; > + } else if ((BaseAddress =3D=3D IoTrapRecord->Context.Address) && > + (UsedLength =3D=3D IoTrapRecord->Context.Length )) { > + EnableIoTrap =3D TRUE; > + } > + > + if (EnableIoTrap) { > + // > + // Check if status matched. > + // If this is already Resume, return warning status. > + // > + if ((IoTrapRegLowDword & B_PSTH_PCR_TRPREG_TSE) !=3D 0) { > + return EFI_ACCESS_DENIED; > + } > + // > + // Set IoTrap register SMI enable bit > + // > + IoTrapRegLowDword |=3D (B_PSTH_PCR_TRPREG_TSE); > + SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, FALSE); > + return EFI_SUCCESS; > + } > + } > + return EFI_INVALID_PARAMETER; > +} > + > +/** > + The IoTrap module abstracts PCH I/O trapping capabilities for other dr= ivers. > + This driver manages the limited I/O trap resources. > + > + @param[in] ImageHandle Image handle for this driver ima= ge > + > + @retval EFI_SUCCESS Driver initialization completed > successfully > +**/ > +EFI_STATUS > +EFIAPI > +InstallIoTrap ( > + IN EFI_HANDLE ImageHandle > + ) > +{ > + EFI_STATUS Status; > + PCH_NVS_AREA_PROTOCOL *PchNvsAreaProtocol; > + UINTN TrapHandlerNum; > + > + // > + // Initialize the EFI SMM driver library > + // > + mDriverImageHandle =3D ImageHandle; > + > + // > + // Initialize the IO TRAP protocol we produce > + // > + mIoTrapData.Signature =3D IO_TRAP_INSTANCE_SIGNATURE; > + mIoTrapData.EfiSmmIoTrapDispatchProtocol.Register =3D IoTrapRegister= ; > + mIoTrapData.EfiSmmIoTrapDispatchProtocol.UnRegister =3D > IoTrapUnRegister; > + > + // > + // Initialize the IO TRAP EX protocol > + // > + mIoTrapData.IoTrapExDispatchProtocol.Register =3D IoTrapExRegist= er; > + mIoTrapData.IoTrapExDispatchProtocol.UnRegister =3D > IoTrapExUnRegister; > + > + // > + // Initialize the IO TRAP control protocol. > + // > + mIoTrapData.PchSmmIoTrapControlProtocol.Pause =3D > IoTrapControlPause; > + mIoTrapData.PchSmmIoTrapControlProtocol.Resume =3D > IoTrapControlResume; > + > + for (TrapHandlerNum =3D 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; > TrapHandlerNum++) { > + // > + // Initialize IO TRAP Callback DataBase > + // > + InitializeListHead > (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase)); > + } > + mIoTrapData.Entry[0].CallbackDispatcher =3D IoTrapDispatcher0; > + mIoTrapData.Entry[1].CallbackDispatcher =3D IoTrapDispatcher1; > + mIoTrapData.Entry[2].CallbackDispatcher =3D IoTrapDispatcher2; > + mIoTrapData.Entry[3].CallbackDispatcher =3D IoTrapDispatcher3; > + > + // > + // Get address of PchNvs structure for later use > + // > + Status =3D gBS->LocateProtocol (&gPchNvsAreaProtocolGuid, NULL, (VOID = **) > &PchNvsAreaProtocol); > + ASSERT_EFI_ERROR (Status); > + mPchNvsArea =3D PchNvsAreaProtocol->Area; > + > + // > + // Install protocol interface > + // > + mIoTrapData.Handle =3D NULL; > + Status =3D gSmst->SmmInstallProtocolInterface ( > + &mIoTrapData.Handle, > + &gEfiSmmIoTrapDispatch2ProtocolGuid, > + EFI_NATIVE_INTERFACE, > + &mIoTrapData.EfiSmmIoTrapDispatchProtocol > + ); > + ASSERT_EFI_ERROR (Status); > + > + Status =3D gSmst->SmmInstallProtocolInterface ( > + &mIoTrapData.Handle, > + &gIoTrapExDispatchProtocolGuid, > + EFI_NATIVE_INTERFACE, > + &mIoTrapData.IoTrapExDispatchProtocol > + ); > + ASSERT_EFI_ERROR (Status); > + > + Status =3D gSmst->SmmInstallProtocolInterface ( > + &mIoTrapData.Handle, > + &gPchSmmIoTrapControlGuid, > + EFI_NATIVE_INTERFACE, > + &mIoTrapData.PchSmmIoTrapControlProtocol > + ); > + ASSERT_EFI_ERROR (Status); > + > + return EFI_SUCCESS; > +} > diff --git > a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDisp > atch.c > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDis > patch.c > new file mode 100644 > index 0000000000..2b70008fee > --- /dev/null > +++ > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDis > patch.c > @@ -0,0 +1,2452 @@ > +/** @file > + This function handle the register/unregister of PCH specific SMI event= s. > + > + Copyright (c) 2019 Intel Corporation. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#include "PchSmmHelpers.h" > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +/** > + The internal function used to create and insert a database record > + for SMI record of Pch Smi types. > + > + @param[in] SrcDesc The pointer to the SMI source > description > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[in] PchSmiType Specific SMI type of PCH SMI > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > +**/ > +EFI_STATUS > +PchSmiRecordInsert ( > + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc, > + IN PCH_SMI_CALLBACK_FUNCTIONS DispatchFunction, > + IN PCH_SMI_TYPES PchSmiType, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + DATABASE_RECORD Record; > + > + if (SrcDesc =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + ZeroMem (&Record, sizeof (DATABASE_RECORD)); > + // > + // Gather information about the registration request > + // > + Record.Signature =3D DATABASE_RECORD_SIGNATURE; > + Record.PchSmiCallback =3D DispatchFunction; > + Record.ProtocolType =3D PchSmiDispatchType; > + Record.PchSmiType =3D PchSmiType; > + > + CopyMem (&Record.SrcDesc, SrcDesc, sizeof (PCH_SMM_SOURCE_DESC)); > + Status =3D SmmCoreInsertRecord ( > + &Record, > + DispatchHandle > + ); > + ASSERT_EFI_ERROR (Status); > + > + return EFI_SUCCESS; > +} > + > + > +// > +// TCO_STS bit that needs to be cleared > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mDescSrcTcoSts =3D { > + PCH_SMM_NO_FLAGS, > + { > + NULL_BIT_DESC_INITIALIZER, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_TCO > + } > + }, > + NULL_BIT_DESC_INITIALIZER > +}; > + > +/** > + Clear the TCO SMI status bit and block after the SMI handling is done > + > + @param[in] SrcDesc Pointer to the PCH SMI source > description table > + > +**/ > +VOID > +EFIAPI > +PchTcoSmiClearSourceAndBlock ( > + CONST PCH_SMM_SOURCE_DESC *SrcDesc > + ) > +{ > + PchSmmClearSourceAndBlock (SrcDesc); > + // > + // Any TCO-based status bits require special handling. > + // SMI_STS.TCO_STS must be cleared in addition to the status bit in th= e TCO > registers > + // > + PchSmmClearSource (&mDescSrcTcoSts); > +} > + > +/** > + Clear the TCO SMI status bit after the SMI handling is done > + > + @param[in] SrcDesc Pointer to the PCH SMI source > description table > + > +**/ > +VOID > +EFIAPI > +PchTcoSmiClearSource ( > + CONST PCH_SMM_SOURCE_DESC *SrcDesc > + ) > +{ > + PchSmmClearSource (SrcDesc); > + // > + // Any TCO-based status bits require special handling. > + // SMI_STS.TCO_STS must be cleared in addition to the status bit in th= e TCO > registers > + // > + PchSmmClearSource (&mDescSrcTcoSts); > +} > + > +/** > + Initialize Source descriptor structure > + > + @param[in] SrcDesc Pointer to the PCH SMI source > description table > + > +**/ > +VOID > +EFIAPI > +NullInitSourceDesc ( > + PCH_SMM_SOURCE_DESC *SrcDesc > + ) > +{ > + ZeroMem (SrcDesc, sizeof (PCH_SMM_SOURCE_DESC)); > + SrcDesc->En[0].Reg.Type =3D PCH_SMM_ADDR_TYPE_NULL; > + SrcDesc->En[1].Reg.Type =3D PCH_SMM_ADDR_TYPE_NULL; > + SrcDesc->Sts[0].Reg.Type =3D PCH_SMM_ADDR_TYPE_NULL; > + SrcDesc->PmcSmiSts.Reg.Type =3D PCH_SMM_ADDR_TYPE_NULL; > +} > + > +// > +// Mch srcdesc > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescMch =3D { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_EN} > + }, > + S_ACPI_IO_SMI_EN, > + N_ACPI_IO_SMI_EN_TCO > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + TCO_ADDR_TYPE, > + {R_TCO_IO_TCO1_STS} > + }, > + S_TCO_IO_TCO1_STS, > + N_TCO_IO_TCO1_STS_DMISMI > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_TCO > + } > +}; > + > +/** > + The register function used to register SMI handler of MCH event. > + > + @param[in] This The pointer to the protocol itse= lf > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchTcoSmiMchRegister ( > + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + DATABASE_RECORD *Record; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D PchSmiRecordInsert ( > + &mSrcDescMch, > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchTcoSmiMchType, > + DispatchHandle > + ); > + if (!EFI_ERROR (Status)) { > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); > + Record->ClearSource =3D PchTcoSmiClearSource; > + PchSmmClearSource (&Record->SrcDesc); > + PchSmmEnableSource (&Record->SrcDesc); > + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +// > +// TcoTimeout srcdesc > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescTcoTimeout =3D { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_EN} > + }, > + S_ACPI_IO_SMI_EN, > + N_ACPI_IO_SMI_EN_TCO > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + TCO_ADDR_TYPE, > + {R_TCO_IO_TCO1_STS} > + }, > + S_TCO_IO_TCO1_STS, > + N_TCO_IO_TCO1_STS_TIMEOUT > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_TCO > + } > +}; > + > +/** > + The register function used to register SMI handler of TcoTimeout event= . > + > + @param[in] This The pointer to the protocol itse= lf > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchTcoSmiTcoTimeoutRegister ( > + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + DATABASE_RECORD *Record; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D PchSmiRecordInsert ( > + &mSrcDescTcoTimeout, > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchTcoSmiTcoTimeoutType, > + DispatchHandle > + ); > + if (!EFI_ERROR (Status)) { > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); > + Record->ClearSource =3D PchTcoSmiClearSource; > + PchSmmClearSource (&Record->SrcDesc); > + PchSmmEnableSource (&Record->SrcDesc); > + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +// > +// OsTco srcdesc > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescOsTco =3D { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_EN} > + }, > + S_ACPI_IO_SMI_EN, > + N_ACPI_IO_SMI_EN_TCO > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + TCO_ADDR_TYPE, > + {R_TCO_IO_TCO1_STS} > + }, > + S_TCO_IO_TCO1_STS, > + N_TCO_IO_TCO1_STS_SW_TCO_SMI > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_TCO > + } > +}; > + > +/** > + The register function used to register SMI handler of OS TCO event. > + > + @param[in] This The pointer to the protocol itse= lf > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchTcoSmiOsTcoRegister ( > + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + DATABASE_RECORD *Record; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D PchSmiRecordInsert ( > + &mSrcDescOsTco, > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchTcoSmiOsTcoType, > + DispatchHandle > + ); > + if (!EFI_ERROR (Status)) { > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); > + Record->ClearSource =3D PchTcoSmiClearSource; > + PchSmmClearSource (&Record->SrcDesc); > + PchSmmEnableSource (&Record->SrcDesc); > + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +// > +// Nmi > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescNmi =3D { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + PCR_ADDR_TYPE, > + {PCH_PCR_ADDRESS (PID_ITSS, R_ITSS_PCR_NMI)} > + }, > + 4, > + N_ITSS_PCR_NMI_NMI2SMI_EN > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + PCR_ADDR_TYPE, > + {PCH_PCR_ADDRESS (PID_ITSS, R_ITSS_PCR_NMI)} > + }, > + 4, > + N_ITSS_PCR_NMI_NMI2SMI_STS > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_TCO > + } > +}; > + > +/** > + Enable the Nmi2Smi source > +**/ > +VOID > +PchNmi2SmiEnableSource ( > + VOID > + ) > +{ > + // > + // The PCR[ITSS].NMI register can only be accessed with BOOT_SAI and > SMM_SAI. > + // Since in CFL there is no SMM_SAI it needs PMC assistance to access = this > register. > + // > + UINT32 ItssNmi; > + ItssNmi =3D PmcGetNmiControl (); > + PmcSetNmiControl (ItssNmi | B_ITSS_PCR_NMI_NMI2SMI_EN); > +} > + > +/** > + Clear the NMI status bit after the SMI handling is done > + > + @param[in] SrcDesc Pointer to the PCH SMI source > description table > +**/ > +VOID > +EFIAPI > +PchNmi2SmiClearSource ( > + CONST PCH_SMM_SOURCE_DESC *SrcDesc > + ) > +{ > + // No need to clear NMI2SMI_STS since it's cleared when NMI source is > cleared. > + // Clear TCO status only. > + PchSmmClearSource (&mDescSrcTcoSts); > +} > + > +/** > + The register function used to register SMI handler of NMI event. > + > + @param[in] This The pointer to the protocol itse= lf > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchTcoSmiNmiRegister ( > + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + DATABASE_RECORD *Record; > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D PchSmiRecordInsert ( > + &mSrcDescNmi, > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchTcoSmiNmiType, > + DispatchHandle > + ); > + if (!EFI_ERROR (Status)) { > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); > + // > + // Since the NMI2SMI status and enable bit are at the same register, > + // it needs separate function to handle the source enable and clear. > + // > + Record->ClearSource =3D PchNmi2SmiClearSource; > + PchNmi2SmiEnableSource (); > + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +// > +// IntruderDetect srcdesc > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescIntruderDet =3D { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_EN} > + }, > + S_ACPI_IO_SMI_EN, > + N_ACPI_IO_SMI_EN_TCO > + }, > + { > + { > + TCO_ADDR_TYPE, > + {R_TCO_IO_TCO2_CNT} > + }, > + S_TCO_IO_TCO2_CNT, > + N_TCO_IO_TCO2_CNT_INTRD_SEL > + } > + }, > + { > + { > + { > + TCO_ADDR_TYPE, > + {R_TCO_IO_TCO2_STS} > + }, > + S_TCO_IO_TCO2_STS, > + N_TCO_IO_TCO2_STS_INTRD_DET > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_TCO > + } > +}; > + > +/** > + The register function used to register SMI handler of Intruder Detect = event. > + > + @param[in] This The pointer to the protocol itse= lf > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchTcoSmiIntruderDetRegister ( > + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + DATABASE_RECORD *Record; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D PchSmiRecordInsert ( > + &mSrcDescIntruderDet, > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchTcoSmiIntruderDetectType, > + DispatchHandle > + ); > + if (!EFI_ERROR (Status)) { > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); > + Record->ClearSource =3D PchTcoSmiClearSourceAndBlock; > + PchSmmClearSource (&Record->SrcDesc); > + PchSmmEnableSource (&Record->SrcDesc); > + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +// > +// SpiBiosWp srcdesc > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescSpiBiosWp =3D { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_EN} > + }, > + S_ACPI_IO_SMI_EN, > + N_ACPI_IO_SMI_EN_TCO > + }, > + { > + { > + PCIE_ADDR_TYPE, > + { ( > + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | > + (PCI_DEVICE_NUMBER_PCH_SPI << 19) | > + (PCI_FUNCTION_NUMBER_PCH_SPI << 16) | > + R_SPI_CFG_BC > + ) } > + }, > + S_SPI_CFG_BC, > + N_SPI_CFG_BC_BLE > + }, > + }, > + { > + { > + { > + PCIE_ADDR_TYPE, > + { ( > + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | > + (PCI_DEVICE_NUMBER_PCH_SPI << 19) | > + (PCI_FUNCTION_NUMBER_PCH_SPI << 16) | > + R_SPI_CFG_BC > + ) } > + }, > + S_SPI_CFG_BC, > + N_SPI_CFG_BC_SYNC_SS > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_TCO > + } > +}; > + > +/** > + Special handling for SPI Write Protect > + > + @param[in] SrcDesc Not used > +**/ > +VOID > +EFIAPI > +PchTcoSpiWpClearSource ( > + CONST PCH_SMM_SOURCE_DESC *SrcDesc > + ) > +{ > + UINT64 SpiRegBase; > + UINT32 BiosControl; > + UINT32 Timeout; > + > + SpiRegBase =3D PCI_SEGMENT_LIB_ADDRESS ( > + DEFAULT_PCI_SEGMENT_NUMBER_PCH, > + DEFAULT_PCI_BUS_NUMBER_PCH, > + PCI_DEVICE_NUMBER_PCH_SPI, > + PCI_FUNCTION_NUMBER_PCH_SPI, > + 0 > + ); > + PciSegmentAndThenOr32 ( > + SpiRegBase + R_SPI_CFG_BC, > + (UINT32) ~B_SPI_CFG_BC_ASYNC_SS, > + B_SPI_CFG_BC_SYNC_SS > + ); > + // > + // Ensure the SYNC is cleared > + // > + Timeout =3D 1000; > + do { > + BiosControl =3D PciSegmentRead32 (SpiRegBase + R_SPI_CFG_BC); > + Timeout--; > + } while ((BiosControl & B_SPI_CFG_BC_SYNC_SS) && (Timeout > 0)); > + // > + // Any TCO-based status bits require special handling. > + // SMI_STS.TCO_STS must be cleared in addition to the status bit in th= e TCO > registers > + // > + PchSmmClearSource (&mDescSrcTcoSts); > +} > + > +/** > + The register function used to register SMI handler of BIOS write prote= ct > event. > + > + @param[in] This The pointer to the protocol itse= lf > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchTcoSmiSpiBiosWpRegister ( > + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + DATABASE_RECORD *Record; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D PchSmiRecordInsert ( > + &mSrcDescSpiBiosWp, > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchTcoSmiSpiBiosWpType, > + DispatchHandle > + ); > + if (!EFI_ERROR (Status)) { > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); > + Record->ClearSource =3D PchTcoSpiWpClearSource; > + PchTcoSpiWpClearSource (NULL); > + // > + // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE. > + // > + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +// > +// LpcBiosWp srcdesc > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescLpcBiosWp =3D { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_EN} > + }, > + S_ACPI_IO_SMI_EN, > + N_ACPI_IO_SMI_EN_TCO > + }, > + { > + { > + PCIE_ADDR_TYPE, > + { ( > + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | > + (PCI_DEVICE_NUMBER_PCH_LPC << 19) | > + (PCI_FUNCTION_NUMBER_PCH_LPC << 16) | > + R_LPC_CFG_BC > + ) } > + }, > + S_LPC_CFG_BC, > + N_LPC_CFG_BC_LE > + } > + }, > + { > + { > + { > + TCO_ADDR_TYPE, > + {R_TCO_IO_TCO1_STS} > + }, > + S_TCO_IO_TCO1_STS, > + N_TCO_IO_TCO1_STS_BIOSWR > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_TCO > + } > +}; > + > +/** > + The register function used to register SMI handler of LPC BIOS write p= rotect > event. > + > + @param[in] This The pointer to the protocol itse= lf > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchTcoSmiLpcBiosWpRegister ( > + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + DATABASE_RECORD *Record; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + if (IsEspiEnabled ()) { > + // > + // Status is D31F0's PCBC.BWPDS > + // > + ASSERT (FALSE); > + return EFI_UNSUPPORTED; > + } > + > + Status =3D PchSmiRecordInsert ( > + &mSrcDescLpcBiosWp, > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchTcoSmiLpcBiosWpType, > + DispatchHandle > + ); > + if (!EFI_ERROR (Status)) { > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); > + Record->ClearSource =3D PchTcoSmiClearSource; > + PchSmmClearSource (&Record->SrcDesc); > + // > + // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE. > + // > + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +// > +// NEWCENTURY_STS bit that needs to be cleared > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescNewCentury =3D { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_EN} > + }, > + S_ACPI_IO_SMI_EN, > + N_ACPI_IO_SMI_EN_TCO > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + TCO_ADDR_TYPE, > + {R_TCO_IO_TCO1_STS} > + }, > + S_TCO_IO_TCO1_STS, > + N_TCO_IO_TCO1_STS_NEWCENTURY > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_TCO > + } > +}; > + > +/** > + The register function used to register SMI handler of NEW CENTURY even= t. > + > + @param[in] This The pointer to the protocol itse= lf > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchTcoSmiNewCenturyRegister ( > + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + DATABASE_RECORD *Record; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D PchSmiRecordInsert ( > + &mSrcDescNewCentury, > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchTcoSmiNewCenturyType, > + DispatchHandle > + ); > + if (!EFI_ERROR (Status)) { > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); > + Record->ClearSource =3D PchTcoSmiClearSourceAndBlock; > + PchSmmClearSource (&Record->SrcDesc); > + PchSmmEnableSource (&Record->SrcDesc); > + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +/** > + Unregister a child SMI source dispatch function with a parent SMM driv= er > + > + @param[in] This Protocol instance pointer. > + @param[in] DispatchHandle Handle of dispatch function to > deregister. > + > + @retval EFI_SUCCESS The dispatch function has been > successfully > + unregistered and the SMI source = has been > disabled > + if there are no other registered= child dispatch > + functions for this SMI source. > + @retval EFI_INVALID_PARAMETER Handle is invalid. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchTcoSmiUnRegister ( > + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + DATABASE_RECORD *Record; > + EFI_STATUS Status; > + > + Record =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); > + if ((Record->SrcDesc.En[1].Reg.Type =3D=3D ACPI_ADDR_TYPE) && > + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Dev =3D=3D > PCI_DEVICE_NUMBER_PCH_SPI) && > + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Fnc =3D=3D > PCI_FUNCTION_NUMBER_PCH_SPI) && > + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Reg =3D=3D R_SPI_CFG_B= C) && > + (Record->SrcDesc.En[1].Bit =3D=3D N_SPI_CFG_BC_BLE)) { > + // > + // SPI Write Protect cannot be disabled > + // > + return EFI_ACCESS_DENIED; > + } else if ((Record->SrcDesc.En[1].Reg.Type =3D=3D ACPI_ADDR_TYPE) && > + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Dev =3D=3D > PCI_DEVICE_NUMBER_PCH_LPC) && > + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Fnc =3D=3D > PCI_FUNCTION_NUMBER_PCH_LPC) && > + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Reg =3D=3D R_LP= C_CFG_BC) > && > + (Record->SrcDesc.En[1].Bit =3D=3D N_LPC_CFG_BC_LE)) { > + // > + // eSPI/LPC Write Protect cannot be disabled > + // > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D PchSmmCoreUnRegister (NULL, DispatchHandle); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileUnregisterHandler (&gPchTcoSmiDispatchProtocolGuid, > Record->Callback, NULL, 0); > + } > + return Status; > +} > + > + > +// > +// PcieRpHotPlug srcdesc > +// > +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC > PchPcieSmiRpHotPlugTemplate =3D { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + PCIE_ADDR_TYPE, > + {R_PCH_PCIE_CFG_MPC} > + }, > + S_PCH_PCIE_CFG_MPC, > + N_PCH_PCIE_CFG_MPC_HPME > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + PCIE_ADDR_TYPE, > + {R_PCH_PCIE_CFG_SMSCS} > + }, > + S_PCH_PCIE_CFG_SMSCS, > + N_PCH_PCIE_CFG_SMSCS_HPPDM > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_PCI_EXP > + } > +}; > + > +/** > + The register function used to register SMI handler of PCIE RP hotplug = event. > + > + @param[in] This The pointer to the protocol itse= lf > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[in] RpIndex Indicate the RP index (0-based) > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchPcieSmiHotPlugRegister ( > + IN PCH_PCIE_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction, > + IN UINTN RpIndex, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + UINTN RpDev; > + UINTN RpFun; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + GetPchPcieRpDevFun (RpIndex, &RpDev, &RpFun); > + // > + // Patch the RP device number and function number of srcdesc. > + // > + PchPcieSmiRpHotPlugTemplate.En[0].Reg.Data.pcie.Fields.Dev =3D (UINT8) > RpDev; > + PchPcieSmiRpHotPlugTemplate.En[0].Reg.Data.pcie.Fields.Fnc =3D (UINT8) > RpFun; > + PchPcieSmiRpHotPlugTemplate.Sts[0].Reg.Data.pcie.Fields.Dev =3D (UINT8= ) > RpDev; > + PchPcieSmiRpHotPlugTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc =3D (UINT8= ) > RpFun; > + > + Status =3D PchSmiRecordInsert ( > + &PchPcieSmiRpHotPlugTemplate, > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchPcieSmiRpHotplugType, > + DispatchHandle > + ); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gPchPcieSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + PchSmmClearSource (&PchPcieSmiRpHotPlugTemplate); > + PchSmmEnableSource (&PchPcieSmiRpHotPlugTemplate); > + > + return Status; > +} > + > +// > +// PcieRpLinkActive srcdesc > +// > +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC > PchPcieSmiRpLinkActiveTemplate =3D { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + PCIE_ADDR_TYPE, > + {R_PCH_PCIE_CFG_MPC} > + }, > + S_PCH_PCIE_CFG_MPC, > + N_PCH_PCIE_CFG_MPC_HPME > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + PCIE_ADDR_TYPE, > + {R_PCH_PCIE_CFG_SMSCS} > + }, > + S_PCH_PCIE_CFG_SMSCS, > + N_PCH_PCIE_CFG_SMSCS_HPLAS > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_PCI_EXP > + } > +}; > + > +/** > + The register function used to register SMI handler of PCIE RP link act= ive > event. > + > + @param[in] This The pointer to the protocol itse= lf > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[in] RpIndex Indicate the RP index (0-based) > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchPcieSmiLinkActiveRegister ( > + IN PCH_PCIE_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction, > + IN UINTN RpIndex, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + UINTN RpDev; > + UINTN RpFun; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + GetPchPcieRpDevFun (RpIndex, &RpDev, &RpFun); > + // > + // Patch the RP device number and function number of srcdesc. > + // > + PchPcieSmiRpLinkActiveTemplate.En[0].Reg.Data.pcie.Fields.Dev =3D (UIN= T8) > RpDev; > + PchPcieSmiRpLinkActiveTemplate.En[0].Reg.Data.pcie.Fields.Fnc =3D (UIN= T8) > RpFun; > + PchPcieSmiRpLinkActiveTemplate.Sts[0].Reg.Data.pcie.Fields.Dev =3D (UI= NT8) > RpDev; > + PchPcieSmiRpLinkActiveTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc =3D (UI= NT8) > RpFun; > + > + Status =3D PchSmiRecordInsert ( > + &PchPcieSmiRpLinkActiveTemplate, > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchPcieSmiRpLinkActiveType, > + DispatchHandle > + ); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gPchPcieSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + PchSmmClearSource (&PchPcieSmiRpLinkActiveTemplate); > + PchSmmEnableSource (&PchPcieSmiRpLinkActiveTemplate); > + > + return Status; > +} > + > +// > +// PcieRpLinkEq srcdesc > +// > +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC > PchPcieSmiRpLinkEqTemplate =3D { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + PCIE_ADDR_TYPE, > + {R_PCH_PCIE_CFG_EQCFG1} > + }, > + S_PCH_PCIE_CFG_EQCFG1, > + N_PCH_PCIE_CFG_EQCFG1_LERSMIE > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + PCIE_ADDR_TYPE, > + {R_PCH_PCIE_CFG_SMSCS} > + }, > + S_PCH_PCIE_CFG_SMSCS, > + N_PCH_PCIE_CFG_SMSCS_LERSMIS > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_PCI_EXP > + } > +}; > + > +/** > + The register function used to register SMI handler of PCIE RP Link > Equalization Request event. > + > + @param[in] This The pointer to the protocol itse= lf > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[in] RpIndex Indicate the RP index (0-based) > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchPcieSmiLinkEqRegister ( > + IN PCH_PCIE_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction, > + IN UINTN RpIndex, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + UINTN RpDev; > + UINTN RpFun; > + EFI_STATUS Status; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + GetPchPcieRpDevFun (RpIndex, &RpDev, &RpFun); > + // > + // Patch the RP device number and function number of srcdesc. > + // > + PchPcieSmiRpLinkEqTemplate.En[0].Reg.Data.pcie.Fields.Dev =3D (UINT8) > RpDev; > + PchPcieSmiRpLinkEqTemplate.En[0].Reg.Data.pcie.Fields.Fnc =3D (UINT8) > RpFun; > + PchPcieSmiRpLinkEqTemplate.Sts[0].Reg.Data.pcie.Fields.Dev =3D (UINT8) > RpDev; > + PchPcieSmiRpLinkEqTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc =3D (UINT8) > RpFun; > + > + Status =3D PchSmiRecordInsert ( > + &PchPcieSmiRpLinkEqTemplate, > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchPcieSmiRpLinkEqType, > + DispatchHandle > + ); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gPchPcieSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2) DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +/** > + Unregister a child SMI source dispatch function with a parent SMM driv= er > + > + @param[in] This Protocol instance pointer. > + @param[in] DispatchHandle Handle of dispatch function to > deregister. > + > + @retval EFI_SUCCESS The dispatch function has been > successfully > + unregistered and the SMI source = has been > disabled > + if there are no other registered= child dispatch > + functions for this SMI source. > + @retval EFI_INVALID_PARAMETER Handle is invalid. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchPcieSmiUnRegister ( > + IN PCH_PCIE_SMI_DISPATCH_PROTOCOL *This, > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + DATABASE_RECORD *RecordToDelete; > + EFI_STATUS Status; > + > + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); > + Status =3D PchSmmCoreUnRegister (NULL, DispatchHandle); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileUnregisterHandler > (&gPchPcieSmiDispatchProtocolGuid, RecordToDelete->Callback, NULL, 0); > + } > + return Status; > +} > + > +// > +// Pme srcdesc > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescPme =3D { > + PCH_SMM_SCI_EN_DEPENDENT, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_GPE0_EN_127_96} > + }, > + S_ACPI_IO_GPE0_EN_127_96, > + N_ACPI_IO_GPE0_EN_127_96_PME > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_GPE0_STS_127_96} > + }, > + S_ACPI_IO_GPE0_STS_127_96, > + N_ACPI_IO_GPE0_STS_127_96_PME > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_GPE0 > + } > +}; > + > +/** > + The register function used to register SMI handler of PME event. > + > + @param[in] This The pointer to the protocol itse= lf > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchAcpiSmiPmeRegister ( > + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D PchSmiRecordInsert ( > + &mSrcDescPme, > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchAcpiSmiPmeType, > + DispatchHandle > + ); > + PchSmmClearSource (&mSrcDescPme); > + PchSmmEnableSource (&mSrcDescPme); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +// > +// PmeB0 srcdesc > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescPmeB0 =3D { > + PCH_SMM_SCI_EN_DEPENDENT, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_GPE0_EN_127_96} > + }, > + S_ACPI_IO_GPE0_EN_127_96, > + N_ACPI_IO_GPE0_EN_127_96_PME_B0 > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_GPE0_STS_127_96} > + }, > + S_ACPI_IO_GPE0_STS_127_96, > + N_ACPI_IO_GPE0_STS_127_96_PME_B0 > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_GPE0 > + } > +}; > +/** > + The register function used to register SMI handler of PME B0 event. > + > + @param[in] This The pointer to the protocol itse= lf > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchAcpiSmiPmeB0Register ( > + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D PchSmiRecordInsert ( > + &mSrcDescPmeB0, > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchAcpiSmiPmeB0Type, > + DispatchHandle > + ); > + PchSmmClearSource (&mSrcDescPmeB0); > + PchSmmEnableSource (&mSrcDescPmeB0); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +// > +// RtcAlarm srcdesc > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescRtcAlarm =3D { > + PCH_SMM_SCI_EN_DEPENDENT, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_PM1_EN} > + }, > + S_ACPI_IO_PM1_EN, > + N_ACPI_IO_PM1_EN_RTC > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_PM1_STS} > + }, > + S_ACPI_IO_PM1_STS, > + N_ACPI_IO_PM1_STS_RTC > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_PM1_STS_REG > + } > +}; > + > +/** > + The register function used to register SMI handler of RTC alarm event. > + > + @param[in] This The pointer to the protocol itse= lf > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchAcpiSmiRtcAlarmRegister ( > + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D PchSmiRecordInsert ( > + &mSrcDescRtcAlarm, > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchAcpiSmiRtcAlarmType, > + DispatchHandle > + ); > + > + PchSmmClearSource (&mSrcDescRtcAlarm); > + PchSmmEnableSource (&mSrcDescRtcAlarm); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +// > +// TmrOverflow srcdesc > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescTmrOverflow =3D { > + PCH_SMM_SCI_EN_DEPENDENT, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_PM1_EN} > + }, > + S_ACPI_IO_PM1_EN, > + N_ACPI_IO_PM1_EN_TMROF > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_PM1_STS} > + }, > + S_ACPI_IO_PM1_STS, > + N_ACPI_IO_PM1_STS_TMROF > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_PM1_STS_REG > + } > +}; > + > +/** > + The register function used to register SMI handler of Timer Overflow e= vent. > + > + @param[in] This The pointer to the protocol itse= lf > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchAcpiSmiTmrOverflowRegister ( > + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D PchSmiRecordInsert ( > + &mSrcDescTmrOverflow, > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchAcpiSmiTmrOverflowType, > + DispatchHandle > + ); > + PchSmmClearSource (&mSrcDescTmrOverflow); > + PchSmmEnableSource (&mSrcDescTmrOverflow); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + > + return Status; > +} > + > +/** > + Unregister a child SMI source dispatch function with a parent SMM driv= er > + > + @param[in] This Protocol instance pointer. > + @param[in] DispatchHandle Handle of dispatch function to > deregister. > + > + @retval EFI_SUCCESS The dispatch function has been > successfully > + unregistered and the SMI source = has been > disabled > + if there are no other registered= child dispatch > + functions for this SMI source. > + @retval EFI_INVALID_PARAMETER Handle is invalid. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchAcpiSmiUnRegister ( > + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + DATABASE_RECORD *RecordToDelete; > + EFI_STATUS Status; > + > + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); > + Status =3D PchSmmCoreUnRegister (NULL, DispatchHandle); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileUnregisterHandler > (&gPchAcpiSmiDispatchProtocolGuid, RecordToDelete->Callback, NULL, 0); > + } > + return Status; > +} > + > +// > +// SerialIrq srcdesc > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescSerialIrq =3D { > + PCH_SMM_NO_FLAGS, > + { > + NULL_BIT_DESC_INITIALIZER, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_SERIRQ > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_SERIRQ > + } > +}; > + > +/** > + The register function used to register SMI handler of Serial IRQ event= . > + > + @param[in] This The pointer to the protocol itse= lf > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchSmiSerialIrqRegister ( > + IN PCH_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D PchSmiRecordInsert ( > + &mSrcDescSerialIrq, > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchSmiSerialIrqType, > + DispatchHandle > + ); > + PchSmmClearSource (&mSrcDescSerialIrq); > + PchSmmEnableSource (&mSrcDescSerialIrq); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +// > +// McSmi srcdesc > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescMcSmi =3D { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_EN} > + }, > + S_ACPI_IO_SMI_EN, > + N_ACPI_IO_SMI_EN_MCSMI > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_MCSMI > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_MCSMI > + } > +}; > + > +/** > + The register function used to register SMI handler of MCSMI event. > + > + @param[in] This The pointer to the protocol itse= lf > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchSmiMcSmiRegister ( > + IN PCH_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D PchSmiRecordInsert ( > + &mSrcDescMcSmi, > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchSmiMcSmiType, > + DispatchHandle > + ); > + PchSmmClearSource (&mSrcDescMcSmi); > + PchSmmEnableSource (&mSrcDescMcSmi); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +// > +// SmBus srcdesc > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescSmbus =3D { > + PCH_SMM_NO_FLAGS, > + { > + NULL_BIT_DESC_INITIALIZER, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_SMBUS > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_SMBUS > + } > +}; > + > +/** > + The register function used to register SMI handler of SMBUS event. > + > + @param[in] This The pointer to the protocol itse= lf > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchSmiSmbusRegister ( > + IN PCH_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D PchSmiRecordInsert ( > + &mSrcDescSmbus, > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchSmiSmBusType, > + DispatchHandle > + ); > + PchSmmClearSource (&mSrcDescSmbus); > + PchSmmEnableSource (&mSrcDescSmbus); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +// > +// SpiAsyncSmi srcdesc > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescSpiAsyncSmi =3D { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + PCIE_ADDR_TYPE, > + { ( > + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | > + (PCI_DEVICE_NUMBER_PCH_SPI << 19) | > + (PCI_FUNCTION_NUMBER_PCH_SPI << 16) | > + R_SPI_CFG_BC > + ) } > + }, > + S_SPI_CFG_BC, > + N_SPI_CFG_BC_ASE_BWP > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + PCIE_ADDR_TYPE, > + { ( > + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | > + (PCI_DEVICE_NUMBER_PCH_SPI << 19) | > + (PCI_FUNCTION_NUMBER_PCH_SPI << 16) | > + R_SPI_CFG_BC > + ) } > + }, > + S_SPI_CFG_BC, > + N_SPI_CFG_BC_ASYNC_SS > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_SPI > + } > +}; > + > +/** > + Special handling for SPI Asynchronous SMI. > + If SPI ASYNC SMI is enabled, De-assert SMI is sent when Flash Cycle Do= ne > + transitions from 1 to 0 or when the SMI enable becomes false. > + > + @param[in] SrcDesc Not used > +**/ > +VOID > +EFIAPI > +PchSmiSpiAsyncClearSource ( > + CONST PCH_SMM_SOURCE_DESC *SrcDesc > + ) > +{ > + UINT64 SpiRegBase; > + UINT32 SpiBar0; > + > + SpiRegBase =3D PCI_SEGMENT_LIB_ADDRESS ( > + DEFAULT_PCI_SEGMENT_NUMBER_PCH, > + DEFAULT_PCI_BUS_NUMBER_PCH, > + PCI_DEVICE_NUMBER_PCH_SPI, > + PCI_FUNCTION_NUMBER_PCH_SPI, > + 0 > + ); > + SpiBar0 =3D PciSegmentRead32 (SpiRegBase + R_SPI_CFG_BAR0) & > ~(B_SPI_CFG_BAR0_MASK); > + if (SpiBar0 !=3D PCH_SPI_BASE_ADDRESS) { > + // > + // Temporary disable MSE, and override with SPI reserved MMIO addres= s, > then enable MSE. > + // > + SpiBar0 =3D PCH_SPI_BASE_ADDRESS; > + PciSegmentAnd8 (SpiRegBase + PCI_COMMAND_OFFSET, (UINT8) > ~EFI_PCI_COMMAND_MEMORY_SPACE); > + PciSegmentWrite32 (SpiRegBase + R_SPI_CFG_BAR0, SpiBar0); > + PciSegmentOr8 (SpiRegBase + PCI_COMMAND_OFFSET, > EFI_PCI_COMMAND_MEMORY_SPACE); > + } > + > + MmioOr32 (SpiBar0 + R_SPI_MEM_HSFSC, B_SPI_MEM_HSFSC_FDONE); > +} > + > +/** > + Special handling to enable SPI Asynchronous SMI > +**/ > +VOID > +PchSmiSpiAsyncEnableSource ( > + VOID > + ) > +{ > + UINT64 SpiRegBase; > + SpiRegBase =3D PCI_SEGMENT_LIB_ADDRESS ( > + DEFAULT_PCI_SEGMENT_NUMBER_PCH, > + DEFAULT_PCI_BUS_NUMBER_PCH, > + PCI_DEVICE_NUMBER_PCH_SPI, > + PCI_FUNCTION_NUMBER_PCH_SPI, > + 0 > + ); > + PciSegmentAndThenOr32 ( > + SpiRegBase + R_SPI_CFG_BC, > + (UINT32) ~B_SPI_CFG_BC_SYNC_SS, > + B_SPI_CFG_BC_ASE_BWP > + ); > + > + // > + // Clear the source > + // > + PchSmiSpiAsyncClearSource (NULL); > +} > + > +/** > + The register function used to register SMI handler of SPI Asynchronous > event. > + > + @param[in] This The pointer to the protocol itse= lf > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchSmiSpiAsyncRegister ( > + IN PCH_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + DATABASE_RECORD *Record; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D PchSmiRecordInsert ( > + &mSrcDescSpiAsyncSmi, > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchSmiSpiAsyncType, > + DispatchHandle > + ); > + > + if (!EFI_ERROR (Status)) { > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); > + Record->ClearSource =3D PchSmiSpiAsyncClearSource; > + PchSmiSpiAsyncClearSource (NULL); > + PchSmiSpiAsyncEnableSource (); > + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +/** > + Unregister a child SMI source dispatch function with a parent SMM driv= er > + > + @param[in] This Protocol instance pointer. > + @param[in] DispatchHandle Handle of dispatch function to > deregister. > + > + @retval EFI_SUCCESS The dispatch function has been > successfully > + unregistered and the SMI source = has been > disabled > + if there are no other registered= child dispatch > + functions for this SMI source. > + @retval EFI_INVALID_PARAMETER Handle is invalid. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval EFI_ACCESS_DENIED Return access denied since SPI a= ync > SMI handler is not able to disabled. > +**/ > +EFI_STATUS > +EFIAPI > +PchSmiUnRegister ( > + IN PCH_SMI_DISPATCH_PROTOCOL *This, > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + DATABASE_RECORD *Record; > + UINT64 SpiRegBase; > + EFI_STATUS Status; > + > + Record =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); > + if ((Record->SrcDesc.En[0].Reg.Type =3D=3D PCIE_ADDR_TYPE) && > + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Dev =3D=3D > PCI_DEVICE_NUMBER_PCH_SPI) && > + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Fnc =3D=3D > PCI_FUNCTION_NUMBER_PCH_SPI) && > + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Reg =3D=3D R_SPI_CFG_B= C) && > + (Record->SrcDesc.En[0].Bit =3D=3D N_SPI_CFG_BC_ASE_BWP)) { > + SpiRegBase =3D PCI_SEGMENT_LIB_ADDRESS ( > + DEFAULT_PCI_SEGMENT_NUMBER_PCH, > + DEFAULT_PCI_BUS_NUMBER_PCH, > + PCI_DEVICE_NUMBER_PCH_SPI, > + PCI_FUNCTION_NUMBER_PCH_SPI, > + 0 > + ); > + if (PciSegmentRead8 (SpiRegBase + R_SPI_CFG_BC) & B_SPI_CFG_BC_BILD) > { > + // > + // SPI Asynchronous SMI cannot be disabled > + // > + return EFI_ACCESS_DENIED; > + } > + } > + Status =3D PchSmmCoreUnRegister (NULL, DispatchHandle); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileUnregisterHandler (&gPchSmiDispatchProtocolGuid, > Record->Callback, NULL, 0); > + } > + return Status; > +} > + > + > +/** > + Declaration of PCH TCO SMI DISPATCH PROTOCOL instance > +**/ > +PCH_TCO_SMI_DISPATCH_PROTOCOL mPchTcoSmiDispatchProtocol =3D { > + PCH_TCO_SMI_DISPATCH_REVISION, // Revision > + PchTcoSmiUnRegister, // Unregister > + PchTcoSmiMchRegister, // Mch > + PchTcoSmiTcoTimeoutRegister, // TcoTimeout > + PchTcoSmiOsTcoRegister, // OsTco > + PchTcoSmiNmiRegister, // Nmi > + PchTcoSmiIntruderDetRegister, // IntruderDectect > + PchTcoSmiSpiBiosWpRegister, // SpiBiosWp > + PchTcoSmiLpcBiosWpRegister, // LpcBiosWp > + PchTcoSmiNewCenturyRegister // NewCentury > +}; > + > +/** > + Declaration of PCH PCIE SMI DISPATCH PROTOCOL instance > +**/ > +PCH_PCIE_SMI_DISPATCH_PROTOCOL mPchPcieSmiDispatchProtocol =3D { > + PCH_PCIE_SMI_DISPATCH_REVISION, // Revision > + PchPcieSmiUnRegister, // Unregister > + PchPcieSmiHotPlugRegister, // PcieRpXHotPlug > + PchPcieSmiLinkActiveRegister, // PcieRpXLinkActive > + PchPcieSmiLinkEqRegister // PcieRpXLinkEq > +}; > + > +/** > + Declaration of PCH ACPI SMI DISPATCH PROTOCOL instance > +**/ > +PCH_ACPI_SMI_DISPATCH_PROTOCOL mPchAcpiSmiDispatchProtocol =3D { > + PCH_ACPI_SMI_DISPATCH_REVISION, // Revision > + PchAcpiSmiUnRegister, // Unregister > + PchAcpiSmiPmeRegister, // Pme > + PchAcpiSmiPmeB0Register, // PmeB0 > + PchAcpiSmiRtcAlarmRegister, // RtcAlarm > + PchAcpiSmiTmrOverflowRegister // TmrOverflow > +}; > + > +/** > + Declaration of MISC PCH SMI DISPATCH PROTOCOL instance > +**/ > +PCH_SMI_DISPATCH_PROTOCOL mPchSmiDispatchProtocol =3D { > + PCH_SMI_DISPATCH_REVISION, // Revision > + PchSmiUnRegister, // Unregister > + PchSmiSerialIrqRegister, // SerialIrq > + PchSmiMcSmiRegister, // McSmi > + PchSmiSmbusRegister, // SmBus > + PchSmiSpiAsyncRegister // SpiAsync > +}; > + > +/** > + Install protocols of PCH specifics SMI types, including > + PCH TCO SMI types, PCH PCIE SMI types, PCH ACPI SMI types, PCH MISC SM= I > types. > + > + @retval the result of protocol installat= ion > +**/ > +EFI_STATUS > +InstallPchSmiDispatchProtocols ( > + VOID > + ) > +{ > + EFI_HANDLE Handle; > + EFI_STATUS Status; > + > + Handle =3D NULL; > + Status =3D gSmst->SmmInstallProtocolInterface ( > + &Handle, > + &gPchTcoSmiDispatchProtocolGuid, > + EFI_NATIVE_INTERFACE, > + &mPchTcoSmiDispatchProtocol > + ); > + Status =3D gSmst->SmmInstallProtocolInterface ( > + &Handle, > + &gPchPcieSmiDispatchProtocolGuid, > + EFI_NATIVE_INTERFACE, > + &mPchPcieSmiDispatchProtocol > + ); > + Status =3D gSmst->SmmInstallProtocolInterface ( > + &Handle, > + &gPchAcpiSmiDispatchProtocolGuid, > + EFI_NATIVE_INTERFACE, > + &mPchAcpiSmiDispatchProtocol > + ); > + Status =3D gSmst->SmmInstallProtocolInterface ( > + &Handle, > + &gPchSmiDispatchProtocolGuid, > + EFI_NATIVE_INTERFACE, > + &mPchSmiDispatchProtocol > + ); > + > + return Status; > +} > + > +/** > + The function to dispatch all callback function of PCH SMI types. > + > + @retval EFI_SUCCESS Function successfully completed > + @retval EFI_UNSUPPORTED no > +**/ > +EFI_STATUS > +PchSmiTypeCallbackDispatcher ( > + IN DATABASE_RECORD *Record > + ) > +{ > + EFI_STATUS Status; > + PCH_SMI_TYPES PchSmiType; > + UINTN RpIndex; > + PCH_PCIE_SMI_RP_CONTEXT RpContext; > + > + PchSmiType =3D Record->PchSmiType; > + Status =3D EFI_SUCCESS; > + > + switch (PchSmiType) { > + case PchTcoSmiMchType: > + case PchTcoSmiTcoTimeoutType: > + case PchTcoSmiOsTcoType: > + case PchTcoSmiNmiType: > + case PchTcoSmiIntruderDetectType: > + case PchTcoSmiSpiBiosWpType: > + case PchTcoSmiLpcBiosWpType: > + case PchTcoSmiNewCenturyType: > + ((PCH_TCO_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) > ((EFI_HANDLE)&Record->Link); > + break; > + case PchPcieSmiRpHotplugType: > + case PchPcieSmiRpLinkActiveType: > + case PchPcieSmiRpLinkEqType: > + RpContext.BusNum =3D DEFAULT_PCI_BUS_NUMBER_PCH; > + RpContext.DevNum =3D (UINT8) > Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Dev; > + RpContext.FuncNum =3D (UINT8) > Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Fnc; > + GetPchPcieRpNumber (RpContext.DevNum, RpContext.FuncNum, > &RpIndex); > + RpContext.RpIndex =3D (UINT8) RpIndex; > + ((PCH_PCIE_SMI_RP_DISPATCH_CALLBACK) (Record->PchSmiCallback)) > ((EFI_HANDLE)&Record->Link, &RpContext); > + break; > + case PchAcpiSmiPmeType: > + case PchAcpiSmiPmeB0Type: > + case PchAcpiSmiRtcAlarmType: > + case PchAcpiSmiTmrOverflowType: > + ((PCH_ACPI_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) > ((EFI_HANDLE)&Record->Link); > + break; > + case PchEspiSmiEspiSlaveType: > + ((PCH_ESPI_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) > ((EFI_HANDLE)&Record->Link); > + break; > + case PchSmiSerialIrqType: > + case PchSmiMcSmiType: > + case PchSmiSmBusType: > + case PchSmiSpiAsyncType: > + case PchIoTrapSmiType: ///< internal type for IoTrap > + ((PCH_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) > ((EFI_HANDLE)&Record->Link); > + break; > + default: > + Status =3D EFI_UNSUPPORTED; > + break; > + } > + > + return Status; > +} > + > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescIoTrap[4] =3D { > + // > + // PCH I/O Trap register 0 monitor > + // > + { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + PCR_ADDR_TYPE, > + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG0) } > + }, > + 4, > + 0 > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + PCR_ADDR_TYPE, > + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) } > + }, > + 1, > + 0 > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_MONITOR > + } > + }, > + // > + // PCH I/O Trap register 1 monitor > + // > + { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + PCR_ADDR_TYPE, > + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG1) } > + }, > + 4, > + 0 > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + PCR_ADDR_TYPE, > + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) } > + }, > + 1, > + 1 > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_MONITOR > + } > + }, > + // > + // PCH I/O Trap register 2 monitor > + // > + { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + PCR_ADDR_TYPE, > + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG2) } > + }, > + 4, > + 0 > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + PCR_ADDR_TYPE, > + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) } > + }, > + 1, > + 2 > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_MONITOR > + } > + }, > + // > + // PCH I/O Trap register 3 monitor, > + // > + { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + PCR_ADDR_TYPE, > + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG3) } > + }, > + 4, > + 0 > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + PCR_ADDR_TYPE, > + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) } > + }, > + 1, > + 3 > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_MONITOR > + } > + } > +}; > + > +/** > + The register function used to register SMI handler of IoTrap event. > + This is internal function and only used by Iotrap module. > + > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source > + @param[in] IoTrapIndex Index number of IOTRAP register > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > +**/ > +EFI_STATUS > +PchInternalIoTrapSmiRegister ( > + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, > + IN UINTN IoTrapIndex, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + > + Status =3D PchSmiRecordInsert ( > + &mSrcDescIoTrap[IoTrapIndex], > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchIoTrapSmiType, > + DispatchHandle > + ); > + PchSmmClearSource (&mSrcDescIoTrap[IoTrapIndex]); > + PchSmmEnableSource (&mSrcDescIoTrap[IoTrapIndex]); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler > (&gEfiSmmIoTrapDispatch2ProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +/** > + Unregister a child SMI source dispatch function with a parent SMM driv= er > + > + @param[in] DispatchHandle Handle of dispatch function to > deregister. > + > + @retval EFI_SUCCESS The dispatch function has been > successfully > + unregistered and the SMI source = has been > disabled > + if there are no other registered= child dispatch > + functions for this SMI source. > + @retval EFI_INVALID_PARAMETER Handle is invalid. > +**/ > +EFI_STATUS > +PchInternalIoTrapSmiUnRegister ( > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + DATABASE_RECORD *RecordToDelete; > + EFI_STATUS Status; > + > + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); > + Status =3D PchSmmCoreUnRegister (NULL, DispatchHandle); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileUnregisterHandler > (&gEfiSmmIoTrapDispatch2ProtocolGuid, RecordToDelete->Callback, NULL, 0); > + } > + return Status; > +} > diff --git > a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCo > re.c > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCo > re.c > new file mode 100644 > index 0000000000..9c36103396 > --- /dev/null > +++ > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCo > re.c > @@ -0,0 +1,911 @@ > +/** @file > + This driver is responsible for the registration of child drivers > + and the abstraction of the PCH SMI sources. > + > + Copyright (c) 2019 Intel Corporation. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#include "PchSmm.h" > +#include "PchSmmHelpers.h" > +#include "PchSmmEspi.h" > +#include > +#include > +#include > +#include > + > +// > +// MODULE / GLOBAL DATA > +// > +// Module variables used by the both the main dispatcher and the source > dispatchers > +// Declared in PchSmm.h > +// > +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mAcpiBaseAddr; > +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mTcoBaseAddr; > +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mReadyToLock; > + > +GLOBAL_REMOVE_IF_UNREFERENCED PRIVATE_DATA mPrivateData =3D { > + { > + NULL, > + NULL > + }, // CallbackDataBase linked list = head > + NULL, // EFI handle returned when call= ing > InstallMultipleProtocolInterfaces > + NULL, // > + { // protocol arrays > + // > + // elements within the array > + // > + { > + PROTOCOL_SIGNATURE, > + UsbType, > + &gEfiSmmUsbDispatch2ProtocolGuid, > + {{ > + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister, > + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister > + }} > + }, > + { > + PROTOCOL_SIGNATURE, > + SxType, > + &gEfiSmmSxDispatch2ProtocolGuid, > + {{ > + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister, > + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister > + }} > + }, > + { > + PROTOCOL_SIGNATURE, > + SwType, > + &gEfiSmmSwDispatch2ProtocolGuid, > + {{ > + (PCH_SMM_GENERIC_REGISTER) PchSwSmiRegister, > + (PCH_SMM_GENERIC_UNREGISTER) PchSwSmiUnRegister, > + (UINTN) MAXIMUM_SWI_VALUE > + }} > + }, > + { > + PROTOCOL_SIGNATURE, > + GpiType, > + &gEfiSmmGpiDispatch2ProtocolGuid, > + {{ > + (PCH_SMM_GENERIC_REGISTER) PchGpiSmiRegister, > + (PCH_SMM_GENERIC_UNREGISTER) PchGpiSmiUnRegister, > + (UINTN) PCH_GPIO_NUM_SUPPORTED_GPIS > + }} > + }, > + { > + PROTOCOL_SIGNATURE, > + PowerButtonType, > + &gEfiSmmPowerButtonDispatch2ProtocolGuid, > + {{ > + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister, > + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister > + }} > + }, > + { > + PROTOCOL_SIGNATURE, > + PeriodicTimerType, > + &gEfiSmmPeriodicTimerDispatch2ProtocolGuid, > + {{ > + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister, > + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister, > + (UINTN) PchSmmPeriodicTimerDispatchGetNextShorterInterval > + }} > + }, > + } > +}; > + > +GLOBAL_REMOVE_IF_UNREFERENCED CONTEXT_FUNCTIONS > mContextFunctions[PCH_SMM_PROTOCOL_TYPE_MAX] =3D { > + { > + NULL, > + NULL, > + NULL > + }, > + { > + SxGetContext, > + SxCmpContext, > + NULL > + }, > + { > + NULL, > + NULL, > + NULL > + }, > + { > + NULL, > + NULL, > + NULL > + }, > + { > + PowerButtonGetContext, > + PowerButtonCmpContext, > + NULL > + }, > + { > + PeriodicTimerGetContext, > + PeriodicTimerCmpContext, > + PeriodicTimerGetCommBuffer > + }, > +}; > + > +// > +// PROTOTYPES > +// > +// Functions use only in this file > +// > +EFI_STATUS > +EFIAPI > +PchSmmCoreDispatcher ( > + IN EFI_HANDLE SmmImageHandle, > + IN CONST VOID *PchSmmCore, OPTIONAL > + IN OUT VOID *CommunicationBuffer, > + IN OUT UINTN *SourceSize > + ); > + > +// > +// FUNCTIONS > +// > +/** > + SMM ready to lock notification event handler. > + > + @param Protocol Points to the protocol's unique identifier > + @param Interface Points to the interface instance > + @param Handle The handle on which the interface was installed > + > + @retval EFI_SUCCESS SmmReadyToLockCallback runs successfully > + > +**/ > +EFI_STATUS > +EFIAPI > +SmmReadyToLockCallback ( > + IN CONST EFI_GUID *Protocol, > + IN VOID *Interface, > + IN EFI_HANDLE Handle > + ) > +{ > + mReadyToLock =3D TRUE; > + > + return EFI_SUCCESS; > +} > + > +/** > + PchSmiDispatcher SMM Module Entry Point\n > + - Introduction\n > + The PchSmiDispatcher module is an SMM driver which provides SMI > handler registration > + services for PCH generated SMIs. > + > + - Details\n > + This module provides SMI handler registration servicies for PCH SMIs= . > + NOTE: All the register/unregister functions will be locked after SMM= ready > to boot signal event. > + Please make sure no handler is installed after that. > + > + - @pre > + - EFI_SMM_BASE2_PROTOCOL > + - Documented in the System Management Mode Core Interface > Specification > + - EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL > + - Documented in the UEFI 2.0 Specification and above > + - EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL > + - This is to ensure that PCI MMIO and IO resource has been prepare= d and > available for this driver to allocate. > + - EFI_SMM_CPU_PROTOCOL > + > + - @result > + The PchSmiDispatcher driver produces: > + - EFI_SMM_USB_DISPATCH2_PROTOCOL > + - EFI_SMM_SX_DISPATCH2_PROTOCOL > + - EFI_SMM_SW_DISPATCH2_PROTOCOL > + - EFI_SMM_GPI_DISPATCH2_PROTOCOL > + - EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL > + - EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL > + - EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL > + - @link _PCH_SMM_IO_TRAP_CONTROL_PROTOCOL > PCH_SMM_IO_TRAP_CONTROL_PROTOCOL @endlink > + - @link _PCH_PCIE_SMI_DISPATCH_PROTOCOL > PCH_PCIE_SMI_DISPATCH_PROTOCOL @endlink > + - @link _PCH_TCO_SMI_DISPATCH_PROTOCOL > PCH_TCO_SMI_DISPATCH_PROTOCOL @endlink > + - @link _PCH_ACPI_SMI_DISPATCH_PROTOCOL > PCH_ACPI_SMI_DISPATCH_PROTOCOL @endlink > + - @link _PCH_SMI_DISPATCH_PROTOCOL PCH_SMI_DISPATCH_PROTOCOL > @endlink > + - @link _PCH_ESPI_SMI_DISPATCH_PROTOCOL > PCH_ESPI_SMI_DISPATCH_PROTOCOL @endlink > + > + @param[in] ImageHandle Pointer to the loaded image protocol f= or > this driver > + @param[in] SystemTable Pointer to the EFI System Table > + > + @retval EFI_SUCCESS PchSmmDispatcher Initialization comple= ted. > +**/ > +EFI_STATUS > +EFIAPI > +InitializePchSmmDispatcher ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + EFI_STATUS Status; > + VOID *SmmReadyToLockRegistration; > + > + // > + // Access ACPI Base Addresses Register > + // > + > + mAcpiBaseAddr =3D PmcGetAcpiBase (); > + ASSERT (mAcpiBaseAddr !=3D 0); > + > + // > + // Access TCO Base Addresses Register > + // > + PchTcoBaseGet (&mTcoBaseAddr); > + ASSERT (mTcoBaseAddr !=3D 0); > + > + > + // > + // Register a callback function to handle subsequent SMIs. This callb= ack > + // will be called by SmmCoreDispatcher. > + // > + Status =3D gSmst->SmiHandlerRegister (PchSmmCoreDispatcher, NULL, > &mPrivateData.SmiHandle); > + ASSERT_EFI_ERROR (Status); > + // > + // Initialize Callback DataBase > + // > + InitializeListHead (&mPrivateData.CallbackDataBase); > + > + // > + // Enable SMIs on the PCH now that we have a callback > + // > + PchSmmInitHardware (); > + > + // > + // Install and initialize all the needed protocols > + // > + PchSwDispatchInit (); > + PchSmmPublishDispatchProtocols (); > + InstallPchSmiDispatchProtocols (); > + InstallIoTrap (ImageHandle); > + InstallEspiSmi (ImageHandle); > + InstallPchSmmPeriodicTimerControlProtocol > (mPrivateData.InstallMultProtHandle); > + > + // > + // Register EFI_SMM_READY_TO_LOCK_PROTOCOL_GUID notify function. > + // > + Status =3D gSmst->SmmRegisterProtocolNotify ( > + &gEfiSmmReadyToLockProtocolGuid, > + SmmReadyToLockCallback, > + &SmmReadyToLockRegistration > + ); > + ASSERT_EFI_ERROR (Status); > + > + return EFI_SUCCESS; > +} > + > +/** > + The internal function used to create and insert a database record > + > + @param[in] InsertRecord Record to insert to database. > + @param[out] DispatchHandle Handle of dispatch function to > register. > + > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record > + @retval EFI_SUCCESS The database record is created > successfully. > +**/ > +EFI_STATUS > +SmmCoreInsertRecord ( > + IN DATABASE_RECORD *NewRecord, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + DATABASE_RECORD *Record; > + > + if ((NewRecord =3D=3D NULL) || > + (NewRecord->Signature !=3D DATABASE_RECORD_SIGNATURE)) > + { > + ASSERT (FALSE); > + return EFI_INVALID_PARAMETER; > + } > + > + Status =3D gSmst->SmmAllocatePool (EfiRuntimeServicesData, sizeof > (DATABASE_RECORD), (VOID **) &Record); > + if (EFI_ERROR (Status)) { > + ASSERT (FALSE); > + return EFI_OUT_OF_RESOURCES; > + } > + CopyMem (Record, NewRecord, sizeof (DATABASE_RECORD)); > + > + // > + // After ensuring the source of event is not null, we will insert the = record into > the database > + // > + InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); > + > + // > + // Child's handle will be the address linked list link in the record > + // > + *DispatchHandle =3D (EFI_HANDLE) (&Record->Link); > + > + return EFI_SUCCESS; > +} > + > +/** > + Unregister a child SMI source dispatch function with a parent SMM driv= er > + > + @param[in] This Protocol instance pointer. > + @param[in] DispatchHandle Handle of dispatch function to > deregister. > + > + @retval EFI_SUCCESS The dispatch function has been > successfully > + unregistered and the SMI source = has been > disabled > + if there are no other registered= child dispatch > + functions for this SMI source. > + @retval EFI_INVALID_PARAMETER Handle is invalid. > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > +**/ > +EFI_STATUS > +EFIAPI > +PchPiSmmCoreUnRegister ( > + IN PCH_SMM_GENERIC_PROTOCOL *This, > + IN EFI_HANDLE *DispatchHandle > + ) > +{ > + DATABASE_RECORD *RecordToDelete; > + EFI_STATUS Status; > + PCH_SMM_QUALIFIED_PROTOCOL *Qualified; > + > + Qualified =3D QUALIFIED_PROTOCOL_FROM_GENERIC (This); > + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); > + Status =3D PchSmmCoreUnRegister (NULL, DispatchHandle); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileUnregisterHandler (Qualified->Guid, > RecordToDelete->Callback, NULL, 0); > + } > + return Status; > +} > + > +/** > + Register a child SMI dispatch function with a parent SMM driver. > + > + @param[in] This Pointer to the > PCH_SMM_GENERIC_PROTOCOL instance. > + @param[in] DispatchFunction Pointer to dispatch function to be > invoked for this SMI source. > + @param[in] DispatchContext Pointer to the dispatch function's > context. > + @param[out] DispatchHandle Handle of dispatch function, for when > interfacing > + with the parent SMM driver, will be th= e address of > linked > + list link in the call back record. > + > + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create > database record > + @retval EFI_INVALID_PARAMETER The input parameter is invalid > + @retval EFI_SUCCESS The dispatch function has been success= fully > + registered and the SMI source has been= enabled. > +**/ > +EFI_STATUS > +EFIAPI > +PchPiSmmCoreRegister ( > + IN PCH_SMM_GENERIC_PROTOCOL *This, > + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction= , > + IN PCH_SMM_CONTEXT *DispatchContext= , > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + DATABASE_RECORD Record; > + PCH_SMM_QUALIFIED_PROTOCOL *Qualified; > + PCH_SMM_SOURCE_DESC NullSourceDesc; > + > + // > + // Initialize NullSourceDesc > + // > + NullInitSourceDesc (&NullSourceDesc); > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the EndOfDxe event > has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + ZeroMem (&Record, sizeof (DATABASE_RECORD)); > + > + // > + // Gather information about the registration request > + // > + Record.Callback =3D DispatchFunction; > + > + Qualified =3D QUALIFIED_PROTOCOL_FROM_GENERIC (This); > + > + Record.ProtocolType =3D Qualified->Type; > + > + Record.ContextFunctions =3D mContextFunctions[Qualified->Type]; > + // > + // Perform linked list housekeeping > + // > + Record.Signature =3D DATABASE_RECORD_SIGNATURE; > + > + switch (Qualified->Type) { > + // > + // By the end of this switch statement, we'll know the > + // source description the child is registering for > + // > + case UsbType: > + Record.ContextSize =3D sizeof (EFI_SMM_USB_REGISTER_CONTEXT); > + CopyMem (&Record.ChildContext, DispatchContext, > Record.ContextSize); > + // > + // Check the validity of Context Type > + // > + if ((Record.ChildContext.Usb.Type < UsbLegacy) || > (Record.ChildContext.Usb.Type > UsbWake)) { > + return EFI_INVALID_PARAMETER; > + } > + > + MapUsbToSrcDesc (DispatchContext, &Record.SrcDesc); > + Record.ClearSource =3D NULL; > + // > + // use default clear source function > + // > + break; > + > + case SxType: > + Record.ContextSize =3D sizeof (EFI_SMM_SX_REGISTER_CONTEXT); > + CopyMem (&Record.ChildContext, DispatchContext, > Record.ContextSize); > + // > + // Check the validity of Context Type and Phase > + // > + if ((Record.ChildContext.Sx.Type < SxS0) || > + (Record.ChildContext.Sx.Type >=3D EfiMaximumSleepType) || > + (Record.ChildContext.Sx.Phase < SxEntry) || > + (Record.ChildContext.Sx.Phase >=3D EfiMaximumPhase) > + ) { > + return EFI_INVALID_PARAMETER; > + } > + > + CopyMem (&Record.SrcDesc, &mSxSourceDesc, sizeof > (PCH_SMM_SOURCE_DESC)); > + Record.ClearSource =3D NULL; > + // > + // use default clear source function > + // > + break; > + > + case PowerButtonType: > + Record.ContextSize =3D sizeof > (EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT); > + CopyMem (&Record.ChildContext, DispatchContext, > Record.ContextSize); > + // > + // Check the validity of Context Phase > + // > + if ((Record.ChildContext.PowerButton.Phase < EfiPowerButtonEntry) = || > + (Record.ChildContext.PowerButton.Phase > EfiPowerButtonExit)) > + { > + return EFI_INVALID_PARAMETER; > + } > + > + CopyMem (&Record.SrcDesc, &mPowerButtonSourceDesc, sizeof > (PCH_SMM_SOURCE_DESC)); > + Record.ClearSource =3D NULL; > + // > + // use default clear source function > + // > + break; > + > + case PeriodicTimerType: > + Record.ContextSize =3D sizeof > (EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT); > + CopyMem (&Record.ChildContext, DispatchContext, > Record.ContextSize); > + // > + // Check the validity of timer value > + // > + if (DispatchContext->PeriodicTimer.SmiTickInterval <=3D 0) { > + return EFI_INVALID_PARAMETER; > + } > + > + MapPeriodicTimerToSrcDesc (DispatchContext, &Record.SrcDesc); > + Record.ClearSource =3D PchSmmPeriodicTimerClearSource; > + break; > + > + default: > + return EFI_INVALID_PARAMETER; > + break; > + } > + > + if (CompareSources (&Record.SrcDesc, &NullSourceDesc)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // After ensuring the source of event is not null, we will insert the = record into > the database > + // Child's handle will be the address linked list link in the record > + // > + Status =3D SmmCoreInsertRecord ( > + &Record, > + DispatchHandle > + ); > + ASSERT_EFI_ERROR (Status); > + > + if (Record.ClearSource =3D=3D NULL) { > + // > + // Clear the SMI associated w/ the source using the default function > + // > + PchSmmClearSource (&Record.SrcDesc); > + } else { > + // > + // This source requires special handling to clear > + // > + Record.ClearSource (&Record.SrcDesc); > + } > + > + PchSmmEnableSource (&Record.SrcDesc); > + SmiHandlerProfileRegisterHandler (Qualified->Guid, DispatchFunction, > (UINTN)RETURN_ADDRESS (0), DispatchContext, Record.ContextSize); > + > + return EFI_SUCCESS; > +} > + > +/** > + Unregister a child SMI source dispatch function with a parent SMM driv= er. > + > + @param[in] This Pointer to the > PCH_SMM_GENERIC_PROTOCOL instance. > + @param[in] DispatchHandle Handle of dispatch function to deregis= ter. > + > + @retval EFI_SUCCESS The dispatch function has been success= fully > + unregistered and the SMI source has be= en disabled > + if there are no other registered child= dispatch > + functions for this SMI source. > + @retval EFI_INVALID_PARAMETER Handle is invalid. > +**/ > +EFI_STATUS > +EFIAPI > +PchSmmCoreUnRegister ( > + IN PCH_SMM_GENERIC_PROTOCOL *This, > + IN EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + BOOLEAN NeedClearEnable; > + UINTN DescIndex; > + DATABASE_RECORD *RecordToDelete; > + DATABASE_RECORD *RecordInDb; > + LIST_ENTRY *LinkInDb; > + > + if (DispatchHandle =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the > SmmReadyToLock event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); > + > + // > + // Take the entry out of the linked list > + // > + if (RecordToDelete->Link.ForwardLink =3D=3D (LIST_ENTRY *) EFI_BAD_POI= NTER) > { > + return EFI_INVALID_PARAMETER; > + } > + > + RemoveEntryList (&RecordToDelete->Link); > + > + // > + // Loop through all the souces in record linked list to see if any sou= rce enable > is equal. > + // If any source enable is equal, we do not want to disable it. > + // > + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; ++DescIndex) { > + if (IS_BIT_DESC_NULL (RecordToDelete->SrcDesc.En[DescIndex])) { > + continue; > + } > + NeedClearEnable =3D TRUE; > + LinkInDb =3D GetFirstNode (&mPrivateData.CallbackDataBase); > + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { > + RecordInDb =3D DATABASE_RECORD_FROM_LINK (LinkInDb); > + if (IsBitEqualToAnySourceEn (&RecordToDelete->SrcDesc.En[DescIndex= ], > &RecordInDb->SrcDesc)) { > + NeedClearEnable =3D FALSE; > + break; > + } > + LinkInDb =3D GetNextNode (&mPrivateData.CallbackDataBase, > &RecordInDb->Link); > + } > + if (NeedClearEnable =3D=3D FALSE) { > + continue; > + } > + WriteBitDesc (&RecordToDelete->SrcDesc.En[DescIndex], 0, FALSE); > + } > + Status =3D gSmst->SmmFreePool (RecordToDelete); > + if (EFI_ERROR (Status)) { > + ASSERT (FALSE); > + return Status; > + } > + return EFI_SUCCESS; > +} > + > +/** > + This function clears the pending SMI status before set EOS. > + NOTE: This only clears the pending SMI with known reason. > + Please do not clear unknown pending SMI status since that will h= ide > potential issues. > + > + @param[in] SmiStsValue SMI status > + @param[in] SciEn Sci Enable status > +**/ > +STATIC > +VOID > +ClearPendingSmiStatus ( > + UINT32 SmiStsValue, > + BOOLEAN SciEn > + ) > +{ > + // > + // Clear NewCentury status if it's not handled. > + // > + if (SmiStsValue & B_ACPI_IO_SMI_STS_TCO) { > + if (IoRead16 (mTcoBaseAddr + R_TCO_IO_TCO1_STS) & > B_TCO_IO_TCO1_STS_NEWCENTURY) { > + PchTcoSmiClearSourceAndBlock (&mSrcDescNewCentury); > + } > + } > + // Clear PWRBTNOR_STS if it's not handled. > + // > + if (IoRead16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS) & > B_ACPI_IO_PM1_STS_PRBTNOR) { > + IoWrite16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS, > B_ACPI_IO_PM1_STS_PRBTNOR); > + } > + // > + // Clear WADT_STS if this is triggered by WADT timer. > + // > + if (!SciEn) { > + if ((IoRead32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_EN_127_96) & > B_ACPI_IO_GPE0_EN_127_96_WADT) && > + (IoRead32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96) & > B_ACPI_IO_GPE0_STS_127_96_WADT)) { > + IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96, > B_ACPI_IO_GPE0_STS_127_96_WADT); > + } > + } > + // > + // Clear GPIO_UNLOCK_SMI_STS in case it is set as GPIO Unlock SMI is n= ot > supported > + // > + if (SmiStsValue & B_ACPI_IO_SMI_STS_GPIO_UNLOCK) { > + IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_SMI_STS, > B_ACPI_IO_SMI_STS_GPIO_UNLOCK); > + } > +} > + > +/** > + The callback function to handle subsequent SMIs. This callback will b= e > called by SmmCoreDispatcher. > + > + @param[in] SmmImageHandle Not used > + @param[in] PchSmmCore Not used > + @param[in, out] CommunicationBuffer Not used > + @param[in, out] SourceSize Not used > + > + @retval EFI_SUCCESS Function successfully completed > +**/ > +EFI_STATUS > +EFIAPI > +PchSmmCoreDispatcher ( > + IN EFI_HANDLE SmmImageHandle, > + IN CONST VOID *PchSmmCore, > + IN OUT VOID *CommunicationBuffer, > + IN OUT UINTN *SourceSize > + ) > +{ > + // > + // Used to prevent infinite loops > + // > + UINTN EscapeCount; > + > + BOOLEAN ContextsMatch; > + BOOLEAN EosSet; > + BOOLEAN SxChildWasDispatched; > + > + DATABASE_RECORD *RecordInDb; > + LIST_ENTRY *LinkInDb; > + DATABASE_RECORD *RecordToExhaust; > + LIST_ENTRY *LinkToExhaust; > + > + PCH_SMM_CONTEXT Context; > + VOID *CommBuffer; > + UINTN CommBufferSize; > + > + EFI_STATUS Status; > + BOOLEAN SciEn; > + UINT32 SmiEnValue; > + UINT32 SmiStsValue; > + UINT8 Port74Save; > + UINT8 Port76Save; > + > + PCH_SMM_SOURCE_DESC ActiveSource; > + > + // > + // Initialize ActiveSource > + // > + NullInitSourceDesc (&ActiveSource); > + > + EscapeCount =3D 3; > + ContextsMatch =3D FALSE; > + EosSet =3D FALSE; > + SxChildWasDispatched =3D FALSE; > + Status =3D EFI_SUCCESS; > + > + // > + // Save IO index registers > + // @note: Save/Restore port 70h directly might break NMI_EN# setting, > + // then save/restore 74h/76h instead. > + // @note: CF8 is not saved. Prefer method is to use MMIO instead of CF= 8 > + // > + Port76Save =3D IoRead8 (R_RTC_IO_EXT_INDEX_ALT); > + Port74Save =3D IoRead8 (R_RTC_IO_INDEX_ALT); > + > + if (!IsListEmpty (&mPrivateData.CallbackDataBase)) { > + // > + // We have children registered w/ us -- continue > + // > + while ((!EosSet) && (EscapeCount > 0)) { > + EscapeCount--; > + > + LinkInDb =3D GetFirstNode (&mPrivateData.CallbackDataBase); > + > + // > + // Cache SciEn, SmiEnValue and SmiStsValue to determine if source = is > active > + // > + SciEn =3D PchSmmGetSciEn (); > + SmiEnValue =3D IoRead32 ((UINTN) (mAcpiBaseAddr + > R_ACPI_IO_SMI_EN)); > + SmiStsValue =3D IoRead32 ((UINTN) (mAcpiBaseAddr + > R_ACPI_IO_SMI_STS)); > + > + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { > + RecordInDb =3D DATABASE_RECORD_FROM_LINK (LinkInDb); > + > + // > + // look for the first active source > + // > + if (!SourceIsActive (&RecordInDb->SrcDesc, SciEn, SmiEnValue, > SmiStsValue)) { > + // > + // Didn't find the source yet, keep looking > + // > + LinkInDb =3D GetNextNode (&mPrivateData.CallbackDataBase, > &RecordInDb->Link); > + > + // > + // if it's the last one, try to clear EOS > + // > + if (IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { > + // > + // Clear pending SMI status before EOS > + // > + ClearPendingSmiStatus (SmiStsValue, SciEn); > + EosSet =3D PchSmmSetAndCheckEos (); > + } > + } else { > + // > + // We found a source. If this is a sleep type, we have to go t= o > + // appropriate sleep state anyway.No matter there is sleep chi= ld or > not > + // > + if (RecordInDb->ProtocolType =3D=3D SxType) { > + SxChildWasDispatched =3D TRUE; > + } > + // > + // "cache" the source description and don't query I/O anymore > + // > + CopyMem ((VOID *) &ActiveSource, (VOID *) &(RecordInDb->SrcDes= c), > sizeof (PCH_SMM_SOURCE_DESC)); > + LinkToExhaust =3D LinkInDb; > + > + // > + // exhaust the rest of the queue looking for the same source > + // > + while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)= ) { > + RecordToExhaust =3D DATABASE_RECORD_FROM_LINK > (LinkToExhaust); > + // > + // RecordToExhaust->Link might be removed (unregistered) by > Callback function, and then the > + // system will hang in ASSERT() while calling GetNextNode(). > + // To prevent the issue, we need to get next record in DB he= re (before > Callback function). > + // > + LinkToExhaust =3D GetNextNode (&mPrivateData.CallbackDataBas= e, > &RecordToExhaust->Link); > + > + if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource= )) { > + // > + // These source descriptions are equal, so this callback s= hould be > + // dispatched. > + // > + if (RecordToExhaust->ContextFunctions.GetContext !=3D NULL= ) { > + // > + // This child requires that we get a calling context fro= m > + // hardware and compare that context to the one supplied > + // by the child. > + // > + ASSERT (RecordToExhaust->ContextFunctions.CmpContext != =3D > NULL); > + > + // > + // Make sure contexts match before dispatching event to = child > + // > + RecordToExhaust->ContextFunctions.GetContext > (RecordToExhaust, &Context); > + ContextsMatch =3D > RecordToExhaust->ContextFunctions.CmpContext (&Context, > &RecordToExhaust->ChildContext); > + > + } else { > + // > + // This child doesn't require any more calling context b= eyond > what > + // it supplied in registration. Simply pass back what i= t gave us. > + // > + Context =3D RecordToExhaust->ChildContext; > + ContextsMatch =3D TRUE; > + } > + > + if (ContextsMatch) { > + if (RecordToExhaust->ProtocolType =3D=3D PchSmiDispatchT= ype) { > + // > + // For PCH SMI dispatch protocols > + // > + PchSmiTypeCallbackDispatcher (RecordToExhaust); > + } else { > + // > + // For EFI standard SMI dispatch protocols > + // > + if (RecordToExhaust->Callback !=3D NULL) { > + if (RecordToExhaust->ContextFunctions.GetCommBuffer = !=3D > NULL) { > + // > + // This callback function needs CommBuffer and > CommBufferSize. > + // Get those from child and then pass to callback = function. > + // > + RecordToExhaust->ContextFunctions.GetCommBuffer > (RecordToExhaust, &CommBuffer, &CommBufferSize); > + } else { > + // > + // Child doesn't support the CommBuffer and > CommBufferSize. > + // Just pass NULL value to callback function. > + // > + CommBuffer =3D NULL; > + CommBufferSize =3D 0; > + } > + > + PERF_START_EX (NULL, "SmmFunction", NULL, AsmReadTsc= (), > RecordToExhaust->ProtocolType); > + RecordToExhaust->Callback ((EFI_HANDLE) & > RecordToExhaust->Link, &Context, CommBuffer, &CommBufferSize); > + PERF_END_EX (NULL, "SmmFunction", NULL, AsmReadTsc (= ), > RecordToExhaust->ProtocolType); > + if (RecordToExhaust->ProtocolType =3D=3D SxType) { > + SxChildWasDispatched =3D TRUE; > + } > + } else { > + ASSERT (FALSE); > + } > + } > + } > + } > + } > + > + if (RecordInDb->ClearSource =3D=3D NULL) { > + // > + // Clear the SMI associated w/ the source using the default = function > + // > + PchSmmClearSource (&ActiveSource); > + } else { > + // > + // This source requires special handling to clear > + // > + RecordInDb->ClearSource (&ActiveSource); > + } > + // > + // Clear pending SMI status before EOS > + // > + ClearPendingSmiStatus (SmiStsValue, SciEn); > + // > + // Also, try to clear EOS > + // > + EosSet =3D PchSmmSetAndCheckEos (); > + // > + // Queue is empty, reset the search > + // > + break; > + } > + } > + } > + } > + // > + // If you arrive here, there are two possible reasons: > + // (1) you've got problems with clearing the SMI status bits in the > + // ACPI table. If you don't properly clear the SMI bits, then you won= 't be > able to set the > + // EOS bit. If this happens too many times, the loop exits. > + // (2) there was a SMM communicate for callback messages that was > received prior > + // to this driver. > + // If there is an asynchronous SMI that occurs while processing the Ca= llback, > let > + // all of the drivers (including this one) have an opportunity to scan= for the > SMI > + // and handle it. > + // If not, we don't want to exit and have the foreground app. clear EO= S > without letting > + // these other sources get serviced. > + // > + // This assert is not valid with CSM legacy solution because it genera= tes > software SMI > + // to test for legacy USB support presence. > + // This may not be illegal, so we cannot assert at this time. > + // > + // ASSERT (EscapeCount > 0); > + // > + if (SxChildWasDispatched) { > + // > + // A child of the SmmSxDispatch protocol was dispatched during this = call; > + // put the system to sleep. > + // > + PchSmmSxGoToSleep (); > + } > + // > + // Restore IO index registers > + // @note: Save/Restore port 70h directly might break NMI_EN# setting, > + // then save/restore 74h/76h instead. > + // > + IoWrite8 (R_RTC_IO_EXT_INDEX_ALT, Port76Save); > + IoWrite8 (R_RTC_IO_INDEX_ALT, Port74Save); > + > + return Status; > +} > diff --git > a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEs > pi.c > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEs > pi.c > new file mode 100644 > index 0000000000..9eb61947a3 > --- /dev/null > +++ > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEs > pi.c > @@ -0,0 +1,1595 @@ > +/** @file > + eSPI SMI implementation > + > + Copyright (c) 2019 Intel Corporation. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#include "PchSmmEspi.h" > +#include > +#include > +#include > +#include > +#include > +#include > + > +GLOBAL_REMOVE_IF_UNREFERENCED ESPI_SMI_INSTANCE > mEspiSmiInstance =3D { > + // > + // Signature > + // > + ESPI_SMI_INSTANCE_SIGNATURE, > + // > + // Handle > + // > + NULL, > + // > + // PchEspiSmiDispatchProtocol > + // > + { > + PCH_ESPI_SMI_DISPATCH_REVISION, > + EspiSmiUnRegister, > + BiosWrProtectRegister, > + BiosWrReportRegister, > + PcNonFatalErrRegister, > + PcFatalErrRegister, > + VwNonFatalErrRegister, > + VwFatalErrRegister, > + FlashNonFatalErrRegister, > + FlashFatalErrRegister, > + LnkType1ErrRegister, > + EspiSlaveSmiRegister > + }, > + // > + // PchSmiEspiHandle[EspiTopLevelTypeMax] > + // > + { > + NULL, NULL, NULL > + }, > + // > + // CallbackDataBase[EspiSmiTypeMax] > + // > + { > + {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL}= , > + {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL} > + }, > + // > + // EspiSmiEventCounter[EspiSmiTypeMax] > + // > + { > + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 > + }, > + // > + // Barrier[EspiTopLevelTypeMax] > + // > + { > + { > + BiosWrProtect, > + BiosWrProtect > + }, > + { > + BiosWrReport, > + LnkType1Err > + }, > + { > + EspiSlaveSmi, > + EspiSlaveSmi > + } > + } > +}; > + > +GLOBAL_REMOVE_IF_UNREFERENCED CONST ESPI_DESCRIPTOR > mEspiDescriptor[EspiSmiTypeMax] =3D { > + // > + // BiosWrProtect > + // > + { > + { > + PCIE_ADDR_TYPE, > + { ( > + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | > + (PCI_DEVICE_NUMBER_PCH_LPC << 19) | > + (PCI_FUNCTION_NUMBER_PCH_LPC << 16) | > + R_ESPI_CFG_PCBC > + ) } > + }, > + // > + // SourceIsActiveAndMask and SourceIsActiveValue > + // > + B_ESPI_CFG_PCBC_BWPDS | B_ESPI_CFG_PCBC_LE, > + B_ESPI_CFG_PCBC_BWPDS | B_ESPI_CFG_PCBC_LE, > + // > + // ClearStatusAndMask and ClearStatusOrMask > + // > + (UINT32) ~B_ESPI_CFG_PCBC_BWRS, > + B_ESPI_CFG_PCBC_BWPDS > + }, > + // > + // BiosWrReport > + // > + { > + { > + PCIE_ADDR_TYPE, > + { ( > + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | > + (PCI_DEVICE_NUMBER_PCH_LPC << 19) | > + (PCI_FUNCTION_NUMBER_PCH_LPC << 16) | > + R_ESPI_CFG_PCBC > + ) } > + }, > + B_ESPI_CFG_PCBC_BWRS | B_ESPI_CFG_PCBC_BWRE, > + B_ESPI_CFG_PCBC_BWRS | B_ESPI_CFG_PCBC_BWRE, > + (UINT32) ~B_ESPI_CFG_PCBC_BWPDS, > + B_ESPI_CFG_PCBC_BWRS > + }, > + // > + // PcNonFatalErr > + // > + { > + { > + PCR_ADDR_TYPE, > + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_PCERR_SLV0) } > + }, > + (B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XNFEE), > + (B_ESPI_PCR_XERR_XNFES | (V_ESPI_PCR_XERR_XNFEE_SMI << > N_ESPI_PCR_XERR_XNFEE)), > + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | B_ESPI_PCR_XERR_XFES), > + B_ESPI_PCR_XERR_XNFES > + }, > + // > + // PcFatalErr > + // > + { > + { > + PCR_ADDR_TYPE, > + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_PCERR_SLV0) } > + }, > + (B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE), > + (B_ESPI_PCR_XERR_XFES | (V_ESPI_PCR_XERR_XFEE_SMI << > N_ESPI_PCR_XERR_XFEE)), > + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | B_ESPI_PCR_XERR_XNFES), > + B_ESPI_PCR_XERR_XFES > + }, > + // > + // VwNonFatalErr > + // > + { > + { > + PCR_ADDR_TYPE, > + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_VWERR_SLV0) } > + }, > + (B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XNFEE), > + (B_ESPI_PCR_XERR_XNFES | (V_ESPI_PCR_XERR_XNFEE_SMI << > N_ESPI_PCR_XERR_XNFEE)), > + (UINT32) ~B_ESPI_PCR_XERR_XFES, > + B_ESPI_PCR_XERR_XNFES > + }, > + // > + // VwFatalErr > + // > + { > + { > + PCR_ADDR_TYPE, > + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_VWERR_SLV0) } > + }, > + (B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE), > + (B_ESPI_PCR_XERR_XFES | (V_ESPI_PCR_XERR_XFEE_SMI << > N_ESPI_PCR_XERR_XFEE)), > + (UINT32) ~B_ESPI_PCR_XERR_XNFES, > + B_ESPI_PCR_XERR_XFES > + }, > + // > + // FlashNonFatalErr > + // > + { > + { > + PCR_ADDR_TYPE, > + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_FCERR_SLV0) } > + }, > + (B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XNFEE), > + (B_ESPI_PCR_XERR_XNFES | (V_ESPI_PCR_XERR_XNFEE_SMI << > N_ESPI_PCR_XERR_XNFEE)), > + (UINT32) ~B_ESPI_PCR_XERR_XFES, > + B_ESPI_PCR_XERR_XNFES > + }, > + // > + // FlashFatalErr > + // > + { > + { > + PCR_ADDR_TYPE, > + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_FCERR_SLV0) } > + }, > + (B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE), > + (B_ESPI_PCR_XERR_XFES | (V_ESPI_PCR_XERR_XFEE_SMI << > N_ESPI_PCR_XERR_XFEE)), > + (UINT32) ~B_ESPI_PCR_XERR_XNFES, > + B_ESPI_PCR_XERR_XFES > + }, > + // > + // LnkType1Err > + // > + { > + { > + PCR_ADDR_TYPE, > + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_LNKERR_SLV0) } > + }, > + B_ESPI_PCR_LNKERR_SLV0_LFET1S | B_ESPI_PCR_LNKERR_SLV0_LFET1E, > + B_ESPI_PCR_LNKERR_SLV0_LFET1S | > (V_ESPI_PCR_LNKERR_SLV0_LFET1E_SMI << > N_ESPI_PCR_LNKERR_SLV0_LFET1E), > + (UINT32) ~B_ESPI_PCR_LNKERR_SLV0_SLCRR, > + B_ESPI_PCR_LNKERR_SLV0_LFET1S > + }, > +}; > + > +/** > + Enable eSPI SMI source > + > + @param[in] EspiSmiType Type based on ESPI_SMI_TYPE > +**/ > +STATIC > +VOID > +EspiSmiEnableSource ( > + IN CONST ESPI_SMI_TYPE EspiSmiType > + ) > +{ > + UINT64 PciBaseAddress; > + > + switch (EspiSmiType) { > + case BiosWrProtect: > + // > + // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE= . > + // > + break; > + case BiosWrReport: > + PciBaseAddress =3D PCI_SEGMENT_LIB_ADDRESS ( > + DEFAULT_PCI_SEGMENT_NUMBER_PCH, > + DEFAULT_PCI_BUS_NUMBER_PCH, > + PCI_DEVICE_NUMBER_PCH_LPC, > + PCI_FUNCTION_NUMBER_PCH_LPC, > + 0 > + ); > + PciSegmentAndThenOr32 ( > + PciBaseAddress + R_ESPI_CFG_PCBC, > + (UINT32) ~(B_ESPI_CFG_PCBC_BWRS | B_ESPI_CFG_PCBC_BWPDS), > + B_ESPI_CFG_PCBC_BWRE > + ); > + break; > + case PcNonFatalErr: > + PchPcrAndThenOr32 ( > + PID_ESPISPI, > + (UINT16) R_ESPI_PCR_PCERR_SLV0, > + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | > B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES), > + B_ESPI_PCR_XERR_XNFEE > + ); > + break; > + > + case PcFatalErr: > + PchPcrAndThenOr32 ( > + PID_ESPISPI, > + (UINT16) R_ESPI_PCR_PCERR_SLV0, > + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | > B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES), > + B_ESPI_PCR_XERR_XFEE > + ); > + break; > + > + case VwNonFatalErr: > + PchPcrAndThenOr32 ( > + PID_ESPISPI, > + (UINT16) R_ESPI_PCR_VWERR_SLV0, > + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES), > + B_ESPI_PCR_XERR_XNFEE > + ); > + break; > + > + case VwFatalErr: > + PchPcrAndThenOr32 ( > + PID_ESPISPI, > + (UINT16) R_ESPI_PCR_VWERR_SLV0, > + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES), > + B_ESPI_PCR_XERR_XFEE > + ); > + break; > + > + case FlashNonFatalErr: > + PchPcrAndThenOr32 ( > + PID_ESPISPI, > + (UINT16) R_ESPI_PCR_FCERR_SLV0, > + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES), > + B_ESPI_PCR_XERR_XNFEE > + ); > + break; > + > + case FlashFatalErr: > + PchPcrAndThenOr32 ( > + PID_ESPISPI, > + (UINT16) R_ESPI_PCR_FCERR_SLV0, > + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES), > + B_ESPI_PCR_XERR_XFEE > + ); > + break; > + > + case LnkType1Err: > + PchPcrAndThenOr32 ( > + PID_ESPISPI, > + (UINT16) R_ESPI_PCR_LNKERR_SLV0, > + (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR | > B_ESPI_PCR_LNKERR_SLV0_LFET1S), > + (UINT32) (V_ESPI_PCR_LNKERR_SLV0_LFET1E_SMI << > N_ESPI_PCR_LNKERR_SLV0_LFET1E) > + ); > + > + if (IsEspiSecondSlaveSupported ()) { > + PchPcrAndThenOr32 ( > + PID_ESPISPI, > + (UINT16) R_ESPI_PCR_LNKERR_SLV1, > + (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR | > B_ESPI_PCR_LNKERR_SLV0_LFET1S), > + (UINT32) (V_ESPI_PCR_LNKERR_SLV0_LFET1E_SMI << > N_ESPI_PCR_LNKERR_SLV0_LFET1E) > + ); > + } > + break; > + > + default: > + DEBUG ((DEBUG_ERROR, "Unsupported EspiSmiType \n")); > + ASSERT (FALSE); > + break; > + } > +} > + > + > +/** > + Disable eSPI SMI source > + > + @param[in] EspiSmiType Type based on ESPI_SMI_TYPE > +**/ > +STATIC > +VOID > +EspiSmiDisableSource ( > + IN CONST ESPI_SMI_TYPE EspiSmiType > + ) > +{ > + > + switch (EspiSmiType) { > + case BiosWrProtect: > + case BiosWrReport: > + DEBUG ((DEBUG_ERROR, "Bit is write lock, thus BWRE/BWPDS source > cannot be disabled \n")); > + ASSERT (FALSE); > + break; > + case PcNonFatalErr: > + PchPcrAndThenOr32 ( > + PID_ESPISPI, > + (UINT16) R_ESPI_PCR_PCERR_SLV0, > + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | > B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | > B_ESPI_PCR_XERR_XNFEE), > + 0 > + ); > + break; > + > + case PcFatalErr: > + PchPcrAndThenOr32 ( > + PID_ESPISPI, > + (UINT16) R_ESPI_PCR_PCERR_SLV0, > + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | > B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | > B_ESPI_PCR_XERR_XFEE), > + 0 > + ); > + break; > + > + case VwNonFatalErr: > + PchPcrAndThenOr32 ( > + PID_ESPISPI, > + (UINT16) R_ESPI_PCR_VWERR_SLV0, > + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | > B_ESPI_PCR_XERR_XNFEE), > + 0 > + ); > + break; > + > + case VwFatalErr: > + PchPcrAndThenOr32 ( > + PID_ESPISPI, > + (UINT16) R_ESPI_PCR_VWERR_SLV0, > + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | > B_ESPI_PCR_XERR_XFEE), > + 0 > + ); > + break; > + > + case FlashNonFatalErr: > + PchPcrAndThenOr32 ( > + PID_ESPISPI, > + (UINT16) R_ESPI_PCR_FCERR_SLV0, > + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | > B_ESPI_PCR_XERR_XNFEE), > + 0 > + ); > + break; > + > + case FlashFatalErr: > + PchPcrAndThenOr32 ( > + PID_ESPISPI, > + (UINT16) R_ESPI_PCR_FCERR_SLV0, > + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | > B_ESPI_PCR_XERR_XFEE), > + 0 > + ); > + break; > + > + case LnkType1Err: > + PchPcrAndThenOr32 ( > + PID_ESPISPI, > + (UINT16) R_ESPI_PCR_LNKERR_SLV0, > + (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR | > B_ESPI_PCR_LNKERR_SLV0_LFET1S), > + 0 > + ); > + > + if (IsEspiSecondSlaveSupported ()) { > + PchPcrAndThenOr32 ( > + PID_ESPISPI, > + (UINT16) R_ESPI_PCR_LNKERR_SLV1, > + (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR | > B_ESPI_PCR_LNKERR_SLV0_LFET1S), > + 0 > + ); > + } > + break; > + > + default: > + DEBUG ((DEBUG_ERROR, "Unsupported EspiSmiType \n")); > + ASSERT (FALSE); > + break; > + } > +} > + > +/** > + Clear a status for the SMI event > + > + @param[in] EspiSmiType Type based on ESPI_SMI_TYPE > +**/ > +STATIC > +VOID > +EspiSmiClearStatus ( > + IN CONST ESPI_SMI_TYPE EspiSmiType > + ) > +{ > + UINT32 PciBus; > + UINT32 PciDev; > + UINT32 PciFun; > + UINT32 PciReg; > + UINT64 PciBaseAddress; > + CONST ESPI_DESCRIPTOR *Desc; > + > + Desc =3D &mEspiDescriptor[EspiSmiType]; > + > + switch (Desc->Address.Type) { > + case PCIE_ADDR_TYPE: > + PciBus =3D Desc->Address.Data.pcie.Fields.Bus; > + PciDev =3D Desc->Address.Data.pcie.Fields.Dev; > + PciFun =3D Desc->Address.Data.pcie.Fields.Fnc; > + PciReg =3D Desc->Address.Data.pcie.Fields.Reg; > + PciBaseAddress =3D PCI_SEGMENT_LIB_ADDRESS > (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0); > + PciSegmentAndThenOr32 (PciBaseAddress + PciReg, > Desc->ClearStatusAndMask, Desc->ClearStatusOrMask); > + break; > + case PCR_ADDR_TYPE: > + PchPcrAndThenOr32 ( > + Desc->Address.Data.Pcr.Fields.Pid, > + Desc->Address.Data.Pcr.Fields.Offset, > + Desc->ClearStatusAndMask, > + Desc->ClearStatusOrMask > + ); > + break; > + default: > + DEBUG ((DEBUG_ERROR, "Address type for eSPI SMI is invalid \n")); > + ASSERT (FALSE); > + break; > + } > +} > + > +/** > + Checks if a source is active by looking at the enable and status bits > + > + @param[in] EspiSmiType Type based on ESPI_SMI_TYPE > +**/ > +STATIC > +BOOLEAN > +EspiSmiSourceIsActive ( > + IN CONST ESPI_SMI_TYPE EspiSmiType > + ) > +{ > + BOOLEAN Active; > + UINT32 PciBus; > + UINT32 PciDev; > + UINT32 PciFun; > + UINT32 PciReg; > + UINT64 PciBaseAddress; > + UINT32 Data32; > + CONST ESPI_DESCRIPTOR *Desc; > + > + Desc =3D &mEspiDescriptor[EspiSmiType]; > + > + Active =3D FALSE; > + switch (Desc->Address.Type) { > + case PCIE_ADDR_TYPE: > + PciBus =3D Desc->Address.Data.pcie.Fields.Bus; > + PciDev =3D Desc->Address.Data.pcie.Fields.Dev; > + PciFun =3D Desc->Address.Data.pcie.Fields.Fnc; > + PciReg =3D Desc->Address.Data.pcie.Fields.Reg; > + PciBaseAddress =3D PCI_SEGMENT_LIB_ADDRESS > (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0); > + Data32 =3D PciSegmentRead32 (PciBaseAddress + PciReg); > + break; > + > + case PCR_ADDR_TYPE: > + Data32 =3D PchPcrRead32 ( > + Desc->Address.Data.Pcr.Fields.Pid, > + Desc->Address.Data.Pcr.Fields.Offset > + ); > + break; > + > + default: > + Data32 =3D 0; > + DEBUG ((DEBUG_ERROR, "Address type for eSPI SMI is invalid \n")); > + ASSERT (FALSE); > + break; > + } > + > + if ((Data32 & Desc->SourceIsActiveAndMask) =3D=3D Desc->SourceIsActive= Value) > { > + Active =3D TRUE; > + } > + > + return Active; > +} > + > +/** > + Insert a handler into the corresponding linked list based on EspiSmiTy= pe > + > + @param[in] DispatchFunction The callback to execute > + @param[in] EspiSmiType Type based on ESPI_SMI_TYPE to > determine which linked list to use > + @param[out] DispatchHandle The link to the record in the databa= se > + > + @retval EFI_SUCCESS Record was successfully inserted int= o > master database > + @retval EFI_OUT_OF_RESOURCES Cannot allocate pool to insert recor= d > +**/ > +STATIC > +EFI_STATUS > +InsertEspiRecord ( > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + IN ESPI_SMI_TYPE EspiSmiType, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + ESPI_SMI_RECORD *Record; > + > + Status =3D gSmst->SmmAllocatePool (EfiRuntimeServicesData, sizeof > (ESPI_SMI_RECORD), (VOID **) &Record); > + if (EFI_ERROR (Status)) { > + ASSERT (FALSE); > + return EFI_OUT_OF_RESOURCES; > + } > + SetMem (Record, sizeof (ESPI_SMI_RECORD), 0); > + > + Record->Callback =3D DispatchFunction; > + Record->Signature =3D ESPI_SMI_RECORD_SIGNATURE; > + > + InsertTailList (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], > &Record->Link); > + EspiSmiClearStatus (EspiSmiType); > + EspiSmiEnableSource (EspiSmiType); > + > + ++mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType]; > + > + *DispatchHandle =3D (EFI_HANDLE) (&Record->Link); > + > + return EFI_SUCCESS; > +} > + > +/** > + This callback is registered to PchSmiDispatch > + > + @param[in] DispatchHandle Used to determine which source have been > triggered > +**/ > +VOID > +EspiSmiCallback ( > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + DATABASE_RECORD *PchSmiRecord; > + ESPI_TOP_LEVEL_TYPE EspiTopLevelType; > + ESPI_SMI_TYPE EspiSmiType; > + ESPI_SMI_RECORD *RecordInDb; > + LIST_ENTRY *LinkInDb; > + > + PchSmiRecord =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); > + > + if (PchSmiRecord->PchSmiType =3D=3D PchTcoSmiLpcBiosWpType) { > + EspiTopLevelType =3D EspiBiosWrProtect; > + } else if (PchSmiRecord->PchSmiType =3D=3D PchSmiSerialIrqType) { > + EspiTopLevelType =3D EspiSerialIrq; > + } else { > + DEBUG ((DEBUG_ERROR, "EspiSmiCallback was dispatched with a wrong > DispatchHandle")); > + ASSERT (FALSE); > + return; > + } > + > + for (EspiSmiType =3D mEspiSmiInstance.Barrier[EspiTopLevelType].Start; > EspiSmiType <=3D mEspiSmiInstance.Barrier[EspiTopLevelType].End; > ++EspiSmiType) { > + if (!EspiSmiSourceIsActive (EspiSmiType)) { > + continue; > + } > + // > + // The source is active, so walk the callback database and dispatch > + // > + if (!IsListEmpty (&mEspiSmiInstance.CallbackDataBase[EspiSmiType])) = { > + // > + // We have children registered w/ us -- continue > + // > + LinkInDb =3D GetFirstNode > (&mEspiSmiInstance.CallbackDataBase[EspiSmiType]); > + > + while (!IsNull (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], > LinkInDb)) { > + RecordInDb =3D ESPI_RECORD_FROM_LINK (LinkInDb); > + > + // > + // RecordInDb->Link might be removed (unregistered) by Callback > function, and then the > + // system will hang in ASSERT() while calling GetNextNode(). > + // To prevent the issue, we need to get next record in DB here (= before > Callback function). > + // > + LinkInDb =3D GetNextNode > (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], &RecordInDb->Link); > + > + // > + // Callback > + // > + if (RecordInDb->Callback !=3D NULL) { > + RecordInDb->Callback ((EFI_HANDLE) &RecordInDb->Link); > + } else { > + ASSERT (FALSE); > + } > + } > + } else if (EspiSmiType =3D=3D LnkType1Err) { > + // > + // If no proper handler registered for Link Type 1 Error > + // Call default SMI handler recover otherwise > + // > + EspiDefaultFatalErrorHandler (); > + } > + > + // > + // Finish walking the linked list for the EspiSmiType, so clear stat= us > + // > + EspiSmiClearStatus (EspiSmiType); > + } > +} > + > +// > +// EspiBiosWp srcdesc > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescEspiBiosWp =3D { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_EN} > + }, > + S_ACPI_IO_SMI_EN, > + N_ACPI_IO_SMI_EN_TCO > + }, > + { > + { > + PCIE_ADDR_TYPE, > + { ( > + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | > + (PCI_DEVICE_NUMBER_PCH_LPC << 19) | > + (PCI_FUNCTION_NUMBER_PCH_LPC << 16) | > + R_ESPI_CFG_PCBC > + ) } > + }, > + S_ESPI_CFG_PCBC, > + N_ESPI_CFG_PCBC_LE > + } > + }, > + { > + { > + { > + PCIE_ADDR_TYPE, > + { ( > + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | > + (PCI_DEVICE_NUMBER_PCH_LPC << 19) | > + (PCI_FUNCTION_NUMBER_PCH_LPC << 16) | > + R_ESPI_CFG_PCBC > + ) } > + }, > + S_ESPI_CFG_PCBC, > + N_ESPI_CFG_PCBC_BWPDS > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_TCO > + } > +}; > + > +/** > + This function will register EspiSmiCallback with mSrcDescEspiBiosWp so= urce > decriptor > + This function make sure there is only one BIOS WP SMI handler is regis= tered. > + While any ESPI sub BIOS WP SMI type is registered, all the BIOS WP SMI > + will go to callback function EspiSmiCallback first, and then dispatchs= the > callbacks > + recorded in mEspiSmiInstance. > + > + @retval EFI_SUCCESS Registration succeed > + @retval others Registration failed > +**/ > +STATIC > +EFI_STATUS > +RegisterBiosWrProtectIfNull ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + DATABASE_RECORD *Record; > + > + if (mEspiSmiInstance.PchSmiEspiHandle[EspiBiosWrProtect] =3D=3D NULL) = { > + Status =3D PchSmiRecordInsert ( > + &mSrcDescEspiBiosWp, > + (PCH_SMI_CALLBACK_FUNCTIONS) EspiSmiCallback, > + PchTcoSmiLpcBiosWpType, > + &mEspiSmiInstance.PchSmiEspiHandle[EspiBiosWrProtect] > + ); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "Fail to register BIOS WP SMI handler \n")); > + return Status; > + } > + Record =3D DATABASE_RECORD_FROM_LINK > (mEspiSmiInstance.PchSmiEspiHandle[EspiBiosWrProtect]); > + Record->ClearSource =3D PchTcoSmiClearSource; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + This function will register EspiSmiCallback with mSrcDescSerialIrq sou= rce > decriptor > + This function make sure there is only one Serial IRQ SMI handler is > registered. > + While any ESPI sub Serial IRQ SMI type is registered, all the Serial I= RQ SMI > + will go to callback function EspiSmiCallback first, and then dispatchs= the > callbacks > + recorded in mEspiSmiInstance. > + > + @retval EFI_SUCCESS Registration succeed > + @retval others Registration failed > +**/ > +STATIC > +EFI_STATUS > +RegisterSerialIrqIfNull ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + > + if (mEspiSmiInstance.PchSmiEspiHandle[EspiSerialIrq] =3D=3D NULL) { > + Status =3D PchSmiRecordInsert ( > + &mSrcDescSerialIrq, > + (PCH_SMI_CALLBACK_FUNCTIONS) EspiSmiCallback, > + PchSmiSerialIrqType, > + &mEspiSmiInstance.PchSmiEspiHandle[EspiSerialIrq] > + ); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "Fail to register Serial IRQ SMI handler \n")= ); > + return Status; > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Installs and initialize this protocol > + > + @param[in] ImageHandle Not used > + > + @retval EFI_SUCCESS Installation succeed > + @retval others Installation failed > +**/ > +EFI_STATUS > +EFIAPI > +InstallEspiSmi ( > + IN EFI_HANDLE ImageHandle > + ) > +{ > + EFI_STATUS Status; > + ESPI_SMI_TYPE EspiSmiType; > + > + DEBUG ((DEBUG_INFO, "[InstallEspiSmi] Enter\n")); > + > + // > + // InitializeListHead for > mEspiSmiInstance.CallBackDataBase[EspiTopLevelTypeMax] > + // > + for (EspiSmiType =3D 0; EspiSmiType < EspiSmiTypeMax; ++EspiSmiType) { > + InitializeListHead (&mEspiSmiInstance.CallbackDataBase[EspiSmiType])= ; > + } > + > + // > + // Install EfiEspiSmiDispatchProtocol > + // > + Status =3D gSmst->SmmInstallProtocolInterface ( > + &mEspiSmiInstance.Handle, > + &gPchEspiSmiDispatchProtocolGuid, > + EFI_NATIVE_INTERFACE, > + &mEspiSmiInstance.PchEspiSmiDispatchProtocol > + ); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "Failed to install eSPI SMI Dispatch Protocol\n= ")); > + ASSERT (FALSE); > + return Status; > + } > + > + // Register eSPI SMM callback to enable Fatal Error handling by defaul= t > handler > + Status =3D RegisterSerialIrqIfNull (); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // Enable LnkType1Err SMI generation for default handler > + EspiSmiClearStatus (LnkType1Err); > + EspiSmiEnableSource (LnkType1Err); > + > + return EFI_SUCCESS; > +} > + > +/** > + eSPI SMI Dispatch Protocol instance to register a BIOS Write Protect e= vent > + > + @param[in] This Not used > + @param[in] DispatchFunction The callback to execute > + @param[out] DispatchHandle The handle for this callback registratio= n > + > + @retval EFI_SUCCESS Registration succeed > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval others Registration failed > +**/ > +EFI_STATUS > +EFIAPI > +BiosWrProtectRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D RegisterBiosWrProtectIfNull (); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + // > + // Insert a record > + // > + Status =3D InsertEspiRecord (DispatchFunction, BiosWrProtect, > DispatchHandle); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +/** > + eSPI SMI Dispatch Protocol instance to register a BIOS Write Report ev= ent > + > + @param[in] This Not used > + @param[in] DispatchFunction The callback to execute > + @param[out] DispatchHandle The handle for this callback registratio= n > + > + @retval EFI_SUCCESS Registration succeed > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval others Registration failed > +**/ > +EFI_STATUS > +EFIAPI > +BiosWrReportRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D RegisterSerialIrqIfNull (); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + // > + // Insert a record > + // > + Status =3D InsertEspiRecord (DispatchFunction, BiosWrReport, > DispatchHandle); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +/** > + eSPI SMI Dispatch Protocol instance to register a Peripheral Channel N= on > Fatal Error event > + > + @param[in] This Not used > + @param[in] DispatchFunction The callback to execute > + @param[out] DispatchHandle The handle for this callback registratio= n > + > + @retval EFI_SUCCESS Registration succeed > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval others Registration failed > +**/ > +EFI_STATUS > +EFIAPI > +PcNonFatalErrRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D RegisterSerialIrqIfNull (); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + // > + // Insert a record > + // > + Status =3D InsertEspiRecord (DispatchFunction, PcNonFatalErr, > DispatchHandle); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +/** > + eSPI SMI Dispatch Protocol instance to register a Peripheral Channel F= atal > Error event > + > + @param[in] This Not used > + @param[in] DispatchFunction The callback to execute > + @param[out] DispatchHandle The handle for this callback registratio= n > + > + @retval EFI_SUCCESS Registration succeed > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval others Registration failed > +**/ > +EFI_STATUS > +EFIAPI > +PcFatalErrRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D RegisterSerialIrqIfNull (); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + // > + // Insert a record > + // > + Status =3D InsertEspiRecord (DispatchFunction, PcFatalErr, DispatchHan= dle); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +/** > + eSPI SMI Dispatch Protocol instance to register a Virtual Wire Non Fat= al Error > event > + > + @param[in] This Not used > + @param[in] DispatchFunction The callback to execute > + @param[out] DispatchHandle The handle for this callback registratio= n > + > + @retval EFI_SUCCESS Registration succeed > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval others Registration failed > +**/ > +EFI_STATUS > +EFIAPI > +VwNonFatalErrRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D RegisterSerialIrqIfNull (); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + // > + // Insert a record > + // > + Status =3D InsertEspiRecord (DispatchFunction, VwNonFatalErr, > DispatchHandle); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +/** > + eSPI SMI Dispatch Protocol instance to register a Virtual Wire Fatal E= rror > event > + > + @param[in] This Not used > + @param[in] DispatchFunction The callback to execute > + @param[out] DispatchHandle The handle for this callback registratio= n > + > + @retval EFI_SUCCESS Registration succeed > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval others Registration failed > +**/ > +EFI_STATUS > +EFIAPI > +VwFatalErrRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D RegisterSerialIrqIfNull (); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + // > + // Insert a record > + // > + Status =3D InsertEspiRecord (DispatchFunction, VwFatalErr, DispatchHan= dle); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +/** > + eSPI SMI Dispatch Protocol instance to register a Flash Channel Non Fa= tal > Error event > + > + @param[in] This Not used > + @param[in] DispatchFunction The callback to execute > + @param[out] DispatchHandle The handle for this callback registratio= n > + > + @retval EFI_SUCCESS Registration succeed > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval others Registration failed > +**/ > +EFI_STATUS > +EFIAPI > +FlashNonFatalErrRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D RegisterSerialIrqIfNull (); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + // > + // Insert a record > + // > + Status =3D InsertEspiRecord (DispatchFunction, FlashNonFatalErr, > DispatchHandle); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +/** > + eSPI SMI Dispatch Protocol instance to register a Flash Channel Fatal = Error > event > + > + @param[in] This Not used > + @param[in] DispatchFunction The callback to execute > + @param[out] DispatchHandle The handle for this callback registratio= n > + > + @retval EFI_SUCCESS Registration succeed > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval others Registration failed > +**/ > +EFI_STATUS > +EFIAPI > +FlashFatalErrRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D RegisterSerialIrqIfNull (); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + // > + // Insert a record > + // > + Status =3D InsertEspiRecord (DispatchFunction, FlashFatalErr, > DispatchHandle); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +/** > + eSPI SMI Dispatch Protocol instance to register a Link Error event > + > + @param[in] This Not used > + @param[in] DispatchFunction The callback to execute > + @param[out] DispatchHandle The handle for this callback registratio= n > + > + @retval EFI_SUCCESS Registration succeed > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval others Registration failed > +**/ > +EFI_STATUS > +EFIAPI > +LnkType1ErrRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D RegisterSerialIrqIfNull (); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + // > + // Insert a record > + // > + Status =3D InsertEspiRecord (DispatchFunction, LnkType1Err, > DispatchHandle); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + return Status; > +} > + > +// > +// EspiSlave srcdesc > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescEspiSlave =3D { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_EN} > + }, > + S_ACPI_IO_SMI_EN, > + N_ACPI_IO_SMI_EN_ESPI > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_ESPI > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_ESPI > + } > +}; > + > +/** > + eSPI SMI Dispatch Protocol instance to register a eSPI slave SMI > + This routine will also lock down ESPI_SMI_LOCK bit after registration = and > prevent > + this handler from unregistration. > + On platform that supports more than 1 device through another chip sele= ct > (SPT-H), > + the SMI handler itself needs to inspect both the eSPI devices' interru= pt > status registers > + (implementation specific for each Slave) in order to identify and serv= ice the > cause. > + After servicing it, it has to clear the Slaves' internal SMI# status r= egisters > + > + @param[in] This Not used > + @param[in] DispatchFunction The callback to execute > + @param[out] DispatchHandle The handle for this callback > registration > + > + @retval EFI_SUCCESS Registration succeed > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered > + @retval EFI_ACCESS_DENIED The ESPI_SMI_LOCK is set and > register is blocked. > + @retval others Registration failed > +**/ > +EFI_STATUS > +EFIAPI > +EspiSlaveSmiRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + // > + // If ESPI_SMI_LOCK is set, the register is blocked. > + // > + if (PmcIsEspiSmiLockSet ()) { > + return EFI_ACCESS_DENIED; > + } > + > + // > + // @note: This service doesn't utilize the data base of mEspiSmiInstan= ce. > + // While SMI is triggered it directly goes to the registing > DispatchFunction > + // instead of EspiSmiCallback. > + // > + Status =3D PchSmiRecordInsert ( > + &mSrcDescEspiSlave, > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, > + PchEspiSmiEspiSlaveType, > + DispatchHandle > + ); > + PchSmmClearSource (&mSrcDescEspiSlave); > + PchSmmEnableSource (&mSrcDescEspiSlave); > + > + // > + // Lock down the ESPI_SMI_LOCK after ESPI SMI is enabled. > + // > + PmcLockEspiSmi (); > + // > + // Keep the DispatchHandle which will be used for unregister function. > + // > + mEspiSmiInstance.PchSmiEspiHandle[EspiPmc] =3D *DispatchHandle; > + > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); > + } > + > + return Status; > +} > + > +/** > + eSPI SMI Dispatch Protocol instance to unregister a callback based on = handle > + > + @param[in] This Not used > + @param[in] DispatchHandle Handle acquired during registratio= n > + > + @retval EFI_SUCCESS Unregister successful > + @retval EFI_INVALID_PARAMETER DispatchHandle is null > + @retval EFI_INVALID_PARAMETER DispatchHandle's forward link has > bad pointer > + @retval EFI_INVALID_PARAMETER DispatchHandle does not exist in > database > + @retval EFI_ACCESS_DENIED Unregistration is done after end o= f > DXE > + @retval EFI_ACCESS_DENIED DispatchHandle is not allowed to > unregistered > +**/ > +EFI_STATUS > +EFIAPI > +EspiSmiUnRegister ( > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + ESPI_TOP_LEVEL_TYPE EspiTopLevelType; > + ESPI_SMI_TYPE EspiSmiType; > + BOOLEAN SafeToDisable; > + LIST_ENTRY *LinkInDb; > + ESPI_SMI_RECORD *RecordPointer; > + DATABASE_RECORD *RecordToDelete; > + > + if (DispatchHandle =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the > SmmReadyToLock event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + if (((LIST_ENTRY *) DispatchHandle)->ForwardLink =3D=3D (LIST_ENTRY *) > EFI_BAD_POINTER) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // For DispatchHandle belongs to Espi Slave SMI, refuses the request o= f > unregistration. > + // > + if (mEspiSmiInstance.PchSmiEspiHandle[EspiPmc] =3D=3D DispatchHandle) = { > + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed for ESPI Slave SMI > handle! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + // > + // Iterate through all the database to find the record > + // > + for (EspiSmiType =3D 0; EspiSmiType < EspiSmiTypeMax; ++EspiSmiType) { > + LinkInDb =3D GetFirstNode > (&mEspiSmiInstance.CallbackDataBase[EspiSmiType]); > + > + while (!IsNull (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], > LinkInDb)) { > + if (LinkInDb !=3D (LIST_ENTRY *) DispatchHandle) { > + LinkInDb =3D GetNextNode > (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], LinkInDb); > + > + } else { > + // > + // Found the source to be from this list > + // > + RemoveEntryList (LinkInDb); > + RecordPointer =3D (ESPI_RECORD_FROM_LINK (LinkInDb)); > + > + if (mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] !=3D 0) { > + if (--mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] =3D=3D= 0) { > + EspiSmiDisableSource (EspiSmiType); > + } > + } > + > + Status =3D gSmst->SmmFreePool (RecordPointer); > + if (EFI_ERROR (Status)) { > + ASSERT (FALSE); > + } > + > + goto EspiSmiUnRegisterEnd; > + } > + } > + } > + // > + // If the code reach here, the handle passed in cannot be found > + // > + DEBUG ((DEBUG_ERROR, "eSPI SMI handle is not in record database \n")); > + ASSERT (FALSE); > + return EFI_INVALID_PARAMETER; > + > +EspiSmiUnRegisterEnd: > + > + // > + // Unregister and clear the handle from PchSmiDispatch > + // > + for (EspiTopLevelType =3D 0; EspiTopLevelType < EspiTopLevelTypeMax; > ++EspiTopLevelType) { > + SafeToDisable =3D TRUE; > + // > + // Checks all the child events that belongs to a top level status in= PMC > + // > + for (EspiSmiType =3D mEspiSmiInstance.Barrier[EspiTopLevelType].Star= t; > EspiSmiType <=3D mEspiSmiInstance.Barrier[EspiTopLevelType].End; > ++EspiSmiType) { > + if (mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] !=3D 0) { > + SafeToDisable =3D FALSE; > + } > + } > + // > + // Finally, disable the top level event in PMC > + // > + if (SafeToDisable) { > + if (mEspiSmiInstance.PchSmiEspiHandle[EspiTopLevelType] !=3D NULL)= { > + Status =3D PchSmmCoreUnRegister (NULL, > mEspiSmiInstance.PchSmiEspiHandle[EspiTopLevelType]); > + ASSERT_EFI_ERROR (Status); > + mEspiSmiInstance.PchSmiEspiHandle[EspiTopLevelType] =3D NULL; > + } > + } > + } > + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); > + if (!EFI_ERROR (Status)) { > + SmiHandlerProfileUnregisterHandler > (&gPchEspiSmiDispatchProtocolGuid, RecordToDelete->Callback, NULL, 0); > + } > + return EFI_SUCCESS; > +} > + > +/** > + Returns AND maks for clearing eSPI channel registers errors statuses > + In addition to common status bit we add channel specific erro bits to = avoid > clearing them > + > + @param[in] ChannelNumber Channel number (0 for PC, 1 for VW= , 2 > for OOB, 3 for FA) > + > + @retval UINT32 AND mask with all the status bit m= asked to > not clear them by mistake > +**/ > +UINT32 > +GetEspiChannelStatusClearMask ( > + UINT8 ChannelNumber > + ) > +{ > + UINT32 Data32; > + > + // Common error status bits for all channel registers > + Data32 =3D B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES; > + > + // Check channels for channel specific status bits > + switch(ChannelNumber) { > + case 0: // Peripheral Channel specific status bits > + Data32 |=3D B_ESPI_PCR_PCERR_PCURD; > + break; > + case 3: // Flash Access Channel specific status bits > + Data32 |=3D B_ESPI_PCR_FCERR_SAFBLK; > + break; > + default: > + break; > + } > + > + // Return the expected AND mask > + return (UINT32)~(Data32); > +} > + > +/** > + Checks if channel error register data has Fatal Error bit set > + If yes then reset the channel on slave > + > + @param[in] ChannelBaseAddress Base address > + @param[in] ChannelNumber Channel number (0 for PC, 1 for VW= , 2 > for OOB, 3 for FA) > + @param[in] SlaveId Slave ID of which channel is to be= reset > +**/ > +VOID > +CheckSlaveChannelErrorAndReset ( > + UINT16 ChannelBaseAddress, > + UINT8 ChannelNumber, > + UINT8 SlaveId > + ) > +{ > + UINT32 Data32; > + UINT16 ChannelAddress; > + EFI_STATUS Status; > + > + if (ChannelNumber =3D=3D 2) { > + DEBUG ((DEBUG_INFO, "Channel %d is not supported by this function du= e > to lack of error register\n", ChannelNumber)); > + return; > + } > + > + if (!IsEspiSlaveChannelSupported (SlaveId, ChannelNumber)) { > + DEBUG ((DEBUG_WARN, "Channel %d is not supported by slave device\n", > ChannelNumber)); > + return; > + } > + > + // Calculate channel address based on slave id > + ChannelAddress =3D (UINT16) (ChannelBaseAddress + (SlaveId * > S_ESPI_PCR_XERR)); > + > + // Reading channel error register data > + Data32 =3D PchPcrRead32 (PID_ESPISPI, ChannelAddress); > + > + DEBUG ((DEBUG_INFO, "eSPI channel error register (0x%4X) has value > 0x%8X\n", ChannelAddress, Data32)); > + > + // Check Fatal Error status bit in channel error register data > + if ((Data32 & B_ESPI_PCR_XERR_XFES) !=3D 0) { > + Status =3D PchEspiSlaveChannelReset (SlaveId, ChannelNumber); > + > + if (EFI_ERROR (Status)) { > + switch (Status) { > + case EFI_UNSUPPORTED: > + DEBUG ((DEBUG_ERROR, "Slave doesn't support channel %d\n", > ChannelNumber)); > + break; > + case EFI_TIMEOUT: > + DEBUG ((DEBUG_ERROR, "Timeout occured during channel %d reset > on slave %d\n", ChannelNumber, SlaveId)); > + break; > + default: > + DEBUG ((DEBUG_ERROR, "Error occured during channel %d reset\n"= , > ChannelNumber)); > + break; > + } > + } else { > + DEBUG ((DEBUG_INFO, "eSPI Slave %d channel %d reset ended > successfully\n", SlaveId, ChannelNumber)); > + // If channel reset was successfull clear the fatal error flag by = writing one > + // we should be aware not to clear other status bits by mistake an= d mask > them > + PchPcrAndThenOr32 ( > + PID_ESPISPI, > + ChannelAddress, > + GetEspiChannelStatusClearMask (ChannelNumber), > + B_ESPI_PCR_XERR_XFES > + ); > + } > + } > +} > + > +/** > + eSPI SMI handler for Fatal Error recovery flow > +**/ > +VOID > +EspiDefaultFatalErrorHandler ( > + VOID > + ) > +{ > + UINT32 Data32; > + UINT8 SlaveId; > + UINT8 MaxSlavesCount; > + > + DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] Enter\n")); > + > + MaxSlavesCount =3D IsEspiSecondSlaveSupported () ? 2 : 1; > + > + DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] MaxSlavesCount > %d\n", MaxSlavesCount)); > + > + for (SlaveId =3D 0; SlaveId < MaxSlavesCount; ++SlaveId) { > + // > + // Check if slave has SLCRR bit set. If it does it means it needs re= covery. > + // > + Data32 =3D PchPcrRead32 (PID_ESPISPI, (UINT16) (R_ESPI_PCR_LNKERR_SL= V0 > + (SlaveId * S_ESPI_PCR_XERR))); > + > + DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] Slave %d LNKERR reg > 0x%8X\n", SlaveId, Data32)); > + // > + // If SLCRR[31] bit is set we need to recover that slave > + // > + if ((Data32 & B_ESPI_PCR_LNKERR_SLV0_SLCRR) !=3D 0) { > + // 1. Perform in-band reset > + PchEspiSlaveInBandReset (SlaveId); > + > + // 2. Channels reset > + CheckSlaveChannelErrorAndReset (R_ESPI_PCR_PCERR_SLV0, 0, SlaveId)= ; > // Peripheral channel reset > + CheckSlaveChannelErrorAndReset (R_ESPI_PCR_VWERR_SLV0, 1, > SlaveId); // Virtual Wire channel reset > + > + // Flash Access channel is not supported for CS1# > + if (SlaveId =3D=3D 0) { > + CheckSlaveChannelErrorAndReset (R_ESPI_PCR_PCERR_SLV0, 3, > SlaveId); // Flash Access channel reset > + } > + > + // Clear SLCRR bit of slave after all channels recovery was done > + PchPcrAndThenOr32 ( > + PID_ESPISPI, > + (UINT16) (R_ESPI_PCR_LNKERR_SLV0 + (SlaveId * S_ESPI_PCR_XERR)), > + (UINT32)~(B_ESPI_PCR_LNKERR_SLV0_LFET1S), > + (UINT32) (B_ESPI_PCR_LNKERR_SLV0_SLCRR) > + ); > + } > + } > + > + DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] Exit\n")); > +} > + > + > diff --git > a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGp > i.c > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGp > i.c > new file mode 100644 > index 0000000000..43277f0938 > --- /dev/null > +++ > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGp > i.c > @@ -0,0 +1,254 @@ > +/** @file > + File to contain all the hardware specific stuff for the Smm Gpi dispat= ch > protocol. > + > + Copyright (c) 2019 Intel Corporation. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#include "PchSmm.h" > +#include "PchSmmHelpers.h" > +#include > +#include > +#include > + > +// > +// Structure for GPI SMI is a template which needs to have > +// GPI Smi bit offset and Smi Status & Enable registers updated (accordi= ngly > +// to choosen group and pad number) after adding it to SMM Callback > database > +// > + > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mPchGpiSourceDescTemplate =3D { > + PCH_SMM_NO_FLAGS, > + { > + NULL_BIT_DESC_INITIALIZER, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + GPIO_ADDR_TYPE, {0x0} > + }, > + S_GPIO_PCR_GP_SMI_STS, 0x0, > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_GPIO_SMI > + } > +}; > + > +/** > + The register function used to register SMI handler of GPI SMI event. > + > + @param[in] This Pointer to the > EFI_SMM_GPI_DISPATCH2_PROTOCOL instance. > + @param[in] DispatchFunction Function to register for handler when t= he > specified GPI causes an SMI. > + @param[in] RegisterContext Pointer to the dispatch function's cont= ext. > + The caller fills this context in before= calling > + the register function to indicate to th= e register > + function the GPI(s) for which the dispa= tch function > + should be invoked. > + @param[out] DispatchHandle Handle generated by the dispatcher to > track the > + function instance. > + > + @retval EFI_SUCCESS The dispatch function has been successf= ully > + registered and the SMI source has been = enabled. > + @retval EFI_ACCESS_DENIED Register is not allowed > + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The GPI inp= ut > value > + is not within valid range. > + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or > SMM) to manage this child. > +**/ > +EFI_STATUS > +EFIAPI > +PchGpiSmiRegister ( > + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This, > + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, > + IN CONST EFI_SMM_GPI_REGISTER_CONTEXT *RegisterContext, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + DATABASE_RECORD Record; > + GPIO_PAD GpioPad; > + UINT8 GpiSmiBitOffset; > + UINT32 GpiHostSwOwnRegAddress; > + UINT32 GpiSmiStsRegAddress; > + UINT32 Data32Or; > + UINT32 Data32And; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the EndOfDxe event > has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + Status =3D GpioGetPadAndSmiRegs ( > + (UINT32) RegisterContext->GpiNum, > + &GpioPad, > + &GpiSmiBitOffset, > + &GpiHostSwOwnRegAddress, > + &GpiSmiStsRegAddress > + ); > + > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + ZeroMem (&Record, sizeof (DATABASE_RECORD)); > + > + // > + // Gather information about the registration request > + // > + Record.Callback =3D DispatchFunction; > + Record.ChildContext.Gpi =3D *RegisterContext; > + Record.ProtocolType =3D GpiType; > + Record.Signature =3D DATABASE_RECORD_SIGNATURE; > + > + CopyMem (&Record.SrcDesc, &mPchGpiSourceDescTemplate, sizeof > (PCH_SMM_SOURCE_DESC) ); > + > + Record.SrcDesc.Sts[0].Reg.Data.raw =3D GpiSmiStsRegAddress; // GPI SM= I > Status register > + Record.SrcDesc.Sts[0].Bit =3D GpiSmiBitOffset; // Bit po= sition for > selected pad > + > + // > + // Insert GpiSmi handler to PchSmmCore database > + // > + *DispatchHandle =3D NULL; > + > + Status =3D SmmCoreInsertRecord ( > + &Record, > + DispatchHandle > + ); > + ASSERT_EFI_ERROR (Status); > + > + SmiHandlerProfileRegisterHandler (&gEfiSmmGpiDispatch2ProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2) DispatchFunction, > (UINTN)RETURN_ADDRESS (0), (void *)RegisterContext, > sizeof(*RegisterContext)); > + > + // > + // Enable GPI SMI > + // HOSTSW_OWN with respect to generating GPI SMI has negative logic: > + // - 0 (ACPI mode) - GPIO pad will be capable of generating SMI/NMI/S= CI > + // - 1 (GPIO mode) - GPIO pad will not generate SMI/NMI/SCI > + // > + Data32And =3D (UINT32)~(1u << GpiSmiBitOffset); > + MmioAnd32 (GpiHostSwOwnRegAddress, Data32And); > + > + // > + // Add HOSTSW_OWN programming into S3 boot script > + // > + Data32Or =3D 0; > + S3BootScriptSaveMemReadWrite (S3BootScriptWidthUint32, > GpiHostSwOwnRegAddress, &Data32Or, &Data32And); > + > + return EFI_SUCCESS; > +} > + > +/** > + Unregister a GPI SMI source dispatch function with a parent SMM driver > + > + @param[in] This Pointer to the > EFI_SMM_GPI_DISPATCH2_PROTOCOL instance. > + @param[in] DispatchHandle Handle of dispatch function to deregis= ter. > + > + @retval EFI_SUCCESS The dispatch function has been success= fully > + unregistered and the SMI source has be= en disabled > + if there are no other registered child= dispatch > + functions for this SMI source. > + @retval EFI_INVALID_PARAMETER Handle is invalid. > +**/ > +EFI_STATUS > +EFIAPI > +PchGpiSmiUnRegister ( > + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This, > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + DATABASE_RECORD *RecordToDelete; > + DATABASE_RECORD *RecordInDb; > + LIST_ENTRY *LinkInDb; > + GPIO_PAD GpioPad; > + UINT8 GpiSmiBitOffset; > + UINT32 GpiHostSwOwnRegAddress; > + UINT32 GpiSmiStsRegAddress; > + UINT32 Data32Or; > + UINT32 Data32And; > + BOOLEAN DisableGpiSmiSource; > + > + > + if (DispatchHandle =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); > + if ((RecordToDelete->Signature !=3D DATABASE_RECORD_SIGNATURE) || > + (RecordToDelete->ProtocolType !=3D GpiType)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the > SmmReadyToLock event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + DisableGpiSmiSource =3D TRUE; > + // > + // Loop through all sources in record linked list to see if any other = GPI SMI > + // is installed on the same pin. If no then disable GPI SMI capability= on this > pad > + // > + LinkInDb =3D GetFirstNode (&mPrivateData.CallbackDataBase); > + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { > + RecordInDb =3D DATABASE_RECORD_FROM_LINK (LinkInDb); > + LinkInDb =3D GetNextNode (&mPrivateData.CallbackDataBase, > &RecordInDb->Link); > + // > + // If this is the record to delete skip it > + // > + if (RecordInDb =3D=3D RecordToDelete) { > + continue; > + } > + // > + // Check if record is GPI SMI type > + // > + if (RecordInDb->ProtocolType =3D=3D GpiType) { > + // > + // Check if same GPIO pad is the source of this SMI > + // > + if (RecordInDb->ChildContext.Gpi.GpiNum =3D=3D > RecordToDelete->ChildContext.Gpi.GpiNum) { > + DisableGpiSmiSource =3D FALSE; > + break; > + } > + } > + } > + > + if (DisableGpiSmiSource) { > + GpioGetPadAndSmiRegs ( > + (UINT32) RecordToDelete->ChildContext.Gpi.GpiNum, > + &GpioPad, > + &GpiSmiBitOffset, > + &GpiHostSwOwnRegAddress, > + &GpiSmiStsRegAddress > + ); > + > + Data32Or =3D 1u << GpiSmiBitOffset; > + Data32And =3D 0xFFFFFFFF; > + MmioOr32 (GpiHostSwOwnRegAddress, Data32Or); > + S3BootScriptSaveMemReadWrite (S3BootScriptWidthUint32, > GpiHostSwOwnRegAddress, &Data32Or, &Data32And); > + } > + > + > + RemoveEntryList (&RecordToDelete->Link); > + ZeroMem (RecordToDelete, sizeof (DATABASE_RECORD)); > + Status =3D gSmst->SmmFreePool (RecordToDelete); > + > + if (EFI_ERROR (Status)) { > + ASSERT (FALSE); > + return Status; > + } > + SmiHandlerProfileUnregisterHandler (&gEfiSmmGpiDispatch2ProtocolGuid, > RecordToDelete->Callback, NULL, 0); > + return EFI_SUCCESS; > +} > diff --git > a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHe > lpers.c > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHe > lpers.c > new file mode 100644 > index 0000000000..f6413921eb > --- /dev/null > +++ > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHe > lpers.c > @@ -0,0 +1,358 @@ > +/** @file > + Helper functions for PCH SMM dispatcher. > + > + Copyright (c) 2019 Intel Corporation. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#include "PchSmmHelpers.h" > +#include > +#include > +#include > +#include > + > +/// > +/// #define BIT_ZERO 0x00000001 > +/// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT32 BIT_ZERO =3D > 0x00000001; > + > +/// > +/// SUPPORT / HELPER FUNCTIONS (PCH version-independent) > +/// > + > +/** > + Compare 2 SMM source descriptors' enable settings. > + > + @param[in] Src1 Pointer to the PCH SMI source descript= ion > table 1 > + @param[in] Src2 Pointer to the PCH SMI source descript= ion > table 2 > + > + @retval TRUE The enable settings of the 2 SMM sourc= e > descriptors are identical. > + @retval FALSE The enable settings of the 2 SMM sourc= e > descriptors are not identical. > +**/ > +BOOLEAN > +CompareEnables ( > + CONST IN PCH_SMM_SOURCE_DESC *Src1, > + CONST IN PCH_SMM_SOURCE_DESC *Src2 > + ) > +{ > + BOOLEAN IsEqual; > + UINTN DescIndex; > + > + IsEqual =3D TRUE; > + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; DescIndex++) { > + /// > + /// It's okay to compare a NULL bit description to a non-NULL bit > description. > + /// They are unequal and these tests will generate the correct resul= t. > + /// > + if (Src1->En[DescIndex].Bit !=3D Src2->En[DescIndex].Bit || > + Src1->En[DescIndex].Reg.Type !=3D Src2->En[DescIndex].Reg.Type |= | > + Src1->En[DescIndex].Reg.Data.raw !=3D > Src2->En[DescIndex].Reg.Data.raw > + ) { > + IsEqual =3D FALSE; > + break; > + /// > + /// out of for loop > + /// > + } > + } > + > + return IsEqual; > +} > + > +/** > + Compare a bit descriptor to the enables of source descriptor. Includes= null > address type. > + > + @param[in] BitDesc Pointer to the PCH SMI bit descriptor > + @param[in] Src Pointer to the PCH SMI source descript= ion > table 2 > + > + @retval TRUE The bit desc is equal to any of the en= ables in > source descriptor > + @retval FALSE The bid desc is not equal to all of th= e enables in > source descriptor > +**/ > +BOOLEAN > +IsBitEqualToAnySourceEn ( > + CONST IN PCH_SMM_BIT_DESC *BitDesc, > + CONST IN PCH_SMM_SOURCE_DESC *Src > + ) > +{ > + BOOLEAN IsEqual; > + UINTN DescIndex; > + > + IsEqual =3D FALSE; > + > + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; ++DescIndex) { > + if ((BitDesc->Reg.Type =3D=3D Src->En[DescIndex].Reg.Type) && > + (BitDesc->Reg.Data.raw =3D=3D Src->En[DescIndex].Reg.Data.raw) &= & > + (BitDesc->Bit =3D=3D Src->En[DescIndex].Bit)) { > + IsEqual =3D TRUE; > + break; > + } > + } > + return IsEqual; > +} > + > +/** > + Compare 2 SMM source descriptors' statuses. > + > + @param[in] Src1 Pointer to the PCH SMI source descript= ion > table 1 > + @param[in] Src2 Pointer to the PCH SMI source descript= ion > table 2 > + > + @retval TRUE The statuses of the 2 SMM source descr= iptors > are identical. > + @retval FALSE The statuses of the 2 SMM source descr= iptors > are not identical. > +**/ > +BOOLEAN > +CompareStatuses ( > + CONST IN PCH_SMM_SOURCE_DESC *Src1, > + CONST IN PCH_SMM_SOURCE_DESC *Src2 > + ) > +{ > + BOOLEAN IsEqual; > + UINTN DescIndex; > + > + IsEqual =3D TRUE; > + > + for (DescIndex =3D 0; DescIndex < NUM_STS_BITS; DescIndex++) { > + /// > + /// It's okay to compare a NULL bit description to a non-NULL bit > description. > + /// They are unequal and these tests will generate the correct resul= t. > + /// > + if (Src1->Sts[DescIndex].Bit !=3D Src2->Sts[DescIndex].Bit || > + Src1->Sts[DescIndex].Reg.Type !=3D Src2->Sts[DescIndex].Reg.Type= || > + Src1->Sts[DescIndex].Reg.Data.raw !=3D > Src2->Sts[DescIndex].Reg.Data.raw > + ) { > + IsEqual =3D FALSE; > + break; > + /// > + /// out of for loop > + /// > + } > + } > + > + return IsEqual; > +} > + > +/** > + Compare 2 SMM source descriptors, based on Enable settings and Status > settings of them. > + > + @param[in] Src1 Pointer to the PCH SMI source descript= ion > table 1 > + @param[in] Src2 Pointer to the PCH SMI source descript= ion > table 2 > + > + @retval TRUE The 2 SMM source descriptors are ident= ical. > + @retval FALSE The 2 SMM source descriptors are not i= dentical. > +**/ > +BOOLEAN > +CompareSources ( > + CONST IN PCH_SMM_SOURCE_DESC *Src1, > + CONST IN PCH_SMM_SOURCE_DESC *Src2 > + ) > +{ > + return (BOOLEAN) (CompareEnables (Src1, Src2) && CompareStatuses (Src1= , > Src2)); > +} > + > +/** > + Check if an SMM source is active. > + > + @param[in] Src Pointer to the PCH SMI source descript= ion > table > + @param[in] SciEn Indicate if SCI is enabled or not > + @param[in] SmiEnValue Value from R_ACPI_IO_SMI_EN > + @param[in] SmiStsValue Value from R_ACPI_IO_SMI_STS > + > + @retval TRUE It is active. > + @retval FALSE It is inactive. > +**/ > +BOOLEAN > +SourceIsActive ( > + CONST IN PCH_SMM_SOURCE_DESC *Src, > + CONST IN BOOLEAN SciEn, > + CONST IN UINT32 SmiEnValue, > + CONST IN UINT32 SmiStsValue > + ) > +{ > + UINTN DescIndex; > + > + /// > + /// This source is dependent on SciEn, and SciEn =3D=3D 1. An ACPI OS= is present, > + /// so we shouldn't do anything w/ this source until SciEn =3D=3D 0. > + /// > + if ((Src->Flags =3D=3D PCH_SMM_SCI_EN_DEPENDENT) && (SciEn)) { > + return FALSE; > + } > + > + /// > + /// Checking top level SMI status. If the status is not active, return= false > immediately > + /// > + if (!IS_BIT_DESC_NULL (Src->PmcSmiSts)) { > + if ((Src->PmcSmiSts.Reg.Type =3D=3D ACPI_ADDR_TYPE) && > + (Src->PmcSmiSts.Reg.Data.acpi =3D=3D R_ACPI_IO_SMI_STS) && > + ((SmiStsValue & (1u << Src->PmcSmiSts.Bit)) =3D=3D 0)) { > + return FALSE; > + } > + } > + > + // > + // Special handling for NMI bit since it requires PMC IPC command. > + // Do w/a here instead of in ReadBitDesc to reduce the PMC IPC command > usage. > + // > + // The PCR[ITSS].NMI register can only be accessed with BOOT_SAI and > SMM_SAI. > + // Since in CFL there is no SMM_SAI it needs PMC assistance to access = this > register. > + // > + if ((Src->En[0].Reg.Data.Pcr.Fields.Pid =3D=3D PID_ITSS) && > + (Src->En[0].Reg.Data.Pcr.Fields.Offset =3D=3D R_ITSS_PCR_NMI)) > + { > + UINT32 ItssNmi; > + ItssNmi =3D PmcGetNmiControl (); > + if ((ItssNmi & (BIT0 << Src->En[0].Bit)) && > + (ItssNmi & (BIT0 << Src->Sts[0].Bit))) > + { > + return TRUE; > + } else { > + return FALSE; > + } > + } > + > + /// > + /// Read each bit desc from hardware and make sure it's a one > + /// > + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; DescIndex++) { > + if (!IS_BIT_DESC_NULL (Src->En[DescIndex])) { > + if ((Src->En[DescIndex].Reg.Type =3D=3D ACPI_ADDR_TYPE) && > + (Src->En[DescIndex].Reg.Data.acpi =3D=3D R_ACPI_IO_SMI_EN) && > + ((SmiEnValue & (1u << Src->En[DescIndex].Bit)) =3D=3D 0)) { > + return FALSE; > + } else if (ReadBitDesc (&Src->En[DescIndex]) =3D=3D 0) { > + return FALSE; > + } > + } > + } > + > + /// > + /// Read each bit desc from hardware and make sure it's a one > + /// > + for (DescIndex =3D 0; DescIndex < NUM_STS_BITS; DescIndex++) { > + if (!IS_BIT_DESC_NULL (Src->Sts[DescIndex])) { > + if ((Src->Sts[DescIndex].Reg.Type =3D=3D ACPI_ADDR_TYPE) && > + (Src->Sts[DescIndex].Reg.Data.acpi =3D=3D R_ACPI_IO_SMI_STS) &= & > + ((SmiStsValue & (1u << Src->Sts[DescIndex].Bit)) =3D=3D 0)) { > + return FALSE; > + } else if (ReadBitDesc (&Src->Sts[DescIndex]) =3D=3D 0) { > + return FALSE; > + } > + } > + } > + > + return TRUE; > +} > + > +/** > + Enable the SMI source event by set the SMI enable bit, this function w= ould > also clear SMI > + status bit to make initial state is correct > + > + @param[in] SrcDesc Pointer to the PCH SMI source descript= ion > table > + > +**/ > +VOID > +PchSmmEnableSource ( > + CONST PCH_SMM_SOURCE_DESC *SrcDesc > + ) > +{ > + UINTN DescIndex; > + > + /// > + /// Set enables to 1 by writing a 1 > + /// > + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; DescIndex++) { > + if (!IS_BIT_DESC_NULL (SrcDesc->En[DescIndex])) { > + WriteBitDesc (&SrcDesc->En[DescIndex], 1, FALSE); > + } > + } > + /// > + /// Clear statuses to 0 by writing a 1 > + /// > + for (DescIndex =3D 0; DescIndex < NUM_STS_BITS; DescIndex++) { > + if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) { > + WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE); > + } > + } > +} > + > +/** > + Disable the SMI source event by clear the SMI enable bit > + > + @param[in] SrcDesc Pointer to the PCH SMI source descript= ion > table > + > +**/ > +VOID > +PchSmmDisableSource ( > + CONST PCH_SMM_SOURCE_DESC *SrcDesc > + ) > +{ > + UINTN DescIndex; > + > + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; DescIndex++) { > + if (!IS_BIT_DESC_NULL (SrcDesc->En[DescIndex])) { > + WriteBitDesc (&SrcDesc->En[DescIndex], 0, FALSE); > + } > + } > +} > + > +/** > + Clear the SMI status bit by set the source bit of SMI status register > + > + @param[in] SrcDesc Pointer to the PCH SMI source descript= ion > table > + > +**/ > +VOID > +PchSmmClearSource ( > + CONST PCH_SMM_SOURCE_DESC *SrcDesc > + ) > +{ > + UINTN DescIndex; > + > + for (DescIndex =3D 0; DescIndex < NUM_STS_BITS; DescIndex++) { > + if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) { > + WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE); > + } > + } > +} > + > +/** > + Sets the source to a 1 and then waits for it to clear. > + Be very careful when calling this function -- it will not > + ASSERT. An acceptable case to call the function is when > + waiting for the NEWCENTURY_STS bit to clear (which takes > + 3 RTCCLKs). > + > + @param[in] SrcDesc Pointer to the PCH SMI source descript= ion > table > + > +**/ > +VOID > +PchSmmClearSourceAndBlock ( > + CONST PCH_SMM_SOURCE_DESC *SrcDesc > + ) > +{ > + UINTN DescIndex; > + BOOLEAN IsSet; > + > + for (DescIndex =3D 0; DescIndex < NUM_STS_BITS; DescIndex++) { > + > + if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) { > + /// > + /// Write the bit > + /// > + WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE); > + > + /// > + /// Don't return until the bit actually clears. > + /// > + IsSet =3D TRUE; > + while (IsSet) { > + IsSet =3D ReadBitDesc (&SrcDesc->Sts[DescIndex]); > + /// > + /// IsSet will eventually clear -- or else we'll have > + /// an infinite loop. > + /// > + } > + } > + } > +} > + > diff --git > a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPe > riodicTimer.c > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPe > riodicTimer.c > new file mode 100644 > index 0000000000..9a5ae464e0 > --- /dev/null > +++ > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPe > riodicTimer.c > @@ -0,0 +1,675 @@ > +/** @file > + File to contain all the hardware specific stuff for the Periodical Tim= er > dispatch protocol. > + > + Copyright (c) 2019 Intel Corporation. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#include "PchSmmHelpers.h" > +#include > +#include > + > +// > +// There is only one instance for PeriodicTimerCommBuffer. > +// It's safe in SMM since there is no re-entry for the function. > +// > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_PERIODIC_TIMER_CONTEXT > mPchPeriodicTimerCommBuffer; > + > +typedef enum { > + PERIODIC_TIMER=3D 0, > + SWSMI_TIMER, > + NUM_TIMERS > +} SUPPORTED_TIMER; > + > +typedef struct _TIMER_INTERVAL { > + UINT64 Interval; > + UINT8 AssociatedTimer; > +} TIMER_INTERVAL; > + > +#define NUM_INTERVALS 8 > + > +// > +// Time constants, in 100 nano-second units > +// > +#define TIME_64s 640000000 ///< 64 s > +#define TIME_32s 320000000 ///< 32 s > +#define TIME_16s 160000000 ///< 16 s > +#define TIME_8s 80000000 ///< 8 s > +#define TIME_64ms 640000 ///< 64 ms > +#define TIME_32ms 320000 ///< 32 ms > +#define TIME_16ms 160000 ///< 16 ms > +#define TIME_1_5ms 15000 ///< 1.5 ms > + > +typedef enum { > + INDEX_TIME_64s =3D 0, > + INDEX_TIME_32s, > + INDEX_TIME_16s, > + INDEX_TIME_8s, > + INDEX_TIME_64ms, > + INDEX_TIME_32ms, > + INDEX_TIME_16ms, > + INDEX_TIME_1_5ms, > + INDEX_TIME_MAX > +} TIMER_INTERVAL_INDEX; > + > +static TIMER_INTERVAL mSmmPeriodicTimerIntervals[NUM_INTERVALS] =3D { > + { > + TIME_64s, > + PERIODIC_TIMER > + }, > + { > + TIME_32s, > + PERIODIC_TIMER > + }, > + { > + TIME_16s, > + PERIODIC_TIMER > + }, > + { > + TIME_8s, > + PERIODIC_TIMER > + }, > + { > + TIME_64ms, > + SWSMI_TIMER > + }, > + { > + TIME_32ms, > + SWSMI_TIMER > + }, > + { > + TIME_16ms, > + SWSMI_TIMER > + }, > + { > + TIME_1_5ms, > + SWSMI_TIMER > + }, > +}; > + > +typedef struct _TIMER_INFO { > + UINTN NumChildren; ///< number of children using this timer > + UINT64 MinReqInterval; ///< minimum interval required by children > + UINTN CurrentSetting; ///< interval this timer is set at right n= ow (index > into interval table) > +} TIMER_INFO; > + > +GLOBAL_REMOVE_IF_UNREFERENCED TIMER_INFO > mTimers[NUM_TIMERS]; > + > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mTimerSourceDesc[NUM_TIMERS] =3D { > + { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_EN} > + }, > + S_ACPI_IO_SMI_EN, > + N_ACPI_IO_SMI_EN_PERIODIC > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_PERIODIC > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_PERIODIC > + } > + }, > + { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_EN} > + }, > + S_ACPI_IO_SMI_EN, > + N_ACPI_IO_SMI_EN_SWSMI_TMR > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_SWSMI_TMR > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_SWSMI_TMR > + } > + } > +}; > + > +/** > + Program Smm Periodic Timer > + > + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC > instance. > +**/ > +VOID > +PchSmmPeriodicTimerProgramTimers ( > + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc > + ); > + > +/** > + Convert the dispatch context to the timer interval, this function will= assert > if then either: > + (1) The context contains an invalid interval > + (2) The timer interval table is corrupt > + > + @param[in] DispatchContext The pointer to the Dispatch Context > + > + @retval TIMER_INTERVAL The timer interval of input dispatch > context > +**/ > +TIMER_INTERVAL * > +ContextToTimerInterval ( > + IN PCH_SMM_CONTEXT *DispatchContext > + ) > +{ > + UINTN loopvar; > + > + /// > + /// Determine which timer this child is using > + /// > + for (loopvar =3D 0; loopvar < NUM_INTERVALS; loopvar++) { > + if (((DispatchContext->PeriodicTimer.SmiTickInterval =3D=3D 0) && > + (DispatchContext->PeriodicTimer.Period >=3D > mSmmPeriodicTimerIntervals[loopvar].Interval)) || > + (DispatchContext->PeriodicTimer.SmiTickInterval =3D=3D > mSmmPeriodicTimerIntervals[loopvar].Interval)) { > + return &mSmmPeriodicTimerIntervals[loopvar]; > + } > + } > + /// > + /// If this assertion fires, then either: > + /// (1) the context contains an invalid interval > + /// (2) the timer interval table is corrupt > + /// > + ASSERT (FALSE); > + > + return NULL; > +} > + > +/** > + Figure out which timer the child is requesting and > + send back the source description > + > + @param[in] DispatchContext The pointer to the Dispatch Context > instances > + @param[out] SrcDesc The pointer to the source description > + > +**/ > +VOID > +MapPeriodicTimerToSrcDesc ( > + IN PCH_SMM_CONTEXT *DispatchContext, > + OUT PCH_SMM_SOURCE_DESC *SrcDesc > + ) > +{ > + TIMER_INTERVAL *TimerInterval; > + > + /// > + /// Figure out which timer the child is requesting and > + /// send back the source description > + /// > + TimerInterval =3D ContextToTimerInterval (DispatchContext); > + if (TimerInterval =3D=3D NULL) { > + return; > + } > + > + CopyMem ( > + (VOID *) SrcDesc, > + (VOID *) (&mTimerSourceDesc[TimerInterval->AssociatedTimer]), > + sizeof (PCH_SMM_SOURCE_DESC) > + ); > + > + /// > + /// Program the value of the interval into hardware > + /// > + PchSmmPeriodicTimerProgramTimers (SrcDesc); > +} > + > +/** > + Update the elapsed time from the Interval data of DATABASE_RECORD > + > + @param[in] Record The pointer to the DATABASE_RECORD. > + @param[out] HwContext The Context to be updated. > + > +**/ > +VOID > +EFIAPI > +PeriodicTimerGetContext ( > + IN DATABASE_RECORD *Record, > + OUT PCH_SMM_CONTEXT *HwContext > + ) > +{ > + TIMER_INTERVAL *TimerInterval; > + > + ASSERT (Record->ProtocolType =3D=3D PeriodicTimerType); > + > + TimerInterval =3D ContextToTimerInterval (&Record->ChildContext); > + if (TimerInterval =3D=3D NULL) { > + return; > + } > + /// > + /// Ignore the hardware context. It's not required for this protocol. > + /// Instead, just increment the child's context. > + /// Update the elapsed time w/ the data from our tables > + /// > + Record->MiscData.ElapsedTime +=3D > mTimers[TimerInterval->AssociatedTimer].MinReqInterval; > + *HwContext =3D Record->ChildContext; > +} > + > +/** > + Check whether Periodic Timer of two contexts match > + > + @param[in] Context1 Context 1 that includes Periodic Timer= 1 > + @param[in] Context2 Context 2 that includes Periodic Timer= 2 > + > + @retval FALSE Periodic Timer match > + @retval TRUE Periodic Timer don't match > +**/ > +BOOLEAN > +EFIAPI > +PeriodicTimerCmpContext ( > + IN PCH_SMM_CONTEXT *HwContext, > + IN PCH_SMM_CONTEXT *ChildContext > + ) > +{ > + DATABASE_RECORD *Record; > + Record =3D DATABASE_RECORD_FROM_CHILDCONTEXT (ChildContext); > + > + if (Record->MiscData.ElapsedTime >=3D ChildContext->PeriodicTimer.Peri= od) > { > + /// > + /// For EDKII, the ElapsedTime is reset when PeriodicTimerGetCommBuf= fer > + /// > + return TRUE; > + } else { > + return FALSE; > + } > +} > + > +/** > + Gather the CommBuffer information of SmmPeriodicTimerDispatch2. > + > + @param[in] Record No use > + @param[out] CommBuffer Point to the CommBuffer structure > + @param[out] CommBufferSize Point to the Size of CommBuffer > structure > + > +**/ > +VOID > +EFIAPI > +PeriodicTimerGetCommBuffer ( > + IN DATABASE_RECORD *Record, > + OUT VOID **CommBuffer, > + OUT UINTN *CommBufferSize > + ) > +{ > + ASSERT (Record->ProtocolType =3D=3D PeriodicTimerType); > + > + mPchPeriodicTimerCommBuffer.ElapsedTime =3D > Record->MiscData.ElapsedTime; > + > + /// > + /// For EDKII, the ElapsedTime is reset here > + /// > + Record->MiscData.ElapsedTime =3D 0; > + > + /// > + /// Return the CommBuffer > + /// > + *CommBuffer =3D (VOID *) &mPchPeriodicTimerCommBuffer; > + *CommBufferSize =3D sizeof (EFI_SMM_PERIODIC_TIMER_CONTEXT); > +} > + > +/** > + Program Smm Periodic Timer > + > + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC > instance. > +**/ > +VOID > +PchSmmPeriodicTimerProgramTimers ( > + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc > + ) > +{ > + SUPPORTED_TIMER Timer; > + DATABASE_RECORD *RecordInDb; > + LIST_ENTRY *LinkInDb; > + TIMER_INTERVAL *TimerInterval; > + > + /// > + /// Find the minimum required interval for each timer > + /// > + for (Timer =3D 0; Timer < NUM_TIMERS; Timer++) { > + mTimers[Timer].MinReqInterval =3D ~ (UINT64) 0x0; > + mTimers[Timer].NumChildren =3D 0; > + } > + > + LinkInDb =3D GetFirstNode (&mPrivateData.CallbackDataBase); > + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { > + RecordInDb =3D DATABASE_RECORD_FROM_LINK (LinkInDb); > + if (RecordInDb->ProtocolType =3D=3D PeriodicTimerType) { > + /// > + /// This child is registerd with the PeriodicTimer protocol > + /// > + TimerInterval =3D ContextToTimerInterval (&RecordInDb->ChildContex= t); > + if (TimerInterval =3D=3D NULL) { > + return; > + } > + > + Timer =3D TimerInterval->AssociatedTimer; > + if (Timer < 0 || Timer >=3D NUM_TIMERS) { > + ASSERT (FALSE); > + CpuDeadLoop (); > + return; > + } > + > + if (mTimers[Timer].MinReqInterval > > RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval) { > + mTimers[Timer].MinReqInterval =3D > RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval; > + } > + > + mTimers[Timer].NumChildren++; > + } > + > + LinkInDb =3D GetNextNode (&mPrivateData.CallbackDataBase, > &RecordInDb->Link); > + } > + /// > + /// Program the hardware > + /// > + if (mTimers[PERIODIC_TIMER].NumChildren > 0) { > + switch (mTimers[PERIODIC_TIMER].MinReqInterval) { > + case TIME_64s: > + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate64s); > + mTimers[PERIODIC_TIMER].CurrentSetting =3D INDEX_TIME_64s; > + break; > + > + case TIME_32s: > + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate32s); > + mTimers[PERIODIC_TIMER].CurrentSetting =3D INDEX_TIME_32s; > + break; > + > + case TIME_16s: > + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate16s); > + mTimers[PERIODIC_TIMER].CurrentSetting =3D INDEX_TIME_16s; > + break; > + > + case TIME_8s: > + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate8s); > + mTimers[PERIODIC_TIMER].CurrentSetting =3D INDEX_TIME_8s; > + break; > + > + default: > + ASSERT (FALSE); > + break; > + } > + > + /// > + /// Restart the timer here, just need to clear the SMI > + /// > + if (SrcDesc->Sts[0].Bit =3D=3D N_ACPI_IO_SMI_STS_PERIODIC) { > + PchSmmClearSource (&mTimerSourceDesc[PERIODIC_TIMER]); > + } > + } else { > + PchSmmDisableSource (&mTimerSourceDesc[PERIODIC_TIMER]); > + } > + > + if (mTimers[SWSMI_TIMER].NumChildren > 0) { > + switch (mTimers[SWSMI_TIMER].MinReqInterval) { > + case TIME_64ms: > + PmcSetSwSmiRate (PmcSwSmiRate64ms); > + mTimers[SWSMI_TIMER].CurrentSetting =3D INDEX_TIME_64ms; > + break; > + > + case TIME_32ms: > + PmcSetSwSmiRate (PmcSwSmiRate32ms); > + mTimers[SWSMI_TIMER].CurrentSetting =3D INDEX_TIME_32ms; > + break; > + > + case TIME_16ms: > + PmcSetSwSmiRate (PmcSwSmiRate16ms); > + mTimers[SWSMI_TIMER].CurrentSetting =3D INDEX_TIME_16ms; > + break; > + > + case TIME_1_5ms: > + PmcSetSwSmiRate (PmcSwSmiRate1p5ms); > + mTimers[SWSMI_TIMER].CurrentSetting =3D INDEX_TIME_1_5ms; > + break; > + > + default: > + ASSERT (FALSE); > + break; > + } > + > + /// > + /// Restart the timer here, need to disable, clear, then enable to r= estart > this timer > + /// > + if (SrcDesc->Sts[0].Bit =3D=3D N_ACPI_IO_SMI_STS_SWSMI_TMR) { > + PchSmmDisableSource (&mTimerSourceDesc[SWSMI_TIMER]); > + PchSmmClearSource (&mTimerSourceDesc[SWSMI_TIMER]); > + PchSmmEnableSource (&mTimerSourceDesc[SWSMI_TIMER]); > + } > + } else { > + PchSmmDisableSource (&mTimerSourceDesc[SWSMI_TIMER]); > + } > +} > + > +/** > + This services returns the next SMI tick period that is supported by th= e > chipset. > + The order returned is from longest to shortest interval period. > + > + @param[in] This Pointer to the > EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL instance. > + @param[in, out] SmiTickInterval Pointer to pointer of the next shorter= SMI > interval period that is supported by the child. > + > + @retval EFI_SUCCESS The service returned successfully. > + @retval EFI_INVALID_PARAMETER The parameter SmiTickInterval is > invalid. > +**/ > +EFI_STATUS > +PchSmmPeriodicTimerDispatchGetNextShorterInterval ( > + IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This, > + IN OUT UINT64 **SmiTickInterval > + ) > +{ > + TIMER_INTERVAL *IntervalPointer; > + > + if (SmiTickInterval =3D=3D NULL) { > + ASSERT(FALSE); > + return EFI_INVALID_PARAMETER; > + } > + > + IntervalPointer =3D (TIMER_INTERVAL *) *SmiTickInterval; > + > + if (IntervalPointer =3D=3D NULL) { > + /// > + /// The first time child requesting an interval > + /// > + IntervalPointer =3D &mSmmPeriodicTimerIntervals[0]; > + } else if (IntervalPointer =3D=3D > &mSmmPeriodicTimerIntervals[NUM_INTERVALS - 1]) { > + /// > + /// At end of the list > + /// > + IntervalPointer =3D NULL; > + } else { > + if ((IntervalPointer >=3D &mSmmPeriodicTimerIntervals[0]) && > + (IntervalPointer < &mSmmPeriodicTimerIntervals[NUM_INTERVALS - > 1]) > + ) { > + /// > + /// Get the next interval in the list > + /// > + IntervalPointer++; > + } else { > + /// > + /// Input is out of range > + /// > + return EFI_INVALID_PARAMETER; > + } > + } > + > + if (IntervalPointer !=3D NULL) { > + *SmiTickInterval =3D &IntervalPointer->Interval; > + } else { > + *SmiTickInterval =3D NULL; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + This function is responsible for calculating and enabling any timers t= hat are > required > + to dispatch messages to children. The SrcDesc argument isn't acutally = used. > + > + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC > instance. > + > +**/ > +VOID > +EFIAPI > +PchSmmPeriodicTimerClearSource ( > + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc > + ) > +{ > + PchSmmPeriodicTimerProgramTimers (SrcDesc); > +} > + > + > +/** > + Check if the handle is in type of PeriodicTimer > + > + @retval TRUE The handle is in type of Periodi= cTimer. > + @retval FALSE The handle is not in type of Per= iodicTimer. > +**/ > +BOOLEAN > +IsSmmPeriodicTimerHandle ( > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + DATABASE_RECORD *RecordInDb; > + LIST_ENTRY *LinkInDb; > + > + LinkInDb =3D GetFirstNode (&mPrivateData.CallbackDataBase); > + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { > + if (DispatchHandle =3D=3D (EFI_HANDLE) LinkInDb) { > + RecordInDb =3D DATABASE_RECORD_FROM_LINK (LinkInDb); > + if (RecordInDb->ProtocolType =3D=3D PeriodicTimerType) { > + return TRUE; > + } > + } > + LinkInDb =3D GetNextNode (&mPrivateData.CallbackDataBase, LinkInDb); > + } > + return FALSE; > +} > + > +/** > + Pause SMM periodic timer callback function. > + > + This function disable the SMI enable of SMI timer according to the > DispatchHandle, > + which is returned by SMM periodic timer callback registration. > + > + @retval EFI_SUCCESS This operation is complete. > + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. > +**/ > +EFI_STATUS > +EFIAPI > +PchSmmPeriodicTimerControlPause ( > + IN PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL *This, > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + DATABASE_RECORD *RecordInDb; > + TIMER_INTERVAL *TimerInterval; > + > + if (IsSmmPeriodicTimerHandle (DispatchHandle) =3D=3D FALSE) { > + return EFI_INVALID_PARAMETER; > + } > + > + RecordInDb =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); > + TimerInterval =3D NULL; > + TimerInterval =3D ContextToTimerInterval (&RecordInDb->ChildContext); > + if (TimerInterval =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + PchSmmDisableSource > (&mTimerSourceDesc[TimerInterval->AssociatedTimer]); > + return EFI_SUCCESS; > +} > + > +/** > + Resume SMM periodic timer callback function. > + > + This function enable the SMI enable of SMI timer according to the > DispatchHandle, > + which is returned by SMM periodic timer callback registration. > + > + @retval EFI_SUCCESS This operation is complete. > + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. > +**/ > +EFI_STATUS > +EFIAPI > +PchSmmPeriodicTimerControlResume ( > + IN PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL *This, > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + DATABASE_RECORD *RecordInDb; > + TIMER_INTERVAL *TimerInterval; > + > + if (IsSmmPeriodicTimerHandle (DispatchHandle) =3D=3D FALSE) { > + return EFI_INVALID_PARAMETER; > + } > + > + RecordInDb =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); > + TimerInterval =3D NULL; > + TimerInterval =3D ContextToTimerInterval (&RecordInDb->ChildContext); > + if (TimerInterval =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + PchSmmEnableSource > (&mTimerSourceDesc[TimerInterval->AssociatedTimer]); > + return EFI_SUCCESS; > +} > + > +GLOBAL_REMOVE_IF_UNREFERENCED > PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL > mPchSmmPeriodicTimerControlProtocol =3D { > + PchSmmPeriodicTimerControlPause, > + PchSmmPeriodicTimerControlResume > +}; > + > +/** > + Install PCH SMM periodic timer control protocol > + > + @param[in] Handle handle for this driver > + > + @retval EFI_SUCCESS Driver initialization completed > successfully > +**/ > +EFI_STATUS > +EFIAPI > +InstallPchSmmPeriodicTimerControlProtocol ( > + IN EFI_HANDLE Handle > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Install protocol interface > + // > + Status =3D gSmst->SmmInstallProtocolInterface ( > + &Handle, > + &gPchSmmPeriodicTimerControlGuid, > + EFI_NATIVE_INTERFACE, > + &mPchSmmPeriodicTimerControlProtocol > + ); > + ASSERT_EFI_ERROR (Status); > + > + return EFI_SUCCESS; > +} > + > diff --git > a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPo > werButton.c > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPo > werButton.c > new file mode 100644 > index 0000000000..17898b899b > --- /dev/null > +++ > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPo > werButton.c > @@ -0,0 +1,83 @@ > +/** @file > + File to contain all the hardware specific stuff for the Smm Power Butt= on > dispatch protocol. > + > + Copyright (c) 2019 Intel Corporation. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#include > +#include > + > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mPowerButtonSourceDesc =3D { > + PCH_SMM_SCI_EN_DEPENDENT, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_PM1_EN} > + }, > + S_ACPI_IO_PM1_EN, > + N_ACPI_IO_PM1_EN_PWRBTN > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_PM1_STS} > + }, > + S_ACPI_IO_PM1_STS, > + N_ACPI_IO_PM1_STS_PWRBTN > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_PM1_STS_REG > + } > +}; > + > +/** > + Get the power button status. > + > + @param[in] Record The pointer to the DATABASE_RECORD. > + @param[out] Context Calling context from the hardware, wil= l be > updated with the current power button status. > + > +**/ > +VOID > +EFIAPI > +PowerButtonGetContext ( > + IN DATABASE_RECORD *Record, > + OUT PCH_SMM_CONTEXT *Context > + ) > +{ > + if (PmcGetPwrBtnLevel ()) { > + Context->PowerButton.Phase =3D EfiPowerButtonExit; > + } else { > + Context->PowerButton.Phase =3D EfiPowerButtonEntry; > + } > +} > + > +/** > + Check whether Power Button status of two contexts match > + > + @param[in] Context1 Context 1 that includes Power Button s= tatus > 1 > + @param[in] Context2 Context 2 that includes Power Button s= tatus > 2 > + > + @retval FALSE Power Button status match > + @retval TRUE Power Button status don't match > +**/ > +BOOLEAN > +EFIAPI > +PowerButtonCmpContext ( > + IN PCH_SMM_CONTEXT *Context1, > + IN PCH_SMM_CONTEXT *Context2 > + ) > +{ > + return (BOOLEAN) (Context1->PowerButton.Phase =3D=3D > Context2->PowerButton.Phase); > +} > diff --git > a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw > .c > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw > .c > new file mode 100644 > index 0000000000..35ecfe5238 > --- /dev/null > +++ > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw > .c > @@ -0,0 +1,385 @@ > +/** @file > + File to contain all the hardware specific stuff for the Smm Sw dispatc= h > protocol. > + > + Copyright (c) 2019 Intel Corporation. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#include "PchSmmHelpers.h" > +#include > +#include > +#include > + > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_CPU_PROTOCOL > *mSmmCpuProtocol; > + > +STATIC LIST_ENTRY mSwSmiCallbackDataBase; > + > +// > +// "SWSMI" RECORD > +// Linked list data structures > +// > +#define SW_SMI_RECORD_SIGNATURE SIGNATURE_32 ('S', 'W', 'S', 'M'= ) > + > +#define SW_SMI_RECORD_FROM_LINK(_record) CR (_record, > SW_SMI_RECORD, Link, SW_SMI_RECORD_SIGNATURE) > + > +typedef struct { > + UINT32 Signature; > + LIST_ENTRY Link; > + EFI_SMM_SW_REGISTER_CONTEXT Context; > + EFI_SMM_HANDLER_ENTRY_POINT2 Callback; > +} SW_SMI_RECORD; > + > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSwSourceDesc =3D { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_EN} > + }, > + S_ACPI_IO_SMI_EN, > + N_ACPI_IO_SMI_EN_APMC > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_APM > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_APM > + } > +}; > + > +/** > + Check the SwSmiInputValue to see if there is a duplicated one in the > database > + > + @param[in] SwSmiInputValue SwSmiInputValue > + > + @retval EFI_SUCCESS There is no duplicated SwSmiInputValue > + @retval EFI_INVALID_PARAMETER There is a duplicated SwSmiInputValue > +**/ > +EFI_STATUS > +SmiInputValueDuplicateCheck ( > + IN UINTN SwSmiInputValue > + ) > +{ > + SW_SMI_RECORD *SwSmiRecord; > + LIST_ENTRY *LinkInDb; > + > + LinkInDb =3D GetFirstNode (&mSwSmiCallbackDataBase); > + while (!IsNull (&mSwSmiCallbackDataBase, LinkInDb)) { > + SwSmiRecord =3D SW_SMI_RECORD_FROM_LINK (LinkInDb); > + if (SwSmiRecord->Context.SwSmiInputValue =3D=3D SwSmiInputValue) { > + return EFI_INVALID_PARAMETER; > + } > + LinkInDb =3D GetNextNode (&mSwSmiCallbackDataBase, > &SwSmiRecord->Link); > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Register a child SMI source dispatch function for the specified softwa= re SMI. > + > + This service registers a function (DispatchFunction) which will be cal= led > when the software > + SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On > return, > + DispatchHandle contains a unique handle which may be used later to > unregister the function > + using UnRegister(). > + > + @param[in] This Pointer to the > EFI_SMM_SW_DISPATCH2_PROTOCOL instance. > + @param[in] DispatchFunction Function to register for handler when > the specified software > + SMI is generated. > + @param[in, out] RegisterContext Pointer to the dispatch function's > context. > + The caller fills this context in befo= re calling > + the register function to indicate to = the register > + function which Software SMI input val= ue the > + dispatch function should be invoked f= or. > + @param[out] DispatchHandle Handle generated by the dispatcher to > track the > + function instance. > + > + @retval EFI_SUCCESS The dispatch function has been successf= ully > + registered and the SMI source has been = enabled. > + @retval EFI_DEVICE_ERROR The SW driver was unable to enable the > SMI source. > + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The SW SMI > input value > + is not within a valid range or is alrea= dy in use. > + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or > SMM) to manage this > + child. > + @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not > be assigned > + for this dispatch. > +**/ > +EFI_STATUS > +EFIAPI > +PchSwSmiRegister ( > + IN EFI_SMM_SW_DISPATCH2_PROTOCOL *This, > + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, > + IN EFI_SMM_SW_REGISTER_CONTEXT *DispatchContext, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + SW_SMI_RECORD *SwSmiRecord; > + UINTN Index; > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + // > + // Find available SW SMI value if the input is -1 > + // > + if (DispatchContext->SwSmiInputValue =3D=3D (UINTN) -1) { > + for (Index =3D 1; Index < MAXIMUM_SWI_VALUE; Index++) { > + Status =3D SmiInputValueDuplicateCheck (Index); > + if (!EFI_ERROR (Status)) { > + DispatchContext->SwSmiInputValue =3D Index; > + break; > + } > + } > + if (DispatchContext->SwSmiInputValue =3D=3D (UINTN) -1) { > + return EFI_OUT_OF_RESOURCES; > + } > + } > + // > + // Check if it's a valid SW SMI value. > + // The value must not bigger than 0xFF. > + // And the value must not be 0xFF sincie it's used for SmmControll pro= tocol. > + // > + if (DispatchContext->SwSmiInputValue >=3D MAXIMUM_SWI_VALUE) { > + return EFI_INVALID_PARAMETER; > + } > + > + Status =3D SmiInputValueDuplicateCheck > (DispatchContext->SwSmiInputValue); > + if (EFI_ERROR (Status)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Create database record and add to database > + // > + Status =3D gSmst->SmmAllocatePool ( > + EfiRuntimeServicesData, > + sizeof (SW_SMI_RECORD), > + (VOID **) &SwSmiRecord > + ); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "Failed to allocate memory for SwSmiRecord! > \n")); > + return EFI_OUT_OF_RESOURCES; > + } > + // > + // Gather information about the registration request > + // > + SwSmiRecord->Signature =3D SW_SMI_RECORD_SIGNATURE; > + SwSmiRecord->Context.SwSmiInputValue =3D > DispatchContext->SwSmiInputValue; > + SwSmiRecord->Callback =3D DispatchFunction; > + // > + // Publish the S/W SMI numbers in Serial logs used for Debug build. > + // > + DEBUG ((DEBUG_INFO, "SW SMI NUM %x Sw Record at Address 0x%X\n", > SwSmiRecord->Context.SwSmiInputValue, SwSmiRecord)); > + > + InsertTailList (&mSwSmiCallbackDataBase, &SwSmiRecord->Link); > + > + // > + // Child's handle will be the address linked list link in the record > + // > + *DispatchHandle =3D (EFI_HANDLE) (&SwSmiRecord->Link); > + > + return EFI_SUCCESS; > +} > + > +/** > + Unregister a child SMI source dispatch function for the specified soft= ware > SMI. > + > + This service removes the handler associated with DispatchHandle so tha= t it > will no longer be > + called in response to a software SMI. > + > + @param[in] This Pointer to the > EFI_SMM_SW_DISPATCH2_PROTOCOL instance. > + @param[in] DispatchHandle Handle of dispatch function to deregist= er. > + > + @retval EFI_SUCCESS The dispatch function has been successf= ully > unregistered. > + @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid. > +**/ > +EFI_STATUS > +EFIAPI > +PchSwSmiUnRegister ( > + IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This, > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + EFI_STATUS Status; > + SW_SMI_RECORD *RecordToDelete; > + > + if (DispatchHandle =3D=3D 0) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Return access denied if the SmmReadyToLock event has been triggered > + // > + if (mReadyToLock =3D=3D TRUE) { > + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the > SmmReadyToLock event has been triggered! \n")); > + return EFI_ACCESS_DENIED; > + } > + > + RecordToDelete =3D SW_SMI_RECORD_FROM_LINK (DispatchHandle); > + // > + // Take the entry out of the linked list > + // > + if (RecordToDelete->Signature !=3D SW_SMI_RECORD_SIGNATURE) { > + return EFI_INVALID_PARAMETER; > + } > + > + RemoveEntryList (&RecordToDelete->Link); > + ZeroMem (RecordToDelete, sizeof (SW_SMI_RECORD)); > + Status =3D gSmst->SmmFreePool (RecordToDelete); > + ASSERT_EFI_ERROR (Status); > + > + return EFI_SUCCESS; > +} > + > +/** > + Main entry point for an SMM handler dispatch or communicate-based > callback. > + > + @param[in] DispatchHandle The unique handle assigned to this > handler by SmiHandlerRegister(). > + @param[in] Context Points to an optional handler context w= hich > was specified when the > + handler was registered. > + @param[in,out] CommBuffer A pointer to a collection of data in > memory that will > + be conveyed from a non-SMM environment = into an > SMM environment. > + @param[in,out] CommBufferSize The size of the CommBuffer. > + > + @retval EFI_SUCCESS The interrupt was handled = and > quiesced. No other handlers > + should still be called. > + @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has > been quiesced but other handlers should > + still be called. > + @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still > pending and other handlers should still > + be called. > + @retval EFI_INTERRUPT_PENDING The interrupt could not be > quiesced. > +**/ > +EFI_STATUS > +EFIAPI > +PchSwSmiDispatcher ( > + IN EFI_HANDLE DispatchHandle, > + IN CONST VOID *Context, > + IN OUT VOID *CommBuffer, > + IN OUT UINTN *CommBufferSize > + ) > +{ > + EFI_STATUS Status; > + EFI_SMM_SAVE_STATE_IO_INFO SmiIoInfo; > + UINTN CpuIndex; > + SW_SMI_RECORD *SwSmiRecord; > + LIST_ENTRY *LinkInDb; > + EFI_SMM_SW_CONTEXT SwSmiCommBuffer; > + UINTN SwSmiCommBufferSize; > + > + SwSmiCommBufferSize =3D sizeof (EFI_SMM_SW_CONTEXT); > + // > + // The value in DataPort might not be accurate in multiple thread > environment. > + // There might be racing condition for R_PCH_IO_APM_STS port. > + // Therefor, this is just for reference. > + // > + SwSmiCommBuffer.DataPort =3D IoRead8 (R_PCH_IO_APM_STS); > + > + for (CpuIndex =3D 0; CpuIndex < gSmst->NumberOfCpus; CpuIndex++) { > + Status =3D mSmmCpuProtocol->ReadSaveState ( > + mSmmCpuProtocol, > + sizeof (EFI_SMM_SAVE_STATE_IO_INFO), > + EFI_SMM_SAVE_STATE_REGISTER_IO, > + CpuIndex, > + &SmiIoInfo > + ); > + // > + // If this is not the SMI source, skip it. > + // > + if (EFI_ERROR (Status)) { > + continue; > + } > + // > + // If the IO address is not "BYTE" "WRITE" to "R_PCH_IO_APM_CNT (0xB= 2)", > skip it. > + // > + if ((SmiIoInfo.IoPort !=3D R_PCH_IO_APM_CNT) || > + (SmiIoInfo.IoType !=3D EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT) || > + (SmiIoInfo.IoWidth !=3D EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8)) > + { > + continue; > + } > + // > + // If the IO data is used for SmmControl protocol, skip it. > + // > + if (SmiIoInfo.IoData =3D=3D 0xFF) { > + continue; > + } > + > + SwSmiCommBuffer.SwSmiCpuIndex =3D CpuIndex; > + SwSmiCommBuffer.CommandPort =3D (UINT8) SmiIoInfo.IoData; > + > + LinkInDb =3D GetFirstNode (&mSwSmiCallbackDataBase); > + while (!IsNull (&mSwSmiCallbackDataBase, LinkInDb)) { > + SwSmiRecord =3D SW_SMI_RECORD_FROM_LINK (LinkInDb); > + if (SwSmiRecord->Context.SwSmiInputValue =3D=3D SmiIoInfo.IoData) = { > + SwSmiRecord->Callback ((EFI_HANDLE) &SwSmiRecord->Link, > &SwSmiRecord->Context, &SwSmiCommBuffer, &SwSmiCommBufferSize); > + } > + LinkInDb =3D GetNextNode (&mSwSmiCallbackDataBase, > &SwSmiRecord->Link); > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Init required protocol for Pch Sw Dispatch protocol. > +**/ > +VOID > +PchSwDispatchInit ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + EFI_HANDLE DispatchHandle; > + DATABASE_RECORD Record; > + > + // > + // Locate PI SMM CPU protocol > + // > + Status =3D gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, > (VOID **)&mSmmCpuProtocol); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Initialize SW SMI Callback DataBase > + // > + InitializeListHead (&mSwSmiCallbackDataBase); > + > + // > + // Insert SwSmi handler to PchSmmCore database > + // There will always be one SwType record in PchSmmCore database > + // > + ZeroMem (&Record, sizeof (DATABASE_RECORD)); > + Record.Signature =3D DATABASE_RECORD_SIGNATURE; > + Record.Callback =3D PchSwSmiDispatcher; > + Record.ProtocolType =3D SwType; > + > + CopyMem (&Record.SrcDesc, &mSwSourceDesc, sizeof > (PCH_SMM_SOURCE_DESC)); > + > + DispatchHandle =3D NULL; > + Status =3D SmmCoreInsertRecord ( > + &Record, > + &DispatchHandle > + ); > + ASSERT_EFI_ERROR (Status); > +} > diff --git > a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx. > c > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx. > c > new file mode 100644 > index 0000000000..52bb906315 > --- /dev/null > +++ > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx. > c > @@ -0,0 +1,229 @@ > +/** @file > + File to contain all the hardware specific stuff for the Smm Sx dispatc= h > protocol. > + > + Copyright (c) 2019 Intel Corporation. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#include "PchSmmHelpers.h" > +#include > +#include > + > +#define PROGRESS_CODE_S3_SUSPEND_END PcdGet32 > (PcdProgressCodeS3SuspendEnd) > + > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSxSourceDesc =3D { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_EN} > + }, > + S_ACPI_IO_SMI_EN, > + N_ACPI_IO_SMI_EN_ON_SLP_EN > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_ON_SLP_EN > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_ON_SLP_EN > + } > +}; > + > +/** > + Get the Sleep type > + > + @param[in] Record No use > + @param[out] Context The context that includes SLP_TYP bits= to be > filled > + > +**/ > +VOID > +EFIAPI > +SxGetContext ( > + IN DATABASE_RECORD *Record, > + OUT PCH_SMM_CONTEXT *Context > + ) > +{ > + UINT32 Pm1Cnt; > + > + Pm1Cnt =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT)); > + > + /// > + /// By design, the context phase will always be ENTRY > + /// > + Context->Sx.Phase =3D SxEntry; > + > + /// > + /// Map the PM1_CNT register's SLP_TYP bits to the context type > + /// > + switch (Pm1Cnt & B_ACPI_IO_PM1_CNT_SLP_TYP) { > + case V_ACPI_IO_PM1_CNT_S0: > + Context->Sx.Type =3D SxS0; > + break; > + > + case V_ACPI_IO_PM1_CNT_S1: > + Context->Sx.Type =3D SxS1; > + break; > + > + case V_ACPI_IO_PM1_CNT_S3: > + Context->Sx.Type =3D SxS3; > + break; > + > + case V_ACPI_IO_PM1_CNT_S4: > + Context->Sx.Type =3D SxS4; > + break; > + > + case V_ACPI_IO_PM1_CNT_S5: > + Context->Sx.Type =3D SxS5; > + break; > + > + default: > + ASSERT (FALSE); > + break; > + } > +} > + > +/** > + Check whether sleep type of two contexts match > + > + @param[in] Context1 Context 1 that includes sleep type 1 > + @param[in] Context2 Context 2 that includes sleep type 2 > + > + @retval FALSE Sleep types match > + @retval TRUE Sleep types don't match > +**/ > +BOOLEAN > +EFIAPI > +SxCmpContext ( > + IN PCH_SMM_CONTEXT *Context1, > + IN PCH_SMM_CONTEXT *Context2 > + ) > +{ > + return (BOOLEAN) (Context1->Sx.Type =3D=3D Context2->Sx.Type); > +} > + > +/** > + For each PCIE RP clear PME SCI status and disable SCI, then > PCIEXP_WAKE_STS from PMC. > + This prevents platform from waking more than one time due to a single = PCIE > wake event. > + Normally it's up to OS to clear SCI statuses. But in a scenario where = platform > wakes > + and goes to S5 instead of booting to OS, the SCI status would remain s= et and > would trigger another wake. > +**/ > +VOID > +ClearPcieSci ( > + VOID > + ) > +{ > + UINT32 MaxPorts; > + UINT32 RpIndex; > + UINT64 RpBase; > + > + MaxPorts =3D GetPchMaxPciePortNum (); > + for (RpIndex =3D 0; RpIndex < MaxPorts; RpIndex++) { > + RpBase =3D PchPcieBase (RpIndex); > + if (PciSegmentRead16 (RpBase + PCI_VENDOR_ID_OFFSET) !=3D 0xFFFF) { > + PciSegmentAnd8 ((RpBase + R_PCH_PCIE_CFG_MPC + 3), > (UINT8)~((UINT8)(B_PCH_PCIE_CFG_MPC_PMCE >> 24))); > + PciSegmentWrite32 (RpBase + R_PCH_PCIE_CFG_SMSCS, > B_PCH_PCIE_CFG_SMSCS_PMCS); > + } > + } > + IoWrite16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS, > B_ACPI_IO_PM1_STS_PCIEXP_WAKE_STS); > +} > + > + > +/** > + When we get an SMI that indicates that we are transitioning to a sleep= state, > + we need to actually transition to that state. We do this by disabling= the > + "SMI on sleep enable" feature, which generates an SMI when the operati= ng > system > + tries to put the system to sleep, and then physically putting the syst= em to > sleep. > + > + > +**/ > +VOID > +PchSmmSxGoToSleep ( > + VOID > + ) > +{ > + UINT32 Pm1Cnt; > + > + ClearPcieSci (); > + > + /// > + /// Flush cache into memory before we go to sleep. It is necessary for= S3 > sleep > + /// because we may update memory in SMM Sx sleep handlers -- the > updates are in cache now > + /// > + AsmWbinvd (); > + > + /// > + /// Disable SMIs > + /// > + PchSmmClearSource (&mSxSourceDesc); > + PchSmmDisableSource (&mSxSourceDesc); > + > + /// > + /// Get Power Management 1 Control Register Value > + /// > + Pm1Cnt =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT)); > + > + /// > + /// Record S3 suspend performance data > + /// > + if ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SLP_TYP) =3D=3D V_ACPI_IO_PM1_CNT_S3) > { > + /// > + /// Report status code before goto S3 sleep > + /// > + REPORT_STATUS_CODE (EFI_PROGRESS_CODE, > PROGRESS_CODE_S3_SUSPEND_END); > + > + /// > + /// Flush cache into memory before we go to sleep. > + /// > + AsmWbinvd (); > + } > + > + /// > + /// Now that SMIs are disabled, write to the SLP_EN bit again to trigg= er the > sleep > + /// > + Pm1Cnt |=3D B_ACPI_IO_PM1_CNT_SLP_EN; > + > + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT), Pm1Cnt); > + > + /// > + /// Should only proceed if wake event is generated. > + /// > + if ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SLP_TYP) =3D=3D V_ACPI_IO_PM1_CNT_S1) > { > + while (((IoRead16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_STS))) & > B_ACPI_IO_PM1_STS_WAK) =3D=3D 0x0); > + } else { > + CpuDeadLoop (); > + } > + /// > + /// The system just went to sleep. If the sleep state was S1, then cod= e > execution will resume > + /// here when the system wakes up. > + /// > + Pm1Cnt =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT)); > + > + if ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) =3D=3D 0) { > + /// > + /// An ACPI OS isn't present, clear the sleep information > + /// > + Pm1Cnt &=3D ~B_ACPI_IO_PM1_CNT_SLP_TYP; > + Pm1Cnt |=3D V_ACPI_IO_PM1_CNT_S0; > + > + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT), Pm1Cnt); > + } > + > + PchSmmClearSource (&mSxSourceDesc); > + PchSmmEnableSource (&mSxSourceDesc); > +} > diff --git > a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUs > b.c > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUs > b.c > new file mode 100644 > index 0000000000..061dbe4300 > --- /dev/null > +++ > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUs > b.c > @@ -0,0 +1,231 @@ > +/** @file > + File to contain all the hardware specific stuff for the Smm USB dispat= ch > protocol. > + > + Copyright (c) 2019 Intel Corporation. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#include "PchSmmHelpers.h" > +#include > +#include > +#include > + > + > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mUsb1Legacy =3D { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_EN} > + }, > + S_ACPI_IO_SMI_EN, > + N_ACPI_IO_SMI_EN_LEGACY_USB > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_LEGACY_USB > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_LEGACY_USB > + } > +}; > + > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mUsb3Legacy =3D { > + PCH_SMM_NO_FLAGS, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_EN} > + }, > + S_ACPI_IO_SMI_EN, > + N_ACPI_IO_SMI_EN_LEGACY_USB3 > + }, > + NULL_BIT_DESC_INITIALIZER > + }, > + { > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_LEGACY_USB3 > + } > + }, > + { > + { > + ACPI_ADDR_TYPE, > + {R_ACPI_IO_SMI_STS} > + }, > + S_ACPI_IO_SMI_STS, > + N_ACPI_IO_SMI_STS_LEGACY_USB3 > + } > +}; > + > +typedef enum { > + PchUsbControllerLpc0 =3D 0, > + PchUsbControllerXhci, > + PchUsbControllerTypeMax > +} PCH_USB_CONTROLLER_TYPE; > + > +typedef struct { > + UINT8 Function; > + UINT8 Device; > + PCH_USB_CONTROLLER_TYPE UsbConType; > +} USB_CONTROLLER; > + > +GLOBAL_REMOVE_IF_UNREFERENCED USB_CONTROLLER > mUsbControllersMap[] =3D { > + { > + PCI_FUNCTION_NUMBER_PCH_LPC, > + PCI_DEVICE_NUMBER_PCH_LPC, > + PchUsbControllerLpc0 > + }, > + { > + PCI_FUNCTION_NUMBER_PCH_XHCI, > + PCI_DEVICE_NUMBER_PCH_XHCI, > + PchUsbControllerXhci > + } > +}; > + > +/** > + Find the handle that best matches the input Device Path and return the= USB > controller type > + > + @param[in] DevicePath Pointer to the device Path table > + @param[out] Controller Returned with the USB controller type = of > the input device path > + > + @retval EFI_SUCCESS Find the handle that best matches the = input > Device Path > + @exception EFI_UNSUPPORTED Invalid device Path table or can't fin= d > any match USB device path > + PCH_USB_CONTROLLER_TYPE The USB contro= ller > type of the input > + device path > +**/ > +EFI_STATUS > +DevicePathToSupportedController ( > + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, > + OUT PCH_USB_CONTROLLER_TYPE *Controller > + ) > +{ > + EFI_STATUS Status; > + EFI_HANDLE DeviceHandle; > + ACPI_HID_DEVICE_PATH *AcpiNode; > + PCI_DEVICE_PATH *PciNode; > + EFI_DEVICE_PATH_PROTOCOL *RemaingDevicePath; > + UINT8 UsbIndex; > + /// > + /// Find the handle that best matches the Device Path. If it is only a > + /// partial match the remaining part of the device path is returned in > + /// RemainingDevicePath. > + /// > + RemaingDevicePath =3D DevicePath; > + Status =3D gBS->LocateDevicePath ( > + &gEfiPciRootBridgeIoProtocolGuid, > + &DevicePath, > + &DeviceHandle > + ); > + if (EFI_ERROR (Status)) { > + return EFI_UNSUPPORTED; > + } > + > + DevicePath =3D RemaingDevicePath; > + > + /// > + /// Get first node: Acpi Node > + /// > + AcpiNode =3D (ACPI_HID_DEVICE_PATH *) RemaingDevicePath; > + > + if (AcpiNode->Header.Type !=3D ACPI_DEVICE_PATH || > + AcpiNode->Header.SubType !=3D ACPI_DP || > + DevicePathNodeLength (&AcpiNode->Header) !=3D sizeof > (ACPI_HID_DEVICE_PATH) || > + AcpiNode->HID !=3D EISA_PNP_ID (0x0A03) || > + AcpiNode->UID !=3D 0 > + ) { > + return EFI_UNSUPPORTED; > + } else { > + /// > + /// Get the next node: Pci Node > + /// > + RemaingDevicePath =3D NextDevicePathNode (RemaingDevicePath); > + PciNode =3D (PCI_DEVICE_PATH *) RemaingDevicePath; > + if (PciNode->Header.Type !=3D HARDWARE_DEVICE_PATH || > + PciNode->Header.SubType !=3D HW_PCI_DP || > + DevicePathNodeLength (&PciNode->Header) !=3D sizeof > (PCI_DEVICE_PATH) > + ) { > + return EFI_UNSUPPORTED; > + } > + > + for (UsbIndex =3D 0; UsbIndex < sizeof (mUsbControllersMap) / sizeof > (USB_CONTROLLER); UsbIndex++) { > + if ((PciNode->Device =3D=3D mUsbControllersMap[UsbIndex].Device) &= & > + (PciNode->Function =3D=3D mUsbControllersMap[UsbIndex].Functio= n)) { > + *Controller =3D mUsbControllersMap[UsbIndex].UsbConType; > + return EFI_SUCCESS; > + } > + } > + > + return EFI_UNSUPPORTED; > + } > +} > + > +/** > + Maps a USB context to a source description. > + > + @param[in] Context The context we need to map. Type must= be > USB. > + @param[in] SrcDesc The source description that correspond= s to > the given context. > + > +**/ > +VOID > +MapUsbToSrcDesc ( > + IN PCH_SMM_CONTEXT *Context, > + OUT PCH_SMM_SOURCE_DESC *SrcDesc > + ) > +{ > + PCH_USB_CONTROLLER_TYPE Controller; > + EFI_STATUS Status; > + > + Status =3D DevicePathToSupportedController (Context->Usb.Device, > &Controller); > + /// > + /// Either the device path passed in by the child is incorrect or > + /// the ones stored here internally are incorrect. > + /// > + ASSERT_EFI_ERROR (Status); > + > + switch (Context->Usb.Type) { > + case UsbLegacy: > + switch (Controller) { > + case PchUsbControllerLpc0: > + CopyMem ((VOID *) SrcDesc, (VOID *) (&mUsb1Legacy), sizeof > (PCH_SMM_SOURCE_DESC)); > + break; > + > + case PchUsbControllerXhci: > + CopyMem ((VOID *) SrcDesc, (VOID *) (&mUsb3Legacy), sizeof > (PCH_SMM_SOURCE_DESC)); > + break; > + > + default: > + ASSERT (FALSE); > + break; > + } > + break; > + > + case UsbWake: > + ASSERT (FALSE); > + break; > + > + default: > + ASSERT (FALSE); > + break; > + } > +} > diff --git > a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmH > elpers.c > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmH > elpers.c > new file mode 100644 > index 0000000000..4ac00b831f > --- /dev/null > +++ > b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmH > elpers.c > @@ -0,0 +1,764 @@ > +/** @file > + This driver is responsible for the registration of child drivers > + and the abstraction of the PCH SMI sources. > + > + Copyright (c) 2019 Intel Corporation. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#include "PchSmmHelpers.h" > +#include > +#include > + > +// > +// Help handle porting bit shifts to IA-64. > +// > +#define BIT_ZERO 0x00000001 > + > +/** > + Publish SMI Dispatch protocols. > + > + > +**/ > +VOID > +PchSmmPublishDispatchProtocols ( > + VOID > + ) > +{ > + EFI_STATUS Status =3D EFI_SUCCESS; > + UINTN Index; > + // > + // Install protocol interfaces. > + // > + for (Index =3D 0; Index < PCH_SMM_PROTOCOL_TYPE_MAX; Index++) { > + Status =3D gSmst->SmmInstallProtocolInterface ( > + &mPrivateData.InstallMultProtHandle, > + mPrivateData.Protocols[Index].Guid, > + EFI_NATIVE_INTERFACE, > + &mPrivateData.Protocols[Index].Protocols.Generic > + ); > + } > + ASSERT_EFI_ERROR (Status); > +} > + > +/** > + Initialize bits that aren't necessarily related to an SMI source. > + > + > + @retval EFI_SUCCESS SMI source initialization completed. > + @retval Asserts Global Smi Bit is not enabled successf= ully. > +**/ > +EFI_STATUS > +PchSmmInitHardware ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Clear all SMIs > + // > + PchSmmClearSmi (); > + > + Status =3D PchSmmEnableGlobalSmiBit (); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Be *really* sure to clear all SMIs > + // > + PchSmmClearSmi (); > + > + return EFI_SUCCESS; > +} > + > +/** > + Enables the PCH to generate SMIs. Note that no SMIs will be generated > + if no SMI sources are enabled. Conversely, no enabled SMI source will > + generate SMIs if SMIs are not globally enabled. This is the main > + switchbox for SMI generation. > + > + > + @retval EFI_SUCCESS Enable Global Smi Bit completed > +**/ > +EFI_STATUS > +PchSmmEnableGlobalSmiBit ( > + VOID > + ) > +{ > + UINT32 SmiEn; > + > + SmiEn =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN)); > + > + // > + // Set the "global smi enable" bit > + // > + SmiEn |=3D B_ACPI_IO_SMI_EN_GBL_SMI; > + > + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN), SmiEn); > + > + return EFI_SUCCESS; > +} > + > +/** > + Clears the SMI after all SMI source have been processed. > + Note that this function will not work correctly (as it is > + written) unless all SMI sources have been processed. > + A revision of this function could manually clear all SMI > + status bits to guarantee success. > +**/ > +VOID > +PchSmmClearSmi ( > + VOID > + ) > +{ > + BOOLEAN EosSet; > + BOOLEAN SciEn; > + UINT32 Pm1Cnt; > + UINT16 Pm1Sts; > + UINT32 Gpe0Sts; > + UINT32 SmiSts; > + UINT16 DevActSts; > + UINT16 Tco1Sts; > + > + Gpe0Sts =3D 0; > + // > + // Determine whether an ACPI OS is present (via the SCI_EN bit) > + // > + Pm1Cnt =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT)); > + SciEn =3D (BOOLEAN) ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) =3D=3D > B_ACPI_IO_PM1_CNT_SCI_EN); > + if (!SciEn) { > + // > + // Clear any SMIs that double as SCIs (when SCI_EN=3D=3D0) > + // > + Pm1Sts =3D IoRead16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_STS)); > + Gpe0Sts =3D IoRead32 ((UINTN) (mAcpiBaseAddr + > R_ACPI_IO_GPE0_STS_127_96)); > + > + Pm1Sts |=3D > + ( > + B_ACPI_IO_PM1_STS_WAK | > + B_ACPI_IO_PM1_STS_PRBTNOR | > + B_ACPI_IO_PM1_STS_RTC | > + B_ACPI_IO_PM1_STS_PWRBTN | > + B_ACPI_IO_PM1_STS_GBL | > + B_ACPI_IO_PM1_STS_TMROF > + ); > + > + Gpe0Sts &=3D (UINT32)~(B_ACPI_IO_GPE0_STS_127_96_WADT); > + > + IoWrite16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_STS), (UINT16) > Pm1Sts); > + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96), > (UINT32) Gpe0Sts); > + } > + // > + // Clear all SMIs that are unaffected by SCI_EN > + // > + SmiSts =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_STS= )); > + DevActSts =3D IoRead16 ((UINTN) (mAcpiBaseAddr + > R_ACPI_IO_DEVACT_STS)); > + Tco1Sts =3D IoRead16 ((UINTN) (mTcoBaseAddr + R_TCO_IO_TCO1_STS)= ); > + > + SmiSts |=3D > + ( > + B_ACPI_IO_SMI_STS_SMBUS | > + B_ACPI_IO_SMI_STS_PERIODIC | > + B_ACPI_IO_SMI_STS_TCO | > + B_ACPI_IO_SMI_STS_MCSMI | > + B_ACPI_IO_SMI_STS_SWSMI_TMR | > + B_ACPI_IO_SMI_STS_APM | > + B_ACPI_IO_SMI_STS_ON_SLP_EN | > + B_ACPI_IO_SMI_STS_BIOS > + ); > + DevActSts |=3D > + ( > + B_ACPI_IO_DEVACT_STS_KBC | > + B_ACPI_IO_DEVACT_STS_PIRQDH | > + B_ACPI_IO_DEVACT_STS_PIRQCG | > + B_ACPI_IO_DEVACT_STS_PIRQBF | > + B_ACPI_IO_DEVACT_STS_PIRQAE > + ); > + Tco1Sts |=3D > + ( > + B_TCO_IO_TCO1_STS_DMISERR | > + B_TCO_IO_TCO1_STS_DMISMI | > + B_TCO_IO_TCO1_STS_DMISCI | > + B_TCO_IO_TCO1_STS_BIOSWR | > + B_TCO_IO_TCO1_STS_NEWCENTURY | > + B_TCO_IO_TCO1_STS_TIMEOUT | > + B_TCO_IO_TCO1_STS_TCO_INT | > + B_TCO_IO_TCO1_STS_SW_TCO_SMI > + ); > + > + GpioClearAllGpiSmiSts (); > + > + IoWrite16 ((UINTN) (mTcoBaseAddr + R_TCO_IO_TCO1_STS), Tco1Sts); > + > + // > + // We do not want to write 1 to clear INTRD_DET bit. > + // > + IoWrite16 ((UINTN) (mTcoBaseAddr + R_TCO_IO_TCO2_STS), (UINT16) > ~B_TCO_IO_TCO2_STS_INTRD_DET); > + > + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_STS), SmiSts); > + > + IoWrite16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_DEVACT_STS), > DevActSts); > + > + // > + // Try to clear the EOS bit. ASSERT on an error > + // > + EosSet =3D PchSmmSetAndCheckEos (); > + ASSERT (EosSet); > +} > + > +/** > + Set the SMI EOS bit after all SMI source have been processed. > + > + > + @retval FALSE EOS was not set to a 1; this is an err= or > + @retval TRUE EOS was correctly set to a 1 > +**/ > +BOOLEAN > +PchSmmSetAndCheckEos ( > + VOID > + ) > +{ > + UINT32 SmiEn; > + > + SmiEn =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN)); > + > + // > + // Reset the PCH to generate subsequent SMIs > + // > + SmiEn |=3D B_ACPI_IO_SMI_EN_EOS; > + > + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN), SmiEn); > + > + // > + // Double check that the assert worked > + // > + SmiEn =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN)); > + > + // > + // Return TRUE if EOS is set correctly > + // > + if ((SmiEn & B_ACPI_IO_SMI_EN_EOS) =3D=3D 0) { > + // > + // EOS was not set to a 1; this is an error > + // > + return FALSE; > + } else { > + // > + // EOS was correctly set to a 1 > + // > + return TRUE; > + } > +} > + > +/** > + Determine whether an ACPI OS is present (via the SCI_EN bit) > + > + > + @retval TRUE ACPI OS is present > + @retval FALSE ACPI OS is not present > +**/ > +BOOLEAN > +PchSmmGetSciEn ( > + VOID > + ) > +{ > + BOOLEAN SciEn; > + UINT32 Pm1Cnt; > + > + // > + // Determine whether an ACPI OS is present (via the SCI_EN bit) > + // > + Pm1Cnt =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT)); > + SciEn =3D (BOOLEAN) ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) =3D=3D > B_ACPI_IO_PM1_CNT_SCI_EN); > + > + return SciEn; > +} > + > +/** > + Read a specifying bit with the register > + These may or may not need to change w/ the PCH version; they're highly > IA-32 dependent, though. > + > + @param[in] BitDesc The struct that includes register addr= ess, size > in byte and bit number > + > + @retval TRUE The bit is enabled > + @retval FALSE The bit is disabled > +**/ > +BOOLEAN > +ReadBitDesc ( > + CONST PCH_SMM_BIT_DESC *BitDesc > + ) > +{ > + EFI_STATUS Status; > + UINT64 Register; > + UINT32 PciBus; > + UINT32 PciDev; > + UINT32 PciFun; > + UINT32 PciReg; > + UINTN RegSize; > + BOOLEAN BitWasOne; > + UINTN ShiftCount; > + UINTN RegisterOffset; > + UINT32 BaseAddr; > + UINT64 PciBaseAddress; > + > + ASSERT (BitDesc !=3D NULL); > + ASSERT (!IS_BIT_DESC_NULL (*BitDesc)); > + > + RegSize =3D 0; > + Register =3D 0; > + ShiftCount =3D 0; > + BitWasOne =3D FALSE; > + > + switch (BitDesc->Reg.Type) { > + > + case ACPI_ADDR_TYPE: > + case TCO_ADDR_TYPE: > + if (BitDesc->Reg.Type =3D=3D ACPI_ADDR_TYPE) { > + RegisterOffset =3D BitDesc->Reg.Data.acpi; > + BaseAddr =3D mAcpiBaseAddr; > + } else { > + RegisterOffset =3D BitDesc->Reg.Data.tco; > + BaseAddr =3D mTcoBaseAddr; > + } > + switch (BitDesc->SizeInBytes) { > + > + case 0: > + // > + // Chances are that this field didn't get initialized. > + // Check your assignments to bit descriptions. > + // > + ASSERT (FALSE); > + break; > + > + case 1: > + RegSize =3D SMM_IO_UINT8; > + break; > + > + case 2: > + RegSize =3D SMM_IO_UINT16; > + break; > + > + case 4: > + RegSize =3D SMM_IO_UINT32; > + break; > + > + case 8: > + RegSize =3D SMM_IO_UINT64; > + break; > + > + default: > + // > + // Unsupported or invalid register size > + // > + ASSERT (FALSE); > + break; > + } > + // > + // Double check that we correctly read in the acpi base address > + // > + ASSERT ((BaseAddr !=3D 0x0) && ((BaseAddr & 0x1) !=3D 0x1)); > + > + ShiftCount =3D BitDesc->Bit; > + // > + // As current CPU Smm Io can only support at most > + // 32-bit read/write,if Operation is 64 bit, > + // we do a 32 bit operation according to BitDesc->Bit > + // > + if (RegSize =3D=3D SMM_IO_UINT64) { > + RegSize =3D SMM_IO_UINT32; > + // > + // If the operation is for high 32 bits > + // > + if (BitDesc->Bit >=3D 32) { > + RegisterOffset +=3D 4; > + ShiftCount -=3D 32; > + } > + } > + > + Status =3D gSmst->SmmIo.Io.Read ( > + &gSmst->SmmIo, > + RegSize, > + BaseAddr + RegisterOffset, > + 1, > + &Register > + ); > + ASSERT_EFI_ERROR (Status); > + > + if ((Register & (LShiftU64 (BIT_ZERO, ShiftCount))) !=3D 0) { > + BitWasOne =3D TRUE; > + } else { > + BitWasOne =3D FALSE; > + } > + break; > + > + case GPIO_ADDR_TYPE: > + case MEMORY_MAPPED_IO_ADDRESS_TYPE: > + // > + // Read the register, and it with the bit to read > + // > + switch (BitDesc->SizeInBytes) { > + case 1: > + Register =3D (UINT64) MmioRead8 ((UINTN) BitDesc->Reg.Data.Mmi= o); > + break; > + > + case 2: > + Register =3D (UINT64) MmioRead16 ((UINTN) BitDesc->Reg.Data.Mm= io); > + break; > + > + case 4: > + Register =3D (UINT64) MmioRead32 ((UINTN) BitDesc->Reg.Data.Mm= io); > + break; > + > + case 8: > + Register =3D (UINT64) MmioRead32 ((UINTN) > BitDesc->Reg.Data.Mmio); > + *((UINT32 *) (&Register) + 1) =3D MmioRead32 ((UINTN) > BitDesc->Reg.Data.Mmio + 4); > + break; > + > + default: > + // > + // Unsupported or invalid register size > + // > + ASSERT (FALSE); > + break; > + } > + > + Register =3D Register & (LShiftU64 (BIT0, BitDesc->Bit)); > + if (Register) { > + BitWasOne =3D TRUE; > + } else { > + BitWasOne =3D FALSE; > + } > + break; > + > + case PCIE_ADDR_TYPE: > + PciBus =3D BitDesc->Reg.Data.pcie.Fields.Bus; > + PciDev =3D BitDesc->Reg.Data.pcie.Fields.Dev; > + PciFun =3D BitDesc->Reg.Data.pcie.Fields.Fnc; > + PciReg =3D BitDesc->Reg.Data.pcie.Fields.Reg; > + PciBaseAddress =3D PCI_SEGMENT_LIB_ADDRESS > (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0); > + switch (BitDesc->SizeInBytes) { > + > + case 0: > + // > + // Chances are that this field didn't get initialized. > + // Check your assignments to bit descriptions. > + // > + ASSERT (FALSE); > + break; > + > + case 1: > + Register =3D (UINT64) PciSegmentRead8 (PciBaseAddress + PciReg= ); > + break; > + > + case 2: > + Register =3D (UINT64) PciSegmentRead16 (PciBaseAddress + PciRe= g); > + break; > + > + case 4: > + Register =3D (UINT64) PciSegmentRead32 (PciBaseAddress + PciRe= g); > + break; > + > + default: > + // > + // Unsupported or invalid register size > + // > + ASSERT (FALSE); > + break; > + } > + > + if ((Register & (LShiftU64 (BIT_ZERO, BitDesc->Bit))) !=3D 0) { > + BitWasOne =3D TRUE; > + } else { > + BitWasOne =3D FALSE; > + } > + break; > + > + case PCR_ADDR_TYPE: > + // > + // Read the register, and it with the bit to read > + // > + switch (BitDesc->SizeInBytes) { > + case 1: > + Register =3D PchPcrRead8 (BitDesc->Reg.Data.Pcr.Fields.Pid, > BitDesc->Reg.Data.Pcr.Fields.Offset); > + break; > + > + case 2: > + Register =3D PchPcrRead16 (BitDesc->Reg.Data.Pcr.Fields.Pid, > BitDesc->Reg.Data.Pcr.Fields.Offset); > + break; > + > + case 4: > + Register =3D PchPcrRead32 (BitDesc->Reg.Data.Pcr.Fields.Pid, > BitDesc->Reg.Data.Pcr.Fields.Offset); > + break; > + > + default: > + // > + // Unsupported or invalid register size > + // > + ASSERT (FALSE); > + break; > + } > + > + Register =3D Register & (LShiftU64 (BIT0, BitDesc->Bit)); > + if (Register) { > + BitWasOne =3D TRUE; > + } else { > + BitWasOne =3D FALSE; > + } > + break; > + > + default: > + // > + // This address type is not yet implemented > + // > + ASSERT (FALSE); > + break; > + } > + > + return BitWasOne; > +} > + > +/** > + Write a specifying bit with the register > + > + @param[in] BitDesc The struct that includes register addr= ess, size > in byte and bit number > + @param[in] ValueToWrite The value to be wrote > + @param[in] WriteClear If the rest bits of the register is wr= ite clear > + > +**/ > +VOID > +WriteBitDesc ( > + CONST PCH_SMM_BIT_DESC *BitDesc, > + CONST BOOLEAN ValueToWrite, > + CONST BOOLEAN WriteClear > + ) > +{ > + EFI_STATUS Status; > + UINT64 Register; > + UINT64 AndVal; > + UINT64 OrVal; > + UINT32 RegSize; > + UINT32 PciBus; > + UINT32 PciDev; > + UINT32 PciFun; > + UINT32 PciReg; > + UINTN RegisterOffset; > + UINT32 BaseAddr; > + UINT64 PciBaseAddress; > + > + ASSERT (BitDesc !=3D NULL); > + ASSERT (!IS_BIT_DESC_NULL (*BitDesc)); > + > + RegSize =3D 0; > + Register =3D 0; > + > + if (WriteClear) { > + AndVal =3D LShiftU64 (BIT_ZERO, BitDesc->Bit); > + } else { > + AndVal =3D ~(LShiftU64 (BIT_ZERO, BitDesc->Bit)); > + } > + > + OrVal =3D (LShiftU64 ((UINT32) ValueToWrite, BitDesc->Bit)); > + > + switch (BitDesc->Reg.Type) { > + > + case ACPI_ADDR_TYPE: > + case TCO_ADDR_TYPE: > + if (BitDesc->Reg.Type =3D=3D ACPI_ADDR_TYPE) { > + RegisterOffset =3D BitDesc->Reg.Data.acpi; > + BaseAddr =3D mAcpiBaseAddr; > + } else { > + RegisterOffset =3D BitDesc->Reg.Data.tco; > + BaseAddr =3D mTcoBaseAddr; > + } > + > + switch (BitDesc->SizeInBytes) { > + > + case 0: > + // > + // Chances are that this field didn't get initialized. > + // Check your assignments to bit descriptions. > + // > + ASSERT (FALSE); > + break; > + > + case 1: > + RegSize =3D SMM_IO_UINT8; > + break; > + > + case 2: > + RegSize =3D SMM_IO_UINT16; > + break; > + > + case 4: > + RegSize =3D SMM_IO_UINT32; > + break; > + > + case 8: > + RegSize =3D SMM_IO_UINT64; > + break; > + > + default: > + // > + // Unsupported or invalid register size > + // > + ASSERT (FALSE); > + break; > + } > + // > + // Double check that we correctly read in the acpi base address > + // > + ASSERT ((BaseAddr !=3D 0x0) && ((BaseAddr & 0x1) !=3D 0x1)); > + > + // > + // As current CPU Smm Io can only support at most > + // 32-bit read/write,if Operation is 64 bit, > + // we do a 32 bit operation according to BitDesc->Bit > + // > + if (RegSize =3D=3D SMM_IO_UINT64) { > + RegSize =3D SMM_IO_UINT32; > + // > + // If the operation is for high 32 bits > + // > + if (BitDesc->Bit >=3D 32) { > + RegisterOffset +=3D 4; > + > + if (WriteClear) { > + AndVal =3D LShiftU64 (BIT_ZERO, BitDesc->Bit - 32); > + } else { > + AndVal =3D ~(LShiftU64 (BIT_ZERO, BitDesc->Bit - 32)); > + } > + > + OrVal =3D LShiftU64 ((UINT32) ValueToWrite, BitDesc->Bit - 32)= ; > + } > + } > + > + Status =3D gSmst->SmmIo.Io.Read ( > + &gSmst->SmmIo, > + RegSize, > + BaseAddr + RegisterOffset, > + 1, > + &Register > + ); > + ASSERT_EFI_ERROR (Status); > + > + Register &=3D AndVal; > + Register |=3D OrVal; > + > + Status =3D gSmst->SmmIo.Io.Write ( > + &gSmst->SmmIo, > + RegSize, > + BaseAddr + RegisterOffset, > + 1, > + &Register > + ); > + ASSERT_EFI_ERROR (Status); > + break; > + > + case GPIO_ADDR_TYPE: > + case MEMORY_MAPPED_IO_ADDRESS_TYPE: > + // > + // Read the register, or it with the bit to set, then write it bac= k. > + // > + switch (BitDesc->SizeInBytes) { > + case 1: > + MmioAndThenOr8 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT8) > AndVal, (UINT8) OrVal); > + break; > + > + case 2: > + MmioAndThenOr16 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT16) > AndVal, (UINT16) OrVal); > + break; > + > + case 4: > + MmioAndThenOr32 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT32) > AndVal, (UINT32) OrVal); > + break; > + > + case 8: > + Register =3D (UINT64) MmioRead32 ((UINTN) > BitDesc->Reg.Data.Mmio); > + *((UINT32 *) (&Register) + 1) =3D MmioRead32 ((UINTN) > BitDesc->Reg.Data.Mmio + 4); > + Register &=3D AndVal; > + Register |=3D OrVal; > + MmioWrite32 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT32) Register= ); > + MmioWrite32 ((UINTN) BitDesc->Reg.Data.Mmio + 4, *((UINT32 *) > (&Register) + 1)); > + break; > + > + default: > + // > + // Unsupported or invalid register size > + // > + ASSERT (FALSE); > + break; > + } > + break; > + > + case PCIE_ADDR_TYPE: > + PciBus =3D BitDesc->Reg.Data.pcie.Fields.Bus; > + PciDev =3D BitDesc->Reg.Data.pcie.Fields.Dev; > + PciFun =3D BitDesc->Reg.Data.pcie.Fields.Fnc; > + PciReg =3D BitDesc->Reg.Data.pcie.Fields.Reg; > + PciBaseAddress =3D PCI_SEGMENT_LIB_ADDRESS > (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0); > + switch (BitDesc->SizeInBytes) { > + > + case 0: > + // > + // Chances are that this field didn't get initialized -- check= your > assignments > + // to bit descriptions. > + // > + ASSERT (FALSE); > + break; > + > + case 1: > + PciSegmentAndThenOr8 (PciBaseAddress + PciReg, (UINT8) AndVal, > (UINT8) OrVal); > + break; > + > + case 2: > + PciSegmentAndThenOr16 (PciBaseAddress + PciReg, (UINT16) AndVa= l, > (UINT16) OrVal); > + break; > + > + case 4: > + PciSegmentAndThenOr32 (PciBaseAddress + PciReg, (UINT32) AndVa= l, > (UINT32) OrVal); > + break; > + > + default: > + // > + // Unsupported or invalid register size > + // > + ASSERT (FALSE); > + break; > + } > + break; > + > + case PCR_ADDR_TYPE: > + // > + // Read the register, or it with the bit to set, then write it bac= k. > + // > + switch (BitDesc->SizeInBytes) { > + case 1: > + PchPcrAndThenOr8 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.= Pid, > (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT8) AndVal, (UINT8) > OrVal); > + break; > + > + case 2: > + PchPcrAndThenOr16 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.= Pid, > (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT16) AndVal, (UINT16) > OrVal); > + break; > + > + case 4: > + PchPcrAndThenOr32 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.= Pid, > (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT32) AndVal, (UINT32) > OrVal); > + break; > + > + default: > + // > + // Unsupported or invalid register size > + // > + ASSERT (FALSE); > + break; > + } > + break; > + > + default: > + // > + // This address type is not yet implemented > + // > + ASSERT (FALSE); > + break; > + } > +} > -- > 2.16.2.windows.1