summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom <tomut@yahoo.com>2020-07-03 10:23:09 -0600
committerAndreas Kling <kling@serenityos.org>2020-07-03 19:32:34 +0200
commit9b4e6f6a23e1669d21e18eb985323f7075de275a (patch)
treeb16609be64fbe5112d6961cc575ad58806d1a80f
parente373e5f007956e59d8efca1fe74ce0e84355b27b (diff)
downloadserenity-9b4e6f6a23e1669d21e18eb985323f7075de275a.zip
Kernel: Consolidate features into CPUFeature enum
This allows us to consolidate printing out all the CPU features into one log statement. Also expose them in /proc/cpuinfo
-rw-r--r--Kernel/Arch/i386/CPU.cpp276
-rw-r--r--Kernel/Arch/i386/CPU.h44
-rw-r--r--Kernel/Arch/i386/ProcessorInfo.cpp3
-rw-r--r--Kernel/Arch/i386/ProcessorInfo.h2
-rw-r--r--Kernel/FileSystem/ProcFS.cpp1
-rw-r--r--Kernel/Random.cpp6
-rw-r--r--Kernel/VM/MemoryManager.cpp2
-rw-r--r--Kernel/VM/Region.cpp2
-rw-r--r--Kernel/init.cpp2
9 files changed, 195 insertions, 143 deletions
diff --git a/Kernel/Arch/i386/CPU.cpp b/Kernel/Arch/i386/CPU.cpp
index b7b8d5bbd6..777c1df580 100644
--- a/Kernel/Arch/i386/CPU.cpp
+++ b/Kernel/Arch/i386/CPU.cpp
@@ -26,6 +26,7 @@
#include <AK/Assertions.h>
#include <AK/String.h>
+#include <AK/StringBuilder.h>
#include <AK/Types.h>
#include <Kernel/Arch/i386/CPU.h>
#include <Kernel/Arch/i386/ProcessorInfo.h>
@@ -633,7 +634,7 @@ void exit_trap(TrapFrame* trap)
return Processor::current().exit_trap(*trap);
}
-void sse_init()
+static void sse_init()
{
asm volatile(
"mov %cr0, %eax\n"
@@ -645,181 +646,215 @@ void sse_init()
"mov %eax, %cr4\n");
}
-bool g_cpu_supports_nx;
-bool g_cpu_supports_pae;
-bool g_cpu_supports_pge;
-bool g_cpu_supports_rdrand;
-bool g_cpu_supports_rdseed;
-bool g_cpu_supports_smap;
-bool g_cpu_supports_smep;
-bool g_cpu_supports_sse;
-bool g_cpu_supports_tsc;
-bool g_cpu_supports_umip;
-
-void cpu_detect()
+u32 read_cr0()
+{
+ u32 cr0;
+ asm("movl %%cr0, %%eax"
+ : "=a"(cr0));
+ return cr0;
+}
+
+u32 read_cr3()
+{
+ u32 cr3;
+ asm("movl %%cr3, %%eax"
+ : "=a"(cr3));
+ return cr3;
+}
+
+void write_cr3(u32 cr3)
+{
+ asm volatile("movl %%eax, %%cr3" ::"a"(cr3)
+ : "memory");
+}
+
+u32 read_cr4()
+{
+ u32 cr4;
+ asm("movl %%cr4, %%eax"
+ : "=a"(cr4));
+ return cr4;
+}
+
+u32 read_dr6()
+{
+ u32 dr6;
+ asm("movl %%dr6, %%eax"
+ : "=a"(dr6));
+ return dr6;
+}
+
+FPUState Processor::s_clean_fpu_state;
+
+static Vector<Processor*>* s_processors;
+static SpinLock s_processor_lock;
+
+Vector<Processor*>& Processor::processors()
{
+ ASSERT(s_processors);
+ return *s_processors;
+}
+
+Processor& Processor::by_id(u32 cpu)
+{
+ // s_processors does not need to be protected by a lock of any kind.
+ // It is populated early in the boot process, and the BSP is waiting
+ // for all APs to finish, after which this array never gets modified
+ // again, so it's safe to not protect access to it here
+ auto& procs = processors();
+ ASSERT(procs[cpu] != nullptr);
+ ASSERT(procs.size() > cpu);
+ return *procs[cpu];
+}
+
+
+void Processor::cpu_detect()
+{
+ // NOTE: This is called during Processor::early_initialize, we cannot
+ // safely log at this point because we don't have kmalloc
+ // initialized yet!
+ auto set_feature =
+ [&](CPUFeature f) {
+ m_features = static_cast<CPUFeature>(static_cast<u32>(m_features) | static_cast<u32>(f));
+ };
+ m_features = static_cast<CPUFeature>(0);
+
CPUID processor_info(0x1);
- g_cpu_supports_pae = (processor_info.edx() & (1 << 6));
- g_cpu_supports_pge = (processor_info.edx() & (1 << 13));
- g_cpu_supports_sse = (processor_info.edx() & (1 << 25));
- g_cpu_supports_tsc = (processor_info.edx() & (1 << 4));
- g_cpu_supports_rdrand = (processor_info.ecx() & (1 << 30));
+ if (processor_info.edx() & (1 << 6))
+ set_feature(CPUFeature::PAE);
+ if (processor_info.edx() & (1 << 13))
+ set_feature(CPUFeature::PGE);
+ if (processor_info.edx() & (1 << 25))
+ set_feature(CPUFeature::SSE);
+ if (processor_info.edx() & (1 << 4))
+ set_feature(CPUFeature::TSC);
+ if (processor_info.ecx() & (1 << 30))
+ set_feature(CPUFeature::RDRAND);
CPUID extended_processor_info(0x80000001);
- g_cpu_supports_nx = (extended_processor_info.edx() & (1 << 20));
+ if (extended_processor_info.edx() & (1 << 20))
+ set_feature(CPUFeature::NX);
CPUID extended_features(0x7);
- g_cpu_supports_smap = (extended_features.ebx() & (1 << 20));
- g_cpu_supports_smep = (extended_features.ebx() & (1 << 7));
- g_cpu_supports_umip = (extended_features.ecx() & (1 << 2));
- g_cpu_supports_rdseed = (extended_features.ebx() & (1 << 18));
+ if (extended_features.ebx() & (1 << 20))
+ set_feature(CPUFeature::SMAP);
+ if (extended_features.ebx() & (1 << 7))
+ set_feature(CPUFeature::SMEP);
+ if (extended_features.ecx() & (1 << 2))
+ set_feature(CPUFeature::UMIP);
+ if (extended_features.ebx() & (1 << 18))
+ set_feature(CPUFeature::RDSEED);
}
-void cpu_setup(u32 cpu)
+void Processor::cpu_setup()
{
- if (cpu == 0)
- cpu_detect();
+ // NOTE: This is called during Processor::early_initialize, we cannot
+ // safely log at this point because we don't have kmalloc
+ // initialized yet!
+ cpu_detect();
- if (g_cpu_supports_sse) {
+ if (has_feature(CPUFeature::SSE))
sse_init();
- klog() << "x86: SSE support enabled";
- }
asm volatile(
"movl %%cr0, %%eax\n"
"orl $0x00010000, %%eax\n"
"movl %%eax, %%cr0\n" ::
: "%eax", "memory");
- klog() << "x86: WP support enabled";
- if (g_cpu_supports_pge) {
+ if (has_feature(CPUFeature::PGE)) {
// Turn on CR4.PGE so the CPU will respect the G bit in page tables.
asm volatile(
"mov %cr4, %eax\n"
"orl $0x80, %eax\n"
"mov %eax, %cr4\n");
- klog() << "x86: PGE support enabled";
- } else {
- klog() << "x86: PGE support not detected";
}
- if (g_cpu_supports_nx) {
+ if (has_feature(CPUFeature::NX)) {
// Turn on IA32_EFER.NXE
asm volatile(
"movl $0xc0000080, %ecx\n"
"rdmsr\n"
"orl $0x800, %eax\n"
"wrmsr\n");
- klog() << "x86: NX support enabled";
- } else {
- klog() << "x86: NX support not detected";
}
- if (g_cpu_supports_smep) {
+ if (has_feature(CPUFeature::SMEP)) {
// Turn on CR4.SMEP
asm volatile(
"mov %cr4, %eax\n"
"orl $0x100000, %eax\n"
"mov %eax, %cr4\n");
- klog() << "x86: SMEP support enabled";
- } else {
- klog() << "x86: SMEP support not detected";
}
- if (g_cpu_supports_smap) {
+ if (has_feature(CPUFeature::SMAP)) {
// Turn on CR4.SMAP
- klog() << "x86: Enabling SMAP";
asm volatile(
"mov %cr4, %eax\n"
"orl $0x200000, %eax\n"
"mov %eax, %cr4\n");
- klog() << "x86: SMAP support enabled";
- } else {
- klog() << "x86: SMAP support not detected";
}
- if (g_cpu_supports_umip) {
+ if (has_feature(CPUFeature::UMIP)) {
asm volatile(
"mov %cr4, %eax\n"
"orl $0x800, %eax\n"
"mov %eax, %cr4\n");
- klog() << "x86: UMIP support enabled";
}
- if (g_cpu_supports_tsc) {
+ if (has_feature(CPUFeature::TSC)) {
asm volatile(
"mov %cr4, %eax\n"
"orl $0x4, %eax\n"
"mov %eax, %cr4\n");
- klog() << "x86: RDTSC support restricted";
}
-
- if (g_cpu_supports_rdrand) {
- klog() << "x86: Using RDRAND for good randomness";
- } else {
- klog() << "x86: No RDRAND support detected, randomness will be poor";
- }
-}
-
-u32 read_cr0()
-{
- u32 cr0;
- asm("movl %%cr0, %%eax"
- : "=a"(cr0));
- return cr0;
}
-u32 read_cr3()
+String Processor::features_string() const
{
- u32 cr3;
- asm("movl %%cr3, %%eax"
- : "=a"(cr3));
- return cr3;
-}
-
-void write_cr3(u32 cr3)
-{
- asm volatile("movl %%eax, %%cr3" ::"a"(cr3)
- : "memory");
-}
-
-u32 read_cr4()
-{
- u32 cr4;
- asm("movl %%cr4, %%eax"
- : "=a"(cr4));
- return cr4;
-}
-
-u32 read_dr6()
-{
- u32 dr6;
- asm("movl %%dr6, %%eax"
- : "=a"(dr6));
- return dr6;
-}
-
-FPUState Processor::s_clean_fpu_state;
-
-static Vector<Processor*>* s_processors;
-static SpinLock s_processor_lock;
-
-Vector<Processor*>& Processor::processors()
-{
- ASSERT(s_processors);
- return *s_processors;
-}
-
-Processor& Processor::by_id(u32 cpu)
-{
- // s_processors does not need to be protected by a lock of any kind.
- // It is populated early in the boot process, and the BSP is waiting
- // for all APs to finish, after which this array never gets modified
- // again, so it's safe to not protect access to it here
- auto& procs = processors();
- ASSERT(procs[cpu] != nullptr);
- ASSERT(procs.size() > cpu);
- return *procs[cpu];
+ StringBuilder builder;
+ auto feature_to_str =
+ [](CPUFeature f) -> const char*
+ {
+ switch (f) {
+ case CPUFeature::NX:
+ return "nx";
+ case CPUFeature::PAE:
+ return "pae";
+ case CPUFeature::PGE:
+ return "pge";
+ case CPUFeature::RDRAND:
+ return "rdrand";
+ case CPUFeature::RDSEED:
+ return "rdseed";
+ case CPUFeature::SMAP:
+ return "smap";
+ case CPUFeature::SMEP:
+ return "smep";
+ case CPUFeature::SSE:
+ return "sse";
+ case CPUFeature::TSC:
+ return "tsc";
+ case CPUFeature::UMIP:
+ return "umip";
+ // no default statement here intentionally so that we get
+ // a warning if a new feature is forgotten to be added here
+ }
+ // Shouldn't ever happen
+ return "???";
+ };
+ bool first = true;
+ for (u32 flag = 1; flag < sizeof(m_features) * 8; flag <<= 1) {
+ if ((static_cast<u32>(m_features) & flag) != 0) {
+ if (first)
+ first = false;
+ else
+ builder.append(' ');
+ auto str = feature_to_str(static_cast<CPUFeature>(flag));
+ builder.append(str, strlen(str));
+ }
+ }
+ return builder.build();
}
void Processor::early_initialize(u32 cpu)
@@ -838,6 +873,8 @@ void Processor::early_initialize(u32 cpu)
m_mm_data = nullptr;
m_info = nullptr;
+ cpu_setup();
+
gdt_init();
ASSERT(&current() == this); // sanity check
}
@@ -847,12 +884,9 @@ void Processor::initialize(u32 cpu)
ASSERT(m_self == this);
ASSERT(&current() == this); // sanity check
- m_cpu = cpu;
- m_in_irq = 0;
-
- m_idle_thread = nullptr;
- m_current_thread = nullptr;
- m_mm_data = nullptr;
+ klog() << "CPU[" << id() << "]: Supported features: " << features_string();
+ if (!has_feature(CPUFeature::RDRAND))
+ klog() << "CPU[" << id() << "]: No RDRAND support detected, randomness will be poor";
if (cpu == 0)
idt_init();
diff --git a/Kernel/Arch/i386/CPU.h b/Kernel/Arch/i386/CPU.h
index bc41078a70..dfb1b9c52a 100644
--- a/Kernel/Arch/i386/CPU.h
+++ b/Kernel/Arch/i386/CPU.h
@@ -265,7 +265,6 @@ struct RegisterState;
const DescriptorTablePointer& get_gdtr();
const DescriptorTablePointer& get_idtr();
-void sse_init();
void register_interrupt_handler(u8 number, void (*f)());
void register_user_callable_interrupt_handler(u8 number, void (*f)());
GenericInterruptHandler& get_interrupt_handler(u8 interrupt_number);
@@ -599,6 +598,19 @@ private:
SplitQword m_start;
};
+enum class CPUFeature : u32 {
+ NX = (1 << 0),
+ PAE = (1 << 1),
+ PGE = (1 << 2),
+ RDRAND = (1 << 3),
+ RDSEED = (1 << 4),
+ SMAP = (1 << 5),
+ SMEP = (1 << 6),
+ SSE = (1 << 7),
+ TSC = (1 << 8),
+ UMIP = (1 << 9)
+};
+
class Thread;
struct TrapFrame;
@@ -614,6 +626,8 @@ class ProcessorInfo;
struct MemoryManagerData;
class Processor {
+ friend class ProcessorInfo;
+
Processor* m_self; // must be first field (%fs offset 0x0)
DescriptorTablePointer m_gdtr;
@@ -626,6 +640,7 @@ class Processor {
TSS32 m_tss;
static FPUState s_clean_fpu_state;
+ CPUFeature m_features;
ProcessorInfo* m_info;
MemoryManagerData* m_mm_data;
@@ -640,6 +655,11 @@ class Processor {
void write_gdt_entry(u16 selector, Descriptor& descriptor);
static Vector<Processor*>& processors();
+ void cpu_detect();
+ void cpu_setup();
+
+ String features_string() const;
+
public:
void early_initialize(u32 cpu);
void initialize(u32 cpu);
@@ -740,6 +760,11 @@ public:
return s_clean_fpu_state;
}
+ ALWAYS_INLINE bool has_feature(CPUFeature f) const
+ {
+ return (static_cast<u32>(m_features) & static_cast<u32>(f)) != 0;
+ }
+
void check_invoke_scheduler();
void invoke_scheduler_async() { m_invoke_scheduler_async = true; }
@@ -846,22 +871,9 @@ public:
}
};
-void cpu_setup(u32 cpu);
-
-extern bool g_cpu_supports_nx;
-extern bool g_cpu_supports_pae;
-extern bool g_cpu_supports_pge;
-extern bool g_cpu_supports_rdrand;
-extern bool g_cpu_supports_rdseed;
-extern bool g_cpu_supports_smap;
-extern bool g_cpu_supports_smep;
-extern bool g_cpu_supports_sse;
-extern bool g_cpu_supports_tsc;
-extern bool g_cpu_supports_umip;
-
ALWAYS_INLINE void stac()
{
- if (!g_cpu_supports_smap)
+ if (!Processor::current().has_feature(CPUFeature::SMAP))
return;
asm volatile("stac" ::
: "cc");
@@ -869,7 +881,7 @@ ALWAYS_INLINE void stac()
ALWAYS_INLINE void clac()
{
- if (!g_cpu_supports_smap)
+ if (!Processor::current().has_feature(CPUFeature::SMAP))
return;
asm volatile("clac" ::
: "cc");
diff --git a/Kernel/Arch/i386/ProcessorInfo.cpp b/Kernel/Arch/i386/ProcessorInfo.cpp
index 21bb32549e..c56b513cdd 100644
--- a/Kernel/Arch/i386/ProcessorInfo.cpp
+++ b/Kernel/Arch/i386/ProcessorInfo.cpp
@@ -88,6 +88,9 @@ ProcessorInfo::ProcessorInfo(Processor& processor):
copy_brand_string_part_to_buffer(2);
m_brandstr = buffer;
}
+
+ // Cache the CPU feature string
+ m_features = m_processor.features_string();
}
}
diff --git a/Kernel/Arch/i386/ProcessorInfo.h b/Kernel/Arch/i386/ProcessorInfo.h
index 5e71e8c26d..2ea9a19dbe 100644
--- a/Kernel/Arch/i386/ProcessorInfo.h
+++ b/Kernel/Arch/i386/ProcessorInfo.h
@@ -37,6 +37,7 @@ class ProcessorInfo
Processor& m_processor;
String m_cpuid;
String m_brandstr;
+ String m_features;
u32 m_display_model;
u32 m_display_family;
u32 m_stepping;
@@ -47,6 +48,7 @@ public:
const String& cpuid() const { return m_cpuid; }
const String& brandstr() const { return m_brandstr; }
+ const String& features() const { return m_features; }
u32 display_model() const { return m_display_model; }
u32 display_family() const { return m_display_family; }
u32 stepping() const { return m_stepping; }
diff --git a/Kernel/FileSystem/ProcFS.cpp b/Kernel/FileSystem/ProcFS.cpp
index 02b6851068..730581d655 100644
--- a/Kernel/FileSystem/ProcFS.cpp
+++ b/Kernel/FileSystem/ProcFS.cpp
@@ -773,6 +773,7 @@ Optional<KBuffer> procfs$cpuinfo(InodeIdentifier)
builder.appendf("processor: %u\n", proc.id());
builder.appendf("cpuid: %s\n", info.cpuid().characters());
builder.appendf("family: %u\n", info.display_family());
+ builder.appendf("features: %s\n", info.features().characters());
builder.appendf("model: %u\n", info.display_model());
builder.appendf("stepping: %u\n", info.stepping());
builder.appendf("type: %u\n", info.type());
diff --git a/Kernel/Random.cpp b/Kernel/Random.cpp
index a1d2c21836..681093f1e1 100644
--- a/Kernel/Random.cpp
+++ b/Kernel/Random.cpp
@@ -44,10 +44,12 @@ KernelRng& KernelRng::the()
KernelRng::KernelRng()
{
- if (g_cpu_supports_rdseed || g_cpu_supports_rdrand) {
+ bool supports_rdseed = Processor::current().has_feature(CPUFeature::RDSEED);
+ bool supports_rdrand = Processor::current().has_feature(CPUFeature::RDRAND);
+ if (supports_rdseed || supports_rdrand) {
for (size_t i = 0; i < resource().pool_count * resource().reseed_threshold; ++i) {
u32 value = 0;
- if (g_cpu_supports_rdseed) {
+ if (supports_rdseed) {
asm volatile(
"1:\n"
"rdseed %0\n"
diff --git a/Kernel/VM/MemoryManager.cpp b/Kernel/VM/MemoryManager.cpp
index eefa569f3b..a4b4ca9d59 100644
--- a/Kernel/VM/MemoryManager.cpp
+++ b/Kernel/VM/MemoryManager.cpp
@@ -80,7 +80,7 @@ void MemoryManager::protect_kernel_image()
pte.set_writable(false);
}
- if (g_cpu_supports_nx) {
+ if (Processor::current().has_feature(CPUFeature::NX)) {
// Disable execution of the kernel data and bss segments.
for (size_t i = (FlatPtr)&start_of_kernel_data; i < (FlatPtr)&end_of_kernel_bss; i += PAGE_SIZE) {
auto& pte = ensure_pte(kernel_page_directory(), VirtualAddress(i));
diff --git a/Kernel/VM/Region.cpp b/Kernel/VM/Region.cpp
index 5238101a65..2078af52f2 100644
--- a/Kernel/VM/Region.cpp
+++ b/Kernel/VM/Region.cpp
@@ -237,7 +237,7 @@ void Region::map_individual_page_impl(size_t page_index)
pte.set_writable(false);
else
pte.set_writable(is_writable());
- if (g_cpu_supports_nx)
+ if (Processor::current().has_feature(CPUFeature::NX))
pte.set_execute_disabled(!is_executable());
pte.set_user_allowed(is_user_accessible());
#ifdef MM_DEBUG
diff --git a/Kernel/init.cpp b/Kernel/init.cpp
index 4912c11b02..07ea0f3e49 100644
--- a/Kernel/init.cpp
+++ b/Kernel/init.cpp
@@ -106,7 +106,6 @@ extern "C" [[noreturn]] void init()
setup_serial_debug();
s_bsp_processor.early_initialize(0);
- cpu_setup(0);
kmalloc_init();
slab_alloc_init();
@@ -169,7 +168,6 @@ extern "C" [[noreturn]] void init_ap(u32 cpu, Processor* processor_info)
klog() << "CPU #" << cpu << " processor_info at " << VirtualAddress(FlatPtr(processor_info));
- cpu_setup(cpu);
processor_info->initialize(cpu);
MemoryManager::initialize(cpu);