mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-27 01:50:24 +00:00
24ecf1d021
The purpose of the PageDirectory::m_page_tables map was really just to act as ref-counting storage for PhysicalPage objects that were being used for the directory's page tables. However, this was basically redundant, since we can find the physical address of each page table from the page directory, and we can find the PhysicalPage object from MemoryManager::get_physical_page_entry(). So if we just manually ref() and unref() the pages when they go in and out of the directory, we no longer need PageDirectory::m_page_tables! Not only does this remove a bunch of kmalloc() traffic, it also solves a race condition that would occur when lazily adding a new page table to a directory: Previously, when MemoryManager::ensure_pte() would call HashMap::set() to insert the new page table into m_page_tables, if the HashMap had to grow its internal storage, it would call kmalloc(). If that kmalloc() would need to perform heap expansion, it would end up calling ensure_pte() again, which would clobber the page directory mapping used by the outer invocation of ensure_pte(). The net result of the above bug would be that any invocation of MemoryManager::ensure_pte() could erroneously return a pointer into a kernel page table instead of the correct one! This whole problem goes away when we remove the HashMap, as ensure_pte() no longer does anything that allocates from the heap.
70 lines
1.9 KiB
C++
70 lines
1.9 KiB
C++
/*
|
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/HashMap.h>
|
|
#include <AK/IntrusiveRedBlackTree.h>
|
|
#include <AK/RefCounted.h>
|
|
#include <AK/RefPtr.h>
|
|
#include <Kernel/Forward.h>
|
|
#include <Kernel/Memory/PhysicalPage.h>
|
|
#include <Kernel/Memory/VirtualRangeAllocator.h>
|
|
|
|
namespace Kernel::Memory {
|
|
|
|
class PageDirectory : public RefCounted<PageDirectory> {
|
|
friend class MemoryManager;
|
|
|
|
public:
|
|
static ErrorOr<NonnullRefPtr<PageDirectory>> try_create_for_userspace(VirtualRangeAllocator const* parent_range_allocator = nullptr);
|
|
static NonnullRefPtr<PageDirectory> must_create_kernel_page_directory();
|
|
static RefPtr<PageDirectory> find_by_cr3(FlatPtr);
|
|
|
|
~PageDirectory();
|
|
|
|
void allocate_kernel_directory();
|
|
|
|
FlatPtr cr3() const
|
|
{
|
|
#if ARCH(X86_64)
|
|
return m_pml4t->paddr().get();
|
|
#else
|
|
return m_directory_table->paddr().get();
|
|
#endif
|
|
}
|
|
|
|
VirtualRangeAllocator& range_allocator() { return m_range_allocator; }
|
|
VirtualRangeAllocator const& range_allocator() const { return m_range_allocator; }
|
|
|
|
AddressSpace* address_space() { return m_space; }
|
|
const AddressSpace* address_space() const { return m_space; }
|
|
|
|
void set_space(Badge<AddressSpace>, AddressSpace& space) { m_space = &space; }
|
|
|
|
RecursiveSpinlock& get_lock() { return m_lock; }
|
|
|
|
// This has to be public to let the global singleton access the member pointer
|
|
IntrusiveRedBlackTreeNode<FlatPtr, PageDirectory, RawPtr<PageDirectory>> m_tree_node;
|
|
|
|
private:
|
|
PageDirectory();
|
|
|
|
AddressSpace* m_space { nullptr };
|
|
VirtualRangeAllocator m_range_allocator;
|
|
#if ARCH(X86_64)
|
|
RefPtr<PhysicalPage> m_pml4t;
|
|
#endif
|
|
RefPtr<PhysicalPage> m_directory_table;
|
|
#if ARCH(X86_64)
|
|
RefPtr<PhysicalPage> m_directory_pages[512];
|
|
#else
|
|
RefPtr<PhysicalPage> m_directory_pages[4];
|
|
#endif
|
|
RecursiveSpinlock m_lock;
|
|
};
|
|
|
|
}
|