Merge pull request #2345 from RadWolfie/init-thread-fix
Fix order of thread initialization
This commit is contained in:
commit
374ba5ec70
|
@ -45,6 +45,8 @@
|
||||||
#include "core\kernel\support\EmuFS.h" // For EmuGenerateFS
|
#include "core\kernel\support\EmuFS.h" // For EmuGenerateFS
|
||||||
#include "core\kernel\support\NativeHandle.h"
|
#include "core\kernel\support\NativeHandle.h"
|
||||||
|
|
||||||
|
#include <semaphore>
|
||||||
|
|
||||||
// prevent name collisions
|
// prevent name collisions
|
||||||
namespace NtDll
|
namespace NtDll
|
||||||
{
|
{
|
||||||
|
@ -58,6 +60,7 @@ typedef struct _PCSTProxyParam
|
||||||
{
|
{
|
||||||
IN xbox::PVOID Ethread;
|
IN xbox::PVOID Ethread;
|
||||||
IN xbox::ulong_xt TlsDataSize;
|
IN xbox::ulong_xt TlsDataSize;
|
||||||
|
IN OUT std::binary_semaphore* signal;
|
||||||
}
|
}
|
||||||
PCSTProxyParam;
|
PCSTProxyParam;
|
||||||
|
|
||||||
|
@ -112,6 +115,18 @@ static unsigned int WINAPI PCSTProxy
|
||||||
#else
|
#else
|
||||||
EmuGenerateFS(eThread);
|
EmuGenerateFS(eThread);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// NOTE: Native KTHREAD-SWITCHING will not need notification as it should be already done within
|
||||||
|
// PsCreateSystemThreadEx function. For now, it is an experimental to see if xbox thread setup do work
|
||||||
|
// without reside in host stack.
|
||||||
|
// Initializing ethread is done, we can allow PsCreateSystemThreadEx process to continue.
|
||||||
|
params.signal->release();
|
||||||
|
params.signal = nullptr;
|
||||||
|
SuspendThread(GetCurrentThread());
|
||||||
|
if (xbox::KeGetCurrentThread()->HasTerminated) {
|
||||||
|
xbox::PsTerminateSystemThread(0);
|
||||||
|
}
|
||||||
|
|
||||||
xbox::PKSTART_FRAME StartFrame = reinterpret_cast<xbox::PKSTART_FRAME>(reinterpret_cast<xbox::addr_xt>(eThread->Tcb.KernelStack) + sizeof(xbox::KSWITCHFRAME));
|
xbox::PKSTART_FRAME StartFrame = reinterpret_cast<xbox::PKSTART_FRAME>(reinterpret_cast<xbox::addr_xt>(eThread->Tcb.KernelStack) + sizeof(xbox::KSWITCHFRAME));
|
||||||
|
|
||||||
LOG_PCSTProxy(
|
LOG_PCSTProxy(
|
||||||
|
@ -309,33 +324,57 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx
|
||||||
KernelStackSize = RoundUp(KernelStackSize, PAGE_SIZE);
|
KernelStackSize = RoundUp(KernelStackSize, PAGE_SIZE);
|
||||||
hKernelStackSize = RoundUp(hKernelStackSize, PAGE_SIZE);
|
hKernelStackSize = RoundUp(hKernelStackSize, PAGE_SIZE);
|
||||||
|
|
||||||
// create thread, using our special proxy technique
|
PETHREAD eThread;
|
||||||
{
|
ntstatus_xt result = ObCreateObject(&PsThreadObjectType, zeroptr, sizeof(ETHREAD) + ThreadExtensionSize, reinterpret_cast<PVOID*>(&eThread));
|
||||||
PETHREAD eThread;
|
if (!X_NT_SUCCESS(result)) {
|
||||||
ntstatus_xt result = ObCreateObject(&PsThreadObjectType, zeroptr, sizeof(ETHREAD) + ThreadExtensionSize, reinterpret_cast<PVOID *>(&eThread));
|
RETURN(result);
|
||||||
if (!X_NT_SUCCESS(result)) {
|
}
|
||||||
RETURN(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::memset(eThread, 0, sizeof(ETHREAD) + ThreadExtensionSize);
|
std::memset(eThread, 0, sizeof(ETHREAD) + ThreadExtensionSize);
|
||||||
|
|
||||||
// Create kernel stack for xbox title to able write on stack instead of host.
|
// Create kernel stack for xbox title to able write on stack instead of host.
|
||||||
PVOID KernelStack = MmCreateKernelStack(KernelStackSize, DebuggerThread);
|
PVOID KernelStack = MmCreateKernelStack(KernelStackSize, DebuggerThread);
|
||||||
|
|
||||||
if (!KernelStack) {
|
if (!KernelStack) {
|
||||||
ObfDereferenceObject(eThread);
|
ObfDereferenceObject(eThread);
|
||||||
RETURN(X_STATUS_INSUFFICIENT_RESOURCES);
|
RETURN(X_STATUS_INSUFFICIENT_RESOURCES);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start thread initialization process here before insert and create thread
|
// Start thread initialization process here before insert and create thread
|
||||||
KeInitializeThread(&eThread->Tcb, KernelStack, KernelStackSize, TlsDataSize, SystemRoutine, StartRoutine, StartContext, &KiUniqueProcess);
|
KeInitializeThread(&eThread->Tcb, KernelStack, KernelStackSize, TlsDataSize, SystemRoutine, StartRoutine, StartContext, &KiUniqueProcess);
|
||||||
|
|
||||||
// The ob handle of the ethread obj is the thread id we return to the title
|
// Create binary_semaphore to allow new thread setup non-kthread switching.
|
||||||
result = ObInsertObject(eThread, zeroptr, 0, &eThread->UniqueThread);
|
std::binary_semaphore signal{0};
|
||||||
if (!X_NT_SUCCESS(result)) {
|
|
||||||
ObfDereferenceObject(eThread);
|
// PCSTProxy is responsible for cleaning up this pointer
|
||||||
RETURN(result);
|
PCSTProxyParam *iPCSTProxyParam = new PCSTProxyParam;
|
||||||
}
|
iPCSTProxyParam->Ethread = eThread;
|
||||||
|
iPCSTProxyParam->TlsDataSize = TlsDataSize;
|
||||||
|
iPCSTProxyParam->signal = &signal;
|
||||||
|
|
||||||
|
unsigned int hThreadId;
|
||||||
|
HANDLE handle = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, hKernelStackSize, PCSTProxy, iPCSTProxyParam, NULL, &hThreadId));
|
||||||
|
if (handle == zeroptr) {
|
||||||
|
delete iPCSTProxyParam;
|
||||||
|
MmDeleteKernelStack(eThread->Tcb.StackBase, eThread->Tcb.StackLimit);
|
||||||
|
ObfDereferenceObject(eThread);
|
||||||
|
RETURN(X_STATUS_INSUFFICIENT_RESOURCES);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are waiting on new thread's non-kthread switching process is done before we can continue on.
|
||||||
|
signal.acquire();
|
||||||
|
|
||||||
|
// Increment the ref count of the thread once more. This is to guard against the case the title closes the thread handle
|
||||||
|
// before this thread terminates with PsTerminateSystemThread
|
||||||
|
// Test case: Amped
|
||||||
|
ObfReferenceObject(eThread);
|
||||||
|
|
||||||
|
// The ob handle of the ethread obj is the thread id we return to the title
|
||||||
|
result = ObInsertObject(eThread, zeroptr, 0, &eThread->UniqueThread);
|
||||||
|
if (X_NT_SUCCESS(result)) {
|
||||||
|
HANDLE dupHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, hThreadId);
|
||||||
|
assert(dupHandle);
|
||||||
|
RegisterXboxHandle(eThread->UniqueThread, dupHandle);
|
||||||
|
|
||||||
if (g_iThreadNotificationCount) {
|
if (g_iThreadNotificationCount) {
|
||||||
PspCallThreadNotificationRoutines(eThread, TRUE);
|
PspCallThreadNotificationRoutines(eThread, TRUE);
|
||||||
|
@ -343,53 +382,37 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx
|
||||||
|
|
||||||
// Create another handle to pass back to the title in the ThreadHandle argument
|
// Create another handle to pass back to the title in the ThreadHandle argument
|
||||||
result = ObOpenObjectByPointer(eThread, &PsThreadObjectType, ThreadHandle);
|
result = ObOpenObjectByPointer(eThread, &PsThreadObjectType, ThreadHandle);
|
||||||
if (!X_NT_SUCCESS(result)) {
|
}
|
||||||
ObfDereferenceObject(eThread);
|
|
||||||
RETURN(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ThreadId != zeroptr) {
|
KeQuerySystemTime(&eThread->CreateTime);
|
||||||
*ThreadId = eThread->UniqueThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
// PCSTProxy is responsible for cleaning up this pointer
|
if (X_NT_SUCCESS(result)) {
|
||||||
PCSTProxyParam *iPCSTProxyParam = new PCSTProxyParam;
|
|
||||||
iPCSTProxyParam->Ethread = eThread;
|
|
||||||
iPCSTProxyParam->TlsDataSize = TlsDataSize;
|
|
||||||
|
|
||||||
unsigned int ThreadId;
|
|
||||||
HANDLE handle = reinterpret_cast<HANDLE>(_beginthreadex(NULL, hKernelStackSize, PCSTProxy, iPCSTProxyParam, CREATE_SUSPENDED, &ThreadId));
|
|
||||||
if (handle == zeroptr) {
|
|
||||||
delete iPCSTProxyParam;
|
|
||||||
ObpClose(eThread->UniqueThread);
|
|
||||||
ObfDereferenceObject(eThread);
|
|
||||||
RETURN(X_STATUS_INSUFFICIENT_RESOURCES);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increment the ref count of the thread once more. This is to guard against the case the title closes the thread handle
|
|
||||||
// before this thread terminates with PsTerminateSystemThread
|
|
||||||
// Test case: Amped
|
|
||||||
ObfReferenceObject(eThread);
|
|
||||||
|
|
||||||
KeQuerySystemTime(&eThread->CreateTime);
|
|
||||||
RegisterXboxHandle(*ThreadHandle, handle);
|
RegisterXboxHandle(*ThreadHandle, handle);
|
||||||
HANDLE dupHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, ThreadId);
|
|
||||||
assert(dupHandle);
|
|
||||||
RegisterXboxHandle(eThread->UniqueThread, dupHandle);
|
|
||||||
|
|
||||||
g_AffinityPolicy->SetAffinityXbox(handle);
|
g_AffinityPolicy->SetAffinityXbox(handle);
|
||||||
|
|
||||||
// Now that ThreadId is populated and affinity is changed, resume the thread (unless the guest passed CREATE_SUSPENDED)
|
if (ThreadId != zeroptr) {
|
||||||
if (!CreateSuspended) {
|
*ThreadId = eThread->UniqueThread;
|
||||||
ResumeThread(handle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log ThreadID identical to how GetCurrentThreadID() is rendered :
|
// Log ThreadID identical to how GetCurrentThreadID() is rendered :
|
||||||
EmuLog(LOG_LEVEL::DEBUG, "Created Xbox proxy thread. Handle : 0x%X, ThreadId : [0x%.4X], Native Handle : 0x%X, Native ThreadId : [0x%.4X]",
|
EmuLog(LOG_LEVEL::DEBUG, "Created Xbox proxy thread. Handle : 0x%X, ThreadId : [0x%.4X], Native Handle : 0x%X, Native ThreadId : [0x%.4X]",
|
||||||
*ThreadHandle, eThread->UniqueThread, handle, ThreadId);
|
*ThreadHandle, eThread->UniqueThread, handle, ThreadId);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
eThread->Tcb.HasTerminated = true;
|
||||||
|
}
|
||||||
|
|
||||||
RETURN(X_STATUS_SUCCESS);
|
// If thread is set to be terminated, allow thread to run and perform termination process from its own thread.
|
||||||
|
if (eThread->Tcb.HasTerminated) {
|
||||||
|
ResumeThread(handle);
|
||||||
|
}
|
||||||
|
// Now that ThreadId is populated and affinity is changed, resume the thread (unless the guest passed CREATE_SUSPENDED)
|
||||||
|
else if (!CreateSuspended) {
|
||||||
|
ResumeThread(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ******************************************************************
|
// ******************************************************************
|
||||||
|
|
Loading…
Reference in New Issue