mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
270 lines
7.5 KiB
C
Executable File
270 lines
7.5 KiB
C
Executable File
/** @file
|
|
Copyright (C) 2016 - 2017, The HermitCrabs Lab. All rights reserved.
|
|
|
|
All rights reserved.
|
|
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which 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 <IndustryStandard/CpuId.h>
|
|
#include <IndustryStandard/GenericIch.h>
|
|
#include <IndustryStandard/Pci.h>
|
|
|
|
#include <Protocol/PciIo.h>
|
|
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/IoLib.h>
|
|
#include <Library/OcCpuLib.h>
|
|
#include <Library/PciLib.h>
|
|
#include <Library/OcTimerLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/UefiLib.h>
|
|
|
|
#include <Macros.h>
|
|
|
|
#include <ProcessorInfo.h>
|
|
|
|
// OcCpuScanProcessor
|
|
/** Scan the processor and fill the cpu info structure with results
|
|
|
|
@param[in] Cpu A pointer to the cpu info structure to fill with results
|
|
|
|
@retval EFI_SUCCESS The scan was completed successfully.
|
|
**/
|
|
EFI_STATUS
|
|
OcCpuScanProcessor (
|
|
IN CPU_INFO *Cpu
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
UINT32 CpuidEax;
|
|
UINT32 CpuidEbx;
|
|
UINT32 CpuidEcx;
|
|
UINT32 CpuidEdx;
|
|
UINT64 Msr = 0;
|
|
|
|
DEBUG_FUNCTION_ENTRY (DEBUG_VERBOSE);
|
|
|
|
Status = EFI_INVALID_PARAMETER;
|
|
|
|
if (Cpu != NULL) {
|
|
|
|
// Get vendor CPUID 0x00000000
|
|
AsmCpuid (CPUID_SIGNATURE, &CpuidEax, (UINT32 *)Cpu->Vendor, (UINT32 *)(Cpu->Vendor + 8), (UINT32 *)(Cpu->Vendor + 4));
|
|
|
|
// Get extended CPUID 0x80000000
|
|
AsmCpuid (CPUID_EXTENDED_FUNCTION, &CpuidEax, &CpuidEbx, &CpuidEcx, &CpuidEdx);
|
|
|
|
Cpu->MaxExtId = CpuidEax;
|
|
|
|
// Get brand string CPUID 0x80000002 - 0x80000004
|
|
if (Cpu->MaxExtId >= CPUID_BRAND_STRING3) {
|
|
|
|
// The brandstring 48 bytes max, guaranteed NULL terminated.
|
|
UINT32 *BrandString = (UINT32 *)Cpu->BrandString;
|
|
|
|
AsmCpuid (
|
|
CPUID_BRAND_STRING1,
|
|
BrandString,
|
|
(BrandString + 1),
|
|
(BrandString + 2),
|
|
(BrandString + 3)
|
|
);
|
|
|
|
AsmCpuid (
|
|
CPUID_BRAND_STRING2,
|
|
(BrandString + 4),
|
|
(BrandString + 5),
|
|
(BrandString + 6),
|
|
(BrandString + 7)
|
|
);
|
|
|
|
AsmCpuid (
|
|
CPUID_BRAND_STRING3,
|
|
(BrandString + 8),
|
|
(BrandString + 9),
|
|
(BrandString + 10),
|
|
(BrandString + 11)
|
|
);
|
|
}
|
|
|
|
// Get processor signature and decode
|
|
if (Cpu->MaxExtId >= CPUID_VERSION_INFO) {
|
|
|
|
AsmCpuid (CPUID_VERSION_INFO, &CpuidEax, &CpuidEbx, &CpuidEcx, &CpuidEdx);
|
|
|
|
Cpu->Signature = CpuidEax;
|
|
Cpu->Stepping = (UINT8)BITFIELD (CpuidEax, 3, 0);
|
|
Cpu->ExtModel = (UINT8)BITFIELD (CpuidEax, 19, 16);
|
|
Cpu->Model = ((UINT8)BITFIELD (CpuidEax, 7, 4) + (Cpu->ExtModel << 4));
|
|
Cpu->Family = (UINT8)BITFIELD (CpuidEax, 11, 8);
|
|
Cpu->Type = (UINT8)BITFIELD (CpuidEax, 13, 12);
|
|
Cpu->ExtFamily = (UINT8)BITFIELD (CpuidEax, 27, 20);
|
|
Cpu->Brand = (UINT8)BITFIELD (CpuidEbx, 7, 0);
|
|
Cpu->Features = QUAD (CpuidEcx, CpuidEdx);
|
|
|
|
}
|
|
|
|
/* LOG */ DEBUG ((EFI_D_INFO, "%a %a\n", "Found", Cpu->BrandString));
|
|
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"Signature %0X Stepping %0X Model %0X Family %0X Type %0X ExtModel %0X ExtFamily %0X\n",
|
|
Cpu->Signature,
|
|
Cpu->Stepping,
|
|
Cpu->Model,
|
|
Cpu->Family,
|
|
Cpu->Type,
|
|
Cpu->ExtModel,
|
|
Cpu->ExtFamily
|
|
));
|
|
|
|
if (*(UINT32 *)Cpu->Vendor == CPUID_VENDOR_INTEL) {
|
|
|
|
Msr = AsmReadMsr64 (MSR_PKG_CST_CONFIG_CONTROL);
|
|
|
|
if ((Cpu->Family == 0x06 && Cpu->Model >= 0x0c) ||
|
|
(Cpu->Family == 0x0f && Cpu->Model >= 0x03))
|
|
{
|
|
|
|
Msr = AsmReadMsr64 (MSR_IA32_PERF_STATUS);
|
|
|
|
if (Cpu->Model >= CPU_MODEL_NEHALEM) {
|
|
|
|
Cpu->CurBusRatio = (UINT8)BITFIELD(Msr, 15, 8);
|
|
|
|
Msr = AsmReadMsr64 (MSR_PLATFORM_INFO);
|
|
|
|
Cpu->MinBusRatio = (UINT8)(RShiftU64 (Msr, 40) & 0xFF);
|
|
Cpu->MaxBusRatio = (UINT8)(RShiftU64 (Msr, 8) & 0xFF);
|
|
|
|
} else {
|
|
|
|
Cpu->MaxBusRatio = (UINT8)(Msr >> 8) & 0x1f;
|
|
|
|
// Non-integer bus ratio for the max-multi
|
|
Cpu->MaxBusRatioDiv = (UINT8)(Msr >> 46) & 0x01;
|
|
|
|
// Non-integer bus ratio for the current-multi (undocumented)
|
|
//CurrDiv = (UINT8)(Msr >> 14) & 0x01;
|
|
|
|
}
|
|
|
|
if ((Cpu->Model != CPU_MODEL_NEHALEM_EX) &&
|
|
(Cpu->Model != CPU_MODEL_WESTMERE_EX))
|
|
{
|
|
Msr = AsmReadMsr64 (MSR_TURBO_RATIO_LIMIT);
|
|
Cpu->TurboBusRatio1 = (UINT8)(RShiftU64 (Msr, MAX_RATIO_LIMIT_1C_OFFSET) & MAX_RATIO_LIMIT_MASK);
|
|
Cpu->TurboBusRatio2 = (UINT8)(RShiftU64 (Msr, MAX_RATIO_LIMIT_2C_OFFSET) & MAX_RATIO_LIMIT_MASK);
|
|
Cpu->TurboBusRatio3 = (UINT8)(RShiftU64 (Msr, MAX_RATIO_LIMIT_3C_OFFSET) & MAX_RATIO_LIMIT_MASK);
|
|
Cpu->TurboBusRatio4 = (UINT8)(RShiftU64 (Msr, MAX_RATIO_LIMIT_4C_OFFSET) & MAX_RATIO_LIMIT_MASK);
|
|
}
|
|
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"Ratio Min %d Max %d Current %d Turbo %d %d %d %d\n",
|
|
Cpu->MinBusRatio,
|
|
Cpu->MaxBusRatio,
|
|
Cpu->CurBusRatio,
|
|
Cpu->TurboBusRatio1,
|
|
Cpu->TurboBusRatio2,
|
|
Cpu->TurboBusRatio3,
|
|
Cpu->TurboBusRatio4
|
|
));
|
|
|
|
// SkyLake and later have an Always Running Timer
|
|
if (Cpu->Model >= CPU_MODEL_SKYLAKE) {
|
|
|
|
AsmCpuid (0x15, &CpuidEax, &CpuidEbx, &CpuidEcx, &CpuidEdx);
|
|
|
|
if (CpuidEbx && CpuidEbx) {
|
|
|
|
Cpu->CPUFrequency = MultU64x32 (BASE_ART_CLOCK_SOURCE, (UINT32)DivU64x32 (CpuidEbx, CpuidEax));
|
|
|
|
/* LOG */ DEBUG ((
|
|
EFI_D_INFO,
|
|
"%a %a %11lld %5dMHz %d * %d / %d = %ld\n",
|
|
"ART",
|
|
"Frequency",
|
|
Cpu->CPUFrequency,
|
|
DivU64x32 (Cpu->CPUFrequency, 1000000),
|
|
BASE_ART_CLOCK_SOURCE,
|
|
CpuidEbx,
|
|
CpuidEax,
|
|
Cpu->CPUFrequency
|
|
));
|
|
|
|
Cpu->FSBFrequency = DivU64x32 (Cpu->CPUFrequency, Cpu->MaxBusRatio);
|
|
|
|
}
|
|
}
|
|
|
|
// Calculate the Tsc frequency
|
|
Cpu->TSCFrequency = CalculateTSC (FALSE);
|
|
|
|
if (Cpu->CPUFrequency == 0) {
|
|
|
|
/* LOG */ DEBUG ((
|
|
EFI_D_INFO,
|
|
"%a %a %11lld %5dMHz\n",
|
|
"TSC",
|
|
"Frequency",
|
|
Cpu->TSCFrequency,
|
|
DivU64x32 (Cpu->TSCFrequency, 1000000)
|
|
));
|
|
|
|
// Both checked to workaround virtual cpu
|
|
if ((Cpu->MinBusRatio > 0) &&
|
|
(Cpu->MaxBusRatio > Cpu->MinBusRatio))
|
|
{
|
|
Cpu->FSBFrequency = DivU64x32 (Cpu->TSCFrequency, Cpu->MaxBusRatio);
|
|
Cpu->CPUFrequency = MultU64x32 (Cpu->FSBFrequency, Cpu->MaxBusRatio);
|
|
|
|
} else {
|
|
|
|
Cpu->CPUFrequency = Cpu->TSCFrequency;
|
|
Cpu->FSBFrequency = 100000000;
|
|
}
|
|
}
|
|
|
|
/* LOG */ DEBUG ((
|
|
EFI_D_INFO,
|
|
"%a %a %11lld %5dMHz\n",
|
|
"CPU",
|
|
"Frequency",
|
|
Cpu->CPUFrequency,
|
|
DivU64x32 (Cpu->CPUFrequency, 1000000)
|
|
));
|
|
|
|
/* LOG */ DEBUG ((
|
|
EFI_D_INFO,
|
|
"%a %a %11lld %5dMHz\n",
|
|
"FSB",
|
|
"Frequency",
|
|
Cpu->FSBFrequency,
|
|
DivU64x32 (Cpu->FSBFrequency, 1000000)
|
|
));
|
|
|
|
}
|
|
}
|
|
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
|
|
DEBUG_FUNCTION_RETURN (DEBUG_VERBOSE);
|
|
|
|
return Status;
|
|
}
|