//165 s32 sys_spu_thread_get_exit_status(u32 id, mem32_t status) { sc_spu.Warning("sys_spu_thread_get_exit_status(id=%d, status_addr=0x%x)", id, status.GetAddr()); if (!status.IsGood()) { return CELL_EFAULT; } CPUThread* thr = Emu.GetCPU().GetThread(id); if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) { return CELL_ESRCH; } u32 res; if (!(*(SPUThread*)thr).SPU.Out_MBox.Pop(res) || !thr->IsStopped()) { return CELL_ESTAT; } status = res; return CELL_OK; }
int sys_spu_thread_connect_event(u32 id, u32 eq, u32 et, u8 spup) { sc_spu.Warning("sys_spu_thread_connect_event(id=0x%x,eq=0x%x,et=0x%x,spup=0x%x)", id, eq, et, spup); EventQueue* equeue; if(!sys_event.CheckId(eq, equeue)) { return CELL_ESRCH; } if(spup > 63) { return CELL_EINVAL; } CPUThread* thr = Emu.GetCPU().GetThread(id); if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) { return CELL_ESRCH; } for(int j=0; j<equeue->pos; ++j) { if(!equeue->ports[j]->thread) { equeue->ports[j]->thread = thr; return CELL_OK; } } return CELL_EISCONN; }
s32 sys_spu_thread_bind_queue(u32 id, u32 eq_id, u32 spuq_num) { sc_spu.Warning("sys_spu_thread_bind_queue(id=%d, equeue_id=%d, spuq_num=0x%x)", id, eq_id, spuq_num); EventQueue* eq; if (!Emu.GetIdManager().GetIDData(eq_id, eq)) { return CELL_ESRCH; } if (eq->type != SYS_SPU_QUEUE) { return CELL_EINVAL; } CPUThread* thr = Emu.GetCPU().GetThread(id); if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) { return CELL_ESRCH; } if (!(*(SPUThread*)thr).SPUQs.RegisterKey(eq, FIX_SPUQ(spuq_num))) { return CELL_EBUSY; } return CELL_OK; }
//181 s32 sys_spu_thread_write_ls(u32 id, u32 address, u64 value, u32 type) { sc_spu.Log("sys_spu_thread_write_ls(id=%d, address=0x%x, value=0x%llx, type=0x%x)", id, address, value, type); CPUThread* thr = Emu.GetCPU().GetThread(id); if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) { return CELL_ESRCH; } if (!thr->IsRunning()) { return CELL_ESTAT; } if (!(*(SPUThread*)thr).IsGoodLSA(address) || (address % type)) // +check alignment { return CELL_EINVAL; } switch (type) { case 1: (*(SPUThread*)thr).WriteLS8(address, value); return CELL_OK; case 2: (*(SPUThread*)thr).WriteLS16(address, value); return CELL_OK; case 4: (*(SPUThread*)thr).WriteLS32(address, value); return CELL_OK; case 8: (*(SPUThread*)thr).WriteLS64(address, value); return CELL_OK; default: return CELL_EINVAL; } }
void CPUThreadManager::RemoveThread(const u32 id) { std::lock_guard<std::mutex> lock(m_mtx_thread); for(u32 i=0; i<m_threads.GetCount(); ++i) { if(m_threads[i].m_wait_thread_id == id) { m_threads[i].Wait(false); m_threads[i].m_wait_thread_id = -1; } if(m_threads[i].GetId() != id) continue; CPUThread* thr = &m_threads[i]; #ifndef QT_UI wxGetApp().SendDbgCommand(DID_REMOVE_THREAD, thr); #endif thr->Close(); m_threads.RemoveFAt(i); break; } Emu.GetIdManager().RemoveID(id); Emu.CheckStatus(); }
//184 int sys_spu_thread_write_snr(u32 id, u32 number, u32 value) { CPUThread* thr = Emu.GetCPU().GetThread(id); if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) { return CELL_ESRCH; } if (number > 1) { return CELL_EINVAL; } if ((*(SPUThread*)thr).cfg.value & ((u64)1<<number)) { //logical OR (*(SPUThread*)thr).SPU.SNR[number].PushUncond_OR(value); } else { //overwrite (*(SPUThread*)thr).SPU.SNR[number].PushUncond(value); } return CELL_OK; }
void CPUThreadManager::RemoveThread(const u32 id) { std::lock_guard<std::mutex> lock(m_mtx_thread); CPUThread* thr = nullptr; u32 thread_index = 0; for (u32 i = 0; i < m_threads.size(); ++i) { if (m_threads[i]->m_wait_thread_id == id) { m_threads[i]->Wait(false); m_threads[i]->m_wait_thread_id = -1; } if (m_threads[i]->GetId() != id) continue; thr = m_threads[i]; thread_index = i; } if (thr) { #ifndef QT_UI wxGetApp().SendDbgCommand(DID_REMOVE_THREAD, thr); #endif thr->Close(); m_threads.erase(m_threads.begin() + thread_index); } // Removing the ID should trigger the actual deletion of the thread Emu.GetIdManager().RemoveID(id); Emu.CheckStatus(); }
s32 sys_ppu_thread_get_priority(u64 thread_id, u32 prio_addr) { sys_ppu_thread.Log("sys_ppu_thread_get_priority(thread_id=%lld, prio_addr=0x%x)", thread_id, prio_addr); CPUThread* thr = Emu.GetCPU().GetThread(thread_id); if(!thr) return CELL_ESRCH; Memory.Write32(prio_addr, (s32)thr->GetPrio()); return CELL_OK; }
PPCThread* GetCurrentPPCThread() { CPUThread* thread = GetCurrentCPUThread(); if(!thread || (thread->GetType() != CPU_THREAD_PPU && thread->GetType() != CPU_THREAD_SPU && thread->GetType() != CPU_THREAD_RAW_SPU)) { throw wxString("GetCurrentPPCThread: bad thread"); } return (PPCThread*)thread; }
int sys_ppu_thread_set_priority(u32 thread_id, int prio) { sysPrxForUser.Warning("sys_ppu_thread_set_priority(thread_id=%d, prio=%d)", thread_id, prio); CPUThread* thr = Emu.GetCPU().GetThread(thread_id); if(!thr) return CELL_ESRCH; thr->SetPrio(prio); return CELL_OK; }
s32 sys_ppu_thread_stop(u64 thread_id) { sysPrxForUser->Warning("sys_ppu_thread_stop(thread_id=%lld)", thread_id); CPUThread* thr = Emu.GetCPU().GetThread(thread_id); if(!thr) return CELL_ESRCH; thr->Stop(); return CELL_OK; }
s32 sys_ppu_thread_set_priority(u64 thread_id, s32 prio) { sysPrxForUser->Log("sys_ppu_thread_set_priority(thread_id=%lld, prio=%d)", thread_id, prio); CPUThread* thr = Emu.GetCPU().GetThread(thread_id); if(!thr) return CELL_ESRCH; thr->SetPrio(prio); return CELL_OK; }
s32 sys_ppu_thread_rename(u64 thread_id, vm::ptr<const char> name) { sys_ppu_thread.Log("sys_ppu_thread_rename(thread_id=%d, name_addr=0x%x('%s'))", thread_id, name.addr(), name.get_ptr()); CPUThread* thr = Emu.GetCPU().GetThread(thread_id); if (!thr) { return CELL_ESRCH; } thr->SetThreadName(name.get_ptr()); return CELL_OK; }
s32 sys_ppu_thread_restart(u64 thread_id) { sys_ppu_thread.Warning("sys_ppu_thread_restart(thread_id=%lld)", thread_id); CPUThread* thr = Emu.GetCPU().GetThread(thread_id); if(!thr) return CELL_ESRCH; thr->Stop(); thr->Run(); return CELL_OK; }
int sys_ppu_thread_restart(u32 thread_id) { sysPrxForUser.Warning("sys_ppu_thread_restart(thread_id=%d)", thread_id); CPUThread* thr = Emu.GetCPU().GetThread(thread_id); if(!thr) return CELL_ESRCH; thr->Stop(); thr->Run(); return CELL_OK; }
s32 sys_ppu_thread_get_priority(u64 thread_id, u32 prio_addr) { sysPrxForUser->Log("sys_ppu_thread_get_priority(thread_id=%lld, prio_addr=0x%x)", thread_id, prio_addr); CPUThread* thr = Emu.GetCPU().GetThread(thread_id); if(!thr) return CELL_ESRCH; if(!Memory.IsGoodAddr(prio_addr)) return CELL_EFAULT; Memory.Write32(prio_addr, thr->GetPrio()); return CELL_OK; }
s32 sys_ppu_thread_detach(u64 thread_id) { sysPrxForUser->Error("sys_ppu_thread_detach(thread_id=%lld)", thread_id); CPUThread* thr = Emu.GetCPU().GetThread(thread_id); if(!thr) return CELL_ESRCH; if(!thr->IsJoinable()) return CELL_EINVAL; thr->SetJoinable(false); return CELL_OK; }
//190 s32 sys_spu_thread_write_spu_mb(u32 id, u32 value) { sc_spu.Log("sys_spu_thread_write_spu_mb(id=%d, value=0x%x)", id, value); CPUThread* thr = Emu.GetCPU().GetThread(id); if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) { return CELL_ESRCH; } (*(SPUThread*)thr).SPU.In_MBox.PushUncond(value); return CELL_OK; }
//188 s32 sys_spu_thread_get_spu_cfg(u32 id, mem64_t value) { sc_spu.Warning("sys_spu_thread_get_spu_cfg(id=%d, value_addr=0x%x)", id, value.GetAddr()); CPUThread* thr = Emu.GetCPU().GetThread(id); if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) { return CELL_ESRCH; } value = (*(SPUThread*)thr).cfg.value; return CELL_OK; }
void _se_translator(unsigned int u, EXCEPTION_POINTERS* pExp) { const u64 addr = (u64)pExp->ExceptionRecord->ExceptionInformation[1] - (u64)Memory.GetBaseAddr(); CPUThread* t = GetCurrentCPUThread(); if (u == EXCEPTION_ACCESS_VIOLATION && addr < 0x100000000 && t) { // TODO: allow recovering from a page fault throw fmt::Format("Access violation: addr = 0x%x (is_alive=%d, last_syscall=0x%llx (%s))", (u32)addr, t->IsAlive() ? 1 : 0, t->m_last_syscall, SysCalls::GetHLEFuncName((u32)t->m_last_syscall).c_str()); } else { // some fatal error (should crash) return; } }
//181 int sys_spu_thread_write_ls(u32 id, u32 address, u64 value, u32 type) { sc_spu.Warning("sys_spu_thread_write_ls(id=0x%x, address=0x%x, value=0x%llx, type=0x%x)", id, address, value, type); CPUThread* thr = Emu.GetCPU().GetThread(id); if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) { return CELL_ESRCH; } (*(SPUThread*)thr).WriteLS64(address, value); return CELL_OK; }
sleep_queue_entry_t::sleep_queue_entry_t(CPUThread& cpu, sleep_queue_t& queue) : m_thread(cpu) , m_queue(queue) { add_entry(); cpu.sleep(); }
s32 sys_spu_thread_connect_event(u32 id, u32 eq_id, u32 et, u8 spup) { sc_spu.Warning("sys_spu_thread_connect_event(id=%d, eq_id=%d, event_type=0x%x, spup=%d)", id, eq_id, et, spup); CPUThread* thr = Emu.GetCPU().GetThread(id); if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) { return CELL_ESRCH; } EventQueue* eq; if (!Emu.GetIdManager().GetIDData(eq_id, eq)) { return CELL_ESRCH; } if (spup > 63) { sc_spu.Error("sys_spu_thread_connect_event: invalid spup (%d)", spup); return CELL_EINVAL; } if (et != SYS_SPU_THREAD_EVENT_USER) { sc_spu.Error("sys_spu_thread_connect_event: unsupported event type (0x%x)", et); return CELL_EINVAL; } // TODO: check if can receive these events SPUThread& spu = *(SPUThread*)thr; EventPort& port = spu.SPUPs[spup]; std::lock_guard<std::mutex> lock(port.m_mutex); if (port.eq) { return CELL_EISCONN; } eq->ports.add(&port); port.eq = eq; return CELL_OK; }
//182 int sys_spu_thread_read_ls(u32 id, u32 address, mem64_t value, u32 type) { sc_spu.Log("sys_spu_thread_read_ls(id=%d, address=0x%x, value_addr=0x%x, type=0x%x)", id, address, value.GetAddr(), type); CPUThread* thr = Emu.GetCPU().GetThread(id); if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) { return CELL_ESRCH; } if (!thr->IsRunning()) { return CELL_ESTAT; } if(!value.IsGood()) { return CELL_EFAULT; } if (!(*(SPUThread*)thr).IsGoodLSA(address) || (address % type)) // +check alignment { return CELL_EINVAL; } switch (type) { case 1: value = (*(SPUThread*)thr).ReadLS8(address); return CELL_OK; case 2: value = (*(SPUThread*)thr).ReadLS16(address); return CELL_OK; case 4: value = (*(SPUThread*)thr).ReadLS32(address); return CELL_OK; case 8: value = (*(SPUThread*)thr).ReadLS64(address); return CELL_OK; default: return CELL_EINVAL; } }
s32 sys_spu_thread_unbind_queue(u32 id, u32 spuq_num) { sc_spu.Warning("sys_spu_thread_unbind_queue(id=0x%x, spuq_num=0x%x)", id, spuq_num); CPUThread* thr = Emu.GetCPU().GetThread(id); if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) { return CELL_ESRCH; } if (!(*(SPUThread*)thr).SPUQs.UnregisterKey(FIX_SPUQ(spuq_num))) { return CELL_ESRCH; // may be CELL_EINVAL } return CELL_OK; }
//190 int sys_spu_thread_write_spu_mb(u32 id, u32 value) { sc_spu.Warning("sys_spu_thread_write_spu_mb(id=0x%x, value=0x%x)", id, value); CPUThread* thr = Emu.GetCPU().GetThread(id); if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) { return CELL_ESRCH; } if(!(*(SPUThread*)thr).SPU.In_MBox.Push(value)) { ConLog.Warning("sys_spu_thread_write_spu_mb(id=0x%x, value=0x%x): used all mbox items."); return CELL_EBUSY; //? } return CELL_OK; }
//184 s32 sys_spu_thread_write_snr(u32 id, u32 number, u32 value) { sc_spu.Log("sys_spu_thread_write_snr(id=%d, number=%d, value=0x%x)", id, number, value); CPUThread* thr = Emu.GetCPU().GetThread(id); if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) { return CELL_ESRCH; } if (number > 1) { return CELL_EINVAL; } (*(SPUThread*)thr).WriteSNR(number, value); return CELL_OK; }
s32 sys_ppu_thread_join(u64 thread_id, mem64_t vptr) { sysPrxForUser->Warning("sys_ppu_thread_join(thread_id=%lld, vptr_addr=0x%x)", thread_id, vptr.GetAddr()); CPUThread* thr = Emu.GetCPU().GetThread(thread_id); if(!thr) return CELL_ESRCH; while (thr->IsAlive()) { if (Emu.IsStopped()) { LOG_WARNING(PPU, "sys_ppu_thread_join(%d) aborted", thread_id); return CELL_OK; } std::this_thread::sleep_for(std::chrono::milliseconds(1)); } vptr = thr->GetExitStatus(); return CELL_OK; }
s32 sys_ppu_thread_join(u64 thread_id, vm::ptr<be_t<u64>> vptr) { sys_ppu_thread.Warning("sys_ppu_thread_join(thread_id=%lld, vptr_addr=0x%x)", thread_id, vptr.addr()); CPUThread* thr = Emu.GetCPU().GetThread(thread_id); if(!thr) return CELL_ESRCH; while (thr->IsAlive()) { if (Emu.IsStopped()) { sys_ppu_thread.Warning("sys_ppu_thread_join(%d) aborted", thread_id); return CELL_OK; } std::this_thread::sleep_for(std::chrono::milliseconds(1)); } *vptr = thr->GetExitStatus(); return CELL_OK; }
//187 s32 sys_spu_thread_set_spu_cfg(u32 id, u64 value) { sc_spu.Warning("sys_spu_thread_set_spu_cfg(id=%d, value=0x%x)", id, value); CPUThread* thr = Emu.GetCPU().GetThread(id); if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) { return CELL_ESRCH; } if (value > 3) { return CELL_EINVAL; } (*(SPUThread*)thr).cfg.value = value; return CELL_OK; }