Rewrite callback handling, part 1. All sorts of other fixes too.

This commit is contained in:
Henrik Rydgard 2012-11-06 15:46:21 +01:00
parent 91eeed6408
commit c61d10363a
26 changed files with 642 additions and 426 deletions

View file

@ -37,6 +37,9 @@
<Filter Include="Core"> <Filter Include="Core">
<UniqueIdentifier>{75f0ee2b-1397-4cf3-9960-94ccd7d4d803}</UniqueIdentifier> <UniqueIdentifier>{75f0ee2b-1397-4cf3-9960-94ccd7d4d803}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="HW">
<UniqueIdentifier>{9696662f-7398-489a-a358-5ebbf4ad4d97}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="ELF\ElfReader.cpp"> <ClCompile Include="ELF\ElfReader.cpp">
@ -147,9 +150,6 @@
<ClCompile Include="HLE\sceKernel.cpp"> <ClCompile Include="HLE\sceKernel.cpp">
<Filter>HLE\Kernel</Filter> <Filter>HLE\Kernel</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="HLE\sceKernelCallback.cpp">
<Filter>HLE\Kernel</Filter>
</ClCompile>
<ClCompile Include="HLE\sceKernelEventFlag.cpp"> <ClCompile Include="HLE\sceKernelEventFlag.cpp">
<Filter>HLE\Kernel</Filter> <Filter>HLE\Kernel</Filter>
</ClCompile> </ClCompile>
@ -285,6 +285,9 @@
<ClCompile Include="ELF\PrxDecrypter.cpp"> <ClCompile Include="ELF\PrxDecrypter.cpp">
<Filter>ELF</Filter> <Filter>ELF</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="HW\MemoryStick.cpp">
<Filter>HW</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="ELF\ElfReader.h"> <ClInclude Include="ELF\ElfReader.h">
@ -377,9 +380,6 @@
<ClInclude Include="HLE\sceKernel.h"> <ClInclude Include="HLE\sceKernel.h">
<Filter>HLE\Kernel</Filter> <Filter>HLE\Kernel</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="HLE\sceKernelCallback.h">
<Filter>HLE\Kernel</Filter>
</ClInclude>
<ClInclude Include="HLE\sceKernelEventFlag.h"> <ClInclude Include="HLE\sceKernelEventFlag.h">
<Filter>HLE\Kernel</Filter> <Filter>HLE\Kernel</Filter>
</ClInclude> </ClInclude>
@ -521,6 +521,9 @@
<ClInclude Include="ELF\PrxDecrypter.h"> <ClInclude Include="ELF\PrxDecrypter.h">
<Filter>ELF</Filter> <Filter>ELF</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="HW\MemoryStick.h">
<Filter>HW</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="CMakeLists.txt" /> <None Include="CMakeLists.txt" />

View file

@ -81,7 +81,7 @@ bool DirectoryFileSystem::DeleteFile(const std::string &filename)
u32 DirectoryFileSystem::OpenFile(std::string filename, FileAccess access) u32 DirectoryFileSystem::OpenFile(std::string filename, FileAccess access)
{ {
std::string fullName = GetLocalPath(filename); 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; OpenFileEntry entry;

View file

@ -94,6 +94,11 @@ u32 MetaFileSystem::OpenFile(std::string filename, FileAccess access)
PSPFileInfo MetaFileSystem::GetFileInfo(std::string filename) PSPFileInfo MetaFileSystem::GetFileInfo(std::string filename)
{ {
std::string of; 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; IFileSystem *system;
if (MapFilePath(filename, of, &system)) if (MapFilePath(filename, of, &system))
{ {

View file

@ -198,4 +198,3 @@ void CallSyscall(u32 op)
ERROR_LOG(HLE,"Unimplemented HLE function %s", moduleDB[modulenum].funcTable[funcnum].name); ERROR_LOG(HLE,"Unimplemented HLE function %s", moduleDB[modulenum].funcTable[funcnum].name);
} }
} }

View file

@ -36,7 +36,6 @@
#include "sceDmac.h" #include "sceDmac.h"
#include "sceKernel.h" #include "sceKernel.h"
#include "sceKernelEventFlag.h" #include "sceKernelEventFlag.h"
#include "sceKernelCallback.h"
#include "sceKernelMemory.h" #include "sceKernelMemory.h"
#include "sceKernelInterrupt.h" #include "sceKernelInterrupt.h"
#include "sceKernelModule.h" #include "sceKernelModule.h"

View file

@ -220,28 +220,29 @@ void sceDisplaySetFramebuf()
void sceDisplayGetFramebuf() void sceDisplayGetFramebuf()
{ {
DEBUG_LOG(HLE,"sceDisplayGetFramebuf"); DEBUG_LOG(HLE,"sceDisplayGetFramebuf()");
RETURN(framebuf.topaddr); RETURN(framebuf.topaddr);
} }
void sceDisplayWaitVblankStart() void sceDisplayWaitVblankStart()
{ {
DEBUG_LOG(HLE,"sceDisplayWaitVblankStart"); DEBUG_LOG(HLE,"sceDisplayWaitVblankStart()");
__KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, false); __KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, false);
RETURN(0); RETURN(0);
} }
void sceDisplayWaitVblank() void sceDisplayWaitVblank()
{ {
DEBUG_LOG(HLE,"sceDisplayWaitVblank"); DEBUG_LOG(HLE,"sceDisplayWaitVblank()");
__KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, false); __KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, false);
sceDisplayWaitVblankStart(); sceDisplayWaitVblankStart();
} }
void sceDisplayWaitVblankStartCB() void sceDisplayWaitVblankStartCB()
{ {
DEBUG_LOG(HLE,"sceDisplayWaitVblankStartCB"); DEBUG_LOG(HLE,"sceDisplayWaitVblankStartCB()");
__KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, true); __KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, true);
__KernelCheckCallbacks();
} }
void sceDisplayGetVcount() void sceDisplayGetVcount()

