diff --git a/rpcs3/Emu/Cell/Modules/sys_mmapper_.cpp b/rpcs3/Emu/Cell/Modules/sys_mmapper_.cpp index 9ed516b40f..b0a409bdc2 100644 --- a/rpcs3/Emu/Cell/Modules/sys_mmapper_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_mmapper_.cpp @@ -8,14 +8,14 @@ s32 sys_mmapper_allocate_memory(ppu_thread& ppu, u32 size, u64 flags, vm::ptr mem_id) { sysPrxForUser.notice("sys_mmapper_allocate_memory_from_container(size=0x%x, cid=0x%x, flags=0x%llx, mem_id=*0x%x)", size, cid, flags, mem_id); - return sys_mmapper_allocate_shared_memory_from_container(ppu, 0xffff000000000000ull, size, cid, flags, mem_id); + return sys_mmapper_allocate_shared_memory_from_container(ppu, SYS_MMAPPER_NO_SHM_KEY, size, cid, flags, mem_id); } s32 sys_mmapper_map_memory(ppu_thread& ppu, u32 addr, u32 mem_id, u64 flags) diff --git a/rpcs3/Emu/Cell/PPUFunction.cpp b/rpcs3/Emu/Cell/PPUFunction.cpp index cb61ef586f..e4c466d55c 100644 --- a/rpcs3/Emu/Cell/PPUFunction.cpp +++ b/rpcs3/Emu/Cell/PPUFunction.cpp @@ -211,7 +211,7 @@ extern std::string ppu_get_syscall_name(u64 code) case 325: return "sys_memory_container_destroy"; case 326: return "sys_mmapper_allocate_fixed_address"; case 327: return "sys_mmapper_enable_page_fault_notification"; - case 328: return "sys_mmapper_allocate_shared_memory_ext"; + case 328: return "sys_mmapper_allocate_shared_memory_from_container_ext"; case 329: return "sys_mmapper_free_shared_memory"; case 330: return "sys_mmapper_allocate_address"; case 331: return "sys_mmapper_free_address"; @@ -222,6 +222,7 @@ extern std::string ppu_get_syscall_name(u64 code) case 336: return "sys_mmapper_change_address_access_right"; case 337: return "sys_mmapper_search_and_map"; case 338: return "sys_mmapper_get_shared_memory_attribute"; + case 339: return "sys_mmapper_allocate_shared_memory_ext"; case 341: return "sys_memory_container_create"; case 342: return "sys_memory_container_destroy"; case 343: return "sys_memory_container_get_size"; diff --git a/rpcs3/Emu/Cell/lv2/lv2.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp index e17c3005eb..d4c3707fa0 100644 --- a/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -332,7 +332,7 @@ const std::array s_ppu_syscall_table BIND_FUNC(sys_memory_container_destroy), //325 (0x145) DBG BIND_FUNC(sys_mmapper_allocate_fixed_address), //326 (0x146) BIND_FUNC(sys_mmapper_enable_page_fault_notification), //327 (0x147) - null_func,//BIND_FUNC(sys_mmapper_allocate_shared_memory_ext) //328 (0x148) + BIND_FUNC(sys_mmapper_allocate_shared_memory_from_container_ext), //328 (0x148) BIND_FUNC(sys_mmapper_free_shared_memory), //329 (0x149) BIND_FUNC(sys_mmapper_allocate_address), //330 (0x14A) BIND_FUNC(sys_mmapper_free_address), //331 (0x14B) @@ -343,7 +343,7 @@ const std::array s_ppu_syscall_table BIND_FUNC(sys_mmapper_change_address_access_right), //336 (0x150) BIND_FUNC(sys_mmapper_search_and_map), //337 (0x151) null_func,//BIND_FUNC(sys_mmapper_get_shared_memory_attribute) //338 (0x152) - null_func,//BIND_FUNC(sys_...) //339 (0x153) + BIND_FUNC(sys_mmapper_allocate_shared_memory_ext), //339 (0x153) null_func,//BIND_FUNC(sys_...) //340 (0x154) BIND_FUNC(sys_memory_container_create), //341 (0x155) BIND_FUNC(sys_memory_container_destroy), //342 (0x156) diff --git a/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp b/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp index 34583f7b28..1fe2465e5d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp @@ -7,6 +7,8 @@ #include "Emu/Memory/vm_var.h" #include "Utilities/VirtualMemory.h" #include "sys_memory.h" +#include "sys_sync.h" +#include "sys_process.h" LOG_CHANNEL(sys_mmapper); @@ -19,6 +21,26 @@ lv2_memory::lv2_memory(u32 size, u32 align, u64 flags, lv2_memory_container* ct) { } +template<> DECLARE(ipc_manager::g_ipc) {}; + +template +error_code create_lv2_shm(bool pshared, u64 ipc_key, u32 size, u32 align, u64 flags, lv2_memory_container* ct) +{ + if (auto error = lv2_obj::create(pshared ? SYS_SYNC_PROCESS_SHARED : SYS_SYNC_NOT_PROCESS_SHARED, ipc_key, exclusive ? SYS_SYNC_NEWLY_CREATED : SYS_SYNC_NOT_CARE, [&]() + { + return std::make_shared( + size, + align, + flags, + ct); + }, false)) + { + return error; + } + + return CELL_OK; +} + error_code sys_mmapper_allocate_address(ppu_thread& ppu, u64 size, u64 flags, u64 alignment, vm::ptr alloc_addr) { vm::temporary_unlock(ppu); @@ -76,11 +98,16 @@ error_code sys_mmapper_allocate_fixed_address(ppu_thread& ppu) return CELL_OK; } -error_code sys_mmapper_allocate_shared_memory(ppu_thread& ppu, u64 unk, u32 size, u64 flags, vm::ptr mem_id) +error_code sys_mmapper_allocate_shared_memory(ppu_thread& ppu, u64 ipc_key, u32 size, u64 flags, vm::ptr mem_id) { vm::temporary_unlock(ppu); - sys_mmapper.warning("sys_mmapper_allocate_shared_memory(0x%llx, size=0x%x, flags=0x%llx, mem_id=*0x%x)", unk, size, flags, mem_id); + sys_mmapper.warning("sys_mmapper_allocate_shared_memory(ipc_key=0x%llx, size=0x%x, flags=0x%llx, mem_id=*0x%x)", ipc_key, size, flags, mem_id); + + if (size == 0) + { + return CELL_EALIGN; + } // Check page granularity switch (flags & SYS_MEMORY_PAGE_SIZE_MASK) @@ -95,7 +122,6 @@ error_code sys_mmapper_allocate_shared_memory(ppu_thread& ppu, u64 unk, u32 size break; } - case SYS_MEMORY_PAGE_SIZE_64K: { if (size % 0x10000) @@ -105,7 +131,6 @@ error_code sys_mmapper_allocate_shared_memory(ppu_thread& ppu, u64 unk, u32 size break; } - default: { return CELL_EINVAL; @@ -120,17 +145,25 @@ error_code sys_mmapper_allocate_shared_memory(ppu_thread& ppu, u64 unk, u32 size return CELL_ENOMEM; } - // Generate a new mem ID - *mem_id = idm::make(size, flags & SYS_MEMORY_PAGE_SIZE_64K ? 0x10000 : 0x100000, flags, dct); + if (auto error = create_lv2_shm(ipc_key != SYS_MMAPPER_NO_SHM_KEY, ipc_key, size, flags & SYS_MEMORY_PAGE_SIZE_64K ? 0x10000 : 0x100000, flags, dct)) + { + return error; + } + *mem_id = idm::last_id(); return CELL_OK; } -error_code sys_mmapper_allocate_shared_memory_from_container(ppu_thread& ppu, u64 unk, u32 size, u32 cid, u64 flags, vm::ptr mem_id) +error_code sys_mmapper_allocate_shared_memory_from_container(ppu_thread& ppu, u64 ipc_key, u32 size, u32 cid, u64 flags, vm::ptr mem_id) { vm::temporary_unlock(ppu); - sys_mmapper.warning("sys_mmapper_allocate_shared_memory_from_container(0x%llx, size=0x%x, cid=0x%x, flags=0x%llx, mem_id=*0x%x)", unk, size, cid, flags, mem_id); + sys_mmapper.warning("sys_mmapper_allocate_shared_memory_from_container(ipc_key=0x%llx, size=0x%x, cid=0x%x, flags=0x%llx, mem_id=*0x%x)", ipc_key, size, cid, flags, mem_id); + + if (size == 0) + { + return CELL_EALIGN; + } // Check page granularity. switch (flags & SYS_MEMORY_PAGE_SIZE_MASK) @@ -145,7 +178,6 @@ error_code sys_mmapper_allocate_shared_memory_from_container(ppu_thread& ppu, u6 break; } - case SYS_MEMORY_PAGE_SIZE_64K: { if (size % 0x10000) @@ -155,7 +187,6 @@ error_code sys_mmapper_allocate_shared_memory_from_container(ppu_thread& ppu, u6 break; } - default: { return CELL_EINVAL; @@ -183,9 +214,226 @@ error_code sys_mmapper_allocate_shared_memory_from_container(ppu_thread& ppu, u6 return ct.ret; } - // Generate a new mem ID - *mem_id = idm::make(size, flags & SYS_MEMORY_PAGE_SIZE_64K ? 0x10000 : 0x100000, flags, ct.ptr.get()); + if (auto error = create_lv2_shm(ipc_key != SYS_MMAPPER_NO_SHM_KEY, ipc_key, size, flags & SYS_MEMORY_PAGE_SIZE_64K ? 0x10000 : 0x100000, flags, ct.ptr.get())) + { + return error; + } + *mem_id = idm::last_id(); + return CELL_OK; +} + +error_code sys_mmapper_allocate_shared_memory_ext(ppu_thread& ppu, u64 ipc_key, u32 size, u32 flags, vm::ptr entries, s32 entry_count, vm::ptr mem_id) +{ + vm::temporary_unlock(ppu); + + sys_mmapper.todo("sys_mmapper_allocate_shared_memory_ext(ipc_key=0x%x, size=0x%x, flags=0x%x, entries=*0x%x, entry_count=0x%x, mem_id=*0x%x)", ipc_key, size, flags, entries, entry_count, mem_id); + + if (size == 0) + { + return CELL_EALIGN; + } + + switch (flags & SYS_MEMORY_PAGE_SIZE_MASK) + { + case SYS_MEMORY_PAGE_SIZE_1M: + case 0: + { + if (size % 0x100000) + { + return CELL_EALIGN; + } + + break; + } + case SYS_MEMORY_PAGE_SIZE_64K: + { + if (size % 0x10000) + { + return CELL_EALIGN; + } + + break; + } + default: + { + return CELL_EINVAL; + } + } + + if (flags & ~SYS_MEMORY_PAGE_SIZE_MASK) + { + return CELL_EINVAL; + } + + if (entry_count <= 0 || entry_count > 0x10) + { + return CELL_EINVAL; + } + + if constexpr (bool to_perm_check = false; true) + { + for (s32 i = 0; i < entry_count; i++) + { + const u64 type = entries[i].type; + + // The whole structure contents are unknown + sys_mmapper.todo("sys_mmapper_allocate_shared_memory_ext(): entry type = 0x%llx", type); + + switch (type) + { + case 0: + case 1: + case 3: + { + break; + } + case 5: + { + to_perm_check = true; + break; + } + default: + { + return CELL_EPERM; + } + } + } + + if (to_perm_check) + { + if (flags != SYS_MEMORY_PAGE_SIZE_64K || !g_ps3_process_info.debug_or_root()) + { + return CELL_EPERM; + } + } + } + + // Get "default" memory container + const auto dct = g_fxo->get(); + + if (!dct->take(size)) + { + return CELL_ENOMEM; + } + + if (auto error = create_lv2_shm(true, ipc_key, size, flags & SYS_MEMORY_PAGE_SIZE_64K ? 0x10000 : 0x100000, flags, dct)) + { + return error; + } + + *mem_id = idm::last_id(); + return CELL_OK; +} + +error_code sys_mmapper_allocate_shared_memory_from_container_ext(ppu_thread& ppu, u64 ipc_key, u32 size, u64 flags, u32 cid, vm::ptr entries, s32 entry_count, vm::ptr mem_id) +{ + vm::temporary_unlock(ppu); + + sys_mmapper.todo("sys_mmapper_allocate_shared_memory_from_container_ext(ipc_key=0x%x, size=0x%x, flags=0x%x, cid=0x%x, entries=*0x%x, entry_count=0x%x, mem_id=*0x%x)", ipc_key, size, flags, cid, entries, + entry_count, mem_id); + + switch (flags & SYS_MEMORY_PAGE_SIZE_MASK) + { + case SYS_MEMORY_PAGE_SIZE_1M: + case 0: + { + if (size % 0x100000) + { + return CELL_EALIGN; + } + + break; + } + case SYS_MEMORY_PAGE_SIZE_64K: + { + if (size % 0x10000) + { + return CELL_EALIGN; + } + + break; + } + default: + { + return CELL_EINVAL; + } + } + + if (flags & ~SYS_MEMORY_PAGE_SIZE_MASK) + { + return CELL_EINVAL; + } + + if (entry_count <= 0 || entry_count > 0x10) + { + return CELL_EINVAL; + } + + if constexpr (bool to_perm_check = false; true) + { + for (s32 i = 0; i < entry_count; i++) + { + const u64 type = entries[i].type; + + sys_mmapper.todo("sys_mmapper_allocate_shared_memory_from_container_ext(): entry type = 0x%llx", type); + + switch (type) + { + case 0: + case 1: + case 3: + { + break; + } + case 5: + { + to_perm_check = true; + break; + } + default: + { + return CELL_EPERM; + } + } + } + + if (to_perm_check) + { + if (flags != SYS_MEMORY_PAGE_SIZE_64K || !g_ps3_process_info.debug_or_root()) + { + return CELL_EPERM; + } + } + } + + const auto ct = idm::get(cid, [&](lv2_memory_container& ct) -> CellError + { + // Try to get "physical memory" + if (!ct.take(size)) + { + return CELL_ENOMEM; + } + + return {}; + }); + + if (!ct) + { + return CELL_ESRCH; + } + + if (ct.ret) + { + return ct.ret; + } + + if (auto error = create_lv2_shm(true, ipc_key, size, flags & SYS_MEMORY_PAGE_SIZE_64K ? 0x10000 : 0x100000, flags, ct.ptr.get())) + { + return error; + } + + *mem_id = idm::last_id(); return CELL_OK; } diff --git a/rpcs3/Emu/Cell/lv2/sys_mmapper.h b/rpcs3/Emu/Cell/lv2/sys_mmapper.h index b1c929e80d..85579c25b5 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mmapper.h +++ b/rpcs3/Emu/Cell/lv2/sys_mmapper.h @@ -28,6 +28,11 @@ enum : u64 SYS_MEMORY_PAGE_FAULT_EVENT_KEY = 0xfffe000000000000ULL, }; +enum : u64 +{ + SYS_MMAPPER_NO_SHM_KEY = 0xffff000000000000ull, // Unofficial name +}; + enum : u64 { SYS_MEMORY_PAGE_FAULT_CAUSE_NON_MAPPED = 0x2ULL, @@ -59,6 +64,15 @@ struct page_fault_event_entries cond_variable cond; }; +struct mmapper_unk_entry_struct0 +{ + be_t a; // 0x0 + be_t b; // 0x4 + be_t c; // 0x8 + be_t d; // 0xc + be_t type; // 0x10 +}; + // Aux class ppu_thread; @@ -67,8 +81,10 @@ error_code mmapper_thread_recover_page_fault(u32 id); // SysCalls error_code sys_mmapper_allocate_address(ppu_thread&, u64 size, u64 flags, u64 alignment, vm::ptr alloc_addr); error_code sys_mmapper_allocate_fixed_address(ppu_thread&); -error_code sys_mmapper_allocate_shared_memory(ppu_thread&, u64 unk, u32 size, u64 flags, vm::ptr mem_id); -error_code sys_mmapper_allocate_shared_memory_from_container(ppu_thread&, u64 unk, u32 size, u32 cid, u64 flags, vm::ptr mem_id); +error_code sys_mmapper_allocate_shared_memory(ppu_thread&, u64 ipc_key, u32 size, u64 flags, vm::ptr mem_id); +error_code sys_mmapper_allocate_shared_memory_from_container(ppu_thread&, u64 ipc_key, u32 size, u32 cid, u64 flags, vm::ptr mem_id); +error_code sys_mmapper_allocate_shared_memory_ext(ppu_thread&, u64 ipc_key, u32 size, u32 flags, vm::ptr src, s32 count, vm::ptr mem_id); +error_code sys_mmapper_allocate_shared_memory_from_container_ext(ppu_thread&, u64 ipc_key, u32 size, u64 flags, u32 mc_id, vm::ptr entries, s32 entry_count, vm::ptr mem_id); error_code sys_mmapper_change_address_access_right(ppu_thread&, u32 addr, u64 flags); error_code sys_mmapper_free_address(ppu_thread&, u32 addr); error_code sys_mmapper_free_shared_memory(ppu_thread&, u32 mem_id); diff --git a/rpcs3/Emu/Cell/lv2/sys_sync.h b/rpcs3/Emu/Cell/lv2/sys_sync.h index 16c9fff20c..281ae8a06c 100644 --- a/rpcs3/Emu/Cell/lv2/sys_sync.h +++ b/rpcs3/Emu/Cell/lv2/sys_sync.h @@ -171,13 +171,13 @@ public: static void cleanup(); template - static error_code create(u32 pshared, u64 ipc_key, s32 flags, F&& make) + static error_code create(u32 pshared, u64 ipc_key, s32 flags, F&& make, bool key_not_zero = true) { switch (pshared) { case SYS_SYNC_PROCESS_SHARED: { - if (ipc_key == 0) + if (key_not_zero && ipc_key == 0) { return CELL_EINVAL; }