diff options
author | Tom <tomut@yahoo.com> | 2020-07-03 10:23:09 -0600 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-07-03 19:32:34 +0200 |
commit | 9b4e6f6a23e1669d21e18eb985323f7075de275a (patch) | |
tree | b16609be64fbe5112d6961cc575ad58806d1a80f | |
parent | e373e5f007956e59d8efca1fe74ce0e84355b27b (diff) | |
download | serenity-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.cpp | 276 | ||||
-rw-r--r-- | Kernel/Arch/i386/CPU.h | 44 | ||||
-rw-r--r-- | Kernel/Arch/i386/ProcessorInfo.cpp | 3 | ||||
-rw-r--r-- | Kernel/Arch/i386/ProcessorInfo.h | 2 | ||||
-rw-r--r-- | Kernel/FileSystem/ProcFS.cpp | 1 | ||||
-rw-r--r-- | Kernel/Random.cpp | 6 | ||||
-rw-r--r-- | Kernel/VM/MemoryManager.cpp | 2 | ||||
-rw-r--r-- | Kernel/VM/Region.cpp | 2 | ||||
-rw-r--r-- | Kernel/init.cpp | 2 |
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(¤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<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); |