1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-24 00:05:07 +00:00
serenity/Kernel/VM/PageDirectory.h
Andreas Kling 2d1bcce34a Kernel: Fix triple-fault when clicking on SystemServer in SystemMonitor
The fault was happening when retrieving a current backtrace for the
SystemServer process.

To generate a backtrace, we go into the paging scope of the process,
meaning we temporarily switch to using its page directory as our own.

Because kernel VM is allocated on demand, it's possible for a process's
mappings above the 3GB mark to be out-of-date. Normally this just gets
fixed up transparently by the page fault handler (which simply copies
the PDE from the canonical MM.kernel_page_directory() into the current
process.)

However, if the current kernel *stack* is in a piece of memory that
the backtraced process lacks up-to-date PDE's for, we still get a page
fault, but are unable to handle it, since the CPU wants to push to the
stack as part of calling the page fault handler. So we're screwed and
it's a triple-fault.

Fix this by always updating the kernel VM mappings before switching
into a paging scope. In practical terms, this is a 1KB memcpy() that
happens when generating a backtrace, or doing exec().
2019-11-27 12:40:42 +01:00

44 lines
1.4 KiB
C++

#pragma once
#include <AK/HashMap.h>
#include <AK/RefCounted.h>
#include <AK/RefPtr.h>
#include <Kernel/VM/PhysicalPage.h>
#include <Kernel/VM/RangeAllocator.h>
class Process;
class PageDirectory : public RefCounted<PageDirectory> {
friend class MemoryManager;
public:
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 RefPtr<PageDirectory> find_by_pdb(u32);
~PageDirectory();
u32 cr3() const { return m_directory_page->paddr().get(); }
PageDirectoryEntry* entries() { return reinterpret_cast<PageDirectoryEntry*>(cr3()); }
void flush(VirtualAddress);
RangeAllocator& range_allocator() { return m_range_allocator; }
Process* process() { return m_process; }
const Process* process() const { return m_process; }
void update_kernel_mappings();
private:
PageDirectory(Process&, const RangeAllocator* parent_range_allocator);
explicit PageDirectory(PhysicalAddress);
Process* m_process { nullptr };
RangeAllocator m_range_allocator;
RefPtr<PhysicalPage> m_directory_page;
HashMap<unsigned, RefPtr<PhysicalPage>> m_physical_pages;
};