text: /** @file
    CPU Common Lib implementation.
  
  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
  SPDX-License-Identifier: BSD-2-Clause-Patent
  
  **/
  
  #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;
    }
  }
  
  