View file

@ -20,7 +20,7 @@
#include "../System.h" #include "../System.h"
#include "../CoreParameter.h" #include "../CoreParameter.h"
#include "sceGe.h" #include "sceGe.h"
#include "sceKernelCallback.h" #include "sceKernelThread.h"
#include "sceKernelInterrupt.h" #include "sceKernelInterrupt.h"
// TODO: Bad dependency. // TODO: Bad dependency.
@ -114,7 +114,7 @@ u32 sceGeDrawSync(u32)
{ {
//wait/check entire drawing state //wait/check entire drawing state
u32 mode = PARAM(0); //0 : wait for completion 1:check and return 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) if (mode == 1)
{ {
return 0; return 0;

View file

@ -23,6 +23,7 @@
#include "../System.h" #include "../System.h"
#include "HLE.h" #include "HLE.h"
#include "../MIPS/MIPS.h" #include "../MIPS/MIPS.h"
#include "../HW/MemoryStick.h"
#include "../FileSystems/FileSystem.h" #include "../FileSystems/FileSystem.h"
#include "../FileSystems/MetaFileSystem.h" #include "../FileSystems/MetaFileSystem.h"
@ -36,6 +37,10 @@
#define ERROR_ERRNO_FILE_NOT_FOUND 0x80010002 #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! TODO: async io is missing features!
@ -178,10 +183,10 @@ void __IoInit()
memstick = new DirectoryFileSystem(&pspFileSystem, mypath); memstick = new DirectoryFileSystem(&pspFileSystem, mypath);
pspFileSystem.Mount("ms0:", memstick); pspFileSystem.Mount("ms0:", memstick);
pspFileSystem.Mount("fatms0:", memstick); pspFileSystem.Mount("fatms0:", memstick);
pspFileSystem.Mount("fatms:", memstick); pspFileSystem.Mount("fatms:", memstick);
pspFileSystem.Mount("flash0:", new EmptyFileSystem()); pspFileSystem.Mount("flash0:", new EmptyFileSystem());
pspFileSystem.Mount("flash1:", new EmptyFileSystem()); pspFileSystem.Mount("flash1:", new EmptyFileSystem());
} }
void __IoShutdown() void __IoShutdown()
@ -224,7 +229,7 @@ void __IoCompleteAsyncIO(SceUID id)
{ {
if (f->callbackID) 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); int argLen = PARAM(3);
u32 outPtr = PARAM(4); u32 outPtr = PARAM(4);
int outLen = PARAM(5); int outLen = PARAM(5);
int retVal = 0; DEBUG_LOG(HLE,"sceIoDevctl(\"%s\", %08x, %08x, %i, %08x, %i)",
DEBUG_LOG(HLE,"%i=sceIoDevctl(\"%s\", %08x, %08x, %i, %08x, %i)", name, cmd,argAddr,argLen,outPtr,outLen);
retVal, 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. // This should really send it on to a FileSystem implementation instead.
if (!strcmp(name, "mscmhc0:")) if (!strcmp(name, "mscmhc0:"))
@ -487,14 +514,48 @@ void sceIoDevctl() //(const char *name, int cmd, void *arg, size_t arglen, void
switch (cmd) switch (cmd)
{ {
// does one of these set a callback as well? (see coded arms) // 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 0x02025806: // Memory stick inserted?
case 0x02025801: // Memstick Driver status? case 0x02025801: // Memstick Driver status?
Memory::Write_U32(1, outPtr); if (Memory::IsValidAddress(outPtr)) {
RETURN(0); Memory::Write_U32(1, outPtr);
RETURN(0);
} else {
RETURN(ERROR_MEMSTICK_DEVCTL_BAD_PARAMS);
}
return; return;
case 0x02425818:
case 0x02425818: // Get memstick size etc
// Pretend we have a 2GB memory stick. // 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 totalSize = (u32)2 * 1024 * 1024 * 1024;
u64 freeSize = 1 * 1024 * 1024 * 1024; u64 freeSize = 1 * 1024 * 1024 * 1024;
DeviceSize deviceSize; DeviceSize deviceSize;
@ -503,36 +564,68 @@ void sceIoDevctl() //(const char *name, int cmd, void *arg, size_t arglen, void
deviceSize.sectorsPerCluster = 0x08; deviceSize.sectorsPerCluster = 0x08;
deviceSize.totalClusters = (u32)((totalSize * 95 / 100) / (deviceSize.sectorSize * deviceSize.sectorsPerCluster)); deviceSize.totalClusters = (u32)((totalSize * 95 / 100) / (deviceSize.sectorSize * deviceSize.sectorsPerCluster));
deviceSize.freeClusters = (u32)((freeSize * 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(0);
return; } else {
RETURN(ERROR_MEMSTICK_DEVCTL_BAD_PARAMS);
} }
return;
} }
} }
if (!strcmp(name, "fatms0:")) if (!strcmp(name, "fatms0:"))
{ {
switch (cmd) { 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 case 0x02415821: // MScmRegisterMSInsertEjectCallback
{ {
u32 cbId = Memory::Read_U32(argAddr); 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; break;
case 0x02415822: // MScmUnregisterMSInsertEjectCallback case 0x02415822: // MScmUnregisterMSInsertEjectCallback
{ {
u32 cbId = Memory::Read_U32(argAddr); 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; 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 case 1: // EMULATOR_DEVCTL__GET_HAS_DISPLAY
if (Memory::IsValidAddress(outPtr)) if (Memory::IsValidAddress(outPtr))
Memory::Write_U32(0, outPtr); // TODO: Make a headless mode for running tests! Memory::Write_U32(0, outPtr); // TODO: Make a headless mode for running tests!
break; RETURN(0);
return;
case 2: // EMULATOR_DEVCTL__SEND_OUTPUT case 2: // EMULATOR_DEVCTL__SEND_OUTPUT
{ {
std::string data(Memory::GetCharPointer(argAddr), argLen); 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()); DEBUG_LOG(HLE, "%s", data.c_str());
} }
break; RETURN(0);
return;
} }
case 3: // EMULATOR_DEVCTL__IS_EMULATOR case 3: // EMULATOR_DEVCTL__IS_EMULATOR
if (Memory::IsValidAddress(outPtr)) if (Memory::IsValidAddress(outPtr))
Memory::Write_U32(1, outPtr); // TODO: Make a headless mode for running tests! 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 //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) 089c6c78 ]: HLE: sceIoDevctl("fatms0:", 02415821, 09ffb9c4, 4, 00000000, 0) (z_un_089c6bc4)
089c6cac ]: HLE: sceIoDevctl("mscmhc0:", 02025806, 00000000, 0, 09ffb9c8, 4) (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); void sceIoRename() //(const char *oldname, const char *newname);

View file

@ -34,7 +34,6 @@
#include "sceIo.h" #include "sceIo.h"
#include "sceKernel.h" #include "sceKernel.h"
#include "sceKernelAlarm.h" #include "sceKernelAlarm.h"
#include "sceKernelCallback.h"
#include "sceKernelInterrupt.h" #include "sceKernelInterrupt.h"
#include "sceKernelThread.h" #include "sceKernelThread.h"
#include "sceKernelMemory.h" #include "sceKernelMemory.h"
@ -119,8 +118,8 @@ void sceKernelExitGame()
void sceKernelRegisterExitCallback() void sceKernelRegisterExitCallback()
{ {
u32 cbid = PARAM(0); u32 cbId = PARAM(0);
ERROR_LOG(HLE,"UNIMPL sceKernelRegisterExitCallback(%i)", cbid); ERROR_LOG(HLE,"UNIMPL sceKernelRegisterExitCallback(%i)", cbId);
RETURN(0); RETURN(0);
} }
@ -223,6 +222,7 @@ void KernelObjectPool::Clear()
} }
memset(pool, 0, sizeof(KernelObject*)*maxCount); memset(pool, 0, sizeof(KernelObject*)*maxCount);
} }
KernelObject *&KernelObjectPool::operator [](SceUID handle) KernelObject *&KernelObjectPool::operator [](SceUID handle)
{ {
_dbg_assert_msg_(HLE, IsValid(handle), "GRABBING UNALLOCED KERNEL OBJ"); _dbg_assert_msg_(HLE, IsValid(handle), "GRABBING UNALLOCED KERNEL OBJ");
@ -231,7 +231,7 @@ KernelObject *&KernelObjectPool::operator [](SceUID handle)
void KernelObjectPool::List() void KernelObjectPool::List()
{ {
for (int i=0; i<maxCount; i++) for (int i = 0; i < maxCount; i++)
{ {
if (occupied[i]) if (occupied[i])
{ {
@ -248,6 +248,7 @@ void KernelObjectPool::List()
} }
} }
} }
int KernelObjectPool::GetCount() int KernelObjectPool::GetCount()
{ {
int count = 0; int count = 0;
@ -259,7 +260,6 @@ int KernelObjectPool::GetCount()
return count; return count;
} }
void sceKernelIcacheInvalidateAll() void sceKernelIcacheInvalidateAll()
{ {
DEBUG_LOG(CPU, "Icache cleared - should clear JIT someday"); DEBUG_LOG(CPU, "Icache cleared - should clear JIT someday");

View file

@ -81,7 +81,7 @@ enum
SCE_KERNEL_ERROR_LINKERR = 0x8002012c, SCE_KERNEL_ERROR_LINKERR = 0x8002012c,
SCE_KERNEL_ERROR_ILLEGAL_OBJECT = 0x8002012d, SCE_KERNEL_ERROR_ILLEGAL_OBJECT = 0x8002012d,
SCE_KERNEL_ERROR_UNKNOWN_MODULE = 0x8002012e, SCE_KERNEL_ERROR_UNKNOWN_MODULE = 0x8002012e,
SCE_KERNEL_ERROR_NOFILE = 0x8002012f, SCE_KERNEL_ERROR_NOFILE = 0x8002012f,
SCE_KERNEL_ERROR_FILEERR = 0x80020130, SCE_KERNEL_ERROR_FILEERR = 0x80020130,
SCE_KERNEL_ERROR_MEMINUSE = 0x80020131, SCE_KERNEL_ERROR_MEMINUSE = 0x80020131,
SCE_KERNEL_ERROR_PARTITION_MISMATCH = 0x80020132, SCE_KERNEL_ERROR_PARTITION_MISMATCH = 0x80020132,

View file

@ -1,255 +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/.
// Refer to http://code.google.com/p/yaupspe/source/detail?r=741987a938f87e55ac284f8c2af6d40b4fb30ffc#
#include "HLE.h"
#include "../MIPS/MIPS.h"
#include "../MIPS/MIPSCodeUtils.h"
#include "sceKernel.h"
#include "sceKernelThread.h"
#include "sceKernelMemory.h"
#include "sceKernelCallback.h"
class Callback : public KernelObject
{
public:
const char *GetName() {return name;}
const char *GetTypeName() {return "CallBack";}
void GetQuickInfo(char *ptr, int size)
{
sprintf(ptr, "thread=%i, argument= %08x",
//hackAddress,
threadId,
argument);
}
~Callback()
{
}
static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_CBID; }
int GetIDType() const { return SCE_KERNEL_TMID_Callback; }
SceUInt size;
char name[32];
u32 entrypoint;
SceUID threadId;
u32 argument;
u32 savedPC;
u32 savedRA;
u32 savedV0;
u32 savedV1;
u32 savedIdRegister;
/*
SceUInt attr;
SceUInt initPattern;
SceUInt currentPattern;
int numWaitThreads;
*/
bool forceDelete;
Action *actionAfter;
};
int g_inCbCount = 0;
//////////////////////////////////////////////////////////////////////////
// CALLBACKS
//////////////////////////////////////////////////////////////////////////
// Internal API
u32 __KernelCreateCallback(const char *name, u32 entrypoint, u32 callbackArg, Action *actionAfter)
{
Callback *c = new Callback;
SceUID id = kernelObjects.Create(c);
c->size = 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<Callback>(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<Callback>(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<Callback>(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<Callback>(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);
}

View file

@ -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();

View file

@ -16,6 +16,7 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "sceKernel.h" #include "sceKernel.h"
#include "sceKernelThread.h"
#include "sceKernelMbx.h" #include "sceKernelMbx.h"
#include "HLE.h" #include "HLE.h"
@ -104,6 +105,7 @@ void sceKernelReceiveMbxCB()
SceUInt uid = PARAM(0); SceUInt uid = PARAM(0);
u32 packetAddrPtr = PARAM(1); u32 packetAddrPtr = PARAM(1);
u32 timeoutPtr = PARAM(2); u32 timeoutPtr = PARAM(2);
__KernelCheckCallbacks();
ERROR_LOG(HLE, "UNIMPL sceKernelReceiveMbxCB(%i, %08x, %08x)", uid, packetAddrPtr, timeoutPtr); ERROR_LOG(HLE, "UNIMPL sceKernelReceiveMbxCB(%i, %08x, %08x)", uid, packetAddrPtr, timeoutPtr);
RETURN(0); RETURN(0);

View file

@ -228,6 +228,7 @@ void sceKernelAllocateFplCB()
RETURN(0); RETURN(0);
} else { } else {
// TODO: Should block and process callbacks! // TODO: Should block and process callbacks!
__KernelCheckCallbacks();
RETURN(0); RETURN(0);
} }
@ -546,6 +547,7 @@ void sceKernelAllocateVplCB()
else else
{ {
ERROR_LOG(HLE, "sceKernelAllocateVplCB FAILURE"); ERROR_LOG(HLE, "sceKernelAllocateVplCB FAILURE");
__KernelCheckCallbacks();
RETURN(-1); RETURN(-1);
} }
} }
@ -633,8 +635,8 @@ const HLEFunction SysMemUserForUser[] =
{0x315AD3A0,0,"sceKernelSetCompiledSdkVersion380_390"}, {0x315AD3A0,0,"sceKernelSetCompiledSdkVersion380_390"},
{0xEBD5C3E6,0,"sceKernelSetCompiledSdkVersion395"}, {0xEBD5C3E6,0,"sceKernelSetCompiledSdkVersion395"},
{0xf77d77cb,sceKernelSetCompilerVersion,"sceKernelSetCompilerVersion"}, {0xf77d77cb,sceKernelSetCompilerVersion,"sceKernelSetCompilerVersion"},
{0x35669d4c,0,"SysMemUserForUser_35669d4c"}, {0x35669d4c,0,"sceKernelSetCompiledSdkVersion600_602"}, //??
{0x1b4217bc,0,"SysMemUserForUser_1b4217bc"}, {0x1b4217bc,0,"sceKernelSetCompiledSdkVersion603_605"},
}; };

View file

@ -146,6 +146,17 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
ptr = newptr; ptr = newptr;
pspDecryptPRX(in, (u8*)ptr, head->psp_size); 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>(module->GetUID());
return 0;
}
if (*(u32*)ptr != 0x464c457f) if (*(u32*)ptr != 0x464c457f)
{ {

View file

@ -215,6 +215,7 @@ void sceKernelWaitSemaCB()
{ {
s->waitingThreads.push_back(__KernelGetCurThread()); s->waitingThreads.push_back(__KernelGetCurThread());
__KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, 0, true); __KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, 0, true);
__KernelCheckCallbacks();
return; return;
} }
DEBUG_LOG(HLE,"After: CurrentCount: %i, Signal: %i", s->ns.currentCount, wantedCount); DEBUG_LOG(HLE,"After: CurrentCount: %i, Signal: %i", s->ns.currentCount, wantedCount);

