Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions rpcs3/Emu/Cell/Modules/cellCamera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1139,8 +1139,10 @@ error_code cellCameraGetBufferInfo(s32 dev_num, vm::ptr<CellCameraInfo> info)
return CELL_OK;
}

error_code cellCameraGetBufferInfoEx(s32 dev_num, vm::ptr<CellCameraInfoEx> info)
error_code cellCameraGetBufferInfoEx(ppu_thread& ppu, s32 dev_num, vm::ptr<CellCameraInfoEx> info)
{
ppu.state += cpu_flag::wait;

cellCamera.notice("cellCameraGetBufferInfoEx(dev_num=%d, info=0x%x)", dev_num, info);

// calls cellCameraGetBufferInfo
Expand All @@ -1151,10 +1153,16 @@ error_code cellCameraGetBufferInfoEx(s32 dev_num, vm::ptr<CellCameraInfoEx> info
}

auto& g_camera = g_fxo->get<camera_thread>();
std::lock_guard lock(g_camera.mutex);

*info = g_camera.info;
CellCameraInfoEx info_out;

{
std::lock_guard lock(g_camera.mutex);

info_out = g_camera.info;
}

*info = info_out;
return CELL_OK;
}

Expand Down
12 changes: 9 additions & 3 deletions rpcs3/Emu/Cell/Modules/cellGem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2308,8 +2308,10 @@ error_code cellGemConvertVideoFinish(ppu_thread& ppu)
return CELL_OK;
}

