Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

read MSR_IA32_TSC_ADJUST only if CPU supports #571

Merged
merged 1 commit into from
Dec 28, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
221 changes: 119 additions & 102 deletions Library/OcCpuLib/FrequencyDetect.c
Original file line number Diff line number Diff line change
Expand Up @@ -489,14 +489,17 @@ InternalCalculateARTFrequencyIntel (
UINT32 MaxId;
UINT32 CpuVendor;

UINT32 CpuidDenominatorEax;
UINT32 CpuidNumeratorEbx;
UINT32 CpuidARTFrequencyEcx;
CPUID_PROCESSOR_FREQUENCY_EAX CpuidFrequencyEax;
UINT64 TscAdjust;
UINT64 CPUFrequencyFromTSC;
CPUID_VERSION_INFO_EAX CpuidVerEax;
UINT8 Model;
CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_EBX CpuidFeatureFlagsEbx;
CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_ECX CpuidFeatureFlagsEcx;
CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_EDX CpuidFeatureFlagsEdx;
UINT32 CpuidDenominatorEax;
UINT32 CpuidNumeratorEbx;
UINT32 CpuidARTFrequencyEcx;
CPUID_PROCESSOR_FREQUENCY_EAX CpuidFrequencyEax;
UINT64 TscAdjust;
UINT64 CPUFrequencyFromTSC;
CPUID_VERSION_INFO_EAX CpuidVerEax;
UINT8 Model;

if (Recalculate) {
ObtainedARTFreq = FALSE;
Expand All @@ -514,109 +517,123 @@ InternalCalculateARTFrequencyIntel (
//
// Determine our core crystal clock frequency
//
if ((CpuVendor == CPUID_VENDOR_INTEL) && (MaxId >= CPUID_TIME_STAMP_COUNTER)) {
TscAdjust = AsmReadMsr64 (MSR_IA32_TSC_ADJUST);
DEBUG ((DEBUG_INFO, "OCCPU: TSC Adjust %Lu\n", TscAdjust));

if (TscAdjustPtr != NULL) {
*TscAdjustPtr = TscAdjust;
if (CpuVendor == CPUID_VENDOR_INTEL) {
if (MaxId >= CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS) {
AsmCpuidEx (
CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS,
0,
NULL,
&CpuidFeatureFlagsEbx.Uint32,
&CpuidFeatureFlagsEcx.Uint32,
&CpuidFeatureFlagsEdx.Uint32
);
if (CpuidFeatureFlagsEbx.Bits.IA32_TSC_ADJUST == 1) {
TscAdjust = AsmReadMsr64 (MSR_IA32_TSC_ADJUST);
DEBUG ((DEBUG_INFO, "OCCPU: TSC Adjust %Lu\n", TscAdjust));

if (TscAdjustPtr != NULL) {
*TscAdjustPtr = TscAdjust;
}
}
}

AsmCpuid (
CPUID_TIME_STAMP_COUNTER,
&CpuidDenominatorEax,
&CpuidNumeratorEbx,
&CpuidARTFrequencyEcx,
NULL
);
if (CpuidARTFrequencyEcx > 0) {
ARTFrequency = CpuidARTFrequencyEcx;
DEBUG ((DEBUG_INFO, "OCCPU: Queried Core Crystal Clock Frequency %11LuHz\n", ARTFrequency));
} else {
AsmCpuid (CPUID_VERSION_INFO, &CpuidVerEax.Uint32, NULL, NULL, NULL);
Model = (UINT8)CpuidVerEax.Bits.Model | (UINT8)(CpuidVerEax.Bits.ExtendedModelId << 4U);
//
// Fall back to identifying ART frequency based on known models
//
switch (Model) {
case CPU_MODEL_SKYLAKE:
case CPU_MODEL_SKYLAKE_DT:
case CPU_MODEL_KABYLAKE:
case CPU_MODEL_KABYLAKE_DT:
ARTFrequency = CLIENT_ART_CLOCK_SOURCE; // 24 Mhz
break;
case CPU_MODEL_DENVERTON:
ARTFrequency = SERVER_ART_CLOCK_SOURCE; // 25 Mhz
break;
case CPU_MODEL_GOLDMONT:
ARTFrequency = ATOM_ART_CLOCK_SOURCE; // 19.2 Mhz
break;
}
if (MaxId >= CPUID_TIME_STAMP_COUNTER) {
AsmCpuid (
CPUID_TIME_STAMP_COUNTER,
&CpuidDenominatorEax,
&CpuidNumeratorEbx,
&CpuidARTFrequencyEcx,
NULL
);
if (CpuidARTFrequencyEcx > 0) {
ARTFrequency = CpuidARTFrequencyEcx;
DEBUG ((DEBUG_INFO, "OCCPU: Queried Core Crystal Clock Frequency %11LuHz\n", ARTFrequency));
} else {
AsmCpuid (CPUID_VERSION_INFO, &CpuidVerEax.Uint32, NULL, NULL, NULL);
Model = (UINT8)CpuidVerEax.Bits.Model | (UINT8)(CpuidVerEax.Bits.ExtendedModelId << 4U);
//
// Fall back to identifying ART frequency based on known models
//
switch (Model) {
case CPU_MODEL_SKYLAKE:
case CPU_MODEL_SKYLAKE_DT:
case CPU_MODEL_KABYLAKE:
case CPU_MODEL_KABYLAKE_DT:
ARTFrequency = CLIENT_ART_CLOCK_SOURCE; // 24 Mhz
break;
case CPU_MODEL_DENVERTON:
ARTFrequency = SERVER_ART_CLOCK_SOURCE; // 25 Mhz
break;
case CPU_MODEL_GOLDMONT:
ARTFrequency = ATOM_ART_CLOCK_SOURCE; // 19.2 Mhz
break;
}

if (ARTFrequency > 0) {
DEBUG ((DEBUG_INFO, "OCCPU: Known Model Core Crystal Clock Frequency %11LuHz\n", ARTFrequency));
if (ARTFrequency > 0) {
DEBUG ((DEBUG_INFO, "OCCPU: Known Model Core Crystal Clock Frequency %11LuHz\n", ARTFrequency));
}
}
}

if ((CpuidDenominatorEax > 0) && (CpuidNumeratorEbx > 0)) {
//
// Some Intel chips don't report their core crystal clock frequency.
// Calculate it by dividing the TSC frequency by the TSC ratio.
//
if ((ARTFrequency == 0) && (MaxId >= CPUID_PROCESSOR_FREQUENCY)) {
CPUFrequencyFromTSC = InternalCalculateTSCFromPMTimer (Recalculate);
ARTFrequency = BaseMultThenDivU64x64x32 (
CPUFrequencyFromTSC,
CpuidDenominatorEax,
CpuidNumeratorEbx,
NULL
);
if (ARTFrequency > 0ULL) {
DEBUG ((
DEBUG_INFO,
"OCCPU: Core Crystal Clock Frequency from TSC %11LuHz = %11LuHz * %u / %u\n",
ARTFrequency,
CPUFrequencyFromTSC,
CpuidDenominatorEax,
CpuidNumeratorEbx
));
//
// Use the reported CPU frequency rather than deriving it from ARTFrequency
//
AsmCpuid (CPUID_PROCESSOR_FREQUENCY, &CpuidFrequencyEax.Uint32, NULL, NULL, NULL);
CPUFrequencyFromART = MultU64x32 (CpuidFrequencyEax.Bits.ProcessorBaseFrequency, 1000000);
if ((CpuidDenominatorEax > 0) && (CpuidNumeratorEbx > 0)) {
//
// Some Intel chips don't report their core crystal clock frequency.
// Calculate it by dividing the TSC frequency by the TSC ratio.
//
if ((ARTFrequency == 0) && (MaxId >= CPUID_PROCESSOR_FREQUENCY)) {
CPUFrequencyFromTSC = InternalCalculateTSCFromPMTimer (Recalculate);
ARTFrequency = BaseMultThenDivU64x64x32 (
CPUFrequencyFromTSC,
CpuidDenominatorEax,
CpuidNumeratorEbx,
NULL
);
if (ARTFrequency > 0ULL) {
DEBUG ((
DEBUG_INFO,
"OCCPU: Core Crystal Clock Frequency from TSC %11LuHz = %11LuHz * %u / %u\n",
ARTFrequency,
CPUFrequencyFromTSC,
CpuidDenominatorEax,
CpuidNumeratorEbx
));
//
// Use the reported CPU frequency rather than deriving it from ARTFrequency
//
AsmCpuid (CPUID_PROCESSOR_FREQUENCY, &CpuidFrequencyEax.Uint32, NULL, NULL, NULL);
CPUFrequencyFromART = MultU64x32 (CpuidFrequencyEax.Bits.ProcessorBaseFrequency, 1000000);
}
}
}

//
// If we still can't determine the core crystal clock frequency, assume
// it's 24 Mhz like most Intel chips to date.
//
if (ARTFrequency == 0ULL) {
ARTFrequency = DEFAULT_ART_CLOCK_SOURCE;
DEBUG ((DEBUG_INFO, "OCCPU: Fallback Core Crystal Clock Frequency %11LuHz\n", ARTFrequency));
}
//
// If we still can't determine the core crystal clock frequency, assume
// it's 24 Mhz like most Intel chips to date.
//
if (ARTFrequency == 0ULL) {
ARTFrequency = DEFAULT_ART_CLOCK_SOURCE;
DEBUG ((DEBUG_INFO, "OCCPU: Fallback Core Crystal Clock Frequency %11LuHz\n", ARTFrequency));
}

ASSERT (ARTFrequency > 0ULL);
if (CPUFrequencyFromART == 0ULL) {
CPUFrequencyFromART = BaseMultThenDivU64x64x32 (
ARTFrequency,
CpuidNumeratorEbx,
CpuidDenominatorEax,
NULL
);
}
ASSERT (ARTFrequency > 0ULL);
if (CPUFrequencyFromART == 0ULL) {
CPUFrequencyFromART = BaseMultThenDivU64x64x32 (
ARTFrequency,
CpuidNumeratorEbx,
CpuidDenominatorEax,
NULL
);
}

ASSERT (CPUFrequencyFromART > 0ULL);
DEBUG ((
DEBUG_INFO,
"OCCPU: CPUFrequencyFromART %11LuHz %5LuMHz = %Lu * %u / %u\n",
CPUFrequencyFromART,
DivU64x32 (CPUFrequencyFromART, 1000000),
ARTFrequency,
CpuidNumeratorEbx,
CpuidDenominatorEax
));
ASSERT (CPUFrequencyFromART > 0ULL);
DEBUG ((
DEBUG_INFO,
"OCCPU: CPUFrequencyFromART %11LuHz %5LuMHz = %Lu * %u / %u\n",
CPUFrequencyFromART,
DivU64x32 (CPUFrequencyFromART, 1000000),
ARTFrequency,
CpuidNumeratorEbx,
CpuidDenominatorEax
));
}
}
}
}
Expand Down
Loading