diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp index bcfbfe7ea..406812e98 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp @@ -88,6 +88,10 @@ namespace ams::kern::arch::arm64 { return this->page_table.MapPageGroup(addr, pg, state, perm); } + Result UnmapPageGroup(KProcessAddress address, const KPageGroup &pg, KMemoryState state) { + return this->page_table.UnmapPageGroup(address, pg, state); + } + Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, KMemoryState state, KMemoryPermission perm) { return this->page_table.MapPages(out_addr, num_pages, alignment, phys_addr, state, perm); } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_handle_table.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_handle_table.hpp index 907c9d08d..838f58028 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_handle_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_handle_table.hpp @@ -126,20 +126,7 @@ namespace ams::kern { NOINLINE bool Remove(ams::svc::Handle handle); template - ALWAYS_INLINE KScopedAutoObject GetObject(ams::svc::Handle handle) const { - MESOSPHERE_ASSERT_THIS(); - - /* Handle pseudo-handles. */ - if constexpr (std::is_base_of::value) { - if (handle == ams::svc::PseudoHandle::CurrentProcess) { - return GetCurrentProcessPointer(); - } - } else if constexpr (std::is_base_of::value) { - if (handle == ams::svc::PseudoHandle::CurrentThread) { - return GetCurrentThreadPointer(); - } - } - + ALWAYS_INLINE KScopedAutoObject GetObjectWithoutPseudoHandle(ams::svc::Handle handle) const { /* Lock and look up in table. */ KScopedDisableDispatch dd; KScopedSpinLock lk(this->lock); @@ -155,6 +142,24 @@ namespace ams::kern { } } + template + ALWAYS_INLINE KScopedAutoObject GetObject(ams::svc::Handle handle) const { + MESOSPHERE_ASSERT_THIS(); + + /* Handle pseudo-handles. */ + if constexpr (std::derived_from) { + if (handle == ams::svc::PseudoHandle::CurrentProcess) { + return GetCurrentProcessPointer(); + } + } else if constexpr (std::derived_from) { + if (handle == ams::svc::PseudoHandle::CurrentThread) { + return GetCurrentThreadPointer(); + } + } + + return this->template GetObjectWithoutPseudoHandle(handle); + } + ALWAYS_INLINE KScopedAutoObject GetObjectForIpcWithoutPseudoHandle(ams::svc::Handle handle) const { /* Lock and look up in table. */ KScopedDisableDispatch dd; diff --git a/libraries/libmesosphere/source/kern_k_condition_variable.cpp b/libraries/libmesosphere/source/kern_k_condition_variable.cpp index 850b03217..3ddf001b4 100644 --- a/libraries/libmesosphere/source/kern_k_condition_variable.cpp +++ b/libraries/libmesosphere/source/kern_k_condition_variable.cpp @@ -90,7 +90,7 @@ namespace ams::kern { R_SUCCEED_IF(test_tag != (handle | ams::svc::HandleWaitMask)); /* Get the lock owner thread. */ - owner_thread = GetCurrentProcess().GetHandleTable().GetObject(handle); + owner_thread = GetCurrentProcess().GetHandleTable().GetObjectWithoutPseudoHandle(handle); R_UNLESS(owner_thread.IsNotNull(), svc::ResultInvalidHandle()); /* Update the lock. */ diff --git a/libraries/libmesosphere/source/svc/kern_svc_process_memory.cpp b/libraries/libmesosphere/source/svc/kern_svc_process_memory.cpp index d02006e68..bac7e90be 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_process_memory.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_process_memory.cpp @@ -57,6 +57,90 @@ namespace ams::kern::svc { return page_table.SetProcessMemoryPermission(address, size, perm); } + Result MapProcessMemory(uintptr_t dst_address, ams::svc::Handle process_handle, uint64_t src_address, size_t size) { + /* Validate the address/size. */ + R_UNLESS(util::IsAligned(dst_address, PageSize), svc::ResultInvalidAddress()); + R_UNLESS(util::IsAligned(src_address, PageSize), svc::ResultInvalidAddress()); + R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); + R_UNLESS(size > 0, svc::ResultInvalidSize()); + R_UNLESS((dst_address < dst_address + size), svc::ResultInvalidCurrentMemory()); + R_UNLESS((src_address < src_address + size), svc::ResultInvalidCurrentMemory()); + R_UNLESS(src_address == static_cast(src_address), svc::ResultInvalidCurrentMemory()); + + /* Get the processes. */ + KProcess *dst_process = GetCurrentProcessPointer(); + KScopedAutoObject src_process = dst_process->GetHandleTable().GetObjectWithoutPseudoHandle(process_handle); + R_UNLESS(src_process.IsNotNull(), svc::ResultInvalidHandle()); + + /* Get the page tables. */ + auto &dst_pt = dst_process->GetPageTable(); + auto &src_pt = src_process->GetPageTable(); + + /* Validate that the mapping is in range. */ + R_UNLESS(src_pt.Contains(src_address, size), svc::ResultInvalidCurrentMemory()); + R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState_SharedCode), svc::ResultInvalidMemoryRegion()); + + /* Create a new page group. */ + KPageGroup pg(dst_pt.GetBlockInfoManager()); + + /* Make the page group. */ + R_TRY(src_pt.MakeAndOpenPageGroup(std::addressof(pg), + src_address, size / PageSize, + KMemoryState_FlagCanMapProcess, KMemoryState_FlagCanMapProcess, + KMemoryPermission_None, KMemoryPermission_None, + KMemoryAttribute_All, KMemoryAttribute_None)); + + /* Close the page group when we're done. */ + ON_SCOPE_EXIT { pg.Close(); }; + + /* Map the group. */ + R_TRY(dst_pt.MapPageGroup(dst_address, pg, KMemoryState_SharedCode, KMemoryPermission_UserReadWrite)); + + return ResultSuccess(); + } + + Result UnmapProcessMemory(uintptr_t dst_address, ams::svc::Handle process_handle, uint64_t src_address, size_t size) { + /* Validate the address/size. */ + R_UNLESS(util::IsAligned(dst_address, PageSize), svc::ResultInvalidAddress()); + R_UNLESS(util::IsAligned(src_address, PageSize), svc::ResultInvalidAddress()); + R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); + R_UNLESS(size > 0, svc::ResultInvalidSize()); + R_UNLESS((dst_address < dst_address + size), svc::ResultInvalidCurrentMemory()); + R_UNLESS((src_address < src_address + size), svc::ResultInvalidCurrentMemory()); + R_UNLESS(src_address == static_cast(src_address), svc::ResultInvalidCurrentMemory()); + + /* Get the processes. */ + KProcess *dst_process = GetCurrentProcessPointer(); + KScopedAutoObject src_process = dst_process->GetHandleTable().GetObjectWithoutPseudoHandle(process_handle); + R_UNLESS(src_process.IsNotNull(), svc::ResultInvalidHandle()); + + /* Get the page tables. */ + auto &dst_pt = dst_process->GetPageTable(); + auto &src_pt = src_process->GetPageTable(); + + /* Validate that the mapping is in range. */ + R_UNLESS(src_pt.Contains(src_address, size), svc::ResultInvalidCurrentMemory()); + R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState_SharedCode), svc::ResultInvalidMemoryRegion()); + + /* Create a new page group. */ + KPageGroup pg(dst_pt.GetBlockInfoManager()); + + /* Make the page group. */ + R_TRY(src_pt.MakeAndOpenPageGroup(std::addressof(pg), + src_address, size / PageSize, + KMemoryState_FlagCanMapProcess, KMemoryState_FlagCanMapProcess, + KMemoryPermission_None, KMemoryPermission_None, + KMemoryAttribute_All, KMemoryAttribute_None)); + + /* Close the page group when we're done. */ + ON_SCOPE_EXIT { pg.Close(); }; + + /* Unmap the group. */ + R_TRY(dst_pt.UnmapPageGroup(dst_address, pg, KMemoryState_SharedCode)); + + return ResultSuccess(); + } + } /* ============================= 64 ABI ============================= */ @@ -66,11 +150,11 @@ namespace ams::kern::svc { } Result MapProcessMemory64(ams::svc::Address dst_address, ams::svc::Handle process_handle, uint64_t src_address, ams::svc::Size size) { - MESOSPHERE_PANIC("Stubbed SvcMapProcessMemory64 was called."); + return MapProcessMemory(dst_address, process_handle, src_address, size); } Result UnmapProcessMemory64(ams::svc::Address dst_address, ams::svc::Handle process_handle, uint64_t src_address, ams::svc::Size size) { - MESOSPHERE_PANIC("Stubbed SvcUnmapProcessMemory64 was called."); + return UnmapProcessMemory(dst_address, process_handle, src_address, size); } Result MapProcessCodeMemory64(ams::svc::Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size) { @@ -88,11 +172,11 @@ namespace ams::kern::svc { } Result MapProcessMemory64From32(ams::svc::Address dst_address, ams::svc::Handle process_handle, uint64_t src_address, ams::svc::Size size) { - MESOSPHERE_PANIC("Stubbed SvcMapProcessMemory64From32 was called."); + return MapProcessMemory(dst_address, process_handle, src_address, size); } Result UnmapProcessMemory64From32(ams::svc::Address dst_address, ams::svc::Handle process_handle, uint64_t src_address, ams::svc::Size size) { - MESOSPHERE_PANIC("Stubbed SvcUnmapProcessMemory64From32 was called."); + return UnmapProcessMemory(dst_address, process_handle, src_address, size); } Result MapProcessCodeMemory64From32(ams::svc::Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size) {