From 3421e1617e0b64ca0b1be18d4fefe769d35244d0 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Thu, 28 Dec 2017 21:35:49 -0500
Subject: [PATCH] process: Add method to mirror a memory region.

---
 src/core/hle/kernel/process.cpp | 25 +++++++++++++++++++++++++
 src/core/hle/kernel/process.h   |  2 ++
 2 files changed, 27 insertions(+)

diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 98c5b0905..9bcb08fc9 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -267,6 +267,31 @@ ResultCode Process::LinearFree(VAddr target, u32 size) {
     return RESULT_SUCCESS;
 }
 
+ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
+    auto vma = vm_manager.FindVMA(src_addr);
+
+    ASSERT_MSG(vma != vm_manager.vma_map.end(), "Invalid memory address");
+    ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address");
+
+    // The returned VMA might be a bigger one encompassing the desired address.
+    auto vma_offset = src_addr - vma->first;
+    ASSERT_MSG(vma_offset + size <= vma->second.size,
+               "Shared memory exceeds bounds of mapped block");
+
+    const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block;
+    size_t backing_block_offset = vma->second.offset + vma_offset;
+
+    CASCADE_RESULT(auto new_vma,
+                   vm_manager.MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size,
+                                             vma->second.meminfo_state));
+    // Protect mirror with permissions from old region
+    vm_manager.Reprotect(new_vma, vma->second.permissions);
+    // Remove permissions from old region
+    vm_manager.Reprotect(vma, VMAPermission::None);
+
+    return RESULT_SUCCESS;
+}
+
 Kernel::Process::Process() {}
 Kernel::Process::~Process() {}
 
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index f05f2703e..3b646c076 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -177,6 +177,8 @@ public:
     ResultVal<VAddr> LinearAllocate(VAddr target, u32 size, VMAPermission perms);
     ResultCode LinearFree(VAddr target, u32 size);
 
+    ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size);
+
 private:
     Process();
     ~Process() override;