int sceKernelVolatileMemLock(int type, u32 paddr, u32 psize) { u32 error = 0; // If dispatch is disabled or in an interrupt, don't check, just return an error. // But still write the addr and size (some games require this to work, and it's testably true.) if (!__KernelIsDispatchEnabled()) { error = SCE_KERNEL_ERROR_CAN_NOT_WAIT; } else if (__IsInInterrupt()) { error = SCE_KERNEL_ERROR_ILLEGAL_CONTEXT; } else { error = __KernelVolatileMemLock(type, paddr, psize); } switch (error) { case 0: DEBUG_LOG(HLE, "sceKernelVolatileMemLock(%i, %08x, %08x) - success", type, paddr, psize); break; case ERROR_POWER_VMEM_IN_USE: { WARN_LOG(HLE, "sceKernelVolatileMemLock(%i, %08x, %08x) - already locked, waiting", type, paddr, psize); const VolatileWaitingThread waitInfo = { __KernelGetCurThread(), paddr, psize }; volatileWaitingThreads.push_back(waitInfo); __KernelWaitCurThread(WAITTYPE_VMEM, 1, 0, 0, false, "volatile mem waited"); } break; case SCE_KERNEL_ERROR_CAN_NOT_WAIT: { WARN_LOG(HLE, "sceKernelVolatileMemLock(%i, %08x, %08x): dispatch disabled", type, paddr, psize); Memory::Write_U32(0x08400000, paddr); Memory::Write_U32(0x00400000, psize); } break; case SCE_KERNEL_ERROR_ILLEGAL_CONTEXT: { WARN_LOG(HLE, "sceKernelVolatileMemLock(%i, %08x, %08x): in interrupt", type, paddr, psize); Memory::Write_U32(0x08400000, paddr); Memory::Write_U32(0x00400000, psize); } break; default: ERROR_LOG_REPORT(HLE, "%08x=sceKernelVolatileMemLock(%i, %08x, %08x) - error", type, paddr, psize, error); break; } return error; }
u32 sceDisplayWaitVblankStartMultiCB(int vblanks) { if (vblanks <= 0) { WARN_LOG(SCEDISPLAY, "sceDisplayWaitVblankStartMultiCB(%d): invalid number of vblanks", vblanks); return SCE_KERNEL_ERROR_INVALID_VALUE; } VERBOSE_LOG(SCEDISPLAY,"sceDisplayWaitVblankStartMultiCB(%d)", vblanks); if (!__KernelIsDispatchEnabled()) return SCE_KERNEL_ERROR_CAN_NOT_WAIT; if (__IsInInterrupt()) return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT; vblankWaitingThreads.push_back(WaitVBlankInfo(__KernelGetCurThread(), vblanks)); __KernelWaitCurThread(WAITTYPE_VBLANK, 1, 0, 0, true, "vblank start multi waited"); return 0; }
u32 GPUCommon::DrawSync(int mode) { // FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause. if (g_Config.bSeparateCPUThread) { // FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause. ScheduleEvent(GPU_EVENT_PROCESS_QUEUE); // Sync first, because the CPU is usually faster than the emulated GPU. SyncThread(); } easy_guard guard(listLock); if (mode < 0 || mode > 1) return SCE_KERNEL_ERROR_INVALID_MODE; if (mode == 0) { if (!__KernelIsDispatchEnabled()) { return SCE_KERNEL_ERROR_CAN_NOT_WAIT; } if (__IsInInterrupt()) { return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT; } if (drawCompleteTicks > CoreTiming::GetTicks()) { __GeWaitCurrentThread(WAITTYPE_GEDRAWSYNC, 1, "GeDrawSync"); } else { for (int i = 0; i < DisplayListMaxCount; ++i) { if (dls[i].state == PSP_GE_DL_STATE_COMPLETED) { dls[i].state = PSP_GE_DL_STATE_NONE; } } } return 0; } // If there's no current list, it must be complete. DisplayList *top = NULL; for (auto it = dlQueue.begin(), end = dlQueue.end(); it != end; ++it) { if (dls[*it].state != PSP_GE_DL_STATE_COMPLETED) { top = &dls[*it]; break; } } if (!top || top->state == PSP_GE_DL_STATE_COMPLETED) return PSP_GE_LIST_COMPLETED; if (currentList->pc == currentList->stall) return PSP_GE_LIST_STALLING; return PSP_GE_LIST_DRAWING; }
inline void CallSyscallWithFlags(const HLEFunction *info) { const u32 flags = info->flags; if ((flags & HLE_NOT_DISPATCH_SUSPENDED) && !__KernelIsDispatchEnabled()) { DEBUG_LOG(HLE, "%s: dispatch suspended", info->name); RETURN(SCE_KERNEL_ERROR_CAN_NOT_WAIT); } else if ((flags & HLE_NOT_IN_INTERRUPT) && __IsInInterrupt()) { DEBUG_LOG(HLE, "%s: in interrupt", info->name); RETURN(SCE_KERNEL_ERROR_ILLEGAL_CONTEXT); } else info->func(); if (hleAfterSyscall != HLE_AFTER_NOTHING) hleFinishSyscall(*info); else SetDeadbeefRegs(); }
int __CtrlReadBuffer(u32 ctrlDataPtr, u32 nBufs, bool negative, bool peek) { if (nBufs > NUM_CTRL_BUFFERS) return SCE_KERNEL_ERROR_INVALID_SIZE; if (!peek && !__KernelIsDispatchEnabled()) return SCE_KERNEL_ERROR_CAN_NOT_WAIT; if (!peek && __IsInInterrupt()) return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT; u32 resetRead = ctrlBufRead; u32 availBufs; // Peeks always work, they just go go from now X buffers. if (peek) availBufs = nBufs; else { availBufs = (ctrlBuf - ctrlBufRead + NUM_CTRL_BUFFERS) % NUM_CTRL_BUFFERS; if (availBufs > nBufs) availBufs = nBufs; } ctrlBufRead = (ctrlBuf - availBufs + NUM_CTRL_BUFFERS) % NUM_CTRL_BUFFERS; int done = 0; for (u32 i = 0; i < availBufs; ++i) { done += __CtrlReadSingleBuffer(ctrlDataPtr, negative); ctrlDataPtr += sizeof(_ctrl_data); } if (peek) ctrlBufRead = resetRead; return done; }
static int __KernelValidateReceiveMsgPipe(SceUID uid, u32 receiveBufAddr, u32 receiveSize, int waitMode, u32 resultAddr, bool tryMode = false) { if (receiveSize & 0x80000000) { ERROR_LOG(SCEKERNEL, "__KernelReceiveMsgPipe(%d): illegal size %d", uid, receiveSize); return SCE_KERNEL_ERROR_ILLEGAL_ADDR; } if (receiveSize != 0 && !Memory::IsValidAddress(receiveBufAddr)) { ERROR_LOG(SCEKERNEL, "__KernelReceiveMsgPipe(%d): bad buffer address %08x (should crash?)", uid, receiveBufAddr); return SCE_KERNEL_ERROR_ILLEGAL_ADDR; } if (waitMode != SCE_KERNEL_MPW_ASAP && waitMode != SCE_KERNEL_MPW_FULL) { ERROR_LOG(SCEKERNEL, "__KernelReceiveMsgPipe(%d): invalid wait mode %d", uid, waitMode); return SCE_KERNEL_ERROR_ILLEGAL_MODE; } if (!tryMode) { if (!__KernelIsDispatchEnabled()) { WARN_LOG(SCEKERNEL, "__KernelReceiveMsgPipe(%d): dispatch disabled", uid); return SCE_KERNEL_ERROR_CAN_NOT_WAIT; } if (__IsInInterrupt()) { WARN_LOG(SCEKERNEL, "__KernelReceiveMsgPipe(%d): in interrupt", uid); return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT; } } return 0; }
void save() { insideInterrupt = __IsInInterrupt(); __KernelSaveContext(&savedCpu); }