diff options
author | Conrad Pankoff <deoxxa@fknsrs.biz> | 2019-12-26 15:28:30 +1100 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-12-26 10:05:51 +0100 |
commit | 17aef7dc990973247c8234bd5a9649b68e412ab6 (patch) | |
tree | e86abf6ccbf6864a2ab917666bef7f73dffb66c2 | |
parent | 5be6a4386099ae3f6ad7f84ccba46a4076e1d381 (diff) | |
download | serenity-17aef7dc990973247c8234bd5a9649b68e412ab6.zip |
Kernel: Detect support for no-execute (NX) CPU features
Previously we assumed all hosts would have support for IA32_EFER.NXE.
This is mostly true for newer hardware, but older hardware will crash
and burn if you try to use this feature.
Now we check for support via CPUID.80000001[20].
-rw-r--r-- | Kernel/VM/MemoryManager.cpp | 35 | ||||
-rw-r--r-- | Kernel/VM/MemoryManager.h | 3 | ||||
-rw-r--r-- | Kernel/VM/Region.cpp | 6 |
3 files changed, 32 insertions, 12 deletions
diff --git a/Kernel/VM/MemoryManager.cpp b/Kernel/VM/MemoryManager.cpp index 92eaf6a2cc..db2a55e0f7 100644 --- a/Kernel/VM/MemoryManager.cpp +++ b/Kernel/VM/MemoryManager.cpp @@ -22,6 +22,9 @@ MemoryManager& MM MemoryManager::MemoryManager(u32 physical_address_for_kernel_page_tables) { + CPUID id(0x80000001); + m_has_nx_support = (id.edx() & (1 << 20)) != 0; + 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)); @@ -57,12 +60,18 @@ void MemoryManager::initialize_paging() create_identity_mapping(kernel_page_directory(), VirtualAddress(PAGE_SIZE), (8 * MB) - PAGE_SIZE); // Disable execution from 0MB through 1MB (BIOS data, legacy things, ...) - for (size_t i = 0; i < (1 * MB); ++i) - ensure_pte(kernel_page_directory(), VirtualAddress(i)).set_execute_disabled(true); + for (size_t i = 0; i < (1 * MB); ++i) { + auto& pte = ensure_pte(kernel_page_directory(), VirtualAddress(i)); + if (m_has_nx_support) + 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) - kernel_page_directory().table().directory(0)[i].set_execute_disabled(true); + for (size_t i = 1; i < 4; ++i) { + auto& pte = kernel_page_directory().table().directory(0)[i]; + if (m_has_nx_support) + pte.set_execute_disabled(true); + } // FIXME: We should move everything kernel-related above the 0xc0000000 virtual mark. @@ -175,12 +184,18 @@ void MemoryManager::initialize_paging() "orl $0x20, %eax\n" "mov %eax, %cr4\n"); - // Turn on IA32_EFER.NXE - asm volatile( - "movl $0xc0000080, %ecx\n" - "rdmsr\n" - "orl $0x800, %eax\n" - "wrmsr\n"); + if (m_has_nx_support) { + kprintf("MM: NX support detected; enabling NXE flag\n"); + + // Turn on IA32_EFER.NXE + asm volatile( + "movl $0xc0000080, %ecx\n" + "rdmsr\n" + "orl $0x800, %eax\n" + "wrmsr\n"); + } else { + kprintf("MM: NX support not detected\n"); + } asm volatile("movl %%eax, %%cr3" ::"a"(kernel_page_directory().cr3())); asm volatile( diff --git a/Kernel/VM/MemoryManager.h b/Kernel/VM/MemoryManager.h index 53596b3589..574c4984cb 100644 --- a/Kernel/VM/MemoryManager.h +++ b/Kernel/VM/MemoryManager.h @@ -111,6 +111,8 @@ private: PageTableEntry& ensure_pte(PageDirectory&, VirtualAddress); + bool has_nx_support() const { return m_has_nx_support; } + RefPtr<PageDirectory> m_kernel_page_directory; PageTableEntry* m_low_page_tables[4] { nullptr }; @@ -130,6 +132,7 @@ private: InlineLinkedList<VMObject> m_vmobjects; bool m_quickmap_in_use { false }; + bool m_has_nx_support { false }; }; struct ProcessPagingScope { diff --git a/Kernel/VM/Region.cpp b/Kernel/VM/Region.cpp index 5db615661f..c2a21e89bf 100644 --- a/Kernel/VM/Region.cpp +++ b/Kernel/VM/Region.cpp @@ -216,7 +216,8 @@ void Region::remap_page(size_t index) pte.set_writable(false); else pte.set_writable(is_writable()); - pte.set_execute_disabled(!is_executable()); + if (MM.has_nx_support()) + pte.set_execute_disabled(!is_executable()); pte.set_user_allowed(is_user_accessible()); m_page_directory->flush(page_vaddr); #ifdef MM_DEBUG @@ -265,7 +266,8 @@ void Region::map(PageDirectory& page_directory) pte.set_writable(false); else pte.set_writable(is_writable()); - pte.set_execute_disabled(!is_executable()); + if (MM.has_nx_support()) + pte.set_execute_disabled(!is_executable()); } else { pte.set_physical_page_base(0); pte.set_present(false); |