From 8c6ef49737df896a55d47c5ee16bf5e6932fef6a Mon Sep 17 00:00:00 2001 From: Guo Mang Date: Fri, 23 Dec 2016 13:07:00 +0800 Subject: BroxtonSiPkg: Add Heci Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang --- .../BroxtonSoC/BroxtonSiPkg/Txe/Heci/Dxe/Hecidrv.c | 340 +++++ .../BroxtonSoC/BroxtonSiPkg/Txe/Heci/Dxe/Hecidrv.h | 60 + .../BroxtonSiPkg/Txe/Heci/Dxe/Hecidrv.inf | 67 + .../BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmm.c | 1373 ++++++++++++++++++++ .../BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmm.h | 61 + .../BroxtonSiPkg/Txe/Heci/Smm/HeciSmm.inf | 59 + .../BroxtonSiPkg/Txe/Heci/Smm/HeciSmmRuntimeDxe.c | 777 +++++++++++ .../Txe/Heci/Smm/HeciSmmRuntimeDxe.inf | 57 + 8 files changed, 2794 insertions(+) create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Dxe/Hecidrv.c create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Dxe/Hecidrv.h create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Dxe/Hecidrv.inf create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmm.c create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmm.h create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmm.inf create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmmRuntimeDxe.c create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Txe/Heci/Smm/HeciSmmRuntimeDxe.inf (limited to 'Silicon/BroxtonSoC') 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.
+ + 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 +#include "Hecidrv.h" +#include +#include +#include +#include +#include +#include + +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.
+ + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Driver Produced Protocol Prototypes +// +#include +#include +#include +#include + +#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.
+# +# 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.
+ + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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.
+ + 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.
+# +# 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.
+ + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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.
+# +# 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 -- cgit v1.2.3