diff --git a/rpcs3/Emu/Cell/lv2/sys_memory.cpp b/rpcs3/Emu/Cell/lv2/sys_memory.cpp index fb8c5b51ac..6110d7d4d5 100644 --- a/rpcs3/Emu/Cell/lv2/sys_memory.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_memory.cpp @@ -5,6 +5,7 @@ #include "Emu/CPU/CPUThread.h" #include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/SPUThread.h" +#include "Emu/Cell/PPUThread.h" #include "Emu/IdManager.h" #include "util/asm.hpp" @@ -249,17 +250,37 @@ error_code sys_memory_free(cpu_thread& cpu, u32 addr) return CELL_OK; } -error_code sys_memory_get_page_attribute(cpu_thread& cpu, u32 addr, vm::ptr attr) +error_code sys_memory_get_page_attribute(ppu_thread& ppu, u32 addr, vm::ptr attr) { - cpu.state += cpu_flag::wait; + ppu.state += cpu_flag::wait; sys_memory.trace("sys_memory_get_page_attribute(addr=0x%x, attr=*0x%x)", addr, attr); - vm::writer_lock rlock; - - if (!vm::check_addr(addr) || addr >= SPU_FAKE_BASE_ADDR) + if ((addr >> 28) == (ppu.stack_addr >> 28)) { - return CELL_EINVAL; + // Stack address: fast path + if (!(addr >= ppu.stack_addr && addr < ppu.stack_addr + ppu.stack_size) && !vm::check_addr(addr)) + { + return { CELL_EINVAL, addr }; + } + + if (!vm::check_addr(attr.addr(), vm::page_readable, attr.size())) + { + return CELL_EFAULT; + } + + attr->attribute = 0x40000ull; // SYS_MEMORY_PROT_READ_WRITE + attr->access_right = SYS_MEMORY_ACCESS_RIGHT_PPU_THR; + attr->page_size = 4096; + attr->pad = 0; // Always write 0 + return CELL_OK; + } + + const auto [ok, vm_flags] = vm::get_addr_flags(addr); + + if (!ok || addr >= SPU_FAKE_BASE_ADDR) + { + return { CELL_EINVAL, addr }; } if (!vm::check_addr(attr.addr(), vm::page_readable, attr.size())) @@ -268,19 +289,20 @@ error_code sys_memory_get_page_attribute(cpu_thread& cpu, u32 addr, vm::ptrattribute = 0x40000ull; // SYS_MEMORY_PROT_READ_WRITE (TODO) - attr->access_right = addr >> 28 == 0xdu ? SYS_MEMORY_ACCESS_RIGHT_PPU_THR : SYS_MEMORY_ACCESS_RIGHT_ANY;// (TODO) + attr->access_right = SYS_MEMORY_ACCESS_RIGHT_ANY; // TODO: Report accurately - if (vm::check_addr(addr, vm::page_1m_size)) + if (vm_flags & vm::page_1m_size) { attr->page_size = 0x100000; } - else if (vm::check_addr(addr, vm::page_64k_size)) + else if (vm_flags & vm::page_64k_size) { attr->page_size = 0x10000; } else { - attr->page_size = 4096; + //attr->page_size = 4096; + fmt::throw_exception("Unreachable"); } attr->pad = 0; // Always write 0 diff --git a/rpcs3/Emu/Cell/lv2/sys_memory.h b/rpcs3/Emu/Cell/lv2/sys_memory.h index c2ca046bcc..2702c45ac2 100644 --- a/rpcs3/Emu/Cell/lv2/sys_memory.h +++ b/rpcs3/Emu/Cell/lv2/sys_memory.h @@ -4,6 +4,7 @@ #include "Emu/Cell/ErrorCodes.h" class cpu_thread; +class ppu_thread; enum lv2_mem_container_id : u32 { @@ -131,7 +132,7 @@ struct sys_memory_user_memory_stat_t error_code sys_memory_allocate(cpu_thread& cpu, u64 size, u64 flags, vm::ptr alloc_addr); error_code sys_memory_allocate_from_container(cpu_thread& cpu, u64 size, u32 cid, u64 flags, vm::ptr alloc_addr); error_code sys_memory_free(cpu_thread& cpu, u32 start_addr); -error_code sys_memory_get_page_attribute(cpu_thread& cpu, u32 addr, vm::ptr attr); +error_code sys_memory_get_page_attribute(ppu_thread& cpu, u32 addr, vm::ptr attr); error_code sys_memory_get_user_memory_size(cpu_thread& cpu, vm::ptr mem_info); error_code sys_memory_get_user_memory_stat(cpu_thread& cpu, vm::ptr mem_stat); error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr cid, u64 size); diff --git a/rpcs3/Emu/Memory/vm.h b/rpcs3/Emu/Memory/vm.h index 3c39d0aa4a..09d2d15421 100644 --- a/rpcs3/Emu/Memory/vm.h +++ b/rpcs3/Emu/Memory/vm.h @@ -81,7 +81,7 @@ namespace vm bool check_addr(u32 addr, u8 flags, u32 size); template - bool check_addr(u32 addr, u8 flags = page_readable) + inline bool check_addr(u32 addr, u8 flags = page_readable) { extern std::array g_pages; @@ -94,6 +94,16 @@ namespace vm return !(~g_pages[addr / 4096] & (flags | page_allocated)); } + // Like check_addr but should only be used in lock-free context with care + inline std::pair get_addr_flags(u32 addr) noexcept + { + extern std::array g_pages; + + const u8 flags = g_pages[addr / 4096].load(); + + return std::make_pair(!!(flags & page_allocated), flags); + } + // Read string in a safe manner (page aware) (bool true = if null-termination) bool read_string(u32 addr, u32 max_size, std::string& out_string, bool check_pages = true) noexcept;