/** @file This is the Common driver that initializes the Intel PCH. Copyright (c) 2017, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "PchInit.h" // // Module variables // GLOBAL_REMOVE_IF_UNREFERENCED PCH_CONFIG_HOB *mPchConfigHob; GLOBAL_REMOVE_IF_UNREFERENCED SI_CONFIG_HOB *mSiConfigHob; /** Common PchInit Module Entry Point **/ VOID PchInitEntryPointCommon ( VOID ) { EFI_PEI_HOB_POINTERS HobPtr; DEBUG ((DEBUG_INFO, "PchInitEntryPointCommon() Start\n")); // // Get PCH Config HOB. // HobPtr.Guid = GetFirstGuidHob (&gPchConfigHobGuid); ASSERT (HobPtr.Guid != NULL); mPchConfigHob = (PCH_CONFIG_HOB *) GET_GUID_HOB_DATA (HobPtr.Guid); // // Get Silicon Config data HOB // HobPtr.Guid = GetFirstGuidHob (&gSiConfigHobGuid); ASSERT (HobPtr.Guid != NULL); mSiConfigHob = (SI_CONFIG_HOB *) GET_GUID_HOB_DATA (HobPtr.Guid); DEBUG ((DEBUG_INFO, "PchInitEntryPointCommon() End\n")); return; } /** Lock USB registers before boot @param[in] PchConfigHob The PCH Config HOB **/ VOID LockXhciConfiguration ( IN CONST PCH_CONFIG_HOB *PchConfigHob ) { UINTN XhciPciMmBase; UINT32 XhccCfg; DEBUG ((DEBUG_INFO, "LockXhciConfiguration () - Start\n")); XhciPciMmBase = MmPciBase ( DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_XHCI, PCI_FUNCTION_NUMBER_PCH_XHCI ); /// /// PCH BIOS Spec Section 13.2.4 Locking xHCI Register Settings /// PCH BIOS Spec Locking xHCI Register settings /// After xHCI is initialized, BIOS should lock the xHCI configuration registers to RO. /// This prevent any unintended changes. There is also a lockdown feature for OverCurrent /// registers. BIOS should set these bits to lock down the settings prior to end of POST. /// 1. Set Access Control bit at XHCI PCI offset 40h[31] to 1b to lock xHCI register settings. /// 2. Set OC Configuration Done bit at XHCI PCI offset 44h[31] to lock overcurrent mappings from /// further changes. /// MmioOr32 (XhciPciMmBase + R_PCH_XHCI_XHCC2, (UINT32) (BIT31)); S3BootScriptSaveMemWrite ( S3BootScriptWidthUint32, (UINTN) (XhciPciMmBase + R_PCH_XHCI_XHCC2), 1, (VOID *) (UINTN) (XhciPciMmBase + R_PCH_XHCI_XHCC2) ); /// /// PCH BIOS Spec xHCI controller setup /// Note: /// XHCI PCI offset 40h is write once register. /// Unsupported Request Detected bit is write clear /// XhccCfg = MmioRead32 (XhciPciMmBase + R_PCH_XHCI_XHCC1); XhccCfg &= (UINT32) ~(B_PCH_XHCI_XHCC1_URD); XhccCfg |= (UINT32) (B_PCH_XHCI_XHCC1_ACCTRL); MmioWrite32 (XhciPciMmBase + R_PCH_XHCI_XHCC1, XhccCfg); S3BootScriptSaveMemWrite ( S3BootScriptWidthUint32, (UINTN) (XhciPciMmBase + R_PCH_XHCI_XHCC1), 1, (VOID *) (UINTN) (XhciPciMmBase + R_PCH_XHCI_XHCC1) ); DEBUG ((DEBUG_INFO, "LockXhciConfiguration () - End\n")); } /** Process all the lock downs **/ VOID ProcessAllLocks ( VOID ) { UINTN Index; UINT8 Data8; UINT16 Data16And; UINT16 Data16Or; UINT32 Data32; UINT32 Data32And; UINT32 Data32Or; UINT32 DlockValue; UINTN PciLpcRegBase; UINTN PciSpiRegBase; UINTN PciPmcRegBase; UINT16 TcoBase; UINT32 PchPwrmBase; UINTN PchSpiBar0; PciLpcRegBase = MmPciBase ( DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPC, PCI_FUNCTION_NUMBER_PCH_LPC ); PciPmcRegBase = MmPciBase ( DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_PMC, PCI_FUNCTION_NUMBER_PCH_PMC ); PciSpiRegBase = MmPciBase ( DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_SPI, PCI_FUNCTION_NUMBER_PCH_SPI ); PchSpiBar0 = MmioRead32 (PciSpiRegBase + R_PCH_SPI_BAR0) &~(B_PCH_SPI_BAR0_MASK); PchTcoBaseGet (&TcoBase); // // Lock XHCI configuration // LockXhciConfiguration (mPchConfigHob); /// /// Set PWRMBASE + 620h [31] to lock the ST and NST PG register fields. /// ConfigurePmcStaticFunctionDisableLock (); /// /// SKL PCH BWG 7.2.4 Additional PCH DMI and OP-DMI Programming Steps /// Step 9.2 /// Set PCR[DMI] + 2234h [31] = 1b. /// Leave this in DXE since setting it in PEI would break the ActiveBIOS module. /// Data32And = 0xFFFFFFFF; Data32Or = B_PCH_PCR_DMI_DMIC_SRL; PchPcrAndThenOr32 ( PID_DMI, R_PCH_PCR_DMI_DMIC, Data32And, Data32Or ); PCH_PCR_BOOT_SCRIPT_READ_WRITE ( S3BootScriptWidthUint32, PID_DMI, R_PCH_PCR_DMI_DMIC, &Data32Or, &Data32And ); /// /// Program the Flash Protection Range Register based on policy /// DlockValue = MmioRead32 (PchSpiBar0 + R_PCH_SPI_DLOCK); for (Index = 0; Index < PCH_FLASH_PROTECTED_RANGES; ++Index) { if ((mPchConfigHob->ProtectRange[Index].WriteProtectionEnable || mPchConfigHob->ProtectRange[Index].ReadProtectionEnable) != TRUE) { continue; } /// /// Proceed to program the register after ensure it is enabled /// Data32 = 0; Data32 |= (mPchConfigHob->ProtectRange[Index].WriteProtectionEnable == TRUE) ? B_PCH_SPI_PRX_WPE : 0; Data32 |= (mPchConfigHob->ProtectRange[Index].ReadProtectionEnable == TRUE) ? B_PCH_SPI_PRX_RPE : 0; Data32 |= ((UINT32) mPchConfigHob->ProtectRange[Index].ProtectedRangeLimit << N_PCH_SPI_PRX_PRL) & B_PCH_SPI_PRX_PRL_MASK; Data32 |= ((UINT32) mPchConfigHob->ProtectRange[Index].ProtectedRangeBase << N_PCH_SPI_PRX_PRB) & B_PCH_SPI_PRX_PRB_MASK; DEBUG ((DEBUG_INFO, "Protected range %d: 0x%08x \n", Index, Data32)); DlockValue |= (UINT32) (B_PCH_SPI_DLOCK_PR0LOCKDN << Index); MmioWrite32 ((UINTN) (PchSpiBar0 + (R_PCH_SPI_PR0 + (Index * S_PCH_SPI_PRX))), Data32); S3BootScriptSaveMemWrite ( S3BootScriptWidthUint32, (UINTN) (PchSpiBar0 + (R_PCH_SPI_PR0 + (Index * S_PCH_SPI_PRX))), 1, (VOID *) (UINTN) (PchSpiBar0 + (R_PCH_SPI_PR0 + (Index * S_PCH_SPI_PRX))) ); } // // Program DLOCK register // MmioWrite32 ((UINTN) (PchSpiBar0 + R_PCH_SPI_DLOCK), DlockValue); S3BootScriptSaveMemWrite ( S3BootScriptWidthUint32, (UINTN) (PchSpiBar0 + R_PCH_SPI_DLOCK), 1, (VOID *) (UINTN) (PchSpiBar0 + R_PCH_SPI_DLOCK) ); /// /// PCH BIOS Spec Section 3.6 Flash Security Recommendation /// In PCH SPI controller the BIOS should set the Flash Configuration Lock-Down bit /// (SPI_BAR0 + 04[15]) at end of post. When set to 1, those Flash Program Registers /// that are locked down by this FLOCKDN bit cannot be written. /// Please refer to the EDS for which program registers are impacted. /// MmioOr32 ((UINTN) (PchSpiBar0 + R_PCH_SPI_HSFSC), (UINT32) (B_PCH_SPI_HSFSC_FLOCKDN)); S3BootScriptSaveMemWrite ( S3BootScriptWidthUint32, (UINTN) (PchSpiBar0 + R_PCH_SPI_HSFSC), 1, (VOID *) (UINTN) (PchSpiBar0 + R_PCH_SPI_HSFSC) ); /// /// SPI Flash Programming Guide Section 5.5.2 Vendor Component Lock /// It is strongly recommended that BIOS sets the Vendor Component Lock (VCL) bits. VCL applies /// the lock to both VSCC0 and VSCC1 even if VSCC0 is not used. Without the VCL bits set, it is /// possible to make Host/GbE VSCC register(s) changes in that can cause undesired host and /// integrated GbE Serial Flash functionality. /// MmioOr32 ((UINTN) (PchSpiBar0 + R_PCH_SPI_SFDP0_VSCC0), B_PCH_SPI_SFDP0_VSCC0_VCL); S3BootScriptSaveMemWrite ( S3BootScriptWidthUint32, (UINTN) (PchSpiBar0 + R_PCH_SPI_SFDP0_VSCC0), 1, (VOID *) (UINTN) (PchSpiBar0 + R_PCH_SPI_SFDP0_VSCC0) ); /// /// Additional Power Management Programming /// Step 3 /// Set GEN_PMCON_LOCK register, PMC PCI offset A6h = 06h, after stretch and ACPI base programming completed. /// MmioOr8 ( (UINTN) (PciPmcRegBase + R_PCH_PMC_GEN_PMCON_B + 2), (UINT8) ((B_PCH_PMC_GEN_PMCON_B_SLPSX_STR_POL_LOCK | B_PCH_PMC_GEN_PMCON_B_ACPI_BASE_LOCK) >> 16) ); S3BootScriptSaveMemWrite ( S3BootScriptWidthUint8, (UINTN) (PciPmcRegBase + R_PCH_PMC_GEN_PMCON_B + 2), 1, (VOID *) (UINTN) (PciPmcRegBase + R_PCH_PMC_GEN_PMCON_B + 2) ); /// /// PCH BIOS Spec Section 3.6 Flash Security Recommendation /// BIOS needs to enable the BIOS Lock Enable (BLE) feature of the PCH by setting /// SPI/eSPI/LPC PCI offset DCh[1] = 1b. /// When this bit is set, attempts to write the BIOS Write Enable (BIOSWE) bit /// in PCH will cause a SMI which will allow the BIOS to verify that the write is /// from a valid source. /// Remember that BIOS needs to set SPI/LPC/eSPI PCI Offset DC [0] = 0b to enable /// BIOS region protection before exiting the SMI handler. /// Also, TCO_EN bit needs to be set (SMI_EN Register, ABASE + 30h[13] = 1b) to keep /// BLE feature enabled after booting to the OS. /// Intel requires that BIOS enables the Lock Enable (LE) feature of the PCH to /// ensure SMM protection of flash. /// Left to platform code to register a callback function to handle BiosWp SMI /// if (mPchConfigHob->LockDown.BiosLock == TRUE) { // // eSPI/LPC // if (! (MmioRead8 (PciLpcRegBase + R_PCH_LPC_BC) & B_PCH_LPC_BC_LE)) { DEBUG ((DEBUG_INFO, "Set LPC bios lock\n")); MmioOr8 ((UINTN) (PciLpcRegBase + R_PCH_LPC_BC), B_PCH_LPC_BC_LE); S3BootScriptSaveMemWrite ( S3BootScriptWidthUint8, (UINTN) (PciLpcRegBase + R_PCH_LPC_BC), 1, (VOID *) (UINTN) (PciLpcRegBase + R_PCH_LPC_BC) ); } // // SPI // if (! (MmioRead8 (PciSpiRegBase + R_PCH_SPI_BC) & B_PCH_SPI_BC_LE)) { DEBUG ((DEBUG_INFO, "Set SPI bios lock\n")); MmioOr8 ((UINTN) (PciSpiRegBase + R_PCH_SPI_BC), (UINT8) B_PCH_SPI_BC_LE); S3BootScriptSaveMemWrite ( S3BootScriptWidthUint8, (UINTN) (PciSpiRegBase + R_PCH_SPI_BC), 1, (VOID *) (UINTN) (PciSpiRegBase + R_PCH_SPI_BC) ); } } /// /// PCH BIOS Spec Section 3.6 Flash Security Recommendation /// BIOS also needs to set the BIOS Interface Lock Down bit in multiple locations /// (PCR[DMI] + 274Ch[0], LPC/eSPI PCI offset DCh[7] and SPI PCI offset DCh[7]). /// Setting these bits will prevent writes to the Top Swap bit (under their respective locations) /// and the Boot BIOS Straps. Enabling this bit will mitigate malicious software /// attempts to replace the system BIOS option ROM with its own code. /// if (mPchConfigHob->LockDown.BiosInterface == TRUE) { /// /// LPC /// MmioOr8 ((UINTN) (PciLpcRegBase + R_PCH_LPC_BC), (UINT32) B_PCH_LPC_BC_BILD); S3BootScriptSaveMemWrite ( S3BootScriptWidthUint8, (UINTN) (PciLpcRegBase + R_PCH_LPC_BC), 1, (VOID *) (UINTN) (PciLpcRegBase + R_PCH_LPC_BC) ); /// /// Reads back for posted write to take effect /// Data8 = MmioRead8 ((UINTN) (PciLpcRegBase + R_PCH_LPC_BC)); S3BootScriptSaveMemPoll ( S3BootScriptWidthUint8, (UINTN) (PciLpcRegBase + R_PCH_LPC_BC), &Data8, // BitMask &Data8, // BitValue 1, // Duration 1 // LoopTimes ); /// /// SPI /// MmioOr8 ((UINTN) (PciSpiRegBase + R_PCH_SPI_BC), (UINT32) B_PCH_SPI_BC_BILD); S3BootScriptSaveMemWrite ( S3BootScriptWidthUint8, (UINTN) (PciSpiRegBase + R_PCH_SPI_BC), 1, (VOID *) (UINTN) (PciSpiRegBase + R_PCH_SPI_BC) ); /// /// Reads back for posted write to take effect /// Data8 = MmioRead8 ((UINTN) (PciSpiRegBase + R_PCH_SPI_BC)); S3BootScriptSaveMemPoll ( S3BootScriptWidthUint8, (UINTN) (PciSpiRegBase + R_PCH_SPI_BC), &Data8, // BitMask &Data8, // BitValue 1, // Duration 1 // LoopTimes ); /// /// Set PCR[DMI] + 274C[0] = 1b /// Data32And = 0xFFFFFFFF; Data32Or = B_PCH_PCR_DMI_BILD; PchPcrAndThenOr32 (PID_DMI, R_PCH_PCR_DMI_GCS, Data32And, Data32Or); PCH_PCR_BOOT_SCRIPT_READ_WRITE ( S3BootScriptWidthUint32, PID_DMI, R_PCH_PCR_DMI_GCS, &Data32Or, &Data32And ); } /// /// PCH BIOS Spec Section 5.13 BIOS guide on using RTC RAM /// For Data integrity protection, set RTC Memory locks (Upper 128 Byte Lock and /// Lower 128 Byte Lock) at SBCR[RTC] + 3400h[4] and SBCR[RTC] + 3400h[3]. Note once locked /// bytes 0x38 - 0x3F in each of the Upper and Lower Byte blocks, respectively, /// cannot be unlocked until next reset. /// if (mPchConfigHob->LockDown.RtcLock == TRUE) { Data32And = 0xFFFFFFFF; Data32Or = (B_PCH_PCR_RTC_CONF_UCMOS_LOCK | B_PCH_PCR_RTC_CONF_LCMOS_LOCK | B_PCH_PCR_RTC_CONF_RESERVED); PchPcrAndThenOr32 ( PID_RTC, R_PCH_PCR_RTC_CONF, Data32And, Data32Or ); PCH_PCR_BOOT_SCRIPT_READ_WRITE ( S3BootScriptWidthUint32, PID_RTC, R_PCH_PCR_RTC_CONF, &Data32Or, &Data32And ); } /// /// Lock Down TCO /// Data16And = 0xFFFF; Data16Or = B_PCH_TCO_CNT_LOCK; IoOr16 (TcoBase + R_PCH_TCO1_CNT, Data16Or); S3BootScriptSaveIoReadWrite ( S3BootScriptWidthUint16, (UINTN) (TcoBase + R_PCH_TCO1_CNT), &Data16Or, // Data to be ORed &Data16And // Data to be ANDed ); /// /// PCH BIOS Spec Section 5.15.1 Additional Chipset Initialization /// Step 1 /// Set SPIBAR0 + F0h [0] to 1b /// MmioOr8 ((UINTN) (PchSpiBar0 + R_PCH_SPI_SSML), B_PCH_SPI_SSML_SSL); // // Lock Down PMC // Set PWRM + 0x18 [27, 22] prior to OS. // PchPwrmBaseGet (&PchPwrmBase); Data32Or = BIT27; if (mPchConfigHob->Pm.PmcReadDisable) { Data32Or |= BIT22; } MmioOr32 (PchPwrmBase + R_PCH_PWRM_CFG, Data32Or); S3BootScriptSaveMemWrite ( S3BootScriptWidthUint32, (UINTN) (PchPwrmBase + R_PCH_PWRM_CFG), 1, (VOID *) (UINTN) (PchPwrmBase + R_PCH_PWRM_CFG) ); } /** Set eSPI BME bit **/ VOID ConfigureEspiBme ( VOID ) { } /** Common PCH initialization before Boot Sript Table is closed **/ VOID PchOnPciEnumCompleteCommon ( VOID ) { UINT32 Data32Or; UINT32 Data32And; DEBUG ((DEBUG_INFO, "PchOnPciEnumCompleteCommon() Start\n")); ProcessAllLocks (); /// /// Perform remaining configuration for PCH SATA on End of DXE /// ConfigurePchSataOnEndOfDxe (); /// /// PSTHCTL (0xD00h[2]) = 1, PSTH IOSF Primary Trunk Clock Gating Enable (PSTHIOSFPTCGE) /// Data32And = 0xFFFFFFFF; Data32Or = B_PCH_PCR_PSTH_PSTHIOSFPTCGE; PchPcrAndThenOr32 (PID_PSTH, R_PCH_PCR_PSTH_PSTHCTL, Data32And, Data32Or); PCH_PCR_BOOT_SCRIPT_READ_WRITE ( S3BootScriptWidthUint32, PID_PSTH, R_PCH_PCR_PSTH_PSTHCTL, &Data32Or, &Data32And ); // // Set eSPI BME after PCI enumeration // ConfigureEspiBme (); // // This function process P2SB configuration // This MUST be executed in very end of End Of Dxe // All PSF access after this function will not acceptable // ConfigureP2sbSbiLock ((BOOLEAN) mPchConfigHob->P2sb.SbiUnlock); DEBUG ((DEBUG_INFO, "PchOnPciEnumCompleteCommon() End\n")); }