Kernel: Support all Intel-defined CPUID feature flags for EAX=1

We're now able to detect all the regular CPUID feature flags from
ECX/EDX for EAX=1 :^)

None of the new ones are being used for anything yet, but they will show
up in /proc/cpuinfo and subsequently lscpu and SystemMonitor.

Note that I replaced the periods from the SSE 4.1 and 4.2 instructions
with underscores, which matches the internal enum names, Linux's
/proc/cpuinfo and the general pattern of replacing special characters
with underscores to limit feature names to [a-z0-9_].

The enum member stringification has been moved to a new function for
better re-usability and to avoid cluttering up Processor.cpp.
This commit is contained in:
Linus Groh 2022-03-27 12:49:38 +01:00 committed by Andreas Kling
parent bc7ec02a82
commit 6ca03b915e
Notes: sideshowbarker 2024-07-17 16:39:31 +09:00
5 changed files with 337 additions and 91 deletions

View File

@ -38,33 +38,88 @@ private:
};
AK_MAKE_ARBITRARY_SIZED_ENUM(CPUFeature, u128,
NX = CPUFeature(1u) << 0u,
PAE = CPUFeature(1u) << 1u,
PGE = CPUFeature(1u) << 2u,
RDRAND = CPUFeature(1u) << 3u,
RDSEED = CPUFeature(1u) << 4u,
SMAP = CPUFeature(1u) << 5u,
SMEP = CPUFeature(1u) << 6u,
SSE = CPUFeature(1u) << 7u,
TSC = CPUFeature(1u) << 8u,
RDTSCP = CPUFeature(1u) << 9u,
CONSTANT_TSC = CPUFeature(1u) << 10u,
NONSTOP_TSC = CPUFeature(1u) << 11u,
UMIP = CPUFeature(1u) << 12u,
SEP = CPUFeature(1u) << 13u,
SYSCALL = CPUFeature(1u) << 14u,
MMX = CPUFeature(1u) << 15u,
SSE2 = CPUFeature(1u) << 16u,
SSE3 = CPUFeature(1u) << 17u,
SSSE3 = CPUFeature(1u) << 18u,
SSE4_1 = CPUFeature(1u) << 19u,
SSE4_2 = CPUFeature(1u) << 20u,
XSAVE = CPUFeature(1u) << 21u,
AVX = CPUFeature(1u) << 22u,
FXSR = CPUFeature(1u) << 23u,
LM = CPUFeature(1u) << 24u,
HYPERVISOR = CPUFeature(1u) << 25u,
PAT = CPUFeature(1u) << 26u,
__End = CPUFeature(1u) << 27u);
/* EAX=1, ECX */ //
SSE3 = CPUFeature(1u) << 0u, // Streaming SIMD Extensions 3
PCLMULQDQ = CPUFeature(1u) << 1u, // PCLMULDQ Instruction
DTES64 = CPUFeature(1u) << 2u, // 64-Bit Debug Store
MONITOR = CPUFeature(1u) << 3u, // MONITOR/MWAIT Instructions
DS_CPL = CPUFeature(1u) << 4u, // CPL Qualified Debug Store
VMX = CPUFeature(1u) << 5u, // Virtual Machine Extensions
SMX = CPUFeature(1u) << 6u, // Safer Mode Extensions
EST = CPUFeature(1u) << 7u, // Enhanced Intel SpeedStep® Technology
TM2 = CPUFeature(1u) << 8u, // Thermal Monitor 2
SSSE3 = CPUFeature(1u) << 9u, // Supplemental Streaming SIMD Extensions 3
CNXT_ID = CPUFeature(1u) << 10u, // L1 Context ID
SDBG = CPUFeature(1u) << 11u, // Silicon Debug (IA32_DEBUG_INTERFACE MSR)
FMA = CPUFeature(1u) << 12u, // Fused Multiply Add
CX16 = CPUFeature(1u) << 13u, // CMPXCHG16B Instruction
XTPR = CPUFeature(1u) << 14u, // xTPR Update Control
PDCM = CPUFeature(1u) << 15u, // Perfmon and Debug Capability (IA32_PERF_CAPABILITIES MSR)
/* ECX Bit 16 */ // Reserved
PCID = CPUFeature(1u) << 17u, // Process Context Identifiers
DCA = CPUFeature(1u) << 18u, // Direct Cache Access
SSE4_1 = CPUFeature(1u) << 19u, // Streaming SIMD Extensions 4.1
SSE4_2 = CPUFeature(1u) << 20u, // Streaming SIMD Extensions 4.2
X2APIC = CPUFeature(1u) << 21u, // Extended xAPIC Support
MOVBE = CPUFeature(1u) << 22u, // MOVBE Instruction
POPCNT = CPUFeature(1u) << 23u, // POPCNT Instruction
TSC_DEADLINE = CPUFeature(1u) << 24u, // Time Stamp Counter Deadline
AES = CPUFeature(1u) << 25u, // AES Instruction Extensions
XSAVE = CPUFeature(1u) << 26u, // XSAVE/XSTOR States
OSXSAVE = CPUFeature(1u) << 27u, // OS-Enabled Extended State Management
AVX = CPUFeature(1u) << 28u, // Advanced Vector Extensions
F16C = CPUFeature(1u) << 29u, // 16-bit floating-point conversion instructions
RDRAND = CPUFeature(1u) << 30u, // RDRAND Instruction
HYPERVISOR = CPUFeature(1u) << 31u, // Hypervisor present (always zero on physical CPUs)
/* EAX=1, EDX */ //
FPU = CPUFeature(1u) << 32u, // Floating-point Unit On-Chip
VME = CPUFeature(1u) << 33u, // Virtual Mode Extension
DE = CPUFeature(1u) << 34u, // Debugging Extension
PSE = CPUFeature(1u) << 35u, // Page Size Extension
TSC = CPUFeature(1u) << 36u, // Time Stamp Counter
MSR = CPUFeature(1u) << 37u, // Model Specific Registers
PAE = CPUFeature(1u) << 38u, // Physical Address Extension
MCE = CPUFeature(1u) << 39u, // Machine-Check Exception
CX8 = CPUFeature(1u) << 40u, // CMPXCHG8 Instruction
APIC = CPUFeature(1u) << 41u, // On-chip APIC Hardware
/* EDX Bit 10 */ // Reserved
SEP = CPUFeature(1u) << 43u, // Fast System Call
MTRR = CPUFeature(1u) << 44u, // Memory Type Range Registers
PGE = CPUFeature(1u) << 45u, // Page Global Enable
MCA = CPUFeature(1u) << 46u, // Machine-Check Architecture
CMOV = CPUFeature(1u) << 47u, // Conditional Move Instruction
PAT = CPUFeature(1u) << 48u, // Page Attribute Table
PSE36 = CPUFeature(1u) << 49u, // 36-bit Page Size Extension
PSN = CPUFeature(1u) << 50u, // Processor serial number is present and enabled
CLFLUSH = CPUFeature(1u) << 51u, // CLFLUSH Instruction
/* EDX Bit 20 */ // Reserved
DS = CPUFeature(1u) << 53u, // CLFLUSH Instruction
ACPI = CPUFeature(1u) << 54u, // CLFLUSH Instruction
MMX = CPUFeature(1u) << 55u, // CLFLUSH Instruction
FXSR = CPUFeature(1u) << 56u, // CLFLUSH Instruction
SSE = CPUFeature(1u) << 57u, // Streaming SIMD Extensions
SSE2 = CPUFeature(1u) << 58u, // Streaming SIMD Extensions 2
SS = CPUFeature(1u) << 59u, // Self-Snoop
HTT = CPUFeature(1u) << 60u, // Multi-Threading
TM = CPUFeature(1u) << 61u, // Thermal Monitor
IA64 = CPUFeature(1u) << 62u, // IA64 processor emulating x86
PBE = CPUFeature(1u) << 63u, // Pending Break Enable
/* EAX=7, EBX */ //
SMEP = CPUFeature(1u) << 64u, // Supervisor Mode Execution Protection
RDSEED = CPUFeature(1u) << 65u, // RDSEED Instruction
SMAP = CPUFeature(1u) << 66u, // Supervisor Mode Access Prevention
/* EAX=7, ECX */ //
UMIP = CPUFeature(1u) << 67u, // User-Mode Instruction Prevention
/* EAX=80000001h, EDX */ //
SYSCALL = CPUFeature(1u) << 68u, // SYSCALL/SYSRET Instructions
NX = CPUFeature(1u) << 69u, // NX bit
RDTSCP = CPUFeature(1u) << 70u, // RDTSCP Instruction
LM = CPUFeature(1u) << 71u, // Long Mode
/* EAX=80000007h, EDX */ //
CONSTANT_TSC = CPUFeature(1u) << 72u, // Invariant TSC
NONSTOP_TSC = CPUFeature(1u) << 73u, // Invariant TSC
__End = CPUFeature(1u) << 127u);
StringView cpu_feature_to_string_view(CPUFeature::Type const&);
}

