static 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: // HACK: This fixes Crash Tag Team Racing. // Should only wait 1200 cycles though according to Unknown's testing, // and with that it's still broken. So it's not this, unfortunately. // Leaving it in for the 0.9.8 release anyway. hleEatCycles(500000); DEBUG_LOG(HLE, "sceKernelVolatileMemLock(%i, %08x, %08x) - success", type, paddr, psize); break; case SCE_KERNEL_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; }
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; }
int sceKernelVolatileMemTryLock(int type, u32 paddr, u32 psize) { u32 error = __KernelVolatileMemLock(type, paddr, psize); switch (error) { case 0: DEBUG_LOG(HLE, "sceKernelVolatileMemTryLock(%i, %08x, %08x) - success", type, paddr, psize); break; case ERROR_POWER_VMEM_IN_USE: ERROR_LOG(HLE, "sceKernelVolatileMemTryLock(%i, %08x, %08x) - already locked!", type, paddr, psize); break; default: ERROR_LOG_REPORT(HLE, "%08x=sceKernelVolatileMemTryLock(%i, %08x, %08x) - error", type, paddr, psize, error); break; } return error; }
int sceKernelVolatileMemUnlock(int type) { if (type != 0) { ERROR_LOG_REPORT(HLE, "sceKernelVolatileMemUnlock(%i) - invalid mode", type); return SCE_KERNEL_ERROR_INVALID_MODE; } if (volatileMemLocked) { volatileMemLocked = false; // Wake someone, always fifo. bool wokeThreads = false; u32 error; while (!volatileWaitingThreads.empty() && !volatileMemLocked) { VolatileWaitingThread waitInfo = volatileWaitingThreads.front(); volatileWaitingThreads.erase(volatileWaitingThreads.begin()); int waitID = __KernelGetWaitID(waitInfo.threadID, WAITTYPE_VMEM, error); // If they were force-released, just skip. if (waitID == 1 && __KernelVolatileMemLock(0, waitInfo.addrPtr, waitInfo.sizePtr) == 0) { __KernelResumeThreadFromWait(waitInfo.threadID, 0); wokeThreads = true; } } if (wokeThreads) { INFO_LOG(HLE, "sceKernelVolatileMemUnlock(%i) handed over to another thread", type); hleReSchedule("volatile mem unlocked"); } else { DEBUG_LOG(HLE, "sceKernelVolatileMemUnlock(%i)", type); } } else { ERROR_LOG_REPORT(HLE, "sceKernelVolatileMemUnlock(%i) FAILED - not locked", type); // I guess it must use a sema. return SCE_KERNEL_ERROR_SEMA_OVF; } return 0; }
static int sceKernelVolatileMemTryLock(int type, u32 paddr, u32 psize) { u32 error = __KernelVolatileMemLock(type, paddr, psize); switch (error) { case 0: // HACK: This fixes Crash Tag Team Racing. // Should only wait 1200 cycles though according to Unknown's testing, // and with that it's still broken. So it's not this, unfortunately. // Leaving it in for the 0.9.8 release anyway. hleEatCycles(500000); DEBUG_LOG(HLE, "sceKernelVolatileMemTryLock(%i, %08x, %08x) - success", type, paddr, psize); break; case SCE_KERNEL_ERROR_POWER_VMEM_IN_USE: ERROR_LOG(HLE, "sceKernelVolatileMemTryLock(%i, %08x, %08x) - already locked!", type, paddr, psize); break; default: ERROR_LOG_REPORT(HLE, "%08x=sceKernelVolatileMemTryLock(%i, %08x, %08x) - error", type, paddr, psize, error); break; } return error; }