Kernel: Implement CPUFeature as an ArbitrarySizedEnum

This will make it possible to add many, many more CPU features - more
than the current limit 32 and later limit of 64 if we stick with an enum
class to be specific :^)
This commit is contained in:
Linus Groh 2022-03-27 12:49:20 +01:00 committed by Andreas Kling
parent e284ee7dcf
commit bc7ec02a82
Notes: sideshowbarker 2024-07-17 16:39:36 +09:00
3 changed files with 69 additions and 74 deletions

View file

@ -1,13 +1,15 @@
/* /*
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#pragma once #pragma once
#include <AK/EnumBits.h> #include <AK/ArbitrarySizedEnum.h>
#include <AK/Types.h> #include <AK/Types.h>
#include <AK/UFixedBigInt.h>
#include <AK/Platform.h> #include <AK/Platform.h>
VALIDATE_IS_X86() VALIDATE_IS_X86()
@ -35,36 +37,34 @@ private:
u32 m_edx { 0xffffffff }; u32 m_edx { 0xffffffff };
}; };
// FIXME: This can't hold every CPU feature as-is. AK_MAKE_ARBITRARY_SIZED_ENUM(CPUFeature, u128,
enum class CPUFeature : u32 { NX = CPUFeature(1u) << 0u,
NX = (1 << 0), PAE = CPUFeature(1u) << 1u,
PAE = (1 << 1), PGE = CPUFeature(1u) << 2u,
PGE = (1 << 2), RDRAND = CPUFeature(1u) << 3u,
RDRAND = (1 << 3), RDSEED = CPUFeature(1u) << 4u,
RDSEED = (1 << 4), SMAP = CPUFeature(1u) << 5u,
SMAP = (1 << 5), SMEP = CPUFeature(1u) << 6u,
SMEP = (1 << 6), SSE = CPUFeature(1u) << 7u,
SSE = (1 << 7), TSC = CPUFeature(1u) << 8u,
TSC = (1 << 8), RDTSCP = CPUFeature(1u) << 9u,
RDTSCP = (1 << 9), CONSTANT_TSC = CPUFeature(1u) << 10u,
CONSTANT_TSC = (1 << 10), NONSTOP_TSC = CPUFeature(1u) << 11u,
NONSTOP_TSC = (1 << 11), UMIP = CPUFeature(1u) << 12u,
UMIP = (1 << 12), SEP = CPUFeature(1u) << 13u,
SEP = (1 << 13), SYSCALL = CPUFeature(1u) << 14u,
SYSCALL = (1 << 14), MMX = CPUFeature(1u) << 15u,
MMX = (1 << 15), SSE2 = CPUFeature(1u) << 16u,
SSE2 = (1 << 16), SSE3 = CPUFeature(1u) << 17u,
SSE3 = (1 << 17), SSSE3 = CPUFeature(1u) << 18u,
SSSE3 = (1 << 18), SSE4_1 = CPUFeature(1u) << 19u,
SSE4_1 = (1 << 19), SSE4_2 = CPUFeature(1u) << 20u,
SSE4_2 = (1 << 20), XSAVE = CPUFeature(1u) << 21u,
XSAVE = (1 << 21), AVX = CPUFeature(1u) << 22u,
AVX = (1 << 22), FXSR = CPUFeature(1u) << 23u,
FXSR = (1 << 23), LM = CPUFeature(1u) << 24u,
LM = (1 << 24), HYPERVISOR = CPUFeature(1u) << 25u,
HYPERVISOR = (1 << 25), PAT = CPUFeature(1u) << 26u,
PAT = (1 << 26), __End = CPUFeature(1u) << 27u);
};
AK_ENUM_BITWISE_OPERATORS(CPUFeature);
} }

View file

@ -80,7 +80,7 @@ class Processor {
TSS m_tss; TSS m_tss;
static FPUState s_clean_fpu_state; static FPUState s_clean_fpu_state;
CPUFeature m_features; CPUFeature::Type m_features;
static Atomic<u32> g_total_processors; static Atomic<u32> g_total_processors;
u8 m_physical_address_bit_width; u8 m_physical_address_bit_width;
u8 m_virtual_address_bit_width; u8 m_virtual_address_bit_width;
@ -397,9 +397,9 @@ public:
static void deferred_call_queue(Function<void()> callback); static void deferred_call_queue(Function<void()> callback);
ALWAYS_INLINE bool has_feature(CPUFeature f) const ALWAYS_INLINE bool has_feature(CPUFeature::Type const& feature) const
{ {
return has_flag(m_features, f); return m_features.has_flag(feature);
} }
void check_invoke_scheduler(); void check_invoke_scheduler();

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2022, the SerenityOS developers. * Copyright (c) 2022, the SerenityOS developers.
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
@ -70,7 +71,7 @@ UNMAP_AFTER_INIT void Processor::cpu_detect()
// NOTE: This is called during Processor::early_initialize, we cannot // NOTE: This is called during Processor::early_initialize, we cannot
// safely log at this point because we don't have kmalloc // safely log at this point because we don't have kmalloc
// initialized yet! // initialized yet!
m_features = static_cast<CPUFeature>(0); m_features = CPUFeature::Type(0u);
CPUID processor_info(0x1); CPUID processor_info(0x1);
@ -289,77 +290,71 @@ UNMAP_AFTER_INIT void Processor::cpu_setup()
NonnullOwnPtr<KString> Processor::features_string() const NonnullOwnPtr<KString> Processor::features_string() const
{ {
StringBuilder builder; StringBuilder builder;
auto feature_to_str = auto feature_to_str = [](CPUFeature::Type const& feature) -> StringView {
[](CPUFeature f) -> StringView { if (feature == CPUFeature::NX)
switch (f) {
case CPUFeature::NX:
return "nx"sv; return "nx"sv;
case CPUFeature::PAE: if (feature == CPUFeature::PAE)
return "pae"sv; return "pae"sv;
case CPUFeature::PGE: if (feature == CPUFeature::PGE)
return "pge"sv; return "pge"sv;
case CPUFeature::RDRAND: if (feature == CPUFeature::RDRAND)
return "rdrand"sv; return "rdrand"sv;
case CPUFeature::RDSEED: if (feature == CPUFeature::RDSEED)
return "rdseed"sv; return "rdseed"sv;
case CPUFeature::SMAP: if (feature == CPUFeature::SMAP)
return "smap"sv; return "smap"sv;
case CPUFeature::SMEP: if (feature == CPUFeature::SMEP)
return "smep"sv; return "smep"sv;
case CPUFeature::SSE: if (feature == CPUFeature::SSE)
return "sse"sv; return "sse"sv;
case CPUFeature::TSC: if (feature == CPUFeature::TSC)
return "tsc"sv; return "tsc"sv;
case CPUFeature::RDTSCP: if (feature == CPUFeature::RDTSCP)
return "rdtscp"sv; return "rdtscp"sv;
case CPUFeature::CONSTANT_TSC: if (feature == CPUFeature::CONSTANT_TSC)
return "constant_tsc"sv; return "constant_tsc"sv;
case CPUFeature::NONSTOP_TSC: if (feature == CPUFeature::NONSTOP_TSC)
return "nonstop_tsc"sv; return "nonstop_tsc"sv;
case CPUFeature::UMIP: if (feature == CPUFeature::UMIP)
return "umip"sv; return "umip"sv;
case CPUFeature::SEP: if (feature == CPUFeature::SEP)
return "sep"sv; return "sep"sv;
case CPUFeature::SYSCALL: if (feature == CPUFeature::SYSCALL)
return "syscall"sv; return "syscall"sv;
case CPUFeature::MMX: if (feature == CPUFeature::MMX)
return "mmx"sv; return "mmx"sv;
case CPUFeature::FXSR: if (feature == CPUFeature::FXSR)
return "fxsr"sv; return "fxsr"sv;
case CPUFeature::SSE2: if (feature == CPUFeature::SSE2)
return "sse2"sv; return "sse2"sv;
case CPUFeature::SSE3: if (feature == CPUFeature::SSE3)
return "sse3"sv; return "sse3"sv;
case CPUFeature::SSSE3: if (feature == CPUFeature::SSSE3)
return "ssse3"sv; return "ssse3"sv;
case CPUFeature::SSE4_1: if (feature == CPUFeature::SSE4_1)
return "sse4.1"sv; return "sse4.1"sv;
case CPUFeature::SSE4_2: if (feature == CPUFeature::SSE4_2)
return "sse4.2"sv; return "sse4.2"sv;
case CPUFeature::XSAVE: if (feature == CPUFeature::XSAVE)
return "xsave"sv; return "xsave"sv;
case CPUFeature::AVX: if (feature == CPUFeature::AVX)
return "avx"sv; return "avx"sv;
case CPUFeature::LM: if (feature == CPUFeature::LM)
return "lm"sv; return "lm"sv;
case CPUFeature::HYPERVISOR: if (feature == CPUFeature::HYPERVISOR)
return "hypervisor"sv; return "hypervisor"sv;
// no default statement here intentionally so that we get if (feature == CPUFeature::PAT)
// a warning if a new feature is forgotten to be added here
case CPUFeature::PAT:
return "pat"sv; return "pat"sv;
} VERIFY_NOT_REACHED();
// Shouldn't ever happen
return "???"sv;
}; };
bool first = true; bool first = true;
for (u32 flag = 1; flag != 0; flag <<= 1) { for (auto feature = CPUFeature::Type(1u); feature != CPUFeature::__End; feature <<= 1u) {
if (has_feature(static_cast<CPUFeature>(flag))) { if (has_feature(feature)) {
if (first) if (first)
first = false; first = false;
else else
MUST(builder.try_append(' ')); MUST(builder.try_append(' '));
auto str = feature_to_str(static_cast<CPUFeature>(flag)); auto str = feature_to_str(feature);
MUST(builder.try_append(str)); MUST(builder.try_append(str));
} }
} }