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

View file

@ -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))
{

View file

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

View file

@ -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"

View file

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

View file

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

View file

@ -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!
@ -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,9 +481,31 @@ 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.
@ -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?
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,37 +564,69 @@ 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);
}
break;
}
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;
}
}
}
if (!strcmp(name, "kemulator:") || !strcmp(name, "emulator:"))
@ -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);

View file

@ -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; i<maxCount; i++)
for (int i = 0; i < maxCount; i++)
{
if (occupied[i])
{
@ -248,6 +248,7 @@ void KernelObjectPool::List()
}
}
}
int KernelObjectPool::GetCount()
{
int count = 0;
@ -259,7 +260,6 @@ int KernelObjectPool::GetCount()
return count;
}
void sceKernelIcacheInvalidateAll()
{
DEBUG_LOG(CPU, "Icache cleared - should clear JIT someday");

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/.
#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);

View file

@ -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"},
};

View file

@ -147,6 +147,17 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
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)
{
ERROR_LOG(HLE, "Wrong magic number %08x",*(u32*)ptr);

View file

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

View file

@ -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 <set>
#include <queue>
#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 <queue>
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)
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,10 +163,15 @@ public:
context.r[MIPS_REG_SP] -= 512;
return true;
}
~Thread()
{
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<CallbackNotification> callbacks;
std::set<SceUID> registeredCallbacks[THREAD_CALLBACK_NUM_TYPES];
std::list<SceUID> 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<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()
{
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,13 +1102,12 @@ void sceKernelWaitThreadEnd()
Thread *t = kernelObjects.Get<Thread>(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);
}
}
else
{
ERROR_LOG(HLE,"sceKernelWaitThreadEnd - bad thread %i", id);
@ -1078,13 +1123,13 @@ void sceKernelWaitThreadEndCB()
Thread *t = kernelObjects.Get<Thread>(id, error);
if (t)
{
if (t->nt.status != THREADSTATUS_DORMANT)
{
if (t->nt.status != THREADSTATUS_DORMANT) {
__KernelWaitCurThread(WAITTYPE_THREADEND, id, 0, 0, true);
return;
}
} else {
DEBUG_LOG(HLE,"sceKernelWaitThreadEnd - thread %i already ended. Doing nothing.", id);
}
__KernelCheckCallbacks();
}
else
{
ERROR_LOG(HLE,"sceKernelWaitThreadEnd - bad thread %i", id);
@ -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<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;
};
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();

View file

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

View file

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

View file

@ -180,6 +180,10 @@ namespace MIPSInt
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;

View file

@ -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},

View file

@ -211,12 +211,15 @@ void Memcpy(const u32 _Address, const void *_Data, const u32 _iLength);
template<class T>
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>
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);

View file

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

View file

@ -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;
}

2
native

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