From 9b4e6f6a23e1669d21e18eb985323f7075de275a Mon Sep 17 00:00:00 2001 From: Tom Date: Fri, 3 Jul 2020 10:23:09 -0600 Subject: [PATCH] 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 --- Kernel/Arch/i386/CPU.cpp | 280 ++++++++++++++++------------- Kernel/Arch/i386/CPU.h | 44 +++-- Kernel/Arch/i386/ProcessorInfo.cpp | 3 + Kernel/Arch/i386/ProcessorInfo.h | 2 + Kernel/FileSystem/ProcFS.cpp | 1 + Kernel/Random.cpp | 6 +- Kernel/VM/MemoryManager.cpp | 2 +- Kernel/VM/Region.cpp | 2 +- Kernel/init.cpp | 2 - 9 files changed, 197 insertions(+), 145 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 #include +#include #include #include #include @@ -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,122 +646,6 @@ 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() -{ - 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)); - - CPUID extended_processor_info(0x80000001); - g_cpu_supports_nx = (extended_processor_info.edx() & (1 << 20)); - - 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)); -} - -void cpu_setup(u32 cpu) -{ - if (cpu == 0) - cpu_detect(); - - if (g_cpu_supports_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) { - // 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) { - // 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) { - // 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) { - // 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) { - asm volatile( - "mov %cr4, %eax\n" - "orl $0x800, %eax\n" - "mov %eax, %cr4\n"); - klog() << "x86: UMIP support enabled"; - } - - if (g_cpu_supports_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; @@ -822,6 +707,156 @@ Processor& Processor::by_id(u32 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(static_cast(m_features) | static_cast(f)); + }; + m_features = static_cast(0); + + CPUID processor_info(0x1); + 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); + if (extended_processor_info.edx() & (1 << 20)) + set_feature(CPUFeature::NX); + + CPUID extended_features(0x7); + 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 Processor::cpu_setup() +{ + // 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 (has_feature(CPUFeature::SSE)) + sse_init(); + + asm volatile( + "movl %%cr0, %%eax\n" + "orl $0x00010000, %%eax\n" + "movl %%eax, %%cr0\n" :: + : "%eax", "memory"); + + 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"); + } + + if (has_feature(CPUFeature::NX)) { + // Turn on IA32_EFER.NXE + asm volatile( + "movl $0xc0000080, %ecx\n" + "rdmsr\n" + "orl $0x800, %eax\n" + "wrmsr\n"); + } + + if (has_feature(CPUFeature::SMEP)) { + // Turn on CR4.SMEP + asm volatile( + "mov %cr4, %eax\n" + "orl $0x100000, %eax\n" + "mov %eax, %cr4\n"); + } + + if (has_feature(CPUFeature::SMAP)) { + // Turn on CR4.SMAP + asm volatile( + "mov %cr4, %eax\n" + "orl $0x200000, %eax\n" + "mov %eax, %cr4\n"); + } + + if (has_feature(CPUFeature::UMIP)) { + asm volatile( + "mov %cr4, %eax\n" + "orl $0x800, %eax\n" + "mov %eax, %cr4\n"); + } + + if (has_feature(CPUFeature::TSC)) { + asm volatile( + "mov %cr4, %eax\n" + "orl $0x4, %eax\n" + "mov %eax, %cr4\n"); + } +} + +String Processor::features_string() const +{ + 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(m_features) & flag) != 0) { + if (first) + first = false; + else + builder.append(' '); + auto str = feature_to_str(static_cast(flag)); + builder.append(str, strlen(str)); + } + } + return builder.build(); +} + void Processor::early_initialize(u32 cpu) { m_self = this; @@ -838,6 +873,8 @@ void Processor::early_initialize(u32 cpu) m_mm_data = nullptr; m_info = nullptr; + cpu_setup(); + gdt_init(); ASSERT(¤t() == this); // sanity check } @@ -847,12 +884,9 @@ void Processor::initialize(u32 cpu) ASSERT(m_self == this); ASSERT(¤t() == 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& 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(m_features) & static_cast(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 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);