From 9082891903745a4e7095a1ab0f18028d05acb976 Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Wed, 29 Dec 2021 21:17:19 +0100 Subject: [PATCH] Make Ps functions use Ob to create thread handles --- src/common/Timer.cpp | 2 + src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 5 +- src/core/kernel/common/ps.h | 8 +- src/core/kernel/common/types.h | 3 +- src/core/kernel/exports/EmuKrnlKe.cpp | 8 +- src/core/kernel/exports/EmuKrnlKi.cpp | 5 +- src/core/kernel/exports/EmuKrnlKi.h | 1 + src/core/kernel/exports/EmuKrnlPs.cpp | 94 ++++++++++++++++------- src/core/kernel/init/CxbxKrnl.cpp | 74 ++---------------- src/core/kernel/init/CxbxKrnl.h | 11 +-- src/core/kernel/support/EmuFS.cpp | 83 ++++++++++++-------- src/core/kernel/support/EmuFS.h | 4 +- 12 files changed, 142 insertions(+), 156 deletions(-) diff --git a/src/common/Timer.cpp b/src/common/Timer.cpp index 0cbfc8e4e..457b3867f 100644 --- a/src/common/Timer.cpp +++ b/src/common/Timer.cpp @@ -34,6 +34,7 @@ #include "Timer.h" #include "common\util\CxbxUtil.h" #include "core\kernel\init\CxbxKrnl.h" +#include "core\kernel\support\EmuFS.h" #ifdef __linux__ #include #endif @@ -142,6 +143,7 @@ void ClockThread(TimerObject* Timer) if (GetTime_NS(Timer) > NewExpireTime) { if (Timer->Exit.load()) { Timer_Destroy(Timer); + EmuKeFreeThread(); return; } Timer->Callback(Timer->Opaque); diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 86894a588..01d5768c8 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -36,6 +36,7 @@ #include "CxbxVersion.h" #include "core\kernel\init\CxbxKrnl.h" #include "core\kernel\support\Emu.h" +#include "core\kernel\support\EmuFS.h" #include "EmuShared.h" #include "..\FixedFunctionState.h" #include "core\hle\D3D8\ResourceTracker.h" @@ -632,9 +633,6 @@ void CxbxInitWindow(bool bFullInit) // We set the priority of this thread a bit higher, to assure reliable timing : SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL); g_AffinityPolicy->SetAffinityOther(hThread); - - CxbxKrnlRegisterThread(hThread); - CloseHandle(hThread); // CxbxKrnlRegisterThread duplicates the handle so we can close this one } /* TODO : Port this Dxbx code : @@ -2173,6 +2171,7 @@ static DWORD WINAPI EmuUpdateTickCount(LPVOID) // We check for LLE flag as NV2A handles it's own VBLANK if LLE is enabled! if (bLLE_GPU) { + EmuKeFreeThread(); return 0; } diff --git a/src/core/kernel/common/ps.h b/src/core/kernel/common/ps.h index e5ec71aba..db2539342 100644 --- a/src/core/kernel/common/ps.h +++ b/src/core/kernel/common/ps.h @@ -25,7 +25,7 @@ namespace xbox XBSYSAPI EXPORTNUM(254) ntstatus_xt NTAPI PsCreateSystemThread ( OUT PHANDLE ThreadHandle, - OUT PDWORD ThreadId OPTIONAL, + OUT PHANDLE ThreadId OPTIONAL, IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext, IN boolean_xt DebuggerThread @@ -40,7 +40,7 @@ XBSYSAPI EXPORTNUM(255) ntstatus_xt NTAPI PsCreateSystemThreadEx IN ulong_xt ThreadExtensionSize, IN ulong_xt KernelStackSize, IN ulong_xt TlsDataSize, - OUT PDWORD ThreadId OPTIONAL, + OUT PHANDLE ThreadId OPTIONAL, IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext, IN boolean_xt CreateSuspended, @@ -69,7 +69,9 @@ XBSYSAPI EXPORTNUM(257) ntstatus_xt NTAPI PsSetCreateThreadNotifyRoutine // ****************************************************************** XBSYSAPI EXPORTNUM(258) void_xt NTAPI PsTerminateSystemThread(IN ntstatus_xt ExitStatus); -XBSYSAPI EXPORTNUM(259) volatile OBJECT_TYPE PsThreadObjectType; +XBSYSAPI EXPORTNUM(259) OBJECT_TYPE PsThreadObjectType; + +PETHREAD PspGetCurrentThread(); } diff --git a/src/core/kernel/common/types.h b/src/core/kernel/common/types.h index b053d70b9..b4053728c 100644 --- a/src/core/kernel/common/types.h +++ b/src/core/kernel/common/types.h @@ -81,6 +81,7 @@ typedef void* LPSECURITY_ATTRIBUTES; #define X_STATUS_UNRECOGNIZED_MEDIA 0xC0000014L #define X_STATUS_NO_MEMORY 0xC0000017L #define X_STATUS_BUFFER_TOO_SMALL 0xC0000023L +#define X_STATUS_INVALID_PARAMETER 0xC000000DL #define X_STATUS_INVALID_PARAMETER_2 0xC00000F0L #define X_STATUS_ALERTED 0x00000101L #define X_STATUS_USER_APC 0x000000C0L @@ -1916,7 +1917,7 @@ typedef struct _ETHREAD { struct _KTHREAD Tcb; uchar_xt UnknownA[0x1C]; // 0x110 - dword_xt UniqueThread; // 0x12C + HANDLE UniqueThread; // 0x12C } ETHREAD, *PETHREAD; diff --git a/src/core/kernel/exports/EmuKrnlKe.cpp b/src/core/kernel/exports/EmuKrnlKe.cpp index 338d27288..d06869692 100644 --- a/src/core/kernel/exports/EmuKrnlKe.cpp +++ b/src/core/kernel/exports/EmuKrnlKe.cpp @@ -140,11 +140,9 @@ xbox::KPCR* WINAPI KeGetPcr() Pcr = (xbox::PKPCR)__readfsdword(TIB_ArbitraryDataSlot); if (Pcr == nullptr) { - EmuLog(LOG_LEVEL::WARNING, "KeGetPCR returned nullptr: Was this called from a non-xbox thread?"); - // Attempt to salvage the situation by calling InitXboxThread to setup KPCR in place - InitXboxThread(); - g_AffinityPolicy->SetAffinityXbox(); - Pcr = (xbox::PKPCR)__readfsdword(TIB_ArbitraryDataSlot); + // If we reach here, it's a bug: it means we are executing xbox code from a host thread, and we have forgotten to intialize + // the xbox thread first + CxbxrKrnlAbort("KeGetPCR returned nullptr: Was this called from a non-xbox thread?"); } return Pcr; diff --git a/src/core/kernel/exports/EmuKrnlKi.cpp b/src/core/kernel/exports/EmuKrnlKi.cpp index 3046cf58c..5f2f66dec 100644 --- a/src/core/kernel/exports/EmuKrnlKi.cpp +++ b/src/core/kernel/exports/EmuKrnlKi.cpp @@ -88,6 +88,7 @@ the said software). #define ASSERT_TIMER_LOCKED assert(KiTimerMtx.Acquired > 0) +xbox::KPROCESS KiUniqueProcess; const xbox::ulong_xt CLOCK_TIME_INCREMENT = 0x2710; xbox::KDPC KiTimerExpireDpc; xbox::KI_TIMER_LOCK KiTimerMtx; @@ -97,13 +98,13 @@ xbox::LIST_ENTRY KiWaitInListHead; xbox::void_xt xbox::KiInitSystem() { - unsigned int i; + KiUniqueProcess.StackCount = 0; InitializeListHead(&KiWaitInListHead); KiTimerMtx.Acquired = 0; KeInitializeDpc(&KiTimerExpireDpc, KiTimerExpiration, NULL); - for (i = 0; i < TIMER_TABLE_SIZE; i++) { + for (unsigned i = 0; i < TIMER_TABLE_SIZE; i++) { InitializeListHead(&KiTimerTableListHead[i].Entry); KiTimerTableListHead[i].Time.u.HighPart = 0xFFFFFFFF; KiTimerTableListHead[i].Time.u.LowPart = 0; diff --git a/src/core/kernel/exports/EmuKrnlKi.h b/src/core/kernel/exports/EmuKrnlKi.h index 159230e49..24b73d6f0 100644 --- a/src/core/kernel/exports/EmuKrnlKi.h +++ b/src/core/kernel/exports/EmuKrnlKi.h @@ -136,6 +136,7 @@ namespace xbox ); }; +extern xbox::KPROCESS KiUniqueProcess; extern const xbox::ulong_xt CLOCK_TIME_INCREMENT; extern xbox::LIST_ENTRY KiWaitInListHead; extern xbox::KTIMER_TABLE_ENTRY KiTimerTableListHead[TIMER_TABLE_SIZE]; diff --git a/src/core/kernel/exports/EmuKrnlPs.cpp b/src/core/kernel/exports/EmuKrnlPs.cpp index 2fa2f9564..291fd0f05 100644 --- a/src/core/kernel/exports/EmuKrnlPs.cpp +++ b/src/core/kernel/exports/EmuKrnlPs.cpp @@ -31,6 +31,7 @@ #include // For PsCreateSystemThreadEx, etc. +#include "core\kernel\exports\EmuKrnlKi.h" #include // For __beginthreadex(), etc. #include // For _controlfp constants @@ -39,6 +40,7 @@ #include "core\kernel\init\CxbxKrnl.h" // For CxbxKrnl_TLS #include "core\kernel\support\Emu.h" // For EmuLog(LOG_LEVEL::WARNING, ) #include "core\kernel\support\EmuFS.h" // For EmuGenerateFS +#include "core\kernel\support\NativeHandle.h" // prevent name collisions namespace NtDll @@ -51,9 +53,10 @@ namespace NtDll // PsCreateSystemThread proxy parameters typedef struct _PCSTProxyParam { - IN PVOID StartRoutine; - IN PVOID StartContext; - IN PVOID SystemRoutine; + IN xbox::PVOID StartRoutine; + IN xbox::PVOID StartContext; + IN xbox::PVOID SystemRoutine; + IN xbox::PVOID Ethread; } PCSTProxyParam; @@ -64,23 +67,25 @@ extern int g_iThreadNotificationCount = 0; // Separate function for logging, otherwise in PCSTProxy __try wont work (Compiler Error C2712) void LOG_PCSTProxy ( - PVOID StartRoutine, - PVOID StartContext, - PVOID SystemRoutine + xbox::PVOID StartRoutine, + xbox::PVOID StartContext, + xbox::PVOID SystemRoutine, + xbox::PVOID Ethread ) { LOG_FUNC_BEGIN LOG_FUNC_ARG(StartRoutine) LOG_FUNC_ARG(StartContext) LOG_FUNC_ARG(SystemRoutine) + LOG_FUNC_ARG(Ethread) LOG_FUNC_END; } // Overload which doesn't change affinity -void InitXboxThread() +void InitXboxThread(xbox::PVOID Ethread) { // initialize FS segment selector - EmuGenerateFS(CxbxKrnl_TLS, CxbxKrnl_TLSData); + EmuGenerateFS(CxbxKrnl_TLS, CxbxKrnl_TLSData, Ethread); _controlfp(_PC_53, _MCW_PC); // Set Precision control to 53 bits (verified setting) _controlfp(_RC_NEAR, _MCW_RC); // Set Rounding control to near (unsure about this) @@ -104,11 +109,12 @@ static unsigned int WINAPI PCSTProxy LOG_PCSTProxy( params.StartRoutine, params.StartContext, - params.SystemRoutine); + params.SystemRoutine, + params.Ethread); // Do minimal thread initialization - InitXboxThread(); + InitXboxThread(params.Ethread); auto routine = (xbox::PKSYSTEM_ROUTINE)params.SystemRoutine; // Debugging notice : When the below line shows up with an Exception dialog and a @@ -137,13 +143,19 @@ void PspSystemThreadStartup xbox::PsTerminateSystemThread(X_STATUS_SUCCESS); } +xbox::PETHREAD xbox::PspGetCurrentThread() +{ + // This works because we assign ethread to Prcb->CurrentThread + return reinterpret_cast(KeGetCurrentThread()); +} + // ****************************************************************** // * 0x00FE - PsCreateSystemThread() // ****************************************************************** XBSYSAPI EXPORTNUM(254) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThread ( OUT PHANDLE ThreadHandle, - OUT PDWORD ThreadId OPTIONAL, + OUT PHANDLE ThreadId OPTIONAL, IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext, IN boolean_xt DebuggerThread @@ -187,7 +199,7 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx IN ulong_xt ThreadExtensionSize, IN ulong_xt KernelStackSize, IN ulong_xt TlsDataSize, - OUT PDWORD ThreadId OPTIONAL, + OUT PHANDLE ThreadId OPTIONAL, IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext, IN boolean_xt CreateSuspended, @@ -222,7 +234,31 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx // create thread, using our special proxy technique { - DWORD dwThreadId = 0; + PETHREAD eThread; + ntstatus_xt result = ObCreateObject(&PsThreadObjectType, zeroptr, sizeof(ETHREAD) + ThreadExtensionSize, reinterpret_cast(&eThread)); + if (!X_NT_SUCCESS(result)) { + RETURN(result); + } + + std::memset(eThread, 0, sizeof(ETHREAD) + ThreadExtensionSize); + + // 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)) { + ObfDereferenceObject(eThread); + RETURN(result); + } + + // Create another handle to pass back to the title in the ThreadHandle argument + result = ObOpenObjectByPointer(eThread, &PsThreadObjectType, ThreadHandle); + if (!X_NT_SUCCESS(result)) { + ObfDereferenceObject(eThread); + RETURN(result); + } + + if (ThreadId != zeroptr) { + *ThreadId = eThread->UniqueThread; + } // PCSTProxy is responsible for cleaning up this pointer PCSTProxyParam *iPCSTProxyParam = new PCSTProxyParam; @@ -230,6 +266,7 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx iPCSTProxyParam->StartRoutine = (PVOID)StartRoutine; iPCSTProxyParam->StartContext = StartContext; iPCSTProxyParam->SystemRoutine = (PVOID)SystemRoutine; // NULL, XapiThreadStartup or unknown? + iPCSTProxyParam->Ethread = eThread; /* // call thread notification routine(s) @@ -253,27 +290,27 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx } }*/ - HANDLE handle = reinterpret_cast(_beginthreadex(NULL, KernelStackSize, PCSTProxy, iPCSTProxyParam, CREATE_SUSPENDED, reinterpret_cast(&dwThreadId))); + HANDLE handle = reinterpret_cast(_beginthreadex(NULL, KernelStackSize, PCSTProxy, iPCSTProxyParam, CREATE_SUSPENDED, nullptr)); if (handle == NULL) { delete iPCSTProxyParam; + ObpClose(eThread->UniqueThread); + ObfDereferenceObject(eThread); RETURN(X_STATUS_INSUFFICIENT_RESOURCES); } - *ThreadHandle = handle; - if (ThreadId != NULL) - *ThreadId = dwThreadId; + + KiUniqueProcess.StackCount++; + RegisterXboxHandle(ThreadHandle, handle); + RegisterXboxHandle(eThread->UniqueThread, handle); g_AffinityPolicy->SetAffinityXbox(handle); - CxbxKrnlRegisterThread(handle); // Now that ThreadId is populated and affinity is changed, resume the thread (unless the guest passed CREATE_SUSPENDED) if (!CreateSuspended) { ResumeThread(handle); } - // Note : DO NOT use iPCSTProxyParam anymore, since ownership is transferred to the proxy (which frees it too) - // Log ThreadID identical to how GetCurrentThreadID() is rendered : - EmuLog(LOG_LEVEL::DEBUG, "Created Xbox proxy thread. Handle : 0x%X, ThreadId : [0x%.4X]", handle, dwThreadId); + EmuLog(LOG_LEVEL::DEBUG, "Created Xbox proxy thread. Handle : 0x%X, ThreadId : [0x%.4X]", *ThreadHandle, eThread->UniqueThread); } RETURN(X_STATUS_SUCCESS); @@ -289,14 +326,13 @@ XBSYSAPI EXPORTNUM(256) xbox::ntstatus_xt NTAPI xbox::PsQueryStatistics { LOG_FUNC_ONE_ARG_OUT(ProcessStatistics); - NTSTATUS ret = X_STATUS_SUCCESS; + ntstatus_xt ret = X_STATUS_SUCCESS; if (ProcessStatistics->Length == sizeof(PS_STATISTICS)) { - LOG_INCOMPLETE(); // TODO : Return number of threads and handles that currently exist - ProcessStatistics->ThreadCount = 1; - ProcessStatistics->HandleCount = 1; + ProcessStatistics->ThreadCount = KiUniqueProcess.StackCount; + ProcessStatistics->HandleCount = ObpObjectHandleTable.HandleCount; // This currently doesn't count native handles that we use as xbox handles } else { - ret = STATUS_INVALID_PARAMETER; + ret = X_STATUS_INVALID_PARAMETER; } RETURN(ret); @@ -368,7 +404,9 @@ XBSYSAPI EXPORTNUM(258) xbox::void_xt NTAPI xbox::PsTerminateSystemThread } }*/ - EmuKeFreePcr(); + EmuKeFreeThread(); + KiUniqueProcess.StackCount--; + _endthreadex(ExitStatus); // ExitThread(ExitStatus); // CxbxKrnlTerminateThread(); @@ -377,7 +415,7 @@ XBSYSAPI EXPORTNUM(258) xbox::void_xt NTAPI xbox::PsTerminateSystemThread // ****************************************************************** // * 0x0103 - PsThreadObjectType // ****************************************************************** -XBSYSAPI EXPORTNUM(259) xbox::OBJECT_TYPE VOLATILE xbox::PsThreadObjectType = +XBSYSAPI EXPORTNUM(259) xbox::OBJECT_TYPE xbox::PsThreadObjectType = { xbox::ExAllocatePoolWithTag, xbox::ExFreePool, diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index a5c963a02..c1685dd5f 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -93,9 +93,6 @@ DebugMode CxbxrKrnl_DebugMode = DebugMode::DM_NONE; std::string CxbxrKrnl_DebugFileName = ""; Xbe::Certificate *g_pCertificate = NULL; -/*! thread handles */ -static std::vector g_hThreads; - char szFilePath_CxbxReloaded_Exe[MAX_PATH] = { 0 }; std::string g_DataFilePath; char szFilePath_EEPROM_bin[MAX_PATH] = { 0 }; @@ -364,6 +361,8 @@ static unsigned int WINAPI CxbxKrnlInterruptThread(PVOID param) Sleep(1); } + EmuKeFreeThread(); + return 0; } @@ -1405,8 +1404,6 @@ static void CxbxrKrnlInitHacks() CxbxrLogDumpXbeInfo(pLibraryVersion); - CxbxKrnlRegisterThread(GetCurrentThread()); - // Make sure the Xbox1 code runs on one core (as the box itself has only 1 CPU, // this will better aproximate the environment with regard to multi-threading) : EmuLogInit(LOG_LEVEL::DEBUG, "Determining CPU affinity."); @@ -1511,12 +1508,14 @@ static void CxbxrKrnlInitHacks() DWORD dwThreadId; HANDLE hThread = (HANDLE)_beginthreadex(NULL, NULL, CxbxKrnlInterruptThread, NULL, NULL, (unsigned int*)&dwThreadId); // Start the kernel clock thread - TimerObject* KernelClockThr = Timer_Create(CxbxKrnlClockThread, nullptr, "Kernel clock thread", false); + TimerObject* KernelClockThr = Timer_Create(CxbxKrnlClockThread, nullptr, "Kernel clock thread", true); Timer_Start(KernelClockThr, SCALE_MS_IN_NS); EmuLogInit(LOG_LEVEL::DEBUG, "Calling XBE entry point..."); CxbxLaunchXbe(Entry); + EmuKeFreeThread(); + // FIXME: Wait for Cxbx to exit or error fatally Sleep(INFINITE); @@ -1544,8 +1543,6 @@ static void CxbxrKrnlInitHacks() { g_bEmuException = true; - CxbxKrnlResume(); - // print out error message (if exists) if(szErrorMessage != NULL) { @@ -1575,67 +1572,6 @@ static void CxbxrKrnlInitHacks() CxbxKrnlShutDown(); } -void CxbxKrnlRegisterThread(HANDLE hThread) -{ - // we must duplicate this handle in order to retain Suspend/Resume thread rights from a remote thread - { - HANDLE hDupHandle = NULL; - - if (DuplicateHandle(g_CurrentProcessHandle, hThread, g_CurrentProcessHandle, &hDupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) { - hThread = hDupHandle; // Thread handle was duplicated, continue registration with the duplicate - } - else { - auto message = CxbxGetLastErrorString("DuplicateHandle"); - EmuLog(LOG_LEVEL::WARNING, message.c_str()); - } - } - - g_hThreads.push_back(hThread); -} - -void CxbxKrnlSuspend() -{ - if(g_bEmuSuspended || g_bEmuException) - return; - - for (auto it = g_hThreads.begin(); it != g_hThreads.end(); ++it) - { - DWORD dwExitCode; - - if(GetExitCodeThread(*it, &dwExitCode) && dwExitCode == STILL_ACTIVE) { - // suspend thread if it is active - SuspendThread(*it); - } else { - // remove thread from thread list if it is dead - g_hThreads.erase(it); - } - } - - g_bEmuSuspended = true; -} - -void CxbxKrnlResume() -{ - if(!g_bEmuSuspended) - return; - - for (auto it = g_hThreads.begin(); it != g_hThreads.end(); ++it) - { - DWORD dwExitCode; - - if (GetExitCodeThread(*it, &dwExitCode) && dwExitCode == STILL_ACTIVE) { - // resume thread if it is active - ResumeThread(*it); - } - else { - // remove thread from thread list if it is dead - g_hThreads.erase(it); - } - } - - g_bEmuSuspended = false; -} - void CxbxKrnlShutDown(bool is_reboot) { if (!is_reboot) { diff --git a/src/core/kernel/init/CxbxKrnl.h b/src/core/kernel/init/CxbxKrnl.h index f22a61fa5..f59818e5b 100644 --- a/src/core/kernel/init/CxbxKrnl.h +++ b/src/core/kernel/init/CxbxKrnl.h @@ -151,15 +151,6 @@ void CxbxKrnlEmulate(unsigned int system, blocks_reserved_t blocks_reserved); #define CxbxrKrnlAbort(fmt, ...) CxbxrKrnlAbortEx(LOG_PREFIX, fmt, ##__VA_ARGS__) -/*! register a thread handle */ -void CxbxKrnlRegisterThread(HANDLE hThread); - -/*! suspend emulation */ -void CxbxKrnlSuspend(); - -/*! resume emulation */ -void CxbxKrnlResume(); - /*! terminate gracefully the emulation */ void CxbxKrnlShutDown(bool is_reboot = false); @@ -193,7 +184,7 @@ extern ULONG g_CxbxFatalErrorCode; extern size_t g_SystemMaxMemory; -void InitXboxThread(); +void InitXboxThread(xbox::PVOID Ethread = xbox::zeroptr); /*! thread local storage structure */ extern Xbe::TLS *CxbxKrnl_TLS; diff --git a/src/core/kernel/support/EmuFS.cpp b/src/core/kernel/support/EmuFS.cpp index 8b43d22e6..a5e4a0a3d 100644 --- a/src/core/kernel/support/EmuFS.cpp +++ b/src/core/kernel/support/EmuFS.cpp @@ -190,35 +190,39 @@ void EmuKeSetPcr(xbox::KPCR *Pcr) void EmuKeFreePcr() { - // NOTE: don't call KeGetPcr because that one creates a new pcr for the thread when __readfsdword returns nullptr, which we don't want - xbox::PKPCR Pcr = reinterpret_cast(__readfsdword(TIB_ArbitraryDataSlot)); + xbox::PKPCR Pcr = KeGetPcr(); + + xbox::PVOID Dummy; + xbox::ulong_xt Size; + xbox::ntstatus_xt Status; + // tls can be nullptr + if (Pcr->NtTib.StackBase) { + // NOTE: the tls pointer was increased by 12 bytes to enforce the 16 bytes alignment, so adjust it to reach the correct pointer + // that was allocated by xbox::NtAllocateVirtualMemory + Dummy = static_cast(Pcr->NtTib.StackBase) - 12; + Size = xbox::zero; + Status = xbox::NtFreeVirtualMemory(&Dummy, &Size, XBOX_MEM_RELEASE); // free tls + assert(Status == X_STATUS_SUCCESS); + } + Dummy = Pcr; + Size = xbox::zero; + Status = xbox::NtFreeVirtualMemory(&Dummy, &Size, XBOX_MEM_RELEASE); // free pcr + assert(Status == X_STATUS_SUCCESS); + __writefsdword(TIB_ArbitraryDataSlot, NULL); +} - if (Pcr) { - // tls can be nullptr - xbox::PVOID Dummy; - xbox::ulong_xt Size; - xbox::ntstatus_xt Status; - if (Pcr->NtTib.StackBase) { - // NOTE: the tls pointer was increased by 12 bytes to enforce the 16 bytes alignment, so adjust it to reach the correct pointer - // that was allocated by xbox::NtAllocateVirtualMemory - Dummy = static_cast(Pcr->NtTib.StackBase) - 12; - Size = xbox::zero; - Status = xbox::NtFreeVirtualMemory(&Dummy, &Size, XBOX_MEM_RELEASE); // free tls - assert(Status == X_STATUS_SUCCESS); - } - Dummy = Pcr->Prcb->CurrentThread; - Size = xbox::zero; - Status = xbox::NtFreeVirtualMemory(&Dummy, &Size, XBOX_MEM_RELEASE); // free ethread - assert(Status == X_STATUS_SUCCESS); - Dummy = Pcr; - Size = xbox::zero; - Status = xbox::NtFreeVirtualMemory(&Dummy, &Size, XBOX_MEM_RELEASE); // free pcr - assert(Status == X_STATUS_SUCCESS); - __writefsdword(TIB_ArbitraryDataSlot, NULL); - } - else { - EmuLog(LOG_LEVEL::WARNING, "__readfsdword in EmuKeFreePcr returned nullptr: was this called from a non-xbox thread?"); +void EmuKeFreeThread() +{ + // This functions is to be used for cxbxr threads that execute xbox code. We can't just call PsTerminateSystemThread because some additional + // xbox state is not created for this kind of threads + + xbox::PETHREAD eThread = xbox::PspGetCurrentThread(); + if (eThread->UniqueThread != NULL) { + xbox::NtClose(eThread->UniqueThread); + eThread->UniqueThread = NULL; } + + EmuKeFreePcr(); } __declspec(naked) void EmuFS_RefreshKPCR() @@ -652,7 +656,7 @@ void EmuInitFS() } // generate fs segment selector -void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData) +void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData, xbox::PVOID Ethread) { void *pNewTLS = nullptr; xbox::PVOID base; @@ -781,14 +785,25 @@ void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData) // Initialize a fake PrcbData.CurrentThread { - base = xbox::zeroptr; - size = sizeof(xbox::ETHREAD); - xbox::NtAllocateVirtualMemory(&base, 0, &size, XBOX_MEM_RESERVE | XBOX_MEM_COMMIT, XBOX_PAGE_READWRITE); - xbox::ETHREAD *EThread = (xbox::ETHREAD*)base; // Clear, to prevent side-effects on random contents - xbox::RtlZeroMemory(EThread, sizeof(xbox::ETHREAD)); + xbox::PETHREAD EThread = static_cast(Ethread); + if (EThread == xbox::zeroptr) { + // If it is nullptr, it means we are creating this thread from cxbxr, otherwise we were created from PsCreateSystemThreadEx + xbox::PETHREAD eThread; + xbox::ntstatus_xt result = xbox::ObCreateObject(&xbox::PsThreadObjectType, xbox::zeroptr, sizeof(xbox::ETHREAD), reinterpret_cast(&eThread)); + if (!X_NT_SUCCESS(result)) { + // We can't recover from here, abort execution + CxbxrKrnlAbort("ObCreateObject: failed to create new xbox thread!"); + } + std::memset(eThread, 0, sizeof(xbox::ETHREAD)); + EThread = eThread; + result = xbox::ObInsertObject(eThread, xbox::zeroptr, 0, &eThread->UniqueThread); + if (!X_NT_SUCCESS(result)) { + // We can't recover from here, abort execution + CxbxrKrnlAbort("ObInsertObject: failed to create new xbox thread!"); + } + } EThread->Tcb.TlsData = pNewTLS; - EThread->UniqueThread = GetCurrentThreadId(); // Set PrcbData.CurrentThread Prcb->CurrentThread = (xbox::KTHREAD*)EThread; // Initialize the thread header and its wait list diff --git a/src/core/kernel/support/EmuFS.h b/src/core/kernel/support/EmuFS.h index 029b2c75d..402adb568 100644 --- a/src/core/kernel/support/EmuFS.h +++ b/src/core/kernel/support/EmuFS.h @@ -33,8 +33,10 @@ extern void EmuInitFS(); // generate fs segment selector -extern void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData); +extern void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData, xbox::PVOID Ethread); // free resources allocated for the thread +void EmuKeFreeThread(); +// free kpcr allocated for the thread void EmuKeFreePcr(); typedef struct