/** @file This is the Common driver that initializes the Intel PCH. Copyright (c) 2017, 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 that 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 "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")); }