mirror of
https://github.com/RGBCube/serenity
synced 2025-05-24 00:05:07 +00:00

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().
44 lines
1.4 KiB
C++
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;
|
|
};
|