From c622539b95f495c769533de21a9bb92c6f1e045a Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 23 Jul 2020 00:58:44 -0700 Subject: [PATCH] kern: SvcSetMemoryPermission --- .../source/kern_k_page_table_base.cpp | 30 ++++++++++++++++- .../source/svc/kern_svc_memory.cpp | 33 +++++++++++++++++-- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/libraries/libmesosphere/source/kern_k_page_table_base.cpp b/libraries/libmesosphere/source/kern_k_page_table_base.cpp index 4075ce182..cf59c3b0e 100644 --- a/libraries/libmesosphere/source/kern_k_page_table_base.cpp +++ b/libraries/libmesosphere/source/kern_k_page_table_base.cpp @@ -1021,7 +1021,35 @@ namespace ams::kern { } Result KPageTableBase::SetMemoryPermission(KProcessAddress addr, size_t size, ams::svc::MemoryPermission svc_perm) { - MESOSPHERE_UNIMPLEMENTED(); + const size_t num_pages = size / PageSize; + + /* Lock the table. */ + KScopedLightLock lk(this->general_lock); + + /* Verify we can change the memory permission. */ + KMemoryState old_state; + KMemoryPermission old_perm; + R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), nullptr, addr, size, KMemoryState_FlagCanReprotect, KMemoryState_FlagCanReprotect, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None)); + + /* Determine new perm. */ + const KMemoryPermission new_perm = ConvertToKMemoryPermission(svc_perm); + R_SUCCEED_IF(old_perm == new_perm); + + /* 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 = { new_perm, false, false, false }; + R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, Null, false, properties, OperationType_ChangePermissions, false)); + + /* Update the blocks. */ + this->memory_block_manager.Update(&allocator, addr, num_pages, old_state, new_perm, KMemoryAttribute_None); + + return ResultSuccess(); } Result KPageTableBase::SetProcessMemoryPermission(KProcessAddress addr, size_t size, ams::svc::MemoryPermission svc_perm) { diff --git a/libraries/libmesosphere/source/svc/kern_svc_memory.cpp b/libraries/libmesosphere/source/svc/kern_svc_memory.cpp index a4a64bdf9..7a8ec7891 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_memory.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_memory.cpp @@ -21,6 +21,35 @@ namespace ams::kern::svc { namespace { + constexpr bool IsValidSetMemoryPermission(ams::svc::MemoryPermission perm) { + switch (perm) { + case ams::svc::MemoryPermission_None: + case ams::svc::MemoryPermission_Read: + case ams::svc::MemoryPermission_ReadWrite: + return true; + default: + return false; + } + } + + Result SetMemoryPermission(uintptr_t address, size_t size, ams::svc::MemoryPermission perm) { + /* Validate address / size. */ + R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress()); + R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); + R_UNLESS(size > 0, svc::ResultInvalidSize()); + R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory()); + + /* Validate the permission. */ + R_UNLESS(IsValidSetMemoryPermission(perm), svc::ResultInvalidNewMemoryPermission()); + + /* Validate that the region is in range for the current process. */ + auto &page_table = GetCurrentProcess().GetPageTable(); + R_UNLESS(page_table.Contains(address, size), svc::ResultInvalidCurrentMemory()); + + /* Set the memory attribute. */ + return page_table.SetMemoryPermission(address, size, perm); + } + Result SetMemoryAttribute(uintptr_t address, size_t size, uint32_t mask, uint32_t attr) { /* Validate address / size. */ R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress()); @@ -97,7 +126,7 @@ namespace ams::kern::svc { /* ============================= 64 ABI ============================= */ Result SetMemoryPermission64(ams::svc::Address address, ams::svc::Size size, ams::svc::MemoryPermission perm) { - MESOSPHERE_PANIC("Stubbed SvcSetMemoryPermission64 was called."); + return SetMemoryPermission(address, size, perm); } Result SetMemoryAttribute64(ams::svc::Address address, ams::svc::Size size, uint32_t mask, uint32_t attr) { @@ -115,7 +144,7 @@ namespace ams::kern::svc { /* ============================= 64From32 ABI ============================= */ Result SetMemoryPermission64From32(ams::svc::Address address, ams::svc::Size size, ams::svc::MemoryPermission perm) { - MESOSPHERE_PANIC("Stubbed SvcSetMemoryPermission64From32 was called."); + return SetMemoryPermission(address, size, perm); } Result SetMemoryAttribute64From32(ams::svc::Address address, ams::svc::Size size, uint32_t mask, uint32_t attr) {