diff options
author | Guo Mang <mang.guo@intel.com> | 2016-12-23 13:07:00 +0800 |
---|---|---|
committer | Guo Mang <mang.guo@intel.com> | 2016-12-26 19:15:09 +0800 |
commit | fb9339ccebbb304a6fdaffcb95814dede3ef5f8a (patch) | |
tree | 6b5feab71e528d46cfbc98ceb755ffac491bb862 /Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci | |
parent | 387310c8dca74b9b92719242c35b08f36dc7336e (diff) | |
download | edk2-platforms-fb9339ccebbb304a6fdaffcb95814dede3ef5f8a.tar.xz |
BroxtonSiPkg: Add Heci
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Guo Mang <mang.guo@intel.com>
Diffstat (limited to 'Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci')
8 files changed, 2794 insertions, 0 deletions
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Dxe/Hecidrv.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Dxe/Hecidrv.c new file mode 100644 index 0000000000..bb98ae04b1 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Dxe/Hecidrv.c @@ -0,0 +1,340 @@ +/** @file
+ HECI driver.
+
+ Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Guid/EventGroup.h>
+#include "Hecidrv.h"
+#include <Private/Library/HeciInitLib.h>
+#include <ScRegs/RegsPcu.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/SideBandLib.h>
+
+extern DXE_SEC_POLICY_PROTOCOL *mDxePlatformSeCPolicy;
+
+EFI_HECI_PROTOCOL *mHeci2Protocol = NULL;
+
+HECI_INSTANCE *mHeciContext;
+EFI_HANDLE mHeciDrv;
+
+#define S_SEC_DevID_RANGE_LO_Test 0xA9A
+#define S_SEC_DevID_RANGE_HI_Test 0xA9E
+
+VOID
+EFIAPI
+FlashDeviceEndOfServicesEvent (
+ VOID
+ )
+{
+ EFI_PEI_HOB_POINTERS HobPtr;
+ MBP_CURRENT_BOOT_MEDIA *BootMediaData = NULL;
+
+ DEBUG ((EFI_D_INFO, "Begin - End of Services HECI Event\n"));
+
+ ASSERT_EFI_ERROR (mHeci2Protocol != NULL);
+
+ HobPtr.Guid = GetFirstGuidHob (&gEfiBootMediaHobGuid);
+ ASSERT (HobPtr.Guid != NULL);
+
+ BootMediaData = (MBP_CURRENT_BOOT_MEDIA *) GET_GUID_HOB_DATA (HobPtr.Guid);
+
+ //
+ // The Send Proxy State Message should not be sent on SPI boot
+ //
+ if (BootMediaData->PhysicalData != BOOT_FROM_SPI) {
+ Heci2GetProxyStateNoResp (mHeci2Protocol);
+ }
+
+ DEBUG ((EFI_D_INFO, "End - End of Services HECI Event\n"));
+}
+
+
+VOID
+EFIAPI
+FlashDeviceEndOfPostEvent (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG((EFI_D_INFO, "Begin - End of Post HECI Event\n"));
+
+ if (mHeci2Protocol == NULL) {
+ DEBUG ((EFI_D_INFO, "HECI Protocol %x\n", mHeci2Protocol));
+ Status = gBS->LocateProtocol (
+ &gEfiHeciSmmRuntimeProtocolGuid,
+ NULL,
+ &mHeci2Protocol
+ );
+ if (GetFirstGuidHob (&gFdoModeEnabledHobGuid) == NULL) {
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "End - End of Post HECI Event\n"));
+}
+
+
+/**
+ Notify the system of the End of Post message.
+
+**/
+VOID NotifyEOP (
+ VOID
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+
+ Handle = NULL;
+
+ Status = gBS->InstallProtocolInterface (
+ &Handle,
+ &gEfiCseEndofPostGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+
+ FlashDeviceEndOfPostEvent ();
+}
+
+
+/**
+ Notify the system send End of Services message.
+
+**/
+VOID NotifyEOS (
+ VOID
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+
+ Handle = NULL;
+
+ Status = gBS->InstallProtocolInterface (
+ &Handle,
+ &gEfiCseEndofServicesGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+
+ FlashDeviceEndOfServicesEvent ();
+}
+
+
+/**
+ CF9GR Lock Config.
+
+**/
+VOID
+LockConfig (
+ VOID
+ )
+{
+ UINT32 PmcBase;
+ UINT32 SecMode;
+ HECI_FWS_REGISTER SecFirmwareStatus;
+ UINT32 Data;
+
+ DEBUG ((DEBUG_INFO, "LockConfig () - Start\n"));
+
+ PmcBase = PMC_BASE_ADDRESS;
+
+ HeciGetSeCStatus (&SecMode);
+ SecFirmwareStatus.ul = HeciPciRead32 (R_SEC_FW_STS0);
+ DEBUG ((DEBUG_INFO, "SecFirmwareStatus.ul: 0x%X\n", SecFirmwareStatus.ul));
+
+ //
+ // APL/BXT IAFW Spec: Additional Power Management Programming
+ // Step 2
+ // Lock the "CF9h Global reset" field by setting CF9LOCK bit (PBASE + 0x48[31]) for production build,
+ // but this field should not be locked for manufacturing mode. When the Manufacturing Mode is closed,
+ // CF9h Global Reset should be cleared (step#1) and CF9LOCK bit should be set (step#2).
+ //
+ Data = 0;
+ if (((SecMode == SEC_MODE_NORMAL) || (SecMode == SEC_MODE_TEMP_DISABLED)) && !(SecFirmwareStatus.r.ManufacturingMode)) {
+ Data |= B_PMC_PMIR_CF9LOCK;
+ }
+
+ MmioAndThenOr32 (
+ (UINTN) (PmcBase + R_PMC_PMIR),
+ (UINT32) (~(B_PMC_PMIR_CF9LOCK | B_PMC_PMIR_CF9GR)),
+ (UINT32) Data
+ );
+
+ S3BootScriptSaveMemWrite (
+ EfiBootScriptWidthUint32,
+ (UINTN) (PmcBase + R_PMC_PMIR),
+ 1,
+ (VOID *) (UINTN) (PmcBase + R_PMC_PMIR)
+ );
+}
+
+
+/**
+ Event handle for Exit boot services.
+
+ @param[in] Event
+ @param[in] ParentImageHandle
+
+**/
+VOID
+EFIAPI
+SeCExitBootServicesEvent (
+ IN EFI_EVENT Event,
+ IN VOID *ParentImageHandle
+ )
+{
+ DEBUG ((EFI_D_INFO, "SeCExitBootServicesEvent ++\n"));
+ DEBUG ((EFI_D_INFO, "Start Send EOS Heci Message\n"));
+
+ HeciEndOfServices ();
+
+ DEBUG ((EFI_D_INFO, "End Of Send EOS Heci Message\n"));
+
+ NotifyEOS ();
+ gBS->CloseEvent (Event);
+
+ DEBUG ((EFI_D_INFO, "SeCExitBootServicesEvent --\n"));
+}
+
+
+/**
+ Event handle for ready to boot.
+
+ @param[in] Event
+ @param[in] ParentImageHandle
+
+**/
+VOID
+EFIAPI
+SeCReadyToBootEvent (
+ IN EFI_EVENT Event,
+ IN VOID *ParentImageHandle
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN SendEOP;
+
+ DEBUG ((EFI_D_INFO, "SeCReadyToBootEvent ++\n"));
+ SendEOP = TRUE;
+ Status = gBS->LocateProtocol (&gDxePlatformSeCPolicyGuid, NULL, (VOID **) &mDxePlatformSeCPolicy);
+ if (!EFI_ERROR (Status)) {
+ SendEOP = (mDxePlatformSeCPolicy->SeCConfig.EndOfPostEnabled == 1);
+ }
+ if (SendEOP) {
+ HeciEndOfPost ();
+ }
+
+ NotifyEOP ();
+ LockConfig ();
+
+ gBS->CloseEvent (Event);
+
+ DEBUG ((EFI_D_INFO, "SeCReadyToBootEvent --\n"));
+}
+
+
+/**
+ Entry point for HECI Driver.
+
+ @param[in] ImageHandle Standard entry point parameter.
+ @param[in] SystemTable Standard entry point parameter.
+
+ @retval EFI_SUCCESS Init success.
+ @retval Others Error occurs during HECI driver init.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeHECI (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT ReadyToBootEvent = NULL;
+ EFI_EVENT ExitBootServicesEvent = NULL;
+ EFI_EVENT EndOfDxeEvent = NULL;
+
+ DEBUG ((EFI_D_INFO, "InitializeHECI Driver Entry Point\n"));
+
+ Status = EfiCreateEventReadyToBootEx (
+ TPL_CALLBACK,
+ SeCReadyToBootEvent,
+ (VOID *) &ImageHandle,
+ &ReadyToBootEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ SeCExitBootServicesEvent,
+ NULL,
+ &gEfiEventExitBootServicesGuid,
+ &ExitBootServicesEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((EFI_D_INFO, "Registering the End of DXE done Call back in HECI ++\n"));
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ HeciDXECallback,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &EndOfDxeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((EFI_D_INFO, "InitializeHECI ++\n"));
+
+ mHeciDrv = ImageHandle;
+ mHeciContext = AllocateZeroPool (sizeof (HECI_INSTANCE));
+
+ //
+ // Initialize HECI protocol pointers
+ //
+ if (mHeciContext != NULL) {
+ mHeciContext->HeciCtlr.ResetHeci = ResetHeciInterface;
+ mHeciContext->HeciCtlr.SendwACK = HeciSendwACK;
+ mHeciContext->HeciCtlr.ReadMsg = HeciReceive;
+ mHeciContext->HeciCtlr.SendMsg = HeciSend;
+ mHeciContext->HeciCtlr.InitHeci = HeciInitialize;
+ mHeciContext->HeciCtlr.ReInitHeci = HeciReInitialize;
+ mHeciContext->HeciCtlr.SeCResetWait = SeCResetWait;
+ mHeciContext->HeciCtlr.GetSeCStatus = HeciGetSeCStatus;
+ mHeciContext->HeciCtlr.GetSeCMode = HeciGetSeCMode;
+ }
+
+ //
+ // Install the HECI interface
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHeciContext->Handle,
+ &gEfiHeciProtocolGuid,
+ &mHeciContext->HeciCtlr,
+ NULL
+ );
+ DEBUG ((EFI_D_INFO, "InitializeHECI --\n"));
+
+ //
+ // Disable the HECI3
+ //
+ SeCDeviceControl (HECI3_DEVICE, Disabled);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Dxe/Hecidrv.h b/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Dxe/Hecidrv.h new file mode 100644 index 0000000000..82aef2e02f --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Dxe/Hecidrv.h @@ -0,0 +1,60 @@ +/** @file
+ Header file for HECI driver.
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _HECI_DRV_H_
+#define _HECI_DRV_H_
+
+#include <SeCAccess.h>
+#include <HeciRegs.h>
+#include <IndustryStandard/Pci22.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PciLib.h>
+#include <Library/SeCLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/SeCPlatformPolicy.h>
+
+//
+// Driver Produced Protocol Prototypes
+//
+#include <Protocol/Heci.h>
+#include <Protocol/SeCRcInfo.h>
+#include <SeCAccess.h>
+#include <HeciRegs.h>
+
+#define HECI_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('H', 'e', 'c', 'i')
+#define HECI_ROUND_UP_BUFFER_LENGTH(Length) ((UINT32) ((((Length) + 3) / 4) * 4))
+
+//
+// HECI private data structure
+//
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ UINT32 HeciMBAR;
+ UINT32 HeciMBAR0;
+ UINT16 DeviceInfo;
+ UINT32 RevisionInfo;
+ EFI_HECI_PROTOCOL HeciCtlr;
+ volatile UINT32 *HpetTimer;
+ EFI_SEC_RC_INFO_PROTOCOL SeCRcInfo;
+} HECI_INSTANCE;
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Dxe/Hecidrv.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Dxe/Hecidrv.inf new file mode 100644 index 0000000000..ed65f9514e --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Dxe/Hecidrv.inf @@ -0,0 +1,67 @@ +## @file
+# HECI driver Module.
+#
+# Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = HeciDrv
+ FILE_GUID = 55E76644-78A5-4a82-A900-7126A5798892
+ VERSION_STRING = 1.0
+ MODULE_TYPE = DXE_DRIVER
+ ENTRY_POINT = InitializeHECI
+
+[Sources]
+ Hecidrv.c
+ Hecidrv.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ BroxtonSiPkg/BroxtonSiPkg.dec
+
+[LibraryClasses]
+ SeCLib
+ UefiBootServicesTableLib
+ DebugLib
+ PciLib
+ BaseLib
+ DxeServicesTableLib
+ MemoryAllocationLib
+ S3BootScriptLib
+ UefiDriverEntryPoint
+ HeciInitLib
+ HeciMsgLib
+ HobLib
+ MmPciLib
+ SeCChipsetLib
+ SideBandLib
+ PcdLib
+
+[Protocols]
+ gEfiHeciProtocolGuid ## CONSUMES
+ gEfiHeciSmmRuntimeProtocolGuid ## CONSUMES
+ gEfiSeCRcInfoProtocolGuid ## PRODUCES
+
+[Guids]
+ gEfiEventExitBootServicesGuid ## UNDEFINED
+ gEfiBootMediaHobGuid
+ gEfiCseEndofPostGuid
+ gEfiCseEndofServicesGuid
+ gEfiEndOfDxeEventGroupGuid
+ gFdoModeEnabledHobGuid
+
+[Pcd]
+ gEfiBxtTokenSpaceGuid.PcdPmcGcrBaseAddress
+
+[Depex]
+ gDxePlatformSeCPolicyGuid
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmm.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmm.c new file mode 100644 index 0000000000..0353ba7015 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmm.c @@ -0,0 +1,1373 @@ +/** @file
+ HECI Smm driver.
+
+ Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Protocol/SmmAccess2.h>
+#include <Protocol/SmmEndOfDxe.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/HeciMsgLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <HeciSmm.h>
+#include <Private/Library/HeciInitLib.h>
+#include <SeCAccess.h>
+#include <library/PciLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PerformanceLib.h>
+#include <Protocol/SmmSwDispatch2.h>
+#include <Protocol/Heci2Pm.h>
+
+UINT32 mHeci_Length = 0;
+UINT32 mHeci_LeftSize = 0;
+UINT32 mHeci_WriteSize = 0;
+UINT32 mHeci_SeCAddress = 0;
+UINT32 mHeci_HostAddress = 0;
+UINT32 mHeci_HeciBar = 0;
+UINT32 *mHeci_Message = NULL;
+BOOLEAN mHeci_Complete = TRUE;
+BOOLEAN mAtRuntime = FALSE;
+
+extern UINT32 mMonoCount;
+extern UINT8 mHmacSha256Key[32];
+
+/**
+ Disable HECI Interrupt.
+
+ **/
+VOID HeciDisableInterrupt (
+ VOID
+ );
+
+/**
+ Clear HECI Interrupt flag.
+
+ **/
+VOID HeciClearInterrupt (
+ VOID
+ );
+
+/**
+ Enabe HECI interrupt.
+
+ **/
+VOID HeciEnableInterrupt (
+ VOID
+ );
+
+/**
+ Heci Interrupt Handle
+
+**/
+
+VOID
+HeciInterruptHandle (
+ VOID
+ );
+
+/**
+ Receive Heci interrupt handle.
+
+ @param[in, out] Meesge
+ @param[in, out] Length
+
+ @retval Status
+
+ **/
+EFI_STATUS
+EFIAPI
+HeciReceiveInterrupt (
+ IN OUT UINT8 *Message,
+ IN OUT UINT32 *Length
+ );
+
+/**
+ Check is Heci Cse Response.
+
+ @retval Bool value
+
+ **/
+BOOLEAN
+IsHeciCseResponse (
+ VOID
+ );
+
+EFI_STATUS
+EfiHeciReadMessage (
+ IN HECI_DEVICE HeciDev,
+ IN UINT32 Blocking,
+ IN UINT32 *MessageBody,
+ IN OUT UINT32 *Length
+ );
+
+EFI_STATUS
+EFIAPI
+Heci2SendwACK (
+ IN OUT UINT32 *Message,
+ IN UINT32 Length,
+ IN OUT UINT32 *RecLength,
+ IN UINT8 HostAddress,
+ IN UINT8 SeCAddress
+ );
+
+BOOLEAN
+EFIAPI
+AtRuntime (
+ VOID
+ );
+
+/**
+ Send Power Gating message.
+
+ @retval Status
+
+ **/
+EFI_STATUS
+SendPGIEntry (
+ VOID
+ )
+{
+ UINT32 Size;
+ UINT32 MessageBody[20];
+ HECI_MESSAGE_HEADER MessageHeader;
+ volatile UINT32 *WriteBuffer;
+ volatile HECI_HOST_CONTROL_REGISTER *HostControlReg;
+ volatile HECI_SEC_CONTROL_REGISTER *SecControlReg;
+
+ HostControlReg = (volatile HECI_HOST_CONTROL_REGISTER *) (UINTN) (mHeci_HeciBar + H_CSR);
+ SecControlReg = (volatile HECI_SEC_CONTROL_REGISTER *) (UINTN) (mHeci_HeciBar + SEC_CSR_HA);
+ WriteBuffer = (UINT32 *) (UINTN) (mHeci_HeciBar + H_CB_WW);
+
+ //
+ // Prepare message header
+ //
+ MessageHeader.Data = 0x80040000;
+ MessageBody[0] = 0x0000000A;
+ *WriteBuffer = MessageHeader.Data;
+ *WriteBuffer = MessageBody[0];
+
+ //
+ // Send the Interrupt;
+ //
+ HostControlReg->r.H_IG = 1;
+
+ while (HostControlReg->r.H_IS == 0) {
+ MicroSecondDelay (10000);
+ }
+
+ while (!IsHeciCseResponse ()) {
+ MicroSecondDelay (10000);
+ }
+
+ HeciDisableInterrupt ();
+ HeciClearInterrupt ();
+
+ Size = sizeof (UINT32);
+ HeciReceiveInterrupt ((UINT8 *) &MessageBody, &Size);
+ ASSERT (MessageBody[0] == 0x0000008A);// retry
+
+ HeciEnableInterrupt ();
+
+ return EFI_SUCCESS;
+}
+
+
+BOOLEAN
+EFIAPI
+IsHeci2Idle (
+ VOID
+ )
+{
+ return (Mmio32 (mHeci_HeciBar, R_HECI_DEVIDLEC) & B_HECI_DEVIDLEC_DEVIDLE) == B_HECI_DEVIDLEC_DEVIDLE;
+}
+
+/**
+ Set HECI2 to idle (D0i3).
+
+ @params None.
+
+ @retval None.
+
+**/
+VOID
+EFIAPI
+SetHeci2Idle (
+ VOID
+ )
+{
+ //
+ // No need to continue if HECI2 is already in idle or in BIOS boot time, i.e., before ExitBootService.
+ // HECI2 should keep in Idle only in OS environment.
+ //
+ if (IsHeci2Idle() || !AtRuntime()) {
+ return;
+ }
+
+ DEBUG ((EFI_D_INFO, "SetHeci2Idle: HECI2 was active. Setting HECI2 to idle...\n"));
+
+ Mmio32 (mHeci_HeciBar, R_HECI_DEVIDLEC) = (B_HECI_DEVIDLEC_DEVIDLE | B_HECI_DEVIDLEC_IR);
+ while ((Mmio32 (mHeci_HeciBar, R_HECI_DEVIDLEC) & B_HECI_DEVIDLEC_CIP) == B_HECI_DEVIDLEC_CIP);
+}
+
+
+/**
+ Bring out HECI2 out of D0i3.
+
+ @params None.
+
+ @retval None.
+
+ **/
+VOID
+EFIAPI
+SetHeci2Active (
+ VOID
+ )
+{
+ volatile HECI_HOST_CONTROL_REGISTER *HostControlReg;
+
+ DEBUG ((EFI_D_INFO, "SetHeci2Active: Setting HECI2 to active...\n"));
+
+ HostControlReg = (volatile HECI_HOST_CONTROL_REGISTER *) (UINTN) (mHeci_HeciBar + H_CSR);
+
+ while ((Mmio32 (mHeci_HeciBar, R_HECI_DEVIDLEC) & B_HECI_DEVIDLEC_CIP) == B_HECI_DEVIDLEC_CIP);
+
+ if (!IsHeci2Idle ()) {
+ return;
+ }
+
+ Mmio32And (mHeci_HeciBar, R_HECI_DEVIDLEC, (UINT32) (~(B_HECI_DEVIDLEC_DEVIDLE | B_HECI_DEVIDLEC_RR)));
+
+ while ((Mmio32 (mHeci_HeciBar, R_HECI_DEVIDLEC) & B_HECI_DEVIDLEC_CIP) == B_HECI_DEVIDLEC_CIP);
+
+ //
+ // Clear interrupt status (if any).
+ //
+ if (HostControlReg->r.H_DEVIDLEC_IS == 1) {
+ HostControlReg->r.H_DEVIDLEC_IS = 1;
+ }
+
+ DEBUG ((EFI_D_INFO, "SetHeci2Active: HECI2 DEVIDLEC register value (should be active) = 0x%x.\n", Mmio32 (mHeci_HeciBar, R_HECI_DEVIDLEC)));
+}
+
+
+UINTN
+EFIAPI
+GetHeci2Bar (
+ VOID
+ )
+{
+ return mHeci_HeciBar;
+}
+
+
+VOID
+EFIAPI
+SetHeci2Bar (
+ UINTN Heci2Bar
+ )
+{
+ mHeci_HeciBar = (UINT32) Heci2Bar;
+}
+
+
+/**
+ Handle for send the Heci2 message.
+
+ @retval bool value
+
+ **/
+BOOLEAN HeciSendHandle (
+ VOID
+ )
+{
+ UINT32 MaxBuffer;
+ UINT32 Size;
+ UINTN Index;
+ UINT32 *MessageBody;
+ HECI_MESSAGE_HEADER MessageHeader;
+ volatile UINT32 *WriteBuffer;
+ volatile HECI_HOST_CONTROL_REGISTER *HostControlReg;
+ volatile HECI_SEC_CONTROL_REGISTER *SecControlReg;
+
+ if (mHeci_LeftSize == 0) {
+ return TRUE;
+ }
+ HostControlReg = (volatile HECI_HOST_CONTROL_REGISTER *) (UINTN) (mHeci_HeciBar + H_CSR);
+ SecControlReg = (volatile HECI_SEC_CONTROL_REGISTER *) (UINTN) (mHeci_HeciBar + SEC_CSR_HA);
+ WriteBuffer = (UINT32 *) (UINTN) (mHeci_HeciBar + H_CB_WW);
+ MessageBody = (UINT32*) mHeci_Message;
+
+ MaxBuffer = HostControlReg->r.H_CBD - 0x10;
+
+ while (mHeci_LeftSize > 0) {
+ Size = (mHeci_LeftSize > MaxBuffer) ? MaxBuffer : mHeci_LeftSize;
+ mHeci_LeftSize -= Size;
+ //
+ // Prepare message header
+ //
+ MessageHeader.Data = 0;
+ MessageHeader.Fields.SeCAddress = mHeci_SeCAddress;
+ MessageHeader.Fields.HostAddress = mHeci_HostAddress;
+ MessageHeader.Fields.MessageComplete = (mHeci_LeftSize > 0) ? 0 : 1;
+ MessageHeader.Fields.Length = (UINT32) ((mHeci_LeftSize > 0) ? Size * sizeof (UINT32) : mHeci_Length - mHeci_WriteSize * sizeof (UINT32));
+ *WriteBuffer = MessageHeader.Data;
+ for (Index = 0; Index < Size; Index ++) {
+ *WriteBuffer = MessageBody[Index + mHeci_WriteSize];
+ }
+ mHeci_WriteSize += Size;
+ //
+ // Send the Interrupt;
+ //
+ HostControlReg->r.H_IG = 1;
+
+ while (HostControlReg->r.H_IS == 0) {
+ MicroSecondDelay (10000);
+ }
+ }
+ HeciDisableInterrupt ();
+ HeciClearInterrupt ();
+ HeciEnableInterrupt ();
+
+ return (mHeci_LeftSize == 0);
+}
+
+UINT32 *CommandDataBuffer = NULL;
+UINTN CommandDataBufferSize = 0;
+UINTN CommandDataBufferHead = 0;
+UINTN CommandDataBufferTail = 0;
+UINT32 * CommandMessage = NULL;
+
+
+/**
+ Store Data into Queue.
+
+ @param[in] Data
+ @param[in] DataLength
+
+**/
+VOID
+InsertToQueue (
+ UINT32 * Data,
+ UINTN DataLength
+ )
+{
+ UINTN TempLength;
+
+ if (CommandDataBufferSize + CommandDataBufferTail - CommandDataBufferHead < DataLength) {
+ ASSERT (FALSE);
+ return;
+ }
+ if (CommandDataBufferHead + DataLength <= CommandDataBufferSize) {
+ CopyMem (&CommandDataBuffer[CommandDataBufferHead], Data, DataLength * sizeof (UINT32));
+ CommandDataBufferHead += DataLength;
+ CommandDataBufferHead %= CommandDataBufferSize;
+ } else {
+ TempLength = CommandDataBufferSize - CommandDataBufferHead;
+ InsertToQueue (Data, TempLength);
+ InsertToQueue (Data + TempLength, DataLength - TempLength);
+ }
+}
+
+
+/**
+ Get Data from Queue.
+
+ @param[in] Data
+ @param[in] DataLength
+
+**/
+VOID
+RemoveFromQueue (
+ UINT32 * Data,
+ UINTN DataLength
+ )
+{
+ UINTN TempLength;
+
+ if (CommandDataBufferTail + DataLength <= CommandDataBufferSize) {
+ CopyMem (Data, &CommandDataBuffer[CommandDataBufferTail], DataLength * sizeof (UINT32));
+ CommandDataBufferTail += DataLength;
+ CommandDataBufferTail %= CommandDataBufferSize;
+ } else {
+ TempLength = CommandDataBufferSize - CommandDataBufferTail;
+ RemoveFromQueue (Data, TempLength);
+ RemoveFromQueue (Data + TempLength, DataLength - TempLength);
+ }
+}
+
+
+/**
+ Init Heci Interrupt Buffer.
+
+**/
+VOID HeciInterruptInit (
+ VOID
+ )
+{
+ UINT32 TempHeciBar = 0;
+
+ TempHeciBar = Heci2PciRead32 (R_HECIMBAR0) & 0xFFFFFFF0;
+ if (TempHeciBar != 0xFFFFFFF0 ) { //No need to assign when the device is disabled
+ mHeci_HeciBar = TempHeciBar;
+ }
+ if (CommandDataBuffer != NULL) {
+ return;
+ }
+
+ CommandDataBuffer = AllocatePages (EFI_SIZE_TO_PAGES (MAX_HECI_BUFFER_SIZE) * 4);
+ CommandDataBufferSize = MAX_HECI_BUFFER_SIZE * 4 / sizeof (UINT32);
+ CommandMessage = AllocatePages (EFI_SIZE_TO_PAGES (MAX_HECI_BUFFER_SIZE));
+}
+
+
+/**
+ Store Command into buffer.
+
+ @param[in] Data
+ @param[in] DataLength
+ @param[in] MsgLength
+ @param[in] CseAddress
+ @param[in] HostAddress
+
+**/
+VOID StoreCommand (
+ IN UINT32 *Data,
+ IN UINT32 DataLength,
+ IN UINT32 MsgLength,
+ IN UINT32 CseAddress,
+ IN UINT32 HostAddress
+ )
+{
+ if (CommandDataBufferSize + CommandDataBufferTail - CommandDataBufferHead < (DataLength + 4)) {
+ ASSERT (FALSE);
+ }
+
+ InsertToQueue (&DataLength, 1);
+ InsertToQueue (&MsgLength, 1);
+ InsertToQueue (&CseAddress, 1);
+ InsertToQueue (&HostAddress, 1);
+ InsertToQueue (Data, DataLength);
+}
+
+
+/**
+ Load the next Command from buffer.
+
+ @param[in] DataSize
+ @param[in] MsgLength
+ @param[in] CseAddress
+ @param[in] HostAddress
+
+ @retval Data
+
+**/
+UINT32 *
+LoadCommand (
+ IN UINT32 *DataSize,
+ IN UINT32 *MsgLength,
+ IN UINT32 *CseAddress,
+ IN UINT32 *HostAddress
+ )
+{
+ UINT32 *Data;
+
+ if (CommandDataBuffer[CommandDataBufferTail] == (UINT32) -1) {
+ CommandDataBufferTail = 0;
+ }
+
+ RemoveFromQueue (DataSize, 1);
+ RemoveFromQueue (MsgLength, 1);
+ RemoveFromQueue (CseAddress, 1);
+ RemoveFromQueue (HostAddress, 1);
+ RemoveFromQueue (CommandMessage, *DataSize);
+ Data = CommandMessage;
+
+ return Data;
+}
+
+
+BOOLEAN mProxyStopPhase = FALSE;
+VOID CheckCommandQueue (
+ VOID
+ )
+{
+ if (CommandDataBufferHead == CommandDataBufferTail) {
+ return;
+ }
+ if (mHeci_LeftSize != 0) {
+ return;
+ }
+ if (!mHeci_Complete) {
+ return;
+ }
+ mHeci_Message = LoadCommand(&mHeci_LeftSize, &mHeci_Length, &mHeci_SeCAddress, &mHeci_HostAddress);
+ mHeci_WriteSize = 0;
+ mHeci_Complete = FALSE;
+ if (mProxyStopPhase) {
+ if (*((UINT8 *) mHeci_Message) == 4) {
+ HeciSendHandle ();
+ while (!mHeci_Complete) {
+ HeciInterruptHandle ();
+ MicroSecondDelay (10000);
+ }
+ }
+ } else {
+ HeciSendHandle ();
+ }
+}
+
+
+BOOLEAN mBlackHolePhase = FALSE;
+
+BOOLEAN InBXTBlackHolePhase (
+ )
+{
+ return mBlackHolePhase;
+}
+
+VOID CheckBXTBlackHole (
+ UINT8 *Data
+ )
+{
+ HECI2_BIOS_MASSAGE *Message;
+
+ Message = (HECI2_BIOS_MASSAGE *) Data;
+ if (Message->header.cmd_id == HECI2_GET_PROXY_STATE_CMD_ID) {
+ if (Message->header.req_resp == 0) {
+ mBlackHolePhase = TRUE;
+ } else {
+ mBlackHolePhase = FALSE;
+ }
+ }
+}
+
+
+/**
+ Interrupt Handle for HECI send message.
+
+ @param[in] Message
+ @param[in] Length
+ @param[in] HostAddress
+ @param[in] SeCAddress
+
+ @retval EFI_STATUS
+
+**/
+EFI_STATUS
+EFIAPI
+HeciSendInterrupt (
+ IN UINT8 *Message,
+ IN UINT32 Length,
+ IN UINT8 HostAddress,
+ IN UINT8 SeCAddress
+ )
+{
+ UINT32 LeftSize;
+
+ CheckBXTBlackHole (Message);
+
+ //
+ // The first DWORD used for send MessageHeader, so useable Buffer Size should Be MaxBuffer -1;
+ //
+ LeftSize = (Length + 3) / 4;
+
+ StoreCommand ((UINT32 *) Message, LeftSize, Length, SeCAddress, HostAddress);
+ CheckCommandQueue ();
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Interrupt Handle for HECI Receive message.
+
+ @param[in] Message
+ @param[in] Length
+
+ @retval EFI_STATUS
+
+**/
+EFI_STATUS
+EFIAPI
+HeciReceiveInterrupt (
+ IN OUT UINT8 *Message,
+ IN OUT UINT32 *Length
+ )
+{
+ UINTN ReadSize;
+ UINTN Size;
+ UINTN Index;
+ UINT32 *MessageBody;
+ UINT32 Data;
+ HECI_MESSAGE_HEADER MessageHeader;
+ volatile UINT32 *ReadBuffer;
+ volatile HECI_HOST_CONTROL_REGISTER *HostControlReg;
+ volatile HECI_SEC_CONTROL_REGISTER *SecControlReg;
+
+ HostControlReg = (volatile HECI_HOST_CONTROL_REGISTER *) (UINTN) (mHeci_HeciBar + H_CSR);
+ SecControlReg = (volatile HECI_SEC_CONTROL_REGISTER *) (UINTN) (mHeci_HeciBar + SEC_CSR_HA);
+ ReadBuffer = (UINT32 *) (UINTN) (mHeci_HeciBar + SEC_CB_RW);
+
+ Size = 0;
+ ReadSize = 0;
+ MessageBody = (UINT32 *) Message;
+
+ MessageHeader.Data = *ReadBuffer;
+ if (*Length > MessageHeader.Fields.Length) {
+ *Length = MessageHeader.Fields.Length;
+ }
+ for (Index = 0; Index < (*Length + 3) / 4; Index ++) {
+ MessageBody[Index + ReadSize] = *ReadBuffer;
+ }
+ for (;Index < (MessageHeader.Fields.Length + 3) / 4; Index ++) {
+ Data = *ReadBuffer;
+ }
+ CheckBXTBlackHole (Message);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Disable Heci interrupt.
+
+**/
+VOID
+HeciDisableInterrupt (
+ VOID
+ )
+{
+ volatile HECI_HOST_CONTROL_REGISTER *HostControlReg;
+
+ HostControlReg = (volatile HECI_HOST_CONTROL_REGISTER *) (UINTN) (mHeci_HeciBar + H_CSR);
+
+ HostControlReg->r.H_IE = 0;
+}
+
+
+/**
+ Enable Heci Interrupt.
+
+**/
+VOID
+HeciEnableInterrupt (
+ VOID
+ )
+{
+ volatile HECI_HOST_CONTROL_REGISTER *HostControlReg;
+
+ HostControlReg = (volatile HECI_HOST_CONTROL_REGISTER *) (UINTN) (mHeci_HeciBar + H_CSR);
+
+ HostControlReg->r.H_IE = 1;
+}
+
+
+/**
+ Clear Heci Interrupt Flag.
+
+**/
+VOID
+HeciClearInterrupt (
+ VOID
+ )
+{
+ volatile HECI_HOST_CONTROL_REGISTER *HostControlReg;
+
+ HostControlReg = (volatile HECI_HOST_CONTROL_REGISTER *) (UINTN) (mHeci_HeciBar + H_CSR);
+
+ HostControlReg->r.H_IS = 1;
+}
+
+
+/**
+ Check dies Heci Interrupt Occur.
+
+ @retval BOOLEAN
+
+**/
+BOOLEAN
+HeciInterruptOccur (
+ VOID
+ )
+{
+ volatile HECI_HOST_CONTROL_REGISTER *HostControlReg;
+
+ HostControlReg = (volatile HECI_HOST_CONTROL_REGISTER *) (UINTN) (mHeci_HeciBar + H_CSR);
+
+ return (HostControlReg->r.H_IS == 1);
+}
+
+
+/**
+ is there Heci Response?
+
+ @retval BOOLEAN
+
+**/
+BOOLEAN
+IsHeciCseResponse (
+ VOID
+ )
+{
+ volatile HECI_SEC_CONTROL_REGISTER *SecControlReg;
+
+ SecControlReg = (volatile HECI_SEC_CONTROL_REGISTER *) (UINTN) (mHeci_HeciBar + SEC_CSR_HA);
+
+ return (SecControlReg->r.SEC_CBRP_HRA != SecControlReg->r.SEC_CBWP_HRA);
+}
+
+
+/**
+ Heci Interrupt Handle.
+
+**/
+UINT8 Msg[400];
+
+VOID
+HeciInterruptHandle (
+ VOID
+ )
+{
+ UINT32 MsgLength;
+
+ if (IsHeciCseResponse ()) {
+ HeciDisableInterrupt ();
+ HeciClearInterrupt ();
+ MsgLength = sizeof (Msg);
+ HeciReceiveInterrupt (Msg, &MsgLength);
+ mHeci_Complete = TRUE;
+ HeciEnableInterrupt ();
+ } else {
+ if (HeciSendHandle ()) {
+ }
+ }
+ CheckCommandQueue ();
+
+ if ((CommandDataBufferHead == CommandDataBufferTail) && mHeci_Complete) {
+ SetHeci2Idle ();
+ }
+}
+
+
+VOID ProxyStopNotify (
+ VOID
+ )
+{
+ HeciPciWrite32 (PCI_CFG_GS3, (PCI_CFG_GS3_PANIC_SUPPORTED | PCI_CFG_GS3_PANIC));
+ mProxyStopPhase = TRUE;
+}
+
+
+VOID FlashCommandQueue (
+ VOID
+ )
+{
+ SetHeci2Active ();
+ while (CommandDataBufferHead != CommandDataBufferTail) {
+ CheckCommandQueue ();
+ }
+}
+
+
+/**
+ SMI Callback function to inform CSE to take NVM ownership.
+
+ @param[in] DispatchHandle
+ @param[in] RegisterContext
+ @param[in] CommBuffer
+ @param[in] CommBufferSize
+
+ @retval EFI_STATUS
+
+**/
+EFI_STATUS
+EFIAPI
+SystemResetCallback (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ ProxyStopNotify ();
+ HeciInterruptHandle ();
+ mHeci_Complete = TRUE;
+ FlashCommandQueue ();
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Registering SMI Callback function for System Reset Notification.
+
+ @param[in] None
+
+ @retval None
+
+**/
+VOID InitSystemResetHandle (
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
+ EFI_SMM_SW_REGISTER_CONTEXT SwContext;
+ EFI_HANDLE SwHandle;
+
+ //
+ // Get the Sw dispatch protocol and register SMI callback functions.
+ //
+ Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);
+ ASSERT_EFI_ERROR (Status);
+ SwContext.SwSmiInputValue = (UINTN) HECI_SYSTEM_RESET_NOTIFY;
+ Status = SwDispatch->Register (SwDispatch, SystemResetCallback, &SwContext, &SwHandle);
+ ASSERT_EFI_ERROR (Status);
+}
+
+UINTN Tag = 0;
+
+
+/**
+ SMM handle to dispatch request.
+
+ @param[in] DispatchHandle
+ @param[in] RegisterContext
+ @param[in] CommBuffer
+ @param[in] CommBufferSize
+
+ @retval EFI_STATUS
+
+**/
+EFI_STATUS
+EFIAPI
+HeciSmmHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *RegisterContext,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ EFI_STATUS Status=EFI_SUCCESS;
+ SMM_HECI_COMMUNICATE_HEADER *SmmHeciFunctionHeader;
+ SMM_HECI_SEND_MESSAGE_BODY *SendMessageBody;
+ SMM_HECI_READ_MESSAGE_BODY *ReadMessageBody;
+ SMM_HECI_SEND_MESSAGE_W_ACK_BODY *SendMessageWAckBody;
+ EFI_HANDLE HeciHandle;
+ UINT32 SecMode;
+
+ //
+ // If input is invalid, stop processing this SMI
+ //
+ if (CommBuffer == NULL || CommBufferSize == NULL) {
+ return Status;
+ }
+
+ SecMode = HeciPciRead32 (R_SEC_FW_STS0);
+ if (SEC_MODE_NORMAL != (SecMode & 0xF0000)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ SmmHeciFunctionHeader = (VOID *) CommBuffer;
+ switch (SmmHeciFunctionHeader->Function) {
+ case SMM_HECI_FUNCTION_SEND_MESSAGE_WITH_ACK:
+ DEBUG ((EFI_D_ERROR, "SMM_HECI_FUNCTION_SEND_MESSAGE_WITH_ACK \n"));
+ if (!((CommandDataBufferHead == CommandDataBufferTail) && mHeci_Complete)) {
+ Status = EFI_NOT_READY;
+ DEBUG ((EFI_D_ERROR, "SMM_HECI_FUNCTION_SEND_MESSAGE_WITH_ACK EFI_NOT_READY\n"));
+ break;
+ }
+ SendMessageWAckBody = (SMM_HECI_SEND_MESSAGE_W_ACK_BODY *) SmmHeciFunctionHeader->Data;
+ Status = Heci2SendwACK (
+ (UINT32 *) SendMessageWAckBody->MessageData,
+ SendMessageWAckBody->Length,
+ &SendMessageWAckBody->RecLength,
+ (UINT8) SendMessageWAckBody->HostAddress,
+ (UINT8) SendMessageWAckBody->CSEAddress
+ );
+ DEBUG ((EFI_D_ERROR, "SMM_HECI_FUNCTION_SEND_MESSAGE_WITH_ACK %x %x\n", Status, *(UINT32*)SendMessageWAckBody->MessageData));
+ break;
+ case SMM_HECI_FUNCTION_READ_MESSAGE:
+ ReadMessageBody = (SMM_HECI_READ_MESSAGE_BODY *) SmmHeciFunctionHeader->Data;
+ Status = EfiHeciReadMessage (
+ HECI2_DEVICE,
+ 0,
+ &ReadMessageBody->Length,
+ (UINT32 *) &ReadMessageBody->MessageData
+ );
+ break;
+ case SMM_HECI_FUNCTION_SEND_MESSAGE:
+ SetHeci2Active ();
+ SendMessageBody = (SMM_HECI_SEND_MESSAGE_BODY *) SmmHeciFunctionHeader->Data;
+ HeciSendInterrupt (SendMessageBody->MessageData, SendMessageBody->Length, (UINT8)SendMessageBody->HostAddress, (UINT8)SendMessageBody->CSEAddress);
+ break;
+
+ case SMM_HECI_FUNCTION_GET_STATUS:
+ if (IsHeci2Idle ()) {
+ SmmHeciFunctionHeader->Data[0] = 0;
+ } else {
+ if (HeciInterruptOccur () || IsHeciCseResponse ()) {
+ HeciInterruptHandle ();
+ }
+ if (InBXTBlackHolePhase ()) {
+ SmmHeciFunctionHeader->Data[0] = 0;
+ } else {
+ if ((CommandDataBufferHead == CommandDataBufferTail) && mHeci_Complete) {
+ SmmHeciFunctionHeader->Data[0] = 0;
+ SetHeci2Idle ();
+ } else {
+ SmmHeciFunctionHeader->Data[0] = 1;
+ }
+ }
+ }
+ break;
+ case SMM_HECI_MESSAGE_END_OF_POST:
+ DEBUG ((EFI_D_INFO, "HeciSmmHandler SMM_HECI_MESSAGE_END_OF_POST\n"));
+ InitSystemResetHandle ();
+ HeciHandle = NULL;
+ Status = gSmst->SmmInstallProtocolInterface (
+ &HeciHandle,
+ &gEfiCseEndofPostGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ break;
+ case SMM_HECI_MESSAGE_END_OF_SERVICES:
+ DEBUG ((EFI_D_INFO, "HeciSmmHandler SMM_HECI_MESSAGE_END_OF_SERVICES\n"));
+ HeciHandle = NULL;
+ Status = gSmst->SmmInstallProtocolInterface (
+ &HeciHandle,
+ &gEfiCseEndofServicesGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ mAtRuntime = TRUE;
+ break;
+ default:
+ Status = EFI_UNSUPPORTED;
+ }
+ SmmHeciFunctionHeader->ReturnStatus = Status;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ SmmEndOfDxeCallback
+
+ @param[in] Protocol
+ @param[in] Interface
+ @param[in] Handle
+
+ @retval EFI_STATUS
+
+**/
+EFI_STATUS
+EFIAPI
+SmmEndOfDxeCallback (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Send Heci message with response.
+
+ @param[in] HeciDev HECI device
+ @param[in, out] Message Message Data
+ @param[in, out] Length Message Data Length
+ @param[in, out] RecLength Return message buffer length
+ @param[in] HostAddress Host Address
+ @param[in] SECAddress CSE Address
+
+ @retval EFI_SUCCESS Send message success.
+ @retval Others Send message failed.
+
+**/
+EFI_STATUS
+EfiHeciSendwack (
+ IN HECI_DEVICE HeciDev,
+ IN OUT UINT32 *Message,
+ IN OUT UINT32 Length,
+ IN OUT UINT32 *RecLength,
+ IN UINT8 HostAddress,
+ IN UINT8 SECAddress
+ )
+{
+ EFI_STATUS Status;
+
+ SetHeci2Active ();
+ Status = Heci2SendwACK (
+ Message,
+ Length,
+ RecLength,
+ HostAddress,
+ SECAddress
+ );
+ SetHeci2Idle ();
+
+ return Status;
+}
+
+
+/**
+ Read the Heci message
+
+ @param[in] HeciDev HECI Device ID.
+ @param[in] Blocking Indicate does waiting for response.
+ @param[in] MessageBody Message data buffer.
+ @param[in, out] Length Message data buffer size.
+
+ @retval EFI_SUCCESS Send message success.
+ @retval Others Send message failed.
+
+**/
+EFI_STATUS
+EfiHeciReadMessage (
+ IN HECI_DEVICE HeciDev,
+ IN UINT32 Blocking,
+ IN UINT32 *MessageBody,
+ IN OUT UINT32 *Length
+ )
+{
+ if (IsHeciCseResponse ()) {
+ HeciInterruptHandle ();
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_READY;
+}
+
+
+/**
+ Send Heci message without response.
+
+ @param[in] HeciDev HECI Device ID.
+ @param[in] Message Message Data.
+ @param[in] Length Message Data length.
+ @param[in] HostAddress Host Address.
+ @param[in] SECAddress CSE Address.
+
+ @retval EFI_SUCCESS Send message success.
+ @retval Others Send message failed.
+
+**/
+EFI_STATUS
+EfiHeciSendMessage (
+ IN HECI_DEVICE HeciDev,
+ IN UINT32 *Message,
+ IN UINT32 Length,
+ IN UINT8 HostAddress,
+ IN UINT8 SECAddress
+ )
+{
+ SetHeci2Active ();
+ HeciSendInterrupt ((UINT8 *) Message, Length, HostAddress, SECAddress);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Reset the heci device.
+
+ @param[in] HeciDev HECI Device ID.
+
+ @retval EFI_SUCCESS Reset HECI success.
+ @retval Others Reset HECI failed.
+
+**/
+EFI_STATUS
+EfiHeciReset (
+ IN HECI_DEVICE HeciDev
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Init the heci device.
+
+ @param[in] HeciDev HECI Device ID.
+
+ @retval EFI_SUCCESS Init HECI success.
+ @retval Others Init HECI failed.
+
+**/
+EFI_STATUS
+EfiHeciInit (
+ IN HECI_DEVICE HeciDev
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Reinit the heci device.
+
+ @param[in] HeciDev HECI Device ID.
+
+ @retval EFI_SUCCESS Reinit HECI success.
+ @retval Others Reinit HECI failed.
+
+**/
+EFI_STATUS
+EfiHeciReinit (
+ IN HECI_DEVICE HeciDev
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Reset the Heci device and waiting for Delay time.
+
+ @param[in] HeciDev HECI Device ID.
+ @param[in] Delay The time waiting for reset.
+
+ @retval EFI_SUCCESS Reset success.
+ @retval Others Reset failed.
+
+**/
+EFI_STATUS
+EfiHeciResetWait (
+ IN HECI_DEVICE HeciDev,
+ IN UINT32 Delay
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Get the Heci status.
+
+ @param[out] Status HECI Staus.
+
+ @retval EFI_SUCCESS Get status success.
+ @retval Others Get status failed.
+
+**/
+EFI_STATUS
+EfiHeciGetSecStatus (
+ IN UINT32 *Status
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Get the heci mode.
+
+ @param[in] HeciDev HECI Device ID.
+ @param[out] Mode Heci Mode
+
+ @retval EFI_SUCCESS Get mode success.
+ @retval Others Get mode failed.
+
+**/
+EFI_STATUS
+EfiHeciGetSecMode (
+ IN HECI_DEVICE HeciDev,
+ IN UINT32 *Mode
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Return whether at runtime.
+
+ @param None.
+
+ @retval TRUE If at runtime.
+ FALSE Not at runtime.
+
+**/
+BOOLEAN
+EFIAPI
+AtRuntime (
+ VOID
+ )
+{
+ return mAtRuntime;
+}
+
+
+EFI_HECI_PROTOCOL mHeciSmmProtocol = {
+ EfiHeciSendwack,
+ EfiHeciReadMessage,
+ EfiHeciSendMessage,
+ EfiHeciReset,
+ EfiHeciInit,
+ EfiHeciResetWait,
+ EfiHeciReinit,
+ EfiHeciGetSecStatus,
+ EfiHeciGetSecMode
+};
+
+EFI_HECI2_PM_PROTOCOL mHeci2PmSmmProtocol = {
+ IsHeci2Idle,
+ SetHeci2Active,
+ SetHeci2Idle,
+ GetHeci2Bar,
+ SetHeci2Bar,
+ AtRuntime
+};
+
+/**
+ SmmPlatformHeci2ProxyHandler
+
+ @param[in] DispatchHandle
+ @param[in] RegisterContext
+ @param[in,out] CommBuffer
+ @param[in,out] CommBufferSize
+
+ @retval EFI_STATUS
+
+**/
+EFI_STATUS
+SmmPlatformHeci2ProxyHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *RegisterContext,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ HeciInterruptInit ();
+ if (HeciInterruptOccur ()) {
+ HeciInterruptHandle ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Variable Driver main entry point. The Variable driver places the 4 EFI
+ runtime services in the EFI System Table and installs arch protocols
+ for variable read and write services being available. It also registers
+ a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS Variable service successfully initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+HeciSmmInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE HeciHandle;
+ EFI_HANDLE SmmHandle;
+ VOID *SmmEndOfDxeRegistration;
+ MBP_SMM_TRUSTED_KEY SmmTrustedKey;
+
+ //
+ // Install the Smm Variable Protocol on a new handle.
+ //
+ if (Heci2PciRead16 (R_SEC_DevID_VID) == 0xFFFF) {
+ return EFI_SUCCESS;
+ }
+
+ if (mMonoCount == 0) {
+ //
+ // Since the is the first message, get the SMM trusted key for this boot
+ //
+ Status = HeciGetSMMTrustedKey (&SmmTrustedKey);
+
+ if (!EFI_ERROR (Status)) {
+ CopyMem (mHmacSha256Key, SmmTrustedKey.SmmTrustedKey, sizeof (mHmacSha256Key));
+ mMonoCount = SmmTrustedKey.MonotonicCounter + 1;
+ DEBUG ((EFI_D_INFO, "HMAC Monotonic Count = %d\n", mMonoCount));
+ } else {
+ DEBUG ((EFI_D_ERROR, "Unable to get the SMM trusted key. Cannot send HECI2 transactions.\n"));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+ }
+
+ //
+ // Install the Smm Variable Protocol on a new handle.
+ //
+ HeciHandle = NULL;
+ Status = gSmst->SmmInstallProtocolInterface (
+ &HeciHandle,
+ &gEfiHeciSmmProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mHeciSmmProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ HeciHandle = NULL;
+ Status = gSmst->SmmInstallProtocolInterface (
+ &HeciHandle,
+ &gEfiHeci2PmProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mHeci2PmSmmProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register SMM variable SMI handler
+ //
+ Status = gSmst->SmiHandlerRegister (HeciSmmHandler, &gEfiHeciSmmProtocolGuid, &HeciHandle);
+ ASSERT_EFI_ERROR (Status);
+
+ SmmHandle = NULL;
+ Status = gSmst->SmiHandlerRegister (SmmPlatformHeci2ProxyHandler, NULL, &SmmHandle);
+
+ //
+ // Register EFI_SMM_END_OF_DXE_PROTOCOL_GUID notify function.
+ //
+ Status = gSmst->SmmRegisterProtocolNotify (
+ &gEfiSmmEndOfDxeProtocolGuid,
+ SmmEndOfDxeCallback,
+ &SmmEndOfDxeRegistration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((EFI_D_INFO, " Start Init Heci2 SMI Interrupt\n"));
+
+ PERF_START_EX (NULL, NULL, NULL, 0, 0x8100);
+ HeciReset (HECI2_DEVICE);
+ PERF_END_EX (NULL, NULL, NULL, 0, 0x8101);
+
+ HeciInterruptInit ();
+ HeciDisableInterrupt ();
+ HeciClearInterrupt ();
+ HeciEnableInterrupt ();
+ DEBUG ((EFI_D_INFO, "Start set HIDM %x %x\n", Heci2PciRead16(0), Heci2PciRead16(2)));
+ Heci2PciWrite32 (0xa0, 2);
+
+ return EFI_SUCCESS;
+}
+
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmm.h b/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmm.h new file mode 100644 index 0000000000..dac73d2f33 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmm.h @@ -0,0 +1,61 @@ +/** @file
+ Definitions for HECI SMM driver.
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _HECI_SMM_H_
+#define _HECI_SMM_H_
+
+#define SMM_HECI_FUNCTION_SEND_MESSAGE_WITH_ACK 1
+#define SMM_HECI_FUNCTION_READ_MESSAGE 2
+#define SMM_HECI_FUNCTION_SEND_MESSAGE 3
+#define SMM_HECI_FUNCTION_GET_STATUS 8
+#define SMM_HECI_TRUSTED_CHANNEL_ERROR 5
+
+#define SMM_HECI_MESSAGE_END_OF_POST 0x100
+#define SMM_HECI_MESSAGE_END_OF_SERVICES 0x101
+
+#define PCI_CFG_GS3 0x74
+#define PCI_CFG_GS3_PANIC_SUPPORTED 0x00080000
+#define PCI_CFG_GS3_PANIC 0x00000008
+
+typedef struct {
+ UINTN Function;
+ EFI_STATUS ReturnStatus;
+ UINT8 Data[1];
+} SMM_HECI_COMMUNICATE_HEADER;
+
+typedef struct {
+ UINT32 Length;
+ UINT32 HostAddress;
+ UINT32 CSEAddress;
+ UINT8 MessageData[1];
+} SMM_HECI_SEND_MESSAGE_BODY;
+
+typedef struct {
+ UINT32 Length;
+ UINT8 MessageData[1];
+} SMM_HECI_READ_MESSAGE_BODY;
+
+typedef struct {
+ UINT32 Length;
+ UINT32 RecLength;
+ UINT32 HostAddress;
+ UINT32 CSEAddress;
+ UINT8 MessageData[1];
+} SMM_HECI_SEND_MESSAGE_W_ACK_BODY;
+
+#define MAX_HECI_BUFFER_SIZE 0x10000
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmm.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmm.inf new file mode 100644 index 0000000000..400d76210a --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmm.inf @@ -0,0 +1,59 @@ +## @file
+# HECI SMM driver Module.
+#
+# Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = HeciSmm
+ FILE_GUID = C4491F51-66B9-4590-95E4-E2B4AD777703
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = HeciSmmInitialize
+
+[Sources]
+ HeciSmm.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ BroxtonSiPkg/BroxtonSiPkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ SeCLib
+ UefiBootServicesTableLib
+ DebugLib
+ PciLib
+ BaseLib
+ DxeServicesTableLib
+ MemoryAllocationLib
+ S3BootScriptLib
+ UefiDriverEntryPoint
+ HeciMsgLib
+ PerformanceLib
+ BaseCryptLib
+
+[Protocols]
+ gEfiHeciProtocolGuid ## PRODUCES
+ gEfiHeciSmmProtocolGuid ## PRODUCES
+ gEfiSmmEndOfDxeProtocolGuid ## PRODUCES
+ gEfiSmmSwDispatch2ProtocolGuid
+ gEfiHeci2PmProtocolGuid ## PRODUCES
+
+[Guids]
+ gEfiCseEndofPostGuid
+ gEfiCseEndofServicesGuid
+
+[Depex]
+ TRUE
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmmRuntimeDxe.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmmRuntimeDxe.c new file mode 100644 index 0000000000..a23a1f48a3 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmmRuntimeDxe.c @@ -0,0 +1,777 @@ +/** @file
+ HECI Smm Runtime Dxe driver.
+
+ Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Protocol/SmmCommunication.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Guid/EventGroup.h>
+#include <protocol/Heci.h>
+#include <HeciSmm.h>
+#include <Library/SideBandLib.h>
+#include <SeCAccess.h>
+#include <HeciRegs.h>
+
+EFI_HANDLE mHandle = NULL;
+EFI_HECI_PROTOCOL *mSmmHeci = NULL;
+EFI_EVENT mVirtualAddressChangeEvent = NULL;
+EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;
+UINT8 *mHeciBuffer = NULL;
+UINT8 *mHeciBufferPhysical = NULL;
+UINTN mHeciBufferSize;
+UINTN mHeciBufferPayloadSize;
+
+/**
+ Put HECI1 and HECI3 into D0I3.
+
+ @param[in] None.
+
+ @retval None
+
+**/
+VOID
+PutDeviceIntoD0I3 (
+ VOID
+ )
+{
+ UINT32 HeciBar;
+
+ DEBUG ((EFI_D_INFO, "Put all HECI devices into D0i3 and hide HECI 2 and HECI 3.\n"));
+
+ HeciBar = HeciPciRead32 (R_HECIMBAR0) & 0xFFFFFFF0 ;
+ if ((Mmio32 (HeciBar, R_HECI_DEVIDLEC) & B_HECI_DEVIDLEC_DEVIDLE) == 0) {
+ //
+ // Poll until CIP == 0
+ //
+ while ((Mmio32 (HeciBar, R_HECI_DEVIDLEC) & B_HECI_DEVIDLEC_CIP) == B_HECI_DEVIDLEC_CIP);
+ Mmio32Or (HeciBar, R_HECI_DEVIDLEC, B_HECI_DEVIDLEC_DEVIDLE);
+ }
+
+ HeciBar = Heci2PciRead32 (R_HECIMBAR0) & 0xFFFFFFF0 ;
+ if ((Mmio32 (HeciBar, R_HECI_DEVIDLEC) & B_HECI_DEVIDLEC_DEVIDLE) == 0) {
+ //
+ // Poll until CIP == 0
+ //
+ while ((Mmio32 (HeciBar, R_HECI_DEVIDLEC) & B_HECI_DEVIDLEC_CIP) == B_HECI_DEVIDLEC_CIP);
+ Mmio32Or (HeciBar, R_HECI_DEVIDLEC, B_HECI_DEVIDLEC_DEVIDLE);
+ }
+
+ HeciBar = Heci3PciRead32 (R_HECIMBAR0) & 0xFFFFFFF0;
+ if ((Mmio32 (HeciBar, R_HECI_DEVIDLEC) & B_HECI_DEVIDLEC_DEVIDLE) == 0) {
+ //
+ // Poll until CIP == 0
+ //
+ while ((Mmio32 (HeciBar, R_HECI_DEVIDLEC) & B_HECI_DEVIDLEC_CIP) == B_HECI_DEVIDLEC_CIP);
+ Mmio32Or (HeciBar, R_HECI_DEVIDLEC, B_HECI_DEVIDLEC_DEVIDLE);
+ }
+
+ SideBandAndThenOr32 (
+ 0xC6,
+ 0x1D38,
+ 0xFFFFFFFF,
+ (UINT32) BIT0
+ );
+
+ SideBandAndThenOr32 (
+ 0xC6,
+ 0x1c38,
+ 0xFFFFFFFF,
+ (UINT32) BIT0
+ );
+ }
+
+
+/**
+ Initialize the communicate buffer using DataSize and Function.
+
+ The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
+ DataSize.
+
+ @param[out] DataPtr Points to the data in the communicate buffer.
+ @param[in] DataSize The data size to send to SMM.
+ @param[in] Function The function number to initialize the communicate header.
+
+ @retval EFI_INVALID_PARAMETER The data size is too big.
+ @retval EFI_SUCCESS Find the specified variable.
+
+**/
+EFI_STATUS
+InitCommunicateBuffer (
+ OUT VOID **DataPtr OPTIONAL,
+ IN UINTN DataSize,
+ IN UINTN Function
+ )
+{
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ SMM_HECI_COMMUNICATE_HEADER *SmmHeciFunctionHeader;
+
+ if (DataSize > mHeciBufferSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mHeciBuffer;
+ CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiHeciSmmProtocolGuid);
+ SmmCommunicateHeader->MessageLength = DataSize + sizeof (EFI_SMM_COMMUNICATE_HEADER);
+
+ SmmHeciFunctionHeader = (SMM_HECI_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
+ SmmHeciFunctionHeader->Function = Function;
+ if (DataPtr != NULL) {
+ *DataPtr = SmmHeciFunctionHeader->Data;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Send the data in communicate buffer to SMM.
+
+ @param[in] DataSize This size of the function header and the data.
+
+ @retval EFI_SUCCESS Success is returned from the functin in SMM.
+ @retval Others Failure is returned from the function in SMM.
+
+**/
+EFI_STATUS
+SendCommunicateBuffer (
+ IN UINTN DataSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN CommSize;
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ SMM_HECI_COMMUNICATE_HEADER *SmmHeciFunctionHeader;
+
+ CommSize = DataSize + sizeof (EFI_SMM_COMMUNICATE_HEADER) + sizeof (SMM_HECI_COMMUNICATE_HEADER);
+ Status = mSmmCommunication->Communicate (mSmmCommunication, mHeciBufferPhysical, &CommSize);
+ ASSERT_EFI_ERROR (Status);
+
+ SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mHeciBuffer;
+ SmmHeciFunctionHeader = (SMM_HECI_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
+
+ return SmmHeciFunctionHeader->ReturnStatus;
+}
+
+
+/**
+ Send Heci message with response.
+
+ @param[in] HeciDev HECI device
+ @param[in,out] Message Message Data
+ @param[in,out] Length Message Data Length
+ @param[in,out] RecLength Return message buffer length
+ @param[in] HostAddress Host Address
+ @param[in] SECAddress CSE Address
+
+ @retval EFI_SUCCESS Send message success.
+ @retval Others Send message failed.
+
+**/
+EFI_STATUS
+EfiHeciSendwack (
+ IN HECI_DEVICE HeciDev,
+ IN OUT UINT32 *Message,
+ IN OUT UINT32 Length,
+ IN OUT UINT32 *RecLength,
+ IN UINT8 HostAddress,
+ IN UINT8 SECAddress
+ )
+{
+ EFI_STATUS Status;
+ UINTN PayloadSize;
+ SMM_HECI_SEND_MESSAGE_W_ACK_BODY *SmmHeciSendMessageBody;
+ UINT32 MaxLength;
+ UINT32 SecMode;
+
+ if (HeciDev != HECI2_DEVICE) {
+ return EFI_UNSUPPORTED;
+ }
+ if (Message == NULL || Length == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ SecMode = HeciPciRead32 (R_SEC_FW_STS0);
+ if (SEC_MODE_NORMAL != (SecMode & 0xF0000)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Length > *RecLength) {
+ MaxLength = Length;
+ } else {
+ MaxLength = *RecLength;
+ }
+ SmmHeciSendMessageBody = NULL;
+
+ PayloadSize = sizeof (SMM_HECI_COMMUNICATE_HEADER) + sizeof (SMM_HECI_SEND_MESSAGE_W_ACK_BODY) + Length;
+
+ Status = InitCommunicateBuffer ((VOID **) &SmmHeciSendMessageBody, PayloadSize, SMM_HECI_FUNCTION_SEND_MESSAGE_WITH_ACK);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ASSERT (SmmHeciSendMessageBody != NULL);
+ if (SmmHeciSendMessageBody != NULL) {
+ DEBUG ((EFI_D_ERROR, "EfiHeciSendwack 2\n"));
+ SmmHeciSendMessageBody->Length = Length;
+ SmmHeciSendMessageBody->HostAddress = HostAddress;
+ SmmHeciSendMessageBody->CSEAddress = SECAddress;
+ CopyMem (SmmHeciSendMessageBody->MessageData, (VOID *) Message, Length);
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (PayloadSize);
+ if (!EFI_ERROR (Status)) {
+ *RecLength = SmmHeciSendMessageBody->RecLength;
+ CopyMem (Message, SmmHeciSendMessageBody->MessageData, *RecLength);
+ }
+ }
+
+Done:
+ return Status;
+}
+
+
+/**
+ Read the Heci message.
+
+ @param[in] HeciDev HECI Device ID.
+ @param[in] Blocking Indicate does waiting for response.
+ @param[in] MessageBody Message data buffer.
+ @param[in,out] Length Message data buffer size.
+
+ @retval EFI_SUCCESS Send message success.
+ @retval Others Send message failed.
+
+**/
+EFI_STATUS
+EfiHeciReadMessage (
+ IN HECI_DEVICE HeciDev,
+ IN UINT32 Blocking,
+ IN UINT32 *MessageBody,
+ IN OUT UINT32 *Length
+ )
+{
+ EFI_STATUS Status;
+ UINT32 SecMode;
+ UINTN PayloadSize;
+ SMM_HECI_READ_MESSAGE_BODY *SmmHeciReadMessageBody;
+
+ if (HeciDev != HECI2_DEVICE) {
+ return EFI_UNSUPPORTED;
+ }
+
+ SecMode = HeciPciRead32 (R_SEC_FW_STS0);
+ if (SEC_MODE_NORMAL != (SecMode & 0xF0000)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ SmmHeciReadMessageBody = NULL;
+
+ PayloadSize = sizeof (SMM_HECI_COMMUNICATE_HEADER) + sizeof (SMM_HECI_READ_MESSAGE_BODY) + *Length;
+
+ Status = InitCommunicateBuffer ((VOID **) &SmmHeciReadMessageBody, PayloadSize, SMM_HECI_FUNCTION_READ_MESSAGE);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ASSERT (SmmHeciReadMessageBody != NULL);
+
+ if (SmmHeciReadMessageBody!= NULL) {
+ SmmHeciReadMessageBody->Length = *Length;
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (PayloadSize);
+ if (!EFI_ERROR (Status)) {
+ *Length = SmmHeciReadMessageBody->Length;
+ CopyMem (MessageBody, SmmHeciReadMessageBody->MessageData, *Length);
+ }
+ }
+Done:
+ return Status;
+}
+
+
+/**
+ Send Heci message without response.
+
+ @param[in] HeciDev HECI Device ID.
+ @param[in] Message Message Data.
+ @param[in] Length Message Data length.
+ @param[in] HostAddress Host Address.
+ @param[in] SECAddress CSE Address.
+
+ @retval EFI_SUCCESS Send message success.
+ @retval Others Send message failed.
+
+**/
+EFI_STATUS
+EfiHeciSendMessage (
+ IN HECI_DEVICE HeciDev,
+ IN UINT32 *Message,
+ IN UINT32 Length,
+ IN UINT8 HostAddress,
+ IN UINT8 SECAddress
+ )
+{
+ EFI_STATUS Status;
+ UINTN PayloadSize;
+ SMM_HECI_SEND_MESSAGE_BODY *SmmHeciSendMessageBody;
+ UINT32 SecMode;
+
+ if (HeciDev != HECI2_DEVICE) {
+ return EFI_UNSUPPORTED;
+ }
+
+ SecMode = HeciPciRead32(R_SEC_FW_STS0);
+ if (SEC_MODE_NORMAL != (SecMode & 0xF0000)) {
+ return EFI_UNSUPPORTED;
+ }
+ if (Message == NULL || Length == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ SmmHeciSendMessageBody = NULL;
+
+ PayloadSize = sizeof (SMM_HECI_COMMUNICATE_HEADER) + Length;
+
+ Status = InitCommunicateBuffer ((VOID **) &SmmHeciSendMessageBody, PayloadSize, SMM_HECI_FUNCTION_SEND_MESSAGE);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ASSERT (SmmHeciSendMessageBody != NULL);
+
+ if (SmmHeciSendMessageBody != NULL) {
+ SmmHeciSendMessageBody->Length = Length;
+ SmmHeciSendMessageBody->HostAddress = HostAddress;
+ SmmHeciSendMessageBody->CSEAddress = SECAddress;
+ CopyMem (SmmHeciSendMessageBody->MessageData, (VOID *) Message, Length);
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (PayloadSize);
+ }
+Done:
+ return Status;
+}
+
+
+/**
+ Reset the heci device.
+
+ @param[in] HeciDev HECI Device ID.
+
+ @retval EFI_SUCCESS Reset HECI success.
+ @retval Others Reset HECI failed.
+
+**/
+EFI_STATUS
+EfiHeciReset (
+ IN HECI_DEVICE HeciDev
+ )
+{
+ if (HeciDev != HECI2_DEVICE) {
+ return EFI_UNSUPPORTED;
+ }
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Init the heci device.
+
+ @param[in] HeciDev HECI Device ID.
+
+ @retval EFI_SUCCESS Init HECI success.
+ @retval Others Init HECI failed.
+
+**/
+EFI_STATUS
+EfiHeciInit (
+ IN HECI_DEVICE HeciDev
+ )
+{
+ if (HeciDev != HECI2_DEVICE) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Reinit the heci device
+
+ @param[in] HeciDev HECI Device ID.
+
+ @retval EFI_SUCCESS Reinit HECI success.
+ @retval Others Reinit HECI failed.
+
+**/
+EFI_STATUS
+EfiHeciReinit (
+ IN HECI_DEVICE HeciDev
+ )
+{
+ if (HeciDev != HECI2_DEVICE) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Reset the Heci device and waiting for Delay time
+
+ @param[in] HeciDev HECI Device ID.
+ @param[in] Delay The time waiting for reset.
+
+ @retval EFI_SUCCESS Reset success.
+ @retval Others Reset failed.
+
+**/
+EFI_STATUS
+EfiHeciResetWait (
+ IN HECI_DEVICE HeciDev,
+ IN UINT32 Delay
+ )
+{
+ if (HeciDev != HECI2_DEVICE) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Get the Heci status
+
+ @param[out] Status HECI Staus.
+
+ @retval EFI_SUCCESS Get status success.
+ @retval Others Get status failed.
+
+**/
+EFI_STATUS
+EfiHeciGetSecStatus (
+ OUT UINT32 *Status2
+ )
+{
+ EFI_STATUS Status;
+ UINTN PayloadSize;
+ UINT8 *Data;
+
+ Data = NULL;
+ PayloadSize = sizeof (SMM_HECI_COMMUNICATE_HEADER);
+
+ Status = InitCommunicateBuffer ((VOID **) &Data, PayloadSize, SMM_HECI_FUNCTION_GET_STATUS);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ASSERT (Data != NULL);
+
+ if (Data != NULL) {
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (PayloadSize);
+ *Status2 = (UINT32) *Data;
+ }
+Done:
+ return Status;
+}
+
+
+/**
+ Get the heci mode.
+
+ @param[in] HeciDev HECI Device ID.
+ @param[out] Mode Heci Mode
+
+ @retval EFI_SUCCESS Get mode success.
+ @retval Others Get mode failed.
+
+**/
+EFI_STATUS
+EfiHeciGetSecMode (
+ IN HECI_DEVICE HeciDev,
+ OUT UINT32 *Mode
+ )
+{
+ if (HeciDev != HECI2_DEVICE) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+EFI_HECI_PROTOCOL mHeciProtocol = {
+ EfiHeciSendwack,
+ EfiHeciReadMessage,
+ EfiHeciSendMessage,
+ EfiHeciReset,
+ EfiHeciInit,
+ EfiHeciResetWait,
+ EfiHeciReinit,
+ EfiHeciGetSecStatus,
+ EfiHeciGetSecMode
+};
+
+
+/**
+ Initialize variable service and install Variable Architectural protocol.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+AddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EfiConvertPointer (0x0, (VOID **) &mHeciBuffer);
+ EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);
+}
+
+/**
+ HeciSmmReady
+
+ @param[in] Event
+ @param[in] Context
+
+ @retval EFI_STATUS
+
+**/
+VOID
+EFIAPI
+HeciSmmReady (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG((EFI_D_INFO, "HeciSmmReady \n"));
+
+ if (mHandle != NULL) {
+ DEBUG ((EFI_D_INFO, "gEfiHeciProtocol Has Installed return\n"));
+ return;
+ }
+ Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Save the buffer physical address used for SMM conmunication.
+ //
+ mHeciBufferPhysical = mHeciBuffer;
+
+ //
+ // Install the Heci Protocol on a new handle.
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mHandle,
+ &gEfiHeciSmmRuntimeProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mHeciProtocol
+ );
+ DEBUG ((EFI_D_INFO, " Heci 2 Prepare Done \n"));
+ ASSERT_EFI_ERROR (Status);
+}
+
+
+VOID
+EFIAPI
+HeciSmmEndOfPostEvent (
+ IN EFI_EVENT Event,
+ IN VOID* Context
+ )
+{
+ UINT32 SecMode;
+
+ SecMode = HeciPciRead32 (R_SEC_FW_STS0);
+ if (SEC_MODE_NORMAL == (SecMode & 0xF0000)) {
+ HeciSmmReady (NULL, NULL);
+ //
+ // Init the communicate buffer. The buffer data size is:
+ //
+ InitCommunicateBuffer (NULL, 0, SMM_HECI_MESSAGE_END_OF_POST);
+ //
+ // Send data to SMM.
+ //
+ SendCommunicateBuffer (0);
+ }
+
+ gBS->CloseEvent (Event);
+}
+
+
+VOID
+EFIAPI
+HeciSmmEndOfDXEEvent (
+ IN EFI_EVENT Event,
+ IN VOID* Context
+ )
+{
+ UINT32 SecMode;
+
+ SecMode = HeciPciRead32 (R_SEC_FW_STS0);
+ if (SEC_MODE_NORMAL == (SecMode & 0xF0000)) {
+ HeciSmmReady (NULL, NULL);
+ }
+
+ gBS->CloseEvent (Event);
+}
+
+
+/**
+ Event handle for Exit boot services
+
+ @param[in] Event
+ @param[in] ParentImageHandle
+
+**/
+VOID
+EFIAPI
+HeciSmmEndOfServicesEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UINT32 SecMode;
+
+ SecMode = HeciPciRead32 (R_SEC_FW_STS0);
+ if (SEC_MODE_NORMAL == (SecMode & 0xF0000)) {
+ //
+ // Init the communicate buffer. The buffer data size is:
+ //
+ InitCommunicateBuffer (NULL, 0, SMM_HECI_MESSAGE_END_OF_SERVICES);
+ //
+ // Send data to SMM.
+ //
+ SendCommunicateBuffer (0);
+ PutDeviceIntoD0I3 ();
+ }
+
+ gBS->CloseEvent (Event);
+}
+
+
+/**
+ Variable Driver main entry point. The Variable driver places the 4 EFI
+ runtime services in the EFI System Table and installs arch protocols
+ for variable read and write services being available. It also registers
+ a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS Variable service successfully initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+HeciSmmRuntimeDxeInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+ EFI_EVENT EndOfDxeEvent;
+ VOID *RegistrationLocal;
+
+ //
+ // Create event
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HeciSmmEndOfDXEEvent,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &EndOfDxeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HeciSmmEndOfPostEvent,
+ (VOID *) NULL,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register for an installation of protocol interface
+ //
+ Status = gBS->RegisterProtocolNotify (
+ &gEfiCseEndofPostGuid,
+ Event,
+ &RegistrationLocal
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Create event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HeciSmmEndOfServicesEvent,
+ (VOID *) NULL,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register for an installation of protocol interface
+ //
+ Status = gBS->RegisterProtocolNotify (
+ &gEfiCseEndofServicesGuid,
+ Event,
+ &RegistrationLocal
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register the event to convert the pointer for runtime.
+ //
+ gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AddressChangeEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mVirtualAddressChangeEvent
+ );
+ //
+ // Allocate memory for variable communicate buffer.
+ //
+ mHeciBufferSize = sizeof (SMM_HECI_COMMUNICATE_HEADER) + MAX_HECI_BUFFER_SIZE;
+ mHeciBuffer = AllocateRuntimePool (mHeciBufferSize);
+ ASSERT (mHeciBuffer != NULL);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmmRuntimeDxe.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmmRuntimeDxe.inf new file mode 100644 index 0000000000..ec617b503b --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmmRuntimeDxe.inf @@ -0,0 +1,57 @@ +## @file
+# HECI Smm Runtime Dxe driver Module.
+#
+# Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = HeciSmmRuntimeDxe
+ FILE_GUID = 97B53FD2-A84C-4469-803F-A16D13AF1479
+ VERSION_STRING = 1.0
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ ENTRY_POINT = HeciSmmRuntimeDxeInitialize
+
+[Sources]
+ HeciSmmRuntimeDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ BroxtonSiPkg/BroxtonSiPkg.dec
+
+[LibraryClasses]
+ SeCLib
+ UefiBootServicesTableLib
+ DebugLib
+ PciLib
+ BaseLib
+ DxeServicesTableLib
+ MemoryAllocationLib
+ S3BootScriptLib
+ UefiDriverEntryPoint
+ HeciMsgLib
+ UefiRuntimeLib
+ SideBandLib
+
+[Protocols]
+ gEfiHeciSmmRuntimeProtocolGuid ## PRODUCES
+ gEfiHeciSmmProtocolGuid ## PRODUCES
+ gEfiSmmCommunicationProtocolGuid ## CONSUMES
+
+[Guids]
+ gEfiEventVirtualAddressChangeGuid ## UNDEFINED
+ gEfiCseEndofPostGuid
+ gEfiCseEndofServicesGuid
+ gEfiEndOfDxeEventGroupGuid
+
+[Depex]
+ TRUE
|