diff --git a/src/core/libraries/kernel/threads/pthread.cpp b/src/core/libraries/kernel/threads/pthread.cpp index eca81c6c0..bc0d1f295 100644 --- a/src/core/libraries/kernel/threads/pthread.cpp +++ b/src/core/libraries/kernel/threads/pthread.cpp @@ -197,7 +197,11 @@ int PS4_SYSV_ABI posix_pthread_detach(PthreadT pthread) { return 0; } -static void RunThread(void* arg) { +#ifdef WIN32 +static DWORD RunThread(void* arg) { +#else +static void* RunThread(void* arg) { +#endif auto* curthread = static_cast(arg); g_curthread = curthread; Common::SetCurrentThreadName(curthread->name.c_str()); @@ -214,6 +218,11 @@ static void RunThread(void* arg) { /* Remove thread from tracking */ DebugState.RemoveCurrentThreadFromGuestList(); posix_pthread_exit(ret); +#ifdef WIN32 + return 0; +#else + return nullptr; +#endif } int PS4_SYSV_ABI posix_pthread_create_name_np(PthreadT* thread, const PthreadAttrT* attr, diff --git a/src/core/libraries/kernel/threads/stack.s b/src/core/libraries/kernel/threads/stack.s index 0adc7ef8b..fbaf86e2b 100644 --- a/src/core/libraries/kernel/threads/stack.s +++ b/src/core/libraries/kernel/threads/stack.s @@ -5,6 +5,19 @@ _runOnAnotherStack: pushq %r12 pushq %r13 +#ifdef WIN32 + pushq %r14 + pushq %r15 + + # save stack check registers + movq %gs:0x08, %r14 # teb->stack_bottom + movq %gs:0x10, %r15 # teb->stack_top + + # disable stack checks + xorq %rcx, %rcx + movq %rcx, %gs:0x08 # teb->stack_bottom = 0 + movq %rcx, %gs:0x10 # teb->stack_top = 0 +#endif movq %rsp, %r12 movq %rbp, %r13 movq %rdx, %rsp @@ -12,6 +25,13 @@ _runOnAnotherStack: callq *%rsi movq %r13, %rbp movq %r12, %rsp +#ifdef WIN32 + # restore stack check registers + movq %r14, %gs:0x08 # teb->stack_bottom + movq %r15, %gs:0x10 # teb->stack_top + popq %r15 + popq %r14 +#endif popq %r13 popq %r12 ret diff --git a/src/core/thread.cpp b/src/core/thread.cpp index 717c7e5f9..ee879a7d8 100644 --- a/src/core/thread.cpp +++ b/src/core/thread.cpp @@ -19,67 +19,20 @@ namespace Core { static constexpr u32 ORBIS_MXCSR = 0x9fc0; static constexpr u32 ORBIS_FPUCW = 0x037f; -#ifdef _WIN64 -#define KGDT64_R3_DATA (0x28) -#define KGDT64_R3_CODE (0x30) -#define KGDT64_R3_CMTEB (0x50) -#define RPL_MASK (0x03) -#define EFLAGS_INTERRUPT_MASK (0x200) - -void InitializeTeb(INITIAL_TEB* teb, void* stackaddr, size_t stacksize) { - teb->StackBase = (void*)((u64)stackaddr + stacksize); - teb->StackLimit = nullptr; - teb->StackAllocationBase = stackaddr; -} - -void InitializeContext(CONTEXT* ctx, ThreadFunc func, void* arg, void* stackaddr, - size_t stacksize) { - /* Note: The stack has to be reversed */ - ctx->Rsp = (u64)stackaddr + stacksize; - ctx->Rbp = (u64)stackaddr + stacksize; - ctx->Rcx = (u64)arg; - ctx->Rip = (u64)func; - - ctx->SegGs = KGDT64_R3_DATA | RPL_MASK; - ctx->SegEs = KGDT64_R3_DATA | RPL_MASK; - ctx->SegDs = KGDT64_R3_DATA | RPL_MASK; - ctx->SegCs = KGDT64_R3_CODE | RPL_MASK; - ctx->SegSs = KGDT64_R3_DATA | RPL_MASK; - ctx->SegFs = KGDT64_R3_CMTEB | RPL_MASK; - - ctx->EFlags = 0x3000 | EFLAGS_INTERRUPT_MASK; - - ctx->ContextFlags = - CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT; -} -#endif - NativeThread::NativeThread() : native_handle{0} {} NativeThread::~NativeThread() {} int NativeThread::Create(ThreadFunc func, void* arg) { - constexpr size_t stacksize = 8_KB; - init_stack_ptr = malloc(stacksize); #ifndef _WIN64 pthread_t* pthr = reinterpret_cast(&native_handle); - pthread_attr_t pattr; - pthread_attr_init(&pattr); - pthread_attr_setstack(&pattr, init_stack_ptr, stacksize); - return pthread_create(pthr, &pattr, (PthreadFunc)func, arg); + return pthread_create(pthr, nullptr, func, arg); #else - CLIENT_ID clientId{}; - INITIAL_TEB teb{}; - CONTEXT ctx{}; - - clientId.UniqueProcess = GetCurrentProcess(); - clientId.UniqueThread = GetCurrentThread(); - - InitializeTeb(&teb, init_stack_ptr, stacksize); - InitializeContext(&ctx, func, arg, init_stack_ptr, stacksize); - - return NtCreateThread(&native_handle, THREAD_ALL_ACCESS, nullptr, GetCurrentProcess(), - &clientId, &ctx, &teb, false); + native_handle = CreateThread(nullptr, 0, func, arg, 0, nullptr); + if (native_handle == nullptr) { + return GetLastError(); + } + return 0; #endif } @@ -91,28 +44,8 @@ void NativeThread::Exit() { tid = 0; #ifdef _WIN64 - NtClose(native_handle); native_handle = nullptr; - - /* The Windows kernel will free the stack - given at thread creation via INITIAL_TEB - (StackAllocationBase) upon thread termination. - - In earlier Windows versions (NT4 to Windows Server 2003), - you could get around this via disabling FreeStackOnTermination - on the TEB. This has been removed since then. - - To avoid this, we must forcefully set the TEB - deallocation stack pointer to NULL so ZwFreeVirtualMemory fails - in the kernel and our stack is not freed. - */ - auto* teb = reinterpret_cast(NtCurrentTeb()); - teb->DeallocationStack = nullptr; - - if (init_stack_ptr != nullptr) { - free(init_stack_ptr); - } - NtTerminateThread(nullptr, 0); + ExitThread(0); #else // Disable and free the signal stack. constexpr stack_t sig_stack = { @@ -124,10 +57,6 @@ void NativeThread::Exit() { free(sig_stack_ptr); sig_stack_ptr = nullptr; } - - if (init_stack_ptr != nullptr) { - free(init_stack_ptr); - } pthread_exit(nullptr); #endif } diff --git a/src/core/thread.h b/src/core/thread.h index ec06b62eb..ca3d08ff9 100644 --- a/src/core/thread.h +++ b/src/core/thread.h @@ -10,9 +10,11 @@ struct PthreadAttr; } // namespace Libraries::Kernel namespace Core { - -using ThreadFunc = void (*)(void*); -using PthreadFunc = void* (*)(void*); +#ifdef WIN32 +using ThreadFunc = DWORD (*)(void*); +#else +using ThreadFunc = void* (*)(void*); +#endif class NativeThread { public: @@ -39,7 +41,6 @@ private: uintptr_t native_handle; void* sig_stack_ptr = nullptr; #endif - void* init_stack_ptr = nullptr; u64 tid; };