From 2a4d68f916acfaaed420a0a033684aba12ed3ff9 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 11 Oct 2023 09:32:23 -0700 Subject: [PATCH] kern: KPageTable: remove MapFirst operation, replace with MapFirstGroup --- .../arch/arm64/kern_k_page_table.hpp | 4 +- .../include/mesosphere/kern_k_page_group.hpp | 12 ++++- .../mesosphere/kern_k_page_table_base.hpp | 2 +- .../source/arch/arm64/kern_k_page_table.cpp | 20 +++---- .../source/kern_k_page_table_base.cpp | 52 ++++++++++++------- 5 files changed, 53 insertions(+), 37 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp index 7da761ef6..f8ab5e680 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp @@ -208,8 +208,8 @@ namespace ams::kern::arch::arm64 { } } - Result MapContiguous(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, bool not_first, PageLinkedList *page_list, bool reuse_ll); - Result MapGroup(KProcessAddress virt_addr, const KPageGroup &pg, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll); + Result MapContiguous(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll); + Result MapGroup(KProcessAddress virt_addr, const KPageGroup &pg, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, bool not_first, PageLinkedList *page_list, bool reuse_ll); bool MergePages(KProcessAddress virt_addr, PageLinkedList *page_list); diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_page_group.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_page_group.hpp index 9beef7f1c..a0d150a08 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_page_group.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_page_group.hpp @@ -158,8 +158,16 @@ namespace ams::kern { private: const KPageGroup *m_pg; public: - explicit ALWAYS_INLINE KScopedPageGroup(const KPageGroup *gp) : m_pg(gp) { if (m_pg) { m_pg->Open(); } } - explicit ALWAYS_INLINE KScopedPageGroup(const KPageGroup &gp) : KScopedPageGroup(std::addressof(gp)) { /* ... */ } + explicit ALWAYS_INLINE KScopedPageGroup(const KPageGroup *gp, bool not_first = true) : m_pg(gp) { + if (m_pg) { + if (not_first) { + m_pg->Open(); + } else { + m_pg->OpenFirst(); + } + } + } + explicit ALWAYS_INLINE KScopedPageGroup(const KPageGroup &gp, bool not_first = true) : KScopedPageGroup(std::addressof(gp), not_first) { /* ... */ } ALWAYS_INLINE ~KScopedPageGroup() { if (m_pg) { m_pg->Close(); } } ALWAYS_INLINE void CancelClose() { diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp index 80a306a7b..f45f0eba0 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp @@ -88,8 +88,8 @@ namespace ams::kern { enum OperationType { OperationType_Map = 0, - OperationType_MapFirst = 1, OperationType_MapGroup = 2, + OperationType_MapFirstGroup = 1, OperationType_Unmap = 3, OperationType_ChangePermissions = 4, OperationType_ChangePermissionsAndRefresh = 5, diff --git a/libraries/libmesosphere/source/arch/arm64/kern_k_page_table.cpp b/libraries/libmesosphere/source/arch/arm64/kern_k_page_table.cpp index 4d1269a07..8ad4a5dd4 100644 --- a/libraries/libmesosphere/source/arch/arm64/kern_k_page_table.cpp +++ b/libraries/libmesosphere/source/arch/arm64/kern_k_page_table.cpp @@ -351,7 +351,7 @@ namespace ams::kern::arch::arm64 { MESOSPHERE_ASSERT(util::IsAligned(GetInteger(virt_addr), PageSize)); MESOSPHERE_ASSERT(this->ContainsPages(virt_addr, num_pages)); - if (operation == OperationType_Map || operation == OperationType_MapFirst) { + if (operation == OperationType_Map) { MESOSPHERE_ABORT_UNLESS(is_pa_valid); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(phys_addr), PageSize)); } else { @@ -378,8 +378,7 @@ namespace ams::kern::arch::arm64 { switch (operation) { case OperationType_Map: - case OperationType_MapFirst: - R_RETURN(this->MapContiguous(virt_addr, phys_addr, num_pages, entry_template, properties.disable_merge_attributes == DisableMergeAttribute_DisableHead, operation != OperationType_MapFirst, page_list, reuse_ll)); + R_RETURN(this->MapContiguous(virt_addr, phys_addr, num_pages, entry_template, properties.disable_merge_attributes == DisableMergeAttribute_DisableHead, page_list, reuse_ll)); case OperationType_ChangePermissions: R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, false, false, page_list, reuse_ll)); case OperationType_ChangePermissionsAndRefresh: @@ -402,7 +401,8 @@ namespace ams::kern::arch::arm64 { auto entry_template = this->GetEntryTemplate(properties); switch (operation) { case OperationType_MapGroup: - R_RETURN(this->MapGroup(virt_addr, page_group, num_pages, entry_template, properties.disable_merge_attributes == DisableMergeAttribute_DisableHead, page_list, reuse_ll)); + case OperationType_MapFirstGroup: + R_RETURN(this->MapGroup(virt_addr, page_group, num_pages, entry_template, properties.disable_merge_attributes == DisableMergeAttribute_DisableHead, operation != OperationType_MapFirstGroup, page_list, reuse_ll)); MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } } @@ -759,7 +759,7 @@ namespace ams::kern::arch::arm64 { R_SUCCEED(); } - Result KPageTable::MapContiguous(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, bool not_first, PageLinkedList *page_list, bool reuse_ll) { + Result KPageTable::MapContiguous(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); /* Cache initial addresses for use on cleanup. */ @@ -830,21 +830,17 @@ namespace ams::kern::arch::arm64 { /* Open references to the pages, if we should. */ if (IsHeapPhysicalAddress(orig_phys_addr)) { - if (not_first) { - Kernel::GetMemoryManager().Open(orig_phys_addr, num_pages); - } else { - Kernel::GetMemoryManager().OpenFirst(orig_phys_addr, num_pages); - } + Kernel::GetMemoryManager().Open(orig_phys_addr, num_pages); } R_SUCCEED(); } - Result KPageTable::MapGroup(KProcessAddress virt_addr, const KPageGroup &pg, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll) { + Result KPageTable::MapGroup(KProcessAddress virt_addr, const KPageGroup &pg, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, bool not_first, PageLinkedList *page_list, bool reuse_ll) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); /* We want to maintain a new reference to every page in the group. */ - KScopedPageGroup spg(pg); + KScopedPageGroup spg(pg, not_first); /* Cache initial address for use on cleanup. */ const KProcessAddress orig_virt_addr = virt_addr; diff --git a/libraries/libmesosphere/source/kern_k_page_table_base.cpp b/libraries/libmesosphere/source/kern_k_page_table_base.cpp index 090521c4c..3d6bc0c95 100644 --- a/libraries/libmesosphere/source/kern_k_page_table_base.cpp +++ b/libraries/libmesosphere/source/kern_k_page_table_base.cpp @@ -4435,32 +4435,44 @@ namespace ams::kern { /* If it's unmapped, we need to map it. */ if (info.GetState() == KMemoryState_Free) { /* Determine the range to map. */ - const KPageProperties map_properties = { KMemoryPermission_UserReadWrite, false, false, DisableMergeAttribute_None }; + const KPageProperties map_properties = { KMemoryPermission_UserReadWrite, false, false, cur_address == this->GetAliasRegionStart() ? DisableMergeAttribute_DisableHead : DisableMergeAttribute_None }; size_t map_pages = std::min(KProcessAddress(info.GetEndAddress()) - cur_address, last_address + 1 - cur_address) / PageSize; /* While we have pages to map, map them. */ - while (map_pages > 0) { - /* Check if we're at the end of the physical block. */ - if (pg_pages == 0) { - /* Ensure there are more pages to map. */ - MESOSPHERE_ASSERT(pg_it != pg.end()); + { + /* Create a page group for the current mapping range. */ + KPageGroup cur_pg(m_block_info_manager); + { + ON_RESULT_FAILURE { + cur_pg.OpenFirst(); + cur_pg.Close(); + }; - /* Advance our physical block. */ - ++pg_it; - pg_phys_addr = pg_it->GetAddress(); - pg_pages = pg_it->GetNumPages(); + size_t remain_pages = map_pages; + while (remain_pages > 0) { + /* Check if we're at the end of the physical block. */ + if (pg_pages == 0) { + /* Ensure there are more pages to map. */ + MESOSPHERE_ASSERT(pg_it != pg.end()); + + /* Advance our physical block. */ + ++pg_it; + pg_phys_addr = pg_it->GetAddress(); + pg_pages = pg_it->GetNumPages(); + } + + /* Add whatever we can to the current block. */ + const size_t cur_pages = std::min(pg_pages, remain_pages); + R_TRY(cur_pg.AddBlock(pg_phys_addr + ((pg_pages - cur_pages) * PageSize), cur_pages)); + + /* Advance. */ + remain_pages -= cur_pages; + pg_pages -= cur_pages; + } } - /* Map whatever we can. */ - const size_t cur_pages = std::min(pg_pages, map_pages); - R_TRY(this->Operate(updater.GetPageList(), cur_address, cur_pages, pg_phys_addr, true, map_properties, OperationType_MapFirst, false)); - - /* Advance. */ - cur_address += cur_pages * PageSize; - map_pages -= cur_pages; - - pg_phys_addr += cur_pages * PageSize; - pg_pages -= cur_pages; + /* Map the papges. */ + R_TRY(this->Operate(updater.GetPageList(), cur_address, map_pages, cur_pg, map_properties, OperationType_MapFirstGroup, false)); } }