diff options
author | Lioncash <mathew1800@gmail.com> | 2019-04-12 06:38:54 +0200 |
---|---|---|
committer | Lioncash <mathew1800@gmail.com> | 2019-04-13 03:56:03 +0200 |
commit | 4d293bb5cbb65d3551dd0d22e92b7065a7ebba14 (patch) | |
tree | d57782959b51296eef132a721a1b6d0600e8e117 /src/core/hle/kernel/vm_manager.cpp | |
parent | kernel/svc: Implement svcMapProcessCodeMemory (diff) | |
download | yuzu-4d293bb5cbb65d3551dd0d22e92b7065a7ebba14.tar yuzu-4d293bb5cbb65d3551dd0d22e92b7065a7ebba14.tar.gz yuzu-4d293bb5cbb65d3551dd0d22e92b7065a7ebba14.tar.bz2 yuzu-4d293bb5cbb65d3551dd0d22e92b7065a7ebba14.tar.lz yuzu-4d293bb5cbb65d3551dd0d22e92b7065a7ebba14.tar.xz yuzu-4d293bb5cbb65d3551dd0d22e92b7065a7ebba14.tar.zst yuzu-4d293bb5cbb65d3551dd0d22e92b7065a7ebba14.zip |
Diffstat (limited to 'src/core/hle/kernel/vm_manager.cpp')
-rw-r--r-- | src/core/hle/kernel/vm_manager.cpp | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 76b491c47..f0c0c12fc 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -331,6 +331,57 @@ ResultCode VMManager::MapCodeMemory(VAddr dst_address, VAddr src_address, u64 si return ReprotectRange(dst_address, size, VMAPermission::Read); } +ResultCode VMManager::UnmapCodeMemory(VAddr dst_address, VAddr src_address, u64 size) { + constexpr auto ignore_attribute = MemoryAttribute::LockedForIPC | MemoryAttribute::DeviceMapped; + const auto src_check_result = CheckRangeState( + src_address, size, MemoryState::All, MemoryState::Heap, VMAPermission::None, + VMAPermission::None, MemoryAttribute::Mask, MemoryAttribute::Locked, ignore_attribute); + + if (src_check_result.Failed()) { + return src_check_result.Code(); + } + + // Yes, the kernel only checks the first page of the region. + const auto dst_check_result = + CheckRangeState(dst_address, Memory::PAGE_SIZE, MemoryState::FlagModule, + MemoryState::FlagModule, VMAPermission::None, VMAPermission::None, + MemoryAttribute::Mask, MemoryAttribute::None, ignore_attribute); + + if (dst_check_result.Failed()) { + return dst_check_result.Code(); + } + + const auto dst_memory_state = std::get<MemoryState>(*dst_check_result); + const auto dst_contiguous_check_result = CheckRangeState( + dst_address, size, MemoryState::All, dst_memory_state, VMAPermission::None, + VMAPermission::None, MemoryAttribute::Mask, MemoryAttribute::None, ignore_attribute); + + if (dst_contiguous_check_result.Failed()) { + return dst_contiguous_check_result.Code(); + } + + const auto unmap_result = UnmapRange(dst_address, size); + if (unmap_result.IsError()) { + return unmap_result; + } + + // With the mirrored portion unmapped, restore the original region's traits. + const auto src_vma_result = CarveVMARange(src_address, size); + if (src_vma_result.Failed()) { + return src_vma_result.Code(); + } + auto src_vma_iter = *src_vma_result; + src_vma_iter->second.state = MemoryState::Heap; + src_vma_iter->second.attribute = MemoryAttribute::None; + Reprotect(src_vma_iter, VMAPermission::ReadWrite); + + if (dst_memory_state == MemoryState::ModuleCode) { + Core::System::GetInstance().InvalidateCpuInstructionCaches(); + } + + return unmap_result; +} + MemoryInfo VMManager::QueryMemory(VAddr address) const { const auto vma = FindVMA(address); MemoryInfo memory_info{}; |