View file

@ -15,12 +15,17 @@
// Official git repository and contact information can be found at // Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <set>
#include <queue>
#include "HLE.h" #include "HLE.h"
#include "HLETables.h" #include "HLETables.h"
#include "../MIPS/MIPSInt.h" #include "../MIPS/MIPSInt.h"
#include "../MIPS/MIPSCodeUtils.h" #include "../MIPS/MIPSCodeUtils.h"
#include "../MIPS/MIPS.h" #include "../MIPS/MIPS.h"
#include "../../Core/CoreTiming.h" #include "../../Core/CoreTiming.h"
#include "../../Core/MemMap.h"
#include "../../Common/Action.h"
#include "sceAudio.h" #include "sceAudio.h"
#include "sceKernel.h" #include "sceKernel.h"
@ -28,9 +33,6 @@
#include "sceKernelThread.h" #include "sceKernelThread.h"
#include "sceKernelModule.h" #include "sceKernelModule.h"
#include "sceKernelInterrupt.h" #include "sceKernelInterrupt.h"
#include "sceKernelCallback.h"
#include <queue>
enum ThreadStatus enum ThreadStatus
{ {
@ -85,6 +87,7 @@ struct SceKernelSysClock {
u32 hi; u32 hi;
}; };
// Real PSP struct, don't change the fields
struct NativeThread struct NativeThread
{ {
u32 nativeSize; u32 nativeSize;
@ -129,18 +132,21 @@ public:
nt.waitID, nt.waitID,
waitValue); waitValue);
} }
static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_THID; }
int GetIDType() const { return SCE_KERNEL_TMID_Thread; } static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_THID; }
bool GrabStack(u32 &stackSize)
int GetIDType() const { return SCE_KERNEL_TMID_Thread; }
bool AllocateStack(u32 &stackSize)
{ {
if (nt.attr & PSP_THREAD_ATTR_KERNEL) if (nt.attr & PSP_THREAD_ATTR_KERNEL)
{ {
// Allocate stacks for kernel threads (idle) in kernel RAM // 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 else
{ {
stackBlock = userMemory.Alloc(stackSize, true, "stack"); stackBlock = userMemory.Alloc(stackSize, true, (std::string("stack/") + nt.name).c_str());
} }
if (stackBlock == (u32)-1) if (stackBlock == (u32)-1)
{ {
@ -157,9 +163,14 @@ public:
context.r[MIPS_REG_SP] -= 512; context.r[MIPS_REG_SP] -= 512;
return true; return true;
} }
~Thread() ~Thread()
{ {
userMemory.Free(stackBlock); if (nt.attr & PSP_THREAD_ATTR_KERNEL) {
kernelMemory.Free(stackBlock);
} else {
userMemory.Free(stackBlock);
}
} }
NativeThread nt; NativeThread nt;
@ -171,11 +182,64 @@ public:
ThreadContext context; ThreadContext context;
std::vector<CallbackNotification> callbacks; std::set<SceUID> registeredCallbacks[THREAD_CALLBACK_NUM_TYPES];
std::list<SceUID> readyCallbacks[THREAD_CALLBACK_NUM_TYPES];
u32 stackBlock; 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); 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 //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() u32 __KernelCallbackReturnAddress()
{ {
return cbReturnHackAddr; return cbReturnHackAddr;
@ -240,9 +310,9 @@ void __KernelThreadingInit()
eventScheduledWakeup = CoreTiming::RegisterEvent("ScheduledWakeup", &hleScheduledWakeup); eventScheduledWakeup = CoreTiming::RegisterEvent("ScheduledWakeup", &hleScheduledWakeup);
// Create the two idle threads, as well. With the absolute minimal possible priority. // 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. // 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, 0, PSP_THREAD_ATTR_KERNEL); __KernelCreateThread(threadIdleID[0], 0, "idle0", idleThreadHackAddr, 0x7f, 4096, PSP_THREAD_ATTR_KERNEL);
__KernelCreateThread(threadIdleID[1], 0, "idle1", idleThreadHackAddr, 0x7f, 0, 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. // 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<Thread>(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<Thread>(__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() void sceKernelReferThreadStatus()
{ {
SceUID threadID = PARAM(0); SceUID threadID = PARAM(0);
@ -472,6 +504,8 @@ bool __KernelTriggerWait(WaitType type, int id, bool dontSwitch)
{ {
t->nt.status = THREADSTATUS_READY; t->nt.status = THREADSTATUS_READY;
} }
// Non-waiting threads do not process callbacks.
t->isProcessingCallbacks = false;
doneAnything = true; doneAnything = true;
} }
} }
@ -548,7 +582,7 @@ void __KernelRemoveFromThreadQueue(Thread *t)
{ {
if (threadqueue[i] == 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); threadqueue.erase(threadqueue.begin() + i);
return; return;
} }
@ -705,7 +739,7 @@ Thread *__KernelCreateThread(SceUID &id, SceUID moduleID, const char *name, u32
strncpy(t->nt.name, name, 32); strncpy(t->nt.name, name, 32);
t->context.r[MIPS_REG_RA] = threadReturnHackAddr; //hack! TODO fix 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; return t;
} }
@ -792,6 +826,7 @@ u32 sceKernelStartThread()
//now copy argument to stack //now copy argument to stack
for (int i = 0; i < (int)argSize; i++) for (int i = 0; i < (int)argSize; i++)
Memory::Write_U8(Memory::Read_U8(argBlockPtr + i), sp + i); Memory::Write_U8(Memory::Read_U8(argBlockPtr + i), sp + i);
return 0; return 0;
} }
else else
@ -833,6 +868,8 @@ void _sceKernelReturnFromThread()
// Wake them // Wake them
if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread())) if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread()))
__KernelReSchedule("return from thread"); __KernelReSchedule("return from thread");
// The stack will be deallocated when the thread is deleted.
} }
void sceKernelExitThread() void sceKernelExitThread()
@ -844,6 +881,8 @@ void sceKernelExitThread()
// Wake them // Wake them
if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread())) if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread()))
__KernelReSchedule("exited thread"); __KernelReSchedule("exited thread");
// The stack will be deallocated when the thread is deleted.
} }
void _sceKernelExitThread() void _sceKernelExitThread()
@ -855,6 +894,8 @@ void _sceKernelExitThread()
// Wake them // Wake them
if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread())) if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread()))
__KernelReSchedule("exit-deleted thread"); __KernelReSchedule("exit-deleted thread");
// The stack will be deallocated when the thread is deleted.
} }
void sceKernelExitDeleteThread() void sceKernelExitDeleteThread()
@ -867,6 +908,8 @@ void sceKernelExitDeleteThread()
ERROR_LOG(HLE,"sceKernelExitDeleteThread()"); ERROR_LOG(HLE,"sceKernelExitDeleteThread()");
currentThread->nt.status = THREADSTATUS_DORMANT; currentThread->nt.status = THREADSTATUS_DORMANT;
currentThread->nt.exitStatus = PARAM(0); currentThread->nt.exitStatus = PARAM(0);
//userMemory.Free(currentThread->stackBlock);
currentThread->stackBlock = -1;
__KernelRemoveFromThreadQueue(t); __KernelRemoveFromThreadQueue(t);
currentThread = 0; currentThread = 0;
@ -989,6 +1032,7 @@ void sceKernelDelayThreadCB()
SceUID curThread = __KernelGetCurThread(); SceUID curThread = __KernelGetCurThread();
__KernelScheduleWakeup(curThread, usec); __KernelScheduleWakeup(curThread, usec);
__KernelWaitCurThread(WAITTYPE_DELAY, curThread, 0, 0, true); __KernelWaitCurThread(WAITTYPE_DELAY, curThread, 0, 0, true);
__KernelCheckCallbacks();
} }
void sceKernelDelayThread() void sceKernelDelayThread()
@ -1039,9 +1083,11 @@ void sceKernelSleepThreadCB()
DEBUG_LOG(HLE,"sceKernelSleepThreadCB()"); DEBUG_LOG(HLE,"sceKernelSleepThreadCB()");
//set it to waiting //set it to waiting
currentThread->nt.wakeupCount--; currentThread->nt.wakeupCount--;
DEBUG_LOG(HLE,"sceKernelSleepThread() - wakeupCount decremented to %i", currentThread->nt.wakeupCount); DEBUG_LOG(HLE,"sceKernelSleepThreadCB() - wakeupCount decremented to %i", currentThread->nt.wakeupCount);
if (currentThread->nt.wakeupCount < 0) if (currentThread->nt.wakeupCount < 0) {
__KernelWaitCurThread(WAITTYPE_SLEEP, 0, 0, 0, true); __KernelWaitCurThread(WAITTYPE_SLEEP, 0, 0, 0, true);
__KernelCheckCallbacks();
}
else else
{ {
RETURN(0); RETURN(0);
@ -1056,12 +1102,11 @@ void sceKernelWaitThreadEnd()
Thread *t = kernelObjects.Get<Thread>(id, error); Thread *t = kernelObjects.Get<Thread>(id, error);
if (t) if (t)
{ {
if (t->nt.status != THREADSTATUS_DORMANT) if (t->nt.status != THREADSTATUS_DORMANT) {
{
__KernelWaitCurThread(WAITTYPE_THREADEND, id, 0, 0, false); __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 else
{ {
@ -1078,12 +1123,12 @@ void sceKernelWaitThreadEndCB()
Thread *t = kernelObjects.Get<Thread>(id, error); Thread *t = kernelObjects.Get<Thread>(id, error);
if (t) if (t)
{ {
if (t->nt.status != THREADSTATUS_DORMANT) if (t->nt.status != THREADSTATUS_DORMANT) {
{
__KernelWaitCurThread(WAITTYPE_THREADEND, id, 0, 0, true); __KernelWaitCurThread(WAITTYPE_THREADEND, id, 0, 0, true);
return; } else {
} DEBUG_LOG(HLE,"sceKernelWaitThreadEnd - thread %i already ended. Doing nothing.", id);
DEBUG_LOG(HLE,"sceKernelWaitThreadEnd - thread %i already ended. Doing nothing.", id); }
__KernelCheckCallbacks();
} }
else else
{ {
@ -1103,3 +1148,303 @@ void sceKernelResumeThread()
DEBUG_LOG(HLE,"UNIMPL sceKernelResumeThread"); DEBUG_LOG(HLE,"UNIMPL sceKernelResumeThread");
RETURN(0); 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<Callback>(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<Callback>(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<Callback>(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<Callback>(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<Callback>(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<Callback>(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<Callback>(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<Thread *>::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<Callback>(cbId, error);
cb->nc.notifyCount++;
cb->nc.notifyArg = notifyArg;
Thread *t = kernelObjects.Get<Thread>(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<Thread *>::iterator iter = threadqueue.begin(); iter != threadqueue.end(); iter++) {
Thread *t = *iter;
for (std::set<SceUID>::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;
}

View file

@ -85,14 +85,6 @@ struct ThreadContext
u32 fcr31; u32 fcr31;
}; };
struct CallbackNotification
{
SceUID cbid;
int count;
int arg;
};
// Internal API, used by implementations of kernel functions // Internal API, used by implementations of kernel functions
void __KernelThreadingInit(); void __KernelThreadingInit();
@ -111,10 +103,30 @@ u32 __KernelResumeThread(SceUID threadID); // can return an error value
u32 __KernelGetWaitValue(SceUID threadID, u32 &error); u32 __KernelGetWaitValue(SceUID threadID, u32 &error);
void __KernelWaitCurThread(WaitType type, SceUID waitId, u32 waitValue, int timeout, bool processCallbacks); void __KernelWaitCurThread(WaitType type, SceUID waitId, u32 waitValue, int timeout, bool processCallbacks);
void __KernelReSchedule(const char *reason = "no reason"); 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(); 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 __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(); void __KernelStartIdleThreads();
@ -124,3 +136,20 @@ void _sceKernelIdle();
u32 __KernelCallbackReturnAddress(); u32 __KernelCallbackReturnAddress();
u32 __KernelInterruptReturnAddress(); 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();

View file

@ -77,6 +77,7 @@ void MIPSState::Reset()
SetWriteMask(b); SetWriteMask(b);
pc = 0; pc = 0;
prevPC = 0;
hi = 0; hi = 0;
lo = 0; lo = 0;
fpcond = 0; fpcond = 0;
@ -155,7 +156,7 @@ void MIPSState::RunLoopUntil(u64 globalTicks)
break; break;
} }
#endif #endif
// u32 lastpc = pc; prevPC = pc;
if (inDelaySlot) if (inDelaySlot)
{ {
MIPSInterpret(op); MIPSInterpret(op);

View file

@ -112,6 +112,7 @@ public:
u32 pc; u32 pc;
u32 nextPC; u32 nextPC;
u32 prevPC;
u32 hi; u32 hi;
u32 lo; u32 lo;

View file

@ -176,10 +176,14 @@ namespace MIPSInt
switch ((op>>16) & 0x1F) 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 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 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 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: default:
_dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted");
break; break;

View file

@ -344,10 +344,10 @@ const MIPSInstruction tableRegImm[32] =
INSTR("tnei", &Jit::Comp_Generic, Dis_Generic, 0, 0), INSTR("tnei", &Jit::Comp_Generic, Dis_Generic, 0, 0),
{-2}, {-2},
INSTR("bltzal", &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, 0, 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, 0, IS_CONDBRANCH|IN_RS|OUT_RA), //L = likely INSTR("bltzall", &Jit::Comp_Generic, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|OUT_RA), //L = likely
INSTR("bgezall", &Jit::Comp_Generic, Dis_RelBranch, 0, IS_CONDBRANCH|IN_RS|OUT_RA), INSTR("bgezall", &Jit::Comp_Generic, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|OUT_RA),
{-2}, {-2},
{-2}, {-2},
{-2}, {-2},

View file

@ -211,12 +211,15 @@ void Memcpy(const u32 _Address, const void *_Data, const u32 _iLength);
template<class T> template<class T>
void ReadStruct(u32 address, T *ptr) void ReadStruct(u32 address, T *ptr)
{ {
memcpy(ptr, GetPointer(address), sizeof(*ptr)); size_t sz = sizeof(*ptr);
memcpy(ptr, GetPointer(address), sz);
} }
template<class T> template<class T>
void WriteStruct(u32 address, T *ptr) 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); const char *GetAddressName(u32 address);

View file

@ -82,7 +82,7 @@ inline void ReadFromHardware(T &var, const u32 address)
} }
else 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) { if (!g_Config.bIgnoreBadMemAccess) {
// TODO: Not sure what the best way to crash is... // TODO: Not sure what the best way to crash is...
exit(0); exit(0);

View file

@ -30,7 +30,7 @@ void BlockAllocator::Shutdown()
u32 BlockAllocator::Alloc(u32 &size, bool fromTop, const char *tag) u32 BlockAllocator::Alloc(u32 &size, bool fromTop, const char *tag)
{ {
// Sanity check // Sanity check
if (size > rangeSize_) { if (size == 0 || size > rangeSize_) {
ERROR_LOG(HLE, "Clearly bogus size: %08x - failing allocation", size); ERROR_LOG(HLE, "Clearly bogus size: %08x - failing allocation", size);
return 0; return 0;
} }

2
native

@ -1 +1 @@
Subproject commit 8288c307cc896b40f9ad000db8f6b00c2b76ad0f Subproject commit 652045e46252c51f02196dcd6f769969fb8b3659