diff --git a/Utilities/Thread.h b/Utilities/Thread.h index 10aee157c0..fecf418bc6 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -95,7 +95,7 @@ private: atomic_t m_joining{}; // Thread interrupt guard counter - u32 m_guard = 0x80000000; + volatile u32 m_guard = 0x80000000; // Thread internals atomic_t m_data{}; diff --git a/rpcs3/Emu/Cell/PPUFunction.h b/rpcs3/Emu/Cell/PPUFunction.h index 3b60580510..02c24490be 100644 --- a/rpcs3/Emu/Cell/PPUFunction.h +++ b/rpcs3/Emu/Cell/PPUFunction.h @@ -4,12 +4,18 @@ using ppu_function_t = void(*)(PPUThread&); -#define BIND_FUNC(func) static_cast([](PPUThread& ppu){\ +// BIND_FUNC macro "converts" any appropriate HLE function to ppu_function_t, binding it to PPU thread context. +// If function already has type ppu_function_t, it's handled specially and classified as "low-level HLE function". +// 1) Low-level functions are bound directly so they don't save their name to ppu.last_function variable. +// 2) Low-level functions don't install thread_guar, so they are very limited, and may be dangerous. +// If you don't need "low-level function", be sure it's either `void()` or `void(PPUThread& ppu, PPUThread&)` for example. +#define BIND_FUNC(func) (std::is_same::value ? reinterpret_cast(func) : static_cast([](PPUThread& ppu){\ + const thread_guard guard(ppu);\ const auto old_f = ppu.last_function;\ ppu.last_function = #func;\ ppu_func_detail::do_call(ppu, func);\ ppu.last_function = old_f;\ -}) +})) struct ppu_va_args_t { diff --git a/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp b/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp index ec831f61e4..de8acf544e 100644 --- a/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp @@ -156,13 +156,18 @@ s32 _sys_interrupt_thread_disestablish(PPUThread& ppu, u32 ih, vm::ptr r13) return CELL_OK; } -void sys_interrupt_thread_eoi(PPUThread& ppu) +void sys_interrupt_thread_eoi(PPUThread& ppu) // Low-level PPU function example { - sys_interrupt.trace("sys_interrupt_thread_eoi()"); - - // TODO: maybe it should actually unwind the stack of PPU thread? - - ppu.GPR[1] = align(ppu.stack_addr + ppu.stack_size, 0x200) - 0x200; // supercrutch to bypass stack check + // Low-level function body must guard all C++-ish calls and all objects with non-trivial destructors + thread_guard{ppu}, sys_interrupt.trace("sys_interrupt_thread_eoi()"); ppu.state += cpu_state::ret; + + // Throw if this syscall was not called directly by the SC instruction (hack) + if (ppu.LR == 0 || ppu.GPR[11] != 88 || ppu.custom_task) + { + // Low-level function must disable interrupts before throwing (not related to sys_interrupt_*, it's rather coincidence) + ppu->interrupt_disable(); + throw cpu_state::ret; + } }