void __UmdBeginCallback(SceUID threadID, SceUID prevCallbackId) { SceUID pauseKey = prevCallbackId == 0 ? threadID : prevCallbackId; if (HLEKernel::VerifyWait(threadID, WAITTYPE_UMD, 1)) { // This means two callbacks in a row. PSP crashes if the same callback runs inside itself. // TODO: Handle this better? if (umdPausedWaits.find(pauseKey) != umdPausedWaits.end()) return; _dbg_assert_msg_(SCEIO, umdStatTimeoutEvent != -1, "Must have a umd timer"); s64 cyclesLeft = CoreTiming::UnscheduleEvent(umdStatTimeoutEvent, threadID); if (cyclesLeft != 0) umdPausedWaits[pauseKey] = CoreTiming::GetTicks() + cyclesLeft; else umdPausedWaits[pauseKey] = 0; HLEKernel::RemoveWaitingThread(umdWaitingThreads, threadID); DEBUG_LOG(SCEIO, "sceUmdWaitDriveStatCB: Suspending lock wait for callback"); } else WARN_LOG_REPORT(SCEIO, "sceUmdWaitDriveStatCB: beginning callback with bad wait id?"); }
static u32 sceDmacMemcpy(u32 dst, u32 src, u32 size) { if (size == 0) { // Some games seem to do this frequently. DEBUG_LOG(HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i): invalid size", dst, src, size); return SCE_KERNEL_ERROR_INVALID_SIZE; } if (!Memory::IsValidAddress(dst) || !Memory::IsValidAddress(src)) { ERROR_LOG(HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i): invalid address", dst, src, size); return SCE_KERNEL_ERROR_INVALID_POINTER; } if (dst + size >= 0x80000000 || src + size >= 0x80000000 || size >= 0x80000000) { ERROR_LOG(HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i): illegal size", dst, src, size); return SCE_KERNEL_ERROR_PRIV_REQUIRED; } if (dmacMemcpyDeadline > CoreTiming::GetTicks()) { WARN_LOG_REPORT(HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i): overlapping read", dst, src, size); // TODO: Should block, seems like copy doesn't start until previous finishes. // Might matter for overlapping copies. } else { DEBUG_LOG(HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i)", dst, src, size); } return __DmacMemcpy(dst, src, size); }
void PostPutAction::run(MipsCall &call) { SceMpegRingBuffer ringbuffer; Memory::ReadStruct(ringAddr_, &ringbuffer); MpegContext *ctx = getMpegCtx(ringbuffer.mpeg); int packetsAdded = currentMIPS->r[2]; if (ringbuffer.packetsRead == 0 && ctx->mediaengine && packetsAdded > 0) { // init mediaEngine AnalyzeMpeg(ctx->mpegheader, ctx); ctx->mediaengine->loadStream(ctx->mpegheader, 2048, ringbuffer.packets * ringbuffer.packetSize); } if (packetsAdded > 0) { if (packetsAdded > ringbuffer.packetsFree) { WARN_LOG(ME, "sceMpegRingbufferPut clamping packetsAdded old=%i new=%i", packetsAdded, ringbuffer.packetsFree); packetsAdded = ringbuffer.packetsFree; } int actuallyAdded = ctx->mediaengine == NULL ? 8 : ctx->mediaengine->addStreamData(Memory::GetPointer(ringbuffer.data), packetsAdded * 2048) / 2048; if (actuallyAdded != packetsAdded) { WARN_LOG_REPORT(ME, "sceMpegRingbufferPut(): unable to enqueue all added packets, going to overwrite some frames."); } ringbuffer.packetsRead += packetsAdded; ringbuffer.packetsWritten += packetsAdded; ringbuffer.packetsFree -= packetsAdded; } DEBUG_LOG(ME, "packetAdded: %i packetsRead: %i packetsTotal: %i", packetsAdded, ringbuffer.packetsRead, ringbuffer.packets); Memory::WriteStruct(ringAddr_, &ringbuffer); call.setReturnValue(packetsAdded); }
int MetaFileSystem::ChDir(const std::string &dir) { lock_guard guard(lock); // Retain the old path and fail if the arg is 1023 bytes or longer. if (dir.size() >= 1023) return SCE_KERNEL_ERROR_NAMETOOLONG; int curThread = __KernelGetCurThread(); std::string of; MountPoint *mountPoint; if (MapFilePath(dir, of, &mountPoint)) { currentDir[curThread] = mountPoint->prefix + of; return 0; } else { for (size_t i = 0; i < fileSystems.size(); i++) { const std::string &prefix = fileSystems[i].prefix; if (strncasecmp(prefix.c_str(), dir.c_str(), prefix.size()) == 0) { // The PSP is completely happy with invalid current dirs as long as they have a valid device. WARN_LOG(HLE, "ChDir failed to map path \"%s\", saving as current directory anyway", dir.c_str()); currentDir[curThread] = dir; return 0; } } WARN_LOG_REPORT(HLE, "ChDir failed to map device for \"%s\", failing", dir.c_str()); return SCE_KERNEL_ERROR_NODEV; } }
void __KernelMutexBeginCallback(SceUID threadID, SceUID prevCallbackId) { SceUID pauseKey = prevCallbackId == 0 ? threadID : prevCallbackId; u32 error; SceUID mutexID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error); u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); Mutex *mutex = mutexID == 0 ? NULL : kernelObjects.Get<Mutex>(mutexID, error); if (mutex) { // This means two callbacks in a row. PSP crashes if the same callback runs inside itself. // TODO: Handle this better? if (mutex->pausedWaitTimeouts.find(pauseKey) != mutex->pausedWaitTimeouts.end()) return; if (timeoutPtr != 0 && mutexWaitTimer != -1) { s64 cyclesLeft = CoreTiming::UnscheduleEvent(mutexWaitTimer, threadID); mutex->pausedWaitTimeouts[pauseKey] = CoreTiming::GetTicks() + cyclesLeft; } else mutex->pausedWaitTimeouts[pauseKey] = 0; // TODO: Hmm, what about priority/fifo order? Does it lose its place in line? mutex->waitingThreads.erase(std::remove(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID), mutex->waitingThreads.end()); DEBUG_LOG(HLE, "sceKernelLockMutexCB: Suspending lock wait for callback"); } else WARN_LOG_REPORT(HLE, "sceKernelLockMutexCB: beginning callback with bad wait id?"); }
void __DisplayVblankBeginCallback(SceUID threadID, SceUID prevCallbackId) { SceUID pauseKey = prevCallbackId == 0 ? threadID : prevCallbackId; // This means two callbacks in a row. PSP crashes if the same callback waits inside itself (may need more testing.) // TODO: Handle this better? if (vblankPausedWaits.find(pauseKey) != vblankPausedWaits.end()) { return; } WaitVBlankInfo waitData(0); for (size_t i = 0; i < vblankWaitingThreads.size(); i++) { WaitVBlankInfo *t = &vblankWaitingThreads[i]; if (t->threadID == threadID) { waitData = *t; vblankWaitingThreads.erase(vblankWaitingThreads.begin() + i); break; } } if (waitData.threadID != threadID) { WARN_LOG_REPORT(SCEDISPLAY, "sceDisplayWaitVblankCB: could not find waiting thread info."); return; } vblankPausedWaits[pauseKey] = vCount + waitData.vcountUnblock; DEBUG_LOG(SCEDISPLAY, "sceDisplayWaitVblankCB: Suspending vblank wait for callback"); }
u32 sceKernelRegisterSubIntrHandler(u32 intrNumber, u32 subIntrNumber, u32 handler, u32 handlerArg) { if (intrNumber >= PSP_NUMBER_INTERRUPTS) { ERROR_LOG_REPORT(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): invalid interrupt", intrNumber, subIntrNumber, handler, handlerArg); return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE; } if (subIntrNumber >= PSP_NUMBER_SUBINTERRUPTS) { ERROR_LOG_REPORT(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): invalid subinterrupt", intrNumber, subIntrNumber, handler, handlerArg); return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE; } u32 error; SubIntrHandler *subIntrHandler = __RegisterSubIntrHandler(intrNumber, subIntrNumber, handler, handlerArg, error); if (subIntrHandler) { if (handler == 0) { WARN_LOG_REPORT(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): ignored NULL handler", intrNumber, subIntrNumber, handler, handlerArg); } else { DEBUG_LOG(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x)", intrNumber, subIntrNumber, handler, handlerArg); } } else if (error = SCE_KERNEL_ERROR_FOUND_HANDLER) { ERROR_LOG_REPORT(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): duplicate handler", intrNumber, subIntrNumber, handler, handlerArg); } else { ERROR_LOG_REPORT(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): error %08x", intrNumber, subIntrNumber, handler, handlerArg, error); } return error; }
static u32 sceHeapAllocHeapMemoryWithOption(u32 heapAddr, u32 memSize, u32 paramsPtr) { Heap *heap = getHeap(heapAddr); u32 grain = 4; if (!heap) { ERROR_LOG(HLE, "sceHeapAllocHeapMemoryWithOption(%08x, %08x, %08x): invalid heap", heapAddr, memSize, paramsPtr); return 0; } // 0 is ignored. if (paramsPtr != 0) { u32 size = Memory::Read_U32(paramsPtr); if (size < 8) { ERROR_LOG(HLE, "sceHeapAllocHeapMemoryWithOption(%08x, %08x, %08x): invalid param size", heapAddr, memSize, paramsPtr); return 0; } if (size > 8) { WARN_LOG_REPORT(HLE, "sceHeapAllocHeapMemoryWithOption(): unexpected param size %d", size); } grain = Memory::Read_U32(paramsPtr + 4); } DEBUG_LOG(HLE,"sceHeapAllocHeapMemoryWithOption(%08x, %08x, %08x)", heapAddr, memSize, paramsPtr); // There's 8 bytes at the end of every block, reserved. memSize += 8; u32 addr = heap->alloc.AllocAligned(memSize, grain, grain, true); return addr; }
int sceHeapCreateHeap(const char* name, u32 heapSize, int attr, u32 paramsPtr) { if (paramsPtr != 0) { u32 size = Memory::Read_U32(paramsPtr); WARN_LOG_REPORT(SCEKERNEL, "sceHeapCreateHeap(): unsupported options parameter, size = %d", size); } if (name == NULL) { WARN_LOG(SCEKERNEL,"sceHeapCreateHeap(): name is NULL"); return 0; } int allocSize = (heapSize + 3) & ~3; Heap *heap = new Heap; heap->size = allocSize; heap->fromtop = (attr & PSP_HEAP_ATTR_HIGHMEM) != 0; u32 addr = userMemory.Alloc(heap->size, heap->fromtop, "Heap"); if (addr == (u32)-1) { ERROR_LOG(SCEKERNEL, "sceHeapCreateHeap(): Failed to allocate %i bytes memory", allocSize); delete heap; return 0; } heap->address = addr; heap->alloc.Init(heap->address,heap->size); heapList[heap->address] = heap; DEBUG_LOG(HLE,"sceHeapCreateHeap(%s, %08x, %08x, %08x)", name, heapSize, attr, paramsPtr); return heap->address; }
int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr) { if (!name) { WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateMutex(): invalid name", SCE_KERNEL_ERROR_ERROR); return SCE_KERNEL_ERROR_ERROR; } if (attr & ~0xBFF) { WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateMutex(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr); return SCE_KERNEL_ERROR_ILLEGAL_ATTR; } if (initialCount < 0) return SCE_KERNEL_ERROR_ILLEGAL_COUNT; if ((attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && initialCount > 1) return SCE_KERNEL_ERROR_ILLEGAL_COUNT; Mutex *mutex = new Mutex(); SceUID id = kernelObjects.Create(mutex); mutex->nm.size = sizeof(mutex->nm); strncpy(mutex->nm.name, name, KERNELOBJECT_MAX_NAME_LENGTH); mutex->nm.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0; mutex->nm.attr = attr; mutex->nm.initialCount = initialCount; if (initialCount == 0) { mutex->nm.lockLevel = 0; mutex->nm.lockThread = -1; } else __KernelMutexAcquireLock(mutex, initialCount); DEBUG_LOG(HLE, "%i=sceKernelCreateMutex(%s, %08x, %d, %08x)", id, name, attr, initialCount, optionsPtr); if (optionsPtr != 0) { u32 size = Memory::Read_U32(optionsPtr); if (size != 0) WARN_LOG_REPORT(HLE, "sceKernelCreateMutex(%s) unsupported options parameter, size = %d", name, size); } if ((attr & ~PSP_MUTEX_ATTR_KNOWN) != 0) WARN_LOG_REPORT(HLE, "sceKernelCreateMutex(%s) unsupported attr parameter: %08x", name, attr); return id; }
void __KernelSemaBeginCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitBeginCallback<Semaphore, WAITTYPE_SEMA, SceUID>(threadID, prevCallbackId, semaWaitTimer); if (result == HLEKernel::WAIT_CB_SUCCESS) DEBUG_LOG(SCEKERNEL, "sceKernelWaitSemaCB: Suspending sema wait for callback") else WARN_LOG_REPORT(SCEKERNEL, "sceKernelWaitSemaCB: beginning callback with bad wait id?"); }
void __AudioSetOutputFrequency(int freq) { if (freq != 44100) { WARN_LOG_REPORT(SCEAUDIO, "Switching audio frequency to %i", freq); } else { DEBUG_LOG(SCEAUDIO, "Switching audio frequency to %i", freq); } mixFrequency = freq; }
void __KernelLwMutexBeginCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitBeginCallback<LwMutex, WAITTYPE_LWMUTEX, SceUID>(threadID, prevCallbackId, lwMutexWaitTimer); if (result == HLEKernel::WAIT_CB_SUCCESS) DEBUG_LOG(SCEKERNEL, "sceKernelLockLwMutexCB: Suspending lock wait for callback"); else WARN_LOG_REPORT(SCEKERNEL, "sceKernelLockLwMutexCB: beginning callback with bad wait id?"); }
int ISOFileSystem::Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) { EntryMap::iterator iter = entries.find(handle); if (iter == entries.end()) { ERROR_LOG(FILESYS, "Ioctl on a bad file handle"); return SCE_KERNEL_ERROR_BADF; } OpenFileEntry &e = iter->second; switch (cmd) { // Get ISO9660 volume descriptor (from open ISO9660 file.) case 0x01020001: if (e.isBlockSectorMode) { ERROR_LOG(FILESYS, "Unsupported read volume descriptor command on a umd block device"); return SCE_KERNEL_ERROR_ERRNO_FUNCTION_NOT_SUPPORTED; } if (!Memory::IsValidAddress(outdataPtr) || outlen < 0x800) { WARN_LOG_REPORT(FILESYS, "sceIoIoctl: Invalid out pointer while reading ISO9660 volume descriptor"); return SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT; } INFO_LOG(SCEIO, "sceIoIoctl: reading ISO9660 volume descriptor read"); blockDevice->ReadBlock(16, Memory::GetPointer(outdataPtr)); return 0; // Get ISO9660 path table (from open ISO9660 file.) case 0x01020002: if (e.isBlockSectorMode) { ERROR_LOG(FILESYS, "Unsupported read path table command on a umd block device"); return SCE_KERNEL_ERROR_ERRNO_FUNCTION_NOT_SUPPORTED; } VolDescriptor desc; blockDevice->ReadBlock(16, (u8 *)&desc); if (outlen < (u32)desc.pathTableLengthLE) { return SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT; } else { int block = (u16)desc.firstLETableSectorLE; u32 size = (u32)desc.pathTableLengthLE; u8 *out = Memory::GetPointer(outdataPtr); int blocks = size / blockDevice->GetBlockSize(); blockDevice->ReadBlocks(block, blocks, out); size -= blocks * blockDevice->GetBlockSize(); out += blocks * blockDevice->GetBlockSize(); // The remaining (or, usually, only) partial sector. if (size > 0) { u8 temp[2048]; blockDevice->ReadBlock(block, temp); memcpy(out, temp, size); } return 0; } } return SCE_KERNEL_ERROR_ERRNO_FUNCTION_NOT_SUPPORTED; }
void PSPSaveDialog::StartIOThread() { if (ioThread) { WARN_LOG_REPORT(SCEUTILITY, "Starting a save io thread when one already pending, uh oh."); JoinIOThread(); } ioThreadStatus = SAVEIO_PENDING; ioThread = new std::thread(&DoExecuteIOAction, this); }
int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr) { DEBUG_LOG(HLE, "sceKernelPollEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr); if ((wait & ~PSP_EVENT_WAITKNOWN) != 0) { WARN_LOG_REPORT(HLE, "sceKernelPollEventFlag(%i) invalid mode parameter: %08x", id, wait); return SCE_KERNEL_ERROR_ILLEGAL_MODE; } // Poll seems to also fail when CLEAR and CLEARALL are used together, but not wait. if ((wait & PSP_EVENT_WAITCLEAR) != 0 && (wait & PSP_EVENT_WAITCLEARALL) != 0) { WARN_LOG_REPORT(HLE, "sceKernelPollEventFlag(%i) invalid mode parameter: %08x", id, wait); return SCE_KERNEL_ERROR_ILLEGAL_MODE; } // Can't wait on 0, it never matches. if (bits == 0) return SCE_KERNEL_ERROR_EVF_ILPAT; u32 error; EventFlag *e = kernelObjects.Get<EventFlag>(id, error); if (e) { if (!__KernelEventFlagMatches(&e->nef.currentPattern, bits, wait, outBitsPtr)) { if (Memory::IsValidAddress(outBitsPtr)) Memory::Write_U32(e->nef.currentPattern, outBitsPtr); if (e->waitingThreads.size() > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0) return SCE_KERNEL_ERROR_EVF_MULTI; // No match - return that, this is polling, not waiting. return SCE_KERNEL_ERROR_EVF_COND; } else { return 0; } } else { return error; } }
void __KernelMbxBeginCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitBeginCallback<Mbx, WAITTYPE_SEMA, MbxWaitingThread>(threadID, prevCallbackId, mbxWaitTimer); if (result == HLEKernel::WAIT_CB_SUCCESS) DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMbxCB: Suspending mbx wait for callback"); else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA) ERROR_LOG_REPORT(SCEKERNEL, "sceKernelReceiveMbxCB: wait not found to pause for callback"); else WARN_LOG_REPORT(SCEKERNEL, "sceKernelReceiveMbxCB: beginning callback with bad wait id?"); }
void __KernelEventFlagBeginCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitBeginCallback<EventFlag, WAITTYPE_EVENTFLAG, EventFlagTh>(threadID, prevCallbackId, eventFlagWaitTimer); if (result == HLEKernel::WAIT_CB_SUCCESS) DEBUG_LOG(SCEKERNEL, "sceKernelWaitEventFlagCB: Suspending lock wait for callback") else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA) ERROR_LOG_REPORT(SCEKERNEL, "sceKernelWaitEventFlagCB: wait not found to pause for callback") else WARN_LOG_REPORT(SCEKERNEL, "sceKernelWaitEventFlagCB: beginning callback with bad wait id?"); }
int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr) { DEBUG_LOG(HLE, "sceKernelWaitEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr); if ((wait & ~PSP_EVENT_WAITKNOWN) != 0) { WARN_LOG_REPORT(HLE, "sceKernelWaitEventFlag(%i) invalid mode parameter: %08x", id, wait); return SCE_KERNEL_ERROR_ILLEGAL_MODE; } // Can't wait on 0, that's guaranteed to wait forever. if (bits == 0) return SCE_KERNEL_ERROR_EVF_ILPAT; if (!__KernelIsDispatchEnabled()) return SCE_KERNEL_ERROR_CAN_NOT_WAIT; u32 error; EventFlag *e = kernelObjects.Get<EventFlag>(id, error); if (e) { EventFlagTh th; if (!__KernelEventFlagMatches(&e->nef.currentPattern, bits, wait, outBitsPtr)) { // If this thread was left in waitingThreads after a timeout, remove it. // Otherwise we might write the outBitsPtr in the wrong place. __KernelEventFlagRemoveThread(e, __KernelGetCurThread()); u32 timeout = 0xFFFFFFFF; if (Memory::IsValidAddress(timeoutPtr)) timeout = Memory::Read_U32(timeoutPtr); // Do we allow more than one thread to wait? if (e->waitingThreads.size() > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0) return SCE_KERNEL_ERROR_EVF_MULTI; // No match - must wait. th.tid = __KernelGetCurThread(); th.bits = bits; th.wait = wait; // If < 5ms, sometimes hardware doesn't write this, but it's unpredictable. th.outAddr = timeout == 0 ? 0 : outBitsPtr; e->waitingThreads.push_back(th); __KernelSetEventFlagTimeout(e, timeoutPtr); __KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr, false, "event flag waited"); } return 0; } else { return error; } }
bool MediaEngine::openContext() { #ifdef USE_FFMPEG InitFFmpeg(); if (m_pFormatCtx || !m_pdata) return false; m_mpegheaderReadPos = 0; m_decodingsize = 0; u8* tempbuf = (u8*)av_malloc(m_bufSize); m_pFormatCtx = avformat_alloc_context(); m_pIOContext = avio_alloc_context(tempbuf, m_bufSize, 0, (void*)this, _MpegReadbuffer, NULL, 0); m_pFormatCtx->pb = m_pIOContext; // Open video file if (avformat_open_input((AVFormatContext**)&m_pFormatCtx, NULL, NULL, NULL) != 0) return false; if (avformat_find_stream_info(m_pFormatCtx, NULL) < 0) { closeContext(); return false; } if (m_videoStream >= (int)m_pFormatCtx->nb_streams) { WARN_LOG_REPORT(ME, "Bad video stream %d", m_videoStream); m_videoStream = -1; } if (m_videoStream == -1) { // Find the first video stream for(int i = 0; i < (int)m_pFormatCtx->nb_streams; i++) { if(m_pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { m_videoStream = i; break; } } if(m_videoStream == -1) return false; } if (!setVideoStream(m_videoStream, true)) return false; setVideoDim(); m_audioContext = AT3Create(); m_isVideoEnd = false; m_noAudioData = false; m_mpegheaderReadPos++; av_seek_frame(m_pFormatCtx, m_videoStream, 0, 0); #endif // USE_FFMPEG return true; }
void __KernelStartModule(Module *m, int args, const char *argp, SceKernelSMOption *options) { if (m->nm.module_start_func != 0 && m->nm.module_start_func != (u32)-1) { if (m->nm.module_start_func != m->nm.entry_addr) WARN_LOG_REPORT(LOADER, "Main module has start func (%08x) different from entry (%08x)?", m->nm.module_start_func, m->nm.entry_addr); } __KernelSetupRootThread(m->GetUID(), args, argp, options->priority, options->stacksize, options->attribute); mainModuleID = m->GetUID(); //TODO: if current thread, put it in wait state, waiting for the new thread }
//SceUID sceKernelCreateEventFlag(const char *name, int attr, int bits, SceKernelEventFlagOptParam *opt); int sceKernelCreateEventFlag(const char *name, u32 flag_attr, u32 flag_initPattern, u32 optPtr) { if (!name) { WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateEventFlag(): invalid name", SCE_KERNEL_ERROR_ERROR); return SCE_KERNEL_ERROR_ERROR; } // These attributes aren't valid. if ((flag_attr & 0x100) != 0 || flag_attr >= 0x300) { WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateEventFlag(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, flag_attr); return SCE_KERNEL_ERROR_ILLEGAL_ATTR; } EventFlag *e = new EventFlag(); SceUID id = kernelObjects.Create(e); e->nef.size = sizeof(NativeEventFlag); strncpy(e->nef.name, name, KERNELOBJECT_MAX_NAME_LENGTH); e->nef.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0; e->nef.attr = flag_attr; e->nef.initPattern = flag_initPattern; e->nef.currentPattern = e->nef.initPattern; e->nef.numWaitThreads = 0; DEBUG_LOG(HLE, "%i=sceKernelCreateEventFlag(\"%s\", %08x, %08x, %08x)", id, e->nef.name, e->nef.attr, e->nef.currentPattern, optPtr); if (optPtr != 0) { u32 size = Memory::Read_U32(optPtr); if (size > 4) WARN_LOG_REPORT(HLE, "sceKernelCreateEventFlag(%s) unsupported options parameter, size = %d", name, size); } if ((flag_attr & ~PSP_EVENT_WAITMULTIPLE) != 0) WARN_LOG_REPORT(HLE, "sceKernelCreateEventFlag(%s) unsupported attr parameter: %08x", name, flag_attr); return id; }
int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 optionPtr) { if (!name) { WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateSema(): invalid name", SCE_KERNEL_ERROR_ERROR); return SCE_KERNEL_ERROR_ERROR; } if (attr >= 0x200) { WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateSema(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr); return SCE_KERNEL_ERROR_ILLEGAL_ATTR; } Semaphore *s = new Semaphore; SceUID id = kernelObjects.Create(s); s->ns.size = sizeof(NativeSemaphore); strncpy(s->ns.name, name, KERNELOBJECT_MAX_NAME_LENGTH); s->ns.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0; s->ns.attr = attr; s->ns.initCount = initVal; s->ns.currentCount = s->ns.initCount; s->ns.maxCount = maxVal; s->ns.numWaitThreads = 0; DEBUG_LOG(HLE, "%i=sceKernelCreateSema(%s, %08x, %i, %i, %08x)", id, s->ns.name, s->ns.attr, s->ns.initCount, s->ns.maxCount, optionPtr); if (optionPtr != 0) { u32 size = Memory::Read_U32(optionPtr); if (size > 4) WARN_LOG_REPORT(HLE, "sceKernelCreateSema(%s) unsupported options parameter, size = %d", name, size); } if ((attr & ~PSP_SEMA_ATTR_PRIORITY) != 0) WARN_LOG_REPORT(HLE, "sceKernelCreateSema(%s) unsupported attr parameter: %08x", name, attr); return id; }
SceUID sceKernelCreateMbx(const char *name, u32 attr, u32 optAddr) { if (!name) { WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateMbx(): invalid name", SCE_KERNEL_ERROR_ERROR); return SCE_KERNEL_ERROR_ERROR; } // Accepts 0x000 - 0x0FF, 0x100 - 0x1FF, and 0x400 - 0x4FF. if (((attr & ~SCE_KERNEL_MBA_ATTR_KNOWN) & ~0xFF) != 0) { WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateMbx(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr); return SCE_KERNEL_ERROR_ILLEGAL_ATTR; } Mbx *m = new Mbx(); SceUID id = kernelObjects.Create(m); m->nmb.size = sizeof(NativeMbx); strncpy(m->nmb.name, name, KERNELOBJECT_MAX_NAME_LENGTH); m->nmb.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0; m->nmb.attr = attr; m->nmb.numWaitThreads = 0; m->nmb.numMessages = 0; m->nmb.packetListHead = 0; DEBUG_LOG(HLE, "%i=sceKernelCreateMbx(%s, %08x, %08x)", id, name, attr, optAddr); if (optAddr != 0) { u32 size = Memory::Read_U32(optAddr); if (size > 4) WARN_LOG_REPORT(HLE, "sceKernelCreateMbx(%s) unsupported options parameter, size = %d", name, size); } if ((attr & ~SCE_KERNEL_MBA_ATTR_KNOWN) != 0) WARN_LOG_REPORT(HLE, "sceKernelCreateMbx(%s) unsupported attr parameter: %08x", name, attr); return id; }
bool MetaFileSystem::MapFilePath(const std::string &_inpath, std::string &outpath, MountPoint **system) { std::string realpath; // Special handling: host0:command.txt (as seen in Super Monkey Ball Adventures, for example) // appears to mean the current directory on the UMD. Let's just assume the current directory. std::string inpath = _inpath; if (strncasecmp(inpath.c_str(), "host0:", strlen("host0:")) == 0) { INFO_LOG(HLE, "Host0 path detected, stripping: %s", inpath.c_str()); inpath = inpath.substr(strlen("host0:")); } const std::string *currentDirectory = &startingDirectory; int currentThread = __KernelGetCurThread(); currentDir_t::iterator it = currentDir.find(currentThread); if (it == currentDir.end()) { //Attempt to emulate SCE_KERNEL_ERROR_NOCWD / 8002032C: may break things requiring fixes elsewhere if (inpath.find(':') == std::string::npos /* means path is relative */) { ioErrorCode = SCE_KERNEL_ERROR_NOCWD; WARN_LOG_REPORT(HLE, "Path is relative, but current directory not set for thread %i. returning 8002032C(SCE_KERNEL_ERROR_NOCWD) instead.", currentThread); } } else { currentDirectory = &(it->second); } if ( RealPath(*currentDirectory, inpath, realpath) ) { for (size_t i = 0; i < fileSystems.size(); i++) { size_t prefLen = fileSystems[i].prefix.size(); if (strncasecmp(fileSystems[i].prefix.c_str(), realpath.c_str(), prefLen) == 0) { outpath = realpath.substr(prefLen); *system = &(fileSystems[i]); VERBOSE_LOG(HLE, "MapFilePath: mapped \"%s\" to prefix: \"%s\", path: \"%s\"", inpath.c_str(), fileSystems[i].prefix.c_str(), outpath.c_str()); return true; } } } DEBUG_LOG(HLE, "MapFilePath: failed mapping \"%s\", returning false", inpath.c_str()); return false; }
//TODO: Implement all sceUtilityScreenshot* for real, it doesn't seem to be complex //but it requires more investigation u32 sceUtilityScreenshotInitStart(u32 unknown1, u32 unknown2, u32 unknown3, u32 unknown4, u32 unknown5, u32 unknown6) { if (currentDialogActive && currentDialogType != UTILITY_DIALOG_SCREENSHOT) { WARN_LOG(HLE, "sceUtilityScreenshotInitStart(%x, %x, %x, %x, %x, %x): wrong dialog type", unknown1, unknown2, unknown3, unknown4, unknown5, unknown6); return SCE_ERROR_UTILITY_WRONG_TYPE; } currentDialogType = UTILITY_DIALOG_SCREENSHOT; currentDialogActive = true; u32 retval = screenshotDialog.Init(); WARN_LOG_REPORT(HLE, "UNIMPL %i=sceUtilityScreenshotInitStart(%x, %x, %x, %x, %x, %x)", retval, unknown1, unknown2, unknown3, unknown4, unknown5, unknown6); return retval; }
//TODO: Implement all sceUtilityScreenshot* for real, it doesn't seem to be complex //but it requires more investigation u32 sceUtilityScreenshotInitStart(u32 paramAddr) { if (currentDialogActive && currentDialogType != UTILITY_DIALOG_SCREENSHOT) { WARN_LOG(SCEUTILITY, "sceUtilityScreenshotInitStart(%08x): wrong dialog type", paramAddr); return SCE_ERROR_UTILITY_WRONG_TYPE; } currentDialogType = UTILITY_DIALOG_SCREENSHOT; currentDialogActive = true; u32 retval = screenshotDialog.Init(); WARN_LOG_REPORT(SCEUTILITY, "%08x=sceUtilityScreenshotInitStart(%08x)", retval, paramAddr); return retval; }
void __KernelEventFlagBeginCallback(SceUID threadID, SceUID prevCallbackId) { SceUID pauseKey = prevCallbackId == 0 ? threadID : prevCallbackId; u32 error; SceUID flagID = __KernelGetWaitID(threadID, WAITTYPE_EVENTFLAG, error); u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); EventFlag *flag = flagID == 0 ? NULL : kernelObjects.Get<EventFlag>(flagID, error); if (flag) { // This means two callbacks in a row. PSP crashes if the same callback runs inside itself. // TODO: Handle this better? if (flag->pausedWaits.find(pauseKey) != flag->pausedWaits.end()) return; EventFlagTh waitData = {0}; for (size_t i = 0; i < flag->waitingThreads.size(); i++) { EventFlagTh *t = &flag->waitingThreads[i]; if (t->tid == threadID) { waitData = *t; // TODO: Hmm, what about priority/fifo order? Does it lose its place in line? flag->waitingThreads.erase(flag->waitingThreads.begin() + i); break; } } if (waitData.tid != threadID) { ERROR_LOG_REPORT(HLE, "sceKernelWaitEventFlagCB: wait not found to pause for callback"); return; } if (timeoutPtr != 0 && eventFlagWaitTimer != -1) { s64 cyclesLeft = CoreTiming::UnscheduleEvent(eventFlagWaitTimer, threadID); waitData.pausedTimeout = CoreTiming::GetTicks() + cyclesLeft; } else waitData.pausedTimeout = 0; flag->pausedWaits[pauseKey] = waitData; DEBUG_LOG(HLE, "sceKernelWaitEventFlagCB: Suspending lock wait for callback"); } else WARN_LOG_REPORT(HLE, "sceKernelWaitEventFlagCB: beginning callback with bad wait id?"); }
u32 sceKernelCreateVTimer(const char *name, u32 optParamAddr) { if (!name) { WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateVTimer(): invalid name", SCE_KERNEL_ERROR_ERROR); return SCE_KERNEL_ERROR_ERROR; } DEBUG_LOG(HLE, "sceKernelCreateVTimer(%s, %08x)", name, optParamAddr); VTimer *vtimer = new VTimer; SceUID id = kernelObjects.Create(vtimer); memset(&vtimer->nvt, 0, sizeof(NativeVTimer)); vtimer->nvt.size = sizeof(NativeVTimer); strncpy(vtimer->nvt.name, name, KERNELOBJECT_MAX_NAME_LENGTH); vtimer->nvt.name[KERNELOBJECT_MAX_NAME_LENGTH] = '\0'; vtimer->memoryPtr = 0; if (optParamAddr != 0) { u32 size = Memory::Read_U32(optParamAddr); if (size > 4) WARN_LOG_REPORT(HLE, "sceKernelCreateVTimer(%s) unsupported options parameter, size = %d", name, size); } return id; }
u32 BlockAllocator::GetTotalFreeBytes() const { u32 sum = 0; for (const Block *bp = bottom_; bp != NULL; bp = bp->next) { const Block &b = *bp; if (!b.taken) { sum += b.size; } } if (sum & (grain_ - 1)) WARN_LOG_REPORT(HLE, "GetTotalFreeBytes: free size %08x does not align to grain %08x.", sum, grain_); return sum; }