From f556f85279e948133ed46103d6b183f1d6c7009c Mon Sep 17 00:00:00 2001 From: Borchev <4501931+Borchev@users.noreply.github.com> Date: Sun, 21 Jul 2024 11:29:24 -0700 Subject: [PATCH] Add sceKernelGetDirectMemoryType and update sceKernelReserveVirtualRange to search for free region when virtual_addr==0 --- src/core/libraries/kernel/libkernel.cpp | 1 + .../libraries/kernel/memory_management.cpp | 8 ++++ src/core/libraries/kernel/memory_management.h | 3 ++ src/core/memory.cpp | 39 ++++++++++++++++++- src/core/memory.h | 3 ++ 5 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/core/libraries/kernel/libkernel.cpp b/src/core/libraries/kernel/libkernel.cpp index 16274236..f2dbf427 100644 --- a/src/core/libraries/kernel/libkernel.cpp +++ b/src/core/libraries/kernel/libkernel.cpp @@ -375,6 +375,7 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) { sceKernelCheckedReleaseDirectMemory); LIB_FUNCTION("rVjRvHJ0X6c", "libkernel", 1, "libkernel", 1, 1, sceKernelVirtualQuery); LIB_FUNCTION("7oxv3PPCumo", "libkernel", 1, "libkernel", 1, 1, sceKernelReserveVirtualRange); + LIB_FUNCTION("BC+OG5m9+bw", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemoryType); LIB_FUNCTION("pO96TwzOm5E", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemorySize); LIB_FUNCTION("NcaWUxfMNIQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapNamedDirectMemory); LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory); diff --git a/src/core/libraries/kernel/memory_management.cpp b/src/core/libraries/kernel/memory_management.cpp index 92fde960..3cf6a4cf 100644 --- a/src/core/libraries/kernel/memory_management.cpp +++ b/src/core/libraries/kernel/memory_management.cpp @@ -211,4 +211,12 @@ void PS4_SYSV_ABI _sceKernelRtldSetApplicationHeapAPI(void* func) { linker->SetHeapApiFunc(func); } +int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut, + void** directMemoryStartOut, + void** directMemoryEndOut) { + LOG_WARNING(Kernel_Vmm, "called, direct memory addr = {:#x}", addr); + auto* memory = Core::Memory::Instance(); + return memory->GetDirectMemoryType(addr, directMemoryTypeOut, directMemoryStartOut, directMemoryEndOut); +} + } // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/memory_management.h b/src/core/libraries/kernel/memory_management.h index 81f8bd7a..2a17f6ed 100644 --- a/src/core/libraries/kernel/memory_management.h +++ b/src/core/libraries/kernel/memory_management.h @@ -81,5 +81,8 @@ int PS4_SYSV_ABI sceKernelDirectMemoryQuery(u64 offset, int flags, OrbisQueryInf size_t infoSize); s32 PS4_SYSV_ABI sceKernelAvailableFlexibleMemorySize(size_t* sizeOut); void PS4_SYSV_ABI _sceKernelRtldSetApplicationHeapAPI(void* func); +int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut, + void** directMemoryStartOut, + void** directMemoryEndOut); } // namespace Libraries::Kernel diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 98628ee4..6aa6543b 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -87,10 +87,27 @@ int MemoryManager::Reserve(void** out_addr, VAddr virtual_addr, size_t size, Mem u64 alignment) { std::scoped_lock lk{mutex}; - ASSERT_MSG(virtual_addr != 0, "TODO: Reserve address is zero - search for free space"); - + virtual_addr = (virtual_addr == 0) ? impl.VirtualBase() : virtual_addr; + alignment = alignment > 0 ? alignment : 16_KB; VAddr mapped_addr = alignment > 0 ? Common::AlignUp(virtual_addr, alignment) : virtual_addr; + // Find the first free area starting with provided virtual address. + if (False(flags & MemoryMapFlags::Fixed)) { + auto it = FindVMA(mapped_addr); + // If the VMA is free and contains the requested mapping we are done. + if (it->second.type == VMAType::Free && it->second.Contains(virtual_addr, size)) { + mapped_addr = virtual_addr; + } else { + // Search for the first free VMA that fits our mapping. + while (it->second.type != VMAType::Free || it->second.size < size) { + it++; + } + ASSERT(it != vma_map.end()); + const auto& vma = it->second; + mapped_addr = alignment > 0 ? Common::AlignUp(vma.base, alignment) : vma.base; + } + } + // Add virtual memory area auto& new_vma = AddMapping(mapped_addr, size); new_vma.disallow_merge = True(flags & MemoryMapFlags::NoCoalesce); @@ -489,4 +506,22 @@ void MemoryManager::UnmapVulkanMemory(VAddr addr, size_t size) { mapped_memories.erase(it); } +int MemoryManager::GetDirectMemoryType(PAddr addr, int* directMemoryTypeOut, void** directMemoryStartOut, + void** directMemoryEndOut) { + std::scoped_lock lk{mutex}; + + auto dmem_area = FindDmemArea(addr); + + if (dmem_area == dmem_map.end() || dmem_area->second.is_free) { + LOG_ERROR(Core, "Unable to find allocated direct memory region to check type!"); + return ORBIS_KERNEL_ERROR_ENOENT; + } + + const auto& area = dmem_area->second; + *directMemoryStartOut = reinterpret_cast(area.base); + *directMemoryEndOut = reinterpret_cast(area.GetEnd()); + *directMemoryTypeOut = area.memory_type; + return ORBIS_OK; +} + } // namespace Core diff --git a/src/core/memory.h b/src/core/memory.h index e584afab..61c89016 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -160,6 +160,9 @@ public: std::pair GetVulkanBuffer(VAddr addr); + int GetDirectMemoryType(PAddr addr, int* directMemoryTypeOut, void** directMemoryStartOut, + void** directMemoryEndOut); + private: VMAHandle FindVMA(VAddr target) { return std::prev(vma_map.upper_bound(target));