From: "Chiu, Chasel" <chasel.chiu@intel.com>
To: "Kubacki, Michael A" <michael.a.kubacki@intel.com>,
"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: "Chaganty, Rangasai V" <rangasai.v.chaganty@intel.com>,
"Desimone, Nathaniel L" <nathaniel.l.desimone@intel.com>,
"Gao, Liming" <liming.gao@intel.com>,
"Kinney, Michael D" <michael.d.kinney@intel.com>,
"Sinha, Ankit" <ankit.sinha@intel.com>
Subject: Re: [edk2-platforms][PATCH V1 27/37] CoffeelakeSiliconPkg/Pch: Add PchSmiDispatcher
Date: Sat, 17 Aug 2019 01:15:40 +0000 [thread overview]
Message-ID: <3C3EFB470A303B4AB093197B6777CCEC504623EC@PGSMSX111.gar.corp.intel.com> (raw)
In-Reply-To: <20190817001603.30632-28-michael.a.kubacki@intel.com>
Reviewed-by: Chasel Chiu <chasel.chiu@intel.com>
> -----Original Message-----
> From: Kubacki, Michael A
> Sent: Saturday, August 17, 2019 8:16 AM
> To: devel@edk2.groups.io
> Cc: Chaganty, Rangasai V <rangasai.v.chaganty@intel.com>; Chiu, Chasel
> <chasel.chiu@intel.com>; Desimone, Nathaniel L
> <nathaniel.l.desimone@intel.com>; Gao, Liming <liming.gao@intel.com>;
> Kinney, Michael D <michael.d.kinney@intel.com>; Sinha, Ankit
> <ankit.sinha@intel.com>
> Subject: [edk2-platforms][PATCH V1 27/37] CoffeelakeSiliconPkg/Pch: Add
> PchSmiDispatcher
>
> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=2082
>
> Adds the PchSmiDispatcher module. Dispatches PCH SMIs to appropriate
> SMI handlers registered in various SMM modules.
>
> Cc: Sai Chaganty <rangasai.v.chaganty@intel.com>
> Cc: Chasel Chiu <chasel.chiu@intel.com>
> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
> Cc: Liming Gao <liming.gao@intel.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Ankit Sinha <ankit.sinha@intel.com>
> Signed-off-by: Michael Kubacki <michael.a.kubacki@intel.com>
> ---
>
> 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 ++++++++
>
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi.
> h | 342 +++
>
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelp
> ers.h | 157 ++
>
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHel
> pers.h | 105 +
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.c
> | 1264 ++++++++++
>
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispat
> ch.c | 2452 ++++++++++++++++++++
>
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCore
> .c | 911 ++++++++
>
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi.
> c | 1595 +++++++++++++
>
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi.c
> | 254 ++
>
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelp
> ers.c | 358 +++
>
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPerio
> dicTimer.c | 675 ++++++
>
> 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 ++
>
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb.
> c | 231 ++
>
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHel
> pers.c | 764 ++++++
> 18 files changed, 11173 insertions(+)
>
> 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. <BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +INF_VERSION = 0x00010017
> +BASE_NAME = PchSmiDispatcher
> +FILE_GUID = B0D6ED53-B844-43f5-BD2F-61095264E77E
> +VERSION_STRING = 1.0
> +MODULE_TYPE = DXE_SMM_DRIVER
> +PI_SPECIFICATION_VERSION = 1.10
> +ENTRY_POINT = 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 = (EFI_SOFTWARE_SMM_DRIVER |
> (EFI_OEM_SPECIFIC | 0x00000001)) = 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. <BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef _IO_TRAP_H_
> +#define _IO_TRAP_H_
> +
> +//
> +// Include files
> +//
> +#include <Library/S3BootScriptLib.h>
> +#include <Library/UefiDriverEntryPoint.h>
> +#include <Protocol/SmmIoTrapDispatch2.h>
> +#include <Protocol/PchSmmIoTrapControl.h>
> +#include <Protocol/IoTrapExDispatch.h>
> +
> +#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 register.
> + **/
> + UINT32 TrapUsedLength;
> + /**
> + Determine if IoTrap can be merged with other IoTrap callbacks.
> + If MergeDisable is TRUE, then there is only one callback function for 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 to 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 drivers.
> + This driver manages the limited I/O trap resources.
> +
> + @param[in] ImageHandle Image handle for this driver image
> +
> + @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 allocation 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 to
> 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 context.
> + The caller fills this context in before calling
> + the register function to indicate to the register
> + function the IO trap SMI source for which 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 the address of
> linked
> + list link in the call back record. This may not be
> NULL.
> +
> + @retval EFI_SUCCESS The dispatch function has been successfully
> + registered and the SMI source has been enabled.
> + @retval EFI_DEVICE_ERROR The driver was unable to enable the SMI
> 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 driver.
> +
> + @param[in] This Pointer to the
> EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL instance.
> + @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
> +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 the 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 the
> 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 the
> 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. <BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef _PCH_SMM_H_
> +#define _PCH_SMM_H_
> +
> +#include <Uefi.h>
> +#include <Protocol/PciRootBridgeIo.h>
> +#include <Protocol/LoadedImage.h>
> +#include <Protocol/SmmControl2.h>
> +#include <Protocol/SmmUsbDispatch2.h>
> +#include <Protocol/SmmSxDispatch2.h>
> +#include <Protocol/SmmSwDispatch2.h>
> +#include <Protocol/SmmGpiDispatch2.h>
> +#include <Protocol/SmmPowerButtonDispatch2.h>
> +#include <Protocol/SmmPeriodicTimerDispatch2.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/DxeServicesTableLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/SmmServicesTableLib.h>
> +#include <Library/ReportStatusCodeLib.h>
> +#include <Library/PerformanceLib.h>
> +#include <Protocol/SmmReadyToLock.h>
> +#include <IndustryStandard/Pci30.h>
> +#include <Library/PchCycleDecodingLib.h>
> +#include <Library/PchPcieRpLib.h>
> +#include <Library/PchPcrLib.h>
> +#include <Library/PciSegmentLib.h>
> +#include <Library/GpioLib.h>
> +#include <Library/PchInfoLib.h>
> +#include <Library/PchEspiLib.h>
> +#include <Private/Library/GpioPrivateLib.h>
> +#include <Protocol/PchTcoSmiDispatch.h>
> +#include <Protocol/PchPcieSmiDispatch.h>
> +#include <Protocol/PchAcpiSmiDispatch.h>
> +#include <Protocol/PchSmiDispatch.h>
> +#include <Protocol/PchEspiSmiDispatch.h>
> +#include <Protocol/IoTrapExDispatch.h>
> +#include <Library/PmcLib.h>
> +#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 ACPI
> 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 = -1 ///< sentinel to indicate NULL or 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 doesn'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 great to
> have a
> +// way to easily identify them:
> +//
> +#define IS_BIT_DESC_NULL(BitDesc) ((BitDesc).Reg.Type ==
> PCH_SMM_ADDR_TYPE_NULL) ///< "returns" true when BitDesc is NULL
> +#define NULL_THIS_BIT_DESC(BitDesc) ((BitDesc).Reg.Type =
> 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 level
> 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 context
> +/// 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 compare
> 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 contexts 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 support
> 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 should 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 descriptions.
> +/// 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 change 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 corresponds 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 *DispatchContext,
> + 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 the
> 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 the 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 successfully
> + 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 driver
> +
> + @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 driver.
> +
> + @param[in] This Pointer to the
> PCH_SMM_GENERIC_PROTOCOL instance.
> + @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
> +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 database
> 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 software SMI.
> +
> + This service registers a function (DispatchFunction) which will be called
> 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 before calling
> + the register function to indicate to the register
> + function which Software SMI input value the
> + dispatch function should be invoked for.
> + @param[out] DispatchHandle Handle generated by the dispatcher to
> track the
> + function instance.
> +
> + @retval EFI_SUCCESS The dispatch function has been successfully
> + 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 already 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 software
> SMI.
> +
> + This service removes the handler associated with DispatchHandle so that 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 deregister.
> +
> + @retval EFI_SUCCESS The dispatch function has been successfully
> 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, will 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 status
> 1
> + @param[in] Context2 Context 2 that includes Power Button status
> 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 that 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 the
> 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
> + );
> +
> +/**
> + 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 operating
> system
> + tries to put the system to sleep, and then physically putting the system 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 SMI
> types.
> +
> + @retval the result of protocol installation
> +**/
> +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 database
> 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 driver
> +
> + @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 database
> 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 the
> specified GPI causes an SMI.
> + @param[in] RegisterContext Pointer to the dispatch function's context.
> + The caller fills this context in before calling
> + the register function to indicate to the register
> + function the GPI(s) for which the dispatch 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 successfully
> + 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 input
> 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 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
> +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. <BR>
> +
> + 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 events
> 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 source
> +///
> +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 event
> +
> + @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 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 event
> +
> + @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 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 Non
> Fatal Error event
> +
> + @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 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 Fatal
> Error event
> +
> + @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 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 Fatal Error
> event
> +
> + @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 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 Error
> event
> +
> + @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 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 Fatal
> Error event
> +
> + @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 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 registration
> +
> + @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 registration
> +
> + @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 bit is
> set.
> + This runtine will also lock donw ESPI_SMI_LOCK bit after registration
> and
> + prevent this handler from unregistration.
> + On platform that supports more than 1 device through another chip select
> (SPT-H),
> + the SMI handler itself needs to inspect both the eSPI devices' interrupt
> status registers
> + (implementation specific for each Slave) in order to identify and service the
> cause.
> + After servicing it, it has to clear the Slaves' internal SMI# status registers
> +
> + @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 registration
> +
> + @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 of
> 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 registration
> +**/
> +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. <BR>
> +
> + 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 description
> table 1
> + @param[in] Src2 Pointer to the PCH SMI source description
> table 2
> +
> + @retval TRUE The enable settings of the 2 SMM source
> descriptors are identical.
> + @retval FALSE The enable settings of the 2 SMM source
> 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 description
> table 2
> +
> + @retval TRUE The bit desc is equal to any of the enables in
> source descriptor
> + @retval FALSE The bid desc is not equal to all of the 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 description
> table 1
> + @param[in] Src2 Pointer to the PCH SMI source description
> table 2
> +
> + @retval TRUE The statuses of the 2 SMM source descriptors
> are identical.
> + @retval FALSE The statuses of the 2 SMM source descriptors
> 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 description
> table 1
> + @param[in] Src2 Pointer to the PCH SMI source description
> table 2
> +
> + @retval TRUE The 2 SMM source descriptors are identical.
> + @retval FALSE The 2 SMM source descriptors are not identical.
> +**/
> +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 description
> 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 would
> also clear SMI
> + status bit to make initial state is correct
> +
> + @param[in] SrcDesc Pointer to the PCH SMI source description
> 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 description
> 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 description
> 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 description
> 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. <BR>
> +
> + 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 successfully.
> +**/
> +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 error
> + @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 address, 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 address, 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 write 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. <BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "PchSmmHelpers.h"
> +#include <Private/Protocol/PchNvsArea.h>
> +#include <Library/SmiHandlerProfileLib.h>
> +#include <Register/PchRegsPcr.h>
> +#include <Register/PchRegsPsth.h>
> +#include <Register/PchRegsDmi.h>
> +
> +#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] = { 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 and
> 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 saved 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 flush all
> previous IO cycles.
> + // b. Then only issues a MemWr to PSTH IO Trap Enable == Value
> + // c. Issues another MemRd to PSTH IO Trap Enable bit -> This serves to push
> the MemWr to PSTH and confirmed that IO Trap is in fact enabled
> + //
> + 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 = 0;
> + BitValue = 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 and
> 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 saved 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 after 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 they
> 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 = resource allocated, FALSE = resource freed
> +
> +**/
> +VOID
> +UpdateIoTrapAcpiResources (
> + IN UINT8 TrapHandlerNum,
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
> + IN BOOLEAN Track
> + )
> +{
> +
> + if (Track == TRUE) {
> + mPchNvsArea->IoTrapAddress[TrapHandlerNum] = (UINT16)
> BaseAddress;
> + mPchNvsArea->IoTrapStatus[TrapHandlerNum] = 1;
> + } else {
> + mPchNvsArea->IoTrapStatus[TrapHandlerNum] = 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 == AddressFromLowDword
> (IoTrapRegLowDword)) &&
> + (IoTrapRecord->Context.Length == LengthFromLowDword
> (IoTrapRegLowDword)) &&
> + (IoTrapRecord->Context.ByteEnable == ByteEnableFromHighDword
> (IoTrapRegHighDword)) &&
> + (IoTrapRecord->Context.ByteEnableMask ==
> 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 = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPC);
> + WriteData = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPD);
> +
> + BaseAddress = (UINT16) (Data32 & B_PSTH_PCR_TRPC_IOA);
> + ActiveHighByteEnable = (UINT8)((Data32 & B_PSTH_PCR_TRPC_AHBE) >>
> 16);
> + ReadCycle = (BOOLEAN) ((Data32 & B_PSTH_PCR_TRPC_RW) ==
> B_PSTH_PCR_TRPC_RW);
> + //
> + // StartAddress and EndAddress will be equal if it's byte access
> + //
> + EndAddress = (UINT16) (HighBitSet32 ((UINT32)
> (ActiveHighByteEnable))) + BaseAddress;
> + StartAddress = (UINT16) (LowBitSet32 ((UINT32) (ActiveHighByteEnable)))
> + BaseAddress;
> +
> + CurrentIoTrapRegisterData.Type =
> (EFI_SMM_IO_TRAP_DISPATCH_TYPE)ReadCycle;
> + CurrentIoTrapContextData.WriteData = WriteData;
> +
> + LinkInDb = GetFirstNode
> (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase));
> +
> + while (!IsNull
> (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase), LinkInDb)) {
> + RecordInDb = IO_TRAP_RECORD_FROM_LINK (LinkInDb);
> +
> + //
> + // If MergeDisable is TRUE, no need to check the address range, dispatch
> the callback function directly.
> + //
> + if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable) {
> + if (RecordInDb->IoTrapCallback != NULL) {
> + RecordInDb->IoTrapCallback (&RecordInDb->Link,
> &CurrentIoTrapContextData, NULL, NULL);
> + }
> + if (RecordInDb->IoTrapExCallback != 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 <= StartAddress) &&
> + (RecordInDb->Context.Address + RecordInDb->Context.Length >
> EndAddress)) {
> + if ((RecordInDb->Context.Type == IoTrapExTypeReadWrite) ||
> (RecordInDb->Context.Type == (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 = GetNextNode
> (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase),
> &RecordInDb->Link);
> + if (IsNull (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase),
> LinkInDb)) {
> + //
> + // An IO access was trapped that does not have a handler registered.
> + // 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 from
> IoTrapDispatch2Protocol.
> + @param[in] IoTrapExDispatchFunction Dispatch function of
> IoTrapExDispatchProtocol.
> + This could be NULL if it's not from
> IoTrapExDispatchProtocol.
> + @param[in out] Address The pointer of IO Address.
> + If the input Addres is 0, it will 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 byte 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 resource,
> + 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 >= 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 not be
> more than 4
> + //
> + if (((Length & (Length - 1)) != 0) && (Length != 3)) {
> + DEBUG ((DEBUG_ERROR, "The Dispatch Length is not power of 2 \n"));
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (((Length >= 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 >= 4) && ((*Address & (Length - 1)) != 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + if (*Address) {
> + TempMergeDisable = TRUE;
> + }else {
> + TempMergeDisable = FALSE;
> + }
> + //
> + // Loop through the first IO Trap handler, looking for the suitable handler
> + //
> + for (TrapHandlerNum = 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM;
> TrapHandlerNum++) {
> + //
> + // Get information from Io Trap handler register
> + //
> + IoTrapRegLowDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 +
> TrapHandlerNum * 8);
> +
> + //
> + // Check if the IO Trap handler is not used
> + //
> + if (AddressFromLowDword (IoTrapRegLowDword) == 0) {
> + //
> + // Search available IO address and allocate it if the IO address is 0
> + //
> + BaseAddress = *Address;
> + if (BaseAddress == 0) {
> + //
> + // Allocate 256 byte range from GCD for common pool usage
> + //
> + if ((PcdGet8 (PcdEfiGcdAllocateType) ==
> EfiGcdAllocateMaxAddressSearchBottomUp) || (PcdGet8
> (PcdEfiGcdAllocateType) == EfiGcdAllocateMaxAddressSearchTopDown)) {
> + BaseAddress = 0xFFFF;
> + }
> + Status = 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 = (UINT16) BaseAddress;
> + UsedLength = GENERIC_IOTRAP_SIZE;
> + mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength = Length;
> + mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource =
> TRUE;
> + UpdateIoTrapAcpiResources (TrapHandlerNum, BaseAddress, TRUE);
> + } else {
> + BaseAddress &= B_PSTH_PCR_TRPREG_AD;
> + UsedLength = Length;
> + }
> +
> + Status = PchInternalIoTrapSmiRegister (
> + mIoTrapData.Entry[TrapHandlerNum].CallbackDispatcher,
> + TrapHandlerNum,
> + &mIoTrapHandle
> + );
> +
> + ASSERT_EFI_ERROR (Status);
> + mIoTrapData.Entry[TrapHandlerNum].IoTrapHandle = mIoTrapHandle;
> +
> + //
> + // Fill in the Length, address and Enable the IO Trap SMI
> + //
> + IoTrapRegLowDword = (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 byte that are
> trapped.
> + // The input ByteEnable and ByteEnableMask are ignored in this case.
> + //
> + IoTrapRegHighDword = (((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 register
> + //
> + IoTrapRegHighDword = ((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 =
> TempMergeDisable;
> + } else {
> + //
> + // Check next handler if MergeDisable is TRUE or the registered IoTrap if
> MergeDisable is TRUE
> + // If the Io Trap register is used by IoTrapEx protocol, then the
> MergeDisable will be FALSE.
> + //
> + if ((TempMergeDisable == TRUE) ||
> (mIoTrapData.Entry[TrapHandlerNum].MergeDisable == TRUE)) {
> + continue;
> + }
> + //
> + // The IO Trap handler is used, calculate the Length
> + //
> + UsedLength = LengthFromLowDword (IoTrapRegLowDword);
> + BaseAddress = AddressFromLowDword (IoTrapRegLowDword);
> + //
> + // Assign an addfress from common pool if the caller's address is 0
> + //
> + if (*Address == 0) {
> + //
> + // Check next handler if it's fully used
> + //
> + if (mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength >=
> 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 >= (UINT16) GENERIC_IOTRAP_SIZE -
> mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength) {
> + continue;
> + }
> + //
> + // For common pool, we don't need to change the BaseAddress and
> UsedLength
> + //
> + *Address = (UINT16) (BaseAddress +
> mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength);
> + mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength += Length;
> + }
> + //
> + // Only set RWM bit when we need both read and write cycles.
> + //
> + IoTrapRegHighDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0
> + TrapHandlerNum * 8 + 4);
> + if ((IoTrapRegHighDword & B_PSTH_PCR_TRPREG_RWM) == 0 &&
> + (UINT32) ((IoTrapRegHighDword & B_PSTH_PCR_TRPREG_RWIO) >>
> N_PSTH_PCR_TRPREG_RWIO) !=
> + (UINT32) Type) {
> + IoTrapRegHighDword = ((IoTrapRegHighDword |
> B_PSTH_PCR_TRPREG_RWM) & ~B_PSTH_PCR_TRPREG_RWIO);
> + SetIoTrapHighDword (TrapHandlerNum, IoTrapRegHighDword, TRUE);
> + }
> + }
> + break;
> + }
> +
> + if (TrapHandlerNum >= IO_TRAP_HANDLER_NUM) {
> + DEBUG ((DEBUG_ERROR, "All IO Trap handler is used, no available IO Trap
> handler! \n"));
> + return EFI_OUT_OF_RESOURCES;
> + }
> + //
> + // Create database record and add to database
> + //
> + Status = 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 = IO_TRAP_RECORD_SIGNATURE;
> + mIoTrapRecord->Context.Address = *Address;
> + mIoTrapRecord->Context.Length = Length;
> + mIoTrapRecord->Context.Type = Type;
> + mIoTrapRecord->Context.ByteEnable = ByteEnable;
> + mIoTrapRecord->Context.ByteEnableMask = ByteEnableMask;
> + mIoTrapRecord->IoTrapCallback = IoTrapDispatchFunction;
> + mIoTrapRecord->IoTrapExCallback = IoTrapExDispatchFunction;
> + mIoTrapRecord->IoTrapNumber = TrapHandlerNum;
> +
> + InsertTailList (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase),
> &mIoTrapRecord->Link);
> +
> + //
> + // Child's handle will be the address linked list link in the record
> + //
> + *DispatchHandle = (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 == 0) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + //
> + // Return access denied if the SmmReadyToLock event has been triggered
> + //
> + if (mReadyToLock == TRUE) {
> + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the
> SmmReadyToLock event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + RecordToDelete = IO_TRAP_RECORD_FROM_LINK (DispatchHandle);
> + //
> + // Take the entry out of the linked list
> + //
> + if (RecordToDelete->Link.ForwardLink == (LIST_ENTRY *) EFI_BAD_POINTER)
> {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + RequireToDisableIoTrapHandler = FALSE;
> + //
> + // Loop through the first IO Trap handler, looking for the suitable handler
> + //
> + TrapHandlerNum = RecordToDelete->IoTrapNumber;
> +
> + if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable) {
> + //
> + // Disable the IO Trap handler if it's the only child of the Trap handler
> + //
> + RequireToDisableIoTrapHandler = TRUE;
> + } else {
> + //
> + // Get information from Io Trap handler register
> + //
> + IoTrapRegLowDword = 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) != 0) {
> +
> + UsedLength = LengthFromLowDword (IoTrapRegLowDword);
> + BaseAddress = AddressFromLowDword (IoTrapRegLowDword);
> +
> + //
> + // Check if it's the maximum address of the Io Trap handler
> + //
> + if ((UINTN)(BaseAddress + UsedLength) ==
> (UINTN)(RecordToDelete->Context.Address +
> RecordToDelete->Context.Length)) {
> +
> + if (BaseAddress == RecordToDelete->Context.Address) {
> + //
> + // Disable the IO Trap handler if it's the only child of the Trap handler
> + //
> + RequireToDisableIoTrapHandler = TRUE;
> + } else {
> + //
> + // Calculate the new IO Trap handler Length
> + //
> + UsedLength = UsedLength - RecordToDelete->Context.Length;
> + //
> + // Check the alignment is dword * power of 2 or not
> + //
> + for (LengthIndex = 0; LengthIndex < sizeof (mLengthTable) / sizeof
> (UINT16); LengthIndex++) {
> + if (UsedLength == 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 = (UINT32) ((((UsedLength - 1) &~(BIT1 + BIT0))
> << 16) | BaseAddress | B_PSTH_PCR_TRPREG_TSE);
> + }
> + SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, TRUE);
> + }
> + }
> + }
> + }
> +
> + if (RequireToDisableIoTrapHandler) {
> + mIoTrapHandle = mIoTrapData.Entry[TrapHandlerNum].IoTrapHandle;
> + Status = 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 = 0;
> + mIoTrapData.Entry[TrapHandlerNum].MergeDisable = FALSE;
> + if (mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource ==
> TRUE) {
> + mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource = FALSE;
> + UpdateIoTrapAcpiResources (TrapHandlerNum, 0, FALSE);
> + }
> + }
> +
> + RemoveEntryList (&RecordToDelete->Link);
> + Status = 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 allocation 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 to
> 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 context.
> + The caller fills this context in before calling
> + the register function to indicate to the register
> + function the IO trap SMI source for which 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 the address of
> linked
> + list link in the call back record. This may not be
> NULL.
> +
> + @retval EFI_SUCCESS The dispatch function has been successfully
> + registered and the SMI source has been enabled.
> + @retval EFI_DEVICE_ERROR The driver was unable to enable the SMI
> 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 = 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 driver.
> +
> + @param[in] This Pointer to the
> EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL instance.
> + @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
> +IoTrapUnRegister (
> + IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *This,
> + IN EFI_HANDLE DispatchHandle
> + )
> +{
> + IO_TRAP_RECORD *RecordToDelete;
> +
> + RecordToDelete = 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 context.
> + The caller fills this context in before calling
> + the register function to indicate to the 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 successfully
> + 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)) != 0)) {
> + DEBUG ((DEBUG_ERROR, "The Dispatch Length is not power of 2 \n"));
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Status = 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 deregister.
> +
> + @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 = 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 the
> DispatchHandle
> + with MergeDisable TRUE and address not zero.
> +
> + NOTE: This call does not guarantee all pending IO cycles to be synchronized
> + and pending IO cycles issued before this call might not be trapped.
> +
> + @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 == 0) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + IoTrapRecord = IO_TRAP_RECORD_FROM_LINK (DispatchHandle);
> +
> + if (IoTrapRecord->Context.Address) {
> + TempMergeDisable =TRUE;
> + }else {
> + TempMergeDisable = FALSE;
> + }
> +
> + if ((IoTrapRecord->Signature != IO_TRAP_RECORD_SIGNATURE) ||
> + (TempMergeDisable != TRUE) ||
> + (IoTrapRecord->Context.Address == 0) ||
> + (IoTrapRecord->Context.Length == 0)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + for (TrapHandlerNum = 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM;
> TrapHandlerNum++) {
> + //
> + // This IoTrap register should be merge disabled.
> + //
> + if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable != TRUE) {
> + continue;
> + }
> + IoTrapRegLowDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 +
> TrapHandlerNum * 8);
> + IoTrapRegHighDword = 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 length from Byte
> Enable Mask
> + // In the other hand, we obtain the length from Address Mask
> + //
> + if (ByteEnableMaskFromHighDword (IoTrapRegHighDword) != 0xF) {
> + UsedLength = (UINT32) (HighBitSet32 (IoTrapRegHighDword & 0xF0) -
> LowBitSet32 (IoTrapRegHighDword & 0xF0) + 1);
> + BaseAddress = AddressFromLowDword (IoTrapRegLowDword) +
> LowBitSet32 (ByteEnableMaskFromHighDword (IoTrapRegHighDword));
> + } else {
> + UsedLength = LengthFromLowDword (IoTrapRegLowDword);
> + BaseAddress = AddressFromLowDword (IoTrapRegLowDword);
> + }
> +
> + //
> + // The address and length of record matches the IoTrap register's.
> + //
> + DisableIoTrap = FALSE;
> + if ((IoTrapRecord->IoTrapExCallback != NULL) &&
> + IsIoTrapExContentMatched (IoTrapRecord, IoTrapRegLowDword,
> IoTrapRegHighDword)) {
> + DisableIoTrap = TRUE;
> + } else if ((BaseAddress == IoTrapRecord->Context.Address) &&
> + (UsedLength == IoTrapRecord->Context.Length )) {
> + DisableIoTrap = TRUE;
> + }
> +
> + if (DisableIoTrap) {
> + //
> + // Check if status matched.
> + // If this is already Paused, return warning status.
> + //
> + if ((IoTrapRegLowDword & B_PSTH_PCR_TRPREG_TSE) == 0) {
> + return EFI_ACCESS_DENIED;
> + }
> + //
> + // Clear IoTrap register SMI enable bit
> + //
> + IoTrapRegLowDword &= (~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 the
> 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 == 0) {
> + return EFI_INVALID_PARAMETER;
> + }
> + IoTrapRecord = IO_TRAP_RECORD_FROM_LINK (DispatchHandle);
> +
> + if (IoTrapRecord->Context.Address) {
> + TempMergeDisable = TRUE;
> + }else {
> + TempMergeDisable = FALSE;
> + }
> +
> + if ((IoTrapRecord->Signature != IO_TRAP_RECORD_SIGNATURE) ||
> + (TempMergeDisable != TRUE) ||
> + (IoTrapRecord->Context.Address == 0) ||
> + (IoTrapRecord->Context.Length == 0)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + for (TrapHandlerNum = 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM;
> TrapHandlerNum++) {
> + //
> + // This IoTrap register should be merge disabled.
> + //
> + if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable != TRUE) {
> + continue;
> + }
> + IoTrapRegLowDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 +
> TrapHandlerNum * 8);
> + IoTrapRegHighDword = 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 length from Byte
> Enable Mask
> + // In the other hand, we obtain the length from Address Mask
> + //
> + if (ByteEnableMaskFromHighDword (IoTrapRegHighDword) != 0xF) {
> + UsedLength = (UINT32) (HighBitSet32 (IoTrapRegHighDword & 0xF0) -
> LowBitSet32 (IoTrapRegHighDword & 0xF0) + 1);
> + BaseAddress = AddressFromLowDword (IoTrapRegLowDword) +
> LowBitSet32 (ByteEnableMaskFromHighDword (IoTrapRegHighDword));
> + } else {
> + UsedLength = LengthFromLowDword (IoTrapRegLowDword);
> + BaseAddress = AddressFromLowDword (IoTrapRegLowDword);
> + }
> +
> + //
> + // The address and length of record matches the IoTrap register's.
> + //
> + EnableIoTrap = FALSE;
> + if ((IoTrapRecord->IoTrapExCallback != NULL) &&
> + IsIoTrapExContentMatched (IoTrapRecord, IoTrapRegLowDword,
> IoTrapRegHighDword)) {
> + EnableIoTrap = TRUE;
> + } else if ((BaseAddress == IoTrapRecord->Context.Address) &&
> + (UsedLength == IoTrapRecord->Context.Length )) {
> + EnableIoTrap = TRUE;
> + }
> +
> + if (EnableIoTrap) {
> + //
> + // Check if status matched.
> + // If this is already Resume, return warning status.
> + //
> + if ((IoTrapRegLowDword & B_PSTH_PCR_TRPREG_TSE) != 0) {
> + return EFI_ACCESS_DENIED;
> + }
> + //
> + // Set IoTrap register SMI enable bit
> + //
> + IoTrapRegLowDword |= (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 drivers.
> + This driver manages the limited I/O trap resources.
> +
> + @param[in] ImageHandle Image handle for this driver image
> +
> + @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 = ImageHandle;
> +
> + //
> + // Initialize the IO TRAP protocol we produce
> + //
> + mIoTrapData.Signature = IO_TRAP_INSTANCE_SIGNATURE;
> + mIoTrapData.EfiSmmIoTrapDispatchProtocol.Register = IoTrapRegister;
> + mIoTrapData.EfiSmmIoTrapDispatchProtocol.UnRegister =
> IoTrapUnRegister;
> +
> + //
> + // Initialize the IO TRAP EX protocol
> + //
> + mIoTrapData.IoTrapExDispatchProtocol.Register = IoTrapExRegister;
> + mIoTrapData.IoTrapExDispatchProtocol.UnRegister =
> IoTrapExUnRegister;
> +
> + //
> + // Initialize the IO TRAP control protocol.
> + //
> + mIoTrapData.PchSmmIoTrapControlProtocol.Pause =
> IoTrapControlPause;
> + mIoTrapData.PchSmmIoTrapControlProtocol.Resume =
> IoTrapControlResume;
> +
> + for (TrapHandlerNum = 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM;
> TrapHandlerNum++) {
> + //
> + // Initialize IO TRAP Callback DataBase
> + //
> + InitializeListHead
> (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase));
> + }
> + mIoTrapData.Entry[0].CallbackDispatcher = IoTrapDispatcher0;
> + mIoTrapData.Entry[1].CallbackDispatcher = IoTrapDispatcher1;
> + mIoTrapData.Entry[2].CallbackDispatcher = IoTrapDispatcher2;
> + mIoTrapData.Entry[3].CallbackDispatcher = IoTrapDispatcher3;
> +
> + //
> + // Get address of PchNvs structure for later use
> + //
> + Status = gBS->LocateProtocol (&gPchNvsAreaProtocolGuid, NULL, (VOID **)
> &PchNvsAreaProtocol);
> + ASSERT_EFI_ERROR (Status);
> + mPchNvsArea = PchNvsAreaProtocol->Area;
> +
> + //
> + // Install protocol interface
> + //
> + mIoTrapData.Handle = NULL;
> + Status = gSmst->SmmInstallProtocolInterface (
> + &mIoTrapData.Handle,
> + &gEfiSmmIoTrapDispatch2ProtocolGuid,
> + EFI_NATIVE_INTERFACE,
> + &mIoTrapData.EfiSmmIoTrapDispatchProtocol
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + Status = gSmst->SmmInstallProtocolInterface (
> + &mIoTrapData.Handle,
> + &gIoTrapExDispatchProtocolGuid,
> + EFI_NATIVE_INTERFACE,
> + &mIoTrapData.IoTrapExDispatchProtocol
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + Status = 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 events.
> +
> + Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "PchSmmHelpers.h"
> +#include <Library/SmiHandlerProfileLib.h>
> +#include <Private/Library/PmcPrivateLib.h>
> +#include <Register/PchRegs.h>
> +#include <Register/PchRegsPcr.h>
> +#include <Register/PchRegsPmc.h>
> +#include <Register/PchRegsLpc.h>
> +#include <Register/PchRegsSpi.h>
> +#include <Register/PchRegsPcie.h>
> +#include <Register/PchRegsPsth.h>
> +#include <Register/PchRegsItss.h>
> +
> +/**
> + 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 database
> 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 == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + ZeroMem (&Record, sizeof (DATABASE_RECORD));
> + //
> + // Gather information about the registration request
> + //
> + Record.Signature = DATABASE_RECORD_SIGNATURE;
> + Record.PchSmiCallback = DispatchFunction;
> + Record.ProtocolType = PchSmiDispatchType;
> + Record.PchSmiType = PchSmiType;
> +
> + CopyMem (&Record.SrcDesc, SrcDesc, sizeof (PCH_SMM_SOURCE_DESC));
> + Status = 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 = {
> + 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 the 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 the 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 = PCH_SMM_ADDR_TYPE_NULL;
> + SrcDesc->En[1].Reg.Type = PCH_SMM_ADDR_TYPE_NULL;
> + SrcDesc->Sts[0].Reg.Type = PCH_SMM_ADDR_TYPE_NULL;
> + SrcDesc->PmcSmiSts.Reg.Type = PCH_SMM_ADDR_TYPE_NULL;
> +}
> +
> +//
> +// Mch srcdesc
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescMch = {
> + 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 itself
> + @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 database
> 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = PchSmiRecordInsert (
> + &mSrcDescMch,
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
> + PchTcoSmiMchType,
> + DispatchHandle
> + );
> + if (!EFI_ERROR (Status)) {
> + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
> + Record->ClearSource = 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 = {
> + 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 itself
> + @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 database
> 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = PchSmiRecordInsert (
> + &mSrcDescTcoTimeout,
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
> + PchTcoSmiTcoTimeoutType,
> + DispatchHandle
> + );
> + if (!EFI_ERROR (Status)) {
> + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
> + Record->ClearSource = 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 = {
> + 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 itself
> + @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 database
> 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = PchSmiRecordInsert (
> + &mSrcDescOsTco,
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
> + PchTcoSmiOsTcoType,
> + DispatchHandle
> + );
> + if (!EFI_ERROR (Status)) {
> + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
> + Record->ClearSource = 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 = {
> + 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 = 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 itself
> + @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 database
> 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = PchSmiRecordInsert (
> + &mSrcDescNmi,
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
> + PchTcoSmiNmiType,
> + DispatchHandle
> + );
> + if (!EFI_ERROR (Status)) {
> + Record = 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 = 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 = {
> + 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 itself
> + @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 database
> 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = PchSmiRecordInsert (
> + &mSrcDescIntruderDet,
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
> + PchTcoSmiIntruderDetectType,
> + DispatchHandle
> + );
> + if (!EFI_ERROR (Status)) {
> + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
> + Record->ClearSource = 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 = {
> + 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 = 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 = 1000;
> + do {
> + BiosControl = 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 the TCO
> registers
> + //
> + PchSmmClearSource (&mDescSrcTcoSts);
> +}
> +
> +/**
> + The register function used to register SMI handler of BIOS write protect
> event.
> +
> + @param[in] This The pointer to the protocol itself
> + @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 database
> 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = PchSmiRecordInsert (
> + &mSrcDescSpiBiosWp,
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
> + PchTcoSmiSpiBiosWpType,
> + DispatchHandle
> + );
> + if (!EFI_ERROR (Status)) {
> + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
> + Record->ClearSource = 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 = {
> + 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 protect
> event.
> +
> + @param[in] This The pointer to the protocol itself
> + @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 database
> 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 == 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 = PchSmiRecordInsert (
> + &mSrcDescLpcBiosWp,
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
> + PchTcoSmiLpcBiosWpType,
> + DispatchHandle
> + );
> + if (!EFI_ERROR (Status)) {
> + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
> + Record->ClearSource = 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 = {
> + 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 event.
> +
> + @param[in] This The pointer to the protocol itself
> + @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 database
> 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = PchSmiRecordInsert (
> + &mSrcDescNewCentury,
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
> + PchTcoSmiNewCenturyType,
> + DispatchHandle
> + );
> + if (!EFI_ERROR (Status)) {
> + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
> + Record->ClearSource = 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 driver
> +
> + @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 = DATABASE_RECORD_FROM_LINK (DispatchHandle);
> + if ((Record->SrcDesc.En[1].Reg.Type == ACPI_ADDR_TYPE) &&
> + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Dev ==
> PCI_DEVICE_NUMBER_PCH_SPI) &&
> + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Fnc ==
> PCI_FUNCTION_NUMBER_PCH_SPI) &&
> + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Reg == R_SPI_CFG_BC) &&
> + (Record->SrcDesc.En[1].Bit == N_SPI_CFG_BC_BLE)) {
> + //
> + // SPI Write Protect cannot be disabled
> + //
> + return EFI_ACCESS_DENIED;
> + } else if ((Record->SrcDesc.En[1].Reg.Type == ACPI_ADDR_TYPE) &&
> + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Dev ==
> PCI_DEVICE_NUMBER_PCH_LPC) &&
> + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Fnc ==
> PCI_FUNCTION_NUMBER_PCH_LPC) &&
> + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Reg == R_LPC_CFG_BC)
> &&
> + (Record->SrcDesc.En[1].Bit == N_LPC_CFG_BC_LE)) {
> + //
> + // eSPI/LPC Write Protect cannot be disabled
> + //
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = 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 = {
> + 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 itself
> + @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 database
> 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 == 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 = (UINT8)
> RpDev;
> + PchPcieSmiRpHotPlugTemplate.En[0].Reg.Data.pcie.Fields.Fnc = (UINT8)
> RpFun;
> + PchPcieSmiRpHotPlugTemplate.Sts[0].Reg.Data.pcie.Fields.Dev = (UINT8)
> RpDev;
> + PchPcieSmiRpHotPlugTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc = (UINT8)
> RpFun;
> +
> + Status = 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 = {
> + 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 active
> event.
> +
> + @param[in] This The pointer to the protocol itself
> + @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 database
> 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 == 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 = (UINT8)
> RpDev;
> + PchPcieSmiRpLinkActiveTemplate.En[0].Reg.Data.pcie.Fields.Fnc = (UINT8)
> RpFun;
> + PchPcieSmiRpLinkActiveTemplate.Sts[0].Reg.Data.pcie.Fields.Dev = (UINT8)
> RpDev;
> + PchPcieSmiRpLinkActiveTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc = (UINT8)
> RpFun;
> +
> + Status = 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 = {
> + 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 itself
> + @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 database
> 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 == 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 = (UINT8)
> RpDev;
> + PchPcieSmiRpLinkEqTemplate.En[0].Reg.Data.pcie.Fields.Fnc = (UINT8)
> RpFun;
> + PchPcieSmiRpLinkEqTemplate.Sts[0].Reg.Data.pcie.Fields.Dev = (UINT8)
> RpDev;
> + PchPcieSmiRpLinkEqTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc = (UINT8)
> RpFun;
> +
> + Status = 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 driver
> +
> + @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 = DATABASE_RECORD_FROM_LINK (DispatchHandle);
> + Status = 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 = {
> + 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 itself
> + @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 database
> 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = 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 = {
> + 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 itself
> + @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 database
> 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = 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 = {
> + 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 itself
> + @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 database
> 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = 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 = {
> + 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 event.
> +
> + @param[in] This The pointer to the protocol itself
> + @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 database
> 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = 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 driver
> +
> + @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 = DATABASE_RECORD_FROM_LINK (DispatchHandle);
> + Status = 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 = {
> + 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 itself
> + @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 database
> 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = 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 = {
> + 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 itself
> + @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 database
> 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = 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 = {
> + 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 itself
> + @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 database
> 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = 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 = {
> + 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 Done
> + 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 = 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 = PciSegmentRead32 (SpiRegBase + R_SPI_CFG_BAR0) &
> ~(B_SPI_CFG_BAR0_MASK);
> + if (SpiBar0 != PCH_SPI_BASE_ADDRESS) {
> + //
> + // Temporary disable MSE, and override with SPI reserved MMIO address,
> then enable MSE.
> + //
> + SpiBar0 = 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 = 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 itself
> + @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 database
> 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = PchSmiRecordInsert (
> + &mSrcDescSpiAsyncSmi,
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
> + PchSmiSpiAsyncType,
> + DispatchHandle
> + );
> +
> + if (!EFI_ERROR (Status)) {
> + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
> + Record->ClearSource = 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 driver
> +
> + @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 aync
> 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 = DATABASE_RECORD_FROM_LINK (DispatchHandle);
> + if ((Record->SrcDesc.En[0].Reg.Type == PCIE_ADDR_TYPE) &&
> + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Dev ==
> PCI_DEVICE_NUMBER_PCH_SPI) &&
> + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Fnc ==
> PCI_FUNCTION_NUMBER_PCH_SPI) &&
> + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Reg == R_SPI_CFG_BC) &&
> + (Record->SrcDesc.En[0].Bit == N_SPI_CFG_BC_ASE_BWP)) {
> + SpiRegBase = 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 = 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 = {
> + 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 = {
> + 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 = {
> + 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 = {
> + 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 SMI
> types.
> +
> + @retval the result of protocol installation
> +**/
> +EFI_STATUS
> +InstallPchSmiDispatchProtocols (
> + VOID
> + )
> +{
> + EFI_HANDLE Handle;
> + EFI_STATUS Status;
> +
> + Handle = NULL;
> + Status = gSmst->SmmInstallProtocolInterface (
> + &Handle,
> + &gPchTcoSmiDispatchProtocolGuid,
> + EFI_NATIVE_INTERFACE,
> + &mPchTcoSmiDispatchProtocol
> + );
> + Status = gSmst->SmmInstallProtocolInterface (
> + &Handle,
> + &gPchPcieSmiDispatchProtocolGuid,
> + EFI_NATIVE_INTERFACE,
> + &mPchPcieSmiDispatchProtocol
> + );
> + Status = gSmst->SmmInstallProtocolInterface (
> + &Handle,
> + &gPchAcpiSmiDispatchProtocolGuid,
> + EFI_NATIVE_INTERFACE,
> + &mPchAcpiSmiDispatchProtocol
> + );
> + Status = 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 = Record->PchSmiType;
> + Status = 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 = DEFAULT_PCI_BUS_NUMBER_PCH;
> + RpContext.DevNum = (UINT8)
> Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Dev;
> + RpContext.FuncNum = (UINT8)
> Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Fnc;
> + GetPchPcieRpNumber (RpContext.DevNum, RpContext.FuncNum,
> &RpIndex);
> + RpContext.RpIndex = (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 = EFI_UNSUPPORTED;
> + break;
> + }
> +
> + return Status;
> +}
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescIoTrap[4] = {
> + //
> + // 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 database
> 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 = 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 driver
> +
> + @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 = DATABASE_RECORD_FROM_LINK (DispatchHandle);
> + Status = 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. <BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "PchSmm.h"
> +#include "PchSmmHelpers.h"
> +#include "PchSmmEspi.h"
> +#include <Library/SmiHandlerProfileLib.h>
> +#include <Register/PchRegsGpio.h>
> +#include <Register/PchRegsPmc.h>
> +#include <Register/PchRegsLpc.h>
> +
> +//
> +// 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 = {
> + {
> + NULL,
> + NULL
> + }, // CallbackDataBase linked list head
> + NULL, // EFI handle returned when calling
> 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] = {
> + {
> + 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 = TRUE;
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + <b>PchSmiDispatcher SMM Module Entry Point</b>\n
> + - <b>Introduction</b>\n
> + The PchSmiDispatcher module is an SMM driver which provides SMI
> handler registration
> + services for PCH generated SMIs.
> +
> + - <b>Details</b>\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 prepared 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 for
> this driver
> + @param[in] SystemTable Pointer to the EFI System Table
> +
> + @retval EFI_SUCCESS PchSmmDispatcher Initialization completed.
> +**/
> +EFI_STATUS
> +EFIAPI
> +InitializePchSmmDispatcher (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + EFI_STATUS Status;
> + VOID *SmmReadyToLockRegistration;
> +
> + //
> + // Access ACPI Base Addresses Register
> + //
> +
> + mAcpiBaseAddr = PmcGetAcpiBase ();
> + ASSERT (mAcpiBaseAddr != 0);
> +
> + //
> + // Access TCO Base Addresses Register
> + //
> + PchTcoBaseGet (&mTcoBaseAddr);
> + ASSERT (mTcoBaseAddr != 0);
> +
> +
> + //
> + // Register a callback function to handle subsequent SMIs. This callback
> + // will be called by SmmCoreDispatcher.
> + //
> + Status = 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 = 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 database
> 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 == NULL) ||
> + (NewRecord->Signature != DATABASE_RECORD_SIGNATURE))
> + {
> + ASSERT (FALSE);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Status = 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 = (EFI_HANDLE) (&Record->Link);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Unregister a child SMI source dispatch function with a parent SMM driver
> +
> + @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 = QUALIFIED_PROTOCOL_FROM_GENERIC (This);
> + RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
> + Status = 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 the 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 successfully
> + 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 == 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 = DispatchFunction;
> +
> + Qualified = QUALIFIED_PROTOCOL_FROM_GENERIC (This);
> +
> + Record.ProtocolType = Qualified->Type;
> +
> + Record.ContextFunctions = mContextFunctions[Qualified->Type];
> + //
> + // Perform linked list housekeeping
> + //
> + Record.Signature = 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 = 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 = NULL;
> + //
> + // use default clear source function
> + //
> + break;
> +
> + case SxType:
> + Record.ContextSize = 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 >= EfiMaximumSleepType) ||
> + (Record.ChildContext.Sx.Phase < SxEntry) ||
> + (Record.ChildContext.Sx.Phase >= EfiMaximumPhase)
> + ) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + CopyMem (&Record.SrcDesc, &mSxSourceDesc, sizeof
> (PCH_SMM_SOURCE_DESC));
> + Record.ClearSource = NULL;
> + //
> + // use default clear source function
> + //
> + break;
> +
> + case PowerButtonType:
> + Record.ContextSize = 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 = NULL;
> + //
> + // use default clear source function
> + //
> + break;
> +
> + case PeriodicTimerType:
> + Record.ContextSize = sizeof
> (EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT);
> + CopyMem (&Record.ChildContext, DispatchContext,
> Record.ContextSize);
> + //
> + // Check the validity of timer value
> + //
> + if (DispatchContext->PeriodicTimer.SmiTickInterval <= 0) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + MapPeriodicTimerToSrcDesc (DispatchContext, &Record.SrcDesc);
> + Record.ClearSource = 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 = SmmCoreInsertRecord (
> + &Record,
> + DispatchHandle
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + if (Record.ClearSource == 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 driver.
> +
> + @param[in] This Pointer to the
> PCH_SMM_GENERIC_PROTOCOL instance.
> + @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
> +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 == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + //
> + // Return access denied if the SmmReadyToLock event has been triggered
> + //
> + if (mReadyToLock == TRUE) {
> + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the
> SmmReadyToLock event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
> +
> + //
> + // Take the entry out of the linked list
> + //
> + if (RecordToDelete->Link.ForwardLink == (LIST_ENTRY *) EFI_BAD_POINTER)
> {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + RemoveEntryList (&RecordToDelete->Link);
> +
> + //
> + // Loop through all the souces in record linked list to see if any source enable
> is equal.
> + // If any source enable is equal, we do not want to disable it.
> + //
> + for (DescIndex = 0; DescIndex < NUM_EN_BITS; ++DescIndex) {
> + if (IS_BIT_DESC_NULL (RecordToDelete->SrcDesc.En[DescIndex])) {
> + continue;
> + }
> + NeedClearEnable = TRUE;
> + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
> + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
> + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
> + if (IsBitEqualToAnySourceEn (&RecordToDelete->SrcDesc.En[DescIndex],
> &RecordInDb->SrcDesc)) {
> + NeedClearEnable = FALSE;
> + break;
> + }
> + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase,
> &RecordInDb->Link);
> + }
> + if (NeedClearEnable == FALSE) {
> + continue;
> + }
> + WriteBitDesc (&RecordToDelete->SrcDesc.En[DescIndex], 0, FALSE);
> + }
> + Status = 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 hide
> 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 not
> 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 be
> 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 = 3;
> + ContextsMatch = FALSE;
> + EosSet = FALSE;
> + SxChildWasDispatched = FALSE;
> + Status = 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 CF8
> + //
> + Port76Save = IoRead8 (R_RTC_IO_EXT_INDEX_ALT);
> + Port74Save = IoRead8 (R_RTC_IO_INDEX_ALT);
> +
> + if (!IsListEmpty (&mPrivateData.CallbackDataBase)) {
> + //
> + // We have children registered w/ us -- continue
> + //
> + while ((!EosSet) && (EscapeCount > 0)) {
> + EscapeCount--;
> +
> + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
> +
> + //
> + // Cache SciEn, SmiEnValue and SmiStsValue to determine if source is
> active
> + //
> + SciEn = PchSmmGetSciEn ();
> + SmiEnValue = IoRead32 ((UINTN) (mAcpiBaseAddr +
> R_ACPI_IO_SMI_EN));
> + SmiStsValue = IoRead32 ((UINTN) (mAcpiBaseAddr +
> R_ACPI_IO_SMI_STS));
> +
> + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
> + RecordInDb = 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 = 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 = PchSmmSetAndCheckEos ();
> + }
> + } else {
> + //
> + // We found a source. If this is a sleep type, we have to go to
> + // appropriate sleep state anyway.No matter there is sleep child or
> not
> + //
> + if (RecordInDb->ProtocolType == SxType) {
> + SxChildWasDispatched = TRUE;
> + }
> + //
> + // "cache" the source description and don't query I/O anymore
> + //
> + CopyMem ((VOID *) &ActiveSource, (VOID *) &(RecordInDb->SrcDesc),
> sizeof (PCH_SMM_SOURCE_DESC));
> + LinkToExhaust = LinkInDb;
> +
> + //
> + // exhaust the rest of the queue looking for the same source
> + //
> + while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)) {
> + RecordToExhaust = 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 here (before
> Callback function).
> + //
> + LinkToExhaust = GetNextNode (&mPrivateData.CallbackDataBase,
> &RecordToExhaust->Link);
> +
> + if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource)) {
> + //
> + // These source descriptions are equal, so this callback should be
> + // dispatched.
> + //
> + if (RecordToExhaust->ContextFunctions.GetContext != NULL) {
> + //
> + // This child requires that we get a calling context from
> + // hardware and compare that context to the one supplied
> + // by the child.
> + //
> + ASSERT (RecordToExhaust->ContextFunctions.CmpContext !=
> NULL);
> +
> + //
> + // Make sure contexts match before dispatching event to child
> + //
> + RecordToExhaust->ContextFunctions.GetContext
> (RecordToExhaust, &Context);
> + ContextsMatch =
> RecordToExhaust->ContextFunctions.CmpContext (&Context,
> &RecordToExhaust->ChildContext);
> +
> + } else {
> + //
> + // This child doesn't require any more calling context beyond
> what
> + // it supplied in registration. Simply pass back what it gave us.
> + //
> + Context = RecordToExhaust->ChildContext;
> + ContextsMatch = TRUE;
> + }
> +
> + if (ContextsMatch) {
> + if (RecordToExhaust->ProtocolType == PchSmiDispatchType) {
> + //
> + // For PCH SMI dispatch protocols
> + //
> + PchSmiTypeCallbackDispatcher (RecordToExhaust);
> + } else {
> + //
> + // For EFI standard SMI dispatch protocols
> + //
> + if (RecordToExhaust->Callback != NULL) {
> + if (RecordToExhaust->ContextFunctions.GetCommBuffer !=
> 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 = NULL;
> + CommBufferSize = 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 == SxType) {
> + SxChildWasDispatched = TRUE;
> + }
> + } else {
> + ASSERT (FALSE);
> + }
> + }
> + }
> + }
> + }
> +
> + if (RecordInDb->ClearSource == 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 = 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 Callback,
> 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 EOS
> without letting
> + // these other sources get serviced.
> + //
> + // This assert is not valid with CSM legacy solution because it generates
> 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. <BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "PchSmmEspi.h"
> +#include <Private/Library/PmcPrivateLib.h>
> +#include <Library/PchEspiLib.h>
> +#include <Library/SmiHandlerProfileLib.h>
> +#include <Register/PchRegs.h>
> +#include <Register/PchRegsPcr.h>
> +#include <Register/PchRegsLpc.h>
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED ESPI_SMI_INSTANCE
> mEspiSmiInstance = {
> + //
> + // 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] = {
> + //
> + // 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 = 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 = &mEspiDescriptor[EspiSmiType];
> +
> + switch (Desc->Address.Type) {
> + case PCIE_ADDR_TYPE:
> + PciBus = Desc->Address.Data.pcie.Fields.Bus;
> + PciDev = Desc->Address.Data.pcie.Fields.Dev;
> + PciFun = Desc->Address.Data.pcie.Fields.Fnc;
> + PciReg = Desc->Address.Data.pcie.Fields.Reg;
> + PciBaseAddress = 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 = &mEspiDescriptor[EspiSmiType];
> +
> + Active = FALSE;
> + switch (Desc->Address.Type) {
> + case PCIE_ADDR_TYPE:
> + PciBus = Desc->Address.Data.pcie.Fields.Bus;
> + PciDev = Desc->Address.Data.pcie.Fields.Dev;
> + PciFun = Desc->Address.Data.pcie.Fields.Fnc;
> + PciReg = Desc->Address.Data.pcie.Fields.Reg;
> + PciBaseAddress = PCI_SEGMENT_LIB_ADDRESS
> (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0);
> + Data32 = PciSegmentRead32 (PciBaseAddress + PciReg);
> + break;
> +
> + case PCR_ADDR_TYPE:
> + Data32 = PchPcrRead32 (
> + Desc->Address.Data.Pcr.Fields.Pid,
> + Desc->Address.Data.Pcr.Fields.Offset
> + );
> + break;
> +
> + default:
> + Data32 = 0;
> + DEBUG ((DEBUG_ERROR, "Address type for eSPI SMI is invalid \n"));
> + ASSERT (FALSE);
> + break;
> + }
> +
> + if ((Data32 & Desc->SourceIsActiveAndMask) == Desc->SourceIsActiveValue)
> {
> + Active = TRUE;
> + }
> +
> + return Active;
> +}
> +
> +/**
> + Insert a handler into the corresponding linked list based on EspiSmiType
> +
> + @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 database
> +
> + @retval EFI_SUCCESS Record was successfully inserted into
> master database
> + @retval EFI_OUT_OF_RESOURCES Cannot allocate pool to insert record
> +**/
> +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 = 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 = DispatchFunction;
> + Record->Signature = ESPI_SMI_RECORD_SIGNATURE;
> +
> + InsertTailList (&mEspiSmiInstance.CallbackDataBase[EspiSmiType],
> &Record->Link);
> + EspiSmiClearStatus (EspiSmiType);
> + EspiSmiEnableSource (EspiSmiType);
> +
> + ++mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType];
> +
> + *DispatchHandle = (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 = DATABASE_RECORD_FROM_LINK (DispatchHandle);
> +
> + if (PchSmiRecord->PchSmiType == PchTcoSmiLpcBiosWpType) {
> + EspiTopLevelType = EspiBiosWrProtect;
> + } else if (PchSmiRecord->PchSmiType == PchSmiSerialIrqType) {
> + EspiTopLevelType = EspiSerialIrq;
> + } else {
> + DEBUG ((DEBUG_ERROR, "EspiSmiCallback was dispatched with a wrong
> DispatchHandle"));
> + ASSERT (FALSE);
> + return;
> + }
> +
> + for (EspiSmiType = mEspiSmiInstance.Barrier[EspiTopLevelType].Start;
> EspiSmiType <= 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 = GetFirstNode
> (&mEspiSmiInstance.CallbackDataBase[EspiSmiType]);
> +
> + while (!IsNull (&mEspiSmiInstance.CallbackDataBase[EspiSmiType],
> LinkInDb)) {
> + RecordInDb = 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 = GetNextNode
> (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], &RecordInDb->Link);
> +
> + //
> + // Callback
> + //
> + if (RecordInDb->Callback != NULL) {
> + RecordInDb->Callback ((EFI_HANDLE) &RecordInDb->Link);
> + } else {
> + ASSERT (FALSE);
> + }
> + }
> + } else if (EspiSmiType == 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 status
> + //
> + EspiSmiClearStatus (EspiSmiType);
> + }
> +}
> +
> +//
> +// EspiBiosWp srcdesc
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescEspiBiosWp = {
> + 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 source
> decriptor
> + This function make sure there is only one BIOS WP SMI handler is registered.
> + 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] == NULL) {
> + Status = 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 = DATABASE_RECORD_FROM_LINK
> (mEspiSmiInstance.PchSmiEspiHandle[EspiBiosWrProtect]);
> + Record->ClearSource = PchTcoSmiClearSource;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function will register EspiSmiCallback with mSrcDescSerialIrq source
> 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 IRQ 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] == NULL) {
> + Status = 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 = 0; EspiSmiType < EspiSmiTypeMax; ++EspiSmiType) {
> + InitializeListHead (&mEspiSmiInstance.CallbackDataBase[EspiSmiType]);
> + }
> +
> + //
> + // Install EfiEspiSmiDispatchProtocol
> + //
> + Status = 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 default
> handler
> + Status = 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 event
> +
> + @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 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = RegisterBiosWrProtectIfNull ();
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + //
> + // Insert a record
> + //
> + Status = 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 event
> +
> + @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 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = RegisterSerialIrqIfNull ();
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + //
> + // Insert a record
> + //
> + Status = 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 Non
> Fatal Error event
> +
> + @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 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = RegisterSerialIrqIfNull ();
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + //
> + // Insert a record
> + //
> + Status = 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 Fatal
> Error event
> +
> + @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 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = RegisterSerialIrqIfNull ();
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + //
> + // Insert a record
> + //
> + Status = InsertEspiRecord (DispatchFunction, PcFatalErr, 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 Non Fatal Error
> event
> +
> + @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 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = RegisterSerialIrqIfNull ();
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + //
> + // Insert a record
> + //
> + Status = 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 Error
> event
> +
> + @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 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = RegisterSerialIrqIfNull ();
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + //
> + // Insert a record
> + //
> + Status = InsertEspiRecord (DispatchFunction, VwFatalErr, 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 Non Fatal
> Error event
> +
> + @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 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = RegisterSerialIrqIfNull ();
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + //
> + // Insert a record
> + //
> + Status = 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 registration
> +
> + @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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = RegisterSerialIrqIfNull ();
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + //
> + // Insert a record
> + //
> + Status = 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 registration
> +
> + @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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = RegisterSerialIrqIfNull ();
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + //
> + // Insert a record
> + //
> + Status = 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 = {
> + 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 select
> (SPT-H),
> + the SMI handler itself needs to inspect both the eSPI devices' interrupt
> status registers
> + (implementation specific for each Slave) in order to identify and service the
> cause.
> + After servicing it, it has to clear the Slaves' internal SMI# status registers
> +
> + @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 == 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 mEspiSmiInstance.
> + // While SMI is triggered it directly goes to the registing
> DispatchFunction
> + // instead of EspiSmiCallback.
> + //
> + Status = 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] = *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 registration
> +
> + @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 of
> 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 == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + //
> + // Return access denied if the SmmReadyToLock event has been triggered
> + //
> + if (mReadyToLock == 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 == (LIST_ENTRY *)
> EFI_BAD_POINTER) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + //
> + // For DispatchHandle belongs to Espi Slave SMI, refuses the request of
> unregistration.
> + //
> + if (mEspiSmiInstance.PchSmiEspiHandle[EspiPmc] == 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 = 0; EspiSmiType < EspiSmiTypeMax; ++EspiSmiType) {
> + LinkInDb = GetFirstNode
> (&mEspiSmiInstance.CallbackDataBase[EspiSmiType]);
> +
> + while (!IsNull (&mEspiSmiInstance.CallbackDataBase[EspiSmiType],
> LinkInDb)) {
> + if (LinkInDb != (LIST_ENTRY *) DispatchHandle) {
> + LinkInDb = GetNextNode
> (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], LinkInDb);
> +
> + } else {
> + //
> + // Found the source to be from this list
> + //
> + RemoveEntryList (LinkInDb);
> + RecordPointer = (ESPI_RECORD_FROM_LINK (LinkInDb));
> +
> + if (mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] != 0) {
> + if (--mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] == 0) {
> + EspiSmiDisableSource (EspiSmiType);
> + }
> + }
> +
> + Status = 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 = 0; EspiTopLevelType < EspiTopLevelTypeMax;
> ++EspiTopLevelType) {
> + SafeToDisable = TRUE;
> + //
> + // Checks all the child events that belongs to a top level status in PMC
> + //
> + for (EspiSmiType = mEspiSmiInstance.Barrier[EspiTopLevelType].Start;
> EspiSmiType <= mEspiSmiInstance.Barrier[EspiTopLevelType].End;
> ++EspiSmiType) {
> + if (mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] != 0) {
> + SafeToDisable = FALSE;
> + }
> + }
> + //
> + // Finally, disable the top level event in PMC
> + //
> + if (SafeToDisable) {
> + if (mEspiSmiInstance.PchSmiEspiHandle[EspiTopLevelType] != NULL) {
> + Status = PchSmmCoreUnRegister (NULL,
> mEspiSmiInstance.PchSmiEspiHandle[EspiTopLevelType]);
> + ASSERT_EFI_ERROR (Status);
> + mEspiSmiInstance.PchSmiEspiHandle[EspiTopLevelType] = NULL;
> + }
> + }
> + }
> + RecordToDelete = 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 masked to
> not clear them by mistake
> +**/
> +UINT32
> +GetEspiChannelStatusClearMask (
> + UINT8 ChannelNumber
> + )
> +{
> + UINT32 Data32;
> +
> + // Common error status bits for all channel registers
> + Data32 = 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 |= B_ESPI_PCR_PCERR_PCURD;
> + break;
> + case 3: // Flash Access Channel specific status bits
> + Data32 |= 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 == 2) {
> + DEBUG ((DEBUG_INFO, "Channel %d is not supported by this function due
> 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 = (UINT16) (ChannelBaseAddress + (SlaveId *
> S_ESPI_PCR_XERR));
> +
> + // Reading channel error register data
> + Data32 = 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) != 0) {
> + Status = 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 and 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 = IsEspiSecondSlaveSupported () ? 2 : 1;
> +
> + DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] MaxSlavesCount
> %d\n", MaxSlavesCount));
> +
> + for (SlaveId = 0; SlaveId < MaxSlavesCount; ++SlaveId) {
> + //
> + // Check if slave has SLCRR bit set. If it does it means it needs recovery.
> + //
> + Data32 = PchPcrRead32 (PID_ESPISPI, (UINT16) (R_ESPI_PCR_LNKERR_SLV0
> + (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) != 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 == 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 dispatch
> protocol.
> +
> + Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "PchSmm.h"
> +#include "PchSmmHelpers.h"
> +#include <Library/SmiHandlerProfileLib.h>
> +#include <Register/PchRegsGpio.h>
> +#include <Register/PchRegsPmc.h>
> +
> +//
> +// Structure for GPI SMI is a template which needs to have
> +// GPI Smi bit offset and Smi Status & Enable registers updated (accordingly
> +// to choosen group and pad number) after adding it to SMM Callback
> database
> +//
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mPchGpiSourceDescTemplate = {
> + 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 the
> specified GPI causes an SMI.
> + @param[in] RegisterContext Pointer to the dispatch function's context.
> + The caller fills this context in before calling
> + the register function to indicate to the register
> + function the GPI(s) for which the dispatch 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 successfully
> + 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 input
> 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 == TRUE) {
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the EndOfDxe event
> has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + Status = 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 = DispatchFunction;
> + Record.ChildContext.Gpi = *RegisterContext;
> + Record.ProtocolType = GpiType;
> + Record.Signature = DATABASE_RECORD_SIGNATURE;
> +
> + CopyMem (&Record.SrcDesc, &mPchGpiSourceDescTemplate, sizeof
> (PCH_SMM_SOURCE_DESC) );
> +
> + Record.SrcDesc.Sts[0].Reg.Data.raw = GpiSmiStsRegAddress; // GPI SMI
> Status register
> + Record.SrcDesc.Sts[0].Bit = GpiSmiBitOffset; // Bit position for
> selected pad
> +
> + //
> + // Insert GpiSmi handler to PchSmmCore database
> + //
> + *DispatchHandle = NULL;
> +
> + Status = 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/SCI
> + // - 1 (GPIO mode) - GPIO pad will not generate SMI/NMI/SCI
> + //
> + Data32And = (UINT32)~(1u << GpiSmiBitOffset);
> + MmioAnd32 (GpiHostSwOwnRegAddress, Data32And);
> +
> + //
> + // Add HOSTSW_OWN programming into S3 boot script
> + //
> + Data32Or = 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 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
> +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 == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
> + if ((RecordToDelete->Signature != DATABASE_RECORD_SIGNATURE) ||
> + (RecordToDelete->ProtocolType != GpiType)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + //
> + // Return access denied if the SmmReadyToLock event has been triggered
> + //
> + if (mReadyToLock == TRUE) {
> + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the
> SmmReadyToLock event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + DisableGpiSmiSource = 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 = GetFirstNode (&mPrivateData.CallbackDataBase);
> + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
> + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
> + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase,
> &RecordInDb->Link);
> + //
> + // If this is the record to delete skip it
> + //
> + if (RecordInDb == RecordToDelete) {
> + continue;
> + }
> + //
> + // Check if record is GPI SMI type
> + //
> + if (RecordInDb->ProtocolType == GpiType) {
> + //
> + // Check if same GPIO pad is the source of this SMI
> + //
> + if (RecordInDb->ChildContext.Gpi.GpiNum ==
> RecordToDelete->ChildContext.Gpi.GpiNum) {
> + DisableGpiSmiSource = FALSE;
> + break;
> + }
> + }
> + }
> +
> + if (DisableGpiSmiSource) {
> + GpioGetPadAndSmiRegs (
> + (UINT32) RecordToDelete->ChildContext.Gpi.GpiNum,
> + &GpioPad,
> + &GpiSmiBitOffset,
> + &GpiHostSwOwnRegAddress,
> + &GpiSmiStsRegAddress
> + );
> +
> + Data32Or = 1u << GpiSmiBitOffset;
> + Data32And = 0xFFFFFFFF;
> + MmioOr32 (GpiHostSwOwnRegAddress, Data32Or);
> + S3BootScriptSaveMemReadWrite (S3BootScriptWidthUint32,
> GpiHostSwOwnRegAddress, &Data32Or, &Data32And);
> + }
> +
> +
> + RemoveEntryList (&RecordToDelete->Link);
> + ZeroMem (RecordToDelete, sizeof (DATABASE_RECORD));
> + Status = 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. <BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "PchSmmHelpers.h"
> +#include <Register/PchRegsPmc.h>
> +#include <Register/PchRegsPcr.h>
> +#include <Register/PchRegsItss.h>
> +#include <Private/Library/PmcPrivateLib.h>
> +
> +///
> +/// #define BIT_ZERO 0x00000001
> +///
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT32 BIT_ZERO =
> 0x00000001;
> +
> +///
> +/// SUPPORT / HELPER FUNCTIONS (PCH version-independent)
> +///
> +
> +/**
> + Compare 2 SMM source descriptors' enable settings.
> +
> + @param[in] Src1 Pointer to the PCH SMI source description
> table 1
> + @param[in] Src2 Pointer to the PCH SMI source description
> table 2
> +
> + @retval TRUE The enable settings of the 2 SMM source
> descriptors are identical.
> + @retval FALSE The enable settings of the 2 SMM source
> 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 = TRUE;
> + for (DescIndex = 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 result.
> + ///
> + if (Src1->En[DescIndex].Bit != Src2->En[DescIndex].Bit ||
> + Src1->En[DescIndex].Reg.Type != Src2->En[DescIndex].Reg.Type ||
> + Src1->En[DescIndex].Reg.Data.raw !=
> Src2->En[DescIndex].Reg.Data.raw
> + ) {
> + IsEqual = 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 description
> table 2
> +
> + @retval TRUE The bit desc is equal to any of the enables in
> source descriptor
> + @retval FALSE The bid desc is not equal to all of the 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 = FALSE;
> +
> + for (DescIndex = 0; DescIndex < NUM_EN_BITS; ++DescIndex) {
> + if ((BitDesc->Reg.Type == Src->En[DescIndex].Reg.Type) &&
> + (BitDesc->Reg.Data.raw == Src->En[DescIndex].Reg.Data.raw) &&
> + (BitDesc->Bit == Src->En[DescIndex].Bit)) {
> + IsEqual = TRUE;
> + break;
> + }
> + }
> + return IsEqual;
> +}
> +
> +/**
> + Compare 2 SMM source descriptors' statuses.
> +
> + @param[in] Src1 Pointer to the PCH SMI source description
> table 1
> + @param[in] Src2 Pointer to the PCH SMI source description
> table 2
> +
> + @retval TRUE The statuses of the 2 SMM source descriptors
> are identical.
> + @retval FALSE The statuses of the 2 SMM source descriptors
> are not identical.
> +**/
> +BOOLEAN
> +CompareStatuses (
> + CONST IN PCH_SMM_SOURCE_DESC *Src1,
> + CONST IN PCH_SMM_SOURCE_DESC *Src2
> + )
> +{
> + BOOLEAN IsEqual;
> + UINTN DescIndex;
> +
> + IsEqual = TRUE;
> +
> + for (DescIndex = 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 result.
> + ///
> + if (Src1->Sts[DescIndex].Bit != Src2->Sts[DescIndex].Bit ||
> + Src1->Sts[DescIndex].Reg.Type != Src2->Sts[DescIndex].Reg.Type ||
> + Src1->Sts[DescIndex].Reg.Data.raw !=
> Src2->Sts[DescIndex].Reg.Data.raw
> + ) {
> + IsEqual = 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 description
> table 1
> + @param[in] Src2 Pointer to the PCH SMI source description
> table 2
> +
> + @retval TRUE The 2 SMM source descriptors are identical.
> + @retval FALSE The 2 SMM source descriptors are not identical.
> +**/
> +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 description
> 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 == 1. An ACPI OS is present,
> + /// so we shouldn't do anything w/ this source until SciEn == 0.
> + ///
> + if ((Src->Flags == 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 == ACPI_ADDR_TYPE) &&
> + (Src->PmcSmiSts.Reg.Data.acpi == R_ACPI_IO_SMI_STS) &&
> + ((SmiStsValue & (1u << Src->PmcSmiSts.Bit)) == 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 == PID_ITSS) &&
> + (Src->En[0].Reg.Data.Pcr.Fields.Offset == R_ITSS_PCR_NMI))
> + {
> + UINT32 ItssNmi;
> + ItssNmi = 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 = 0; DescIndex < NUM_EN_BITS; DescIndex++) {
> + if (!IS_BIT_DESC_NULL (Src->En[DescIndex])) {
> + if ((Src->En[DescIndex].Reg.Type == ACPI_ADDR_TYPE) &&
> + (Src->En[DescIndex].Reg.Data.acpi == R_ACPI_IO_SMI_EN) &&
> + ((SmiEnValue & (1u << Src->En[DescIndex].Bit)) == 0)) {
> + return FALSE;
> + } else if (ReadBitDesc (&Src->En[DescIndex]) == 0) {
> + return FALSE;
> + }
> + }
> + }
> +
> + ///
> + /// Read each bit desc from hardware and make sure it's a one
> + ///
> + for (DescIndex = 0; DescIndex < NUM_STS_BITS; DescIndex++) {
> + if (!IS_BIT_DESC_NULL (Src->Sts[DescIndex])) {
> + if ((Src->Sts[DescIndex].Reg.Type == ACPI_ADDR_TYPE) &&
> + (Src->Sts[DescIndex].Reg.Data.acpi == R_ACPI_IO_SMI_STS) &&
> + ((SmiStsValue & (1u << Src->Sts[DescIndex].Bit)) == 0)) {
> + return FALSE;
> + } else if (ReadBitDesc (&Src->Sts[DescIndex]) == 0) {
> + return FALSE;
> + }
> + }
> + }
> +
> + return TRUE;
> +}
> +
> +/**
> + Enable the SMI source event by set the SMI enable bit, this function would
> also clear SMI
> + status bit to make initial state is correct
> +
> + @param[in] SrcDesc Pointer to the PCH SMI source description
> table
> +
> +**/
> +VOID
> +PchSmmEnableSource (
> + CONST PCH_SMM_SOURCE_DESC *SrcDesc
> + )
> +{
> + UINTN DescIndex;
> +
> + ///
> + /// Set enables to 1 by writing a 1
> + ///
> + for (DescIndex = 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 = 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 description
> table
> +
> +**/
> +VOID
> +PchSmmDisableSource (
> + CONST PCH_SMM_SOURCE_DESC *SrcDesc
> + )
> +{
> + UINTN DescIndex;
> +
> + for (DescIndex = 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 description
> table
> +
> +**/
> +VOID
> +PchSmmClearSource (
> + CONST PCH_SMM_SOURCE_DESC *SrcDesc
> + )
> +{
> + UINTN DescIndex;
> +
> + for (DescIndex = 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 description
> table
> +
> +**/
> +VOID
> +PchSmmClearSourceAndBlock (
> + CONST PCH_SMM_SOURCE_DESC *SrcDesc
> + )
> +{
> + UINTN DescIndex;
> + BOOLEAN IsSet;
> +
> + for (DescIndex = 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 = TRUE;
> + while (IsSet) {
> + IsSet = 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 Timer
> dispatch protocol.
> +
> + Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "PchSmmHelpers.h"
> +#include <Protocol/PchSmmPeriodicTimerControl.h>
> +#include <Private/Library/PmcPrivateLib.h>
> +
> +//
> +// 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= 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 = 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] = {
> + {
> + 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 now (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] = {
> + {
> + 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 = 0; loopvar < NUM_INTERVALS; loopvar++) {
> + if (((DispatchContext->PeriodicTimer.SmiTickInterval == 0) &&
> + (DispatchContext->PeriodicTimer.Period >=
> mSmmPeriodicTimerIntervals[loopvar].Interval)) ||
> + (DispatchContext->PeriodicTimer.SmiTickInterval ==
> 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 = ContextToTimerInterval (DispatchContext);
> + if (TimerInterval == 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 == PeriodicTimerType);
> +
> + TimerInterval = ContextToTimerInterval (&Record->ChildContext);
> + if (TimerInterval == 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 +=
> mTimers[TimerInterval->AssociatedTimer].MinReqInterval;
> + *HwContext = 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 = DATABASE_RECORD_FROM_CHILDCONTEXT (ChildContext);
> +
> + if (Record->MiscData.ElapsedTime >= ChildContext->PeriodicTimer.Period)
> {
> + ///
> + /// For EDKII, the ElapsedTime is reset when PeriodicTimerGetCommBuffer
> + ///
> + 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 == PeriodicTimerType);
> +
> + mPchPeriodicTimerCommBuffer.ElapsedTime =
> Record->MiscData.ElapsedTime;
> +
> + ///
> + /// For EDKII, the ElapsedTime is reset here
> + ///
> + Record->MiscData.ElapsedTime = 0;
> +
> + ///
> + /// Return the CommBuffer
> + ///
> + *CommBuffer = (VOID *) &mPchPeriodicTimerCommBuffer;
> + *CommBufferSize = 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 = 0; Timer < NUM_TIMERS; Timer++) {
> + mTimers[Timer].MinReqInterval = ~ (UINT64) 0x0;
> + mTimers[Timer].NumChildren = 0;
> + }
> +
> + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
> + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
> + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
> + if (RecordInDb->ProtocolType == PeriodicTimerType) {
> + ///
> + /// This child is registerd with the PeriodicTimer protocol
> + ///
> + TimerInterval = ContextToTimerInterval (&RecordInDb->ChildContext);
> + if (TimerInterval == NULL) {
> + return;
> + }
> +
> + Timer = TimerInterval->AssociatedTimer;
> + if (Timer < 0 || Timer >= NUM_TIMERS) {
> + ASSERT (FALSE);
> + CpuDeadLoop ();
> + return;
> + }
> +
> + if (mTimers[Timer].MinReqInterval >
> RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval) {
> + mTimers[Timer].MinReqInterval =
> RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval;
> + }
> +
> + mTimers[Timer].NumChildren++;
> + }
> +
> + LinkInDb = 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 = INDEX_TIME_64s;
> + break;
> +
> + case TIME_32s:
> + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate32s);
> + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32s;
> + break;
> +
> + case TIME_16s:
> + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate16s);
> + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16s;
> + break;
> +
> + case TIME_8s:
> + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate8s);
> + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_8s;
> + break;
> +
> + default:
> + ASSERT (FALSE);
> + break;
> + }
> +
> + ///
> + /// Restart the timer here, just need to clear the SMI
> + ///
> + if (SrcDesc->Sts[0].Bit == 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 = INDEX_TIME_64ms;
> + break;
> +
> + case TIME_32ms:
> + PmcSetSwSmiRate (PmcSwSmiRate32ms);
> + mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_32ms;
> + break;
> +
> + case TIME_16ms:
> + PmcSetSwSmiRate (PmcSwSmiRate16ms);
> + mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_16ms;
> + break;
> +
> + case TIME_1_5ms:
> + PmcSetSwSmiRate (PmcSwSmiRate1p5ms);
> + mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_1_5ms;
> + break;
> +
> + default:
> + ASSERT (FALSE);
> + break;
> + }
> +
> + ///
> + /// Restart the timer here, need to disable, clear, then enable to restart
> this timer
> + ///
> + if (SrcDesc->Sts[0].Bit == 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 the
> 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 == NULL) {
> + ASSERT(FALSE);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + IntervalPointer = (TIMER_INTERVAL *) *SmiTickInterval;
> +
> + if (IntervalPointer == NULL) {
> + ///
> + /// The first time child requesting an interval
> + ///
> + IntervalPointer = &mSmmPeriodicTimerIntervals[0];
> + } else if (IntervalPointer ==
> &mSmmPeriodicTimerIntervals[NUM_INTERVALS - 1]) {
> + ///
> + /// At end of the list
> + ///
> + IntervalPointer = NULL;
> + } else {
> + if ((IntervalPointer >= &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 != NULL) {
> + *SmiTickInterval = &IntervalPointer->Interval;
> + } else {
> + *SmiTickInterval = NULL;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is responsible for calculating and enabling any timers that 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 PeriodicTimer.
> + @retval FALSE The handle is not in type of PeriodicTimer.
> +**/
> +BOOLEAN
> +IsSmmPeriodicTimerHandle (
> + IN EFI_HANDLE DispatchHandle
> + )
> +{
> + DATABASE_RECORD *RecordInDb;
> + LIST_ENTRY *LinkInDb;
> +
> + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
> + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
> + if (DispatchHandle == (EFI_HANDLE) LinkInDb) {
> + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
> + if (RecordInDb->ProtocolType == PeriodicTimerType) {
> + return TRUE;
> + }
> + }
> + LinkInDb = 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) == FALSE) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + RecordInDb = DATABASE_RECORD_FROM_LINK (DispatchHandle);
> + TimerInterval = NULL;
> + TimerInterval = ContextToTimerInterval (&RecordInDb->ChildContext);
> + if (TimerInterval == 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) == FALSE) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + RecordInDb = DATABASE_RECORD_FROM_LINK (DispatchHandle);
> + TimerInterval = NULL;
> + TimerInterval = ContextToTimerInterval (&RecordInDb->ChildContext);
> + if (TimerInterval == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> + PchSmmEnableSource
> (&mTimerSourceDesc[TimerInterval->AssociatedTimer]);
> + return EFI_SUCCESS;
> +}
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED
> PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL
> mPchSmmPeriodicTimerControlProtocol = {
> + 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 = 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 Button
> dispatch protocol.
> +
> + Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <PchSmmHelpers.h>
> +#include <Private/Library/PmcPrivateLib.h>
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mPowerButtonSourceDesc = {
> + 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, will 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 = EfiPowerButtonExit;
> + } else {
> + Context->PowerButton.Phase = EfiPowerButtonEntry;
> + }
> +}
> +
> +/**
> + Check whether Power Button status of two contexts match
> +
> + @param[in] Context1 Context 1 that includes Power Button status
> 1
> + @param[in] Context2 Context 2 that includes Power Button status
> 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 ==
> 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 dispatch
> protocol.
> +
> + Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "PchSmmHelpers.h"
> +#include <Protocol/SmmCpu.h>
> +#include <Register/PchRegsLpc.h>
> +#include <Register/PchRegsPmc.h>
> +
> +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 = {
> + 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 = GetFirstNode (&mSwSmiCallbackDataBase);
> + while (!IsNull (&mSwSmiCallbackDataBase, LinkInDb)) {
> + SwSmiRecord = SW_SMI_RECORD_FROM_LINK (LinkInDb);
> + if (SwSmiRecord->Context.SwSmiInputValue == SwSmiInputValue) {
> + return EFI_INVALID_PARAMETER;
> + }
> + LinkInDb = GetNextNode (&mSwSmiCallbackDataBase,
> &SwSmiRecord->Link);
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Register a child SMI source dispatch function for the specified software SMI.
> +
> + This service registers a function (DispatchFunction) which will be called
> 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 before calling
> + the register function to indicate to the register
> + function which Software SMI input value the
> + dispatch function should be invoked for.
> + @param[out] DispatchHandle Handle generated by the dispatcher to
> track the
> + function instance.
> +
> + @retval EFI_SUCCESS The dispatch function has been successfully
> + 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 already 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 == 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 == (UINTN) -1) {
> + for (Index = 1; Index < MAXIMUM_SWI_VALUE; Index++) {
> + Status = SmiInputValueDuplicateCheck (Index);
> + if (!EFI_ERROR (Status)) {
> + DispatchContext->SwSmiInputValue = Index;
> + break;
> + }
> + }
> + if (DispatchContext->SwSmiInputValue == (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 protocol.
> + //
> + if (DispatchContext->SwSmiInputValue >= MAXIMUM_SWI_VALUE) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Status = SmiInputValueDuplicateCheck
> (DispatchContext->SwSmiInputValue);
> + if (EFI_ERROR (Status)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + //
> + // Create database record and add to database
> + //
> + Status = 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 = SW_SMI_RECORD_SIGNATURE;
> + SwSmiRecord->Context.SwSmiInputValue =
> DispatchContext->SwSmiInputValue;
> + SwSmiRecord->Callback = 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 = (EFI_HANDLE) (&SwSmiRecord->Link);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Unregister a child SMI source dispatch function for the specified software
> SMI.
> +
> + This service removes the handler associated with DispatchHandle so that 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 deregister.
> +
> + @retval EFI_SUCCESS The dispatch function has been successfully
> 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 == 0) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + //
> + // Return access denied if the SmmReadyToLock event has been triggered
> + //
> + if (mReadyToLock == TRUE) {
> + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the
> SmmReadyToLock event has been triggered! \n"));
> + return EFI_ACCESS_DENIED;
> + }
> +
> + RecordToDelete = SW_SMI_RECORD_FROM_LINK (DispatchHandle);
> + //
> + // Take the entry out of the linked list
> + //
> + if (RecordToDelete->Signature != SW_SMI_RECORD_SIGNATURE) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + RemoveEntryList (&RecordToDelete->Link);
> + ZeroMem (RecordToDelete, sizeof (SW_SMI_RECORD));
> + Status = 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 which
> 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 = 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 = IoRead8 (R_PCH_IO_APM_STS);
> +
> + for (CpuIndex = 0; CpuIndex < gSmst->NumberOfCpus; CpuIndex++) {
> + Status = 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 (0xB2)",
> skip it.
> + //
> + if ((SmiIoInfo.IoPort != R_PCH_IO_APM_CNT) ||
> + (SmiIoInfo.IoType != EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT) ||
> + (SmiIoInfo.IoWidth != EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8))
> + {
> + continue;
> + }
> + //
> + // If the IO data is used for SmmControl protocol, skip it.
> + //
> + if (SmiIoInfo.IoData == 0xFF) {
> + continue;
> + }
> +
> + SwSmiCommBuffer.SwSmiCpuIndex = CpuIndex;
> + SwSmiCommBuffer.CommandPort = (UINT8) SmiIoInfo.IoData;
> +
> + LinkInDb = GetFirstNode (&mSwSmiCallbackDataBase);
> + while (!IsNull (&mSwSmiCallbackDataBase, LinkInDb)) {
> + SwSmiRecord = SW_SMI_RECORD_FROM_LINK (LinkInDb);
> + if (SwSmiRecord->Context.SwSmiInputValue == SmiIoInfo.IoData) {
> + SwSmiRecord->Callback ((EFI_HANDLE) &SwSmiRecord->Link,
> &SwSmiRecord->Context, &SwSmiCommBuffer, &SwSmiCommBufferSize);
> + }
> + LinkInDb = 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 = 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 = DATABASE_RECORD_SIGNATURE;
> + Record.Callback = PchSwSmiDispatcher;
> + Record.ProtocolType = SwType;
> +
> + CopyMem (&Record.SrcDesc, &mSwSourceDesc, sizeof
> (PCH_SMM_SOURCE_DESC));
> +
> + DispatchHandle = NULL;
> + Status = 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 dispatch
> protocol.
> +
> + Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "PchSmmHelpers.h"
> +#include <Register/PchRegsPmc.h>
> +#include <Register/PchRegsPcie.h>
> +
> +#define PROGRESS_CODE_S3_SUSPEND_END PcdGet32
> (PcdProgressCodeS3SuspendEnd)
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSxSourceDesc = {
> + 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 = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT));
> +
> + ///
> + /// By design, the context phase will always be ENTRY
> + ///
> + Context->Sx.Phase = 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 = SxS0;
> + break;
> +
> + case V_ACPI_IO_PM1_CNT_S1:
> + Context->Sx.Type = SxS1;
> + break;
> +
> + case V_ACPI_IO_PM1_CNT_S3:
> + Context->Sx.Type = SxS3;
> + break;
> +
> + case V_ACPI_IO_PM1_CNT_S4:
> + Context->Sx.Type = SxS4;
> + break;
> +
> + case V_ACPI_IO_PM1_CNT_S5:
> + Context->Sx.Type = 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 == 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 set and
> would trigger another wake.
> +**/
> +VOID
> +ClearPcieSci (
> + VOID
> + )
> +{
> + UINT32 MaxPorts;
> + UINT32 RpIndex;
> + UINT64 RpBase;
> +
> + MaxPorts = GetPchMaxPciePortNum ();
> + for (RpIndex = 0; RpIndex < MaxPorts; RpIndex++) {
> + RpBase = PchPcieBase (RpIndex);
> + if (PciSegmentRead16 (RpBase + PCI_VENDOR_ID_OFFSET) != 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 operating
> system
> + tries to put the system to sleep, and then physically putting the system 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 = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT));
> +
> + ///
> + /// Record S3 suspend performance data
> + ///
> + if ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SLP_TYP) == 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 trigger the
> sleep
> + ///
> + Pm1Cnt |= 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) == V_ACPI_IO_PM1_CNT_S1)
> {
> + while (((IoRead16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_STS))) &
> B_ACPI_IO_PM1_STS_WAK) == 0x0);
> + } else {
> + CpuDeadLoop ();
> + }
> + ///
> + /// The system just went to sleep. If the sleep state was S1, then code
> execution will resume
> + /// here when the system wakes up.
> + ///
> + Pm1Cnt = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT));
> +
> + if ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) == 0) {
> + ///
> + /// An ACPI OS isn't present, clear the sleep information
> + ///
> + Pm1Cnt &= ~B_ACPI_IO_PM1_CNT_SLP_TYP;
> + Pm1Cnt |= 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 dispatch
> protocol.
> +
> + Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "PchSmmHelpers.h"
> +#include <Register/RegsUsb.h>
> +#include <Register/PchRegsLpc.h>
> +#include <Register/PchRegsPmc.h>
> +
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mUsb1Legacy = {
> + 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 = {
> + 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 = 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[] = {
> + {
> + 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 find
> any match USB device path
> + PCH_USB_CONTROLLER_TYPE The USB controller
> 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 = DevicePath;
> + Status = gBS->LocateDevicePath (
> + &gEfiPciRootBridgeIoProtocolGuid,
> + &DevicePath,
> + &DeviceHandle
> + );
> + if (EFI_ERROR (Status)) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + DevicePath = RemaingDevicePath;
> +
> + ///
> + /// Get first node: Acpi Node
> + ///
> + AcpiNode = (ACPI_HID_DEVICE_PATH *) RemaingDevicePath;
> +
> + if (AcpiNode->Header.Type != ACPI_DEVICE_PATH ||
> + AcpiNode->Header.SubType != ACPI_DP ||
> + DevicePathNodeLength (&AcpiNode->Header) != sizeof
> (ACPI_HID_DEVICE_PATH) ||
> + AcpiNode->HID != EISA_PNP_ID (0x0A03) ||
> + AcpiNode->UID != 0
> + ) {
> + return EFI_UNSUPPORTED;
> + } else {
> + ///
> + /// Get the next node: Pci Node
> + ///
> + RemaingDevicePath = NextDevicePathNode (RemaingDevicePath);
> + PciNode = (PCI_DEVICE_PATH *) RemaingDevicePath;
> + if (PciNode->Header.Type != HARDWARE_DEVICE_PATH ||
> + PciNode->Header.SubType != HW_PCI_DP ||
> + DevicePathNodeLength (&PciNode->Header) != sizeof
> (PCI_DEVICE_PATH)
> + ) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + for (UsbIndex = 0; UsbIndex < sizeof (mUsbControllersMap) / sizeof
> (USB_CONTROLLER); UsbIndex++) {
> + if ((PciNode->Device == mUsbControllersMap[UsbIndex].Device) &&
> + (PciNode->Function == mUsbControllersMap[UsbIndex].Function)) {
> + *Controller = 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 corresponds 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 = 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. <BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "PchSmmHelpers.h"
> +#include <Register/PchRegs.h>
> +#include <Register/PchRegsPmc.h>
> +
> +//
> +// Help handle porting bit shifts to IA-64.
> +//
> +#define BIT_ZERO 0x00000001
> +
> +/**
> + Publish SMI Dispatch protocols.
> +
> +
> +**/
> +VOID
> +PchSmmPublishDispatchProtocols (
> + VOID
> + )
> +{
> + EFI_STATUS Status = EFI_SUCCESS;
> + UINTN Index;
> + //
> + // Install protocol interfaces.
> + //
> + for (Index = 0; Index < PCH_SMM_PROTOCOL_TYPE_MAX; Index++) {
> + Status = 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 successfully.
> +**/
> +EFI_STATUS
> +PchSmmInitHardware (
> + VOID
> + )
> +{
> + EFI_STATUS Status;
> +
> + //
> + // Clear all SMIs
> + //
> + PchSmmClearSmi ();
> +
> + Status = 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 = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN));
> +
> + //
> + // Set the "global smi enable" bit
> + //
> + SmiEn |= 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 = 0;
> + //
> + // Determine whether an ACPI OS is present (via the SCI_EN bit)
> + //
> + Pm1Cnt = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT));
> + SciEn = (BOOLEAN) ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) ==
> B_ACPI_IO_PM1_CNT_SCI_EN);
> + if (!SciEn) {
> + //
> + // Clear any SMIs that double as SCIs (when SCI_EN==0)
> + //
> + Pm1Sts = IoRead16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_STS));
> + Gpe0Sts = IoRead32 ((UINTN) (mAcpiBaseAddr +
> R_ACPI_IO_GPE0_STS_127_96));
> +
> + Pm1Sts |=
> + (
> + 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 &= (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 = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_STS));
> + DevActSts = IoRead16 ((UINTN) (mAcpiBaseAddr +
> R_ACPI_IO_DEVACT_STS));
> + Tco1Sts = IoRead16 ((UINTN) (mTcoBaseAddr + R_TCO_IO_TCO1_STS));
> +
> + SmiSts |=
> + (
> + 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 |=
> + (
> + 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 |=
> + (
> + 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 = 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 error
> + @retval TRUE EOS was correctly set to a 1
> +**/
> +BOOLEAN
> +PchSmmSetAndCheckEos (
> + VOID
> + )
> +{
> + UINT32 SmiEn;
> +
> + SmiEn = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN));
> +
> + //
> + // Reset the PCH to generate subsequent SMIs
> + //
> + SmiEn |= B_ACPI_IO_SMI_EN_EOS;
> +
> + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN), SmiEn);
> +
> + //
> + // Double check that the assert worked
> + //
> + SmiEn = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN));
> +
> + //
> + // Return TRUE if EOS is set correctly
> + //
> + if ((SmiEn & B_ACPI_IO_SMI_EN_EOS) == 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 = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT));
> + SciEn = (BOOLEAN) ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) ==
> 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 address, 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 != NULL);
> + ASSERT (!IS_BIT_DESC_NULL (*BitDesc));
> +
> + RegSize = 0;
> + Register = 0;
> + ShiftCount = 0;
> + BitWasOne = FALSE;
> +
> + switch (BitDesc->Reg.Type) {
> +
> + case ACPI_ADDR_TYPE:
> + case TCO_ADDR_TYPE:
> + if (BitDesc->Reg.Type == ACPI_ADDR_TYPE) {
> + RegisterOffset = BitDesc->Reg.Data.acpi;
> + BaseAddr = mAcpiBaseAddr;
> + } else {
> + RegisterOffset = BitDesc->Reg.Data.tco;
> + BaseAddr = 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 = SMM_IO_UINT8;
> + break;
> +
> + case 2:
> + RegSize = SMM_IO_UINT16;
> + break;
> +
> + case 4:
> + RegSize = SMM_IO_UINT32;
> + break;
> +
> + case 8:
> + RegSize = 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 != 0x0) && ((BaseAddr & 0x1) != 0x1));
> +
> + ShiftCount = 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 == SMM_IO_UINT64) {
> + RegSize = SMM_IO_UINT32;
> + //
> + // If the operation is for high 32 bits
> + //
> + if (BitDesc->Bit >= 32) {
> + RegisterOffset += 4;
> + ShiftCount -= 32;
> + }
> + }
> +
> + Status = gSmst->SmmIo.Io.Read (
> + &gSmst->SmmIo,
> + RegSize,
> + BaseAddr + RegisterOffset,
> + 1,
> + &Register
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + if ((Register & (LShiftU64 (BIT_ZERO, ShiftCount))) != 0) {
> + BitWasOne = TRUE;
> + } else {
> + BitWasOne = 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 = (UINT64) MmioRead8 ((UINTN) BitDesc->Reg.Data.Mmio);
> + break;
> +
> + case 2:
> + Register = (UINT64) MmioRead16 ((UINTN) BitDesc->Reg.Data.Mmio);
> + break;
> +
> + case 4:
> + Register = (UINT64) MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio);
> + break;
> +
> + case 8:
> + Register = (UINT64) MmioRead32 ((UINTN)
> BitDesc->Reg.Data.Mmio);
> + *((UINT32 *) (&Register) + 1) = MmioRead32 ((UINTN)
> BitDesc->Reg.Data.Mmio + 4);
> + break;
> +
> + default:
> + //
> + // Unsupported or invalid register size
> + //
> + ASSERT (FALSE);
> + break;
> + }
> +
> + Register = Register & (LShiftU64 (BIT0, BitDesc->Bit));
> + if (Register) {
> + BitWasOne = TRUE;
> + } else {
> + BitWasOne = FALSE;
> + }
> + break;
> +
> + case PCIE_ADDR_TYPE:
> + PciBus = BitDesc->Reg.Data.pcie.Fields.Bus;
> + PciDev = BitDesc->Reg.Data.pcie.Fields.Dev;
> + PciFun = BitDesc->Reg.Data.pcie.Fields.Fnc;
> + PciReg = BitDesc->Reg.Data.pcie.Fields.Reg;
> + PciBaseAddress = 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 = (UINT64) PciSegmentRead8 (PciBaseAddress + PciReg);
> + break;
> +
> + case 2:
> + Register = (UINT64) PciSegmentRead16 (PciBaseAddress + PciReg);
> + break;
> +
> + case 4:
> + Register = (UINT64) PciSegmentRead32 (PciBaseAddress + PciReg);
> + break;
> +
> + default:
> + //
> + // Unsupported or invalid register size
> + //
> + ASSERT (FALSE);
> + break;
> + }
> +
> + if ((Register & (LShiftU64 (BIT_ZERO, BitDesc->Bit))) != 0) {
> + BitWasOne = TRUE;
> + } else {
> + BitWasOne = FALSE;
> + }
> + break;
> +
> + case PCR_ADDR_TYPE:
> + //
> + // Read the register, and it with the bit to read
> + //
> + switch (BitDesc->SizeInBytes) {
> + case 1:
> + Register = PchPcrRead8 (BitDesc->Reg.Data.Pcr.Fields.Pid,
> BitDesc->Reg.Data.Pcr.Fields.Offset);
> + break;
> +
> + case 2:
> + Register = PchPcrRead16 (BitDesc->Reg.Data.Pcr.Fields.Pid,
> BitDesc->Reg.Data.Pcr.Fields.Offset);
> + break;
> +
> + case 4:
> + Register = PchPcrRead32 (BitDesc->Reg.Data.Pcr.Fields.Pid,
> BitDesc->Reg.Data.Pcr.Fields.Offset);
> + break;
> +
> + default:
> + //
> + // Unsupported or invalid register size
> + //
> + ASSERT (FALSE);
> + break;
> + }
> +
> + Register = Register & (LShiftU64 (BIT0, BitDesc->Bit));
> + if (Register) {
> + BitWasOne = TRUE;
> + } else {
> + BitWasOne = 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 address, 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 write 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 != NULL);
> + ASSERT (!IS_BIT_DESC_NULL (*BitDesc));
> +
> + RegSize = 0;
> + Register = 0;
> +
> + if (WriteClear) {
> + AndVal = LShiftU64 (BIT_ZERO, BitDesc->Bit);
> + } else {
> + AndVal = ~(LShiftU64 (BIT_ZERO, BitDesc->Bit));
> + }
> +
> + OrVal = (LShiftU64 ((UINT32) ValueToWrite, BitDesc->Bit));
> +
> + switch (BitDesc->Reg.Type) {
> +
> + case ACPI_ADDR_TYPE:
> + case TCO_ADDR_TYPE:
> + if (BitDesc->Reg.Type == ACPI_ADDR_TYPE) {
> + RegisterOffset = BitDesc->Reg.Data.acpi;
> + BaseAddr = mAcpiBaseAddr;
> + } else {
> + RegisterOffset = BitDesc->Reg.Data.tco;
> + BaseAddr = 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 = SMM_IO_UINT8;
> + break;
> +
> + case 2:
> + RegSize = SMM_IO_UINT16;
> + break;
> +
> + case 4:
> + RegSize = SMM_IO_UINT32;
> + break;
> +
> + case 8:
> + RegSize = 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 != 0x0) && ((BaseAddr & 0x1) != 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 == SMM_IO_UINT64) {
> + RegSize = SMM_IO_UINT32;
> + //
> + // If the operation is for high 32 bits
> + //
> + if (BitDesc->Bit >= 32) {
> + RegisterOffset += 4;
> +
> + if (WriteClear) {
> + AndVal = LShiftU64 (BIT_ZERO, BitDesc->Bit - 32);
> + } else {
> + AndVal = ~(LShiftU64 (BIT_ZERO, BitDesc->Bit - 32));
> + }
> +
> + OrVal = LShiftU64 ((UINT32) ValueToWrite, BitDesc->Bit - 32);
> + }
> + }
> +
> + Status = gSmst->SmmIo.Io.Read (
> + &gSmst->SmmIo,
> + RegSize,
> + BaseAddr + RegisterOffset,
> + 1,
> + &Register
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + Register &= AndVal;
> + Register |= OrVal;
> +
> + Status = 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 back.
> + //
> + 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 = (UINT64) MmioRead32 ((UINTN)
> BitDesc->Reg.Data.Mmio);
> + *((UINT32 *) (&Register) + 1) = MmioRead32 ((UINTN)
> BitDesc->Reg.Data.Mmio + 4);
> + Register &= AndVal;
> + Register |= 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 = BitDesc->Reg.Data.pcie.Fields.Bus;
> + PciDev = BitDesc->Reg.Data.pcie.Fields.Dev;
> + PciFun = BitDesc->Reg.Data.pcie.Fields.Fnc;
> + PciReg = BitDesc->Reg.Data.pcie.Fields.Reg;
> + PciBaseAddress = 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) AndVal,
> (UINT16) OrVal);
> + break;
> +
> + case 4:
> + PciSegmentAndThenOr32 (PciBaseAddress + PciReg, (UINT32) AndVal,
> (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 back.
> + //
> + 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
next prev parent reply other threads:[~2019-08-17 1:15 UTC|newest]
Thread overview: 121+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-08-17 0:15 [edk2-platforms][PATCH V1 00/37] Coffee Lake and Whiskey Lake support Kubacki, Michael A
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 01/37] CoffeelakeSiliconPkg: Add package and Include headers Kubacki, Michael A
2019-08-17 0:51 ` Nate DeSimone
2019-08-17 1:08 ` Chiu, Chasel
2019-08-17 1:18 ` Chaganty, Rangasai V
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 02/37] CoffeelakeSiliconPkg/Cpu: Add " Kubacki, Michael A
2019-08-17 0:51 ` Nate DeSimone
2019-08-17 1:08 ` Chiu, Chasel
2019-08-17 6:58 ` Chaganty, Rangasai V
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 03/37] CoffeelakeSiliconPkg/Me: " Kubacki, Michael A
2019-08-17 0:51 ` Nate DeSimone
2019-08-17 1:08 ` Chiu, Chasel
2019-08-17 7:04 ` Chaganty, Rangasai V
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 04/37] CoffeelakeSiliconPkg/Pch: Add include headers Kubacki, Michael A
2019-08-17 0:51 ` Nate DeSimone
2019-08-17 1:08 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 05/37] CoffeelakeSiliconPkg/Pch: Add ConfigBlock headers Kubacki, Michael A
2019-08-17 0:51 ` Nate DeSimone
2019-08-17 1:09 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 06/37] CoffeelakeSiliconPkg/Pch: Add Library include headers Kubacki, Michael A
2019-08-17 0:51 ` Nate DeSimone
2019-08-17 1:09 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 07/37] CoffeelakeSiliconPkg/Pch: Add PPI and Protocol " Kubacki, Michael A
2019-08-17 0:51 ` Nate DeSimone
2019-08-17 1:09 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 08/37] CoffeelakeSiliconPkg/Pch: Add Register " Kubacki, Michael A
2019-08-17 0:51 ` Nate DeSimone
2019-08-17 1:09 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 09/37] CoffeelakeSiliconPkg/Pch: Add Private " Kubacki, Michael A
2019-08-17 0:51 ` Nate DeSimone
2019-08-17 1:12 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 10/37] CoffeelakeSiliconPkg/Pch: Add Private/Library " Kubacki, Michael A
2019-08-17 0:52 ` Nate DeSimone
2019-08-17 1:09 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 11/37] CoffeelakeSiliconPkg/Pch: Add Private/Protocol " Kubacki, Michael A
2019-08-17 0:51 ` Nate DeSimone
2019-08-17 1:10 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 12/37] CoffeelakeSiliconPkg/SampleCode: Add Include headers Kubacki, Michael A
2019-08-17 0:52 ` Nate DeSimone
2019-08-17 1:12 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 13/37] CoffeelakeSiliconPkg/SystemAgent: " Kubacki, Michael A
2019-08-17 0:52 ` Nate DeSimone
2019-08-17 1:12 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 14/37] CoffeelakeSiliconPkg: Add package common library instances Kubacki, Michael A
2019-08-17 0:52 ` Nate DeSimone
2019-08-17 1:12 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 15/37] CoffeelakeSiliconPkg/Cpu: Add " Kubacki, Michael A
2019-08-17 0:52 ` Nate DeSimone
2019-08-17 1:15 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 16/37] CoffeelakeSiliconPkg/Me: " Kubacki, Michael A
2019-08-17 0:52 ` Nate DeSimone
2019-08-17 1:12 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 17/37] CoffeelakeSiliconPkg/Pch: Add Base " Kubacki, Michael A
2019-08-17 0:52 ` Nate DeSimone
2019-08-17 1:13 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 18/37] CoffeelakeSiliconPkg/Pch: Add DXE " Kubacki, Michael A
2019-08-17 0:52 ` Nate DeSimone
2019-08-17 1:13 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 19/37] CoffeelakeSiliconPkg/Pch: Add PEI " Kubacki, Michael A
2019-08-17 0:52 ` Nate DeSimone
2019-08-17 1:13 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 20/37] CoffeelakeSiliconPkg/Pch: Add SMM " Kubacki, Michael A
2019-08-17 0:53 ` Nate DeSimone
2019-08-17 1:16 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 21/37] CoffeelakeSiliconPkg/Pch: Add Base " Kubacki, Michael A
2019-08-17 0:52 ` Nate DeSimone
2019-08-17 1:13 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 22/37] CoffeelakeSiliconPkg/Pch: Add DXE private " Kubacki, Michael A
2019-08-17 0:52 ` Nate DeSimone
2019-08-17 1:13 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 23/37] CoffeelakeSiliconPkg/Pch: Add PEI " Kubacki, Michael A
2019-08-17 0:53 ` Nate DeSimone
2019-08-17 1:14 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 24/37] CoffeelakeSiliconPkg/Pch: Add SMM " Kubacki, Michael A
2019-08-17 0:53 ` Nate DeSimone
2019-08-17 1:14 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 25/37] CoffeelakeSiliconPkg/SystemAgent: Add " Kubacki, Michael A
2019-08-17 0:53 ` Nate DeSimone
2019-08-17 1:14 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 26/37] CoffeelakeSiliconPkg/Pch: Add modules Kubacki, Michael A
2019-08-17 0:53 ` Nate DeSimone
2019-08-17 1:14 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 27/37] CoffeelakeSiliconPkg/Pch: Add PchSmiDispatcher Kubacki, Michael A
2019-08-17 0:53 ` Nate DeSimone
2019-08-17 1:15 ` Chiu, Chasel [this message]
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 28/37] CoffeelakeSiliconPkg/SystemAgent: Add modules Kubacki, Michael A
2019-08-17 0:53 ` Nate DeSimone
2019-08-17 1:15 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 29/37] CoffeelakeSiliconPkg: Add package DSC files Kubacki, Michael A
2019-08-17 0:53 ` Nate DeSimone
2019-08-17 1:14 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 30/37] Maintainers.txt: Add CoffeelakeSiliconPkg maintainers Kubacki, Michael A
2019-08-17 0:53 ` Nate DeSimone
2019-08-17 1:15 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 31/37] WhiskeylakeOpenBoardPkg: Add package and headers Kubacki, Michael A
2019-08-17 0:54 ` Nate DeSimone
2019-08-17 1:16 ` Chiu, Chasel
2019-08-19 18:09 ` Sinha, Ankit
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 32/37] WhiskeylakeOpenBoardPkg/WhiskeylakeURvp: Add headers Kubacki, Michael A
2019-08-17 0:54 ` Nate DeSimone
2019-08-17 1:16 ` Chiu, Chasel
2019-08-17 0:15 ` [edk2-platforms][PATCH V1 33/37] WhiskeylakeOpenBoardPkg: Add library instances Kubacki, Michael A
2019-08-17 0:54 ` Nate DeSimone
2019-08-17 1:16 ` Chiu, Chasel
2019-08-17 0:16 ` [edk2-platforms][PATCH V1 34/37] WhiskeylakeOpenBoardPkg/WhiskeylakeURvp: " Kubacki, Michael A
2019-08-17 0:54 ` Nate DeSimone
2019-08-17 1:17 ` Chiu, Chasel
2019-08-17 20:08 ` Chaganty, Rangasai V
2019-08-17 0:16 ` [edk2-platforms][PATCH V1 35/37] WhiskeylakeOpenBoardPkg: Add modules Kubacki, Michael A
2019-08-17 0:54 ` Nate DeSimone
2019-08-17 1:17 ` Chiu, Chasel
2019-08-17 7:50 ` Chaganty, Rangasai V
2019-08-17 0:16 ` [edk2-platforms][PATCH V1 36/37] WhiskeylakeOpenBoardPkg/WhiskeylakeURvp: Add DSC and build files Kubacki, Michael A
2019-08-17 0:54 ` Nate DeSimone
2019-08-17 1:16 ` Chiu, Chasel
2019-08-17 20:11 ` Chaganty, Rangasai V
2019-08-17 0:16 ` [edk2-platforms][PATCH V1 37/37] Add WhiskeylakeOpenBoardPkg to global build config and documentation Kubacki, Michael A
2019-08-17 0:54 ` Nate DeSimone
2019-08-17 1:17 ` Chiu, Chasel
2019-08-17 20:00 ` Chaganty, Rangasai V
2019-08-19 18:14 ` [edk2-platforms][PATCH V1 00/37] Coffee Lake and Whiskey Lake support Sinha, Ankit
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3C3EFB470A303B4AB093197B6777CCEC504623EC@PGSMSX111.gar.corp.intel.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox