diff --git a/rpcs3/Emu/Cell/lv2/sys_memory.cpp b/rpcs3/Emu/Cell/lv2/sys_memory.cpp index 419be54210..70d1b1f31c 100644 --- a/rpcs3/Emu/Cell/lv2/sys_memory.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_memory.cpp @@ -123,7 +123,7 @@ error_code sys_memory_free(u32 addr) verify(HERE), area; // Deallocate memory - u32 cid, size = area->dealloc(addr, &cid); + u32 cid, size = area->dealloc(addr, nullptr, &cid); if (!size) { diff --git a/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp b/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp index aa12dd5dc5..fbefd4570b 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp @@ -255,7 +255,7 @@ error_code sys_mmapper_map_shared_memory(u32 addr, u32 mem_id, u64 flags) return CELL_OK; } - if (!area->falloc(addr, mem->size)) + if (!area->falloc(addr, mem->size, mem->data.data())) { mem->addr = 0; return CELL_EBUSY; @@ -289,7 +289,7 @@ error_code sys_mmapper_search_and_map(u32 start_addr, u32 mem_id, u64 flags, vm: return CELL_OK; } - const u32 addr = area->alloc(mem->size, mem->align); + const u32 addr = area->alloc(mem->size, mem->align, mem->data.data()); if (!addr) { @@ -328,7 +328,7 @@ error_code sys_mmapper_unmap_shared_memory(u32 addr, vm::ptr mem_id) return CELL_EINVAL; } - verify(HERE), area->dealloc(addr), mem->addr.exchange(0) == addr; + verify(HERE), area->dealloc(addr, mem->data.data()), mem->addr.exchange(0) == addr; return CELL_OK; } diff --git a/rpcs3/Emu/Cell/lv2/sys_mmapper.h b/rpcs3/Emu/Cell/lv2/sys_mmapper.h index 88749178b4..b626fe1484 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mmapper.h +++ b/rpcs3/Emu/Cell/lv2/sys_mmapper.h @@ -14,12 +14,15 @@ struct lv2_memory : lv2_obj atomic_t addr{}; // Actual mapping address + std::vector data; + lv2_memory(u32 size, u32 align, u64 flags, const std::shared_ptr& ct) : size(size) , align(align) , flags(flags) , ct(ct) { + data.resize(size); } }; diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index e1717118c7..75040eb842 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -491,7 +491,7 @@ namespace vm fmt::throw_exception("Invalid memory location (%u)" HERE, (uint)location); } - return block->alloc(size, align, sup); + return block->alloc(size, align, nullptr, sup); } u32 falloc(u32 addr, u32 size, memory_location_t location, u32 sup) @@ -503,7 +503,7 @@ namespace vm fmt::throw_exception("Invalid memory location (%u, addr=0x%x)" HERE, (uint)location, addr); } - return block->falloc(addr, size, sup); + return block->falloc(addr, size, nullptr, sup); } u32 dealloc(u32 addr, memory_location_t location, u32* sup_out) @@ -515,7 +515,7 @@ namespace vm fmt::throw_exception("Invalid memory location (%u, addr=0x%x)" HERE, (uint)location, addr); } - return block->dealloc(addr, sup_out); + return block->dealloc(addr, nullptr, sup_out); } void dealloc_verbose_nothrow(u32 addr, memory_location_t location) noexcept @@ -576,12 +576,12 @@ namespace vm } } - u32 block_t::alloc(u32 size, u32 align, u32 sup) + u32 block_t::alloc(const u32 orig_size, u32 align, const uchar* data, u32 sup) { writer_lock lock; // Align to minimal page size - size = ::align(size, 4096); + const u32 size = ::align(orig_size, 4096); // Check alignment (it's page allocation, so passing small values there is just silly) if (align < 4096 || align != (0x80000000u >> cntlz32(align, true))) @@ -611,6 +611,11 @@ namespace vm { if (try_alloc(addr, size, pflags, sup)) { + if (data) + { + std::memcpy(vm::base(addr), data, orig_size); + } + return addr; } } @@ -618,19 +623,21 @@ namespace vm return 0; } - u32 block_t::falloc(u32 addr, u32 size, u32 sup) + u32 block_t::falloc(u32 addr, const u32 orig_size, const uchar* data, u32 sup) { writer_lock lock; // align to minimal page size - size = ::align(size, 4096); + const u32 size = ::align(orig_size, 4096); // return if addr or size is invalid if (!size || size > this->size || addr < this->addr || addr + size - 1 > this->addr + this->size - 1) { return 0; } + u8 pflags = page_readable | page_writable; + if ((flags & SYS_MEMORY_PAGE_SIZE_1M) == SYS_MEMORY_PAGE_SIZE_1M) { pflags |= page_1m_size; @@ -645,10 +652,15 @@ namespace vm return 0; } + if (data) + { + std::memcpy(vm::base(addr), data, orig_size); + } + return addr; } - u32 block_t::dealloc(u32 addr, u32* sup_out) + u32 block_t::dealloc(u32 addr, uchar* data_out, u32* sup_out) { writer_lock lock; @@ -662,6 +674,11 @@ namespace vm // Remove entry m_map.erase(found); + if (data_out) + { + std::memcpy(data_out, vm::base(addr), size); + } + // Unmap "real" memory pages _page_unmap(addr, size); diff --git a/rpcs3/Emu/Memory/vm.h b/rpcs3/Emu/Memory/vm.h index eadfcc2bcd..0c50f1d9e0 100644 --- a/rpcs3/Emu/Memory/vm.h +++ b/rpcs3/Emu/Memory/vm.h @@ -148,13 +148,13 @@ namespace vm const u64 flags; // Currently unused // Search and map memory (don't pass alignment smaller than 4096) - u32 alloc(u32 size, u32 align = 4096, u32 sup = 0); + u32 alloc(u32 size, u32 align = 4096, const uchar* data = nullptr, u32 sup = 0); // Try to map memory at fixed location - u32 falloc(u32 addr, u32 size, u32 sup = 0); + u32 falloc(u32 addr, u32 size, const uchar* data = nullptr, u32 sup = 0); // Unmap memory at specified location previously returned by alloc(), return size - u32 dealloc(u32 addr, u32* sup_out = nullptr); + u32 dealloc(u32 addr, uchar* data_out = nullptr, u32* sup_out = nullptr); // Internal u32 imp_used(const vm::writer_lock&);