diff --git a/rpcs3/Emu/Cell/lv2/sys_vm.cpp b/rpcs3/Emu/Cell/lv2/sys_vm.cpp index baad00b6f939..381596e0cc95 100644 --- a/rpcs3/Emu/Cell/lv2/sys_vm.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_vm.cpp @@ -1,8 +1,23 @@ -#include "stdafx.h" +#include "stdafx.h" #include "sys_vm.h" -#include "sys_memory.h" +sys_vm_t::sys_vm_t(const std::shared_ptr& area, const std::shared_ptr& ct, u32 psize) + : ct(ct) + , area(area) + , psize(psize) +{ + // Write ID + sys_vm_t::g_ids[area->addr >> 28].release(idm::last_id()); +} +sys_vm_t::~sys_vm_t() +{ + // Free ID + sys_vm_t::g_ids[area->addr >> 28].release(0); + + // Return memory + ct->used -= psize; +} LOG_CHANNEL(sys_vm); @@ -15,22 +30,32 @@ 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; + } + // Look for unmapped space if (const auto area = vm::find_map(0x10000000, 0x10000000, 2 | (flag & SYS_MEMORY_PAGE_SIZE_MASK))) { // Alloc all memory (shall not fail) verify(HERE), area->alloc(vsize); + idm::make(area, ct, psize); + // Write a pointer for the allocated memory *addr = area->addr; return CELL_OK; } + ct->used -= psize; return CELL_ENOMEM; } @@ -46,11 +71,17 @@ error_code sys_vm_unmap(u32 addr) { sys_vm.warning("sys_vm_unmap(addr=0x%x)", addr); - if (!vm::unmap(addr)) + const u32 id = sys_vm_t::find_id(addr); + const auto block = idm::get(id); + std::lock_guard lock(block->mutex); + + if (!block || block->area->addr != addr) { return {CELL_EINVAL, addr}; } + block->area.reset(); + idm::remove(id); return CELL_OK; } @@ -58,6 +89,26 @@ 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 = idm::get(sys_vm_t::find_id(addr)); + + if (!block || block->area->addr != addr) + { + return CELL_EINVAL; + } + + std::lock_guard lock(block->mutex); + + if (!block->ct->take(size)) + { + return CELL_ENOMEM; + } + + block->psize += size; return CELL_OK; } @@ -65,6 +116,27 @@ 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 = idm::get(sys_vm_t::find_id(addr)); + + if (!block || block->area->addr != addr) + { + return CELL_EINVAL; + } + + std::lock_guard lock(block->mutex); + + if (block->psize < 0x100000 + size) + { + return CELL_EBUSY; + } + + block->psize -= size; + block->ct->used -= size; return CELL_OK; } @@ -72,6 +144,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 = idm::get(sys_vm_t::find_id(addr)); + + if (!block || addr + size > block->area->addr + block->area->size) + { + return CELL_EINVAL; + } + return CELL_OK; } @@ -79,6 +163,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 = idm::get(sys_vm_t::find_id(addr)); + + if (!block || addr + size > block->area->addr + block->area->size) + { + return CELL_EINVAL; + } + return CELL_OK; } @@ -86,6 +182,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 = idm::get(sys_vm_t::find_id(addr)); + + if (!block || addr + size > block->area->addr + block->area->size) + { + return CELL_EINVAL; + } + return CELL_OK; } @@ -93,6 +201,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 = idm::get(sys_vm_t::find_id(addr)); + + if (!block || addr + size > block->area->addr + block->area->size) + { + return CELL_EINVAL; + } + return CELL_OK; } @@ -100,6 +220,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 = idm::get(sys_vm_t::find_id(addr)); + + if (!block || addr + size > block->area->addr + block->area->size) + { + return CELL_EINVAL; + } + std::memset(vm::base(addr), 0, size); return CELL_OK; } @@ -108,6 +240,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 = idm::get(sys_vm_t::find_id(addr)); + + if (!block || addr + size > block->area->addr + block->area->size) + { + return CELL_EINVAL; + } + return CELL_OK; } @@ -115,6 +259,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 = idm::get(sys_vm_t::find_id(addr)); + + if (!block || addr + size > block->area->addr + block->area->size) + { + return CELL_EINVAL; + } + return CELL_OK; } @@ -122,6 +278,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 = idm::get(sys_vm_t::find_id(addr)); + + if (!block || addr + size > block->area->addr + block->area->size) + { + return CELL_EINVAL; + } + *result = SYS_VM_STATE_ON_MEMORY; return CELL_OK; @@ -131,13 +294,22 @@ 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 = idm::get(sys_vm_t::find_id(addr)); + + if (!block || block->area->addr != addr) + { + return CELL_EINVAL; + } + 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 = block->psize; stat->pmem_used = 0; stat->timestamp = 0; return CELL_OK; } + +DECLARE(sys_vm_t::g_ids){}; diff --git a/rpcs3/Emu/Cell/lv2/sys_vm.h b/rpcs3/Emu/Cell/lv2/sys_vm.h index bfee507e8db8..33a665807888 100644 --- a/rpcs3/Emu/Cell/lv2/sys_vm.h +++ b/rpcs3/Emu/Cell/lv2/sys_vm.h @@ -1,8 +1,11 @@ -#pragma once +#pragma once #include "Emu/Memory/vm.h" #include "Emu/Cell/ErrorCodes.h" #include "Emu/IdManager.h" +#include "sys_memory.h" + +#include enum : u64 { @@ -25,6 +28,29 @@ struct sys_vm_statistics_t be_t timestamp; }; +// Block info +struct sys_vm_t +{ + static const u32 id_base = 0x1; + static const u32 id_step = 0x1; + static const u32 id_count = 16; + + const std::shared_ptr ct; + std::shared_ptr area; + u32 psize; + shared_mutex mutex; + + sys_vm_t(const std::shared_ptr& area, const std::shared_ptr& ct, u32 psize); + ~sys_vm_t(); + + static std::array, id_count> g_ids; + + static u32 find_id(u32 addr) + { + return g_ids[addr >> 28].load(); + } +}; + // 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..30acdc5c0231 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -953,7 +953,7 @@ namespace vm auto block = _find_map(size, align, flags); - g_locations.emplace_back(block); + if (block) g_locations.emplace_back(block); return block; }