From 9b82596b87a61c44ced12e8aa3f166b00d407461 Mon Sep 17 00:00:00 2001 From: eladash Date: Wed, 27 Mar 2019 19:15:21 +0200 Subject: [PATCH] Implement sys_vm_append/return_memory --- rpcs3/Emu/Cell/lv2/sys_vm.cpp | 178 +++++++++++++++++++++++++++++++++- rpcs3/Emu/Cell/lv2/sys_vm.h | 11 +++ rpcs3/Emu/Memory/vm.cpp | 19 ++-- rpcs3/Emu/Memory/vm.h | 7 +- 4 files changed, 200 insertions(+), 15 deletions(-) diff --git a/rpcs3/Emu/Cell/lv2/sys_vm.cpp b/rpcs3/Emu/Cell/lv2/sys_vm.cpp index baad00b6f939..f05de1e64cef 100644 --- a/rpcs3/Emu/Cell/lv2/sys_vm.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_vm.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "sys_vm.h" #include "sys_memory.h" @@ -15,13 +15,22 @@ error_code sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy return CELL_EINVAL; } - if (cid != SYS_MEMORY_CONTAINER_ID_INVALID && !idm::check(cid)) + auto ct = cid == SYS_MEMORY_CONTAINER_ID_INVALID ? fxm::get() : idm::get(cid); + + if (!ct) { return CELL_ESRCH; } + if (!ct->take(psize)) + { + return CELL_ENOMEM; + } + + auto info = new sys_vm_block_t(ct.get(), psize); + // Look for unmapped space - if (const auto area = vm::find_map(0x10000000, 0x10000000, 2 | (flag & SYS_MEMORY_PAGE_SIZE_MASK))) + if (auto area = vm::find_map(0x10000000, 0x10000000, 2 | (flag & SYS_MEMORY_PAGE_SIZE_MASK), info)) { // Alloc all memory (shall not fail) verify(HERE), area->alloc(vsize); @@ -31,6 +40,8 @@ error_code sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy return CELL_OK; } + ct->used -= psize; + delete info; return CELL_ENOMEM; } @@ -58,6 +69,29 @@ error_code sys_vm_append_memory(u32 addr, u32 size) { sys_vm.warning("sys_vm_append_memory(addr=0x%x, size=0x%x)", addr, size); + if (!size || size % 0x100000) + { + return CELL_EINVAL; + } + + const auto block = vm::get(vm::any, addr); + + if (!block || !block->sup) + { + return CELL_EINVAL; + } + + auto info = static_cast(block->sup); + + std::lock_guard lock(info->mutex); + + if (!info->ct->take(size)) + { + return CELL_ENOMEM; + } + + info->psize += size; + return CELL_OK; } @@ -65,6 +99,31 @@ error_code sys_vm_return_memory(u32 addr, u32 size) { sys_vm.warning("sys_vm_return_memory(addr=0x%x, size=0x%x)", addr, size); + if (!size || size % 0x100000) + { + return CELL_EINVAL; + } + + const auto block = vm::get(vm::any, addr); + + if (!block || !block->sup) + { + return CELL_EINVAL; + } + + auto info = static_cast(block->sup); + + std::lock_guard lock(info->mutex); + + if (info->psize < 0x100000 + size) + { + return CELL_EBUSY; + } + + info->psize -= size; + + info->ct->used -= size; + return CELL_OK; } @@ -72,6 +131,18 @@ error_code sys_vm_lock(u32 addr, u32 size) { sys_vm.warning("sys_vm_lock(addr=0x%x, size=0x%x)", addr, size); + if (!size) + { + return CELL_EINVAL; + } + + const auto block = vm::get(vm::any, addr); + + if (!block || !block->sup) + { + return CELL_EINVAL; + } + return CELL_OK; } @@ -79,6 +150,18 @@ error_code sys_vm_unlock(u32 addr, u32 size) { sys_vm.warning("sys_vm_unlock(addr=0x%x, size=0x%x)", addr, size); + if (!size) + { + return CELL_EINVAL; + } + + const auto block = vm::get(vm::any, addr); + + if (!block || !block->sup) + { + return CELL_EINVAL; + } + return CELL_OK; } @@ -86,6 +169,18 @@ error_code sys_vm_touch(u32 addr, u32 size) { sys_vm.warning("sys_vm_touch(addr=0x%x, size=0x%x)", addr, size); + if (!size) + { + return CELL_EINVAL; + } + + const auto block = vm::get(vm::any, addr); + + if (!block || !block->sup) + { + return CELL_EINVAL; + } + return CELL_OK; } @@ -93,6 +188,18 @@ error_code sys_vm_flush(u32 addr, u32 size) { sys_vm.warning("sys_vm_flush(addr=0x%x, size=0x%x)", addr, size); + if (!size) + { + return CELL_EINVAL; + } + + const auto block = vm::get(vm::any, addr); + + if (!block || !block->sup) + { + return CELL_EINVAL; + } + return CELL_OK; } @@ -100,6 +207,18 @@ error_code sys_vm_invalidate(u32 addr, u32 size) { sys_vm.warning("sys_vm_invalidate(addr=0x%x, size=0x%x)", addr, size); + if (!size) + { + return CELL_EINVAL; + } + + const auto block = vm::get(vm::any, addr); + + if (!block || !block->sup) + { + return CELL_EINVAL; + } + std::memset(vm::base(addr), 0, size); return CELL_OK; } @@ -108,6 +227,18 @@ error_code sys_vm_store(u32 addr, u32 size) { sys_vm.warning("sys_vm_store(addr=0x%x, size=0x%x)", addr, size); + if (!size) + { + return CELL_EINVAL; + } + + const auto block = vm::get(vm::any, addr); + + if (!block || !block->sup) + { + return CELL_EINVAL; + } + return CELL_OK; } @@ -115,6 +246,18 @@ error_code sys_vm_sync(u32 addr, u32 size) { sys_vm.warning("sys_vm_sync(addr=0x%x, size=0x%x)", addr, size); + if (!size) + { + return CELL_EINVAL; + } + + const auto block = vm::get(vm::any, addr); + + if (!block || !block->sup) + { + return CELL_EINVAL; + } + return CELL_OK; } @@ -122,6 +265,13 @@ error_code sys_vm_test(u32 addr, u32 size, vm::ptr result) { sys_vm.warning("sys_vm_test(addr=0x%x, size=0x%x, result=*0x%x)", addr, size, result); + const auto block = vm::get(vm::any, addr); + + if (!block || !block->sup || !block->addr != addr) + { + return CELL_EINVAL; + } + *result = SYS_VM_STATE_ON_MEMORY; return CELL_OK; @@ -131,13 +281,33 @@ error_code sys_vm_get_statistics(u32 addr, vm::ptr stat) { sys_vm.warning("sys_vm_get_statistics(addr=0x%x, stat=*0x%x)", addr, stat); + const auto block = vm::get(vm::any, addr); + + if (!block || !block->sup || block->addr != addr) + { + return CELL_EINVAL; + } + + auto info = static_cast(block->sup); + stat->page_fault_ppu = 0; stat->page_fault_spu = 0; stat->page_in = 0; stat->page_out = 0; - stat->pmem_total = 0; + stat->pmem_total = info->psize; stat->pmem_used = 0; stat->timestamp = 0; return CELL_OK; } + +sys_vm_block_t::sys_vm_block_t(lv2_memory_container* ct, u32 psize) + : ct(ct) + , psize(psize) +{ +} + +sys_vm_block_t::~sys_vm_block_t() +{ + ct->used -= psize; +} diff --git a/rpcs3/Emu/Cell/lv2/sys_vm.h b/rpcs3/Emu/Cell/lv2/sys_vm.h index bfee507e8db8..1023e8095adc 100644 --- a/rpcs3/Emu/Cell/lv2/sys_vm.h +++ b/rpcs3/Emu/Cell/lv2/sys_vm.h @@ -3,6 +3,7 @@ #include "Emu/Memory/vm.h" #include "Emu/Cell/ErrorCodes.h" #include "Emu/IdManager.h" +#include "sys_memory.h" enum : u64 { @@ -25,6 +26,16 @@ struct sys_vm_statistics_t be_t timestamp; }; +struct sys_vm_block_t +{ + lv2_memory_container* ct; + u32 psize; + shared_mutex mutex; + + sys_vm_block_t(lv2_memory_container* ct, u32 psize); + ~sys_vm_block_t(); +}; + // SysCalls error_code sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr); error_code sys_vm_memory_map_different(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr); diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 38fc254e9fc0..3e5e30e1e5ab 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -601,10 +601,11 @@ namespace vm return true; } - block_t::block_t(u32 addr, u32 size, u64 flags) + block_t::block_t(u32 addr, u32 size, u64 flags, void* sup) : addr(addr) , size(size) , flags(flags) + , sup(sup) { // Allocate compressed reservation info area (avoid SPU MMIO area) if (addr != 0xe0000000) @@ -663,6 +664,8 @@ namespace vm m_common->unmap_critical(vm::get_super_ptr(addr)); } } + + delete sup; } u32 block_t::alloc(const u32 orig_size, u32 align, const std::shared_ptr* src, u64 flags) @@ -890,20 +893,20 @@ namespace vm return true; } - static std::shared_ptr _find_map(u32 size, u32 align, u64 flags) + static std::shared_ptr _find_map(u32 size, u32 align, u64 flags, void* sup = nullptr) { for (u32 addr = ::align(0x20000000, align); addr < 0xC0000000; addr += align) { if (_test_map(addr, size)) { - return std::make_shared(addr, size, flags); + return std::make_shared(addr, size, flags, sup); } } return nullptr; } - std::shared_ptr map(u32 addr, u32 size, u64 flags) + std::shared_ptr map(u32 addr, u32 size, u64 flags, void* sup) { vm::writer_lock lock(0); @@ -925,14 +928,14 @@ namespace vm } } - auto block = std::make_shared(addr, size, flags); + auto block = std::make_shared(addr, size, flags, sup); g_locations.emplace_back(block); return block; } - std::shared_ptr find_map(u32 orig_size, u32 align, u64 flags) + std::shared_ptr find_map(u32 orig_size, u32 align, u64 flags, void* sup) { vm::writer_lock lock(0); @@ -951,9 +954,9 @@ namespace vm return nullptr; } - auto block = _find_map(size, align, flags); + auto block = _find_map(size, align, flags, sup); - g_locations.emplace_back(block); + if (block) g_locations.emplace_back(block); return block; } diff --git a/rpcs3/Emu/Memory/vm.h b/rpcs3/Emu/Memory/vm.h index b5914b3283d4..49eaa72ef872 100644 --- a/rpcs3/Emu/Memory/vm.h +++ b/rpcs3/Emu/Memory/vm.h @@ -151,7 +151,7 @@ namespace vm bool try_alloc(u32 addr, u8 flags, u32 size, std::shared_ptr&&); public: - block_t(u32 addr, u32 size, u64 flags = 0); + block_t(u32 addr, u32 size, u64 flags = 0, void* sup = nullptr); ~block_t(); @@ -159,6 +159,7 @@ namespace vm const u32 addr; // Start address const u32 size; // Total size const u64 flags; // Currently unused + void* sup; // Additional info (TODO: Store info about type of data) // Search and map memory (min alignment is 0x10000) u32 alloc(u32 size, u32 align = 0x10000, const std::shared_ptr* = nullptr, u64 flags = 0); @@ -180,10 +181,10 @@ namespace vm }; // Create new memory block with specified parameters and return it - std::shared_ptr map(u32 addr, u32 size, u64 flags = 0); + std::shared_ptr map(u32 addr, u32 size, u64 flags = 0, void* sup = nullptr); // Create new memory block with at arbitrary position with specified alignment - std::shared_ptr find_map(u32 size, u32 align, u64 flags = 0); + std::shared_ptr find_map(u32 size, u32 align, u64 flags = 0, void* sup = nullptr); // Delete existing memory block with specified start address, return it std::shared_ptr unmap(u32 addr, bool must_be_empty = false);