From 5aeaab601ec60df85152482cb97c12f9d503c68e Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 1 Jan 2020 12:56:21 +0100 Subject: [PATCH] Kernel: Move CPU feature detection to Arch/x86/CPU.{cpp.h} We now refuse to boot on machines that don't support PAE since all of our paging code depends on it. Also let's only enable SSE and PGE support if the CPU advertises it. --- Kernel/Arch/i386/CPU.cpp | 22 +++++++++++++- Kernel/Arch/i386/CPU.h | 7 +++++ Kernel/VM/MemoryManager.cpp | 58 ++++++++++++++++++------------------- Kernel/VM/MemoryManager.h | 4 --- Kernel/VM/Region.cpp | 4 +-- Kernel/init.cpp | 19 +++++++----- 6 files changed, 70 insertions(+), 44 deletions(-) diff --git a/Kernel/Arch/i386/CPU.cpp b/Kernel/Arch/i386/CPU.cpp index 1d713b584d..12c05f6cc3 100644 --- a/Kernel/Arch/i386/CPU.cpp +++ b/Kernel/Arch/i386/CPU.cpp @@ -283,7 +283,7 @@ void page_fault_handler(RegisterDump regs) current->process().name().characters(), current->pid(), current->tid(), - regs.exception_code & PageFaultFlags::ReservedBitViolation ? "reserved bit violation / " : "", + regs.exception_code & PageFaultFlags::ReservedBitViolation ? "reserved bit violation / " : "", regs.exception_code & PageFaultFlags::InstructionFetch ? "instruction fetch / " : "", regs.exception_code & PageFaultFlags::Write ? "write to" : "read from", fault_address); @@ -543,3 +543,23 @@ void sse_init() "orl $0x600, %eax\n" "mov %eax, %cr4\n"); } + +bool g_cpu_supports_nx; +bool g_cpu_supports_pae; +bool g_cpu_supports_pge; +bool g_cpu_supports_smep; +bool g_cpu_supports_sse; + +void detect_cpu_features() +{ + 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)); + + CPUID extended_processor_info(0x80000001); + g_cpu_supports_nx = (extended_processor_info.edx() & (1 << 20)); + + CPUID extended_features(0x7); + g_cpu_supports_smep = (extended_features.ebx() & (1 << 7)); +} diff --git a/Kernel/Arch/i386/CPU.h b/Kernel/Arch/i386/CPU.h index d946a783f0..9c831ad067 100644 --- a/Kernel/Arch/i386/CPU.h +++ b/Kernel/Arch/i386/CPU.h @@ -506,3 +506,10 @@ public: asm volatile("wrmsr" ::"a"(low), "d"(high), "c"(m_msr)); } }; + +void detect_cpu_features(); +extern bool g_cpu_supports_nx; +extern bool g_cpu_supports_pae; +extern bool g_cpu_supports_pge; +extern bool g_cpu_supports_smep; +extern bool g_cpu_supports_sse; diff --git a/Kernel/VM/MemoryManager.cpp b/Kernel/VM/MemoryManager.cpp index 2eb472ad7b..0b67633d52 100644 --- a/Kernel/VM/MemoryManager.cpp +++ b/Kernel/VM/MemoryManager.cpp @@ -21,19 +21,8 @@ MemoryManager& MM return *s_the; } -void MemoryManager::detect_cpu_features() -{ - CPUID extended_processor_info(0x80000001); - m_has_nx_support = (extended_processor_info.edx() & (1 << 20)) != 0; - - CPUID extended_features(0x7); - m_has_smep_support = (extended_features.ebx() & (1 << 7)) != 0; -} - MemoryManager::MemoryManager(u32 physical_address_for_kernel_page_tables) { - detect_cpu_features(); - m_kernel_page_directory = PageDirectory::create_at_fixed_address(PhysicalAddress(physical_address_for_kernel_page_tables)); for (size_t i = 0; i < 4; ++i) { m_low_page_tables[i] = (PageTableEntry*)(physical_address_for_kernel_page_tables + PAGE_SIZE * (5 + i)); @@ -51,6 +40,11 @@ MemoryManager::~MemoryManager() void MemoryManager::initialize_paging() { + if (!g_cpu_supports_pae) { + kprintf("x86: Cannot boot on machines without PAE support.\n"); + hang(); + } + #ifdef MM_DEBUG dbgprintf("MM: Kernel page directory @ %p\n", kernel_page_directory().cr3()); #endif @@ -71,14 +65,14 @@ void MemoryManager::initialize_paging() // Disable execution from 0MB through 1MB (BIOS data, legacy things, ...) for (size_t i = 0; i < (1 * MB); ++i) { auto& pte = ensure_pte(kernel_page_directory(), VirtualAddress(i)); - if (m_has_nx_support) + if (g_cpu_supports_nx) pte.set_execute_disabled(true); } // Disable execution from 2MB through 8MB (kmalloc, kmalloc_eternal, slabs, page tables, ...) for (size_t i = 1; i < 4; ++i) { auto& pte = kernel_page_directory().table().directory(0)[i]; - if (m_has_nx_support) + if (g_cpu_supports_nx) pte.set_execute_disabled(true); } @@ -181,40 +175,44 @@ void MemoryManager::initialize_paging() dbgprintf("MM: Installing page directory\n"); #endif - // 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"); - // Turn on CR4.PAE asm volatile( "mov %cr4, %eax\n" "orl $0x20, %eax\n" "mov %eax, %cr4\n"); - if (m_has_smep_support) { - kprintf("MM: SMEP support detected; enabling\n"); - // Turn on CR4.SMEP - asm volatile( - "mov %cr4, %eax\n" - "orl $0x100000, %eax\n" - "mov %eax, %cr4\n"); + 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"); + kprintf("x86: PGE support enabled\n"); } else { - kprintf("MM: SMEP support not detected\n"); + kprintf("x86: PGE support not detected\n"); } - if (m_has_nx_support) { - kprintf("MM: NX support detected; enabling NXE flag\n"); + if (g_cpu_supports_smep) { + // Turn on CR4.SMEP + asm volatile( + "mov %cr4, %eax\n" + "orl $0x100000, %eax\n" + "mov %eax, %cr4\n"); + kprintf("x86: SMEP support enabled\n"); + } else { + kprintf("x86: SMEP support not detected\n"); + } + if (g_cpu_supports_nx) { // Turn on IA32_EFER.NXE asm volatile( "movl $0xc0000080, %ecx\n" "rdmsr\n" "orl $0x800, %eax\n" "wrmsr\n"); + kprintf("x86: NX support enabled\n"); } else { - kprintf("MM: NX support not detected\n"); + kprintf("x86: NX support not detected\n"); } asm volatile("movl %%eax, %%cr3" ::"a"(kernel_page_directory().cr3())); diff --git a/Kernel/VM/MemoryManager.h b/Kernel/VM/MemoryManager.h index e8bca5248f..967e681a2c 100644 --- a/Kernel/VM/MemoryManager.h +++ b/Kernel/VM/MemoryManager.h @@ -112,8 +112,6 @@ private: PageTableEntry& ensure_pte(PageDirectory&, VirtualAddress); - bool has_nx_support() const { return m_has_nx_support; } - RefPtr m_kernel_page_directory; PageTableEntry* m_low_page_tables[4] { nullptr }; @@ -133,8 +131,6 @@ private: InlineLinkedList m_vmobjects; bool m_quickmap_in_use { false }; - bool m_has_nx_support { false }; - bool m_has_smep_support { false }; }; struct ProcessPagingScope { diff --git a/Kernel/VM/Region.cpp b/Kernel/VM/Region.cpp index 6278d69e75..01a2bc353b 100644 --- a/Kernel/VM/Region.cpp +++ b/Kernel/VM/Region.cpp @@ -223,7 +223,7 @@ void Region::remap_page(size_t index) pte.set_writable(false); else pte.set_writable(is_writable()); - if (MM.has_nx_support()) + if (g_cpu_supports_nx) pte.set_execute_disabled(!is_executable()); pte.set_user_allowed(is_user_accessible()); m_page_directory->flush(page_vaddr); @@ -273,7 +273,7 @@ void Region::map(PageDirectory& page_directory) pte.set_writable(false); else pte.set_writable(is_writable()); - if (MM.has_nx_support()) + if (g_cpu_supports_nx) pte.set_execute_disabled(!is_executable()); } else { pte.set_physical_page_base(0); diff --git a/Kernel/init.cpp b/Kernel/init.cpp index 8acf7460fc..05d3be0b89 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -5,8 +5,8 @@ #include "Scheduler.h" #include "kstdio.h" #include -#include #include +#include #include #include #include @@ -199,7 +199,7 @@ extern "C" { multiboot_info_t* multiboot_info_ptr; } -typedef void (*ctor_func_t)(); +typedef void (*ctor_func_t)(); // Defined in the linker script extern ctor_func_t start_ctors; @@ -207,9 +207,9 @@ extern ctor_func_t end_ctors; // Define some Itanium C++ ABI methods to stop the linker from complaining // If we actually call these something has gone horribly wrong -void* __dso_handle __attribute__((visibility ("hidden"))); +void* __dso_handle __attribute__((visibility("hidden"))); -extern "C" int __cxa_atexit ( void (*)(void *), void *, void *) +extern "C" int __cxa_atexit(void (*)(void*), void*, void*) { ASSERT_NOT_REACHED(); return 0; @@ -236,7 +236,7 @@ extern "C" [[noreturn]] void init(u32 physical_address_for_kernel_page_tables) if (multiboot_info_ptr->cmdline && bad_prefix_check(reinterpret_cast(multiboot_info_ptr->cmdline), "serial_debug")) set_serial_debug(true); - sse_init(); + detect_cpu_features(); kmalloc_init(); slab_alloc_init(); @@ -251,6 +251,13 @@ extern "C" [[noreturn]] void init(u32 physical_address_for_kernel_page_tables) auto console = make(); + kprintf("Starting SerenityOS...\n"); + + if (g_cpu_supports_sse) { + sse_init(); + kprintf("x86: SSE support enabled\n"); + } + RTC::initialize(); PIC::initialize(); gdt_init(); @@ -275,8 +282,6 @@ extern "C" [[noreturn]] void init(u32 physical_address_for_kernel_page_tables) tty1 = new VirtualConsole(1); VirtualConsole::switch_to(0); - kprintf("Starting SerenityOS...\n"); - MemoryManager::initialize(physical_address_for_kernel_page_tables); if (APIC::init())