diff --git a/app/src/main/cpp/skyline/kernel/memory.cpp b/app/src/main/cpp/skyline/kernel/memory.cpp index 7ad8ff70..0eabcb8d 100644 --- a/app/src/main/cpp/skyline/kernel/memory.cpp +++ b/app/src/main/cpp/skyline/kernel/memory.cpp @@ -500,6 +500,46 @@ namespace skyline::kernel { Logger::Error("Failed to free memory: {}", strerror(errno)); } + void MemoryManager::SvcMapMemory(span source, span destination) { + std::unique_lock lock{mutex}; + + MapInternal(std::pair( + destination.data(),{ + .size = destination.size(), + .permission = {true, true, false}, + .state = memory::states::Stack, + .isSrcMergeDisallowed = true + })); + + std::memcpy(destination.data(), source.data(), source.size()); + + ForeachChunkinRange(source, [&](std::pair &desc) __attribute__((always_inline)) { + desc.second.permission = {false, false, false}; + desc.second.attributes.isBorrowed = true; + MapInternal(desc); + }); + } + + void MemoryManager::SvcUnmapMemory(span source, span destination) { + std::unique_lock lock{mutex}; + + auto dstChunk = chunks.lower_bound(destination.data()); + if (destination.data() < dstChunk->first) + --dstChunk; + while (dstChunk->second.state.value == memory::states::Unmapped) + ++dstChunk; + + if ((destination.data() + destination.size()) > dstChunk->first) [[likely]] { + ForeachChunkinRange(span{source.data() + (dstChunk->first - destination.data()), dstChunk->second.size}, [&](std::pair &desc) __attribute__((always_inline)) { + desc.second.permission = dstChunk->second.permission; + desc.second.attributes.isBorrowed = false; + MapInternal(desc); + }); + + std::memcpy(source.data() + (dstChunk->first - destination.data()), dstChunk->first, dstChunk->second.size); + } + } + void MemoryManager::AddRef(std::shared_ptr ptr) { memRefs.push_back(std::move(ptr)); } diff --git a/app/src/main/cpp/skyline/kernel/memory.h b/app/src/main/cpp/skyline/kernel/memory.h index 5bc93b52..e7e4feba 100644 --- a/app/src/main/cpp/skyline/kernel/memory.h +++ b/app/src/main/cpp/skyline/kernel/memory.h @@ -322,6 +322,10 @@ namespace skyline { */ void FreeMemory(span memory); + void SvcMapMemory(span source, span destination); + + void SvcUnmapMemory(span source, span destination); + /** * @brief Adds a reference to shared memory, extending its lifetime until `RemoveRef` is called */ @@ -346,7 +350,7 @@ namespace skyline { /** * @return If the supplied region is contained withing the accessible guest address space */ - bool AddressSpaceContains(span region) const { + constexpr bool AddressSpaceContains(span region) const { if (addressSpaceType == memory::AddressSpaceType::AddressSpace36Bit) return codeBase36Bit.contains(region) || base.contains(region); else diff --git a/app/src/main/cpp/skyline/kernel/svc.cpp b/app/src/main/cpp/skyline/kernel/svc.cpp index b4033c28..c8c33db4 100644 --- a/app/src/main/cpp/skyline/kernel/svc.cpp +++ b/app/src/main/cpp/skyline/kernel/svc.cpp @@ -172,11 +172,7 @@ namespace skyline::kernel::svc { return; } - state.process->memory.MapStackMemory(span{destination, size}); - std::memcpy(destination, source, size); - - state.process->memory.SetRegionPermission(span{source, size}, {false, false, false}); - state.process->memory.SetRegionBorrowed(span{source, size}, true); + state.process->memory.SvcMapMemory(span{source, size}, span{destination, size}); Logger::Debug("Mapped range 0x{:X} - 0x{:X} to 0x{:X} - 0x{:X} (Size: 0x{:X} bytes)", source, source + size, destination, destination + size, size); state.ctx->gpr.w0 = Result{}; @@ -205,18 +201,8 @@ namespace skyline::kernel::svc { return; } - auto dstChunk{state.process->memory.GetChunk(destination).value()}; - while (dstChunk.second.state.value == memory::states::Unmapped) - dstChunk = state.process->memory.GetChunk(dstChunk.first + dstChunk.second.size).value(); - - if ((destination + size) > dstChunk.first) [[likely]] { - state.process->memory.SetRegionPermission(span{source + (dstChunk.first - destination), dstChunk.second.size}, dstChunk.second.permission); - state.process->memory.SetRegionBorrowed(span{source + (dstChunk.first - destination), dstChunk.second.size}, false); - - std::memcpy(source + (dstChunk.first - destination), dstChunk.first, dstChunk.second.size); - - state.process->memory.UnmapMemory(span{destination, size}); - } + state.process->memory.SvcUnmapMemory(span{source, size}, span{destination, size}); + state.process->memory.UnmapMemory(span{destination, size}); Logger::Debug("Unmapped range 0x{:X} - 0x{:X} to 0x{:X} - 0x{:X} (Size: 0x{:X} bytes)", destination, destination + size, source, source + size, size); state.ctx->gpr.w0 = Result{};