error_code cellGemConvertVideoStart(vm::cptr<void> video_frame)
error_code cellGemConvertVideoStart(ppu_thread& ppu, vm::cptr<void> video_frame)
{
ppu.state += cpu_flag::wait;

cellGem.warning("cellGemConvertVideoStart(video_frame=*0x%x)", video_frame);

auto& gem = g_fxo->get<gem_config>();
Expand Down Expand Up @@ -2461,6 +2463,8 @@ error_code cellGemEnableMagnetometer2(u32 gem_num, u32 enable)

error_code cellGemEnd(ppu_thread& ppu)
{
ppu.state += cpu_flag::wait;

cellGem.warning("cellGemEnd()");

auto& gem = g_fxo->get<gem_config>();
Expand Down Expand Up @@ -3265,15 +3269,15 @@ error_code cellGemPrepareCamera(s32 max_exposure, f32 image_quality)

extern error_code cellCameraGetAttribute(s32 dev_num, s32 attrib, vm::ptr<u32> arg1, vm::ptr<u32> arg2);
extern error_code cellCameraSetAttribute(s32 dev_num, s32 attrib, u32 arg1, u32 arg2);
extern error_code cellCameraGetBufferInfoEx(s32 dev_num, vm::ptr<CellCameraInfoEx> info);
extern error_code cellCameraGetBufferInfoEx(ppu_thread&, s32 dev_num, vm::ptr<CellCameraInfoEx> info);

vm::var<CellCameraInfoEx> info = vm::make_var<CellCameraInfoEx>({});
vm::var<u32> arg1 = vm::make_var<u32>({});
vm::var<u32> arg2 = vm::make_var<u32>({});

cellCameraGetAttribute(0, 0x3e6, arg1, arg2);
cellCameraSetAttribute(0, 0x3e6, 0x3e, *arg2 | 0x80);
cellCameraGetBufferInfoEx(0, info);
cellCameraGetBufferInfoEx(*cpu_thread::get_current<ppu_thread>(), 0, info);

if (info->width == 640)
{
Expand Down Expand Up @@ -3605,6 +3609,8 @@ error_code cellGemTrackHues(vm::cptr<u32> req_hues, vm::ptr<u32> res_hues)

error_code cellGemUpdateFinish(ppu_thread& ppu)
{
ppu.state += cpu_flag::wait;

cellGem.warning("cellGemUpdateFinish()");

auto& gem = g_fxo->get<gem_config>();
Expand Down
23 changes: 19 additions & 4 deletions rpcs3/Emu/Cell/SPUThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4125,7 +4125,7 @@ bool spu_thread::process_mfc_cmd()
if (raddr != addr)
{
// Last check for event before we replace the reservation with a new one
if (reservation_check(raddr, rdata))
if (~ch_events.load().events & SPU_EVENT_LR && reservation_check(raddr, rdata, addr))
{
set_events(SPU_EVENT_LR);
}
Expand Down Expand Up @@ -4821,7 +4821,7 @@ bool spu_thread::process_mfc_cmd()
ch_mfc_cmd.cmd, ch_mfc_cmd.lsa, ch_mfc_cmd.eal, ch_mfc_cmd.tag, ch_mfc_cmd.size);
}

bool spu_thread::reservation_check(u32 addr, const decltype(rdata)& data) const
bool spu_thread::reservation_check(u32 addr, const decltype(rdata)& data, u32 current_eal) const
{
if (!addr)
{
Expand All @@ -4840,9 +4840,24 @@ bool spu_thread::reservation_check(u32 addr, const decltype(rdata)& data) const
return !cmp_rdata(data, *vm::get_super_ptr<decltype(rdata)>(addr));
}

if ((addr >> 20) == (current_eal >> 20))
{
if (vm::check_addr(addr, vm::page_1m_size))
{
// Same random-access-memory page as the current MFC command, assume allocated
return !cmp_rdata(data, vm::_ref<decltype(rdata)>(addr));
}

if ((addr >> 16) == (current_eal >> 16) && vm::check_addr(addr, vm::page_64k_size))
{
// Same random-access-memory page as the current MFC command, assume allocated
return !cmp_rdata(data, vm::_ref<decltype(rdata)>(addr));
}
}

// Ensure data is allocated (HACK: would raise LR event if not)
// Set range_lock first optimistically
range_lock->store(u64{128} << 32 | addr);
range_lock->store(u64{128} << 32 | addr | vm::range_readable);

u64 lock_val = *std::prev(std::end(vm::g_range_lock_set));
u64 old_lock = 0;
Expand Down Expand Up @@ -4923,7 +4938,7 @@ bool spu_thread::reservation_check(u32 addr, u32 hash, atomic_t<u64, 64>* range_

// Ensure data is allocated (HACK: would raise LR event if not)
// Set range_lock first optimistically
range_lock->store(u64{128} << 32 | addr);
range_lock->store(u64{128} << 32 | addr | vm::range_readable);

u64 lock_val = *std::prev(std::end(vm::g_range_lock_set));
u64 old_lock = 0;
Expand Down
3 changes: 2 additions & 1 deletion rpcs3/Emu/Cell/SPUThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,8 @@ class spu_thread : public cpu_thread

// Returns true if reservation existed but was just discovered to be lost
// It is safe to use on any address, even if not directly accessed by SPU (so it's slower)
bool reservation_check(u32 addr, const decltype(rdata)& data) const;
// Optionally pass a known allocated address for internal optimization (the current Effective-Address of the MFC command)
bool reservation_check(u32 addr, const decltype(rdata)& data, u32 current_eal = 0) const;
static bool reservation_check(u32 addr, u32 hash, atomic_t<u64, 64>* range_lock);
usz register_cache_line_waiter(u32 addr);
void deregister_cache_line_waiter(usz index);
Expand Down
40 changes: 31 additions & 9 deletions rpcs3/Emu/Cell/lv2/sys_memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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<sys_page_attr_t> attr)
error_code sys_memory_get_page_attribute(ppu_thread& ppu, u32 addr, vm::ptr<sys_page_attr_t> 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 ((addr >> 28) == (ppu.stack_addr >> 28))
{
// 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;
}

if (!vm::check_addr(addr) || addr >= SPU_FAKE_BASE_ADDR)
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;
return { CELL_EINVAL, addr };
}

if (!vm::check_addr(attr.addr(), vm::page_readable, attr.size()))
Expand All @@ -268,19 +289,20 @@ error_code sys_memory_get_page_attribute(cpu_thread& cpu, u32 addr, vm::ptr<sys_
}

attr->attribute = 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
Expand Down
3 changes: 2 additions & 1 deletion rpcs3/Emu/Cell/lv2/sys_memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "Emu/Cell/ErrorCodes.h"

class cpu_thread;
class ppu_thread;

enum lv2_mem_container_id : u32
{
Expand Down Expand Up @@ -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<u32> alloc_addr);
error_code sys_memory_allocate_from_container(cpu_thread& cpu, u64 size, u32 cid, u64 flags, vm::ptr<u32> 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<sys_page_attr_t> attr);
error_code sys_memory_get_page_attribute(ppu_thread& cpu, u32 addr, vm::ptr<sys_page_attr_t> attr);
error_code sys_memory_get_user_memory_size(cpu_thread& cpu, vm::ptr<sys_memory_info_t> mem_info);
error_code sys_memory_get_user_memory_stat(cpu_thread& cpu, vm::ptr<sys_memory_user_memory_stat_t> mem_stat);
error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr<u32> cid, u64 size);
Expand Down
7 changes: 7 additions & 0 deletions rpcs3/Emu/Memory/vm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,13 @@ namespace vm
{
to_clear = for_all_range_locks(to_clear & ~get_range_lock_bits(true), [&](u64 addr2, u32 size2)
{
constexpr u32 range_size_loc = vm::range_pos - 32;

if ((size2 >> range_size_loc) == (vm::range_readable >> vm::range_pos))
{
return 0;
}

// Split and check every 64K page separately
for (u64 hi = addr2 >> 16, max = (addr2 + size2 - 1) >> 16; hi <= max; hi++)
{
Expand Down
12 changes: 11 additions & 1 deletion rpcs3/Emu/Memory/vm.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ namespace vm
bool check_addr(u32 addr, u8 flags, u32 size);

template <u32 Size = 1>
bool check_addr(u32 addr, u8 flags = page_readable)
inline bool check_addr(u32 addr, u8 flags = page_readable)
{
extern std::array<memory_page, 0x100000000 / 4096> g_pages;

Expand All @@ -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<bool, u8> get_addr_flags(u32 addr) noexcept
{
extern std::array<memory_page, 0x100000000 / 4096> 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;

Expand Down
18 changes: 16 additions & 2 deletions rpcs3/rpcs3qt/kernel_explorer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -651,15 +651,29 @@ void kernel_explorer::update()
return fmt::format(" (%.1fs)", wait_time);
};

std::vector<std::pair<s32, std::string>> ppu_threads;

idm::select<named_thread<ppu_thread>>([&](u32 id, ppu_thread& ppu)
{
const auto func = ppu.last_function;
const ppu_thread_status status = lv2_obj::ppu_state(&ppu, false, false).first;

add_leaf(find_node(root, additional_nodes::ppu_threads), QString::fromStdString(fmt::format(u8"PPU 0x%07x: “%s”, PRIO: %d, Joiner: %s, Status: %s, State: %s, %s func: “%s”%s", id, *ppu.ppu_tname.load(), ppu.prio.load().prio, ppu.joiner.load(), status, ppu.state.load()
, ppu.ack_suspend ? "After" : (ppu.current_function ? "In" : "Last"), func ? func : "", get_wait_time_str(ppu.start_time))));
const s32 prio = ppu.prio.load().prio;
std::string prio_text = fmt::format("%4d", prio);
prio_text = fmt::replace_all(prio_text, " ", " ");

ppu_threads.emplace_back(prio, fmt::format(u8"PPU 0x%07x: PRIO: %s, “%s”Joiner: %s, Status: %s, State: %s, %s func: “%s”%s", id, prio_text, *ppu.ppu_tname.load(), ppu.joiner.load(), status, ppu.state.load()
, ppu.ack_suspend ? "After" : (ppu.current_function ? "In" : "Last"), func ? func : "", get_wait_time_str(ppu.start_time)));
}, idm::unlocked);

// Sort by priority
std::stable_sort(ppu_threads.begin(), ppu_threads.end(), FN(x.first < y.first));

for (const auto& [prio, text] : ppu_threads)
{
add_leaf(find_node(root, additional_nodes::ppu_threads), QString::fromStdString(text));
}

lock_idm_lv2.reset();

idm::select<named_thread<spu_thread>>([&](u32 /*id*/, spu_thread& spu)
Expand Down
Loading