From 55481df50f98feb04b18beb518904681b8fcc345 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 5 Jun 2019 14:20:13 -0400 Subject: [PATCH] kernel/vm_manager: Add overload of FindFreeRegion() that operates on a boundary This will be necessary for making our TLS slot management slightly more straightforward. This can also be utilized for other purposes in the future. We can implement the existing simpler overload in terms of this one anyways, we just pass the beginning and end of the ASLR region as the boundaries. --- src/core/hle/kernel/vm_manager.cpp | 31 ++++++++++++++++++++---------- src/core/hle/kernel/vm_manager.h | 31 +++++++++++++++++++++++++++--- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index c929c2a52f..3df5ccb7fb 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -152,22 +152,33 @@ ResultVal VMManager::MapBackingMemory(VAddr target, u8* me } ResultVal VMManager::FindFreeRegion(u64 size) const { - // Find the first Free VMA. - const VAddr base = GetASLRRegionBaseAddress(); - const VMAHandle vma_handle = std::find_if(vma_map.begin(), vma_map.end(), [&](const auto& vma) { - if (vma.second.type != VMAType::Free) - return false; + return FindFreeRegion(GetASLRRegionBaseAddress(), GetASLRRegionEndAddress(), size); +} - const VAddr vma_end = vma.second.base + vma.second.size; - return vma_end > base && vma_end >= base + size; - }); +ResultVal VMManager::FindFreeRegion(VAddr begin, VAddr end, u64 size) const { + ASSERT(begin < end); + ASSERT(size <= end - begin); - if (vma_handle == vma_map.end()) { + const VMAHandle vma_handle = + std::find_if(vma_map.begin(), vma_map.end(), [begin, end, size](const auto& vma) { + if (vma.second.type != VMAType::Free) { + return false; + } + const VAddr vma_base = vma.second.base; + const VAddr vma_end = vma_base + vma.second.size; + const VAddr assumed_base = (begin < vma_base) ? vma_base : begin; + const VAddr used_range = assumed_base + size; + + return vma_base <= assumed_base && assumed_base < used_range && used_range < end && + used_range <= vma_end; + }); + + if (vma_handle == vma_map.cend()) { // TODO(Subv): Find the correct error code here. return ResultCode(-1); } - const VAddr target = std::max(base, vma_handle->second.base); + const VAddr target = std::max(begin, vma_handle->second.base); return MakeResult(target); } diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index dfbf7a8941..752ae62f93 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -362,13 +362,38 @@ public: ResultVal MapBackingMemory(VAddr target, u8* memory, u64 size, MemoryState state); /** - * Finds the first free address that can hold a region of the desired size. + * Finds the first free memory region of the given size within + * the user-addressable ASLR memory region. * - * @param size Size of the desired region. - * @return The found free address. + * @param size The size of the desired region in bytes. + * + * @returns If successful, the base address of the free region with + * the given size. */ ResultVal FindFreeRegion(u64 size) const; + /** + * Finds the first free address range that can hold a region of the desired size + * + * @param begin The starting address of the range. + * This is treated as an inclusive beginning address. + * + * @param end The ending address of the range. + * This is treated as an exclusive ending address. + * + * @param size The size of the free region to attempt to locate, + * in bytes. + * + * @returns If successful, the base address of the free region with + * the given size. + * + * @returns If unsuccessful, a result containing an error code. + * + * @pre The starting address must be less than the ending address. + * @pre The size must not exceed the address range itself. + */ + ResultVal FindFreeRegion(VAddr begin, VAddr end, u64 size) const; + /** * Maps a memory-mapped IO region at a given address. *