View File

@ -0,0 +1,160 @@
/*
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Arch/x86/CPUID.h>
namespace Kernel {
StringView cpu_feature_to_string_view(CPUFeature::Type const& feature)
{
if (feature == CPUFeature::SSE3)
return "sse3"sv;
if (feature == CPUFeature::PCLMULQDQ)
return "pclmulqdq"sv;
if (feature == CPUFeature::DTES64)
return "dtes64"sv;
if (feature == CPUFeature::MONITOR)
return "monitor"sv;
if (feature == CPUFeature::DS_CPL)
return "ds_cpl"sv;
if (feature == CPUFeature::VMX)
return "vmx"sv;
if (feature == CPUFeature::SMX)
return "smx"sv;
if (feature == CPUFeature::EST)
return "est"sv;
if (feature == CPUFeature::TM2)
return "tm2"sv;
if (feature == CPUFeature::SSSE3)
return "ssse3"sv;
// NOTE: This is called cid on Linux, but CNXT_ID in the Intel manual.
if (feature == CPUFeature::CNXT_ID)
return "cnxt_id"sv;
if (feature == CPUFeature::SDBG)
return "sdbg"sv;
if (feature == CPUFeature::FMA)
return "fma"sv;
if (feature == CPUFeature::CX16)
return "cx16"sv;
if (feature == CPUFeature::XTPR)
return "xtpr"sv;
if (feature == CPUFeature::PDCM)
return "pdcm"sv;
if (feature == CPUFeature::PCID)
return "pcid"sv;
if (feature == CPUFeature::DCA)
return "dca"sv;
if (feature == CPUFeature::SSE4_1)
return "sse4_1"sv;
if (feature == CPUFeature::SSE4_2)
return "sse4_2"sv;
if (feature == CPUFeature::X2APIC)
return "x2apic"sv;
if (feature == CPUFeature::MOVBE)
return "movbe"sv;
if (feature == CPUFeature::POPCNT)
return "popcnt"sv;
// NOTE: This is called tsc_deadline_timer on Linux, but TSC_DEADLINE in the Intel manual.
if (feature == CPUFeature::TSC_DEADLINE)
return "tsc_deadline"sv;
if (feature == CPUFeature::AES)
return "aes"sv;
if (feature == CPUFeature::XSAVE)
return "xsave"sv;
if (feature == CPUFeature::OSXSAVE)
return "osxsave"sv;
if (feature == CPUFeature::AVX)
return "avx"sv;
if (feature == CPUFeature::F16C)
return "f16c"sv;
if (feature == CPUFeature::RDRAND)
return "rdrand"sv;
if (feature == CPUFeature::HYPERVISOR)
return "hypervisor"sv;
if (feature == CPUFeature::FPU)
return "fpu"sv;
if (feature == CPUFeature::VME)
return "vme"sv;
if (feature == CPUFeature::DE)
return "de"sv;
if (feature == CPUFeature::PSE)
return "pse"sv;
if (feature == CPUFeature::TSC)
return "tsc"sv;
if (feature == CPUFeature::MSR)
return "msr"sv;
if (feature == CPUFeature::PAE)
return "pae"sv;
if (feature == CPUFeature::MCE)
return "mce"sv;
if (feature == CPUFeature::CX8)
return "cx8"sv;
if (feature == CPUFeature::APIC)
return "apic"sv;
if (feature == CPUFeature::SEP)
return "sep"sv;
if (feature == CPUFeature::MTRR)
return "mtrr"sv;
if (feature == CPUFeature::PGE)
return "pge"sv;
if (feature == CPUFeature::MCA)
return "mca"sv;
if (feature == CPUFeature::CMOV)
return "cmov"sv;
if (feature == CPUFeature::PAT)
return "pat"sv;
if (feature == CPUFeature::PSE36)
return "pse36"sv;
if (feature == CPUFeature::PSN)
return "psn"sv;
if (feature == CPUFeature::CLFLUSH)
return "clflush"sv;
if (feature == CPUFeature::DS)
return "ds"sv;
if (feature == CPUFeature::ACPI)
return "acpi"sv;
if (feature == CPUFeature::MMX)
return "mmx"sv;
if (feature == CPUFeature::FXSR)
return "fxsr"sv;
if (feature == CPUFeature::SSE)
return "sse"sv;
if (feature == CPUFeature::SSE2)
return "sse2"sv;
if (feature == CPUFeature::SS)
return "ss"sv;
if (feature == CPUFeature::HTT)
return "htt"sv;
if (feature == CPUFeature::TM)
return "tm"sv;
if (feature == CPUFeature::IA64)
return "ia64"sv;
if (feature == CPUFeature::PBE)
return "pbe"sv;
if (feature == CPUFeature::SMEP)
return "smep"sv;
if (feature == CPUFeature::RDSEED)
return "rdseed"sv;
if (feature == CPUFeature::SMAP)
return "smap"sv;
if (feature == CPUFeature::UMIP)
return "umip"sv;
if (feature == CPUFeature::SYSCALL)
return "syscall"sv;
if (feature == CPUFeature::NX)
return "nx"sv;
if (feature == CPUFeature::RDTSCP)
return "rdtscp"sv;
if (feature == CPUFeature::LM)
return "lm"sv;
if (feature == CPUFeature::CONSTANT_TSC)
return "constant_tsc"sv;
if (feature == CPUFeature::NONSTOP_TSC)
return "nonstop_tsc"sv;
VERIFY_NOT_REACHED();
}
}

View File

@ -89,31 +89,109 @@ UNMAP_AFTER_INIT void Processor::cpu_detect()
if (processor_info.ecx() & (1 << 0))
m_features |= CPUFeature::SSE3;
if (processor_info.ecx() & (1 << 1))
m_features |= CPUFeature::PCLMULQDQ;
if (processor_info.ecx() & (1 << 2))
m_features |= CPUFeature::DTES64;
if (processor_info.ecx() & (1 << 3))
m_features |= CPUFeature::MONITOR;
if (processor_info.ecx() & (1 << 4))
m_features |= CPUFeature::DS_CPL;
if (processor_info.ecx() & (1 << 5))
m_features |= CPUFeature::VMX;
if (processor_info.ecx() & (1 << 6))
m_features |= CPUFeature::SMX;
if (processor_info.ecx() & (1 << 7))
m_features |= CPUFeature::EST;
if (processor_info.ecx() & (1 << 8))
m_features |= CPUFeature::TM2;
if (processor_info.ecx() & (1 << 9))
m_features |= CPUFeature::SSSE3;
if (processor_info.ecx() & (1 << 10))
m_features |= CPUFeature::CNXT_ID;
if (processor_info.ecx() & (1 << 11))
m_features |= CPUFeature::SDBG;
if (processor_info.ecx() & (1 << 12))
m_features |= CPUFeature::FMA;
if (processor_info.ecx() & (1 << 13))
m_features |= CPUFeature::CX16;
if (processor_info.ecx() & (1 << 14))
m_features |= CPUFeature::XTPR;
if (processor_info.ecx() & (1 << 15))
m_features |= CPUFeature::PDCM;
if (processor_info.ecx() & (1 << 17))
m_features |= CPUFeature::PCID;
if (processor_info.ecx() & (1 << 18))
m_features |= CPUFeature::DCA;
if (processor_info.ecx() & (1 << 19))
m_features |= CPUFeature::SSE4_1;
if (processor_info.ecx() & (1 << 20))
m_features |= CPUFeature::SSE4_2;
if (processor_info.ecx() & (1 << 21))
m_features |= CPUFeature::X2APIC;
if (processor_info.ecx() & (1 << 22))
m_features |= CPUFeature::MOVBE;
if (processor_info.ecx() & (1 << 23))
m_features |= CPUFeature::POPCNT;
if (processor_info.ecx() & (1 << 24))
m_features |= CPUFeature::TSC_DEADLINE;
if (processor_info.ecx() & (1 << 25))
m_features |= CPUFeature::AES;
if (processor_info.ecx() & (1 << 26))
m_features |= CPUFeature::XSAVE;
if (processor_info.ecx() & (1 << 27))
m_features |= CPUFeature::OSXSAVE;
if (processor_info.ecx() & (1 << 28))
m_features |= CPUFeature::AVX;
if (processor_info.ecx() & (1 << 29))
m_features |= CPUFeature::F16C;
if (processor_info.ecx() & (1 << 30))
m_features |= CPUFeature::RDRAND;
if (processor_info.ecx() & (1 << 31))
m_features |= CPUFeature::HYPERVISOR;
if (processor_info.edx() & (1 << 0))
m_features |= CPUFeature::FPU;
if (processor_info.edx() & (1 << 1))
m_features |= CPUFeature::VME;
if (processor_info.edx() & (1 << 2))
m_features |= CPUFeature::DE;
if (processor_info.edx() & (1 << 3))
m_features |= CPUFeature::PSE;
if (processor_info.edx() & (1 << 4))
m_features |= CPUFeature::TSC;
if (processor_info.edx() & (1 << 5))
m_features |= CPUFeature::MSR;
if (processor_info.edx() & (1 << 6))
m_features |= CPUFeature::PAE;
if (processor_info.edx() & (1 << 13))
m_features |= CPUFeature::PGE;
if (processor_info.edx() & (1 << 7))
m_features |= CPUFeature::MCE;
if (processor_info.edx() & (1 << 8))
m_features |= CPUFeature::CX8;
if (processor_info.edx() & (1 << 9))
m_features |= CPUFeature::APIC;
if (processor_info.edx() & (1 << 11))
handle_edx_bit_11_feature();
if (processor_info.edx() & (1 << 12))
m_features |= CPUFeature::MTRR;
if (processor_info.edx() & (1 << 13))
m_features |= CPUFeature::PGE;
if (processor_info.edx() & (1 << 14))
m_features |= CPUFeature::MCA;
if (processor_info.edx() & (1 << 15))
m_features |= CPUFeature::CMOV;
if (processor_info.edx() & (1 << 16))
m_features |= CPUFeature::PAT;
if (processor_info.edx() & (1 << 17))
m_features |= CPUFeature::PSE36;
if (processor_info.edx() & (1 << 18))
m_features |= CPUFeature::PSN;
if (processor_info.edx() & (1 << 19))
m_features |= CPUFeature::CLFLUSH;
if (processor_info.edx() & (1 << 21))
m_features |= CPUFeature::DS;
if (processor_info.edx() & (1 << 22))
m_features |= CPUFeature::ACPI;
if (processor_info.edx() & (1 << 23))
m_features |= CPUFeature::MMX;
if (processor_info.edx() & (1 << 24))
@ -122,6 +200,16 @@ UNMAP_AFTER_INIT void Processor::cpu_detect()
m_features |= CPUFeature::SSE;
if (processor_info.edx() & (1 << 26))
m_features |= CPUFeature::SSE2;
if (processor_info.edx() & (1 << 27))
m_features |= CPUFeature::SS;
if (processor_info.edx() & (1 << 28))
m_features |= CPUFeature::HTT;
if (processor_info.edx() & (1 << 29))
m_features |= CPUFeature::TM;
if (processor_info.edx() & (1 << 30))
m_features |= CPUFeature::IA64;
if (processor_info.edx() & (1 << 31))
m_features |= CPUFeature::PBE;
CPUID extended_features(0x7);
if (extended_features.ebx() & (1 << 7))
@ -290,63 +378,6 @@ UNMAP_AFTER_INIT void Processor::cpu_setup()
NonnullOwnPtr<KString> Processor::features_string() const
{
StringBuilder builder;
auto feature_to_str = [](CPUFeature::Type const& feature) -> StringView {
if (feature == CPUFeature::NX)
return "nx"sv;
if (feature == CPUFeature::PAE)
return "pae"sv;
if (feature == CPUFeature::PGE)
return "pge"sv;
if (feature == CPUFeature::RDRAND)
return "rdrand"sv;
if (feature == CPUFeature::RDSEED)
return "rdseed"sv;
if (feature == CPUFeature::SMAP)
return "smap"sv;
if (feature == CPUFeature::SMEP)
return "smep"sv;
if (feature == CPUFeature::SSE)
return "sse"sv;
if (feature == CPUFeature::TSC)
return "tsc"sv;
if (feature == CPUFeature::RDTSCP)
return "rdtscp"sv;
if (feature == CPUFeature::CONSTANT_TSC)
return "constant_tsc"sv;
if (feature == CPUFeature::NONSTOP_TSC)
return "nonstop_tsc"sv;
if (feature == CPUFeature::UMIP)
return "umip"sv;
if (feature == CPUFeature::SEP)
return "sep"sv;
if (feature == CPUFeature::SYSCALL)
return "syscall"sv;
if (feature == CPUFeature::MMX)
return "mmx"sv;
if (feature == CPUFeature::FXSR)
return "fxsr"sv;
if (feature == CPUFeature::SSE2)
return "sse2"sv;
if (feature == CPUFeature::SSE3)
return "sse3"sv;
if (feature == CPUFeature::SSSE3)
return "ssse3"sv;
if (feature == CPUFeature::SSE4_1)
return "sse4.1"sv;
if (feature == CPUFeature::SSE4_2)
return "sse4.2"sv;
if (feature == CPUFeature::XSAVE)
return "xsave"sv;
if (feature == CPUFeature::AVX)
return "avx"sv;
if (feature == CPUFeature::LM)
return "lm"sv;
if (feature == CPUFeature::HYPERVISOR)
return "hypervisor"sv;
if (feature == CPUFeature::PAT)
return "pat"sv;
VERIFY_NOT_REACHED();
};
bool first = true;
for (auto feature = CPUFeature::Type(1u); feature != CPUFeature::__End; feature <<= 1u) {
if (has_feature(feature)) {
@ -354,8 +385,7 @@ NonnullOwnPtr<KString> Processor::features_string() const
first = false;
else
MUST(builder.try_append(' '));
auto str = feature_to_str(feature);
MUST(builder.try_append(str));
MUST(builder.try_append(cpu_feature_to_string_view(feature)));
}
}
return KString::must_create(builder.string_view());

View File

@ -322,6 +322,7 @@ if ("${SERENITY_ARCH}" STREQUAL "i686" OR "${SERENITY_ARCH}" STREQUAL "x86_64")
${KERNEL_SOURCES}
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/common/ASM_wrapper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/common/CPU.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/common/CPUID.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/common/Interrupts.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/common/Processor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/common/ProcessorInfo.cpp

View File

@ -8,8 +8,8 @@ cd "${script_path}/.."
MISSING_FLAGS=n
while IFS= read -r FLAG; do
# Ignore ELF_DEBUG because it's not a debug flag.
if [ "$FLAG" = "ELF_DEBUG" ]; then
# Ignore false positives that are not debug flags.
if [ "$FLAG" = "ELF_DEBUG" ] || [ "$FLAG" = "IA32_DEBUG_INTERFACE" ]; then
continue
fi