kern: devirtualize page table operations

This commit is contained in:
Michael Scire 2021-09-21 10:09:27 -07:00
parent ab81ed2795
commit 3fe072a1d0
4 changed files with 37 additions and 10 deletions

View file

@ -22,9 +22,11 @@
namespace ams::kern::arch::arm64 { namespace ams::kern::arch::arm64 {
class KPageTable : public KPageTableBase { class KPageTable final : public KPageTableBase {
NON_COPYABLE(KPageTable); NON_COPYABLE(KPageTable);
NON_MOVEABLE(KPageTable); NON_MOVEABLE(KPageTable);
private:
friend class KPageTableBase;
public: public:
using TraversalEntry = KPageTableImpl::TraversalEntry; using TraversalEntry = KPageTableImpl::TraversalEntry;
using TraversalContext = KPageTableImpl::TraversalContext; using TraversalContext = KPageTableImpl::TraversalContext;
@ -96,9 +98,9 @@ namespace ams::kern::arch::arm64 {
u64 m_ttbr; u64 m_ttbr;
u8 m_asid; u8 m_asid;
protected: protected:
virtual Result Operate(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, KPhysicalAddress phys_addr, bool is_pa_valid, const KPageProperties properties, OperationType operation, bool reuse_ll) override; Result OperateImpl(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, KPhysicalAddress phys_addr, bool is_pa_valid, const KPageProperties properties, OperationType operation, bool reuse_ll);
virtual Result Operate(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, const KPageGroup &page_group, const KPageProperties properties, OperationType operation, bool reuse_ll) override; Result OperateImpl(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, const KPageGroup &page_group, const KPageProperties properties, OperationType operation, bool reuse_ll);
virtual void FinalizeUpdate(PageLinkedList *page_list) override; void FinalizeUpdateImpl(PageLinkedList *page_list);
KPageTableManager &GetPageTableManager() const { return *m_manager; } KPageTableManager &GetPageTableManager() const { return *m_manager; }
private: private:

View file

@ -217,9 +217,13 @@ namespace ams::kern {
size_t GetRegionSize(KMemoryState state) const; size_t GetRegionSize(KMemoryState state) const;
bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const; bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const;
protected: protected:
virtual Result Operate(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, KPhysicalAddress phys_addr, bool is_pa_valid, const KPageProperties properties, OperationType operation, bool reuse_ll) = 0; /* NOTE: These three functions (Operate, Operate, FinalizeUpdate) are virtual functions */
virtual Result Operate(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, const KPageGroup &page_group, const KPageProperties properties, OperationType operation, bool reuse_ll) = 0; /* in Nintendo's kernel. We devirtualize them, since KPageTable is the only derived */
virtual void FinalizeUpdate(PageLinkedList *page_list) = 0; /* class, and this avoids unnecessary virtual function calls. See "kern_select_page_table.hpp" */
/* for definition of these functions. */
Result Operate(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, KPhysicalAddress phys_addr, bool is_pa_valid, const KPageProperties properties, OperationType operation, bool reuse_ll);
Result Operate(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, const KPageGroup &page_group, const KPageProperties properties, OperationType operation, bool reuse_ll);
void FinalizeUpdate(PageLinkedList *page_list);
ALWAYS_INLINE KPageTableImpl &GetImpl() { return m_impl; } ALWAYS_INLINE KPageTableImpl &GetImpl() { return m_impl; }
ALWAYS_INLINE const KPageTableImpl &GetImpl() const { return m_impl; } ALWAYS_INLINE const KPageTableImpl &GetImpl() const { return m_impl; }

View file

@ -32,3 +32,24 @@
#error "Unknown architecture for KPageTable" #error "Unknown architecture for KPageTable"
#endif #endif
namespace ams::kern {
/* NOTE: These three functions (Operate, Operate, FinalizeUpdate) are virtual functions */
/* in Nintendo's kernel. We devirtualize them, since KPageTable is the only derived */
/* class, and this avoids unnecessary virtual function calls. */
static_assert(std::derived_from<KPageTable, KPageTableBase>);
ALWAYS_INLINE Result KPageTableBase::Operate(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, KPhysicalAddress phys_addr, bool is_pa_valid, const KPageProperties properties, OperationType operation, bool reuse_ll) {
return static_cast<KPageTable *>(this)->OperateImpl(page_list, virt_addr, num_pages, phys_addr, is_pa_valid, properties, operation, reuse_ll);
}
ALWAYS_INLINE Result KPageTableBase::Operate(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, const KPageGroup &page_group, const KPageProperties properties, OperationType operation, bool reuse_ll) {
return static_cast<KPageTable *>(this)->OperateImpl(page_list, virt_addr, num_pages, page_group, properties, operation, reuse_ll);
}
ALWAYS_INLINE void KPageTableBase::FinalizeUpdate(PageLinkedList *page_list) {
return static_cast<KPageTable *>(this)->FinalizeUpdateImpl(page_list);
}
}

View file

@ -319,7 +319,7 @@ namespace ams::kern::arch::arm64 {
return ResultSuccess(); return ResultSuccess();
} }
Result KPageTable::Operate(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, KPhysicalAddress phys_addr, bool is_pa_valid, const KPageProperties properties, OperationType operation, bool reuse_ll) { Result KPageTable::OperateImpl(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, KPhysicalAddress phys_addr, bool is_pa_valid, const KPageProperties properties, OperationType operation, bool reuse_ll) {
/* Check validity of parameters. */ /* Check validity of parameters. */
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
MESOSPHERE_ASSERT(num_pages > 0); MESOSPHERE_ASSERT(num_pages > 0);
@ -350,7 +350,7 @@ namespace ams::kern::arch::arm64 {
} }
} }
Result KPageTable::Operate(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, const KPageGroup &page_group, const KPageProperties properties, OperationType operation, bool reuse_ll) { Result KPageTable::OperateImpl(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, const KPageGroup &page_group, const KPageProperties properties, OperationType operation, bool reuse_ll) {
/* Check validity of parameters. */ /* Check validity of parameters. */
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
MESOSPHERE_ASSERT(util::IsAligned(GetInteger(virt_addr), PageSize)); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(virt_addr), PageSize));
@ -1429,7 +1429,7 @@ namespace ams::kern::arch::arm64 {
return ResultSuccess(); return ResultSuccess();
} }
void KPageTable::FinalizeUpdate(PageLinkedList *page_list) { void KPageTable::FinalizeUpdateImpl(PageLinkedList *page_list) {
while (page_list->Peek()) { while (page_list->Peek()) {
KVirtualAddress page = KVirtualAddress(page_list->Pop()); KVirtualAddress page = KVirtualAddress(page_list->Pop());
MESOSPHERE_ASSERT(this->GetPageTableManager().IsInPageTableHeap(page)); MESOSPHERE_ASSERT(this->GetPageTableManager().IsInPageTableHeap(page));