From da6434a65a7dc0a874ce20324a3a7ed4ab5fefe1 Mon Sep 17 00:00:00 2001 From: RipleyTom Date: Sat, 11 Jun 2022 14:12:42 +0200 Subject: [PATCH] Implements sys_fs_fcntl 0xC0000008 & 0xC000001A (#11957) --- rpcs3/Emu/Cell/PPUModule.cpp | 2 +- rpcs3/Emu/Cell/lv2/sys_fs.cpp | 103 +++++++++++++++++++++++++- rpcs3/Emu/Cell/lv2/sys_fs.h | 55 +++++++++++++- rpcs3/Emu/Cell/lv2/sys_memory.cpp | 10 +-- rpcs3/Emu/Cell/lv2/sys_memory.h | 19 +++++ rpcs3/Emu/Cell/lv2/sys_mmapper.cpp | 2 +- rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp | 6 +- rpcs3/Emu/Cell/lv2/sys_spu.cpp | 6 +- rpcs3/Emu/Cell/lv2/sys_vm.cpp | 6 +- 9 files changed, 188 insertions(+), 21 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 1bd58fe129..1d2bfce920 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -1850,7 +1850,7 @@ bool ppu_load_exec(const ppu_exec_object& elf) g_fxo->init(mem_size); } - g_fxo->get().used += primary_stacksize; + ensure(g_fxo->get().take(primary_stacksize)); ppu->cmd_push({ppu_cmd::initialize, 0}); diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index deff7dc3e4..6567b0ab6b 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "sys_sync.h" #include "sys_fs.h" +#include "sys_memory.h" #include "Emu/Cell/PPUModule.h" #include "Emu/Cell/PPUThread.h" @@ -865,6 +866,22 @@ error_code sys_fs_close(ppu_thread& ppu, u32 fd) sys_fs.warning("%s: %s", FD_state_log, *file); } + // Free memory associated with fd if any + if (file->ct_id && file->ct_used) + { + auto& default_container = g_fxo->get(); + std::lock_guard lock(default_container.mutex); + + if (auto ct = idm::get(file->ct_id)) + { + ct->free(file->ct_used); + if (default_container.id == file->ct_id) + { + default_container.used -= file->ct_used; + } + } + } + // Ensure Host file handle won't be kept open after this syscall file->file.close(); } @@ -1653,7 +1670,7 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr _arg, u32 case 0xc0000007: // cellFsArcadeHddSerialNumber { - const auto arg = vm::static_ptr_cast(_arg); + const auto arg = vm::static_ptr_cast(_arg); // TODO populate arg-> unk1+2 arg->out_code = CELL_OK; return CELL_OK; @@ -1661,7 +1678,86 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr _arg, u32 case 0xc0000008: // cellFsSetDefaultContainer, cellFsSetIoBuffer, cellFsSetIoBufferFromDefaultContainer { - break; + // Allocates memory from a container/default container to a specific fd or default IO processing + const auto arg = vm::static_ptr_cast(_arg); + auto& default_container = g_fxo->get(); + + std::lock_guard def_container_lock(default_container.mutex); + + if (fd == 0xFFFFFFFF) + { + // No check on container is done when setting default container + default_container.id = arg->size ? ::narrow(arg->container_id) : 0u; + default_container.cap = arg->size; + default_container.used = 0; + + arg->out_code = CELL_OK; + return CELL_OK; + } + + auto file = idm::get(fd); + if (!file) + { + return CELL_EBADF; + } + + if (auto ct = idm::get(file->ct_id)) + { + ct->free(file->ct_used); + if (default_container.id == file->ct_id) + { + default_container.used -= file->ct_used; + } + } + + file->ct_id = 0; + file->ct_used = 0; + + // Aligns on lower bound + u32 actual_size = arg->size - (arg->size % ((arg->page_type & CELL_FS_IO_BUFFER_PAGE_SIZE_64KB) ? 0x10000 : 0x100000)); + + if (!actual_size) + { + arg->out_code = CELL_OK; + return CELL_OK; + } + + u32 new_container_id = arg->container_id == 0xFFFFFFFF ? default_container.id : ::narrow(arg->container_id); + if (default_container.id == new_container_id && (default_container.used + actual_size) > default_container.cap) + { + return CELL_ENOMEM; + } + + const auto ct = idm::get(new_container_id, [&](lv2_memory_container& ct) -> CellError + { + if (!ct.take(actual_size)) + { + return CELL_ENOMEM; + } + + return {}; + }); + + if (!ct) + { + return CELL_ESRCH; + } + + if (ct.ret) + { + return ct.ret; + } + + if (default_container.id == new_container_id) + { + default_container.used += actual_size; + } + + file->ct_id = new_container_id; + file->ct_used = actual_size; + + arg->out_code = CELL_OK; + return CELL_OK; } case 0xc0000015: // USB Vid/Pid lookup - Used by arcade games on dev_usbXXX @@ -1735,7 +1831,8 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr _arg, u32 case 0xc000001a: // cellFsSetDiscReadRetrySetting, 5731DF45 { - break; + [[maybe_unused]] const auto arg = vm::static_ptr_cast(_arg); + return CELL_OK; } case 0xc000001c: // USB Vid/Pid/Serial lookup diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.h b/rpcs3/Emu/Cell/lv2/sys_fs.h index ee8ebda2d4..de970c8339 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.h +++ b/rpcs3/Emu/Cell/lv2/sys_fs.h @@ -67,6 +67,12 @@ enum : u8 CELL_FS_TYPE_SYMLINK = 3, }; +enum : u32 +{ + CELL_FS_IO_BUFFER_PAGE_SIZE_64KB = 0x0002, + CELL_FS_IO_BUFFER_PAGE_SIZE_1MB = 0x0004, +}; + struct CellFsDirent { u8 d_type; @@ -203,6 +209,9 @@ struct lv2_file final : lv2_fs_object std::string real_path; const lv2_file_type type; + // IO Container + u32 ct_id{}, ct_used{}; + // Stream lock atomic_t lock{0}; @@ -435,7 +444,7 @@ struct lv2_file_c0000006 : lv2_file_op CHECK_SIZE(lv2_file_c0000006, 0x20); -struct lv2_file_c000007 : lv2_file_op +struct lv2_file_c0000007 : lv2_file_op { be_t out_code; vm::bcptr name; @@ -446,7 +455,24 @@ struct lv2_file_c000007 : lv2_file_op be_t unk2_size; //0x21 }; -CHECK_SIZE(lv2_file_c000007, 0x1c); +CHECK_SIZE(lv2_file_c0000007, 0x1c); + +struct lv2_file_c0000008 : lv2_file_op +{ + u8 _x0[4]; + be_t op; // 0xC0000008 + u8 _x8[8]; + be_t container_id; + be_t size; + be_t page_type; // 0x4000 for cellFsSetDefaultContainer + // 0x4000 | page_type given by user, valid values seem to be: + // CELL_FS_IO_BUFFER_PAGE_SIZE_64KB 0x0002 + // CELL_FS_IO_BUFFER_PAGE_SIZE_1MB 0x0004 + be_t out_code; + u8 _x24[4]; +}; + +CHECK_SIZE(lv2_file_c0000008, 0x28); struct lv2_file_c0000015 : lv2_file_op { @@ -463,6 +489,19 @@ struct lv2_file_c0000015 : lv2_file_op CHECK_SIZE(lv2_file_c0000015, 0x20); +struct lv2_file_c000001a : lv2_file_op +{ + be_t disc_retry_type; // CELL_FS_DISC_READ_RETRY_NONE results in a 0 here + // CELL_FS_DISC_READ_RETRY_DEFAULT results in a 0x63 here + be_t _x4; // 0 + be_t _x8; // 0x000186A0 + be_t _xC; // 0 + be_t _x10; // 0 + be_t _x14; // 0 +}; + +CHECK_SIZE(lv2_file_c000001a, 0x18); + struct lv2_file_c000001c : lv2_file_op { be_t size; // 0x20 @@ -507,6 +546,18 @@ struct CellFsMountInfo CHECK_SIZE(CellFsMountInfo, 0x94); +// Default IO container +struct default_sys_fs_container +{ + default_sys_fs_container(const default_sys_fs_container&) = delete; + default_sys_fs_container& operator=(const default_sys_fs_container&) = delete; + + shared_mutex mutex; + u32 id = 0; + u32 cap = 0; + u32 used = 0; +}; + // Syscalls error_code sys_fs_test(ppu_thread& ppu, u32 arg1, u32 arg2, vm::ptr arg3, u32 arg4, vm::ptr buf, u32 buf_size); diff --git a/rpcs3/Emu/Cell/lv2/sys_memory.cpp b/rpcs3/Emu/Cell/lv2/sys_memory.cpp index 751b13fdaf..ab4863d0fb 100644 --- a/rpcs3/Emu/Cell/lv2/sys_memory.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_memory.cpp @@ -83,7 +83,7 @@ error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptrused -= size; + ct->free(size); return CELL_ENOMEM; } @@ -172,7 +172,7 @@ error_code sys_memory_free(cpu_thread& cpu, u32 addr) } const auto size = (ensure(vm::dealloc(addr))); - reader_lock{id_manager::g_mutex}, ct->used -= size; + reader_lock{id_manager::g_mutex}, ct->free(size); return CELL_OK; } @@ -277,7 +277,7 @@ error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr cid, u32 si return CELL_OK; } - dct.used -= size; + dct.free(size); return CELL_EAGAIN; } @@ -311,7 +311,7 @@ error_code sys_memory_container_destroy(cpu_thread& cpu, u32 cid) } // Return "physical memory" to the default container - g_fxo->get().used -= ct->size; + g_fxo->get().free(ct->size); return CELL_OK; } diff --git a/rpcs3/Emu/Cell/lv2/sys_memory.h b/rpcs3/Emu/Cell/lv2/sys_memory.h index dadffe9da8..b903f90ecc 100644 --- a/rpcs3/Emu/Cell/lv2/sys_memory.h +++ b/rpcs3/Emu/Cell/lv2/sys_memory.h @@ -89,6 +89,25 @@ struct lv2_memory_container return result; } + + u32 free(u64 amount) + { + auto [_, result] = used.fetch_op([&](u32& value) -> u32 + { + if (value >= amount) + { + value -= static_cast(amount); + return static_cast(amount); + } + + return 0; + }); + + // Sanity check + ensure(result == amount); + + return result; + } }; struct sys_memory_user_memory_stat_t diff --git a/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp b/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp index 388b985adb..d2d5308c4a 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp @@ -529,7 +529,7 @@ error_code sys_mmapper_free_shared_memory(ppu_thread& ppu, u32 mem_id) if (!mem.exists) { // Return "physical memory" to the memory container - mem.ct->used -= mem.size; + mem.ct->free(mem.size); } return {}; diff --git a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp index 0473fb484a..49023e473f 100644 --- a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp @@ -45,7 +45,7 @@ void ppu_thread_exit(ppu_thread& ppu, ppu_opcode_t, be_t*, struct ppu_intrp if (auto& dct = g_fxo->get(); !Emu.IsStopped()) { - dct.used -= ppu.stack_size; + dct.free(ppu.stack_size); } if (ppu.call_history.index) @@ -418,7 +418,7 @@ error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr thread_id, vm::p if (!stack_base) { - dct.used -= stack_size; + dct.free(stack_size); return CELL_ENOMEM; } @@ -447,7 +447,7 @@ error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr thread_id, vm::p if (!tid) { vm::dealloc(stack_base); - dct.used -= stack_size; + dct.free(stack_size); return CELL_EAGAIN; } diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index 3bf52a5a86..990d1c24b3 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -780,7 +780,7 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr id, u32 num if (!limits.check(use_scheduler ? limits_data{.controllable = num} : limits_data{.physical = num})) { - ct->used -= mem_size; + ct->free(mem_size); return CELL_EBUSY; } @@ -788,7 +788,7 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr id, u32 num if (!group) { - ct->used -= mem_size; + ct->free(mem_size); return CELL_EAGAIN; } @@ -823,7 +823,7 @@ error_code sys_spu_thread_group_destroy(ppu_thread& ppu, u32 id) return CELL_EBUSY; } - group.ct->used -= group.mem_size; + group.ct->free(group.mem_size); return {}; }); diff --git a/rpcs3/Emu/Cell/lv2/sys_vm.cpp b/rpcs3/Emu/Cell/lv2/sys_vm.cpp index 5503a87e58..9d69472a2f 100644 --- a/rpcs3/Emu/Cell/lv2/sys_vm.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_vm.cpp @@ -85,7 +85,7 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 return CELL_OK; } - ct->used -= psize; + ct->free(psize); g_fxo->get().total_vsize -= vsize; return CELL_ENOMEM; } @@ -119,7 +119,7 @@ error_code sys_vm_unmap(ppu_thread& ppu, u32 addr) ensure(vm::unmap(addr).second); // Return memory - vmo.ct->used -= vmo.psize; + vmo.ct->free(vmo.psize); g_fxo->get().total_vsize -= vmo.size; }); @@ -205,7 +205,7 @@ error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u32 size) return CELL_EBUSY; } - vmo.ct->used -= size; + vmo.ct->free(size); return {}; });