From c9f8252577759848ec7226cbb0ed3f03d4385133 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 31 Jul 2020 00:29:00 -0700 Subject: [PATCH] kern: resolve MESOSPHERE_UNIMPLEMENTEDs other than UserException --- .../arm64/kern_k_supervisor_page_table.hpp | 2 - .../arm64/kern_k_supervisor_page_table.cpp | 3 - .../source/kern_k_page_table_base.cpp | 78 ++++++++++++++++++- .../source/svc/kern_svc_process.cpp | 14 ++-- 4 files changed, 85 insertions(+), 12 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp index e653d5be8..8e795aa7c 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp @@ -41,8 +41,6 @@ namespace ams::kern::arch::arm64 { cpu::InvalidateEntireTlb(); } - void Finalize(s32 core_id); - Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm) { return this->page_table.MapPages(out_addr, num_pages, alignment, phys_addr, region_start, region_num_pages, state, perm); } diff --git a/libraries/libmesosphere/source/arch/arm64/kern_k_supervisor_page_table.cpp b/libraries/libmesosphere/source/arch/arm64/kern_k_supervisor_page_table.cpp index 7abef71f1..17d808e64 100644 --- a/libraries/libmesosphere/source/arch/arm64/kern_k_supervisor_page_table.cpp +++ b/libraries/libmesosphere/source/arch/arm64/kern_k_supervisor_page_table.cpp @@ -39,7 +39,4 @@ namespace ams::kern::arch::arm64 { } } - void KSupervisorPageTable::Finalize(s32 core_id) { - MESOSPHERE_UNIMPLEMENTED(); - } } diff --git a/libraries/libmesosphere/source/kern_k_page_table_base.cpp b/libraries/libmesosphere/source/kern_k_page_table_base.cpp index e3e9a3a63..58780fb10 100644 --- a/libraries/libmesosphere/source/kern_k_page_table_base.cpp +++ b/libraries/libmesosphere/source/kern_k_page_table_base.cpp @@ -1647,11 +1647,85 @@ namespace ams::kern { } Result KPageTableBase::MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm) { - MESOSPHERE_UNIMPLEMENTED(); + MESOSPHERE_ASSERT(util::IsAligned(GetInteger(phys_addr), PageSize)); + MESOSPHERE_ASSERT(util::IsAligned(size, PageSize)); + MESOSPHERE_ASSERT(size > 0); + R_UNLESS(phys_addr < phys_addr + size, svc::ResultInvalidAddress()); + const size_t num_pages = size / PageSize; + const KPhysicalAddress last = phys_addr + size - 1; + + /* Get region extents. */ + const KProcessAddress region_start = this->GetRegionAddress(KMemoryState_Static); + const size_t region_size = this->GetRegionSize(KMemoryState_Static); + const size_t region_num_pages = region_size / PageSize; + + /* Locate the memory region. */ + auto region_it = KMemoryLayout::FindContainingRegion(phys_addr); + const auto end_it = KMemoryLayout::GetEnd(phys_addr); + R_UNLESS(region_it != end_it, svc::ResultInvalidAddress()); + + MESOSPHERE_ASSERT(region_it->Contains(GetInteger(phys_addr))); + R_UNLESS(GetInteger(last) <= region_it->GetLastAddress(), svc::ResultInvalidAddress()); + + /* Check the region attributes. */ + const bool is_rw = perm == KMemoryPermission_UserReadWrite; + R_UNLESS( region_it->IsDerivedFrom(KMemoryRegionType_Dram), svc::ResultInvalidAddress()); + R_UNLESS(!region_it->HasTypeAttribute(KMemoryRegionAttr_NoUserMap), svc::ResultInvalidAddress()); + R_UNLESS(!region_it->HasTypeAttribute(KMemoryRegionAttr_UserReadOnly) || !is_rw, svc::ResultInvalidAddress()); + + /* Lock the table. */ + KScopedLightLock lk(this->general_lock); + + /* Select an address to map at. */ + KProcessAddress addr = Null; + const size_t phys_alignment = std::min(std::min(GetInteger(phys_addr) & -GetInteger(phys_addr), size & -size), MaxPhysicalMapAlignment); + for (s32 block_type = KPageTable::GetMaxBlockType(); block_type >= 0; block_type--) { + const size_t alignment = KPageTable::GetBlockSize(static_cast(block_type)); + if (alignment > phys_alignment) { + continue; + } + + addr = this->FindFreeArea(region_start, region_num_pages, num_pages, alignment, 0, this->GetNumGuardPages()); + if (addr != Null) { + break; + } + } + R_UNLESS(addr != Null, svc::ResultOutOfMemory()); + + /* Check that we can map static here. */ + MESOSPHERE_ASSERT(this->CanContain(addr, size, KMemoryState_Static)); + MESOSPHERE_R_ASSERT(this->CheckMemoryState(addr, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None)); + + /* Create an update allocator. */ + KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager); + R_TRY(allocator.GetResult()); + + /* We're going to perform an update, so create a helper. */ + KScopedPageTableUpdater updater(this); + + /* Perform mapping operation. */ + const KPageProperties properties = { perm, false, false, false }; + R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, phys_addr, true, properties, OperationType_Map, false)); + + /* Update the blocks. */ + this->memory_block_manager.Update(&allocator, addr, num_pages, KMemoryState_Static, perm, KMemoryAttribute_None); + + /* We successfully mapped the pages. */ + return ResultSuccess(); } Result KPageTableBase::MapRegion(KMemoryRegionType region_type, KMemoryPermission perm) { - MESOSPHERE_UNIMPLEMENTED(); + /* Get the memory region. */ + auto &tree = KMemoryLayout::GetPhysicalMemoryRegionTree(); + auto it = tree.TryFindFirstDerivedRegion(region_type); + R_UNLESS(it != tree.end(), svc::ResultOutOfRange()); + + /* Map the region. */ + R_TRY_CATCH(this->MapStatic(it->GetAddress(), it->GetSize(), perm)) { + R_CONVERT(svc::ResultInvalidAddress, svc::ResultOutOfRange()) + } R_END_TRY_CATCH; + + return ResultSuccess(); } Result KPageTableBase::MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, bool is_pa_valid, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm) { diff --git a/libraries/libmesosphere/source/svc/kern_svc_process.cpp b/libraries/libmesosphere/source/svc/kern_svc_process.cpp index 38cbd7b9a..5369409ee 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_process.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_process.cpp @@ -37,15 +37,19 @@ namespace ams::kern::svc { /* Get the process from the object. */ KProcess *process = nullptr; - if (obj->IsDerivedFrom(KProcess::GetStaticTypeObj())) { + if (KProcess *p = obj->DynamicCast(); p != nullptr) { /* The object is a process, so we can use it directly. */ - process = reinterpret_cast(obj.GetPointerUnsafe()); - } else if (obj->IsDerivedFrom(KThread::GetStaticTypeObj())) { + process = p; + } else if (KThread *t = obj->DynamicCast(); t != nullptr) { /* The object is a thread, so we want to use its parent. */ process = reinterpret_cast(obj.GetPointerUnsafe())->GetOwnerProcess(); - } else if (obj->IsDerivedFrom(KDebug::GetStaticTypeObj())) { + } else if (KDebug *d = obj->DynamicCast(); d != nullptr) { /* The object is a debug, so we want to use the process it's attached to. */ - MESOSPHERE_UNIMPLEMENTED(); + obj = d->GetProcess(); + + if (obj.IsNotNull()) { + process = static_cast(obj.GetPointerUnsafe()); + } } /* Make sure the target process exists. */