summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorConrad Pankoff <deoxxa@fknsrs.biz>2019-12-26 15:28:30 +1100
committerAndreas Kling <awesomekling@gmail.com>2019-12-26 10:05:51 +0100
commit17aef7dc990973247c8234bd5a9649b68e412ab6 (patch)
treee86abf6ccbf6864a2ab917666bef7f73dffb66c2
parent5be6a4386099ae3f6ad7f84ccba46a4076e1d381 (diff)
downloadserenity-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.cpp35
-rw-r--r--Kernel/VM/MemoryManager.h3
-rw-r--r--Kernel/VM/Region.cpp6
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);