1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-24 17:17:42 +00:00

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.
This commit is contained in:
Andreas Kling 2020-01-01 12:56:21 +01:00
parent 3d59db4be4
commit 5aeaab601e
6 changed files with 70 additions and 44 deletions

View file

@ -283,7 +283,7 @@ void page_fault_handler(RegisterDump regs)
current->process().name().characters(), current->process().name().characters(),
current->pid(), current->pid(),
current->tid(), 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::InstructionFetch ? "instruction fetch / " : "",
regs.exception_code & PageFaultFlags::Write ? "write to" : "read from", regs.exception_code & PageFaultFlags::Write ? "write to" : "read from",
fault_address); fault_address);
@ -543,3 +543,23 @@ void sse_init()
"orl $0x600, %eax\n" "orl $0x600, %eax\n"
"mov %eax, %cr4\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));
}

View file

@ -506,3 +506,10 @@ public:
asm volatile("wrmsr" ::"a"(low), "d"(high), "c"(m_msr)); 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;

View file

@ -21,19 +21,8 @@ MemoryManager& MM
return *s_the; 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) 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)); m_kernel_page_directory = PageDirectory::create_at_fixed_address(PhysicalAddress(physical_address_for_kernel_page_tables));
for (size_t i = 0; i < 4; ++i) { for (size_t i = 0; i < 4; ++i) {
m_low_page_tables[i] = (PageTableEntry*)(physical_address_for_kernel_page_tables + PAGE_SIZE * (5 + 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() void MemoryManager::initialize_paging()
{ {
if (!g_cpu_supports_pae) {
kprintf("x86: Cannot boot on machines without PAE support.\n");
hang();
}
#ifdef MM_DEBUG #ifdef MM_DEBUG
dbgprintf("MM: Kernel page directory @ %p\n", kernel_page_directory().cr3()); dbgprintf("MM: Kernel page directory @ %p\n", kernel_page_directory().cr3());
#endif #endif
@ -71,14 +65,14 @@ void MemoryManager::initialize_paging()
// Disable execution from 0MB through 1MB (BIOS data, legacy things, ...) // Disable execution from 0MB through 1MB (BIOS data, legacy things, ...)
for (size_t i = 0; i < (1 * MB); ++i) { for (size_t i = 0; i < (1 * MB); ++i) {
auto& pte = ensure_pte(kernel_page_directory(), VirtualAddress(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); pte.set_execute_disabled(true);
} }
// Disable execution from 2MB through 8MB (kmalloc, kmalloc_eternal, slabs, page tables, ...) // Disable execution from 2MB through 8MB (kmalloc, kmalloc_eternal, slabs, page tables, ...)
for (size_t i = 1; i < 4; ++i) { for (size_t i = 1; i < 4; ++i) {
auto& pte = kernel_page_directory().table().directory(0)[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); pte.set_execute_disabled(true);
} }
@ -181,40 +175,44 @@ void MemoryManager::initialize_paging()
dbgprintf("MM: Installing page directory\n"); dbgprintf("MM: Installing page directory\n");
#endif #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 // Turn on CR4.PAE
asm volatile( asm volatile(
"mov %cr4, %eax\n" "mov %cr4, %eax\n"
"orl $0x20, %eax\n" "orl $0x20, %eax\n"
"mov %eax, %cr4\n"); "mov %eax, %cr4\n");
if (m_has_smep_support) { if (g_cpu_supports_pge) {
kprintf("MM: SMEP support detected; enabling\n"); // Turn on CR4.PGE so the CPU will respect the G bit in page tables.
// Turn on CR4.SMEP asm volatile(
asm volatile( "mov %cr4, %eax\n"
"mov %cr4, %eax\n" "orl $0x80, %eax\n"
"orl $0x100000, %eax\n" "mov %eax, %cr4\n");
"mov %eax, %cr4\n"); kprintf("x86: PGE support enabled\n");
} else { } else {
kprintf("MM: SMEP support not detected\n"); kprintf("x86: PGE support not detected\n");
} }
if (m_has_nx_support) { if (g_cpu_supports_smep) {
kprintf("MM: NX support detected; enabling NXE flag\n"); // 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 // Turn on IA32_EFER.NXE
asm volatile( asm volatile(
"movl $0xc0000080, %ecx\n" "movl $0xc0000080, %ecx\n"
"rdmsr\n" "rdmsr\n"
"orl $0x800, %eax\n" "orl $0x800, %eax\n"
"wrmsr\n"); "wrmsr\n");
kprintf("x86: NX support enabled\n");
} else { } 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())); asm volatile("movl %%eax, %%cr3" ::"a"(kernel_page_directory().cr3()));

View file

@ -112,8 +112,6 @@ private:
PageTableEntry& ensure_pte(PageDirectory&, VirtualAddress); PageTableEntry& ensure_pte(PageDirectory&, VirtualAddress);
bool has_nx_support() const { return m_has_nx_support; }
RefPtr<PageDirectory> m_kernel_page_directory; RefPtr<PageDirectory> m_kernel_page_directory;
PageTableEntry* m_low_page_tables[4] { nullptr }; PageTableEntry* m_low_page_tables[4] { nullptr };
@ -133,8 +131,6 @@ private:
InlineLinkedList<VMObject> m_vmobjects; InlineLinkedList<VMObject> m_vmobjects;
bool m_quickmap_in_use { false }; bool m_quickmap_in_use { false };
bool m_has_nx_support { false };
bool m_has_smep_support { false };
}; };
struct ProcessPagingScope { struct ProcessPagingScope {

View file

@ -223,7 +223,7 @@ void Region::remap_page(size_t index)
pte.set_writable(false); pte.set_writable(false);
else else
pte.set_writable(is_writable()); pte.set_writable(is_writable());
if (MM.has_nx_support()) if (g_cpu_supports_nx)
pte.set_execute_disabled(!is_executable()); pte.set_execute_disabled(!is_executable());
pte.set_user_allowed(is_user_accessible()); pte.set_user_allowed(is_user_accessible());
m_page_directory->flush(page_vaddr); m_page_directory->flush(page_vaddr);
@ -273,7 +273,7 @@ void Region::map(PageDirectory& page_directory)
pte.set_writable(false); pte.set_writable(false);
else else
pte.set_writable(is_writable()); pte.set_writable(is_writable());
if (MM.has_nx_support()) if (g_cpu_supports_nx)
pte.set_execute_disabled(!is_executable()); pte.set_execute_disabled(!is_executable());
} else { } else {
pte.set_physical_page_base(0); pte.set_physical_page_base(0);

View file

@ -5,8 +5,8 @@
#include "Scheduler.h" #include "Scheduler.h"
#include "kstdio.h" #include "kstdio.h"
#include <AK/Types.h> #include <AK/Types.h>
#include <Kernel/Arch/i386/CPU.h>
#include <Kernel/Arch/i386/APIC.h> #include <Kernel/Arch/i386/APIC.h>
#include <Kernel/Arch/i386/CPU.h>
#include <Kernel/Arch/i386/PIC.h> #include <Kernel/Arch/i386/PIC.h>
#include <Kernel/Arch/i386/PIT.h> #include <Kernel/Arch/i386/PIT.h>
#include <Kernel/CMOS.h> #include <Kernel/CMOS.h>
@ -199,7 +199,7 @@ extern "C" {
multiboot_info_t* multiboot_info_ptr; multiboot_info_t* multiboot_info_ptr;
} }
typedef void (*ctor_func_t)(); typedef void (*ctor_func_t)();
// Defined in the linker script // Defined in the linker script
extern ctor_func_t start_ctors; 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 // Define some Itanium C++ ABI methods to stop the linker from complaining
// If we actually call these something has gone horribly wrong // 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(); ASSERT_NOT_REACHED();
return 0; 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<const char*>(multiboot_info_ptr->cmdline), "serial_debug")) if (multiboot_info_ptr->cmdline && bad_prefix_check(reinterpret_cast<const char*>(multiboot_info_ptr->cmdline), "serial_debug"))
set_serial_debug(true); set_serial_debug(true);
sse_init(); detect_cpu_features();
kmalloc_init(); kmalloc_init();
slab_alloc_init(); slab_alloc_init();
@ -251,6 +251,13 @@ extern "C" [[noreturn]] void init(u32 physical_address_for_kernel_page_tables)
auto console = make<Console>(); auto console = make<Console>();
kprintf("Starting SerenityOS...\n");
if (g_cpu_supports_sse) {
sse_init();
kprintf("x86: SSE support enabled\n");
}
RTC::initialize(); RTC::initialize();
PIC::initialize(); PIC::initialize();
gdt_init(); gdt_init();
@ -275,8 +282,6 @@ extern "C" [[noreturn]] void init(u32 physical_address_for_kernel_page_tables)
tty1 = new VirtualConsole(1); tty1 = new VirtualConsole(1);
VirtualConsole::switch_to(0); VirtualConsole::switch_to(0);
kprintf("Starting SerenityOS...\n");
MemoryManager::initialize(physical_address_for_kernel_page_tables); MemoryManager::initialize(physical_address_for_kernel_page_tables);
if (APIC::init()) if (APIC::init())