mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-11-22 09:09:18 +01:00
coreinit: Rework thread creation
New implementation is much closer to console behavior. For example we didn't align the stack which would cause crashes in the Miiverse applet
This commit is contained in:
parent
041f29a914
commit
a16c37f0c5
@ -187,7 +187,7 @@ int Latte_ThreadEntry()
|
||||
rule.overwrite_settings.width >= 0 || rule.overwrite_settings.height >= 0 || rule.overwrite_settings.depth >= 0)
|
||||
{
|
||||
LatteGPUState.allowFramebufferSizeOptimization = false;
|
||||
cemuLog_log(LogType::Force, "Graphic pack {} prevents rendertarget size optimization.", pack->GetName());
|
||||
cemuLog_log(LogType::Force, "Graphic pack \"{}\" prevents rendertarget size optimization. This warning can be ignored and is intended for graphic pack developers", pack->GetName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -35,12 +35,12 @@
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_MEM_BlockHeap.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_MEM_ExpHeap.h"
|
||||
|
||||
CoreinitSharedData* gCoreinitData = NULL;
|
||||
CoreinitSharedData* gCoreinitData = nullptr;
|
||||
|
||||
sint32 ScoreStackTrace(OSThread_t* thread, MPTR sp)
|
||||
{
|
||||
uint32 stackMinAddr = _swapEndianU32(thread->stackEnd);
|
||||
uint32 stackMaxAddr = _swapEndianU32(thread->stackBase);
|
||||
uint32 stackMinAddr = thread->stackEnd.GetMPTR();
|
||||
uint32 stackMaxAddr = thread->stackBase.GetMPTR();
|
||||
|
||||
sint32 score = 0;
|
||||
uint32 currentStackPtr = sp;
|
||||
@ -95,8 +95,8 @@ void DebugLogStackTrace(OSThread_t* thread, MPTR sp)
|
||||
|
||||
// print stack trace
|
||||
uint32 currentStackPtr = highestScoreSP;
|
||||
uint32 stackMinAddr = _swapEndianU32(thread->stackEnd);
|
||||
uint32 stackMaxAddr = _swapEndianU32(thread->stackBase);
|
||||
uint32 stackMinAddr = thread->stackEnd.GetMPTR();
|
||||
uint32 stackMaxAddr = thread->stackBase.GetMPTR();
|
||||
for (sint32 i = 0; i < 20; i++)
|
||||
{
|
||||
uint32 nextStackPtr = memory_readU32(currentStackPtr);
|
||||
|
@ -22,7 +22,7 @@ namespace coreinit
|
||||
MPTR _iob_lock[GHS_FOPEN_MAX];
|
||||
uint16be __gh_FOPEN_MAX;
|
||||
MEMPTR<void> ghs_environ;
|
||||
uint32 ghs_Errno; // exposed by __gh_errno_ptr() or via 'errno' data export
|
||||
uint32 ghs_Errno; // exposed as 'errno' data export
|
||||
};
|
||||
|
||||
SysAllocator<GHSAccessibleData> g_ghs_data;
|
||||
@ -159,7 +159,7 @@ namespace coreinit
|
||||
void* __gh_errno_ptr()
|
||||
{
|
||||
OSThread_t* currentThread = coreinit::OSGetCurrentThread();
|
||||
return ¤tThread->context.error;
|
||||
return ¤tThread->context.ghs_errno;
|
||||
}
|
||||
|
||||
void* __get_eh_store_globals()
|
||||
|
@ -204,7 +204,7 @@ namespace coreinit
|
||||
// and a message queue large enough to hold the maximum number of commands (IPC_NUM_RESOURCE_BUFFERS)
|
||||
OSInitMessageQueue(gIPCThreadMsgQueue.GetPtr() + coreIndex, _gIPCThreadSemaphoreStorage.GetPtr() + coreIndex * IPC_NUM_RESOURCE_BUFFERS, IPC_NUM_RESOURCE_BUFFERS);
|
||||
OSThread_t* ipcThread = gIPCThread.GetPtr() + coreIndex;
|
||||
OSCreateThreadType(ipcThread, PPCInterpreter_makeCallableExportDepr(__IPCDriverThreadFunc), 0, nullptr, _gIPCThreadStack.GetPtr() + 0x4000 * coreIndex + 0x4000, 0x4000, 15, (1 << coreIndex), OSThread_t::THREAD_TYPE::TYPE_DRIVER);
|
||||
__OSCreateThreadType(ipcThread, PPCInterpreter_makeCallableExportDepr(__IPCDriverThreadFunc), 0, nullptr, _gIPCThreadStack.GetPtr() + 0x4000 * coreIndex + 0x4000, 0x4000, 15, (1 << coreIndex), OSThread_t::THREAD_TYPE::TYPE_DRIVER);
|
||||
sprintf((char*)_gIPCThreadNameStorage.GetPtr()+coreIndex*0x18, "{SYS IPC Core %d}", coreIndex);
|
||||
OSSetThreadName(ipcThread, (char*)_gIPCThreadNameStorage.GetPtr() + coreIndex * 0x18);
|
||||
OSResumeThread(ipcThread);
|
||||
|
@ -215,14 +215,171 @@ namespace coreinit
|
||||
hCPU->spr.LR = lr;
|
||||
hCPU->gpr[3] = r3;
|
||||
hCPU->gpr[4] = r4;
|
||||
hCPU->instructionPointer = _swapEndianU32(currentThread->entrypoint);
|
||||
hCPU->instructionPointer = currentThread->entrypoint.GetMPTR();
|
||||
}
|
||||
|
||||
void coreinitExport_OSExitThreadDepr(PPCInterpreter_t* hCPU);
|
||||
|
||||
void OSCreateThreadInternal(OSThread_t* thread, uint32 entryPoint, MPTR stackLowerBaseAddr, uint32 stackSize, uint8 affinityMask, OSThread_t::THREAD_TYPE threadType)
|
||||
void __OSInitContext(OSContext_t* ctx, MEMPTR<void> initialIP, MEMPTR<void> initialStackPointer)
|
||||
{
|
||||
ctx->SetContextMagic();
|
||||
ctx->gpr[0] = 0; // r0 is left uninitialized on console?
|
||||
for(auto& it : ctx->gpr)
|
||||
it = 0;
|
||||
ctx->gpr[1] = _swapEndianU32(initialStackPointer.GetMPTR());
|
||||
ctx->gpr[2] = _swapEndianU32(RPLLoader_GetSDA2Base());
|
||||
ctx->gpr[13] = _swapEndianU32(RPLLoader_GetSDA1Base());
|
||||
ctx->srr0 = initialIP.GetMPTR();
|
||||
ctx->cr = 0;
|
||||
ctx->ukn0A8 = 0;
|
||||
ctx->ukn0AC = 0;
|
||||
ctx->gqr[0] = 0;
|
||||
ctx->gqr[1] = 0;
|
||||
ctx->gqr[2] = 0;
|
||||
ctx->gqr[3] = 0;
|
||||
ctx->gqr[4] = 0;
|
||||
ctx->gqr[5] = 0;
|
||||
ctx->gqr[6] = 0;
|
||||
ctx->gqr[7] = 0;
|
||||
ctx->dsi_dar = 0;
|
||||
ctx->srr1 = 0x9032;
|
||||
ctx->xer = 0;
|
||||
ctx->dsi_dsisr = 0;
|
||||
ctx->upir = 0;
|
||||
ctx->boostCount = 0;
|
||||
ctx->state = 0;
|
||||
for(auto& it : ctx->coretime)
|
||||
it = 0;
|
||||
ctx->starttime = 0;
|
||||
ctx->ghs_errno = 0;
|
||||
ctx->upmc1 = 0;
|
||||
ctx->upmc2 = 0;
|
||||
ctx->upmc3 = 0;
|
||||
ctx->upmc4 = 0;
|
||||
ctx->ummcr0 = 0;
|
||||
ctx->ummcr1 = 0;
|
||||
}
|
||||
|
||||
void __OSThreadInit(OSThread_t* thread, MEMPTR<void> entrypoint, uint32 argInt, MEMPTR<void> argPtr, MEMPTR<void> stackTop, uint32 stackSize, sint32 priority, uint32 upirCoreIndex, OSThread_t::THREAD_TYPE threadType)
|
||||
{
|
||||
thread->effectivePriority = priority;
|
||||
thread->type = threadType;
|
||||
thread->basePriority = priority;
|
||||
thread->SetThreadMagic();
|
||||
thread->id = 0x8000;
|
||||
thread->waitAlarm = nullptr;
|
||||
thread->entrypoint = entrypoint;
|
||||
thread->quantumTicks = 0;
|
||||
if(entrypoint)
|
||||
{
|
||||
thread->state = OSThread_t::THREAD_STATE::STATE_READY;
|
||||
thread->suspendCounter = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
thread->state = OSThread_t::THREAD_STATE::STATE_NONE;
|
||||
thread->suspendCounter = 0;
|
||||
}
|
||||
thread->exitValue = (uint32)-1;
|
||||
thread->requestFlags = OSThread_t::REQUEST_FLAG_BIT::REQUEST_FLAG_NONE;
|
||||
thread->pendingSuspend = 0;
|
||||
thread->suspendResult = 0xFFFFFFFF;
|
||||
thread->coretimeSumQuantumStart = 0;
|
||||
thread->deallocatorFunc = nullptr;
|
||||
thread->cleanupCallback = nullptr;
|
||||
thread->waitingForFastMutex = nullptr;
|
||||
thread->stateFlags = 0;
|
||||
thread->waitingForMutex = nullptr;
|
||||
memset(&thread->crt, 0, sizeof(thread->crt));
|
||||
static_assert(sizeof(thread->crt) == 0x1D8);
|
||||
thread->tlsBlocksMPTR = 0;
|
||||
thread->numAllocatedTLSBlocks = 0;
|
||||
thread->tlsStatus = 0;
|
||||
OSInitThreadQueueEx(&thread->joinQueue, thread);
|
||||
OSInitThreadQueueEx(&thread->suspendQueue, thread);
|
||||
thread->mutexQueue.ukn08 = thread;
|
||||
thread->mutexQueue.ukn0C = 0;
|
||||
thread->mutexQueue.tail = nullptr;
|
||||
thread->mutexQueue.head = nullptr;
|
||||
thread->ownedFastMutex.next = nullptr;
|
||||
thread->ownedFastMutex.prev = nullptr;
|
||||
thread->contendedFastMutex.next = nullptr;
|
||||
thread->contendedFastMutex.prev = nullptr;
|
||||
|
||||
MEMPTR<void> alignedStackTop{MEMPTR<void>(stackTop).GetMPTR() & 0xFFFFFFF8};
|
||||
MEMPTR<uint32be> alignedStackTop32{alignedStackTop};
|
||||
alignedStackTop32[-1] = 0;
|
||||
alignedStackTop32[-2] = 0;
|
||||
|
||||
__OSInitContext(&thread->context, MEMPTR<void>(PPCInterpreter_makeCallableExportDepr(threadEntry)), (void*)(alignedStackTop32.GetPtr() - 2));
|
||||
thread->stackBase = stackTop; // without alignment
|
||||
thread->stackEnd = ((uint8*)stackTop.GetPtr() - stackSize);
|
||||
thread->context.upir = upirCoreIndex;
|
||||
thread->context.lr = _swapEndianU32(PPCInterpreter_makeCallableExportDepr(coreinitExport_OSExitThreadDepr));
|
||||
thread->context.gpr[3] = _swapEndianU32(argInt);
|
||||
thread->context.gpr[4] = _swapEndianU32(argPtr.GetMPTR());
|
||||
|
||||
*(uint32be*)((uint8*)stackTop.GetPtr() - stackSize) = 0xDEADBABE;
|
||||
thread->alarmRelatedUkn = 0;
|
||||
for(auto& it : thread->specificArray)
|
||||
it = nullptr;
|
||||
thread->context.fpscr.fpscr = 4;
|
||||
for(sint32 i=0; i<32; i++)
|
||||
{
|
||||
thread->context.fp_ps0[i] = 0.0;
|
||||
thread->context.fp_ps1[i] = 0.0;
|
||||
}
|
||||
thread->context.gqr[2] = 0x40004;
|
||||
thread->context.gqr[3] = 0x50005;
|
||||
thread->context.gqr[4] = 0x60006;
|
||||
thread->context.gqr[5] = 0x70007;
|
||||
|
||||
for(sint32 i=0; i<Espresso::CORE_COUNT; i++)
|
||||
thread->context.coretime[i] = 0;
|
||||
|
||||
// currentRunQueue and waitQueueLink is not initialized by COS and instead overwritten without validation
|
||||
// since we already have integrity checks in other functions, lets initialize it here
|
||||
for(sint32 i=0; i<Espresso::CORE_COUNT; i++)
|
||||
thread->currentRunQueue[i] = nullptr;
|
||||
thread->waitQueueLink.prev = nullptr;
|
||||
thread->waitQueueLink.next = nullptr;
|
||||
|
||||
thread->wakeTimeRelatedUkn2 = 0;
|
||||
thread->wakeUpCount = 0;
|
||||
thread->wakeUpTime = 0;
|
||||
thread->wakeTimeRelatedUkn1 = 0x7FFFFFFFFFFFFFFF;
|
||||
thread->quantumTicks = 0;
|
||||
thread->coretimeSumQuantumStart = 0;
|
||||
thread->totalCycles = 0;
|
||||
|
||||
for(auto& it : thread->padding68C)
|
||||
it = 0;
|
||||
}
|
||||
|
||||
void SetThreadAffinityToCore(OSThread_t* thread, uint32 coreIndex)
|
||||
{
|
||||
cemu_assert_debug(coreIndex < 3);
|
||||
thread->attr &= ~(OSThread_t::ATTR_BIT::ATTR_AFFINITY_CORE0 | OSThread_t::ATTR_BIT::ATTR_AFFINITY_CORE1 | OSThread_t::ATTR_BIT::ATTR_AFFINITY_CORE2 | OSThread_t::ATTR_BIT::ATTR_UKN_010);
|
||||
thread->context.affinity &= 0xFFFFFFF8;
|
||||
if (coreIndex == 0)
|
||||
{
|
||||
thread->attr |= OSThread_t::ATTR_BIT::ATTR_AFFINITY_CORE0;
|
||||
thread->context.affinity |= (1<<0);
|
||||
}
|
||||
else if (coreIndex == 1)
|
||||
{
|
||||
thread->attr |= OSThread_t::ATTR_BIT::ATTR_AFFINITY_CORE1;
|
||||
thread->context.affinity |= (1<<1);
|
||||
}
|
||||
else // if (coreIndex == 2)
|
||||
{
|
||||
thread->attr |= OSThread_t::ATTR_BIT::ATTR_AFFINITY_CORE2;
|
||||
thread->context.affinity |= (1<<2);
|
||||
}
|
||||
}
|
||||
|
||||
void __OSCreateThreadOnActiveThreadWorkaround(OSThread_t* thread)
|
||||
{
|
||||
cemu_assert_debug(thread != nullptr); // make thread struct mandatory. Caller can always use SysAllocator
|
||||
__OSLockScheduler();
|
||||
bool isThreadStillActive = __OSIsThreadActive(thread);
|
||||
if (isThreadStillActive)
|
||||
@ -248,84 +405,97 @@ namespace coreinit
|
||||
}
|
||||
cemu_assert_debug(__OSIsThreadActive(thread) == false);
|
||||
__OSUnlockScheduler();
|
||||
memset(thread, 0x00, sizeof(OSThread_t));
|
||||
// init signatures
|
||||
thread->SetMagic();
|
||||
thread->type = threadType;
|
||||
thread->state = (entryPoint != MPTR_NULL) ? OSThread_t::THREAD_STATE::STATE_READY : OSThread_t::THREAD_STATE::STATE_NONE;
|
||||
thread->entrypoint = _swapEndianU32(entryPoint);
|
||||
__OSSetThreadBasePriority(thread, 0);
|
||||
__OSUpdateThreadEffectivePriority(thread);
|
||||
// untested, but seems to work (Batman Arkham City uses these values to calculate the stack size for duplicated threads)
|
||||
thread->stackBase = _swapEndianU32(stackLowerBaseAddr + stackSize); // these fields are quite important and lots of games rely on them being accurate (Examples: Darksiders 2, SMW3D, Batman Arkham City)
|
||||
thread->stackEnd = _swapEndianU32(stackLowerBaseAddr);
|
||||
// init stackpointer
|
||||
thread->context.gpr[GPR_SP] = _swapEndianU32(stackLowerBaseAddr + stackSize - 0x20); // how many free bytes should there be at the beginning of the stack?
|
||||
// init misc stuff
|
||||
thread->attr = affinityMask;
|
||||
thread->context.setAffinity(affinityMask);
|
||||
thread->context.srr0 = PPCInterpreter_makeCallableExportDepr(threadEntry);
|
||||
thread->context.lr = _swapEndianU32(PPCInterpreter_makeCallableExportDepr(coreinitExport_OSExitThreadDepr));
|
||||
thread->id = 0x8000; // Warriors Orochi 3 softlocks if this is zero due to confusing threads (_OSActivateThread should set this?)
|
||||
// init ugqr
|
||||
thread->context.gqr[0] = 0x00000000;
|
||||
thread->context.gqr[1] = 0x00000000;
|
||||
thread->context.gqr[2] = 0x00040004;
|
||||
thread->context.gqr[3] = 0x00050005;
|
||||
thread->context.gqr[4] = 0x00060006;
|
||||
thread->context.gqr[5] = 0x00070007;
|
||||
thread->context.gqr[6] = 0x00000000;
|
||||
thread->context.gqr[7] = 0x00000000;
|
||||
// init r2 (SDA2) and r3 (SDA)
|
||||
thread->context.gpr[2] = _swapEndianU32(RPLLoader_GetSDA2Base());
|
||||
thread->context.gpr[13] = _swapEndianU32(RPLLoader_GetSDA1Base());
|
||||
// GHS related thread init?
|
||||
}
|
||||
|
||||
__OSLockScheduler();
|
||||
// if entrypoint is non-zero then put the thread on the active list and suspend it
|
||||
if (entryPoint != MPTR_NULL)
|
||||
bool __OSCreateThreadInternal2(OSThread_t* thread, MEMPTR<void> entrypoint, uint32 argInt, MEMPTR<void> argPtr, MEMPTR<void> stackBase, uint32 stackSize, sint32 priority, uint32 attrBits, OSThread_t::THREAD_TYPE threadType)
|
||||
{
|
||||
__OSCreateThreadOnActiveThreadWorkaround(thread);
|
||||
OSThread_t* currentThread = OSGetCurrentThread();
|
||||
if (priority < 0 || priority >= 32)
|
||||
{
|
||||
thread->suspendCounter = 1;
|
||||
__OSActivateThread(thread);
|
||||
thread->state = OSThread_t::THREAD_STATE::STATE_READY;
|
||||
cemuLog_log(LogType::APIErrors, "OSCreateThreadInternal: Thread priority must be in range 0-31");
|
||||
return false;
|
||||
}
|
||||
if (threadType == OSThread_t::THREAD_TYPE::TYPE_IO)
|
||||
{
|
||||
priority = priority + 0x20;
|
||||
}
|
||||
else if (threadType == OSThread_t::THREAD_TYPE::TYPE_APP)
|
||||
{
|
||||
priority = priority + 0x40;
|
||||
}
|
||||
if(attrBits >= 0x20 || stackBase == nullptr || stackSize == 0)
|
||||
{
|
||||
cemuLog_logDebug(LogType::APIErrors, "OSCreateThreadInternal: Invalid attributes, stack base or size");
|
||||
return false;
|
||||
}
|
||||
uint32 im = OSDisableInterrupts();
|
||||
__OSLockScheduler(thread);
|
||||
|
||||
uint32 coreIndex = PPCInterpreter_getCurrentInstance() ? OSGetCoreId() : 1;
|
||||
__OSThreadInit(thread, entrypoint, argInt, argPtr, stackBase, stackSize, priority, coreIndex, threadType);
|
||||
thread->threadName = nullptr;
|
||||
thread->context.affinity = attrBits & 7;
|
||||
thread->attr = attrBits;
|
||||
if ((attrBits & 7) == 0) // if no explicit affinity is given, use the current core
|
||||
SetThreadAffinityToCore(thread, OSGetCoreId());
|
||||
if(currentThread)
|
||||
{
|
||||
for(sint32 i=0; i<Espresso::CORE_COUNT; i++)
|
||||
{
|
||||
thread->dsiCallback[i] = currentThread->dsiCallback[i];
|
||||
thread->isiCallback[i] = currentThread->isiCallback[i];
|
||||
thread->programCallback[i] = currentThread->programCallback[i];
|
||||
thread->perfMonCallback[i] = currentThread->perfMonCallback[i];
|
||||
thread->alignmentExceptionCallback[i] = currentThread->alignmentExceptionCallback[i];
|
||||
}
|
||||
thread->context.srr1 = thread->context.srr1 | (currentThread->context.srr1 & 0x900);
|
||||
thread->context.fpscr.fpscr = thread->context.fpscr.fpscr | (currentThread->context.fpscr.fpscr & 0xF8);
|
||||
}
|
||||
else
|
||||
thread->suspendCounter = 0;
|
||||
__OSUnlockScheduler();
|
||||
{
|
||||
for(sint32 i=0; i<Espresso::CORE_COUNT; i++)
|
||||
{
|
||||
thread->dsiCallback[i] = 0;
|
||||
thread->isiCallback[i] = 0;
|
||||
thread->programCallback[i] = 0;
|
||||
thread->perfMonCallback[i] = 0;
|
||||
thread->alignmentExceptionCallback[i] = nullptr;
|
||||
}
|
||||
}
|
||||
if (entrypoint)
|
||||
{
|
||||
thread->id = 0x8000;
|
||||
__OSActivateThread(thread); // also handles adding the thread to g_activeThreadQueue
|
||||
}
|
||||
__OSUnlockScheduler(thread);
|
||||
OSRestoreInterrupts(im);
|
||||
// recompile entry point function
|
||||
if (entrypoint)
|
||||
PPCRecompiler_recompileIfUnvisited(entrypoint.GetMPTR());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OSCreateThreadType(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop, sint32 stackSize, sint32 priority, uint32 attr, OSThread_t::THREAD_TYPE threadType)
|
||||
{
|
||||
OSCreateThreadInternal(thread, entryPoint, memory_getVirtualOffsetFromPointer(stackTop) - stackSize, stackSize, attr, threadType);
|
||||
thread->context.gpr[3] = _swapEndianU32(numParam); // num arguments
|
||||
thread->context.gpr[4] = _swapEndianU32(memory_getVirtualOffsetFromPointer(ptrParam)); // arguments pointer
|
||||
__OSSetThreadBasePriority(thread, priority);
|
||||
__OSUpdateThreadEffectivePriority(thread);
|
||||
// set affinity
|
||||
uint8 affinityMask = 0;
|
||||
affinityMask = attr & 0x7;
|
||||
// if no core is selected -> set current one
|
||||
if (affinityMask == 0)
|
||||
affinityMask |= (1 << PPCInterpreter_getCoreIndex(PPCInterpreter_getCurrentInstance()));
|
||||
// set attr
|
||||
// todo: Support for other attr bits
|
||||
thread->attr = (affinityMask & 0xFF) | (attr & OSThread_t::ATTR_BIT::ATTR_DETACHED);
|
||||
thread->context.setAffinity(affinityMask);
|
||||
// recompile entry point function
|
||||
if (entryPoint != MPTR_NULL)
|
||||
PPCRecompiler_recompileIfUnvisited(entryPoint);
|
||||
return true;
|
||||
if(threadType != OSThread_t::THREAD_TYPE::TYPE_APP && threadType != OSThread_t::THREAD_TYPE::TYPE_IO)
|
||||
{
|
||||
cemuLog_logDebug(LogType::APIErrors, "OSCreateThreadType: Invalid thread type");
|
||||
cemu_assert_suspicious();
|
||||
return false;
|
||||
}
|
||||
return __OSCreateThreadInternal2(thread, MEMPTR<void>(entryPoint), numParam, ptrParam, stackTop, stackSize, priority, attr, threadType);
|
||||
}
|
||||
|
||||
bool OSCreateThread(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop, sint32 stackSize, sint32 priority, uint32 attr)
|
||||
{
|
||||
return OSCreateThreadType(thread, entryPoint, numParam, ptrParam, stackTop, stackSize, priority, attr, OSThread_t::THREAD_TYPE::TYPE_APP);
|
||||
return __OSCreateThreadInternal2(thread, MEMPTR<void>(entryPoint), numParam, ptrParam, stackTop, stackSize, priority, attr, OSThread_t::THREAD_TYPE::TYPE_APP);
|
||||
}
|
||||
|
||||
// alias to OSCreateThreadType, similar to OSCreateThread, but with an additional parameter for the thread type
|
||||
// similar to OSCreateThreadType, but can be used to create any type of thread
|
||||
bool __OSCreateThreadType(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop, sint32 stackSize, sint32 priority, uint32 attr, OSThread_t::THREAD_TYPE threadType)
|
||||
{
|
||||
return OSCreateThreadType(thread, entryPoint, numParam, ptrParam, stackTop, stackSize, priority, attr, threadType);
|
||||
return __OSCreateThreadInternal2(thread, MEMPTR<void>(entryPoint), numParam, ptrParam, stackTop, stackSize, priority, attr, threadType);
|
||||
}
|
||||
|
||||
bool OSRunThread(OSThread_t* thread, MPTR funcAddress, sint32 numParam, void* ptrParam)
|
||||
@ -352,7 +522,7 @@ namespace coreinit
|
||||
// set thread state
|
||||
// todo - this should fully reinitialize the thread?
|
||||
|
||||
thread->entrypoint = _swapEndianU32(funcAddress);
|
||||
thread->entrypoint = funcAddress;
|
||||
thread->context.srr0 = PPCInterpreter_makeCallableExportDepr(threadEntry);
|
||||
thread->context.lr = _swapEndianU32(PPCInterpreter_makeCallableExportDepr(coreinitExport_OSExitThreadDepr));
|
||||
thread->context.gpr[3] = _swapEndianU32(numParam);
|
||||
@ -378,10 +548,10 @@ namespace coreinit
|
||||
OSThread_t* currentThread = coreinit::OSGetCurrentThread();
|
||||
|
||||
// thread cleanup callback
|
||||
if (!currentThread->cleanupCallback2.IsNull())
|
||||
if (currentThread->cleanupCallback)
|
||||
{
|
||||
currentThread->stateFlags = _swapEndianU32(_swapEndianU32(currentThread->stateFlags) | 0x00000001);
|
||||
PPCCoreCallback(currentThread->cleanupCallback2.GetMPTR(), currentThread, _swapEndianU32(currentThread->stackEnd));
|
||||
PPCCoreCallback(currentThread->cleanupCallback.GetMPTR(), currentThread, currentThread->stackEnd);
|
||||
}
|
||||
// cpp exception cleanup
|
||||
if (gCoreinitData->__cpp_exception_cleanup_ptr != 0 && currentThread->crt.eh_globals != nullptr)
|
||||
@ -602,7 +772,10 @@ namespace coreinit
|
||||
sint32 previousSuspendCount = thread->suspendCounter;
|
||||
cemu_assert_debug(previousSuspendCount >= 0);
|
||||
if (previousSuspendCount == 0)
|
||||
{
|
||||
cemuLog_log(LogType::APIErrors, "OSResumeThread: Resuming thread 0x{:08x} which isn't suspended", MEMPTR<OSThread_t>(thread).GetMPTR());
|
||||
return 0;
|
||||
}
|
||||
thread->suspendCounter = previousSuspendCount - resumeCount;
|
||||
if (thread->suspendCounter < 0)
|
||||
thread->suspendCounter = 0;
|
||||
@ -732,8 +905,8 @@ namespace coreinit
|
||||
void* OSSetThreadCleanupCallback(OSThread_t* thread, void* cleanupCallback)
|
||||
{
|
||||
__OSLockScheduler();
|
||||
void* previousFunc = thread->cleanupCallback2.GetPtr();
|
||||
thread->cleanupCallback2 = cleanupCallback;
|
||||
void* previousFunc = thread->cleanupCallback.GetPtr();
|
||||
thread->cleanupCallback = cleanupCallback;
|
||||
__OSUnlockScheduler();
|
||||
return previousFunc;
|
||||
}
|
||||
@ -1341,7 +1514,7 @@ namespace coreinit
|
||||
void __OSQueueThreadDeallocation(OSThread_t* thread)
|
||||
{
|
||||
uint32 coreIndex = OSGetCoreId();
|
||||
TerminatorThread::DeallocatorQueueEntry queueEntry(thread, memory_getPointerFromVirtualOffset(_swapEndianU32(thread->stackEnd)), thread->deallocatorFunc);
|
||||
TerminatorThread::DeallocatorQueueEntry queueEntry(thread, thread->stackEnd, thread->deallocatorFunc);
|
||||
s_terminatorThreads[coreIndex].queueDeallocators.push(queueEntry);
|
||||
OSSignalSemaphoreInternal(s_terminatorThreads[coreIndex].semaphoreQueuedDeallocators.GetPtr(), false); // do not reschedule here! Current thread must not be interrupted otherwise deallocator will run too early
|
||||
}
|
||||
|
@ -2,9 +2,6 @@
|
||||
#include "Cafe/HW/Espresso/Const.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_Scheduler.h"
|
||||
|
||||
#define OS_CONTEXT_MAGIC_0 'OSCo'
|
||||
#define OS_CONTEXT_MAGIC_1 'ntxt'
|
||||
|
||||
struct OSThread_t;
|
||||
|
||||
struct OSContextRegFPSCR_t
|
||||
@ -16,6 +13,9 @@ struct OSContextRegFPSCR_t
|
||||
|
||||
struct OSContext_t
|
||||
{
|
||||
static constexpr uint32 OS_CONTEXT_MAGIC_0 = 0x4f53436f; // "OSCo"
|
||||
static constexpr uint32 OS_CONTEXT_MAGIC_1 = 0x6e747874; // "ntxt"
|
||||
|
||||
/* +0x000 */ betype<uint32> magic0;
|
||||
/* +0x004 */ betype<uint32> magic1;
|
||||
/* +0x008 */ uint32 gpr[32];
|
||||
@ -36,24 +36,29 @@ struct OSContext_t
|
||||
/* +0x1BC */ uint32 gqr[8]; // GQR/UGQR
|
||||
/* +0x1DC */ uint32be upir; // set to current core index
|
||||
/* +0x1E0 */ uint64be fp_ps1[32];
|
||||
/* +0x2E0 */ uint64 uknTime2E0;
|
||||
/* +0x2E8 */ uint64 uknTime2E8;
|
||||
/* +0x2F0 */ uint64 uknTime2F0;
|
||||
/* +0x2F8 */ uint64 uknTime2F8;
|
||||
/* +0x300 */ uint32 error; // returned by __gh_errno_ptr() (used by socketlasterr)
|
||||
/* +0x2E0 */ uint64be coretime[3];
|
||||
/* +0x2F8 */ uint64be starttime;
|
||||
/* +0x300 */ uint32be ghs_errno; // returned by __gh_errno_ptr() (used by socketlasterr)
|
||||
/* +0x304 */ uint32be affinity;
|
||||
/* +0x308 */ uint32 ukn0308;
|
||||
/* +0x30C */ uint32 ukn030C;
|
||||
/* +0x310 */ uint32 ukn0310;
|
||||
/* +0x314 */ uint32 ukn0314;
|
||||
/* +0x318 */ uint32 ukn0318;
|
||||
/* +0x31C */ uint32 ukn031C;
|
||||
/* +0x308 */ uint32be upmc1;
|
||||
/* +0x30C */ uint32be upmc2;
|
||||
/* +0x310 */ uint32be upmc3;
|
||||
/* +0x314 */ uint32be upmc4;
|
||||
/* +0x318 */ uint32be ummcr0;
|
||||
/* +0x31C */ uint32be ummcr1;
|
||||
|
||||
bool checkMagic()
|
||||
{
|
||||
return magic0 == (uint32)OS_CONTEXT_MAGIC_0 && magic1 == (uint32)OS_CONTEXT_MAGIC_1;
|
||||
}
|
||||
|
||||
void SetContextMagic()
|
||||
{
|
||||
magic0 = OS_CONTEXT_MAGIC_0;
|
||||
magic1 = OS_CONTEXT_MAGIC_1;
|
||||
}
|
||||
|
||||
|
||||
bool hasCoreAffinitySet(uint32 coreIndex) const
|
||||
{
|
||||
return (((uint32)affinity >> coreIndex) & 1) != 0;
|
||||
@ -361,6 +366,8 @@ namespace coreinit
|
||||
|
||||
struct OSThread_t
|
||||
{
|
||||
static constexpr uint32 MAGIC_THREAD = 0x74487244; // "tHrD"
|
||||
|
||||
enum class THREAD_TYPE : uint32
|
||||
{
|
||||
TYPE_DRIVER = 0,
|
||||
@ -383,7 +390,7 @@ struct OSThread_t
|
||||
ATTR_AFFINITY_CORE1 = 0x2,
|
||||
ATTR_AFFINITY_CORE2 = 0x4,
|
||||
ATTR_DETACHED = 0x8,
|
||||
// more flags?
|
||||
ATTR_UKN_010 = 0x10,
|
||||
};
|
||||
|
||||
enum REQUEST_FLAG_BIT : uint32
|
||||
@ -404,23 +411,21 @@ struct OSThread_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SetMagic()
|
||||
void SetThreadMagic()
|
||||
{
|
||||
context.magic0 = OS_CONTEXT_MAGIC_0;
|
||||
context.magic1 = OS_CONTEXT_MAGIC_1;
|
||||
magic = 'tHrD';
|
||||
magic = MAGIC_THREAD;
|
||||
}
|
||||
|
||||
bool IsValidMagic() const
|
||||
{
|
||||
return magic == 'tHrD' && context.magic0 == OS_CONTEXT_MAGIC_0 && context.magic1 == OS_CONTEXT_MAGIC_1;
|
||||
return magic == MAGIC_THREAD && context.magic0 == OSContext_t::OS_CONTEXT_MAGIC_0 && context.magic1 == OSContext_t::OS_CONTEXT_MAGIC_1;
|
||||
}
|
||||
|
||||
/* +0x000 */ OSContext_t context;
|
||||
/* +0x320 */ uint32be magic; // 'tHrD'
|
||||
/* +0x320 */ uint32be magic; // "tHrD" (0x74487244)
|
||||
/* +0x324 */ betype<THREAD_STATE> state;
|
||||
/* +0x325 */ uint8 attr;
|
||||
/* +0x326 */ uint16be id; // Warriors Orochi 3 uses this to identify threads. Seems like this is always set to 0x8000 ?
|
||||
/* +0x326 */ uint16be id; // Warriors Orochi 3 uses this to identify threads
|
||||
/* +0x328 */ betype<sint32> suspendCounter;
|
||||
/* +0x32C */ sint32be effectivePriority; // effective priority (lower is higher)
|
||||
/* +0x330 */ sint32be basePriority; // base priority (lower is higher)
|
||||
@ -440,21 +445,21 @@ struct OSThread_t
|
||||
|
||||
/* +0x38C */ coreinit::OSThreadLink activeThreadChain; // queue of active threads (g_activeThreadQueue)
|
||||
|
||||
/* +0x394 */ MPTR stackBase; // upper limit of stack
|
||||
/* +0x398 */ MPTR stackEnd; // lower limit of stack
|
||||
/* +0x394 */ MEMPTR<void> stackBase; // upper limit of stack
|
||||
/* +0x398 */ MEMPTR<void> stackEnd; // lower limit of stack
|
||||
|
||||
/* +0x39C */ MPTR entrypoint;
|
||||
/* +0x39C */ MEMPTR<void> entrypoint;
|
||||
/* +0x3A0 */ crt_t crt;
|
||||
|
||||
/* +0x578 */ sint32 alarmRelatedUkn;
|
||||
/* +0x57C */ std::array<MEMPTR<void>, 16> specificArray;
|
||||
/* +0x5BC */ betype<THREAD_TYPE> type;
|
||||
/* +0x5C0 */ MEMPTR<const char> threadName;
|
||||
/* +0x5C4 */ MPTR waitAlarm; // used only by OSWaitEventWithTimeout/OSSignalEvent ?
|
||||
/* +0x5C4 */ MEMPTR<void> waitAlarm; // used only by OSWaitEventWithTimeout/OSSignalEvent ?
|
||||
|
||||
/* +0x5C8 */ uint32 userStackPointer;
|
||||
|
||||
/* +0x5CC */ MEMPTR<void> cleanupCallback2;
|
||||
/* +0x5CC */ MEMPTR<void> cleanupCallback;
|
||||
/* +0x5D0 */ MEMPTR<void> deallocatorFunc;
|
||||
|
||||
/* +0x5D4 */ uint32 stateFlags; // 0x5D4 | various flags? Controls if canceling/suspension is allowed (at cancel points) or not? If 1 -> Cancel/Suspension not allowed, if 0 -> Cancel/Suspension allowed
|
||||
@ -480,19 +485,21 @@ struct OSThread_t
|
||||
|
||||
/* +0x660 */ uint32 ukn660;
|
||||
|
||||
// todo - some of the members towards the end of the struct were only added in later COS versions. Figure out the mapping between version and members
|
||||
|
||||
// TLS
|
||||
/* +0x664 */ uint16 numAllocatedTLSBlocks;
|
||||
/* +0x666 */ sint16 tlsStatus;
|
||||
/* +0x668 */ MPTR tlsBlocksMPTR;
|
||||
|
||||
|
||||
/* +0x66C */ MEMPTR<coreinit::OSFastMutex> waitingForFastMutex;
|
||||
/* +0x670 */ coreinit::OSFastMutexLink contendedFastMutex;
|
||||
/* +0x678 */ coreinit::OSFastMutexLink ownedFastMutex;
|
||||
/* +0x680 */ MEMPTR<void> alignmentExceptionCallback[Espresso::CORE_COUNT];
|
||||
|
||||
/* +0x680 */ uint32 padding680[28 / 4];
|
||||
/* +0x68C */ uint32 padding68C[20 / 4];
|
||||
};
|
||||
|
||||
static_assert(sizeof(OSThread_t) == 0x6A0-4); // todo - determine correct size
|
||||
static_assert(sizeof(OSThread_t) == 0x6A0);
|
||||
|
||||
namespace coreinit
|
||||
{
|
||||
|
@ -117,10 +117,10 @@ void nsysnetExport_socket_lib_finish(PPCInterpreter_t* hCPU)
|
||||
osLib_returnFromFunction(hCPU, 0); // 0 -> Success
|
||||
}
|
||||
|
||||
uint32* __gh_errno_ptr()
|
||||
static uint32be* __gh_errno_ptr()
|
||||
{
|
||||
OSThread_t* osThread = coreinit::OSGetCurrentThread();
|
||||
return &osThread->context.error;
|
||||
return &osThread->context.ghs_errno;
|
||||
}
|
||||
|
||||
void _setSockError(sint32 errCode)
|
||||
|
@ -963,7 +963,7 @@ namespace snd_core
|
||||
OSInitMessageQueue(__AXIstThreadMsgQueue.GetPtr(), __AXIstThreadMsgArray.GetPtr(), 0x10);
|
||||
// create thread
|
||||
uint8 istThreadAttr = 0;
|
||||
coreinit::OSCreateThreadType(__AXIstThread.GetPtr(), PPCInterpreter_makeCallableExportDepr(AXIst_ThreadEntry), 0, &__AXIstThreadMsgQueue, __AXIstThreadStack.GetPtr() + 0x4000, 0x4000, 14, istThreadAttr, OSThread_t::THREAD_TYPE::TYPE_DRIVER);
|
||||
coreinit::__OSCreateThreadType(__AXIstThread.GetPtr(), PPCInterpreter_makeCallableExportDepr(AXIst_ThreadEntry), 0, &__AXIstThreadMsgQueue, __AXIstThreadStack.GetPtr() + 0x4000, 0x4000, 14, istThreadAttr, OSThread_t::THREAD_TYPE::TYPE_DRIVER);
|
||||
coreinit::OSResumeThread(__AXIstThread.GetPtr());
|
||||
}
|
||||
|
||||
|
@ -155,7 +155,7 @@ void ExceptionHandler_LogGeneralInfo()
|
||||
const char* threadName = "NULL";
|
||||
if (!threadItrBE->threadName.IsNull())
|
||||
threadName = threadItrBE->threadName.GetPtr();
|
||||
sprintf(dumpLine, "%08x Ent %08x IP %08x LR %08x %-9s Aff %d%d%d Pri %2d Name %s", threadItrMPTR, _swapEndianU32(threadItrBE->entrypoint), threadItrBE->context.srr0, _swapEndianU32(threadItrBE->context.lr), threadStateStr, (affinity >> 0) & 1, (affinity >> 1) & 1, (affinity >> 2) & 1, effectivePriority, threadName);
|
||||
sprintf(dumpLine, "%08x Ent %08x IP %08x LR %08x %-9s Aff %d%d%d Pri %2d Name %s", threadItrMPTR, threadItrBE->entrypoint.GetMPTR(), threadItrBE->context.srr0, _swapEndianU32(threadItrBE->context.lr), threadStateStr, (affinity >> 0) & 1, (affinity >> 1) & 1, (affinity >> 2) & 1, effectivePriority, threadName);
|
||||
// write line to log
|
||||
CrashLog_WriteLine(dumpLine);
|
||||
}
|
||||
|
@ -195,10 +195,10 @@ void DebugPPCThreadsWindow::RefreshThreadList()
|
||||
m_thread_list->InsertItem(item);
|
||||
m_thread_list->SetItemData(item, (long)threadItrMPTR);
|
||||
// entry point
|
||||
sprintf(tempStr, "%08X", _swapEndianU32(cafeThread->entrypoint));
|
||||
sprintf(tempStr, "%08X", cafeThread->entrypoint.GetMPTR());
|
||||
m_thread_list->SetItem(i, 1, tempStr);
|
||||
// stack base (low)
|
||||
sprintf(tempStr, "%08X - %08X", _swapEndianU32(cafeThread->stackEnd), _swapEndianU32(cafeThread->stackBase));
|
||||
sprintf(tempStr, "%08X - %08X", cafeThread->stackEnd.GetMPTR(), cafeThread->stackBase.GetMPTR());
|
||||
m_thread_list->SetItem(i, 2, tempStr);
|
||||
// pc
|
||||
RPLStoredSymbol* symbol = rplSymbolStorage_getByAddress(cafeThread->context.srr0);
|
||||
|
Loading…
Reference in New Issue
Block a user