diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 22eb1f25cd..7ac7a64719 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -37,6 +37,9 @@ {75f0ee2b-1397-4cf3-9960-94ccd7d4d803} + + {9696662f-7398-489a-a358-5ebbf4ad4d97} + @@ -147,9 +150,6 @@ HLE\Kernel - - HLE\Kernel - HLE\Kernel @@ -285,6 +285,9 @@ ELF + + HW + @@ -377,9 +380,6 @@ HLE\Kernel - - HLE\Kernel - HLE\Kernel @@ -521,6 +521,9 @@ ELF + + HW + diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index 3baa309438..61c8f60856 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -81,7 +81,7 @@ bool DirectoryFileSystem::DeleteFile(const std::string &filename) u32 DirectoryFileSystem::OpenFile(std::string filename, FileAccess access) { std::string fullName = GetLocalPath(filename); - INFO_LOG(HLE,"Actually opening %s",fullName.c_str()); + INFO_LOG(HLE,"Actually opening %s (%s)", fullName.c_str(), filename.c_str()); OpenFileEntry entry; diff --git a/Core/FileSystems/MetaFileSystem.cpp b/Core/FileSystems/MetaFileSystem.cpp index 4c7279a2da..3dd8cb35d4 100644 --- a/Core/FileSystems/MetaFileSystem.cpp +++ b/Core/FileSystems/MetaFileSystem.cpp @@ -94,6 +94,11 @@ u32 MetaFileSystem::OpenFile(std::string filename, FileAccess access) PSPFileInfo MetaFileSystem::GetFileInfo(std::string filename) { std::string of; + if (filename.find(':') == std::string::npos) + { + filename = currentDirectory + "/" + filename; + DEBUG_LOG(HLE,"GetFileInfo: Expanded path to %s", filename.c_str()); + } IFileSystem *system; if (MapFilePath(filename, of, &system)) { diff --git a/Core/HLE/HLE.cpp b/Core/HLE/HLE.cpp index 163d1cbc4f..4be48dace0 100644 --- a/Core/HLE/HLE.cpp +++ b/Core/HLE/HLE.cpp @@ -198,4 +198,3 @@ void CallSyscall(u32 op) ERROR_LOG(HLE,"Unimplemented HLE function %s", moduleDB[modulenum].funcTable[funcnum].name); } } - diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index 985e79fafd..9cee2dddc9 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -36,7 +36,6 @@ #include "sceDmac.h" #include "sceKernel.h" #include "sceKernelEventFlag.h" -#include "sceKernelCallback.h" #include "sceKernelMemory.h" #include "sceKernelInterrupt.h" #include "sceKernelModule.h" diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 869a95e278..c1b51a3a90 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -220,28 +220,29 @@ void sceDisplaySetFramebuf() void sceDisplayGetFramebuf() { - DEBUG_LOG(HLE,"sceDisplayGetFramebuf"); + DEBUG_LOG(HLE,"sceDisplayGetFramebuf()"); RETURN(framebuf.topaddr); } void sceDisplayWaitVblankStart() { - DEBUG_LOG(HLE,"sceDisplayWaitVblankStart"); + DEBUG_LOG(HLE,"sceDisplayWaitVblankStart()"); __KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, false); RETURN(0); } void sceDisplayWaitVblank() { - DEBUG_LOG(HLE,"sceDisplayWaitVblank"); + DEBUG_LOG(HLE,"sceDisplayWaitVblank()"); __KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, false); sceDisplayWaitVblankStart(); } void sceDisplayWaitVblankStartCB() { - DEBUG_LOG(HLE,"sceDisplayWaitVblankStartCB"); + DEBUG_LOG(HLE,"sceDisplayWaitVblankStartCB()"); __KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, true); + __KernelCheckCallbacks(); } void sceDisplayGetVcount() diff --git a/Core/HLE/sceGe.cpp b/Core/HLE/sceGe.cpp index 680e6b822d..50ed1e2e1d 100644 --- a/Core/HLE/sceGe.cpp +++ b/Core/HLE/sceGe.cpp @@ -20,7 +20,7 @@ #include "../System.h" #include "../CoreParameter.h" #include "sceGe.h" -#include "sceKernelCallback.h" +#include "sceKernelThread.h" #include "sceKernelInterrupt.h" // TODO: Bad dependency. @@ -114,7 +114,7 @@ u32 sceGeDrawSync(u32) { //wait/check entire drawing state u32 mode = PARAM(0); //0 : wait for completion 1:check and return - DEBUG_LOG(HLE,"FAKE sceGeDrawSync(mode=%d)",mode); + DEBUG_LOG(HLE,"FAKE sceGeDrawSync(mode=%d) (0=wait for completion)",mode); if (mode == 1) { return 0; diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index f4d4224c2c..9b689f6003 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -23,6 +23,7 @@ #include "../System.h" #include "HLE.h" #include "../MIPS/MIPS.h" +#include "../HW/MemoryStick.h" #include "../FileSystems/FileSystem.h" #include "../FileSystems/MetaFileSystem.h" @@ -36,6 +37,10 @@ #define ERROR_ERRNO_FILE_NOT_FOUND 0x80010002 + +#define ERROR_MEMSTICK_DEVCTL_BAD_PARAMS 0x80220081 +#define ERROR_MEMSTICK_DEVCTL_TOO_MANY_CALLBACKS 0x80220082 + /* TODO: async io is missing features! @@ -178,10 +183,10 @@ void __IoInit() memstick = new DirectoryFileSystem(&pspFileSystem, mypath); pspFileSystem.Mount("ms0:", memstick); - pspFileSystem.Mount("fatms0:", memstick); - pspFileSystem.Mount("fatms:", memstick); - pspFileSystem.Mount("flash0:", new EmptyFileSystem()); - pspFileSystem.Mount("flash1:", new EmptyFileSystem()); + pspFileSystem.Mount("fatms0:", memstick); + pspFileSystem.Mount("fatms:", memstick); + pspFileSystem.Mount("flash0:", new EmptyFileSystem()); + pspFileSystem.Mount("flash1:", new EmptyFileSystem()); } void __IoShutdown() @@ -224,7 +229,7 @@ void __IoCompleteAsyncIO(SceUID id) { if (f->callbackID) { - __KernelNotifyCallback(__KernelGetCurThread(), f->callbackID, f->callbackArg); + // __KernelNotifyCallbackType(THREAD_CALLBACK_IO, __KernelGetCurThread(), f->callbackID, f->callbackArg); } } } @@ -476,10 +481,32 @@ void sceIoDevctl() //(const char *name, int cmd, void *arg, size_t arglen, void int argLen = PARAM(3); u32 outPtr = PARAM(4); int outLen = PARAM(5); - int retVal = 0; - DEBUG_LOG(HLE,"%i=sceIoDevctl(\"%s\", %08x, %08x, %i, %08x, %i)", - retVal, name, cmd,argAddr,argLen,outPtr,outLen); + DEBUG_LOG(HLE,"sceIoDevctl(\"%s\", %08x, %08x, %i, %08x, %i)", + name, cmd,argAddr,argLen,outPtr,outLen); + // UMD checks + switch (cmd) { + case 0x01F20001: // Get Disc Type. + if (Memory::IsValidAddress(outPtr)) { + Memory::Write_U32(0x10, outPtr); // Game disc + RETURN(0); return; + } else { + RETURN(-1); return; + } + break; + case 0x01F20002: // Get current LBA. + if (Memory::IsValidAddress(outPtr)) { + Memory::Write_U32(0, outPtr); // Game disc + RETURN(0); return; + } else { + RETURN(-1); return; + } + break; + case 0x01F100A3: // Seek + RETURN(0); return; + break; + } + // This should really send it on to a FileSystem implementation instead. if (!strcmp(name, "mscmhc0:")) @@ -487,14 +514,48 @@ void sceIoDevctl() //(const char *name, int cmd, void *arg, size_t arglen, void switch (cmd) { // does one of these set a callback as well? (see coded arms) + case 0x02025804: // Register callback + if (Memory::IsValidAddress(argAddr) && argLen == 4) { + u32 cbId = Memory::Read_U32(argAddr); + if (0 == __KernelRegisterCallback(THREAD_CALLBACK_MEMORYSTICK, cbId)) { + DEBUG_LOG(HLE, "sceIoDevCtl: Memstick callback %i registered, notifying immediately.", cbId); + __KernelNotifyCallbackType(THREAD_CALLBACK_MEMORYSTICK, cbId, MemoryStick_State()); + RETURN(0); + } else { + RETURN(ERROR_MEMSTICK_DEVCTL_BAD_PARAMS); + } + return; + } + break; + + case 0x02025805: // Unregister callback + if (Memory::IsValidAddress(argAddr) && argLen == 4) { + u32 cbId = Memory::Read_U32(argAddr); + if (0 == __KernelUnregisterCallback(THREAD_CALLBACK_MEMORYSTICK, cbId)) { + DEBUG_LOG(HLE, "sceIoDevCtl: Unregistered memstick callback %i", cbId); + RETURN(0); + } else { + RETURN(ERROR_MEMSTICK_DEVCTL_BAD_PARAMS); + } + return; + } + break; + case 0x02025806: // Memory stick inserted? case 0x02025801: // Memstick Driver status? - Memory::Write_U32(1, outPtr); - RETURN(0); + if (Memory::IsValidAddress(outPtr)) { + Memory::Write_U32(1, outPtr); + RETURN(0); + } else { + RETURN(ERROR_MEMSTICK_DEVCTL_BAD_PARAMS); + } return; - case 0x02425818: + + case 0x02425818: // Get memstick size etc // Pretend we have a 2GB memory stick. - { + if (Memory::IsValidAddress(argAddr)) { // "Should" be outPtr but isn't + u32 pointer = Memory::Read_U32(argAddr); + u64 totalSize = (u32)2 * 1024 * 1024 * 1024; u64 freeSize = 1 * 1024 * 1024 * 1024; DeviceSize deviceSize; @@ -503,36 +564,68 @@ void sceIoDevctl() //(const char *name, int cmd, void *arg, size_t arglen, void deviceSize.sectorsPerCluster = 0x08; deviceSize.totalClusters = (u32)((totalSize * 95 / 100) / (deviceSize.sectorSize * deviceSize.sectorsPerCluster)); deviceSize.freeClusters = (u32)((freeSize * 95 / 100) / (deviceSize.sectorSize * deviceSize.sectorsPerCluster)); - Memory::WriteStruct(outPtr, &deviceSize); + Memory::WriteStruct(pointer, &deviceSize); RETURN(0); - return; + } else { + RETURN(ERROR_MEMSTICK_DEVCTL_BAD_PARAMS); } - + return; } } if (!strcmp(name, "fatms0:")) { switch (cmd) { - case 0x02425823: - if (Memory::IsValidAddress(outPtr)) - Memory::Write_U32(1, outPtr); // TODO: Make a headless mode for running tests! - break; case 0x02415821: // MScmRegisterMSInsertEjectCallback { u32 cbId = Memory::Read_U32(argAddr); - ERROR_LOG(HLE, "sceIoDevCtl: Registering memstick callbacks not yet supported (%08x)", cbId); + if (0 == __KernelRegisterCallback(THREAD_CALLBACK_MEMORYSTICK_FAT, cbId)) { + DEBUG_LOG(HLE, "sceIoDevCtl: Memstick FAT callback %i registered, notifying immediately.", cbId); + __KernelNotifyCallbackType(THREAD_CALLBACK_MEMORYSTICK_FAT, cbId, MemoryStick_FatState()); + RETURN(0); + } else { + RETURN(-1); + } + return; } break; case 0x02415822: // MScmUnregisterMSInsertEjectCallback { u32 cbId = Memory::Read_U32(argAddr); - ERROR_LOG(HLE, "sceIoDevCtl: Unregistering memstick callbacks not yet supported (%08x)", cbId); + if (0 == __KernelUnregisterCallback(THREAD_CALLBACK_MEMORYSTICK_FAT, cbId)) { + DEBUG_LOG(HLE, "sceIoDevCtl: Unregistered memstick FAT callback %i", cbId); + RETURN(0); + } else { + RETURN(-1); + } + return; } + case 0x02425823: // Check if valid + if (Memory::IsValidAddress(outPtr)) + Memory::Write_U32(1, outPtr); // TODO: Make a headless mode for running tests! break; + case 0x02425818: // Get memstick size etc + // Pretend we have a 2GB memory stick. + { + if (Memory::IsValidAddress(argAddr)) { // "Should" be outPtr but isn't + u32 pointer = Memory::Read_U32(argAddr); + + u64 totalSize = (u32)2 * 1024 * 1024 * 1024; + u64 freeSize = 1 * 1024 * 1024 * 1024; + DeviceSize deviceSize; + deviceSize.maxSectors = 512; + deviceSize.sectorSize = 0x200; + deviceSize.sectorsPerCluster = 0x08; + deviceSize.totalClusters = (u32)((totalSize * 95 / 100) / (deviceSize.sectorSize * deviceSize.sectorsPerCluster)); + deviceSize.freeClusters = (u32)((freeSize * 95 / 100) / (deviceSize.sectorSize * deviceSize.sectorsPerCluster)); + Memory::WriteStruct(pointer, &deviceSize); + RETURN(0); + } else { + RETURN(ERROR_MEMSTICK_DEVCTL_BAD_PARAMS); + } + return; + } } - RETURN(0); - return; } @@ -544,7 +637,8 @@ void sceIoDevctl() //(const char *name, int cmd, void *arg, size_t arglen, void case 1: // EMULATOR_DEVCTL__GET_HAS_DISPLAY if (Memory::IsValidAddress(outPtr)) Memory::Write_U32(0, outPtr); // TODO: Make a headless mode for running tests! - break; + RETURN(0); + return; case 2: // EMULATOR_DEVCTL__SEND_OUTPUT { std::string data(Memory::GetCharPointer(argAddr), argLen); @@ -561,14 +655,20 @@ void sceIoDevctl() //(const char *name, int cmd, void *arg, size_t arglen, void { DEBUG_LOG(HLE, "%s", data.c_str()); } - break; + RETURN(0); + return; } case 3: // EMULATOR_DEVCTL__IS_EMULATOR if (Memory::IsValidAddress(outPtr)) Memory::Write_U32(1, outPtr); // TODO: Make a headless mode for running tests! - break; + RETURN(0); + return; } - retVal = 0; + + ERROR_LOG(HLE, "sceIoDevCtl: UNKNOWN PARAMETERS"); + + RETURN(0); + return; } //089c6d1c weird branch @@ -579,7 +679,7 @@ void sceIoDevctl() //(const char *name, int cmd, void *arg, size_t arglen, void 089c6c78 ]: HLE: sceIoDevctl("fatms0:", 02415821, 09ffb9c4, 4, 00000000, 0) (z_un_089c6bc4) 089c6cac ]: HLE: sceIoDevctl("mscmhc0:", 02025806, 00000000, 0, 09ffb9c8, 4) (z_un_089c6bc4) */ - RETURN(retVal); + RETURN(SCE_KERNEL_ERROR_UNSUP); } void sceIoRename() //(const char *oldname, const char *newname); diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 8f1d562617..bd8d92bbec 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -34,7 +34,6 @@ #include "sceIo.h" #include "sceKernel.h" #include "sceKernelAlarm.h" -#include "sceKernelCallback.h" #include "sceKernelInterrupt.h" #include "sceKernelThread.h" #include "sceKernelMemory.h" @@ -119,8 +118,8 @@ void sceKernelExitGame() void sceKernelRegisterExitCallback() { - u32 cbid = PARAM(0); - ERROR_LOG(HLE,"UNIMPL sceKernelRegisterExitCallback(%i)", cbid); + u32 cbId = PARAM(0); + ERROR_LOG(HLE,"UNIMPL sceKernelRegisterExitCallback(%i)", cbId); RETURN(0); } @@ -223,6 +222,7 @@ void KernelObjectPool::Clear() } memset(pool, 0, sizeof(KernelObject*)*maxCount); } + KernelObject *&KernelObjectPool::operator [](SceUID handle) { _dbg_assert_msg_(HLE, IsValid(handle), "GRABBING UNALLOCED KERNEL OBJ"); @@ -231,7 +231,7 @@ KernelObject *&KernelObjectPool::operator [](SceUID handle) void KernelObjectPool::List() { - for (int i=0; isize = sizeof(Callback); - strcpy(c->name, name); - - c->entrypoint = entrypoint; - c->threadId = __KernelGetCurThread(); - c->argument = callbackArg; - c->actionAfter = actionAfter; - - return id; -} - - -//extern Thread *currentThread; -void sceKernelCreateCallback() -{ - u32 entrypoint = PARAM(1); - u32 callbackArg = PARAM(2); - - const char *name = Memory::GetCharPointer(PARAM(0)); - - u32 id = __KernelCreateCallback(name, entrypoint, callbackArg); - - DEBUG_LOG(HLE,"%i=sceKernelCreateCallback(name=%s,entry= %08x, callbackArg = %08x)", id, name, entrypoint, callbackArg); - - RETURN(id); -} - -void sceKernelDeleteCallback() -{ - SceUID id = PARAM(0); - DEBUG_LOG(HLE,"sceKernelDeleteCallback(%i)", id); - RETURN(kernelObjects.Destroy(id)); -} - -void sceKernelNotifyCallback() -{ - SceUID cbid = PARAM(0); - u32 arg = PARAM(1); - DEBUG_LOG(HLE,"sceKernelNotifyCallback(%i, %i)", cbid, arg); - - __KernelNotifyCallback(__KernelGetCurThread(), cbid, arg); - RETURN(0); -} - -void sceKernelCancelCallback() -{ - SceUID cbid = PARAM(0); - ERROR_LOG(HLE,"UNIMPL sceKernelCancelCallback(%i)", cbid); - //__KernelCancelCallback(__KernelGetCurThread(), cbid); - RETURN(0); -} - -void sceKernelGetCallbackCount() -{ - SceUID cbid = PARAM(0); - ERROR_LOG(HLE,"UNIMPL sceKernelGetCallbackCount(%i)", cbid); - - RETURN(0); -} - -void sceKernelReferCallbackStatus() -{ - SceUID cbid = PARAM(0); - u32 statusAddr = PARAM(1); - ERROR_LOG(HLE,"UNIMPL sceKernelReferCallbackStatus(%i, %08x)", cbid, statusAddr); - - RETURN(0); -} - -void __KernelCallCallback(SceUID id) -{ - //First, make sure we're on the right thread - u32 error; - Callback *c = kernelObjects.Get(id, error); - if (c) - { - if (c->threadId == __KernelGetCurThread()) - { - //Alright, we're on the right thread - - // Save the few regs that need saving - c->savedPC = currentMIPS->pc; - c->savedRA = currentMIPS->r[MIPS_REG_RA]; - c->savedV0 = currentMIPS->r[MIPS_REG_V0]; - c->savedV1 = currentMIPS->r[MIPS_REG_V1]; - c->savedIdRegister = currentMIPS->r[MIPS_REG_CB_ID]; - - // Set up the new state - // TODO: check? - CallbackNotification *notify = __KernelGetCallbackNotification(id); - if (notify != NULL) - { - currentMIPS->r[4] = notify->count; - currentMIPS->r[5] = notify->arg; - notify->count = 0; - notify->arg = 0; - } - else - { - currentMIPS->r[4] = 0; - currentMIPS->r[5] = 0; - } - - currentMIPS->r[6] = c->argument; - currentMIPS->pc = c->entrypoint; - currentMIPS->r[MIPS_REG_RA] = __KernelCallbackReturnAddress(); - - g_inCbCount++; - } - } - else - { - //ARGH! - } -} - -void _sceKernelReturnFromCallback() -{ - SceUID cbid = currentMIPS->r[MIPS_REG_CB_ID]; // yeah! - DEBUG_LOG(HLE,"_sceKernelReturnFromCallback(cbid=%i)", cbid); - // Value returned by the callback function - u32 retVal = currentMIPS->r[MIPS_REG_V0]; - - u32 error; - Callback *cb = kernelObjects.Get(cbid, error); - if (!cb) - { - ERROR_LOG(HLE, "_sceKernelReturnFromCallback(): INVALID CBID in register! we're screwed"); - return; - } - - currentMIPS->pc = cb->savedPC; - currentMIPS->r[MIPS_REG_RA] = cb->savedRA; - currentMIPS->r[MIPS_REG_V0] = cb->savedV0; - currentMIPS->r[MIPS_REG_V1] = cb->savedV1; - currentMIPS->r[MIPS_REG_CB_ID] = cb->savedIdRegister; - - // Callbacks that don't return 0 are deleted. But should this be done here? - if (retVal != 0 || cb->forceDelete) - { - DEBUG_LOG(HLE, "_sceKernelReturnFromCallback(): Callback returned non-zero, gets deleted!"); - kernelObjects.Destroy(cbid); - } - - if (cb->actionAfter) - { - cb->actionAfter->run(); - } - g_inCbCount--; - // yeah! back in the real world, let's keep going.... -} - -u32 sceKernelCheckCallback() -{ - //only check those of current thread - ERROR_LOG(HLE,"UNIMPL sceKernelCheckCallback()"); - - // HACK that makes the audio thread work in Puyo Puyo Fever - the main thread never yields! - // Probably because callbacks aren't working right. - __KernelReSchedule("checkcallbackhack"); - - return 0; -} - -bool __KernelInCallback() -{ - return (g_inCbCount != 0); -} - diff --git a/Core/HLE/sceKernelCallback.h b/Core/HLE/sceKernelCallback.h deleted file mode 100644 index f3af93cbe4..0000000000 --- a/Core/HLE/sceKernelCallback.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2012- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#pragma once - -#include "Action.h" - -// Internal access - used by sceSetGeCallback -u32 __KernelCreateCallback(const char *name, u32 entrypoint, u32 signalArg, Action *actionAfter = 0); - -void sceKernelCreateCallback(); -void sceKernelDeleteCallback(); -void sceKernelNotifyCallback(); -void sceKernelCancelCallback(); -void sceKernelGetCallbackCount(); -void _sceKernelReturnFromCallback(); -u32 sceKernelCheckCallback(); -void sceKernelGetCallbackCount(); -void sceKernelReferCallbackStatus(); -bool __KernelInCallback(); - diff --git a/Core/HLE/sceKernelMbx.cpp b/Core/HLE/sceKernelMbx.cpp index 2fd592176d..8262bf1faf 100644 --- a/Core/HLE/sceKernelMbx.cpp +++ b/Core/HLE/sceKernelMbx.cpp @@ -16,6 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "sceKernel.h" +#include "sceKernelThread.h" #include "sceKernelMbx.h" #include "HLE.h" @@ -104,6 +105,7 @@ void sceKernelReceiveMbxCB() SceUInt uid = PARAM(0); u32 packetAddrPtr = PARAM(1); u32 timeoutPtr = PARAM(2); + __KernelCheckCallbacks(); ERROR_LOG(HLE, "UNIMPL sceKernelReceiveMbxCB(%i, %08x, %08x)", uid, packetAddrPtr, timeoutPtr); RETURN(0); diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index b96f716985..3049d35a35 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -228,6 +228,7 @@ void sceKernelAllocateFplCB() RETURN(0); } else { // TODO: Should block and process callbacks! + __KernelCheckCallbacks(); RETURN(0); } @@ -546,6 +547,7 @@ void sceKernelAllocateVplCB() else { ERROR_LOG(HLE, "sceKernelAllocateVplCB FAILURE"); + __KernelCheckCallbacks(); RETURN(-1); } } @@ -633,8 +635,8 @@ const HLEFunction SysMemUserForUser[] = {0x315AD3A0,0,"sceKernelSetCompiledSdkVersion380_390"}, {0xEBD5C3E6,0,"sceKernelSetCompiledSdkVersion395"}, {0xf77d77cb,sceKernelSetCompilerVersion,"sceKernelSetCompilerVersion"}, - {0x35669d4c,0,"SysMemUserForUser_35669d4c"}, - {0x1b4217bc,0,"SysMemUserForUser_1b4217bc"}, + {0x35669d4c,0,"sceKernelSetCompiledSdkVersion600_602"}, //?? + {0x1b4217bc,0,"sceKernelSetCompiledSdkVersion603_605"}, }; diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index e9dd558cca..ef1c137fae 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -146,6 +146,17 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro ptr = newptr; pspDecryptPRX(in, (u8*)ptr, head->psp_size); } + + if (*(u32*)ptr == 0x4543537e) { // "~SCE" + ERROR_LOG(HLE, "Wrong magic number %08x (~SCE, kernel module?)",*(u32*)ptr); + *error_string = "Kernel module?"; + if (newptr) + { + delete [] newptr; + } + kernelObjects.Destroy(module->GetUID()); + return 0; + } if (*(u32*)ptr != 0x464c457f) { diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index dbd1626076..493572b714 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -215,6 +215,7 @@ void sceKernelWaitSemaCB() { s->waitingThreads.push_back(__KernelGetCurThread()); __KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, 0, true); + __KernelCheckCallbacks(); return; } DEBUG_LOG(HLE,"After: CurrentCount: %i, Signal: %i", s->ns.currentCount, wantedCount); diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 5512e6c1d6..af21990a06 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -15,12 +15,17 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include +#include + #include "HLE.h" #include "HLETables.h" #include "../MIPS/MIPSInt.h" #include "../MIPS/MIPSCodeUtils.h" #include "../MIPS/MIPS.h" #include "../../Core/CoreTiming.h" +#include "../../Core/MemMap.h" +#include "../../Common/Action.h" #include "sceAudio.h" #include "sceKernel.h" @@ -28,9 +33,6 @@ #include "sceKernelThread.h" #include "sceKernelModule.h" #include "sceKernelInterrupt.h" -#include "sceKernelCallback.h" - -#include enum ThreadStatus { @@ -85,6 +87,7 @@ struct SceKernelSysClock { u32 hi; }; +// Real PSP struct, don't change the fields struct NativeThread { u32 nativeSize; @@ -129,18 +132,21 @@ public: nt.waitID, waitValue); } - static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_THID; } - int GetIDType() const { return SCE_KERNEL_TMID_Thread; } - bool GrabStack(u32 &stackSize) + + static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_THID; } + + int GetIDType() const { return SCE_KERNEL_TMID_Thread; } + + bool AllocateStack(u32 &stackSize) { if (nt.attr & PSP_THREAD_ATTR_KERNEL) { // Allocate stacks for kernel threads (idle) in kernel RAM - stackBlock = kernelMemory.Alloc(stackSize, true, "stack"); + stackBlock = kernelMemory.Alloc(stackSize, true, (std::string("stack/") + nt.name).c_str()); } else { - stackBlock = userMemory.Alloc(stackSize, true, "stack"); + stackBlock = userMemory.Alloc(stackSize, true, (std::string("stack/") + nt.name).c_str()); } if (stackBlock == (u32)-1) { @@ -157,9 +163,14 @@ public: context.r[MIPS_REG_SP] -= 512; return true; } + ~Thread() { - userMemory.Free(stackBlock); + if (nt.attr & PSP_THREAD_ATTR_KERNEL) { + kernelMemory.Free(stackBlock); + } else { + userMemory.Free(stackBlock); + } } NativeThread nt; @@ -171,11 +182,64 @@ public: ThreadContext context; - std::vector callbacks; + std::set registeredCallbacks[THREAD_CALLBACK_NUM_TYPES]; + std::list readyCallbacks[THREAD_CALLBACK_NUM_TYPES]; u32 stackBlock; }; +struct NativeCallback +{ + SceUInt size; + char name[32]; + SceUID threadId; + u32 entrypoint; + u32 commonArgument; + + int notifyCount; + int notifyArg; +}; + +class Callback : public KernelObject +{ +public: + const char *GetName() {return nc.name;} + const char *GetTypeName() {return "CallBack";} + + void GetQuickInfo(char *ptr, int size) + { + sprintf(ptr, "thread=%i, argument= %08x", + //hackAddress, + nc.threadId, + nc.commonArgument); + } + + ~Callback() + { + } + + static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_CBID; } + int GetIDType() const { return SCE_KERNEL_TMID_Callback; } + + NativeCallback nc; + + u32 savedPC; + u32 savedRA; + u32 savedV0; + u32 savedV1; + u32 savedIdRegister; + + /* + SceUInt attr; + SceUInt initPattern; + SceUInt currentPattern; + int numWaitThreads; + */ + + bool forceDelete; +}; + +int g_inCbCount = 0; Thread *__KernelCreateThread(SceUID &id, SceUID moduleID, const char *name, u32 entryPoint, u32 priority, int stacksize, u32 attr); @@ -200,6 +264,12 @@ SceUID curModule; //STATE END ////////////////////////////////////////////////////////////////////////// +// TODO: Should move to this wrapper so we can keep the current thread as a SceUID instead +// of a dangerous raw pointer. +Thread *__GetCurrentThread() { + return currentThread; +} + u32 __KernelCallbackReturnAddress() { return cbReturnHackAddr; @@ -240,9 +310,9 @@ void __KernelThreadingInit() eventScheduledWakeup = CoreTiming::RegisterEvent("ScheduledWakeup", &hleScheduledWakeup); // Create the two idle threads, as well. With the absolute minimal possible priority. - // Zero stack size. Hm, if callbacks are ever to run on these threads, that's not a good idea. - __KernelCreateThread(threadIdleID[0], 0, "idle0", idleThreadHackAddr, 0x7f, 0, PSP_THREAD_ATTR_KERNEL); - __KernelCreateThread(threadIdleID[1], 0, "idle1", idleThreadHackAddr, 0x7f, 0, PSP_THREAD_ATTR_KERNEL); + // 4096 stack size - don't know what the right value is. Hm, if callbacks are ever to run on these threads... + __KernelCreateThread(threadIdleID[0], 0, "idle0", idleThreadHackAddr, 0x7f, 4096, PSP_THREAD_ATTR_KERNEL); + __KernelCreateThread(threadIdleID[1], 0, "idle1", idleThreadHackAddr, 0x7f, 4096, PSP_THREAD_ATTR_KERNEL); // These idle threads are later started in LoadExec, which calls __KernelStartIdleThreads below. } @@ -296,44 +366,6 @@ u32 __KernelGetWaitValue(SceUID threadID, u32 &error) } } -// TODO: If cbid == -1, notify the callback ID on all threads that have it. -void __KernelNotifyCallback(SceUID threadID, SceUID cbid, u32 notifyArg) -{ - u32 error; - Thread *t = kernelObjects.Get(threadID, error); - if (t) - { - for (size_t i = 0; i < t->callbacks.size(); t++) - { - if (t->callbacks[i].cbid == cbid) - { - t->callbacks[i].arg = notifyArg; - t->callbacks[i].count++; - return; - } - } - CallbackNotification cb; - cb.cbid = cbid; - cb.arg = notifyArg; - cb.count = 1; - } - // TODO: error checking -} - -CallbackNotification *__KernelGetCallbackNotification(SceUID cbid) -{ - u32 error; - Thread *t = kernelObjects.Get(__KernelGetCurThread(), error); - for (size_t i = 0; i < t->callbacks.size(); t++) - { - if (t->callbacks[i].cbid == cbid) - { - return &t->callbacks[i]; - } - } - return 0; -} - void sceKernelReferThreadStatus() { SceUID threadID = PARAM(0); @@ -472,6 +504,8 @@ bool __KernelTriggerWait(WaitType type, int id, bool dontSwitch) { t->nt.status = THREADSTATUS_READY; } + // Non-waiting threads do not process callbacks. + t->isProcessingCallbacks = false; doneAnything = true; } } @@ -548,7 +582,7 @@ void __KernelRemoveFromThreadQueue(Thread *t) { if (threadqueue[i] == t) { - DEBUG_LOG(HLE, "Deleted thread %p from thread queue", t); + DEBUG_LOG(HLE, "Deleted thread %p (%i) from thread queue", t, t->GetUID()); threadqueue.erase(threadqueue.begin() + i); return; } @@ -705,7 +739,7 @@ Thread *__KernelCreateThread(SceUID &id, SceUID moduleID, const char *name, u32 strncpy(t->nt.name, name, 32); t->context.r[MIPS_REG_RA] = threadReturnHackAddr; //hack! TODO fix - t->GrabStack(t->nt.stackSize); // can change the stacksize! + t->AllocateStack(t->nt.stackSize); // can change the stacksize! return t; } @@ -792,6 +826,7 @@ u32 sceKernelStartThread() //now copy argument to stack for (int i = 0; i < (int)argSize; i++) Memory::Write_U8(Memory::Read_U8(argBlockPtr + i), sp + i); + return 0; } else @@ -833,6 +868,8 @@ void _sceKernelReturnFromThread() // Wake them if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread())) __KernelReSchedule("return from thread"); + + // The stack will be deallocated when the thread is deleted. } void sceKernelExitThread() @@ -844,6 +881,8 @@ void sceKernelExitThread() // Wake them if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread())) __KernelReSchedule("exited thread"); + + // The stack will be deallocated when the thread is deleted. } void _sceKernelExitThread() @@ -855,6 +894,8 @@ void _sceKernelExitThread() // Wake them if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread())) __KernelReSchedule("exit-deleted thread"); + + // The stack will be deallocated when the thread is deleted. } void sceKernelExitDeleteThread() @@ -867,6 +908,8 @@ void sceKernelExitDeleteThread() ERROR_LOG(HLE,"sceKernelExitDeleteThread()"); currentThread->nt.status = THREADSTATUS_DORMANT; currentThread->nt.exitStatus = PARAM(0); + //userMemory.Free(currentThread->stackBlock); + currentThread->stackBlock = -1; __KernelRemoveFromThreadQueue(t); currentThread = 0; @@ -989,6 +1032,7 @@ void sceKernelDelayThreadCB() SceUID curThread = __KernelGetCurThread(); __KernelScheduleWakeup(curThread, usec); __KernelWaitCurThread(WAITTYPE_DELAY, curThread, 0, 0, true); + __KernelCheckCallbacks(); } void sceKernelDelayThread() @@ -1039,9 +1083,11 @@ void sceKernelSleepThreadCB() DEBUG_LOG(HLE,"sceKernelSleepThreadCB()"); //set it to waiting currentThread->nt.wakeupCount--; - DEBUG_LOG(HLE,"sceKernelSleepThread() - wakeupCount decremented to %i", currentThread->nt.wakeupCount); - if (currentThread->nt.wakeupCount < 0) + DEBUG_LOG(HLE,"sceKernelSleepThreadCB() - wakeupCount decremented to %i", currentThread->nt.wakeupCount); + if (currentThread->nt.wakeupCount < 0) { __KernelWaitCurThread(WAITTYPE_SLEEP, 0, 0, 0, true); + __KernelCheckCallbacks(); + } else { RETURN(0); @@ -1056,12 +1102,11 @@ void sceKernelWaitThreadEnd() Thread *t = kernelObjects.Get(id, error); if (t) { - if (t->nt.status != THREADSTATUS_DORMANT) - { + if (t->nt.status != THREADSTATUS_DORMANT) { __KernelWaitCurThread(WAITTYPE_THREADEND, id, 0, 0, false); - return; + } else { + DEBUG_LOG(HLE,"sceKernelWaitThreadEnd - thread %i already ended. Doing nothing.", id); } - DEBUG_LOG(HLE,"sceKernelWaitThreadEnd - thread %i already ended. Doing nothing.", id); } else { @@ -1078,12 +1123,12 @@ void sceKernelWaitThreadEndCB() Thread *t = kernelObjects.Get(id, error); if (t) { - if (t->nt.status != THREADSTATUS_DORMANT) - { + if (t->nt.status != THREADSTATUS_DORMANT) { __KernelWaitCurThread(WAITTYPE_THREADEND, id, 0, 0, true); - return; - } - DEBUG_LOG(HLE,"sceKernelWaitThreadEnd - thread %i already ended. Doing nothing.", id); + } else { + DEBUG_LOG(HLE,"sceKernelWaitThreadEnd - thread %i already ended. Doing nothing.", id); + } + __KernelCheckCallbacks(); } else { @@ -1103,3 +1148,303 @@ void sceKernelResumeThread() DEBUG_LOG(HLE,"UNIMPL sceKernelResumeThread"); RETURN(0); } + +////////////////////////////////////////////////////////////////////////// +// CALLBACKS +////////////////////////////////////////////////////////////////////////// + + +// Internal API +u32 __KernelCreateCallback(const char *name, u32 entrypoint, u32 commonArg) +{ + Callback *cb = new Callback; + SceUID id = kernelObjects.Create(cb); + + cb->nc.size = sizeof(NativeCallback); + strcpy(cb->nc.name, name); + + cb->nc.entrypoint = entrypoint; + cb->nc.threadId = __KernelGetCurThread(); + cb->nc.commonArgument = commonArg; + cb->nc.notifyCount = 0; + cb->nc.notifyArg = 0; + + cb->forceDelete = false; + + return id; +} + +void sceKernelCreateCallback() +{ + u32 entrypoint = PARAM(1); + u32 callbackArg = PARAM(2); + + const char *name = Memory::GetCharPointer(PARAM(0)); + + u32 id = __KernelCreateCallback(name, entrypoint, callbackArg); + + DEBUG_LOG(HLE,"%i=sceKernelCreateCallback(name=%s,entry= %08x, callbackArg = %08x)", id, name, entrypoint, callbackArg); + + RETURN(id); +} + +void sceKernelDeleteCallback() +{ + SceUID id = PARAM(0); + DEBUG_LOG(HLE,"sceKernelDeleteCallback(%i)", id); + + // TODO: Make sure it's gone from all threads first! + + RETURN(kernelObjects.Destroy(id)); +} + +// Rarely used +void sceKernelNotifyCallback() +{ + SceUID cbId = PARAM(0); + u32 arg = PARAM(1); + DEBUG_LOG(HLE,"sceKernelNotifyCallback(%i, %i) UNIMPL", cbId, arg); + + // __KernelNotifyCallback(__KernelGetCurThread(), cbId, arg); + RETURN(0); +} + +void sceKernelCancelCallback() +{ + SceUID cbId = PARAM(0); + ERROR_LOG(HLE,"sceKernelCancelCallback(%i) - BAD", cbId); + u32 error; + Callback *cb = kernelObjects.Get(cbId, error); + if (cb) { + // This is what JPCSP does. Huh? + cb->nc.notifyArg = 0; + RETURN(0); + } else { + ERROR_LOG(HLE,"sceKernelCancelCallback(%i) - bad cbId", cbId); + RETURN(error); + } + RETURN(0); +} + +void sceKernelGetCallbackCount() +{ + SceUID cbId = PARAM(0); + u32 error; + Callback *cb = kernelObjects.Get(cbId, error); + if (cb) { + RETURN(cb->nc.notifyCount); + } else { + ERROR_LOG(HLE,"sceKernelGetCallbackCount(%i) - bad cbId", cbId); + RETURN(error); + } +} + +void sceKernelReferCallbackStatus() +{ + SceUID cbId = PARAM(0); + u32 statusAddr = PARAM(1); + u32 error; + Callback *c = kernelObjects.Get(cbId, error); + if (c) { + DEBUG_LOG(HLE,"sceKernelReferCallbackStatus(%i, %08x)", cbId, statusAddr); + if (Memory::IsValidAddress(statusAddr)) { + Memory::WriteStruct(statusAddr, &c->nc); + } // else TODO + RETURN(0); + } else { + ERROR_LOG(HLE,"sceKernelReferCallbackStatus(%i, %08x) - bad cbId", cbId, statusAddr); + RETURN(error); + } +} + + +// Context switches to the thread and executes the callback. +u32 __KernelRunCallbackOnThread(SceUID cbId, Thread *thread) +{ + if (g_inCbCount > 0) { + WARN_LOG(HLE, "__KernelRunCallbackOnThread: Already in a callback!"); + } + + u32 error; + Callback *cb = kernelObjects.Get(cbId, error); + if (!cb) { + return error; + } + + // First, context switch to the thread. + Thread *curThread = __GetCurrentThread(); + if (thread != curThread) { + __KernelSaveContext(&curThread->context); + __KernelLoadContext(&thread->context); + } + + //Alright, we're on the right thread + + // Save the few regs that need saving + cb->savedPC = currentMIPS->pc; + cb->savedRA = currentMIPS->r[MIPS_REG_RA]; + cb->savedV0 = currentMIPS->r[MIPS_REG_V0]; + cb->savedV1 = currentMIPS->r[MIPS_REG_V1]; + cb->savedIdRegister = currentMIPS->r[MIPS_REG_CB_ID]; + + // Set up the new state + // TODO: check? + currentMIPS->r[MIPS_REG_A0] = cb->nc.notifyCount; + currentMIPS->r[MIPS_REG_A1] = cb->nc.notifyArg; + currentMIPS->r[MIPS_REG_A2] = cb->nc.commonArgument; + currentMIPS->pc = cb->nc.entrypoint; + currentMIPS->r[MIPS_REG_RA] = __KernelCallbackReturnAddress(); + currentMIPS->r[MIPS_REG_CB_ID] = cbId; + + // Clear the notify count / arg + cb->nc.notifyCount = 0; + cb->nc.notifyArg = 0; + + g_inCbCount++; + return 0; +} + +void _sceKernelReturnFromCallback() +{ + SceUID cbId = currentMIPS->r[MIPS_REG_CB_ID]; + // Value returned by the callback function + u32 retVal = currentMIPS->r[MIPS_REG_V0]; + DEBUG_LOG(HLE,"_sceKernelReturnFromCallback(cbId=%i), returned %08x", cbId, retVal); + + u32 error; + Callback *cb = kernelObjects.Get(cbId, error); + if (!cb) + { + ERROR_LOG(HLE, "_sceKernelReturnFromCallback(): INVALID CBID %i in register! we're screwed", cbId); + return; + } + + currentMIPS->pc = cb->savedPC; + currentMIPS->r[MIPS_REG_RA] = cb->savedRA; + currentMIPS->r[MIPS_REG_V0] = cb->savedV0; + currentMIPS->r[MIPS_REG_V1] = cb->savedV1; + currentMIPS->r[MIPS_REG_CB_ID] = cb->savedIdRegister; + + // Callbacks that don't return 0 are deleted. But should this be done here? + if (retVal != 0 || cb->forceDelete) + { + DEBUG_LOG(HLE, "_sceKernelReturnFromCallback(): Callback returned non-zero, gets deleted!"); + kernelObjects.Destroy(cbId); + } + + g_inCbCount--; + + // yeah! back in the real world, let's keep going. Should we process more callbacks? +} + +// Check callbacks on the current thread only. +// Returns true if any callbacks were processed on the current thread. +bool __KernelCheckThreadCallbacks(Thread *thread) { + if (!thread->isProcessingCallbacks) + return false; + + for (int i = 0; i < THREAD_CALLBACK_NUM_TYPES; i++) { + if (thread->readyCallbacks[i].size()) { + SceUID readyCallback = thread->readyCallbacks[i].front(); + thread->readyCallbacks[i].pop_front(); + __KernelRunCallbackOnThread(readyCallback, thread); + return true; + } + } + return false; +} + +// Checks for callbacks on all threads +bool __KernelCheckCallbacks() { + SceUID currentThread = __KernelGetCurThread(); + // do { + bool processed = false; + + for (std::vector::iterator iter = threadqueue.begin(); iter != threadqueue.end(); iter++) { + Thread *thread = *iter; + if (thread->isProcessingCallbacks && __KernelCheckThreadCallbacks(thread)) { + processed = true; + } + } + // } while (processed && currentThread == __KernelGetCurThread()); + return processed; +} + +u32 sceKernelCheckCallback() +{ + Thread *curThread = __GetCurrentThread(); + + // This thread can now process callbacks. + curThread->isProcessingCallbacks = true; + + int callbacksProcessed = __KernelCheckThreadCallbacks(curThread) ? 1 : 0; + + // Note - same thread as above - checking callbacks may switch threads. + curThread->isProcessingCallbacks = false; + + if (callbacksProcessed) { + ERROR_LOG(HLE,"sceKernelCheckCallback() - processed a callback."); + } else { + DEBUG_LOG(HLE,"sceKernelCheckCallback() - no callbacks to process, doing nothing"); + } + + return callbacksProcessed; +} + +bool __KernelInCallback() +{ + return (g_inCbCount != 0); +} + + +u32 __KernelRegisterCallback(RegisteredCallbackType type, SceUID cbId) +{ + Thread *t = __GetCurrentThread(); + if (t->registeredCallbacks[type].find(cbId) == t->registeredCallbacks[type].end()) { + t->registeredCallbacks[type].insert(cbId); + return 0; + } else { + return SCE_KERNEL_ERROR_INVAL; + } +} + +u32 __KernelUnregisterCallback(RegisteredCallbackType type, SceUID cbId) +{ + Thread *t = __GetCurrentThread(); + if (t->registeredCallbacks[type].find(cbId) != t->registeredCallbacks[type].end()) { + t->registeredCallbacks[type].erase(cbId); + return 0; + } else { + return SCE_KERNEL_ERROR_INVAL; + } +} + +void __KernelNotifyCallback(RegisteredCallbackType type, SceUID threadId, SceUID cbId, int notifyArg) +{ + u32 error; + + Callback *cb = kernelObjects.Get(cbId, error); + cb->nc.notifyCount++; + cb->nc.notifyArg = notifyArg; + + Thread *t = kernelObjects.Get(threadId, error); + t->readyCallbacks[type].remove(cbId); + t->readyCallbacks[type].push_back(cbId); +} + +// TODO: If cbId == -1, notify the callback ID on all threads that have it. +u32 __KernelNotifyCallbackType(RegisteredCallbackType type, SceUID cbId, int notifyArg) +{ + for (std::vector::iterator iter = threadqueue.begin(); iter != threadqueue.end(); iter++) { + Thread *t = *iter; + for (std::set::iterator citer = t->registeredCallbacks[type].begin(); citer != t->registeredCallbacks[type].end(); citer++) { + if (cbId == -1 || cbId == *citer) { + __KernelNotifyCallback(type, t->GetUID(), *citer, notifyArg); + } + } + } + + // checkCallbacks on other threads? + return 0; +} + diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index fc64926761..9bca5a566e 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -85,14 +85,6 @@ struct ThreadContext u32 fcr31; }; -struct CallbackNotification -{ - SceUID cbid; - int count; - int arg; -}; - - // Internal API, used by implementations of kernel functions void __KernelThreadingInit(); @@ -111,10 +103,30 @@ u32 __KernelResumeThread(SceUID threadID); // can return an error value u32 __KernelGetWaitValue(SceUID threadID, u32 &error); void __KernelWaitCurThread(WaitType type, SceUID waitId, u32 waitValue, int timeout, bool processCallbacks); void __KernelReSchedule(const char *reason = "no reason"); -void __KernelNotifyCallback(SceUID threadID, SceUID cbid, u32 arg); -CallbackNotification *__KernelGetCallbackNotification(SceUID cbid); + +// Registered callback types +enum RegisteredCallbackType { + THREAD_CALLBACK_UMD = 0, + THREAD_CALLBACK_IO = 1, + THREAD_CALLBACK_MEMORYSTICK = 2, + THREAD_CALLBACK_MEMORYSTICK_FAT = 3, + THREAD_CALLBACK_POWER = 4, + THREAD_CALLBACK_EXIT = 5, + THREAD_CALLBACK_USER_DEFINED = 6, + THREAD_CALLBACK_SIZE = 7, + THREAD_CALLBACK_NUM_TYPES = 8, +}; + +// These operate on the current thread +u32 __KernelRegisterCallback(RegisteredCallbackType type, SceUID cbId); +u32 __KernelUnregisterCallback(RegisteredCallbackType type, SceUID cbId); + +// If cbId == -1, all the callbacks of the type on all the threads get notified. +// If not, only this particular callback gets notified. +u32 __KernelNotifyCallbackType(RegisteredCallbackType type, SceUID cbId, int notifyArg); + SceUID __KernelGetCurThread(); void __KernelSetupRootThread(SceUID moduleId, int args, const char *argp, int prio, int stacksize, int attr); //represents the real PSP elf loader, run before execution void __KernelStartIdleThreads(); @@ -124,3 +136,20 @@ void _sceKernelIdle(); u32 __KernelCallbackReturnAddress(); u32 __KernelInterruptReturnAddress(); + +// Internal access - used by sceSetGeCallback +u32 __KernelCreateCallback(const char *name, u32 entrypoint, u32 signalArg); + +void sceKernelCreateCallback(); +void sceKernelDeleteCallback(); +void sceKernelNotifyCallback(); +void sceKernelCancelCallback(); +void sceKernelGetCallbackCount(); +void _sceKernelReturnFromCallback(); +u32 sceKernelCheckCallback(); +void sceKernelGetCallbackCount(); +void sceKernelReferCallbackStatus(); +bool __KernelInCallback(); + +// Should be called by (nearly) all ...CB functions. +bool __KernelCheckCallbacks(); diff --git a/Core/MIPS/MIPS.cpp b/Core/MIPS/MIPS.cpp index 98baf93980..48ec684729 100644 --- a/Core/MIPS/MIPS.cpp +++ b/Core/MIPS/MIPS.cpp @@ -77,6 +77,7 @@ void MIPSState::Reset() SetWriteMask(b); pc = 0; + prevPC = 0; hi = 0; lo = 0; fpcond = 0; @@ -155,7 +156,7 @@ void MIPSState::RunLoopUntil(u64 globalTicks) break; } #endif - // u32 lastpc = pc; + prevPC = pc; if (inDelaySlot) { MIPSInterpret(op); diff --git a/Core/MIPS/MIPS.h b/Core/MIPS/MIPS.h index 88a297ea93..522971f996 100644 --- a/Core/MIPS/MIPS.h +++ b/Core/MIPS/MIPS.h @@ -112,6 +112,7 @@ public: u32 pc; u32 nextPC; + u32 prevPC; u32 hi; u32 lo; diff --git a/Core/MIPS/MIPSInt.cpp b/Core/MIPS/MIPSInt.cpp index f9d02fc58d..f666f7e776 100644 --- a/Core/MIPS/MIPSInt.cpp +++ b/Core/MIPS/MIPSInt.cpp @@ -176,10 +176,14 @@ namespace MIPSInt switch ((op>>16) & 0x1F) { - case 0: if ((s32)R(rs) < 0) DelayBranchTo(addr); else PC += 4; break;//bltz + case 0: if ((s32)R(rs) < 0) DelayBranchTo(addr); else PC += 4; break;//bltz case 1: if ((s32)R(rs) >= 0) DelayBranchTo(addr); else PC += 4; break;//bgez case 2: if ((s32)R(rs) < 0) DelayBranchTo(addr); else PC += 8; break;//bltzl case 3: if ((s32)R(rs) >= 0) DelayBranchTo(addr); else PC += 8; break;//bgezl + case 16: R(MIPS_REG_RA) = PC + 8; if ((s32)R(rs) < 0) DelayBranchTo(addr); else PC += 4; break;//bltz + case 17: R(MIPS_REG_RA) = PC + 8; if ((s32)R(rs) >= 0) DelayBranchTo(addr); else PC += 4; break;//bgez + case 18: R(MIPS_REG_RA) = PC + 8; if ((s32)R(rs) < 0) DelayBranchTo(addr); else PC += 8; break;//bltzl + case 19: R(MIPS_REG_RA) = PC + 8; if ((s32)R(rs) >= 0) DelayBranchTo(addr); else PC += 8; break;//bgezl default: _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); break; diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index 7904f94385..e348b73376 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -344,10 +344,10 @@ const MIPSInstruction tableRegImm[32] = INSTR("tnei", &Jit::Comp_Generic, Dis_Generic, 0, 0), {-2}, - INSTR("bltzal", &Jit::Comp_Generic, Dis_RelBranch, 0, IS_CONDBRANCH|IN_RS|OUT_RA), - INSTR("bgezal", &Jit::Comp_Generic, Dis_RelBranch, 0, IS_CONDBRANCH|IN_RS|OUT_RA), - INSTR("bltzall", &Jit::Comp_Generic, Dis_RelBranch, 0, IS_CONDBRANCH|IN_RS|OUT_RA), //L = likely - INSTR("bgezall", &Jit::Comp_Generic, Dis_RelBranch, 0, IS_CONDBRANCH|IN_RS|OUT_RA), + INSTR("bltzal", &Jit::Comp_Generic, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|OUT_RA), + INSTR("bgezal", &Jit::Comp_Generic, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|OUT_RA), + INSTR("bltzall", &Jit::Comp_Generic, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|OUT_RA), //L = likely + INSTR("bgezall", &Jit::Comp_Generic, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|OUT_RA), {-2}, {-2}, {-2}, diff --git a/Core/MemMap.h b/Core/MemMap.h index a7d94d9228..6afd44e118 100644 --- a/Core/MemMap.h +++ b/Core/MemMap.h @@ -211,12 +211,15 @@ void Memcpy(const u32 _Address, const void *_Data, const u32 _iLength); template void ReadStruct(u32 address, T *ptr) { - memcpy(ptr, GetPointer(address), sizeof(*ptr)); + size_t sz = sizeof(*ptr); + memcpy(ptr, GetPointer(address), sz); } + template void WriteStruct(u32 address, T *ptr) { - memcpy(GetPointer(address), ptr, sizeof(*ptr)); + size_t sz = sizeof(*ptr); + memcpy(GetPointer(address), ptr, sz); } const char *GetAddressName(u32 address); diff --git a/Core/MemMapFunctions.cpp b/Core/MemMapFunctions.cpp index ad6eea90f3..35e511988a 100644 --- a/Core/MemMapFunctions.cpp +++ b/Core/MemMapFunctions.cpp @@ -82,7 +82,7 @@ inline void ReadFromHardware(T &var, const u32 address) } else { - WARN_LOG(MEMMAP, "ReadFromHardware: Invalid address %08x PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); + WARN_LOG(MEMMAP, "ReadFromHardware: Invalid address %08x PC %08x PPC %08x LR %08x", address, currentMIPS->pc, currentMIPS->prevPC, currentMIPS->r[MIPS_REG_RA]); if (!g_Config.bIgnoreBadMemAccess) { // TODO: Not sure what the best way to crash is... exit(0); diff --git a/Core/Util/BlockAllocator.cpp b/Core/Util/BlockAllocator.cpp index 77d7e3a612..3f9953ea8b 100644 --- a/Core/Util/BlockAllocator.cpp +++ b/Core/Util/BlockAllocator.cpp @@ -30,7 +30,7 @@ void BlockAllocator::Shutdown() u32 BlockAllocator::Alloc(u32 &size, bool fromTop, const char *tag) { // Sanity check - if (size > rangeSize_) { + if (size == 0 || size > rangeSize_) { ERROR_LOG(HLE, "Clearly bogus size: %08x - failing allocation", size); return 0; } diff --git a/native b/native index 8288c307cc..652045e462 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit 8288c307cc896b40f9ad000db8f6b00c2b76ad0f +Subproject commit 652045e46252c51f02196dcd6f769969fb8b3659