diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 6e7f0f73ba..df9f5649f1 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -333,7 +333,7 @@ int Process::do_exec(String path, Vector arguments, Vector envir u32 entry_eip = 0; // FIXME: Is there a race here? auto old_page_directory = move(m_page_directory); - m_page_directory = PageDirectory::create_for_userspace(); + m_page_directory = PageDirectory::create_for_userspace(*this); #ifdef MM_DEBUG dbgprintf("Process %u exec: PD=%x created\n", pid(), m_page_directory.ptr()); #endif @@ -590,7 +590,7 @@ Process::Process(String&& name, uid_t uid, gid_t gid, pid_t ppid, RingLevel ring { dbgprintf("Process: New process PID=%u with name=%s\n", m_pid, m_name.characters()); - m_page_directory = PageDirectory::create_for_userspace(fork_parent ? &fork_parent->page_directory().range_allocator() : nullptr); + m_page_directory = PageDirectory::create_for_userspace(*this, fork_parent ? &fork_parent->page_directory().range_allocator() : nullptr); #ifdef MM_DEBUG dbgprintf("Process %u ctor: PD=%x created\n", pid(), m_page_directory.ptr()); #endif diff --git a/Kernel/VM/MemoryManager.cpp b/Kernel/VM/MemoryManager.cpp index 51e75a2f94..fd0ff993ac 100644 --- a/Kernel/VM/MemoryManager.cpp +++ b/Kernel/VM/MemoryManager.cpp @@ -257,7 +257,8 @@ void MemoryManager::initialize() Region* MemoryManager::kernel_region_from_vaddr(VirtualAddress vaddr) { - ASSERT(vaddr.get() >= 0xc0000000); + if (vaddr.get() < 0xc0000000) + return nullptr; for (auto& region : MM.m_kernel_regions) { if (region->contains(vaddr)) return region; @@ -279,18 +280,15 @@ Region* MemoryManager::user_region_from_vaddr(Process& process, VirtualAddress v Region* MemoryManager::region_from_vaddr(Process& process, VirtualAddress vaddr) { ASSERT_INTERRUPTS_DISABLED(); - - if (vaddr.get() >= 0xc0000000) - return kernel_region_from_vaddr(vaddr); - + if (auto* region = kernel_region_from_vaddr(vaddr)) + return region; return user_region_from_vaddr(process, vaddr); } const Region* MemoryManager::region_from_vaddr(const Process& process, VirtualAddress vaddr) { - if (vaddr.get() >= 0xc0000000) - return kernel_region_from_vaddr(vaddr); - + if (auto* region = kernel_region_from_vaddr(vaddr)) + return region; return user_region_from_vaddr(const_cast(process), vaddr); } @@ -398,6 +396,17 @@ bool MemoryManager::page_in_from_inode(Region& region, unsigned page_index_in_re return true; } +Region* MemoryManager::region_from_vaddr(VirtualAddress vaddr) +{ + if (auto* region = kernel_region_from_vaddr(vaddr)) + return region; + auto page_directory = PageDirectory::find_by_pdb(cpu_cr3()); + if (!page_directory) + return nullptr; + ASSERT(page_directory->process()); + return user_region_from_vaddr(*page_directory->process(), vaddr); +} + PageFaultResponse MemoryManager::handle_page_fault(const PageFault& fault) { ASSERT_INTERRUPTS_DISABLED(); @@ -417,7 +426,7 @@ PageFaultResponse MemoryManager::handle_page_fault(const PageFault& fault) return PageFaultResponse::Continue; } } - auto* region = region_from_vaddr(current->process(), fault.vaddr()); + auto* region = region_from_vaddr(fault.vaddr()); if (!region) { kprintf("NP(error) fault at invalid address L%x\n", fault.vaddr().get()); return PageFaultResponse::ShouldCrash; diff --git a/Kernel/VM/MemoryManager.h b/Kernel/VM/MemoryManager.h index 6c4884a319..255c1a39ee 100644 --- a/Kernel/VM/MemoryManager.h +++ b/Kernel/VM/MemoryManager.h @@ -108,6 +108,8 @@ private: static Region* user_region_from_vaddr(Process&, VirtualAddress); static Region* kernel_region_from_vaddr(VirtualAddress); + static Region* region_from_vaddr(VirtualAddress); + bool copy_on_write(Region&, unsigned page_index_in_region); bool page_in_from_inode(Region&, unsigned page_index_in_region); bool zero_page(Region& region, unsigned page_index_in_region); diff --git a/Kernel/VM/PageDirectory.cpp b/Kernel/VM/PageDirectory.cpp index f6d401a38f..8283883fad 100644 --- a/Kernel/VM/PageDirectory.cpp +++ b/Kernel/VM/PageDirectory.cpp @@ -6,16 +6,36 @@ static const u32 userspace_range_base = 0x01000000; static const u32 kernelspace_range_base = 0xc0000000; +static HashMap& pdb_map() +{ + ASSERT_INTERRUPTS_DISABLED(); + static HashMap* map; + if (!map) + map = new HashMap; + return *map; +} + +RefPtr PageDirectory::find_by_pdb(u32 pdb) +{ + InterruptDisabler disabler; + return pdb_map().get(pdb).value_or({}); +} + PageDirectory::PageDirectory(PhysicalAddress paddr) : m_range_allocator(VirtualAddress(0xc0000000), 0x3f000000) { m_directory_page = PhysicalPage::create(paddr, true, false); + InterruptDisabler disabler; + pdb_map().set(m_directory_page->paddr().get(), this); } -PageDirectory::PageDirectory(const RangeAllocator* parent_range_allocator) - : m_range_allocator(parent_range_allocator ? RangeAllocator(*parent_range_allocator) : RangeAllocator(VirtualAddress(userspace_range_base), kernelspace_range_base - userspace_range_base)) +PageDirectory::PageDirectory(Process& process, const RangeAllocator* parent_range_allocator) + : m_process(&process) + , m_range_allocator(parent_range_allocator ? RangeAllocator(*parent_range_allocator) : RangeAllocator(VirtualAddress(userspace_range_base), kernelspace_range_base - userspace_range_base)) { MM.populate_page_directory(*this); + InterruptDisabler disabler; + pdb_map().set(m_directory_page->paddr().get(), this); } PageDirectory::~PageDirectory() @@ -23,6 +43,8 @@ PageDirectory::~PageDirectory() #ifdef MM_DEBUG dbgprintf("MM: ~PageDirectory K%x\n", this); #endif + InterruptDisabler disabler; + pdb_map().remove(m_directory_page->paddr().get()); } void PageDirectory::flush(VirtualAddress vaddr) diff --git a/Kernel/VM/PageDirectory.h b/Kernel/VM/PageDirectory.h index 7eecd07d16..b6458c1055 100644 --- a/Kernel/VM/PageDirectory.h +++ b/Kernel/VM/PageDirectory.h @@ -1,17 +1,24 @@ #pragma once #include -#include #include +#include #include #include +class Process; + class PageDirectory : public RefCounted { friend class MemoryManager; public: - static NonnullRefPtr create_for_userspace(const RangeAllocator* parent_range_allocator = nullptr) { return adopt(*new PageDirectory(parent_range_allocator)); } + static NonnullRefPtr create_for_userspace(Process& process, const RangeAllocator* parent_range_allocator = nullptr) + { + return adopt(*new PageDirectory(process, parent_range_allocator)); + } static NonnullRefPtr create_at_fixed_address(PhysicalAddress paddr) { return adopt(*new PageDirectory(paddr)); } + static RefPtr find_by_pdb(u32); + ~PageDirectory(); u32 cr3() const { return m_directory_page->paddr().get(); } @@ -21,10 +28,14 @@ public: RangeAllocator& range_allocator() { return m_range_allocator; } + Process* process() { return m_process; } + const Process* process() const { return m_process; } + private: - explicit PageDirectory(const RangeAllocator* parent_range_allocator); + PageDirectory(Process&, const RangeAllocator* parent_range_allocator); explicit PageDirectory(PhysicalAddress); + Process* m_process { nullptr }; RangeAllocator m_range_allocator; RefPtr m_directory_page; HashMap> m_physical_pages;