mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 00:48:11 +00:00
Kernel: Add mapping from page directory base (PDB) to PageDirectory
This allows the page fault code to find the owning PageDirectory and corresponding process for faulting regions. The mapping is implemented as a global hash map right now, which is definitely not optimal. We can come up with something better when it becomes necessary.
This commit is contained in:
parent
8d07bce12a
commit
2ad963d261
5 changed files with 60 additions and 16 deletions
|
@ -333,7 +333,7 @@ int Process::do_exec(String path, Vector<String> arguments, Vector<String> envir
|
||||||
u32 entry_eip = 0;
|
u32 entry_eip = 0;
|
||||||
// FIXME: Is there a race here?
|
// FIXME: Is there a race here?
|
||||||
auto old_page_directory = move(m_page_directory);
|
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
|
#ifdef MM_DEBUG
|
||||||
dbgprintf("Process %u exec: PD=%x created\n", pid(), m_page_directory.ptr());
|
dbgprintf("Process %u exec: PD=%x created\n", pid(), m_page_directory.ptr());
|
||||||
#endif
|
#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());
|
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
|
#ifdef MM_DEBUG
|
||||||
dbgprintf("Process %u ctor: PD=%x created\n", pid(), m_page_directory.ptr());
|
dbgprintf("Process %u ctor: PD=%x created\n", pid(), m_page_directory.ptr());
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -257,7 +257,8 @@ void MemoryManager::initialize()
|
||||||
|
|
||||||
Region* MemoryManager::kernel_region_from_vaddr(VirtualAddress vaddr)
|
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) {
|
for (auto& region : MM.m_kernel_regions) {
|
||||||
if (region->contains(vaddr))
|
if (region->contains(vaddr))
|
||||||
return region;
|
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)
|
Region* MemoryManager::region_from_vaddr(Process& process, VirtualAddress vaddr)
|
||||||
{
|
{
|
||||||
ASSERT_INTERRUPTS_DISABLED();
|
ASSERT_INTERRUPTS_DISABLED();
|
||||||
|
if (auto* region = kernel_region_from_vaddr(vaddr))
|
||||||
if (vaddr.get() >= 0xc0000000)
|
return region;
|
||||||
return kernel_region_from_vaddr(vaddr);
|
|
||||||
|
|
||||||
return user_region_from_vaddr(process, vaddr);
|
return user_region_from_vaddr(process, vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Region* MemoryManager::region_from_vaddr(const Process& process, VirtualAddress vaddr)
|
const Region* MemoryManager::region_from_vaddr(const Process& process, VirtualAddress vaddr)
|
||||||
{
|
{
|
||||||
if (vaddr.get() >= 0xc0000000)
|
if (auto* region = kernel_region_from_vaddr(vaddr))
|
||||||
return kernel_region_from_vaddr(vaddr);
|
return region;
|
||||||
|
|
||||||
return user_region_from_vaddr(const_cast<Process&>(process), vaddr);
|
return user_region_from_vaddr(const_cast<Process&>(process), vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,6 +396,17 @@ bool MemoryManager::page_in_from_inode(Region& region, unsigned page_index_in_re
|
||||||
return true;
|
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)
|
PageFaultResponse MemoryManager::handle_page_fault(const PageFault& fault)
|
||||||
{
|
{
|
||||||
ASSERT_INTERRUPTS_DISABLED();
|
ASSERT_INTERRUPTS_DISABLED();
|
||||||
|
@ -417,7 +426,7 @@ PageFaultResponse MemoryManager::handle_page_fault(const PageFault& fault)
|
||||||
return PageFaultResponse::Continue;
|
return PageFaultResponse::Continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto* region = region_from_vaddr(current->process(), fault.vaddr());
|
auto* region = region_from_vaddr(fault.vaddr());
|
||||||
if (!region) {
|
if (!region) {
|
||||||
kprintf("NP(error) fault at invalid address L%x\n", fault.vaddr().get());
|
kprintf("NP(error) fault at invalid address L%x\n", fault.vaddr().get());
|
||||||
return PageFaultResponse::ShouldCrash;
|
return PageFaultResponse::ShouldCrash;
|
||||||
|
|
|
@ -108,6 +108,8 @@ private:
|
||||||
static Region* user_region_from_vaddr(Process&, VirtualAddress);
|
static Region* user_region_from_vaddr(Process&, VirtualAddress);
|
||||||
static Region* kernel_region_from_vaddr(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 copy_on_write(Region&, unsigned page_index_in_region);
|
||||||
bool page_in_from_inode(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);
|
bool zero_page(Region& region, unsigned page_index_in_region);
|
||||||
|
|
|
@ -6,16 +6,36 @@
|
||||||
static const u32 userspace_range_base = 0x01000000;
|
static const u32 userspace_range_base = 0x01000000;
|
||||||
static const u32 kernelspace_range_base = 0xc0000000;
|
static const u32 kernelspace_range_base = 0xc0000000;
|
||||||
|
|
||||||
|
static HashMap<u32, PageDirectory*>& pdb_map()
|
||||||
|
{
|
||||||
|
ASSERT_INTERRUPTS_DISABLED();
|
||||||
|
static HashMap<u32, PageDirectory*>* map;
|
||||||
|
if (!map)
|
||||||
|
map = new HashMap<u32, PageDirectory*>;
|
||||||
|
return *map;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<PageDirectory> PageDirectory::find_by_pdb(u32 pdb)
|
||||||
|
{
|
||||||
|
InterruptDisabler disabler;
|
||||||
|
return pdb_map().get(pdb).value_or({});
|
||||||
|
}
|
||||||
|
|
||||||
PageDirectory::PageDirectory(PhysicalAddress paddr)
|
PageDirectory::PageDirectory(PhysicalAddress paddr)
|
||||||
: m_range_allocator(VirtualAddress(0xc0000000), 0x3f000000)
|
: m_range_allocator(VirtualAddress(0xc0000000), 0x3f000000)
|
||||||
{
|
{
|
||||||
m_directory_page = PhysicalPage::create(paddr, true, false);
|
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)
|
PageDirectory::PageDirectory(Process& process, 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))
|
: 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);
|
MM.populate_page_directory(*this);
|
||||||
|
InterruptDisabler disabler;
|
||||||
|
pdb_map().set(m_directory_page->paddr().get(), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
PageDirectory::~PageDirectory()
|
PageDirectory::~PageDirectory()
|
||||||
|
@ -23,6 +43,8 @@ PageDirectory::~PageDirectory()
|
||||||
#ifdef MM_DEBUG
|
#ifdef MM_DEBUG
|
||||||
dbgprintf("MM: ~PageDirectory K%x\n", this);
|
dbgprintf("MM: ~PageDirectory K%x\n", this);
|
||||||
#endif
|
#endif
|
||||||
|
InterruptDisabler disabler;
|
||||||
|
pdb_map().remove(m_directory_page->paddr().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageDirectory::flush(VirtualAddress vaddr)
|
void PageDirectory::flush(VirtualAddress vaddr)
|
||||||
|
|
|
@ -1,17 +1,24 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/HashMap.h>
|
#include <AK/HashMap.h>
|
||||||
#include <AK/RefPtr.h>
|
|
||||||
#include <AK/RefCounted.h>
|
#include <AK/RefCounted.h>
|
||||||
|
#include <AK/RefPtr.h>
|
||||||
#include <Kernel/VM/PhysicalPage.h>
|
#include <Kernel/VM/PhysicalPage.h>
|
||||||
#include <Kernel/VM/RangeAllocator.h>
|
#include <Kernel/VM/RangeAllocator.h>
|
||||||
|
|
||||||
|
class Process;
|
||||||
|
|
||||||
class PageDirectory : public RefCounted<PageDirectory> {
|
class PageDirectory : public RefCounted<PageDirectory> {
|
||||||
friend class MemoryManager;
|
friend class MemoryManager;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static NonnullRefPtr<PageDirectory> create_for_userspace(const RangeAllocator* parent_range_allocator = nullptr) { return adopt(*new PageDirectory(parent_range_allocator)); }
|
static NonnullRefPtr<PageDirectory> create_for_userspace(Process& process, const RangeAllocator* parent_range_allocator = nullptr)
|
||||||
|
{
|
||||||
|
return adopt(*new PageDirectory(process, parent_range_allocator));
|
||||||
|
}
|
||||||
static NonnullRefPtr<PageDirectory> create_at_fixed_address(PhysicalAddress paddr) { return adopt(*new PageDirectory(paddr)); }
|
static NonnullRefPtr<PageDirectory> create_at_fixed_address(PhysicalAddress paddr) { return adopt(*new PageDirectory(paddr)); }
|
||||||
|
static RefPtr<PageDirectory> find_by_pdb(u32);
|
||||||
|
|
||||||
~PageDirectory();
|
~PageDirectory();
|
||||||
|
|
||||||
u32 cr3() const { return m_directory_page->paddr().get(); }
|
u32 cr3() const { return m_directory_page->paddr().get(); }
|
||||||
|
@ -21,10 +28,14 @@ public:
|
||||||
|
|
||||||
RangeAllocator& range_allocator() { return m_range_allocator; }
|
RangeAllocator& range_allocator() { return m_range_allocator; }
|
||||||
|
|
||||||
|
Process* process() { return m_process; }
|
||||||
|
const Process* process() const { return m_process; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit PageDirectory(const RangeAllocator* parent_range_allocator);
|
PageDirectory(Process&, const RangeAllocator* parent_range_allocator);
|
||||||
explicit PageDirectory(PhysicalAddress);
|
explicit PageDirectory(PhysicalAddress);
|
||||||
|
|
||||||
|
Process* m_process { nullptr };
|
||||||
RangeAllocator m_range_allocator;
|
RangeAllocator m_range_allocator;
|
||||||
RefPtr<PhysicalPage> m_directory_page;
|
RefPtr<PhysicalPage> m_directory_page;
|
||||||
HashMap<unsigned, RefPtr<PhysicalPage>> m_physical_pages;
|
HashMap<unsigned, RefPtr<PhysicalPage>> m_physical_pages;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue