From 928202f744f32fd6ba69f8ef28c6e5bec190cddb Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Tue, 7 Nov 2017 13:38:33 -0500
Subject: [PATCH] Kernel/VMManager: Added a function to map a block of memory
 into the first available address after a given base.

---
 src/core/hle/kernel/vm_manager.cpp | 27 +++++++++++++++++++++++++++
 src/core/hle/kernel/vm_manager.h   | 12 ++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 7a007c065..0eecb7e57 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -93,6 +93,33 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
     return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
 }
 
+ResultVal<VAddr> VMManager::MapMemoryBlockToBase(VAddr base, std::shared_ptr<std::vector<u8>> block,
+                                                 size_t offset, u32 size, MemoryState state) {
+
+    // Find the first Free VMA.
+    VMAHandle vma_handle = std::find_if(vma_map.begin(), vma_map.end(), [&](const auto& vma) {
+        if (vma.second.type != VMAType::Free)
+            return false;
+
+        VAddr vma_end = vma.second.base + vma.second.size;
+        return vma_end > base && vma_end >= base + size;
+    });
+
+    if (vma_handle == vma_map.end()) {
+        return ResultCode(ErrorDescription::OutOfMemory, ErrorModule::Kernel,
+                          ErrorSummary::OutOfResource, ErrorLevel::Permanent);
+    }
+
+    VAddr target = std::max(base, vma_handle->second.base);
+
+    auto result = MapMemoryBlock(target, block, offset, size, state);
+
+    if (result.Failed())
+        return result.Code();
+
+    return MakeResult<VAddr>(target);
+}
+
 ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* memory, u32 size,
                                                             MemoryState state) {
     ASSERT(memory != nullptr);
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 1302527bb..3a1367978 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -144,6 +144,18 @@ public:
     ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block,
                                         size_t offset, u32 size, MemoryState state);
 
+    /**
+     * Maps part of a ref-counted block of memory at the first free address after the given base.
+     *
+     * @param base The base address to start the mapping at.
+     * @param block The block to be mapped.
+     * @param offset Offset into `block` to map from.
+     * @param size Size of the mapping.
+     * @param state MemoryState tag to attach to the VMA.
+     * @returns The address at which the memory was mapped.
+     */
+    ResultVal<VAddr> MapMemoryBlockToBase(VAddr base, std::shared_ptr<std::vector<u8>> block,
+                                          size_t offset, u32 size, MemoryState state);
     /**
      * Maps an unmanaged host memory pointer at a given address.
      *