summaryrefslogtreecommitdiff
path: root/Kernel/Arch
diff options
context:
space:
mode:
authorNico Weber <thakis@chromium.org>2020-10-07 13:19:09 -0400
committerAndreas Kling <kling@serenityos.org>2020-10-08 10:00:39 +0200
commit8a01be48491383d80213bdcb7c5b4e3d3c3ec624 (patch)
tree0fb1a61f87efcb237eaa1bf0f48a0f524b768fbd /Kernel/Arch
parent1d96d5eea44ea4813d947cca9bd84cf10733d927 (diff)
downloadserenity-8a01be48491383d80213bdcb7c5b4e3d3c3ec624.zip
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.
Diffstat (limited to 'Kernel/Arch')
-rw-r--r--Kernel/Arch/i386/CPU.cpp22
-rw-r--r--Kernel/Arch/i386/CPU.h21
-rw-r--r--Kernel/Arch/i386/ProcessorInfo.cpp10
3 files changed, 41 insertions, 12 deletions
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<u32*>(buffer);
auto copy_brand_string_part_to_buffer = [&](u32 i) {