From e205a7d993b0b3261045056d458c0c32f653d348 Mon Sep 17 00:00:00 2001 From: Stephen Miller Date: Mon, 26 May 2025 19:53:56 -0500 Subject: [PATCH] Better sceKernelMmap Handles errors where we would previously throw exceptions. Also moves the file logic to MapFile, since that way all the possible errors are in one place. Also fixes some function parameters to align with our current standards. --- src/core/libraries/kernel/memory.cpp | 52 ++++++++++++++++++---------- src/core/memory.cpp | 12 +++++-- src/core/memory.h | 4 +-- 3 files changed, 46 insertions(+), 22 deletions(-) diff --git a/src/core/libraries/kernel/memory.cpp b/src/core/libraries/kernel/memory.cpp index cb41a664a..e890324df 100644 --- a/src/core/libraries/kernel/memory.cpp +++ b/src/core/libraries/kernel/memory.cpp @@ -7,8 +7,7 @@ #include "common/assert.h" #include "common/logging/log.h" #include "common/scope_exit.h" -#include "common/singleton.h" -#include "core/file_sys/fs.h" +#include "common/singleton.h"9 #include "core/libraries/kernel/kernel.h" #include "core/libraries/kernel/memory.h" #include "core/libraries/kernel/orbis_error.h" @@ -553,30 +552,47 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolBatch(const OrbisKernelMemoryPoolBatchEntry* return result; } -int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd, size_t offset, - void** res) { - LOG_INFO(Kernel_Vmm, "called addr = {}, len = {}, prot = {}, flags = {}, fd = {}, offset = {}", - fmt::ptr(addr), len, prot, flags, fd, offset); - auto* h = Common::Singleton::Instance(); +void* PS4_SYSV_ABI posix_mmap(void* addr, u64 len, s32 prot, s32 flags, s32 fd, s64 phys_addr) { + LOG_INFO(Kernel_Vmm, "called addr = {}, len = {}, prot = {}, flags = {}, fd = {}, phys_addr = {}", + fmt::ptr(addr), len, prot, flags, fd, phys_addr); + + void* addr_out; auto* memory = Core::Memory::Instance(); const auto mem_prot = static_cast(prot); const auto mem_flags = static_cast(flags); + + s32 result = 0; if (fd == -1) { - return memory->MapMemory(res, std::bit_cast(addr), len, mem_prot, mem_flags, - Core::VMAType::Flexible); + result = memory->MapMemory(&addr_out, std::bit_cast(addr), len, mem_prot, mem_flags, + Core::VMAType::Flexible); } else { - const uintptr_t handle = h->GetFile(fd)->f.GetFileMapping(); - return memory->MapFile(res, std::bit_cast(addr), len, mem_prot, mem_flags, handle, - offset); + result = memory->MapFile(&addr_out, std::bit_cast(addr), len, mem_prot, mem_flags, + fd, phys_addr); } + + if (result < 0) { + // If the memory mappings fail, mmap sets errno to the appropriate error code, + // then returns (void*)-1; + ErrSceToPosix(result); + return reinterpret_cast(-1); + } + + return addr_out; } -void* PS4_SYSV_ABI posix_mmap(void* addr, u64 len, int prot, int flags, int fd, u64 offset) { - void* ptr; - LOG_INFO(Kernel_Vmm, "posix mmap redirect to sceKernelMmap"); - int result = sceKernelMmap(addr, len, prot, flags, fd, offset, &ptr); - ASSERT(result == 0); - return ptr; +s32 PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, s32 prot, s32 flags, s32 fd, s64 phys_addr, + void** res) { + void* addr_out = posix_mmap(addr, len, prot, flags, fd, phys_addr); + + if (addr_out == reinterpret_cast(-1)) { + // posix_mmap failed, calculate and return the appropriate kernel error code using errno. + LOG_ERROR(Kernel_Fs, "error = {}", *__Error()); + return ErrnoToSceKernelError(*__Error()); + } + + // Set the outputted address + *res = addr_out; + return 0; } s32 PS4_SYSV_ABI sceKernelConfiguredFlexibleMemorySize(u64* sizeOut) { diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 8c496f816..f3e3500c1 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -5,6 +5,7 @@ #include "common/assert.h" #include "common/config.h" #include "common/debug.h" +#include "core/file_sys/fs.h" #include "core/libraries/kernel/memory.h" #include "core/libraries/kernel/orbis_error.h" #include "core/libraries/kernel/process.h" @@ -459,8 +460,15 @@ int MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, size_t size, Mem vma.base, vma.base + vma.size, virtual_addr, virtual_addr + size); } - // Map the file. - impl.MapFile(mapped_addr, size_aligned, offset, std::bit_cast(prot), fd); + // Get the file to map + auto file = h->GetFile(fd); + if (file == nullptr) { + return ORBIS_KERNEL_ERROR_EBADF; + } + + const auto handle = file->f.GetFileMapping(); + + impl.MapFile(mapped_addr, size_aligned, phys_addr, std::bit_cast(prot), fd); if (prot >= MemoryProt::GpuRead) { // PS4s only map to GPU memory when the protection includes GPU access. diff --git a/src/core/memory.h b/src/core/memory.h index 883b48854..aba8b47cc 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -195,8 +195,8 @@ public: MemoryMapFlags flags, VMAType type, std::string_view name = "anon", bool is_exec = false, PAddr phys_addr = -1, u64 alignment = 0); - int MapFile(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot, - MemoryMapFlags flags, uintptr_t fd, size_t offset); + s32 MapFile(void** out_addr, VAddr virtual_addr, u64 size, MemoryProt prot, + MemoryMapFlags flags, s32 fd, s64 phys_addr); s32 PoolDecommit(VAddr virtual_addr, size_t size);