mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
OcCpuLib: Add hypervisor CPUID support to work with virtualization (#17)
This commit is contained in:
parent
fa13915b00
commit
d65c11fef8
@ -37,6 +37,7 @@ typedef struct {
|
||||
CPUID_VERSION_INFO_EDX CpuidVerEdx;
|
||||
|
||||
UINT32 MicrocodeRevision;
|
||||
BOOLEAN Hypervisor; //< indicate whether we are under virtualization
|
||||
|
||||
UINT8 Type;
|
||||
UINT8 Family;
|
||||
@ -104,6 +105,13 @@ typedef struct {
|
||||
//
|
||||
UINT64 CPUFrequencyFromART;
|
||||
|
||||
|
||||
//
|
||||
// The CPU frequency derived from the CPUID VMWare Timing leaf.
|
||||
// 0 if VMWare Timing leaf is not present.
|
||||
//
|
||||
UINT64 CPUFrequencyFromVMT;
|
||||
|
||||
//
|
||||
// The Front Side Bus (FSB) frequency calculated from dividing the CPU
|
||||
// frequency by the Max Ratio.
|
||||
|
||||
@ -1004,109 +1004,116 @@ ScanIntelProcessor (
|
||||
}
|
||||
|
||||
//
|
||||
// TODO: this may not be accurate on some older processors.
|
||||
// When the CPU is virtualized and cpuid invtsc is enabled, then we already get
|
||||
// the information we want outside the function, skip anyway.
|
||||
// Things may be different in other hypervisors, but should work with QEMU/VMWare for now.
|
||||
//
|
||||
if (Cpu->Model >= CPU_MODEL_NEHALEM) {
|
||||
PerfStatus.Uint64 = AsmReadMsr64 (MSR_IA32_PERF_STATUS);
|
||||
Cpu->CurBusRatio = (UINT8) (PerfStatus.Bits.State >> 8U);
|
||||
PlatformInfo.Uint64 = AsmReadMsr64 (MSR_NEHALEM_PLATFORM_INFO);
|
||||
Cpu->MinBusRatio = (UINT8) PlatformInfo.Bits.MaximumEfficiencyRatio;
|
||||
Cpu->MaxBusRatio = (UINT8) PlatformInfo.Bits.MaximumNonTurboRatio;
|
||||
} else if (Cpu->Model >= CPU_MODEL_PENRYN) {
|
||||
PerfStatus.Uint64 = AsmReadMsr64 (MSR_IA32_PERF_STATUS);
|
||||
Cpu->MaxBusRatio = (UINT8) (PerfStatus.Uint64 >> 8U) & 0x1FU;
|
||||
if (Cpu->CPUFrequencyFromVMT == 0) {
|
||||
//
|
||||
// Undocumented values:
|
||||
// Non-integer bus ratio for the max-multi.
|
||||
// Non-integer bus ratio for the current-multi.
|
||||
// TODO: this may not be accurate on some older processors.
|
||||
//
|
||||
// MaxBusRatioDiv = (UINT8)(PerfStatus.Uint64 >> 46U) & 0x01U;
|
||||
// CurrDiv = (UINT8)(PerfStatus.Uint64 >> 14U) & 0x01U;
|
||||
//
|
||||
}
|
||||
if (Cpu->Model >= CPU_MODEL_NEHALEM) {
|
||||
PerfStatus.Uint64 = AsmReadMsr64 (MSR_IA32_PERF_STATUS);
|
||||
Cpu->CurBusRatio = (UINT8) (PerfStatus.Bits.State >> 8U);
|
||||
PlatformInfo.Uint64 = AsmReadMsr64 (MSR_NEHALEM_PLATFORM_INFO);
|
||||
Cpu->MinBusRatio = (UINT8) PlatformInfo.Bits.MaximumEfficiencyRatio;
|
||||
Cpu->MaxBusRatio = (UINT8) PlatformInfo.Bits.MaximumNonTurboRatio;
|
||||
} else if (Cpu->Model >= CPU_MODEL_PENRYN) {
|
||||
PerfStatus.Uint64 = AsmReadMsr64 (MSR_IA32_PERF_STATUS);
|
||||
Cpu->MaxBusRatio = (UINT8) (PerfStatus.Uint64 >> 8U) & 0x1FU;
|
||||
//
|
||||
// Undocumented values:
|
||||
// Non-integer bus ratio for the max-multi.
|
||||
// Non-integer bus ratio for the current-multi.
|
||||
//
|
||||
// MaxBusRatioDiv = (UINT8)(PerfStatus.Uint64 >> 46U) & 0x01U;
|
||||
// CurrDiv = (UINT8)(PerfStatus.Uint64 >> 14U) & 0x01U;
|
||||
//
|
||||
}
|
||||
|
||||
if (Cpu->Model >= CPU_MODEL_NEHALEM
|
||||
&& Cpu->Model != CPU_MODEL_NEHALEM_EX
|
||||
&& Cpu->Model != CPU_MODEL_WESTMERE_EX) {
|
||||
TurboLimit.Uint64 = AsmReadMsr64 (MSR_NEHALEM_TURBO_RATIO_LIMIT);
|
||||
Cpu->TurboBusRatio1 = (UINT8) TurboLimit.Bits.Maximum1C;
|
||||
Cpu->TurboBusRatio2 = (UINT8) TurboLimit.Bits.Maximum2C;
|
||||
Cpu->TurboBusRatio3 = (UINT8) TurboLimit.Bits.Maximum3C;
|
||||
Cpu->TurboBusRatio4 = (UINT8) TurboLimit.Bits.Maximum4C;
|
||||
}
|
||||
if (Cpu->Model >= CPU_MODEL_NEHALEM
|
||||
&& Cpu->Model != CPU_MODEL_NEHALEM_EX
|
||||
&& Cpu->Model != CPU_MODEL_WESTMERE_EX) {
|
||||
TurboLimit.Uint64 = AsmReadMsr64 (MSR_NEHALEM_TURBO_RATIO_LIMIT);
|
||||
Cpu->TurboBusRatio1 = (UINT8) TurboLimit.Bits.Maximum1C;
|
||||
Cpu->TurboBusRatio2 = (UINT8) TurboLimit.Bits.Maximum2C;
|
||||
Cpu->TurboBusRatio3 = (UINT8) TurboLimit.Bits.Maximum3C;
|
||||
Cpu->TurboBusRatio4 = (UINT8) TurboLimit.Bits.Maximum4C;
|
||||
}
|
||||
|
||||
DEBUG ((
|
||||
DEBUG_INFO,
|
||||
"OCCPU: 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
|
||||
));
|
||||
|
||||
//
|
||||
// For logging purposes (the first call to these functions might happen
|
||||
// before logging is fully initialised), do not use the cached results in
|
||||
// DEBUG builds.
|
||||
//
|
||||
Recalculate = FALSE;
|
||||
|
||||
DEBUG_CODE_BEGIN ();
|
||||
Recalculate = TRUE;
|
||||
DEBUG_CODE_END ();
|
||||
|
||||
//
|
||||
// Calculate the Tsc frequency
|
||||
//
|
||||
DEBUG_CODE_BEGIN ();
|
||||
TimerAddr = OcGetPmTimerAddr (&TimerSourceType);
|
||||
DEBUG ((DEBUG_INFO, "OCCPU: Timer address is %Lx from %a\n", (UINT64) TimerAddr, TimerSourceType));
|
||||
DEBUG_CODE_END ();
|
||||
Cpu->CPUFrequencyFromTSC = OcCalculateTSCFromPMTimer (Recalculate);
|
||||
|
||||
//
|
||||
// Determine our core crystal clock frequency
|
||||
//
|
||||
Cpu->ARTFrequency = OcCalcluateARTFrequencyIntel (&Cpu->CPUFrequencyFromART, Recalculate);
|
||||
|
||||
//
|
||||
// Calculate CPU frequency based on ART if present, otherwise TSC
|
||||
//
|
||||
Cpu->CPUFrequency = Cpu->CPUFrequencyFromART > 0 ? Cpu->CPUFrequencyFromART : Cpu->CPUFrequencyFromTSC;
|
||||
|
||||
//
|
||||
// Verify that our two CPU frequency calculations do not differ substantially.
|
||||
//
|
||||
if (Cpu->CPUFrequencyFromART > 0 && Cpu->CPUFrequencyFromTSC > 0
|
||||
&& ABS((INT64) Cpu->CPUFrequencyFromART - (INT64) Cpu->CPUFrequencyFromTSC) > OC_CPU_FREQUENCY_TOLERANCE) {
|
||||
DEBUG ((
|
||||
DEBUG_WARN,
|
||||
"OCCPU: ART based CPU frequency differs substantially from TSC: %11LuHz != %11LuHz\n",
|
||||
Cpu->CPUFrequencyFromART,
|
||||
Cpu->CPUFrequencyFromTSC
|
||||
DEBUG_INFO,
|
||||
"OCCPU: 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
|
||||
));
|
||||
}
|
||||
|
||||
//
|
||||
// There may be some quirks with virtual CPUs (VMware is fine).
|
||||
// Formerly we checked Cpu->MinBusRatio > 0, but we have no MinBusRatio on Penryn.
|
||||
//
|
||||
if (Cpu->CPUFrequency > 0 && Cpu->MaxBusRatio > Cpu->MinBusRatio) {
|
||||
Cpu->FSBFrequency = DivU64x32 (Cpu->CPUFrequency, Cpu->MaxBusRatio);
|
||||
} else {
|
||||
//
|
||||
// TODO: It seems to be possible that CPU frequency == 0 here...
|
||||
// For logging purposes (the first call to these functions might happen
|
||||
// before logging is fully initialised), do not use the cached results in
|
||||
// DEBUG builds.
|
||||
//
|
||||
Cpu->FSBFrequency = 100000000; // 100 Mhz
|
||||
}
|
||||
Recalculate = FALSE;
|
||||
|
||||
DEBUG_CODE_BEGIN ();
|
||||
Recalculate = TRUE;
|
||||
DEBUG_CODE_END ();
|
||||
|
||||
//
|
||||
// Calculate the Tsc frequency
|
||||
//
|
||||
DEBUG_CODE_BEGIN ();
|
||||
TimerAddr = OcGetPmTimerAddr (&TimerSourceType);
|
||||
DEBUG ((DEBUG_INFO, "OCCPU: Timer address is %Lx from %a\n", (UINT64) TimerAddr, TimerSourceType));
|
||||
DEBUG_CODE_END ();
|
||||
Cpu->CPUFrequencyFromTSC = OcCalculateTSCFromPMTimer (Recalculate);
|
||||
|
||||
//
|
||||
// Determine our core crystal clock frequency
|
||||
//
|
||||
Cpu->ARTFrequency = OcCalcluateARTFrequencyIntel (&Cpu->CPUFrequencyFromART, Recalculate);
|
||||
|
||||
//
|
||||
// Calculate CPU frequency based on ART if present, otherwise TSC
|
||||
//
|
||||
Cpu->CPUFrequency = Cpu->CPUFrequencyFromART > 0 ? Cpu->CPUFrequencyFromART : Cpu->CPUFrequencyFromTSC;
|
||||
|
||||
//
|
||||
// Verify that our two CPU frequency calculations do not differ substantially.
|
||||
//
|
||||
if (Cpu->CPUFrequencyFromART > 0 && Cpu->CPUFrequencyFromTSC > 0
|
||||
&& ABS((INT64) Cpu->CPUFrequencyFromART - (INT64) Cpu->CPUFrequencyFromTSC) > OC_CPU_FREQUENCY_TOLERANCE) {
|
||||
DEBUG ((
|
||||
DEBUG_WARN,
|
||||
"OCCPU: ART based CPU frequency differs substantially from TSC: %11LuHz != %11LuHz\n",
|
||||
Cpu->CPUFrequencyFromART,
|
||||
Cpu->CPUFrequencyFromTSC
|
||||
));
|
||||
}
|
||||
|
||||
//
|
||||
// There may be some quirks with virtual CPUs (VMware is fine).
|
||||
// Formerly we checked Cpu->MinBusRatio > 0, but we have no MinBusRatio on Penryn.
|
||||
//
|
||||
if (Cpu->CPUFrequency > 0 && Cpu->MaxBusRatio > Cpu->MinBusRatio) {
|
||||
Cpu->FSBFrequency = DivU64x32 (Cpu->CPUFrequency, Cpu->MaxBusRatio);
|
||||
} else {
|
||||
//
|
||||
// TODO: It seems to be possible that CPU frequency == 0 here...
|
||||
//
|
||||
Cpu->FSBFrequency = 100000000; // 100 Mhz
|
||||
}
|
||||
}
|
||||
//
|
||||
// Calculate number of cores
|
||||
// If we are under virtualization, then we should get the topology from CPUID the same was as with Penryn.
|
||||
//
|
||||
if (Cpu->MaxId >= CPUID_CACHE_PARAMS && Cpu->Model <= CPU_MODEL_PENRYN) {
|
||||
if (Cpu->MaxId >= CPUID_CACHE_PARAMS && (Cpu->Model <= CPU_MODEL_PENRYN || Cpu->Hypervisor)) {
|
||||
AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &CpuidCacheEax.Uint32, &CpuidCacheEbx.Uint32, NULL, NULL);
|
||||
if (CpuidCacheEax.Bits.CacheType != CPUID_CACHE_PARAMS_CACHE_TYPE_NULL) {
|
||||
CoreCount = (UINT16)GetPowerOfTwo32 (CpuidCacheEax.Bits.MaximumAddressableIdsForProcessorCores + 1);
|
||||
@ -1177,14 +1184,16 @@ ScanAmdProcessor (
|
||||
//
|
||||
Cpu->AppleProcessorType = AppleProcessorTypeCorei5Type5;
|
||||
//
|
||||
// get TSC Frequency calculated in OcTimerLib
|
||||
// get TSC Frequency calculated in OcTimerLib, unless we got it already from virtualization extensions.
|
||||
// FIXME(1): This code assumes the CPU operates in P0. Either ensure it does
|
||||
// and raise the mode on demand, or adapt the logic to consider
|
||||
// both the operating and the nominal frequency, latter for
|
||||
// the invariant TSC.
|
||||
//
|
||||
Cpu->CPUFrequencyFromTSC = OcCalculateTSCFromPMTimer (Recalculate);
|
||||
Cpu->CPUFrequency = Cpu->CPUFrequencyFromTSC;
|
||||
if (Cpu->CPUFrequencyFromVMT == 0) {
|
||||
Cpu->CPUFrequencyFromTSC = OcCalculateTSCFromPMTimer (Recalculate);
|
||||
Cpu->CPUFrequency = Cpu->CPUFrequencyFromTSC;
|
||||
}
|
||||
//
|
||||
// Get core and thread count from CPUID
|
||||
//
|
||||
@ -1198,10 +1207,18 @@ ScanAmdProcessor (
|
||||
|
||||
switch (Cpu->ExtFamily) {
|
||||
case AMD_CPU_EXT_FAMILY_17H:
|
||||
CofVid = AsmReadMsr64 (K10_PSTATE_STATUS);
|
||||
CoreFrequencyID = BitFieldRead64 (CofVid, 0, 7);
|
||||
CoreDivisorID = BitFieldRead64 (CofVid, 8, 13);
|
||||
Cpu->MaxBusRatio = (UINT8) (CoreFrequencyID / CoreDivisorID * 2);
|
||||
if (Cpu->CPUFrequencyFromVMT == 0) {
|
||||
CofVid = AsmReadMsr64 (K10_PSTATE_STATUS);
|
||||
CoreFrequencyID = BitFieldRead64 (CofVid, 0, 7);
|
||||
CoreDivisorID = BitFieldRead64 (CofVid, 8, 13);
|
||||
if (CoreDivisorID > 0ULL) {
|
||||
//
|
||||
// Sometimes incorrect hypervisor configuration will lead to dividing by zero,
|
||||
// but these variables will not be used under hypervisor, so just skip these.
|
||||
//
|
||||
Cpu->MaxBusRatio = (UINT8) (CoreFrequencyID / CoreDivisorID * 2);
|
||||
}
|
||||
}
|
||||
//
|
||||
// Get core count from CPUID
|
||||
//
|
||||
@ -1216,17 +1233,25 @@ ScanAmdProcessor (
|
||||
break;
|
||||
case AMD_CPU_EXT_FAMILY_15H:
|
||||
case AMD_CPU_EXT_FAMILY_16H:
|
||||
// FIXME: Please refer to FIXME(1) for the MSR used here.
|
||||
CofVid = AsmReadMsr64 (K10_COFVID_STATUS);
|
||||
CoreFrequencyID = BitFieldRead64 (CofVid, 0, 5);
|
||||
CoreDivisorID = BitFieldRead64 (CofVid, 6, 8);
|
||||
Divisor = LShiftU64 (1, CoreDivisorID);
|
||||
//
|
||||
// BKDG for AMD Family 15h Models 10h-1Fh Processors (42300 Rev 3.12)
|
||||
// Core current operating frequency in MHz. CoreCOF = 100 *
|
||||
// (MSRC001_00[6B:64][CpuFid] + 10h) / (2 ^ MSRC001_00[6B:64][CpuDid]).
|
||||
//
|
||||
Cpu->MaxBusRatio = (UINT8)((CoreFrequencyID + 0x10) / Divisor);
|
||||
if (Cpu->CPUFrequencyFromVMT == 0) {
|
||||
// FIXME: Please refer to FIXME(1) for the MSR used here.
|
||||
CofVid = AsmReadMsr64 (K10_COFVID_STATUS);
|
||||
CoreFrequencyID = BitFieldRead64 (CofVid, 0, 5);
|
||||
CoreDivisorID = BitFieldRead64 (CofVid, 6, 8);
|
||||
Divisor = LShiftU64 (1, CoreDivisorID);
|
||||
//
|
||||
// BKDG for AMD Family 15h Models 10h-1Fh Processors (42300 Rev 3.12)
|
||||
// Core current operating frequency in MHz. CoreCOF = 100 *
|
||||
// (MSRC001_00[6B:64][CpuFid] + 10h) / (2 ^ MSRC001_00[6B:64][CpuDid]).
|
||||
//
|
||||
if (Divisor > 0ULL) {
|
||||
//
|
||||
// Sometimes incorrect hypervisor configuration will lead to dividing by zero,
|
||||
// but these variables will not be used under hypervisor, so just skip these.
|
||||
//
|
||||
Cpu->MaxBusRatio = (UINT8)((CoreFrequencyID + 0x10) / Divisor);
|
||||
}
|
||||
}
|
||||
//
|
||||
// AMD 15h and 16h CPUs don't support hyperthreading,
|
||||
// so the core count is equal to the thread count
|
||||
@ -1247,13 +1272,26 @@ ScanAmdProcessor (
|
||||
));
|
||||
|
||||
//
|
||||
// CPUPM is not supported on AMD, meaning the current
|
||||
// and minimum bus ratio are equal to the maximum bus ratio
|
||||
// When under virtualization this information is already available to us.
|
||||
//
|
||||
Cpu->CurBusRatio = Cpu->MaxBusRatio;
|
||||
Cpu->MinBusRatio = Cpu->MaxBusRatio;
|
||||
if (Cpu->CPUFrequencyFromVMT == 0) {
|
||||
//
|
||||
// Sometimes incorrect hypervisor configuration will lead to dividing by zero.
|
||||
//
|
||||
if (Cpu->MaxBusRatio == 0) {
|
||||
Cpu->FSBFrequency = 100000000; // 100 Mhz like Intel part.
|
||||
Cpu->MaxBusRatio = 1; // TODO: Maybe unsafe too, we need more investigation.
|
||||
} else {
|
||||
Cpu->FSBFrequency = DivU64x32 (Cpu->CPUFrequency, Cpu->MaxBusRatio);
|
||||
}
|
||||
//
|
||||
// CPUPM is not supported on AMD, meaning the current
|
||||
// and minimum bus ratio are equal to the maximum bus ratio
|
||||
//
|
||||
Cpu->CurBusRatio = Cpu->MaxBusRatio;
|
||||
Cpu->MinBusRatio = Cpu->MaxBusRatio;
|
||||
}
|
||||
|
||||
Cpu->FSBFrequency = DivU64x32 (Cpu->CPUFrequency, Cpu->MaxBusRatio);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1363,6 +1401,15 @@ OcCpuScanProcessor (
|
||||
Cpu->ExtFamily = (UINT8) Cpu->CpuidVerEax.Bits.ExtendedFamilyId;
|
||||
Cpu->Brand = (UINT8) Cpu->CpuidVerEbx.Bits.BrandIndex;
|
||||
Cpu->Features = (((UINT64) Cpu->CpuidVerEcx.Uint32) << 32ULL) | Cpu->CpuidVerEdx.Uint32;
|
||||
|
||||
//
|
||||
// TODO: We do not have Hypervisor support in EDK II CPUID structure yet.
|
||||
// See https://github.com/acidanthera/audk/pull/2.
|
||||
// Get Hypervisor/Virtualization information.
|
||||
//
|
||||
Cpu->Hypervisor = (BOOLEAN) (Cpu->CpuidVerEcx.Bits.NotUsed > 0);
|
||||
DEBUG ((DEBUG_INFO, "OCCPU: Hypervisor: %d\n", Cpu->Hypervisor));
|
||||
|
||||
if (Cpu->Features & CPUID_FEATURE_HTT) {
|
||||
Cpu->ThreadCount = (UINT16) Cpu->CpuidVerEbx.Bits.MaximumAddressableIdsForLogicalProcessors;
|
||||
}
|
||||
@ -1381,6 +1428,49 @@ OcCpuScanProcessor (
|
||||
Cpu->ExtModel,
|
||||
Cpu->ExtFamily
|
||||
));
|
||||
|
||||
//
|
||||
// If we are under virtualization and cpuid invtsc is enabled, we can just read
|
||||
// TSCFrequency and FSBFrequency from VMWare Timing node instead of reading MSR
|
||||
// (which hypervisors may not implemented yet), at least in QEMU/VMWare it works.
|
||||
// Source:
|
||||
// 1. CPUID usage for interaction between Hypervisors and Linux.: https://lwn.net/Articles/301888/
|
||||
// 2. [Qemu-devel] [PATCH v2 0/3] x86-kvm: Fix Mac guest timekeeping by exposi: https://lists.gnu.org/archive/html/qemu-devel/2017-01/msg04344.html
|
||||
//
|
||||
AsmCpuid (0x40000000, &CpuidEax, NULL, NULL, NULL);
|
||||
if (Cpu->Hypervisor && (CpuidEax >= 0x40000010)) {
|
||||
DEBUG ((DEBUG_INFO, "OCCPU: Cpu under virtualization, try get TSC/FSB frequency from VMWare Timing\n"));
|
||||
AsmCpuid (0x40000010, &CpuidEax, &CpuidEbx, NULL, NULL);
|
||||
|
||||
if (CpuidEax & CpuidEbx) {
|
||||
//
|
||||
// We get kHZ from node and we should translate it first.
|
||||
//
|
||||
Cpu->CPUFrequencyFromVMT = CpuidEax * 1000;
|
||||
Cpu->FSBFrequency = CpuidEbx * 1000;
|
||||
|
||||
Cpu->CPUFrequency = Cpu->CPUFrequencyFromVMT;
|
||||
//
|
||||
// We can caculate Bus Ratio here
|
||||
//
|
||||
Cpu->MaxBusRatio = DivU64x32 (Cpu->CPUFrequency, Cpu->FSBFrequency);
|
||||
//
|
||||
// We don't have anything like turbo, so we just assign some variables here
|
||||
//
|
||||
Cpu->MinBusRatio = Cpu->MaxBusRatio;
|
||||
Cpu->CurBusRatio = Cpu->CurBusRatio;
|
||||
|
||||
DEBUG ((
|
||||
DEBUG_INFO,
|
||||
"OCCPU: VMWare TSC: %11LuHz, %5LuMHz; FSB: %11LuHz, %5LuMHz; BusRatio: %d\n",
|
||||
Cpu->CPUFrequency,
|
||||
DivU64x32 (Cpu->CPUFrequency, 1000000),
|
||||
Cpu->FSBFrequency,
|
||||
DivU64x32 (Cpu->FSBFrequency, 1000000),
|
||||
Cpu->MaxBusRatio
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if (Cpu->Vendor[0] == CPUID_VENDOR_INTEL) {
|
||||
ScanIntelProcessor (Cpu);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user