From e757063d3120e68fe53b9c888bc6c5fe7372b406 Mon Sep 17 00:00:00 2001 From: Stephen Miller <56742918+StevenMiller123@users.noreply.github.com> Date: Wed, 5 Feb 2025 09:21:05 -0600 Subject: [PATCH] Improved error handling in sceKernelAllocateDirectMemory (#2037) * Handle errors in sceKernelAllocateDirectMemory * Improve accuracy of error cases Some of our existing cases are normally EAGAIN returns. * Improve logging on errors * Clang * TEMPORARY HACK FOR NBA TESTS This will be removed before this PR is marked as ready, and is only here to make sure the other NBA games (and perhaps DOA3) work if some missing init behavior is handled. * Revert "TEMPORARY HACK FOR NBA TESTS" This reverts commit a0e27b0229811778c8390066d00b5221aa5d54a6. * Change error message --- src/core/libraries/kernel/memory.cpp | 28 ++++++++++++++++++++++------ src/core/memory.cpp | 5 ++++- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/core/libraries/kernel/memory.cpp b/src/core/libraries/kernel/memory.cpp index 8deefb496..551fd8e3e 100644 --- a/src/core/libraries/kernel/memory.cpp +++ b/src/core/libraries/kernel/memory.cpp @@ -26,17 +26,20 @@ u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize() { int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len, u64 alignment, int memoryType, s64* physAddrOut) { - if (searchStart < 0 || searchEnd <= searchStart) { - LOG_ERROR(Kernel_Vmm, "Provided address range is invalid!"); + if (searchStart < 0 || searchEnd < 0) { + LOG_ERROR(Kernel_Vmm, "Invalid parameters!"); return ORBIS_KERNEL_ERROR_EINVAL; } - const bool is_in_range = searchEnd - searchStart >= len; - if (len <= 0 || !Common::Is16KBAligned(len) || !is_in_range) { - LOG_ERROR(Kernel_Vmm, "Provided address range is invalid!"); + if (len <= 0 || !Common::Is16KBAligned(len)) { + LOG_ERROR(Kernel_Vmm, "Length {:#x} is invalid!", len); return ORBIS_KERNEL_ERROR_EINVAL; } if (alignment != 0 && !Common::Is16KBAligned(alignment)) { - LOG_ERROR(Kernel_Vmm, "Alignment value is invalid!"); + LOG_ERROR(Kernel_Vmm, "Alignment {:#x} is invalid!", alignment); + return ORBIS_KERNEL_ERROR_EINVAL; + } + if (memoryType > 10) { + LOG_ERROR(Kernel_Vmm, "Memory type {:#x} is invalid!", memoryType); return ORBIS_KERNEL_ERROR_EINVAL; } if (physAddrOut == nullptr) { @@ -44,8 +47,21 @@ int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u return ORBIS_KERNEL_ERROR_EINVAL; } + const bool is_in_range = searchEnd - searchStart >= len; + if (searchEnd <= searchStart || searchEnd < len || !is_in_range) { + LOG_ERROR(Kernel_Vmm, + "Provided address range is too small!" + " searchStart = {:#x}, searchEnd = {:#x}, length = {:#x}", + searchStart, searchEnd, len); + return ORBIS_KERNEL_ERROR_EAGAIN; + } + auto* memory = Core::Memory::Instance(); PAddr phys_addr = memory->Allocate(searchStart, searchEnd, len, alignment, memoryType); + if (phys_addr == -1) { + return ORBIS_KERNEL_ERROR_EAGAIN; + } + *physAddrOut = static_cast(phys_addr); LOG_INFO(Kernel_Vmm, diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 271092eaf..4717b3a74 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -117,7 +117,10 @@ PAddr MemoryManager::Allocate(PAddr search_start, PAddr search_end, size_t size, dmem_area->second.GetEnd() <= search_end) { ++dmem_area; } - ASSERT_MSG(is_suitable(), "Unable to find free direct memory area: size = {:#x}", size); + if (!is_suitable()) { + LOG_ERROR(Kernel_Vmm, "Unable to find free direct memory area: size = {:#x}", size); + return -1; + } // Align free position PAddr free_addr = dmem_area->second.base;