mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 21:48:13 +00:00
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().
This commit is contained in:
parent
5b8cf2ee23
commit
2d1bcce34a
3 changed files with 16 additions and 0 deletions
|
@ -479,6 +479,12 @@ void MemoryManager::enter_process_paging_scope(Process& process)
|
||||||
{
|
{
|
||||||
ASSERT(current);
|
ASSERT(current);
|
||||||
InterruptDisabler disabler;
|
InterruptDisabler disabler;
|
||||||
|
|
||||||
|
// NOTE: To prevent triple-faulting here, we have to ensure that the current stack
|
||||||
|
// is accessible to the incoming page directory. We achieve this by forcing
|
||||||
|
// an update of the kernel VM mappings in the entered scope's page directory.
|
||||||
|
process.page_directory().update_kernel_mappings();
|
||||||
|
|
||||||
current->tss().cr3 = process.page_directory().cr3();
|
current->tss().cr3 = process.page_directory().cr3();
|
||||||
asm volatile("movl %%eax, %%cr3" ::"a"(process.page_directory().cr3())
|
asm volatile("movl %%eax, %%cr3" ::"a"(process.page_directory().cr3())
|
||||||
: "memory");
|
: "memory");
|
||||||
|
|
|
@ -57,3 +57,11 @@ void PageDirectory::flush(VirtualAddress vaddr)
|
||||||
if (this == &MM.kernel_page_directory() || ¤t->process().page_directory() == this)
|
if (this == &MM.kernel_page_directory() || ¤t->process().page_directory() == this)
|
||||||
MM.flush_tlb(vaddr);
|
MM.flush_tlb(vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PageDirectory::update_kernel_mappings()
|
||||||
|
{
|
||||||
|
// This ensures that the kernel virtual address space is up-to-date in this page directory.
|
||||||
|
// This may be necessary to avoid triple faulting when entering a process's paging scope
|
||||||
|
// whose mappings are out-of-date.
|
||||||
|
memcpy(entries() + 768, MM.kernel_page_directory().entries() + 768, sizeof(PageDirectoryEntry) * 256);
|
||||||
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@ public:
|
||||||
Process* process() { return m_process; }
|
Process* process() { return m_process; }
|
||||||
const Process* process() const { return m_process; }
|
const Process* process() const { return m_process; }
|
||||||
|
|
||||||
|
void update_kernel_mappings();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PageDirectory(Process&, const RangeAllocator* parent_range_allocator);
|
PageDirectory(Process&, const RangeAllocator* parent_range_allocator);
|
||||||
explicit PageDirectory(PhysicalAddress);
|
explicit PageDirectory(PhysicalAddress);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue