diff options
Diffstat (limited to 'Silicon/Intel/KabylakeSiliconPkg/Cpu/LibraryPrivate/PeiDxeSmmCpuCommonLib/CpuCommonLib.c')
-rw-r--r-- | Silicon/Intel/KabylakeSiliconPkg/Cpu/LibraryPrivate/PeiDxeSmmCpuCommonLib/CpuCommonLib.c | 562 |
1 files changed, 562 insertions, 0 deletions
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Cpu/LibraryPrivate/PeiDxeSmmCpuCommonLib/CpuCommonLib.c b/Silicon/Intel/KabylakeSiliconPkg/Cpu/LibraryPrivate/PeiDxeSmmCpuCommonLib/CpuCommonLib.c new file mode 100644 index 0000000000..100bd1464c --- /dev/null +++ b/Silicon/Intel/KabylakeSiliconPkg/Cpu/LibraryPrivate/PeiDxeSmmCpuCommonLib/CpuCommonLib.c @@ -0,0 +1,562 @@ +/** @file
+ CPU Common Lib implementation.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License 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 <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/CpuLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PciLib.h>
+#include <Library/TimerLib.h>
+#include <Library/CpuPlatformLib.h>
+#include <Library/CpuMailboxLib.h>
+#include <Register/Cpuid.h>
+#include <Register/Msr.h>
+#include <CpuAccess.h>
+
+#include <Library/CpuCommonLib.h>
+
+#define INTERRUPT_VECTOR_NUMBER 256
+#define END_OF_TIMETABLE 0x3FF
+
+
+/**
+ Set up flags in CR4 for XMM instruction enabling
+**/
+VOID
+EFIAPI
+XmmInit (
+ VOID
+ )
+{
+ EFI_CPUID_REGISTER Cpuid;
+ UINTN Cr0;
+ UINTN Cr4;
+
+ ///
+ /// Read the CPUID information
+ ///
+ AsmCpuid (CPUID_VERSION_INFO, &Cpuid.RegEax, &Cpuid.RegEbx, &Cpuid.RegEcx, &Cpuid.RegEdx);
+
+ ///
+ /// Check whether SSE2 is supported
+ ///
+ if (Cpuid.RegEdx & BIT26) {
+ ///
+ /// Enable XMM
+ ///
+ Cr0 = AsmReadCr0 ();
+ Cr0 |= BIT1;
+ AsmWriteCr0 (Cr0);
+
+ Cr4 = AsmReadCr4 ();
+ Cr4 |= (UINTN) (BIT9 | BIT10);
+ AsmWriteCr4 (Cr4);
+ }
+}
+
+/**
+ Enable "Machine Check Enable" bit in Cr4
+**/
+VOID
+EFIAPI
+EnableMce (
+ VOID
+ )
+{
+ UINTN Cr4;
+
+ ///
+ /// Enable MCE
+ ///
+ Cr4 = AsmReadCr4 ();
+ Cr4 |= BIT6;
+ AsmWriteCr4 (Cr4);
+}
+
+/**
+ Mtrr Synch Up Entry
+**/
+UINTN
+EFIAPI
+MpMtrrSynchUpEntry (
+ VOID
+ )
+{
+ EFI_CPUID_REGISTER Cpuid;
+ UINT64 MsrData;
+ UINTN Cr0;
+ UINTN Cr4;
+
+ ///
+ /// Read the CPUID and MSR 1Bh information
+ ///
+ AsmCpuid (CPUID_VERSION_INFO, &Cpuid.RegEax, &Cpuid.RegEbx, &Cpuid.RegEcx, &Cpuid.RegEdx);
+ MsrData = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+
+ ///
+ /// Set CD(Bit30) bit and clear NW(Bit29) bit of CR0 followed by a WBINVD.
+ ///
+ if (!(Cpuid.RegEdx & BIT24) || (MsrData & BIT8)) {
+ AsmDisableCache ();
+ } else {
+ ///
+ /// We could bypass the wbinvd by
+ /// checking MSR 1Bh(MSR_IA32_APIC_BASE) Bit8 (1 = BSP, 0 = AP) to see if we're the BSP?
+ /// and checking CPUID if the processor support self-snooping.
+ ///
+ Cr0 = AsmReadCr0 ();
+ Cr0 &= (UINTN) ~BIT29;
+ Cr0 |= BIT30;
+ AsmWriteCr0 (Cr0);
+ }
+
+ ///
+ /// Clear PGE flag Bit 7
+ ///
+ Cr4 = AsmReadCr4 ();
+ Cr4 &= (UINTN) ~BIT7;
+ AsmWriteCr4 (Cr4);
+
+ ///
+ /// Flush all TLBs
+ ///
+ CpuFlushTlb ();
+
+ return Cr4;
+}
+
+/**
+ Mtrr Synch Up Exit
+**/
+VOID
+EFIAPI
+MpMtrrSynchUpExit (
+ UINTN Cr4
+ )
+{
+ UINTN Cr0;
+
+ ///
+ /// Flush all TLBs the second time
+ ///
+ CpuFlushTlb ();
+
+ ///
+ /// Clear both the CD and NW bits of CR0.
+ ///
+ Cr0 = AsmReadCr0 ();
+ Cr0 &= (UINTN) ~(BIT29 | BIT30);
+ AsmWriteCr0 (Cr0);
+
+ ///
+ /// Set PGE Flag in CR4 if set
+ ///
+ AsmWriteCr4 (Cr4);
+}
+
+/**
+ This procedure sends an IPI to the designated processor in
+ the requested delivery mode with the requested vector.
+
+ @param[in] ApicID - APIC ID of processor.
+ @param[in] VectorNumber - Vector number.
+ @param[in] DeliveryMode - I/O APIC Interrupt Deliver Modes
+
+ @retval EFI_INVALID_PARAMETER - Input paramters were not correct.
+ @retval EFI_NOT_READY - There was a pending interrupt
+ @retval EFI_SUCCESS - Interrupt sent successfully
+**/
+EFI_STATUS
+EFIAPI
+CpuSendIpi (
+ IN UINT32 ApicID,
+ IN UINTN VectorNumber,
+ IN UINTN DeliveryMode
+ )
+{
+ MSR_IA32_APIC_BASE_REGISTER Msr;
+ EFI_PHYSICAL_ADDRESS ApicBase;
+ UINT32 IcrLow;
+ UINT32 IcrHigh;
+ BOOLEAN XapicEnabled;
+ UINT32 TriggerMode;
+
+ ///
+ /// Check for valid input parameters.
+ ///
+ if (VectorNumber >= INTERRUPT_VECTOR_NUMBER) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DeliveryMode >= DELIVERY_MODE_MAX) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ///
+ /// Fix the vector number for special interrupts like SMI and INIT.
+ ///
+ if (DeliveryMode == DELIVERY_MODE_SMI || DeliveryMode == DELIVERY_MODE_INIT) {
+ VectorNumber = 0x0;
+ }
+
+ ///
+ /// Initialze ICR high dword, since P6 family processor needs
+ /// the destination field to be 0x0F when it is a broadcast
+ ///
+ IcrHigh = 0x0f000000;
+ IcrLow = (UINT32) (VectorNumber | (LShiftU64 (DeliveryMode, 8)));
+
+ TriggerMode = TRIGGER_MODE_EDGE;
+
+ ///
+ /// Interrupt trigger mode
+ ///
+ if (TriggerMode == TRIGGER_MODE_LEVEL) {
+ IcrLow |= 0x8000;
+ }
+
+ ///
+ /// Interrupt pin polarity
+ ///
+ IcrLow |= 0x4000;
+
+ ///
+ /// xAPIC Enabled
+ ///
+ Msr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ XapicEnabled = (BOOLEAN) ((Msr.Bits.EXTD == 1) && (Msr.Bits.EN == 1));
+
+ if (XapicEnabled) {
+ IcrHigh = (UINT32) ApicID;
+ } else {
+ IcrHigh = (UINT32) LShiftU64 (ApicID, 24);
+ }
+
+ ApicBase = Msr.Uint64 & 0xffffff000;
+
+ /* If Extended XAPIC Mode is enabled,
+ legacy xAPIC is no longer working.
+ So, previous MMIO offset must be transferred to MSR offset R/W.
+ ----------------------------------------------------------------
+ MMIO Offset MSR Offset Register Name
+ ----------------------------------------------------------------
+ 300h-310h 830h Interrupt Command Register [63:0]
+ 831h [Reserved]
+ ----------------------------------------------------------------
+ */
+ ///
+ /// To write APIC register by MSR or MMIO
+ ///
+ if (XapicEnabled) {
+ AsmWriteMsr64 (MSR_IA32_X2APIC_ICR, (((UINT64) LShiftU64 (IcrHigh, 32)) | (UINT64) IcrLow));
+ } else {
+ *(volatile UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_ICR_HIGH_OFFSET) = (UINT32) IcrHigh;
+ *(volatile UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_ICR_LOW_OFFSET) = (UINT32) IcrLow;
+ }
+
+ MicroSecondDelay (10);
+
+ ///
+ /// To get APIC register from MSR or MMIO
+ ///
+ if (XapicEnabled) {
+ IcrLow = (UINT32) AsmReadMsr64 (MSR_IA32_X2APIC_ICR);
+ } else {
+ IcrLow = (UINT32) *(volatile UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_ICR_LOW_OFFSET);
+ }
+
+ if (IcrLow & BIT12) {
+ return EFI_NOT_READY;
+ }
+
+ MicroSecondDelay (100);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get APIC ID of processor
+
+ @retval APIC ID of processor
+**/
+UINT32
+GetCpuApicId (
+ VOID
+ )
+{
+ EFI_CPUID_REGISTER CpuidRegisters;
+
+ AsmCpuid (
+ CPUID_VERSION_INFO,
+ &CpuidRegisters.RegEax,
+ &CpuidRegisters.RegEbx,
+ &CpuidRegisters.RegEcx,
+ &CpuidRegisters.RegEdx
+ );
+ return (UINT32) (CpuidRegisters.RegEbx >> 24);
+}
+
+/**
+ Programs XAPIC registers.
+
+ @param[in] Bsp - Is this BSP?
+**/
+VOID
+ProgramXApic (
+ BOOLEAN Bsp
+ )
+{
+ UINT64 ApicBaseReg;
+ EFI_PHYSICAL_ADDRESS ApicBase;
+ volatile UINT32 *EntryAddress;
+ UINT32 EntryValue;
+
+ ApicBaseReg = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBase = ApicBaseReg & 0xffffff000ULL;
+
+ ///
+ /// Program the spurious vector entry
+ ///
+ EntryAddress = (UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_SPURIOUS_VECTOR_OFFSET);
+ EntryValue = *EntryAddress;
+ EntryValue &= 0xFFFFFD0F;
+ EntryValue |= 0x10F;
+ *EntryAddress = EntryValue;
+
+ ///
+ /// Program the LINT1 vector entry as extINT
+ ///
+ EntryAddress = (UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_LINT0_VECTOR_OFFSET);
+ EntryValue = *EntryAddress;
+
+ if (Bsp) {
+ EntryValue &= 0xFFFE00FF;
+ EntryValue |= 0x700;
+ } else {
+ EntryValue |= 0x10000;
+ }
+
+ *EntryAddress = EntryValue;
+
+ ///
+ /// Program the LINT1 vector entry as NMI
+ ///
+ EntryAddress = (UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_LINT1_VECTOR_OFFSET);
+ EntryValue = *EntryAddress;
+ EntryValue &= 0xFFFE00FF;
+ if (Bsp) {
+ EntryValue |= 0x400;
+ } else {
+ EntryValue |= 0x10400;
+ }
+
+ *EntryAddress = EntryValue;
+}
+
+/**
+ This function is to disable BIOS Write Protect in SMM phase.
+**/
+VOID
+EFIAPI
+CpuSmmDisableBiosWriteProtect (
+ VOID
+ )
+{
+ UINT32 Data32;
+
+ ///
+ /// Read memory location FED30880h OR with 00000001h, place the result in EAX,
+ /// and write data to lower 32 bits of MSR 1FEh (sample code available)
+ ///
+ Data32 = MmioRead32 ((UINTN) (0xFED30880)) | (UINT32) (BIT0);
+ AsmWriteMsr32 (0x000001FE, Data32);
+}
+
+/**
+ This function is to enable BIOS Write Protect in SMM phase.
+**/
+VOID
+EFIAPI
+CpuSmmEnableBiosWriteProtect (
+ VOID
+ )
+{
+ UINT32 Data32;
+
+ ///
+ /// Read memory location FED30880h AND with FFFFFFFEh, place the result in EAX,
+ /// and write data to lower 32 bits of MSR 1FEh (sample code available)
+ ///
+ Data32 = MmioRead32 ((UINTN) (0xFED30880)) & (UINT32) (~BIT0);
+ AsmWriteMsr32 (0x000001FE, Data32);
+}
+
+/**
+ This function returns the maximum number of cores supported in this physical processor package.
+
+ @retval Maximum number of supported cores in the package.
+**/
+UINT8
+GetMaxSupportedCoreCount (
+ VOID
+ )
+{
+ EFI_CPUID_REGISTER Cpuid;
+ AsmCpuidEx (
+ 4,
+ 0,
+ &Cpuid.RegEax,
+ NULL,
+ NULL,
+ NULL
+ );
+ return (UINT8) (RShiftU64 (Cpuid.RegEax, 26) & 0x3f) + 1;
+}
+
+/**
+ This function returns the actual factory-configured number of threads per core,
+ and actual factory-configured number of cores in this physical processor package.
+
+ @param[out] *ThreadsPerCore - variable that will store Maximum enabled threads per core
+ @param[out] *NumberOfCores - variable that will store Maximum enabled cores per die
+**/
+VOID
+GetSupportedCount (
+ OUT UINT16 *ThreadsPerCore, OPTIONAL
+ OUT UINT16 *NumberOfCores OPTIONAL
+ )
+{
+ EFI_CPUID_REGISTER CpuidRegs;
+ UINT16 Threads;
+
+ AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, NULL, &CpuidRegs.RegEbx, NULL, NULL);
+ Threads = (UINT16) CpuidRegs.RegEbx;
+
+ if (ThreadsPerCore != NULL) {
+ *ThreadsPerCore = Threads;
+ }
+
+ if (NumberOfCores != NULL) {
+ AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 1, NULL, &CpuidRegs.RegEbx, NULL, NULL);
+ *NumberOfCores = (UINT16) (CpuidRegs.RegEbx / Threads);
+ }
+}
+
+
+/**
+ Check to see if the executing thread is BSP
+
+ @retval TRUE Executing thread is BSP
+ @retval FALSE Executing thread is AP
+**/
+BOOLEAN
+IsBsp (
+ VOID
+ )
+{
+ MSR_IA32_APIC_BASE_REGISTER Msr;
+
+ Msr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ return (BOOLEAN) (Msr.Bits.BSP == 1);
+}
+
+
+BOOLEAN
+IsPrmrrAlreadySet (
+ VOID
+ )
+{
+ return FALSE;
+}
+
+/**
+ Check if this is non-core processor - HT AP thread
+
+ @retval TRUE if this is HT AP thread
+ @retval FALSE if this is core thread
+**/
+BOOLEAN
+IsSecondaryThread (
+ VOID
+ )
+{
+ UINT32 ApicID;
+ EFI_CPUID_REGISTER CpuidRegisters;
+ UINT8 CpuCount;
+ UINT8 CoreCount;
+ UINT8 CpuPerCore;
+ UINT32 Mask;
+
+ ApicID = GetCpuApicId ();
+
+ AsmCpuid (
+ CPUID_VERSION_INFO,
+ &CpuidRegisters.RegEax,
+ &CpuidRegisters.RegEbx,
+ &CpuidRegisters.RegEcx,
+ &CpuidRegisters.RegEdx
+ );
+ if ((CpuidRegisters.RegEdx & 0x10000000) == 0) {
+ return FALSE;
+ }
+
+ CpuCount = (UINT8) ((CpuidRegisters.RegEbx >> 16) & 0xff);
+ if (CpuCount == 1) {
+ return FALSE;
+ }
+
+ AsmCpuid (
+ CPUID_SIGNATURE,
+ &CpuidRegisters.RegEax,
+ &CpuidRegisters.RegEbx,
+ &CpuidRegisters.RegEcx,
+ &CpuidRegisters.RegEdx
+ );
+ if (CpuidRegisters.RegEax > 3) {
+
+ CoreCount = GetMaxSupportedCoreCount ();
+ } else {
+ CoreCount = 1;
+ }
+ ///
+ /// Assumes there is symmetry across core boundary, i.e. each core within a package has the same number of logical processors
+ ///
+ if (CpuCount == CoreCount) {
+ return FALSE;
+ }
+
+ CpuPerCore = CpuCount / CoreCount;
+
+ ///
+ /// Assume 1 Core has no more than 8 threads
+ ///
+ if (CpuPerCore == 2) {
+ Mask = 0x1;
+ } else if (CpuPerCore <= 4) {
+ Mask = 0x3;
+ } else {
+ Mask = 0x7;
+ }
+
+ if ((ApicID & Mask) == 0) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
|