From 8a01be48491383d80213bdcb7c5b4e3d3c3ec624 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 7 Oct 2020 13:19:09 -0400 Subject: Kernel: Add some CPU feature flags related to TSC In case we want to rely more on TSC in time keeping in the future, idk This adds: - RDTSCP, for when the RDTSCP instruction is available - CONSTANT_TSC, for when the TSC has a constant frequency, invariant under things like the CPU boosting its frequency. - NONSTOP_TSC, for when the TSC doesn't pause when the CPU enters sleep states. AMD cpus and newer intel cpus set the INVSTC bit (bit 8 in edx of extended cpuid 0x8000000008), which implies both CONSTANT_TSC and NONSTOP_TSC. Some older intel processors have CONSTANT_TSC but not NONSTOP_TSC; this is set based on cpu model checks. There isn't a ton of documentation on this, so this follows Linux terminology and http://blog.tinola.com/?e=54 CONSTANT_TSC: https://github.com/torvalds/linux/commit/39b3a7910556005a7a0d042ecb7ff98bfa84ea57 NONSTOP_TSC: https://github.com/torvalds/linux/commit/40fb17152c50a69dc304dd632131c2f41281ce44 qemu disables invtsc (bit 8 in edx of extended cpuid 0x8000000008) by default even if the host cpu supports it. It can be enabled by running with `SERENITY_QEMU_CPU=host,migratable=off` set. --- Kernel/Arch/i386/CPU.cpp | 22 ++++++++++++++++++++++ Kernel/Arch/i386/CPU.h | 21 ++++++++++++--------- Kernel/Arch/i386/ProcessorInfo.cpp | 10 +++++++--- 3 files changed, 41 insertions(+), 12 deletions(-) (limited to 'Kernel/Arch') diff --git a/Kernel/Arch/i386/CPU.cpp b/Kernel/Arch/i386/CPU.cpp index 2634c9eecd..7bffaf6f5d 100644 --- a/Kernel/Arch/i386/CPU.cpp +++ b/Kernel/Arch/i386/CPU.cpp @@ -998,15 +998,31 @@ void Processor::cpu_detect() u32 family = (processor_info.eax() >> 8) & 0xf; if (!(family == 6 && model < 3 && stepping < 3)) set_feature(CPUFeature::SEP); + if ((family == 6 && model >= 3) || (family == 0xf && model >= 0xe)) + set_feature(CPUFeature::CONSTANT_TSC); } + + u32 max_extended_leaf = CPUID(0x80000000).eax(); + + ASSERT(max_extended_leaf >= 0x80000001); CPUID extended_processor_info(0x80000001); if (extended_processor_info.edx() & (1 << 20)) set_feature(CPUFeature::NX); + if (extended_processor_info.edx() & (1 << 27)) + set_feature(CPUFeature::RDTSCP); if (extended_processor_info.edx() & (1 << 11)) { // Only available in 64 bit mode set_feature(CPUFeature::SYSCALL); } + if (max_extended_leaf >= 0x80000007) { + CPUID cpuid(0x80000007); + if (cpuid.edx() & (1 << 8)) { + set_feature(CPUFeature::CONSTANT_TSC); + set_feature(CPUFeature::NONSTOP_TSC); + } + } + CPUID extended_features(0x7); if (extended_features.ebx() & (1 << 20)) set_feature(CPUFeature::SMAP); @@ -1107,6 +1123,12 @@ String Processor::features_string() const return "sse"; case CPUFeature::TSC: return "tsc"; + case CPUFeature::RDTSCP: + return "rdtscp"; + case CPUFeature::CONSTANT_TSC: + return "constant_tsc"; + case CPUFeature::NONSTOP_TSC: + return "nonstop_tsc"; case CPUFeature::UMIP: return "umip"; case CPUFeature::SEP: diff --git a/Kernel/Arch/i386/CPU.h b/Kernel/Arch/i386/CPU.h index 0431c60ca1..bc5f8546b5 100644 --- a/Kernel/Arch/i386/CPU.h +++ b/Kernel/Arch/i386/CPU.h @@ -606,15 +606,18 @@ enum class CPUFeature : u32 { SMEP = (1 << 6), SSE = (1 << 7), TSC = (1 << 8), - UMIP = (1 << 9), - SEP = (1 << 10), - SYSCALL = (1 << 11), - MMX = (1 << 12), - SSE2 = (1 << 13), - SSE3 = (1 << 14), - SSSE3 = (1 << 15), - SSE4_1 = (1 << 16), - SSE4_2 = (1 << 17) + RDTSCP = (1 << 9), + CONSTANT_TSC = (1 << 10), + NONSTOP_TSC = (1 << 11), + UMIP = (1 << 12), + SEP = (1 << 13), + SYSCALL = (1 << 14), + MMX = (1 << 15), + SSE2 = (1 << 16), + SSE3 = (1 << 17), + SSSE3 = (1 << 18), + SSE4_1 = (1 << 19), + SSE4_2 = (1 << 20), }; class Thread; diff --git a/Kernel/Arch/i386/ProcessorInfo.cpp b/Kernel/Arch/i386/ProcessorInfo.cpp index e570995472..273389424d 100644 --- a/Kernel/Arch/i386/ProcessorInfo.cpp +++ b/Kernel/Arch/i386/ProcessorInfo.cpp @@ -34,6 +34,7 @@ namespace Kernel { ProcessorInfo::ProcessorInfo(Processor& processor) : m_processor(processor) { + u32 max_leaf; { CPUID cpuid(0); StringBuilder builder; @@ -44,12 +45,14 @@ ProcessorInfo::ProcessorInfo(Processor& processor) (value >> 16) & 0xff, (value >> 24) & 0xff); }; + max_leaf = cpuid.eax(); emit_u32(cpuid.ebx()); emit_u32(cpuid.edx()); emit_u32(cpuid.ecx()); m_cpuid = builder.build(); } { + ASSERT(max_leaf >= 1); CPUID cpuid(1); m_stepping = cpuid.eax() & 0xf; u32 model = (cpuid.eax() >> 4) & 0xf; @@ -68,9 +71,10 @@ ProcessorInfo::ProcessorInfo(Processor& processor) m_display_model = model; } } - { - // FIXME: Check first that this is supported by calling CPUID with eax=0x80000000 - // and verifying that the returned eax>=0x80000004. + + u32 max_extended_leaf = CPUID(0x80000000).eax(); + + if (max_extended_leaf >= 0x80000004) { alignas(u32) char buffer[48]; u32* bufptr = reinterpret_cast(buffer); auto copy_brand_string_part_to_buffer = [&](u32 i) { -- cgit v1.2.3