From c1263eeb79529c460730dc62fe2ec3a1efbdfb87 Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Wed, 17 Jun 2026 12:00:49 +0300 Subject: [PATCH] sys_rsx: Fix IOMAP syscalls argument types --- rpcs3/Emu/Cell/lv2/sys_rsx.cpp | 56 ++++++++++++++++++++++++---------- rpcs3/Emu/Cell/lv2/sys_rsx.h | 6 ++-- rpcs3/Emu/Memory/vm.cpp | 8 ++--- rpcs3/Emu/Memory/vm.h | 4 +-- 4 files changed, 49 insertions(+), 25 deletions(-) diff --git a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp index 4ef4e04d85..c91a1aa1aa 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp @@ -18,7 +18,7 @@ LOG_CHANNEL(sys_rsx); // Unknown error code returned by sys_rsx_context_attribute enum sys_rsx_error : s32 { - SYS_RSX_CONTEXT_ATTRIBUTE_ERROR = -17 + LV1_ILLEGAL_PARAMETER_VALUE = -17 }; template<> @@ -28,7 +28,7 @@ void fmt_class_string::format(std::string& out, u64 arg) { switch (error) { - STR_CASE(SYS_RSX_CONTEXT_ATTRIBUTE_ERROR); + STR_CASE(LV1_ILLEGAL_PARAMETER_VALUE); } return unknown; @@ -169,12 +169,28 @@ error_code sys_rsx_device_close(cpu_thread& cpu) * @param a6 (IN): E.g. Immediate value passed in cellGcmSys is 16. * @param a7 (IN): E.g. Immediate value passed in cellGcmSys is 8. */ -error_code sys_rsx_memory_allocate(cpu_thread& cpu, vm::ptr mem_handle, vm::ptr mem_addr, u32 size, u64 flags, u64 a5, u64 a6, u64 a7) +error_code sys_rsx_memory_allocate(cpu_thread& cpu, vm::ptr mem_handle, vm::ptr mem_addr, u64 size, u64 flags, u64 a5, u64 a6, u64 a7) { - cpu.state += cpu_flag::wait; - sys_rsx.warning("sys_rsx_memory_allocate(mem_handle=*0x%x, mem_addr=*0x%x, size=0x%x, flags=0x%llx, a5=0x%llx, a6=0x%llx, a7=0x%llx)", mem_handle, mem_addr, size, flags, a5, a6, a7); + // size == 0 yields available size, unimplemented + ensure(size != 0); + + if (size & 0xFFFFF) + { + return LV1_ILLEGAL_PARAMETER_VALUE; + } + + // This is a result from how the argument is treated internally + size %= 0x100000 * 0x1'0000'00000; + + if (size > 0x1000'0000) + { + return LV1_ILLEGAL_PARAMETER_VALUE; + } + + cpu.state += cpu_flag::wait; + if (vm::falloc(rsx::constants::local_mem_base, size, vm::video)) { rsx::get_current_renderer()->local_mem_size = size; @@ -395,7 +411,7 @@ error_code sys_rsx_context_free(ppu_thread& ppu, u32 context_id) * @param size (IN): Size of mapping area in bytes. E.g. 0x00200000 * @param flags (IN): */ -error_code sys_rsx_context_iomap(cpu_thread& cpu, u32 context_id, u32 io, u32 ea, u32 size, u64 flags) +error_code sys_rsx_context_iomap(cpu_thread& cpu, u32 context_id, u64 io, u64 ea, u64 size, u64 flags) { cpu.state += cpu_flag::wait; @@ -403,8 +419,12 @@ error_code sys_rsx_context_iomap(cpu_thread& cpu, u32 context_id, u32 io, u32 ea const auto render = rsx::get_current_renderer(); - if (!size || io & 0xFFFFF || ea + u64{size} > rsx::constants::local_mem_base || ea & 0xFFFFF || size & 0xFFFFF || - context_id != 0x55555555 || render->main_mem_size < io + u64{size}) + if (!size || io & 0xFFFFF || size > 0x200'00000 || size > std::min(~io, ~size) || ea & 0xFFFFF || size & 0xFFFFF) + { + return CELL_EINVAL; + } + + if (context_id != 0x55555555 || render->main_mem_size < io + size) { return CELL_EINVAL; } @@ -419,7 +439,7 @@ error_code sys_rsx_context_iomap(cpu_thread& cpu, u32 context_id, u32 io, u32 ea vm::writer_lock rlock; - for (u32 addr = ea, end = ea + size; addr < end; addr += 0x100000) + for (u64 addr = ea, end = ea + size; addr < end; addr += 0x100000) { if (!vm::check_addr(addr, vm::page_readable | (addr < 0x20000000 ? 0 : vm::page_1m_size))) { @@ -458,7 +478,7 @@ error_code sys_rsx_context_iomap(cpu_thread& cpu, u32 context_id, u32 io, u32 ea * @param io (IN): IO address. E.g. 0x00600000 (Start page 6) * @param size (IN): Size to unmap in byte. E.g. 0x00200000 */ -error_code sys_rsx_context_iounmap(cpu_thread& cpu, u32 context_id, u32 io, u32 size) +error_code sys_rsx_context_iounmap(cpu_thread& cpu, u32 context_id, u64 io, u64 size) { cpu.state += cpu_flag::wait; @@ -466,8 +486,12 @@ error_code sys_rsx_context_iounmap(cpu_thread& cpu, u32 context_id, u32 io, u32 const auto render = rsx::get_current_renderer(); - if (!size || size & 0xFFFFF || io & 0xFFFFF || context_id != 0x55555555 || - render->main_mem_size < io + u64{size}) + if (!size || size & 0xFFFFF || io & 0xFFFFF || size > 0x200'00000 || size > ~io) + { + return CELL_EINVAL; + } + + if (context_id != 0x55555555 || render->main_mem_size < io + size) { return CELL_EINVAL; } @@ -481,7 +505,7 @@ error_code sys_rsx_context_iounmap(cpu_thread& cpu, u32 context_id, u32 io, u32 std::scoped_lock lock(render->sys_rsx_mtx); - for (const u32 end = (io >>= 20) + (size >>= 20); io < end;) + for (const u64 end = (io >>= 20) + (size >>= 20); io < end;) { auto& table = render->iomap_table; @@ -626,7 +650,7 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64 const u8 id = a3 & 0xFF; if (id > 7) { - return SYS_RSX_CONTEXT_ATTRIBUTE_ERROR; + return LV1_ILLEGAL_PARAMETER_VALUE; } std::lock_guard lock(render->sys_rsx_mtx); @@ -676,7 +700,7 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64 { if (a3 > 7) { - return SYS_RSX_CONTEXT_ATTRIBUTE_ERROR; + return LV1_ILLEGAL_PARAMETER_VALUE; } // NOTE: There currently seem to only be 2 active heads on PS3 @@ -784,7 +808,7 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64 if (a3 >= std::size(render->zculls)) { - return SYS_RSX_CONTEXT_ATTRIBUTE_ERROR; + return LV1_ILLEGAL_PARAMETER_VALUE; } if (!render->is_fifo_idle()) diff --git a/rpcs3/Emu/Cell/lv2/sys_rsx.h b/rpcs3/Emu/Cell/lv2/sys_rsx.h index 44f02a697d..9b06b88ea4 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsx.h +++ b/rpcs3/Emu/Cell/lv2/sys_rsx.h @@ -127,12 +127,12 @@ struct RsxDisplayInfo // SysCalls error_code sys_rsx_device_open(cpu_thread& cpu); error_code sys_rsx_device_close(cpu_thread& cpu); -error_code sys_rsx_memory_allocate(cpu_thread& cpu, vm::ptr mem_handle, vm::ptr mem_addr, u32 size, u64 flags, u64 a5, u64 a6, u64 a7); +error_code sys_rsx_memory_allocate(cpu_thread& cpu, vm::ptr mem_handle, vm::ptr mem_addr, u64 size, u64 flags, u64 a5, u64 a6, u64 a7); error_code sys_rsx_memory_free(cpu_thread& cpu, u32 mem_handle); error_code sys_rsx_context_allocate(cpu_thread& cpu, vm::ptr context_id, vm::ptr lpar_dma_control, vm::ptr lpar_driver_info, vm::ptr lpar_reports, u64 mem_ctx, u64 system_mode); error_code sys_rsx_context_free(ppu_thread& ppu, u32 context_id); -error_code sys_rsx_context_iomap(cpu_thread& cpu, u32 context_id, u32 io, u32 ea, u32 size, u64 flags); -error_code sys_rsx_context_iounmap(cpu_thread& cpu, u32 context_id, u32 io, u32 size); +error_code sys_rsx_context_iomap(cpu_thread& cpu, u32 context_id, u64 io, u64 ea, u64 size, u64 flags); +error_code sys_rsx_context_iounmap(cpu_thread& cpu, u32 context_id, u64 io, u64 size); error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64 a4, u64 a5, u64 a6); error_code sys_rsx_device_map(cpu_thread& cpu, vm::ptr dev_addr, vm::ptr a2, u32 dev_id); error_code sys_rsx_device_unmap(cpu_thread& cpu, u32 dev_id); diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 0a899f7a7d..6372e6e3cc 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -1070,15 +1070,15 @@ namespace vm return size; } - bool check_addr(u32 addr, u8 flags, u32 size) + bool check_addr(u64 addr, u8 flags, u32 size) { if (size == 0) { return true; } - // Overflow checking - if (0x10000'0000ull - addr < size) + // u64 addressing is not supported at the moment + if (addr > u32{umax} || 0x10000'0000ull - addr < size) { return false; } @@ -1086,7 +1086,7 @@ namespace vm // Always check this flag flags |= page_allocated; - for (u32 i = addr / 4096, max = (addr + size - 1) / 4096; i <= max;) + for (u64 i = addr / 4096, max = (addr + size - 1) / 4096; i <= max;) { auto state = +g_pages[i]; diff --git a/rpcs3/Emu/Memory/vm.h b/rpcs3/Emu/Memory/vm.h index 87e798aadb..c59e32d5b4 100644 --- a/rpcs3/Emu/Memory/vm.h +++ b/rpcs3/Emu/Memory/vm.h @@ -78,10 +78,10 @@ namespace vm bool page_protect(u32 addr, u32 size, u8 flags_test = 0, u8 flags_set = 0, u8 flags_clear = 0); // Check flags for specified memory range (unsafe) - bool check_addr(u32 addr, u8 flags, u32 size); + bool check_addr(u64 addr, u8 flags, u32 size); template - inline bool check_addr(u32 addr, u8 flags = page_readable) + inline bool check_addr(u64 addr, u8 flags = page_readable) { extern std::array g_pages;