mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Expose PSPThread in the same manner
This commit is contained in:
parent
644f5e4e6c
commit
2bfe327dbd
13 changed files with 360 additions and 345 deletions
|
@ -2170,6 +2170,7 @@ add_library(${CoreLibName} ${CoreLinkType}
|
||||||
Core/HLE/HLETables.cpp
|
Core/HLE/HLETables.cpp
|
||||||
Core/HLE/HLETables.h
|
Core/HLE/HLETables.h
|
||||||
Core/HLE/KernelWaitHelpers.h
|
Core/HLE/KernelWaitHelpers.h
|
||||||
|
Core/HLE/PSPThreadContext.h
|
||||||
Core/HLE/KUBridge.h
|
Core/HLE/KUBridge.h
|
||||||
Core/HLE/KUBridge.cpp
|
Core/HLE/KUBridge.cpp
|
||||||
Core/HLE/Plugins.h
|
Core/HLE/Plugins.h
|
||||||
|
|
|
@ -1,21 +1,18 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstddef>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
typedef std::pair<uint32_t, uint32_t> ExpressionPair;
|
typedef std::pair<uint32_t, uint32_t> ExpressionPair;
|
||||||
typedef std::vector<ExpressionPair> PostfixExpression;
|
typedef std::vector<ExpressionPair> PostfixExpression;
|
||||||
|
|
||||||
enum ExpressionType
|
enum ExpressionType {
|
||||||
{
|
|
||||||
EXPR_TYPE_UINT = 0,
|
EXPR_TYPE_UINT = 0,
|
||||||
EXPR_TYPE_FLOAT = 2,
|
EXPR_TYPE_FLOAT = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
class IExpressionFunctions
|
class IExpressionFunctions {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
virtual ~IExpressionFunctions() {}
|
virtual ~IExpressionFunctions() {}
|
||||||
virtual bool parseReference(char* str, uint32_t& referenceIndex) = 0;
|
virtual bool parseReference(char* str, uint32_t& referenceIndex) = 0;
|
||||||
|
|
|
@ -1195,6 +1195,7 @@
|
||||||
<ClInclude Include="HLE\KUBridge.h" />
|
<ClInclude Include="HLE\KUBridge.h" />
|
||||||
<ClInclude Include="HLE\NetInetConstants.h" />
|
<ClInclude Include="HLE\NetInetConstants.h" />
|
||||||
<ClInclude Include="HLE\Plugins.h" />
|
<ClInclude Include="HLE\Plugins.h" />
|
||||||
|
<ClInclude Include="HLE\PSPThreadContext.h" />
|
||||||
<ClInclude Include="HLE\sceAac.h" />
|
<ClInclude Include="HLE\sceAac.h" />
|
||||||
<ClInclude Include="HLE\sceKernelHeap.h" />
|
<ClInclude Include="HLE\sceKernelHeap.h" />
|
||||||
<ClInclude Include="HLE\sceNetApctl.h" />
|
<ClInclude Include="HLE\sceNetApctl.h" />
|
||||||
|
|
|
@ -2178,6 +2178,9 @@
|
||||||
<ClInclude Include="LuaContext.h">
|
<ClInclude Include="LuaContext.h">
|
||||||
<Filter>Core</Filter>
|
<Filter>Core</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="HLE\PSPThreadContext.h">
|
||||||
|
<Filter>HLE\Kernel</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\LICENSE.TXT" />
|
<None Include="..\LICENSE.TXT" />
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include "Core/MIPS/MIPSDebugInterface.h"
|
#include "Core/MIPS/MIPSDebugInterface.h"
|
||||||
|
#include "Common/Math/expression_parser.h"
|
||||||
|
|
||||||
enum BreakAction : u32 {
|
enum BreakAction : u32 {
|
||||||
BREAK_ACTION_IGNORE = 0x00,
|
BREAK_ACTION_IGNORE = 0x00,
|
||||||
|
|
|
@ -18,9 +18,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include "Core/HLE/sceKernelThread.h"
|
#include "Core/HLE/PSPThreadContext.h"
|
||||||
#include "Core/MIPS/MIPSDebugInterface.h"
|
#include "Core/MIPS/MIPSDebugInterface.h"
|
||||||
|
|
||||||
|
struct PSPThreadContext;
|
||||||
|
|
||||||
class KernelThreadDebugInterface : public DebugInterface {
|
class KernelThreadDebugInterface : public DebugInterface {
|
||||||
public:
|
public:
|
||||||
KernelThreadDebugInterface(PSPThreadContext &t) : ctx(t) {}
|
KernelThreadDebugInterface(PSPThreadContext &t) : ctx(t) {}
|
||||||
|
|
35
Core/HLE/PSPThreadContext.h
Normal file
35
Core/HLE/PSPThreadContext.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Had to break this out into its own header to solve a circular include issue.
|
||||||
|
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
struct PSPThreadContext {
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
// r must be followed by f.
|
||||||
|
u32 r[32];
|
||||||
|
union {
|
||||||
|
float f[32];
|
||||||
|
u32 fi[32];
|
||||||
|
int fs[32];
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
float v[128];
|
||||||
|
u32 vi[128];
|
||||||
|
};
|
||||||
|
u32 vfpuCtrl[16];
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
u32 pc;
|
||||||
|
|
||||||
|
u32 lo;
|
||||||
|
u32 hi;
|
||||||
|
|
||||||
|
u32 fcr31;
|
||||||
|
u32 fpcond;
|
||||||
|
};
|
||||||
|
u32 other[6];
|
||||||
|
};
|
||||||
|
};
|
|
@ -74,11 +74,6 @@
|
||||||
#include "GPU/GPUCommon.h"
|
#include "GPU/GPUCommon.h"
|
||||||
#include "GPU/GPUState.h"
|
#include "GPU/GPUState.h"
|
||||||
|
|
||||||
enum {
|
|
||||||
PSP_THREAD_ATTR_KERNEL = 0x00001000,
|
|
||||||
PSP_THREAD_ATTR_USER = 0x80000000,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum : u32 {
|
enum : u32 {
|
||||||
// Function exports.
|
// Function exports.
|
||||||
NID_MODULE_START = 0xD632ACDB,
|
NID_MODULE_START = 0xD632ACDB,
|
||||||
|
|
|
@ -105,23 +105,6 @@ enum ThreadEventType {
|
||||||
|
|
||||||
bool __KernelThreadTriggerEvent(bool isKernel, SceUID threadID, ThreadEventType type);
|
bool __KernelThreadTriggerEvent(bool isKernel, SceUID threadID, ThreadEventType type);
|
||||||
|
|
||||||
enum {
|
|
||||||
PSP_THREAD_ATTR_KERNEL = 0x00001000,
|
|
||||||
PSP_THREAD_ATTR_VFPU = 0x00004000,
|
|
||||||
PSP_THREAD_ATTR_SCRATCH_SRAM = 0x00008000, // Save/restore scratch as part of context???
|
|
||||||
PSP_THREAD_ATTR_NO_FILLSTACK = 0x00100000, // No filling of 0xff.
|
|
||||||
PSP_THREAD_ATTR_CLEAR_STACK = 0x00200000, // Clear thread stack when deleted.
|
|
||||||
PSP_THREAD_ATTR_LOW_STACK = 0x00400000, // Allocate stack from bottom not top.
|
|
||||||
PSP_THREAD_ATTR_USER = 0x80000000,
|
|
||||||
PSP_THREAD_ATTR_USBWLAN = 0xa0000000,
|
|
||||||
PSP_THREAD_ATTR_VSH = 0xc0000000,
|
|
||||||
|
|
||||||
// TODO: Support more, not even sure what all of these mean.
|
|
||||||
PSP_THREAD_ATTR_USER_MASK = 0xf8f060ff,
|
|
||||||
PSP_THREAD_ATTR_USER_ERASE = 0x78800000,
|
|
||||||
PSP_THREAD_ATTR_SUPPORTED = (PSP_THREAD_ATTR_KERNEL | PSP_THREAD_ATTR_VFPU | PSP_THREAD_ATTR_NO_FILLSTACK | PSP_THREAD_ATTR_CLEAR_STACK | PSP_THREAD_ATTR_LOW_STACK | PSP_THREAD_ATTR_USER)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NativeCallback
|
struct NativeCallback
|
||||||
{
|
{
|
||||||
SceUInt_le size;
|
SceUInt_le size;
|
||||||
|
@ -173,58 +156,6 @@ public:
|
||||||
NativeCallback nc;
|
NativeCallback nc;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if COMMON_LITTLE_ENDIAN
|
|
||||||
typedef WaitType WaitType_le;
|
|
||||||
#else
|
|
||||||
typedef swap_struct_t<WaitType, swap_32_t<WaitType> > WaitType_le;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Real PSP struct, don't change the fields.
|
|
||||||
struct SceKernelThreadRunStatus
|
|
||||||
{
|
|
||||||
SceSize_le size;
|
|
||||||
u32_le status;
|
|
||||||
s32_le currentPriority;
|
|
||||||
WaitType_le waitType;
|
|
||||||
SceUID_le waitID;
|
|
||||||
s32_le wakeupCount;
|
|
||||||
SceKernelSysClock runForClocks;
|
|
||||||
s32_le numInterruptPreempts;
|
|
||||||
s32_le numThreadPreempts;
|
|
||||||
s32_le numReleases;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Real PSP struct, don't change the fields.
|
|
||||||
struct NativeThread
|
|
||||||
{
|
|
||||||
u32_le nativeSize;
|
|
||||||
char name[KERNELOBJECT_MAX_NAME_LENGTH+1];
|
|
||||||
|
|
||||||
// Threading stuff
|
|
||||||
u32_le attr;
|
|
||||||
u32_le status;
|
|
||||||
u32_le entrypoint;
|
|
||||||
u32_le initialStack;
|
|
||||||
u32_le stackSize;
|
|
||||||
u32_le gpreg;
|
|
||||||
|
|
||||||
s32_le initialPriority;
|
|
||||||
s32_le currentPriority;
|
|
||||||
WaitType_le waitType;
|
|
||||||
SceUID_le waitID;
|
|
||||||
s32_le wakeupCount;
|
|
||||||
s32_le exitStatus;
|
|
||||||
SceKernelSysClock runForClocks;
|
|
||||||
s32_le numInterruptPreempts;
|
|
||||||
s32_le numThreadPreempts;
|
|
||||||
s32_le numReleases;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ThreadWaitInfo {
|
|
||||||
u32 waitValue;
|
|
||||||
u32 timeoutPtr;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Owns outstanding MIPS calls and provides a way to get them by ID.
|
// Owns outstanding MIPS calls and provides a way to get them by ID.
|
||||||
class MipsCallManager {
|
class MipsCallManager {
|
||||||
public:
|
public:
|
||||||
|
@ -344,8 +275,7 @@ public:
|
||||||
PSPAction *chainedAction;
|
PSPAction *chainedAction;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ActionAfterCallback : public PSPAction
|
class ActionAfterCallback : public PSPAction {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
ActionAfterCallback() {}
|
ActionAfterCallback() {}
|
||||||
void run(MipsCall &call) override;
|
void run(MipsCall &call) override;
|
||||||
|
@ -354,13 +284,11 @@ public:
|
||||||
return new ActionAfterCallback;
|
return new ActionAfterCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCallback(SceUID cbId_)
|
void setCallback(SceUID cbId_) {
|
||||||
{
|
|
||||||
cbId = cbId_;
|
cbId = cbId_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoState(PointerWrap &p) override
|
void DoState(PointerWrap &p) override {
|
||||||
{
|
|
||||||
auto s = p.Section("ActionAfterCallback", 1);
|
auto s = p.Section("ActionAfterCallback", 1);
|
||||||
if (!s)
|
if (!s)
|
||||||
return;
|
return;
|
||||||
|
@ -371,14 +299,11 @@ public:
|
||||||
SceUID cbId;
|
SceUID cbId;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PSPThread : public KernelObject {
|
u32 PSPThread::GetMissingErrorCode() {
|
||||||
public:
|
return SCE_KERNEL_ERROR_UNKNOWN_THID;
|
||||||
PSPThread() : debug(context) {}
|
}
|
||||||
|
|
||||||
const char *GetName() override { return nt.name; }
|
void PSPThread::GetQuickInfo(char *ptr, int size) {
|
||||||
const char *GetTypeName() override { return GetStaticTypeName(); }
|
|
||||||
static const char *GetStaticTypeName() { return "Thread"; }
|
|
||||||
void GetQuickInfo(char *ptr, int size) override {
|
|
||||||
snprintf(ptr, size, "pc= %08x sp= %08x %s %s %s %s %s %s (wt=%i wid=%i wv= %08x )",
|
snprintf(ptr, size, "pc= %08x sp= %08x %s %s %s %s %s %s (wt=%i wid=%i wv= %08x )",
|
||||||
context.pc, context.r[MIPS_REG_SP],
|
context.pc, context.r[MIPS_REG_SP],
|
||||||
(nt.status & THREADSTATUS_RUNNING) ? "RUN" : "",
|
(nt.status & THREADSTATUS_RUNNING) ? "RUN" : "",
|
||||||
|
@ -390,13 +315,16 @@ public:
|
||||||
(int)nt.waitType,
|
(int)nt.waitType,
|
||||||
nt.waitID,
|
nt.waitID,
|
||||||
waitInfo.waitValue);
|
waitInfo.waitValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockAllocator &PSPThread::StackAllocator() {
|
||||||
|
if (nt.attr & PSP_THREAD_ATTR_KERNEL) {
|
||||||
|
return kernelMemory;
|
||||||
}
|
}
|
||||||
|
return userMemory;
|
||||||
|
}
|
||||||
|
|
||||||
static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_THID; }
|
bool PSPThread::AllocateStack(u32 &stackSize) {
|
||||||
static int GetStaticIDType() { return SCE_KERNEL_TMID_Thread; }
|
|
||||||
int GetIDType() const override { return SCE_KERNEL_TMID_Thread; }
|
|
||||||
|
|
||||||
bool AllocateStack(u32 &stackSize) {
|
|
||||||
_assert_msg_(stackSize >= 0x200, "thread stack should be 256 bytes or larger");
|
_assert_msg_(stackSize >= 0x200, "thread stack should be 256 bytes or larger");
|
||||||
|
|
||||||
FreeStack();
|
FreeStack();
|
||||||
|
@ -414,9 +342,9 @@ public:
|
||||||
nt.initialStack = currentStack.start;
|
nt.initialStack = currentStack.start;
|
||||||
nt.stackSize = stackSize;
|
nt.stackSize = stackSize;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FillStack() {
|
bool PSPThread::FillStack() {
|
||||||
// Fill the stack.
|
// Fill the stack.
|
||||||
if ((nt.attr & PSP_THREAD_ATTR_NO_FILLSTACK) == 0) {
|
if ((nt.attr & PSP_THREAD_ATTR_NO_FILLSTACK) == 0) {
|
||||||
Memory::Memset(currentStack.start, 0xFF, nt.stackSize, "ThreadFillStack");
|
Memory::Memset(currentStack.start, 0xFF, nt.stackSize, "ThreadFillStack");
|
||||||
|
@ -436,9 +364,9 @@ public:
|
||||||
|
|
||||||
Memory::Write_U32(GetUID(), nt.initialStack);
|
Memory::Write_U32(GetUID(), nt.initialStack);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeStack() {
|
void PSPThread::FreeStack() {
|
||||||
if (currentStack.start != 0) {
|
if (currentStack.start != 0) {
|
||||||
DEBUG_LOG(Log::sceKernel, "Freeing thread stack %s", nt.name);
|
DEBUG_LOG(Log::sceKernel, "Freeing thread stack %s", nt.name);
|
||||||
|
|
||||||
|
@ -449,10 +377,9 @@ public:
|
||||||
StackAllocator().Free(currentStack.start);
|
StackAllocator().Free(currentStack.start);
|
||||||
currentStack.start = 0;
|
currentStack.start = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PushExtendedStack(u32 size)
|
bool PSPThread::PushExtendedStack(u32 size) {
|
||||||
{
|
|
||||||
u32 stack = userMemory.Alloc(size, true, StringFromFormat("extended/%s", nt.name).c_str());
|
u32 stack = userMemory.Alloc(size, true, StringFromFormat("extended/%s", nt.name).c_str());
|
||||||
if (stack == (u32)-1)
|
if (stack == (u32)-1)
|
||||||
return false;
|
return false;
|
||||||
|
@ -467,10 +394,9 @@ public:
|
||||||
Memory::Memset(currentStack.start, 0xFF, nt.stackSize, "ThreadExtendStack");
|
Memory::Memset(currentStack.start, 0xFF, nt.stackSize, "ThreadExtendStack");
|
||||||
Memory::Write_U32(GetUID(), nt.initialStack);
|
Memory::Write_U32(GetUID(), nt.initialStack);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PopExtendedStack()
|
bool PSPThread::PopExtendedStack() {
|
||||||
{
|
|
||||||
if (pushedStacks.size() == 0)
|
if (pushedStacks.size() == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -480,47 +406,22 @@ public:
|
||||||
nt.initialStack = currentStack.start;
|
nt.initialStack = currentStack.start;
|
||||||
nt.stackSize = currentStack.end - currentStack.start;
|
nt.stackSize = currentStack.end - currentStack.start;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Can't use a destructor since savestates will call that too.
|
void PSPThread::Cleanup() {
|
||||||
void Cleanup()
|
|
||||||
{
|
|
||||||
// Callbacks are automatically deleted when their owning thread is deleted.
|
// Callbacks are automatically deleted when their owning thread is deleted.
|
||||||
for (auto it = callbacks.begin(), end = callbacks.end(); it != end; ++it)
|
for (auto it = callbacks.begin(), end = callbacks.end(); it != end; ++it)
|
||||||
kernelObjects.Destroy<PSPCallback>(*it);
|
kernelObjects.Destroy<PSPCallback>(*it);
|
||||||
|
|
||||||
if (pushedStacks.size() != 0)
|
if (pushedStacks.size() != 0) {
|
||||||
{
|
|
||||||
WARN_LOG_REPORT(Log::sceKernel, "Thread ended within an extended stack");
|
WARN_LOG_REPORT(Log::sceKernel, "Thread ended within an extended stack");
|
||||||
for (size_t i = 0; i < pushedStacks.size(); ++i)
|
for (size_t i = 0; i < pushedStacks.size(); ++i)
|
||||||
userMemory.Free(pushedStacks[i].start);
|
userMemory.Free(pushedStacks[i].start);
|
||||||
}
|
}
|
||||||
FreeStack();
|
FreeStack();
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockAllocator &StackAllocator() {
|
void PSPThread::DoState(PointerWrap &p) {
|
||||||
if (nt.attr & PSP_THREAD_ATTR_KERNEL) {
|
|
||||||
return kernelMemory;
|
|
||||||
}
|
|
||||||
return userMemory;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setReturnValue(u32 retval);
|
|
||||||
void setReturnValue(u64 retval);
|
|
||||||
void resumeFromWait();
|
|
||||||
bool isWaitingFor(WaitType type, int id) const;
|
|
||||||
int getWaitID(WaitType type) const;
|
|
||||||
ThreadWaitInfo getWaitInfo() const;
|
|
||||||
|
|
||||||
// Utils
|
|
||||||
inline bool isRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; }
|
|
||||||
inline bool isStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; }
|
|
||||||
inline bool isReady() const { return (nt.status & THREADSTATUS_READY) != 0; }
|
|
||||||
inline bool isWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; }
|
|
||||||
inline bool isSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; }
|
|
||||||
|
|
||||||
void DoState(PointerWrap &p) override
|
|
||||||
{
|
|
||||||
auto s = p.Section("Thread", 1, 5);
|
auto s = p.Section("Thread", 1, 5);
|
||||||
if (!s)
|
if (!s)
|
||||||
return;
|
return;
|
||||||
|
@ -535,8 +436,7 @@ public:
|
||||||
// TODO: If we want to "version" a DoState method here, we can just use minVer = 0.
|
// TODO: If we want to "version" a DoState method here, we can just use minVer = 0.
|
||||||
Do(p, context);
|
Do(p, context);
|
||||||
|
|
||||||
if (s <= 3)
|
if (s <= 3) {
|
||||||
{
|
|
||||||
// We must have been loading an old state if we're here.
|
// We must have been loading an old state if we're here.
|
||||||
// Reorder VFPU data to new order.
|
// Reorder VFPU data to new order.
|
||||||
float temp[128];
|
float temp[128];
|
||||||
|
@ -546,8 +446,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s <= 2)
|
if (s <= 2) {
|
||||||
{
|
|
||||||
context.other[4] = context.other[5];
|
context.other[4] = context.other[5];
|
||||||
context.other[3] = context.other[4];
|
context.other[3] = context.other[4];
|
||||||
}
|
}
|
||||||
|
@ -560,44 +459,12 @@ public:
|
||||||
Do(p, pushedStacks);
|
Do(p, pushedStacks);
|
||||||
Do(p, currentStack);
|
Do(p, currentStack);
|
||||||
|
|
||||||
if (s >= 2)
|
if (s >= 2) {
|
||||||
{
|
|
||||||
Do(p, waitingThreads);
|
Do(p, waitingThreads);
|
||||||
Do(p, pausedWaits);
|
Do(p, pausedWaits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NativeThread nt{};
|
|
||||||
|
|
||||||
ThreadWaitInfo waitInfo{};
|
|
||||||
SceUID moduleId = -1;
|
|
||||||
|
|
||||||
bool isProcessingCallbacks = false;
|
|
||||||
u32 currentMipscallId = -1;
|
|
||||||
SceUID currentCallbackId = -1;
|
|
||||||
|
|
||||||
PSPThreadContext context{};
|
|
||||||
KernelThreadDebugInterface debug;
|
|
||||||
|
|
||||||
std::vector<SceUID> callbacks;
|
|
||||||
|
|
||||||
std::list<u32> pendingMipsCalls;
|
|
||||||
|
|
||||||
struct StackInfo {
|
|
||||||
u32 start;
|
|
||||||
u32 end;
|
|
||||||
};
|
|
||||||
// This is a stack of... stacks, since sceKernelExtendThreadStack() can recurse.
|
|
||||||
// These are stacks that aren't "active" right now, but will pop off once the func returns.
|
|
||||||
std::vector<StackInfo> pushedStacks;
|
|
||||||
|
|
||||||
StackInfo currentStack{};
|
|
||||||
|
|
||||||
// For thread end.
|
|
||||||
std::vector<SceUID> waitingThreads;
|
|
||||||
// Key is the callback id it was for, or if no callback, the thread id.
|
|
||||||
std::map<SceUID, u64> pausedWaits;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WaitTypeFuncs
|
struct WaitTypeFuncs
|
||||||
{
|
{
|
||||||
|
@ -3104,7 +2971,20 @@ void __KernelChangeThreadState(PSPThread *thread, ThreadStatus newStatus) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *ThreadStatusToString(ThreadStatus status) {
|
||||||
|
switch (status) {
|
||||||
|
case THREADSTATUS_RUNNING: return "Running";
|
||||||
|
case THREADSTATUS_READY: return "Ready";
|
||||||
|
case THREADSTATUS_WAIT: return "Wait";
|
||||||
|
case THREADSTATUS_SUSPEND: return "Suspended";
|
||||||
|
case THREADSTATUS_DORMANT: return "Dormant";
|
||||||
|
case THREADSTATUS_DEAD: return "Dead";
|
||||||
|
case THREADSTATUS_WAITSUSPEND: return "WaitSuspended";
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return "(unk)";
|
||||||
|
}
|
||||||
|
|
||||||
static bool __CanExecuteCallbackNow(PSPThread *thread) {
|
static bool __CanExecuteCallbackNow(PSPThread *thread) {
|
||||||
return currentCallbackThreadID == 0 && g_inCbCount == 0;
|
return currentCallbackThreadID == 0 && g_inCbCount == 0;
|
||||||
|
@ -3540,7 +3420,7 @@ std::vector<DebugThreadInfo> GetThreadsInfo() {
|
||||||
info.id = uid;
|
info.id = uid;
|
||||||
strncpy(info.name,t->GetName(),KERNELOBJECT_MAX_NAME_LENGTH);
|
strncpy(info.name,t->GetName(),KERNELOBJECT_MAX_NAME_LENGTH);
|
||||||
info.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0;
|
info.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0;
|
||||||
info.status = t->nt.status;
|
info.status = (ThreadStatus)t->nt.status;
|
||||||
info.entrypoint = t->nt.entrypoint;
|
info.entrypoint = t->nt.entrypoint;
|
||||||
info.initialStack = t->nt.initialStack;
|
info.initialStack = t->nt.initialStack;
|
||||||
info.stackSize = (u32)t->nt.stackSize;
|
info.stackSize = (u32)t->nt.stackSize;
|
||||||
|
|
|
@ -19,15 +19,20 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Core/HLE/sceKernel.h"
|
#include "Core/HLE/sceKernel.h"
|
||||||
|
#include "Core/HLE/PSPThreadContext.h"
|
||||||
|
#include "Core/HLE/KernelThreadDebugInterface.h"
|
||||||
|
|
||||||
// There's a good description of the thread scheduling rules in:
|
// There's a good description of the thread scheduling rules in:
|
||||||
// http://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/HLE/modules150/ThreadManForUser.java
|
// http://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/HLE/modules150/ThreadManForUser.java
|
||||||
|
|
||||||
class PSPThread;
|
class PSPThread;
|
||||||
class DebugInterface;
|
class DebugInterface;
|
||||||
|
class BlockAllocator;
|
||||||
|
|
||||||
int sceKernelChangeThreadPriority(SceUID threadID, int priority);
|
int sceKernelChangeThreadPriority(SceUID threadID, int priority);
|
||||||
SceUID __KernelCreateThreadInternal(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr);
|
SceUID __KernelCreateThreadInternal(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr);
|
||||||
|
@ -82,8 +87,7 @@ struct SceKernelSysClock {
|
||||||
|
|
||||||
// TODO: Map these to PSP wait types. Most of these are wrong.
|
// TODO: Map these to PSP wait types. Most of these are wrong.
|
||||||
// remember to update the waitTypeNames array in sceKernelThread.cpp when changing these
|
// remember to update the waitTypeNames array in sceKernelThread.cpp when changing these
|
||||||
enum WaitType : int
|
enum WaitType : int {
|
||||||
{
|
|
||||||
WAITTYPE_NONE = 0,
|
WAITTYPE_NONE = 0,
|
||||||
WAITTYPE_SLEEP = 1,
|
WAITTYPE_SLEEP = 1,
|
||||||
WAITTYPE_DELAY = 2,
|
WAITTYPE_DELAY = 2,
|
||||||
|
@ -124,34 +128,156 @@ typedef void (* WaitEndCallbackFunc)(SceUID threadID, SceUID prevCallbackId);
|
||||||
|
|
||||||
void __KernelRegisterWaitTypeFuncs(WaitType type, WaitBeginCallbackFunc beginFunc, WaitEndCallbackFunc endFunc);
|
void __KernelRegisterWaitTypeFuncs(WaitType type, WaitBeginCallbackFunc beginFunc, WaitEndCallbackFunc endFunc);
|
||||||
|
|
||||||
struct PSPThreadContext {
|
#if COMMON_LITTLE_ENDIAN
|
||||||
void reset();
|
typedef WaitType WaitType_le;
|
||||||
|
#else
|
||||||
|
typedef swap_struct_t<WaitType, swap_32_t<WaitType> > WaitType_le;
|
||||||
|
#endif
|
||||||
|
|
||||||
// r must be followed by f.
|
// Real PSP struct, don't change the fields.
|
||||||
u32 r[32];
|
struct SceKernelThreadRunStatus {
|
||||||
union {
|
SceSize_le size;
|
||||||
float f[32];
|
u32_le status;
|
||||||
u32 fi[32];
|
s32_le currentPriority;
|
||||||
int fs[32];
|
WaitType_le waitType;
|
||||||
};
|
SceUID_le waitID;
|
||||||
union {
|
s32_le wakeupCount;
|
||||||
float v[128];
|
SceKernelSysClock runForClocks;
|
||||||
u32 vi[128];
|
s32_le numInterruptPreempts;
|
||||||
};
|
s32_le numThreadPreempts;
|
||||||
u32 vfpuCtrl[16];
|
s32_le numReleases;
|
||||||
|
};
|
||||||
|
|
||||||
union {
|
// Real PSP struct, don't change the fields.
|
||||||
struct {
|
struct NativeThread {
|
||||||
u32 pc;
|
u32_le nativeSize;
|
||||||
|
char name[KERNELOBJECT_MAX_NAME_LENGTH + 1];
|
||||||
|
|
||||||
u32 lo;
|
// Threading stuff
|
||||||
u32 hi;
|
u32_le attr;
|
||||||
|
u32_le status;
|
||||||
|
u32_le entrypoint;
|
||||||
|
u32_le initialStack;
|
||||||
|
u32_le stackSize;
|
||||||
|
u32_le gpreg;
|
||||||
|
|
||||||
u32 fcr31;
|
s32_le initialPriority;
|
||||||
u32 fpcond;
|
s32_le currentPriority;
|
||||||
};
|
WaitType_le waitType;
|
||||||
u32 other[6];
|
SceUID_le waitID;
|
||||||
|
s32_le wakeupCount;
|
||||||
|
s32_le exitStatus;
|
||||||
|
SceKernelSysClock runForClocks;
|
||||||
|
s32_le numInterruptPreempts;
|
||||||
|
s32_le numThreadPreempts;
|
||||||
|
s32_le numReleases;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ThreadWaitInfo {
|
||||||
|
u32 waitValue;
|
||||||
|
u32 timeoutPtr;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PSP_THREAD_ATTR_KERNEL = 0x00001000,
|
||||||
|
PSP_THREAD_ATTR_VFPU = 0x00004000,
|
||||||
|
PSP_THREAD_ATTR_SCRATCH_SRAM = 0x00008000, // Save/restore scratch as part of context???
|
||||||
|
PSP_THREAD_ATTR_NO_FILLSTACK = 0x00100000, // No filling of 0xff.
|
||||||
|
PSP_THREAD_ATTR_CLEAR_STACK = 0x00200000, // Clear thread stack when deleted.
|
||||||
|
PSP_THREAD_ATTR_LOW_STACK = 0x00400000, // Allocate stack from bottom not top.
|
||||||
|
PSP_THREAD_ATTR_USER = 0x80000000,
|
||||||
|
PSP_THREAD_ATTR_USBWLAN = 0xa0000000,
|
||||||
|
PSP_THREAD_ATTR_VSH = 0xc0000000,
|
||||||
|
|
||||||
|
// TODO: Support more, not even sure what all of these mean.
|
||||||
|
PSP_THREAD_ATTR_USER_MASK = 0xf8f060ff,
|
||||||
|
PSP_THREAD_ATTR_USER_ERASE = 0x78800000,
|
||||||
|
PSP_THREAD_ATTR_SUPPORTED = (PSP_THREAD_ATTR_KERNEL | PSP_THREAD_ATTR_VFPU | PSP_THREAD_ATTR_NO_FILLSTACK | PSP_THREAD_ATTR_CLEAR_STACK | PSP_THREAD_ATTR_LOW_STACK | PSP_THREAD_ATTR_USER)
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ThreadStatus : u32 {
|
||||||
|
THREADSTATUS_RUNNING = 1,
|
||||||
|
THREADSTATUS_READY = 2,
|
||||||
|
THREADSTATUS_WAIT = 4,
|
||||||
|
THREADSTATUS_SUSPEND = 8,
|
||||||
|
THREADSTATUS_DORMANT = 16,
|
||||||
|
THREADSTATUS_DEAD = 32,
|
||||||
|
|
||||||
|
THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND
|
||||||
|
};
|
||||||
|
const char *ThreadStatusToString(ThreadStatus status);
|
||||||
|
|
||||||
|
class PSPThread : public KernelObject {
|
||||||
|
public:
|
||||||
|
PSPThread() : debug(context) {}
|
||||||
|
const char *GetName() override { return nt.name; }
|
||||||
|
const char *GetTypeName() override { return GetStaticTypeName(); }
|
||||||
|
static const char *GetStaticTypeName() { return "Thread"; }
|
||||||
|
void GetQuickInfo(char *ptr, int size) override;
|
||||||
|
|
||||||
|
static u32 GetMissingErrorCode();
|
||||||
|
static int GetStaticIDType() { return SCE_KERNEL_TMID_Thread; }
|
||||||
|
int GetIDType() const override { return SCE_KERNEL_TMID_Thread; }
|
||||||
|
|
||||||
|
bool AllocateStack(u32 &stackSize);
|
||||||
|
bool FillStack();
|
||||||
|
void FreeStack();
|
||||||
|
|
||||||
|
bool PushExtendedStack(u32 size);
|
||||||
|
bool PopExtendedStack();
|
||||||
|
|
||||||
|
// Can't use a destructor since savestates will call that too.
|
||||||
|
void Cleanup();
|
||||||
|
|
||||||
|
BlockAllocator &StackAllocator();
|
||||||
|
|
||||||
|
void setReturnValue(u32 retval);
|
||||||
|
void setReturnValue(u64 retval);
|
||||||
|
void resumeFromWait();
|
||||||
|
bool isWaitingFor(WaitType type, int id) const;
|
||||||
|
int getWaitID(WaitType type) const;
|
||||||
|
ThreadWaitInfo getWaitInfo() const;
|
||||||
|
|
||||||
|
// Utils
|
||||||
|
inline bool isRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; }
|
||||||
|
inline bool isStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; }
|
||||||
|
inline bool isReady() const { return (nt.status & THREADSTATUS_READY) != 0; }
|
||||||
|
inline bool isWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; }
|
||||||
|
inline bool isSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; }
|
||||||
|
|
||||||
|
void DoState(PointerWrap &p) override;
|
||||||
|
|
||||||
|
NativeThread nt{};
|
||||||
|
|
||||||
|
ThreadWaitInfo waitInfo{};
|
||||||
|
SceUID moduleId = -1;
|
||||||
|
KernelThreadDebugInterface debug;
|
||||||
|
|
||||||
|
bool isProcessingCallbacks = false;
|
||||||
|
u32 currentMipscallId = -1;
|
||||||
|
SceUID currentCallbackId = -1;
|
||||||
|
|
||||||
|
PSPThreadContext context{};
|
||||||
|
|
||||||
|
std::vector<SceUID> callbacks;
|
||||||
|
|
||||||
|
// TODO: Should probably just be a vector.
|
||||||
|
std::list<u32> pendingMipsCalls;
|
||||||
|
|
||||||
|
struct StackInfo {
|
||||||
|
u32 start;
|
||||||
|
u32 end;
|
||||||
};
|
};
|
||||||
|
// This is a stack of... stacks, since sceKernelExtendThreadStack() can recurse.
|
||||||
|
// These are stacks that aren't "active" right now, but will pop off once the func returns.
|
||||||
|
std::vector<StackInfo> pushedStacks;
|
||||||
|
|
||||||
|
StackInfo currentStack{};
|
||||||
|
|
||||||
|
// For thread end.
|
||||||
|
std::vector<SceUID> waitingThreads;
|
||||||
|
// Key is the callback id it was for, or if no callback, the thread id.
|
||||||
|
std::map<SceUID, u64> pausedWaits;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Internal API, used by implementations of kernel functions
|
// Internal API, used by implementations of kernel functions
|
||||||
|
@ -296,18 +422,6 @@ public:
|
||||||
int actionTypeID;
|
int actionTypeID;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ThreadStatus
|
|
||||||
{
|
|
||||||
THREADSTATUS_RUNNING = 1,
|
|
||||||
THREADSTATUS_READY = 2,
|
|
||||||
THREADSTATUS_WAIT = 4,
|
|
||||||
THREADSTATUS_SUSPEND = 8,
|
|
||||||
THREADSTATUS_DORMANT = 16,
|
|
||||||
THREADSTATUS_DEAD = 32,
|
|
||||||
|
|
||||||
THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND
|
|
||||||
};
|
|
||||||
|
|
||||||
void __KernelChangeThreadState(PSPThread *thread, ThreadStatus newStatus);
|
void __KernelChangeThreadState(PSPThread *thread, ThreadStatus newStatus);
|
||||||
|
|
||||||
typedef void (*ThreadCallback)(SceUID threadID);
|
typedef void (*ThreadCallback)(SceUID threadID);
|
||||||
|
@ -317,7 +431,7 @@ struct DebugThreadInfo
|
||||||
{
|
{
|
||||||
SceUID id;
|
SceUID id;
|
||||||
char name[KERNELOBJECT_MAX_NAME_LENGTH+1];
|
char name[KERNELOBJECT_MAX_NAME_LENGTH+1];
|
||||||
u32 status;
|
ThreadStatus status;
|
||||||
u32 curPC;
|
u32 curPC;
|
||||||
u32 entrypoint;
|
u32 entrypoint;
|
||||||
u32 initialStack;
|
u32 initialStack;
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cstdio>
|
|
||||||
#include "Common/Math/expression_parser.h"
|
#include "Common/Math/expression_parser.h"
|
||||||
#include "Core/MIPS/MIPS.h"
|
#include "Core/MIPS/MIPS.h"
|
||||||
#include "Core/Debugger/DebugInterface.h"
|
#include "Core/Debugger/DebugInterface.h"
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
#include "Core/HLE/ErrorCodes.h"
|
#include "Core/HLE/ErrorCodes.h"
|
||||||
#include "Core/HLE/sceKernelMemory.h"
|
#include "Core/HLE/sceKernelMemory.h"
|
||||||
#include "Core/HLE/sceKernelInterrupt.h"
|
#include "Core/HLE/sceKernelInterrupt.h"
|
||||||
#include "Core/HLE/sceKernelThread.h"
|
|
||||||
#include "Core/HLE/sceGe.h"
|
#include "Core/HLE/sceGe.h"
|
||||||
#include "Core/Util/PPGeDraw.h"
|
#include "Core/Util/PPGeDraw.h"
|
||||||
#include "Core/MemMapHelpers.h"
|
#include "Core/MemMapHelpers.h"
|
||||||
|
@ -37,6 +36,8 @@
|
||||||
#include "GPU/Debugger/Record.h"
|
#include "GPU/Debugger/Record.h"
|
||||||
#include "GPU/Debugger/Stepping.h"
|
#include "GPU/Debugger/Stepping.h"
|
||||||
|
|
||||||
|
bool __KernelIsDispatchEnabled();
|
||||||
|
|
||||||
void GPUCommon::Flush() {
|
void GPUCommon::Flush() {
|
||||||
drawEngineCommon_->Flush();
|
drawEngineCommon_->Flush();
|
||||||
}
|
}
|
||||||
|
|
|
@ -306,21 +306,6 @@ static void DrawVFPU(ImConfig &config, ImControl &control, const MIPSDebugInterf
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *ThreadStatusToString(u32 status) {
|
|
||||||
switch (status) {
|
|
||||||
case THREADSTATUS_RUNNING: return "Running";
|
|
||||||
case THREADSTATUS_READY: return "Ready";
|
|
||||||
case THREADSTATUS_WAIT: return "Wait";
|
|
||||||
case THREADSTATUS_SUSPEND: return "Suspended";
|
|
||||||
case THREADSTATUS_DORMANT: return "Dormant";
|
|
||||||
case THREADSTATUS_DEAD: return "Dead";
|
|
||||||
case THREADSTATUS_WAITSUSPEND: return "WaitSuspended";
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return "(unk)";
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaitIDToString(WaitType waitType, SceUID waitID, char *buffer, size_t bufSize) {
|
void WaitIDToString(WaitType waitType, SceUID waitID, char *buffer, size_t bufSize) {
|
||||||
switch (waitType) {
|
switch (waitType) {
|
||||||
case WAITTYPE_AUDIOCHANNEL:
|
case WAITTYPE_AUDIOCHANNEL:
|
||||||
|
|
Loading…
Add table
Reference in a new issue