diff options
Diffstat (limited to 'ReferenceCode/Haswell/CpuInit/Dxe/Features.c')
-rw-r--r-- | ReferenceCode/Haswell/CpuInit/Dxe/Features.c | 1093 |
1 files changed, 1093 insertions, 0 deletions
diff --git a/ReferenceCode/Haswell/CpuInit/Dxe/Features.c b/ReferenceCode/Haswell/CpuInit/Dxe/Features.c new file mode 100644 index 0000000..2561850 --- /dev/null +++ b/ReferenceCode/Haswell/CpuInit/Dxe/Features.c @@ -0,0 +1,1093 @@ +/** @file + CPU feature control module + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ +#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) +#include "EdkIIGlueDxe.h" +#include "CpuInitDxe.h" +#include "Features.h" +#include "MachineCheck.h" +#include "Mpcommon.h" +#include "CpuPlatformLib.h" +#endif + +extern DXE_CPU_PLATFORM_POLICY_PROTOCOL *mPlatformCpu; + +UINT8 mFeatureLock; +UINTN mCommonFeatures; +UINTN mSetupFeatures; + +static UINT8 mLock; +static LEAST_FEATURE_PROC mLeastFeatureProcessor; + +/** + Write 64bits MSR with script + + @param[in] Index - MSR index that will be written + @param[in] Value - value written to MSR +**/ +VOID +AsmWriteMsr64WithScript ( + IN UINT32 Index, + IN UINT64 Value + ) +{ + AsmWriteMsr64 (Index, Value); + WriteMsr64ToScript (Index, Value); +} + +/** + Write 64bits MSR to script + + @param[in] Index - MSR index that will be written + @param[in] Value - value written to MSR +**/ +VOID +WriteMsr64ToScript ( + IN UINT32 Index, + IN UINT64 Value + ) +{ + UINTN TableIndex; + + ASSERT (mMPSystemData != NULL); + + /// + /// Save it into script + /// + AsmAcquireMPLock (&(mMPSystemData->S3BootScriptLock)); + TableIndex = mMPSystemData->S3BootScriptCount++; + AsmReleaseMPLock (&(mMPSystemData->S3BootScriptLock)); + + ASSERT (TableIndex < MAX_CPU_S3_TABLE_SIZE - 1); + mMPSystemData->S3BootScriptTable[TableIndex].ApicId = GetApicID (NULL, NULL); + mMPSystemData->S3BootScriptTable[TableIndex].MsrIndex = Index; + mMPSystemData->S3BootScriptTable[TableIndex].MsrValue = Value; +} + +/** + Provide access to the CPU misc enables MSR + + @param[in] Enable - Enable or Disable Misc Features + @param[in] BitMask - The register bit offset of MSR MSR_IA32_MISC_ENABLE +**/ +VOID +CpuMiscEnable ( + BOOLEAN Enable, + UINT64 BitMask + ) +{ + UINT64 MsrValue; + + MsrValue = AsmReadMsr64 (MSR_IA32_MISC_ENABLE); + if (Enable) { + MsrValue |= BitMask; + } else { + MsrValue &= ~BitMask; + } + + AsmWriteMsr64 (MSR_IA32_MISC_ENABLE, MsrValue); +} + +/** + Calculate how many bits are one from given number + + @param[in] Value - number that will be calculated bits + + @retval Number of bits +**/ +UINT32 +GetBitsNumberOfOne ( + UINT32 Value + ) +{ + UINT32 Result; + + Result = 0; + while (Value) { + if (Value & 1) { + Result++; + } + Value >>= 1; + } + return Result; +} + +/// +/// DCA contains processor code and chipset code +/// CPU driver has the following assumption on the initialization flow +/// 1. Chipset pre-initialization should detect DCA support per chipset capability after CpuPlatformPolicy +/// 2. If not support, it should update CpuPlatformPolicy DCA to disable state +/// 3. If support, it should enable the DCA related registers +/// 4. CPU initialization for DCA (CPU may change CpuPlatformPolicy DCA states per CPU capability) +/// 5. Normal chipset driver (IOH) should look at CpuPlatformPolicy DCA policy again in PCI enumeratoin +/// 6. Chipset enable or disable DCA according to CpuPlatformPolicy DCA state +/// +/** + Detect DCA supported or not + + @retval DCA_SUPPORT if supported or 0 if not supported +**/ +UINTN +IsDcaSupported ( + VOID + ) +{ + EFI_CPUID_REGISTER CpuidRegisters; + BOOLEAN Support; + + Support = 0; + AsmCpuid ( + CPUID_VERSION_INFO, + &CpuidRegisters.RegEax, + &CpuidRegisters.RegEbx, + &CpuidRegisters.RegEcx, + &CpuidRegisters.RegEdx + ); + if ((CpuidRegisters.RegEcx & B_CPUID_VERSION_INFO_ECX_DCA) != 0) { + /// + /// Execute Disable Bit feature is not supported on this processor. + /// + Support = DCA_SUPPORT; + } + return Support; +} + +/** + Detect HT supported or not + + @retval HT_SUPPORT if supported or 0 if not supported +**/ +UINTN +IsHTSupported ( + VOID + ) +{ + EFI_CPUID_REGISTER CpuidRegisters; + UINTN Support; + + Support = 0; + + AsmCpuidEx ( + CPUID_CORE_TOPOLOGY, + 0, + &CpuidRegisters.RegEax, + &CpuidRegisters.RegEbx, + &CpuidRegisters.RegEcx, + &CpuidRegisters.RegEdx + ); + if ((CpuidRegisters.RegEbx & 0x00FF) == 2) { + Support = HT_SUPPORT; + } + return Support; + +} + +/** + Detect if AES supported or not + + @retval AES_SUPPORT if supported or 0 if not supported +**/ +UINTN +IsAesSupported ( + VOID + ) +{ + + EFI_CPUID_REGISTER CpuidRegisters; + UINTN Support; + + Support = 0; + EfiCpuid (CPUID_VERSION_INFO, &CpuidRegisters); + if ((CpuidRegisters.RegEcx & B_CPUID_VERSION_INFO_ECX_AES) != 0) { + Support = AES_SUPPORT; + } + return Support; +} + +/** + Detect if XD supported or not + + @retval XD_SUPPORT if supported or 0 if not supported +**/ +UINTN +IsXdSupported ( + VOID + ) +{ + EFI_CPUID_REGISTER CpuidRegisters; + BOOLEAN Support; + + Support = 0; + AsmCpuid ( + CPUID_EXTENDED_FUNCTION, + &CpuidRegisters.RegEax, + &CpuidRegisters.RegEbx, + &CpuidRegisters.RegEcx, + &CpuidRegisters.RegEdx + ); + if (CpuidRegisters.RegEax > CPUID_EXTENDED_FUNCTION) { + AsmCpuid ( + CPUID_EXTENDED_CPU_SIG, + &CpuidRegisters.RegEax, + &CpuidRegisters.RegEbx, + &CpuidRegisters.RegEcx, + &CpuidRegisters.RegEdx + ); + if ((CpuidRegisters.RegEdx & B_CPUID_VERSION_INFO_EDX_XD) != 0) { + /// + /// Execute Disable Bit feature is not supported on this processor. + /// + Support = XD_SUPPORT; + } + } + return Support; +} + +/** + Enable XD if supported or disable it if not supported + + @param[in] Support - bitmap that indicate XD supported or not +**/ +VOID +EnableDisableXd ( + IN UINTN Support + ) +{ + BOOLEAN XdSupport; + + if ((mCommonFeatures & XD_SUPPORT) == 0) { + return; + } + XdSupport = (BOOLEAN)((Support & XD_SUPPORT) == XD_SUPPORT); + /// + /// MSR MISC_ENABLE[34] has negative logic: 0 - XD Enabled, 1 - XD Disabled + /// + CpuMiscEnable (!XdSupport, B_MSR_IA32_MISC_ENABLE_XD); +} + +/** + Check on the processor if VMX/TXT is supported. + + @retval VMX_SUPPORT and TXT_SUPPORT if supported or 0 if not supported +**/ +UINTN +IsVmxSupported ( + VOID + ) +{ + EFI_CPUID_REGISTER CpuIdRegister; + UINTN Support; + + Support = 0; + + /// + /// Get CPUID to check if the processor supports Vanderpool Technology. + /// + AsmCpuid ( + CPUID_VERSION_INFO, + &CpuIdRegister.RegEax, + &CpuIdRegister.RegEbx, + &CpuIdRegister.RegEcx, + &CpuIdRegister.RegEdx + ); + if ((CpuIdRegister.RegEcx & B_CPUID_VERSION_INFO_ECX_VME) != 0) { + /// + /// VT is supported. + /// + Support |= VMX_SUPPORT; + } + if ((CpuIdRegister.RegEcx & B_CPUID_VERSION_INFO_ECX_SME) != 0) { + /// + /// TXT is supported. + /// + Support |= TXT_SUPPORT; + } + return Support; +} + +/** + Enable VMX/TXT on the processor. + + @param[in] Support - To enable or disable VMX/TXT feature. +**/ +VOID +EnableDisableVmx ( + IN UINTN Support + ) +{ + UINT64 Ia32FeatCtrl; + UINT64 NewFeatCtrl; + + Ia32FeatCtrl = AsmReadMsr64 (MSR_IA32_FEATURE_CONTROL); + Ia32FeatCtrl &= ~((UINT64) OPTION_FEATURE_RESERVED_MASK); + + NewFeatCtrl = Ia32FeatCtrl; + + /// + /// If Vmx is Disabled, Enable it. + /// + if (mCommonFeatures & VMX_SUPPORT) { + if (Support & VMX_SUPPORT) { + NewFeatCtrl |= B_MSR_IA32_FEATURE_CONTROL_EVT; + } else { + NewFeatCtrl &= ~B_MSR_IA32_FEATURE_CONTROL_EVT; + } + } + if (mCommonFeatures & TXT_SUPPORT) { + if (Support & TXT_SUPPORT) { + /// + /// MSR Lock will be done in later. + /// + NewFeatCtrl |= (B_MSR_IA32_FEATURE_CONTROL_SLFE | B_MSR_IA32_FEATURE_CONTROL_SGE); + if (mCommonFeatures & VMX_SUPPORT) { + /// + /// Bit [1] can only be set if CPU is both VMX and TXT capable + /// + NewFeatCtrl |= B_MSR_IA32_FEATURE_CONTROL_ELT; + } + } else { + NewFeatCtrl &= ~(B_MSR_IA32_FEATURE_CONTROL_ELT | B_MSR_IA32_FEATURE_CONTROL_SLFE | B_MSR_IA32_FEATURE_CONTROL_SGE); + } + } + + /// + /// Check the Feature Lock Bit. + /// If it is already set, which indicates we are executing POST + /// due to a warm RESET (i.e., PWRGOOD was not de-asserted). + /// + if ((Ia32FeatCtrl & B_MSR_IA32_FEATURE_CONTROL_LOCK) == 0) { + AsmWriteMsr64WithScript (MSR_IA32_FEATURE_CONTROL, NewFeatCtrl); + } else { + /// + /// if Lock bit is set + /// + NewFeatCtrl &= ~(B_MSR_IA32_FEATURE_CONTROL_LOCK); + WriteMsr64ToScript (MSR_IA32_FEATURE_CONTROL, NewFeatCtrl); + } +} + +/** + Enable / Disable AES on the processor. + + @param[in] Support - To enable or disable AES feature. +**/ +VOID +EnableDisableAes ( + IN UINTN Support + ) +{ + UINT64 MsrValue; + + if (!(mCommonFeatures & AES_SUPPORT) || (IsSecondaryThread ())) { + return; + } + + /// + /// The processor was manufacted with AES-NI feature + /// + MsrValue = AsmReadMsr64 (MSR_IA32_FEATURE_CONFIG); + + /// + /// Check the Feature Lock Bit. + /// If it is already set, which indicates we are executing POST + /// due to a warm RESET (i.e., PWRGOOD was not de-asserted). + /// + if ((MsrValue & B_IA32_FEATURE_CONFIG_LOCK) == 0) { + if (Support & AES_SUPPORT) { + /// + /// Enabled AES, writes of 00b, 01b pr 10b to the MSR will result in AES enable. + /// Should lock this MSR always, so write 01b to the MSR. + /// + MsrValue &= ~B_IA32_FEATURE_CONFIG_AES_DIS; + MsrValue |= B_IA32_FEATURE_CONFIG_LOCK; + } else { + /// + /// To disable AES, system BIOS must write 11b to this MSR. + /// + MsrValue |= (B_IA32_FEATURE_CONFIG_AES_DIS + B_IA32_FEATURE_CONFIG_LOCK); + } + AsmWriteMsr64WithScript (MSR_IA32_FEATURE_CONFIG, MsrValue); + } + return; +} + +/** + Check on the processor if Debug Interface is supported. + + @retval DEBUG_SUPPORT and DEBUG_LOCK_SUPPORT if supported or 0 if not supported +**/ +UINTN +IsDebugInterfaceSupported ( + VOID + ) +{ + UINTN Support; + EFI_CPUID_REGISTER CpuIdRegister; + + Support = 0; + + /// + /// Access to MSR_IA32_DEBUG_INTERFACE is supported on: + /// HSW B0, HSWULT B0 and CRW B0 Stepping + /// HSW stepping >= C0, HSWULT Stepping >= C0 and CRW stepping >= C0 stepping, if CPUID (EAX=1): ECX[11] = 1 + /// + AsmCpuid ( + CPUID_VERSION_INFO, + &CpuIdRegister.RegEax, + &CpuIdRegister.RegEbx, + &CpuIdRegister.RegEcx, + &CpuIdRegister.RegEdx + ); + switch (CpuIdRegister.RegEax) { + case (EnumCpuHsw + EnumHswA0): + //DEBUG ((EFI_D_INFO,"MSR_IA32_DEBUG_INTERFACE is not supported on Ax CPU stepping\n")); (AMI_CHG+) + break; + case (EnumCpuHsw + EnumHswB0): + case (EnumCpuHswUlt + EnumHswUltB0): + case (EnumCpuCrw + EnumCrwB0): + Support |= DEBUG_SUPPORT; + Support |= DEBUG_LOCK_SUPPORT; + break; + default: + if (CpuIdRegister.RegEcx & BIT11) { + Support |= DEBUG_SUPPORT; + Support |= DEBUG_LOCK_SUPPORT; + } + break; + } + return Support; +} + +/** + Enable/Disable Debug Interfaces in the processor. + + @param[in] Support - To enable or disable Debug Interface feature. +**/ +VOID +EnableDisableDebugInterface ( + IN UINTN Support + ) +{ + UINT64 Ia32DebugInterface; + BOOLEAN IsBsp; + + /// + /// IA32_DEBUG_INTERFACE_MSR scope is "Package", program on BSP only + /// + IsBsp = (AsmReadMsr64 (MSR_IA32_APIC_BASE) & B_MSR_IA32_APIC_BASE_BSP) ? TRUE : FALSE; + if (!(mCommonFeatures & DEBUG_SUPPORT) || (IsBsp == FALSE)) { + return; + } + + /// + /// Check if the processor supports debug interface + /// + if (IsDebugInterfaceSupported()) { + Ia32DebugInterface = AsmReadMsr64 (MSR_IA32_DEBUG_INTERFACE); + if (!(Ia32DebugInterface & B_DEBUG_INTERFACE_LOCK)) { + if (Support & DEBUG_SUPPORT) { + /// + /// Enable Debug Interface (MSR 0xC80.Bit0 = 1) + /// + Ia32DebugInterface |= B_DEBUG_INTERFACE_ENABLE; + DEBUG ((EFI_D_ERROR, "Enable MSR_IA32_DEBUG_INTERFACE\n")); + } else { + /// + /// Disable Debug Interface (MSR 0xC80.Bit0 = 0) + /// + Ia32DebugInterface &= ~B_DEBUG_INTERFACE_ENABLE; + DEBUG ((EFI_D_ERROR, "Disable MSR_IA32_DEBUG_INTERFACE\n")); + } + if (Support & DEBUG_LOCK_SUPPORT) { + Ia32DebugInterface &= ~B_DEBUG_INTERFACE_LOCK; + } + DEBUG ((EFI_D_ERROR, "Set MSR_IA32_DEBUG_INTERFACE to %x\n",Ia32DebugInterface)); + AsmWriteMsr64WithScript (MSR_IA32_DEBUG_INTERFACE, Ia32DebugInterface); + } + } + return; +} + +/** + Lock VMX/TXT feature bits on the processor. + Set "CFG Lock" (MSR 0E2h Bit[15] + + @param[in] LockFeatureEnable - TRUE to lock these feature bits and FALSE to not lock +**/ +VOID +LockFeatureBit ( + IN BOOLEAN LockFeatureEnable + ) +{ + UINT64 Ia32FeatCtrl; + UINT32 MsrValue; + + if (!LockFeatureEnable) { + return; + } + + /// + /// MSR 3Ah for VMX/TXT Lock + /// + Ia32FeatCtrl = AsmReadMsr64 (MSR_IA32_FEATURE_CONTROL); + Ia32FeatCtrl &= ~((UINT64) OPTION_FEATURE_RESERVED_MASK); + + if ((Ia32FeatCtrl & B_MSR_IA32_FEATURE_CONTROL_LOCK) == 0) { + /// + /// Set Feature Lock bits. + /// + Ia32FeatCtrl |= B_MSR_IA32_FEATURE_CONTROL_LOCK; + AsmWriteMsr64WithScript (MSR_IA32_FEATURE_CONTROL, Ia32FeatCtrl); + } else { + WriteMsr64ToScript (MSR_IA32_FEATURE_CONTROL, Ia32FeatCtrl); + } + + MsrValue = GetCsrDesiredCores (); + if ((MsrValue & BIT16) == 0) { + /// + /// Set Lock + /// + SetLockCsrDesiredCores (); + } + return; +} + +/** + Detect if X2APIC supported or not + + @retval XAPIC_SUPPORT if supported or 0 if not supported +**/ +UINTN +IsXapicSupported ( + VOID + ) +{ + EFI_CPUID_REGISTER CpuidRegisters; + UINTN Support; + UINT64 MsrValue; + + Support = 0; + + MsrValue = AsmReadMsr64 (MSR_IA32_APIC_BASE); + AsmCpuid ( + CPUID_VERSION_INFO, + &CpuidRegisters.RegEax, + &CpuidRegisters.RegEbx, + &CpuidRegisters.RegEcx, + &CpuidRegisters.RegEdx + ); + if ((CpuidRegisters.RegEcx & B_CPUID_VERSION_INFO_ECX_XAPIC) != 0) { + if (MsrValue & B_MSR_IA32_APIC_BASE_G_XAPIC) { + /// + /// XAPIC Mode feature is supported on this processor. + /// + Support = XAPIC_SUPPORT; + } + } + return Support; +} + +/** + Enable / Disable X2APIC on the processor. + + @param[in] Support - To enable or disable X2APIC feature. +**/ +VOID +EnableDisableXAPIC ( + IN UINTN Support + ) +{ + UINT64 MsrValue; + + if (!(mCommonFeatures & XAPIC_SUPPORT)) { + return; + } + MsrValue = AsmReadMsr64 (MSR_IA32_APIC_BASE); + if (Support & XAPIC_SUPPORT) { + MsrValue |= B_MSR_IA32_APIC_BASE_M_XAPIC; + } else { + MsrValue &= ~B_MSR_IA32_APIC_BASE_G_XAPIC; + MsrValue &= ~B_MSR_IA32_APIC_BASE_M_XAPIC; + AsmWriteMsr64 (MSR_IA32_APIC_BASE, MsrValue); + MsrValue |= B_MSR_IA32_APIC_BASE_G_XAPIC; + } + AsmWriteMsr64 (MSR_IA32_APIC_BASE, MsrValue); +} + +/** + Initialize other processor functions (TPR messaging, floating point) +**/ +VOID +InitializeMiscProcessorFunctions ( + VOID + ) +{ + UINT64 MsrValue; + + /// + /// Enable TPR Update messages,if supported (see section 2.5) + /// + MsrValue = AsmReadMsr64 (PIC_THREAD_CONTROL); + MsrValue &= (~B_PIC_THREAD_CONTROL_TPR_DIS); + AsmWriteMsr64WithScript (PIC_THREAD_CONTROL, MsrValue); + + /// + /// Enable the Save Floating Point feature on every logical processors in the + /// platform when available. The BIOS must verify the SMM SAVE CONTROL capability + /// bit is set to 1 in PLATFORM_INFO MSR CEh [16] (see Section 2.16) before setting + /// the SMM_SAVE_CONTROL MSR 3Eh [0] to 1. + /// + MsrValue = AsmReadMsr64 (MSR_PLATFORM_INFO); + if ((MsrValue & B_PLATFORM_INFO_SMM_SAVE_CONTROL) != 0) { + MsrValue = AsmReadMsr64 (MSR_IA32_SMM_SAVE_CONTROL); + MsrValue |= B_MSR_IA32_SMM_SAVE_CONTROL_SFPPE; + AsmWriteMsr64WithScript (MSR_IA32_SMM_SAVE_CONTROL, MsrValue); + } + +} + +/** + Create feature control structure which will be used to program each feature on each core. + + @param[in] MPSystemData - MP_SYSTEM_DATA global variable that contains platform policy protocol settings of each features. +**/ +VOID +InitializeFeaturePerSetup ( + IN MP_SYSTEM_DATA *MPSystemData + ) +{ + mFeatureLock = VacantFlag; + mCommonFeatures = (UINTN) -1; + mSetupFeatures = (UINTN) -1; + + if (!MPSystemData->VmxEnable) { + mSetupFeatures &= ~VMX_SUPPORT; + } + if (!MPSystemData->TxtEnable) { + mSetupFeatures &= ~TXT_SUPPORT; + } + if (!MPSystemData->ExecuteDisableBit) { + mSetupFeatures &= ~XD_SUPPORT; + } + if (!MPSystemData->XapicEnable) { + mSetupFeatures &= ~XAPIC_SUPPORT; + } + if (!MPSystemData->AesEnable) { + mSetupFeatures &= ~AES_SUPPORT; + } + if (!MPSystemData->DebugInterfaceEnable) { + mSetupFeatures &= ~DEBUG_SUPPORT; + } + if (!MPSystemData->DebugInterfaceLockEnable) { + mSetupFeatures &= ~DEBUG_LOCK_SUPPORT; + } +} + +/** + Detect each processor feature and log all supported features + + @param[in] MpServices - EFI_MP_SERVICES_PROTOCOL +**/ +VOID +CollectProcessorFeature ( + IN EFI_MP_SERVICES_PROTOCOL *MpServices + ) +{ + UINTN Support; + + Support = 0; + Support |= IsXdSupported (); + Support |= IsVmxSupported (); + Support |= IsDcaSupported (); + Support |= IsAesSupported (); + Support |= IsXapicSupported (); + Support |= IsHTSupported (); + Support |= IsDebugInterfaceSupported (); + + AsmAcquireMPLock (&mFeatureLock); + mCommonFeatures &= Support; + AsmReleaseMPLock (&mFeatureLock); + + return; +} + +/** + Program all processor features basing on desired settings + + @param[in] MpServices - EFI_MP_SERVICES_PROTOCOL +**/ +VOID +ProgramProcessorFeature ( + IN EFI_MP_SERVICES_PROTOCOL *MpServices + ) +{ + UINTN Supported; + BOOLEAN IsBsp; + + Supported = mCommonFeatures & mSetupFeatures; + + /// + /// Configure features such as Xd, Vmx, Smx, XAPIC, AES, DebugInterface + /// + EnableDisableXd (Supported); + EnableDisableVmx (Supported); + EnableDisableXAPIC (Supported); + EnableDisableAes (Supported); + EnableDisableDebugInterface (Supported); + + /// + /// Lock Proceesor Features + /// Make sure all CPU Features configuration are set before lock + /// + LockFeatureBit (1); + + /// + /// Programe XApic register + /// + IsBsp = (AsmReadMsr64 (MSR_IA32_APIC_BASE) & B_MSR_IA32_APIC_BASE_BSP) ? TRUE : FALSE; + ProgramXApic (IsBsp); + + /// + /// Initialize MonitorMWait register + /// + CpuMiscEnable (mMPSystemData->MonitorMwaitEnable, B_MSR_IA32_MISC_ENABLE_MONITOR); + + /// + /// Initialize Machine Check registers + /// + InitializeMachineCheckRegisters (NULL, mMPSystemData->MachineCheckEnable); + + // + // Misc functions + // + InitializeMiscProcessorFunctions(); + + return; +} + +/** + Program CPUID Limit before booting to OS + + @param[in] MpServices - MP Services Protocol entry +**/ +VOID +ProgramCpuidLimit ( + IN EFI_MP_SERVICES_PROTOCOL *MpServices + ) +{ + UINT64 MsrValue; + + /// + /// Move Limit CPUID Maxval configuration here to not impact the BOOT + /// After setting this, no code can execute CPUID function > 3. + /// + CpuMiscEnable (mMPSystemData->LimitCpuidMaximumValue, B_MSR_IA32_MISC_ENABLE_CPUID_MAX); + + /// + /// Finally record the MISC MSR into CPU S3 script table + /// to avoid access for multiple times + /// + MsrValue = AsmReadMsr64 (MSR_IA32_MISC_ENABLE); + AsmWriteMsr64WithScript (MSR_IA32_MISC_ENABLE, MsrValue); + + return; +} + +/** + Initialize prefetcher settings + + @param[in] MlcStreamerprefecterEnabled - Enable/Disable MLC streamer prefetcher + @param[in] MlcSpatialPrefetcherEnabled - Enable/Disable MLC spatial prefetcher +**/ +VOID +InitializeProcessorsPrefetcher ( + IN UINTN MlcStreamerprefecterEnabled, + IN UINTN MlcSpatialPrefetcherEnabled + ) +{ + UINT64 MsrValue; + MsrValue = AsmReadMsr64 (MISC_FEATURE_CONTROL); + + if (MlcStreamerprefecterEnabled == CPU_FEATURE_DISABLE) { + MsrValue |= B_MISC_FEATURE_CONTROL_MLC_STRP; + } + + if (MlcSpatialPrefetcherEnabled == CPU_FEATURE_DISABLE) { + MsrValue |= B_MISC_FEATURE_CONTROL_MLC_SPAP; + } + + if ((MsrValue & (B_MISC_FEATURE_CONTROL_MLC_STRP | B_MISC_FEATURE_CONTROL_MLC_SPAP)) != 0) { + AsmWriteMsr64 (MISC_FEATURE_CONTROL, MsrValue); + } + + return; +} + +/** + Get processor feature + + @param[in] Features - pointer to a buffer which stores feature information +**/ +VOID +GetProcessorFeatures ( + IN UINT32 *Features + ) +{ + EFI_CPUID_REGISTER CpuidRegisters; + + AsmCpuid ( + CPUID_VERSION_INFO, + &CpuidRegisters.RegEax, + &CpuidRegisters.RegEbx, + &CpuidRegisters.RegEcx, + &CpuidRegisters.RegEdx + ); + Features[0] = CpuidRegisters.RegEcx; + Features[1] = CpuidRegisters.RegEdx; + AsmCpuid ( + CPUID_EXTENDED_CPU_SIG, + &CpuidRegisters.RegEax, + &CpuidRegisters.RegEbx, + &CpuidRegisters.RegEcx, + &CpuidRegisters.RegEdx + ); + Features[2] = CpuidRegisters.RegEax; + Features[3] = CpuidRegisters.RegEbx; + Features[4] = CpuidRegisters.RegEcx; + Features[5] = CpuidRegisters.RegEdx; + + return; +} + +/** + Update some processor info into LEAST_FEATURE_PROC data structure. + + @param[in] Index - indicate which processor calling this routine + @param[in] LeastFeatureProcessor - the data structure that will be updated +**/ +VOID +UpdateProcessorInfo ( + IN UINTN Index, + IN LEAST_FEATURE_PROC *LeastFeatureProcessor + ) +{ + UINT16 FamilyId; + UINT8 Model; + UINT8 SteppingId; + + EfiCpuVersion (&FamilyId, &Model, &SteppingId, NULL); + LeastFeatureProcessor->Index = Index; + LeastFeatureProcessor->ApicId = GetApicID (NULL, NULL); + LeastFeatureProcessor->Version = EfiMakeCpuVersion (FamilyId, Model, SteppingId); +} + +/** + Get processor feature delta + + @param[in] FeaturesInput - Supported features for input processor + @param[in] CommonFeatures - Supported features for processor (subset of FeaturesInput) + + @retval The least of processor features +**/ +UINT32 +GetProcessorFeatureDelta ( + IN UINT32 *FeaturesInput, + IN UINT32 *CommonFeatures + ) +{ + UINT32 Delta; + UINTN Index; + + /// + /// CommonFeatures is the subset of FeaturesInput + /// + Delta = 0; + for (Index = 0; Index < MAX_FEATURE_NUM; Index++) { + Delta += GetBitsNumberOfOne (FeaturesInput[Index] - CommonFeatures[Index]); + } + + return 0; +} + +/** + Find out the common features supported by all core/threads + + @param[in] MpServices - EFI_MP_SERVICES_PROTOCOL +**/ +VOID +GetProcessorCommonFeature ( + IN EFI_MP_SERVICES_PROTOCOL *MpServices + ) +{ + UINTN Index; + UINT32 Features[MAX_FEATURE_NUM]; + + GetProcessorFeatures (Features); + + AsmAcquireMPLock (&mLock); + for (Index = 0; Index < MAX_FEATURE_NUM; Index++) { + mLeastFeatureProcessor.Features[Index] &= Features[Index]; + } + AsmReleaseMPLock (&mLock); + return; +} + +/** + Get the processor data with least features + + @param[in] MpServices - EFI_MP_SERVICES_PROTOCOL +**/ +VOID +GetProcessorWithLeastFeature ( + IN EFI_MP_SERVICES_PROTOCOL *MpServices + ) +{ + EFI_STATUS Status; + UINTN CurrentProcessor; + LEAST_FEATURE_PROC LeastFeatureProcessor; + + Status = MpServices->WhoAmI ( + MpServices, + &CurrentProcessor + ); + if (EFI_ERROR (Status)) { + return; + } + + GetProcessorFeatures (LeastFeatureProcessor.Features); + LeastFeatureProcessor.FeatureDelta = GetProcessorFeatureDelta ( + LeastFeatureProcessor.Features, + mLeastFeatureProcessor.Features + ); + + AsmAcquireMPLock (&mLock); + if (LeastFeatureProcessor.FeatureDelta < mLeastFeatureProcessor.FeatureDelta) { + mLeastFeatureProcessor.FeatureDelta = LeastFeatureProcessor.FeatureDelta; + UpdateProcessorInfo (CurrentProcessor, &mLeastFeatureProcessor); + } else if (LeastFeatureProcessor.FeatureDelta == mLeastFeatureProcessor.FeatureDelta) { + UpdateProcessorInfo (CurrentProcessor, &LeastFeatureProcessor); + if (LeastFeatureProcessor.Version < mLeastFeatureProcessor.Version) { + UpdateProcessorInfo (CurrentProcessor, &mLeastFeatureProcessor); + } else if (LeastFeatureProcessor.Version == mLeastFeatureProcessor.Version) { + if (LeastFeatureProcessor.ApicId < mLeastFeatureProcessor.ApicId) { + UpdateProcessorInfo (CurrentProcessor, &mLeastFeatureProcessor); + } + } + } + + AsmReleaseMPLock (&mLock); + + return; +} + +/** + Switch BSP to the processor which has least features + + @param[in] MpServices - EFI_MP_SERVICES_PROTOCOL + + @retval EFI_STATUS - status code returned from each sub-routines +**/ +EFI_STATUS +SwitchToLowestFeatureProcess ( + IN EFI_MP_SERVICES_PROTOCOL *MpServices + ) +{ + EFI_STATUS Status; + UINTN CurrentProcessor; + UINTN NewBsp; + UINT32 Features[MAX_FEATURE_NUM]; + + Status = MpServices->WhoAmI ( + MpServices, + &CurrentProcessor + ); + if (EFI_ERROR (Status)) { + return Status; + } + + ReportStatusCode ( + EFI_PROGRESS_CODE, + EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_PC_BSP_SELECT + ); + + /// + /// Take current BSP as the least feature + /// + UpdateProcessorInfo (CurrentProcessor, &mLeastFeatureProcessor); + GetProcessorFeatures (mLeastFeatureProcessor.Features); + CopyMem (Features, mLeastFeatureProcessor.Features, sizeof (Features)); + Status = MpServices->StartupAllAPs ( + MpServices, + GetProcessorCommonFeature, + FALSE, + NULL, + 100000, + (VOID *) MpServices, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + /// + /// Go through all processors to find the processor with least features + /// + mLeastFeatureProcessor.FeatureDelta = GetProcessorFeatureDelta (Features, mLeastFeatureProcessor.Features); + Status = MpServices->StartupAllAPs ( + MpServices, + GetProcessorWithLeastFeature, + FALSE, + NULL, + 100000, + (VOID *) MpServices, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + /// + /// Switch BSP according + /// + if (mPlatformCpu->CpuConfig->BspSelection == 16) { + /// + /// Enable least feature SBSP selection + /// + NewBsp = mLeastFeatureProcessor.Index; + } else { + /// + /// Do not change the current BSP + /// made by SEC + /// + NewBsp = CurrentProcessor; + } + + if (NewBsp != CurrentProcessor) { + + DEBUG ((EFI_D_INFO, "Switch BSP from %d ==> %d\n", CurrentProcessor, NewBsp)); + Status = MpServices->SwitchBSP ( + MpServices, + NewBsp, + TRUE + ); + } + + return Status; +} |