diff --git a/src/common/Timer.cpp b/src/common/Timer.cpp index 72881273a..c9515856c 100644 --- a/src/common/Timer.cpp +++ b/src/common/Timer.cpp @@ -25,8 +25,6 @@ // * // ****************************************************************** -#include - #ifdef _WIN32 #include #endif @@ -36,6 +34,7 @@ #include "Timer.h" #include "common\util\CxbxUtil.h" #include "core\kernel\support\EmuFS.h" +#include "core/kernel/exports/EmuKrnlPs.hpp" #ifdef __linux__ #include #endif @@ -218,7 +217,7 @@ void Timer_Start(TimerObject* Timer, uint64_t Expire_MS) Timer->ExpireTime_MS.store(Expire_MS); if (Timer->IsXboxTimer) { xbox::HANDLE hThread; - xbox::PsCreateSystemThread(&hThread, xbox::zeroptr, ClockThread, Timer, FALSE); + CxbxrCreateThread(&hThread, xbox::zeroptr, ClockThread, Timer, FALSE); } else { std::thread(ClockThread, Timer).detach(); diff --git a/src/core/kernel/exports/EmuKrnlPs.cpp b/src/core/kernel/exports/EmuKrnlPs.cpp index 1e4b7b599..c4a63ec3a 100644 --- a/src/core/kernel/exports/EmuKrnlPs.cpp +++ b/src/core/kernel/exports/EmuKrnlPs.cpp @@ -154,7 +154,7 @@ static unsigned int WINAPI PCSTProxy return 0; // will never be reached } -// Placeholder system function, instead of XapiThreadStartup +// Placeholder system function xbox::void_xt NTAPI PspSystemThreadStartup ( IN xbox::PKSTART_ROUTINE StartRoutine, @@ -231,6 +231,35 @@ xbox::void_xt NTAPI PspReaperRoutine( } } +xbox::ntstatus_xt NTAPI CxbxrCreateThread +( + OUT xbox::PHANDLE ThreadHandle, + OUT xbox::PHANDLE ThreadId OPTIONAL, + IN xbox::PKSTART_ROUTINE StartRoutine, + IN xbox::PVOID StartContext, + IN xbox::boolean_xt DebuggerThread +) +{ + Xbe::TLS* XbeTls = (Xbe::TLS*)CxbxKrnl_Xbe->m_Header.dwTLSAddr; + xbox::ulong_xt TlsDataSize = (XbeTls->dwDataEndAddr - XbeTls->dwDataStartAddr); + TlsDataSize += XbeTls->dwSizeofZeroFill + 15; + TlsDataSize = (TlsDataSize & ~15) + 4; + // Verify EmuGenerateFS's TlsData's setup is carry over to XapiThreadStartup function. + // Instead of using PspSystemThreadStartup which is entirely different function. + return xbox::PsCreateSystemThreadEx( + /*OUT*/ThreadHandle, + /*ThreadExtensionSize=*/0, + /*KernelStackSize=*/KERNEL_STACK_SIZE, + TlsDataSize, + /*OUT*/ThreadId, + /*StartRoutine=*/StartRoutine, + StartContext, + /*CreateSuspended=*/FALSE, + /*DebuggerThread=*/DebuggerThread, + /*SystemRoutine=*/PspSystemThreadStartup // should use XapiThreadStartup + ); +} + static xbox::KDPC PsReaperDpc; xbox::void_xt xbox::PsInitSystem() { diff --git a/src/core/kernel/exports/EmuKrnlPs.hpp b/src/core/kernel/exports/EmuKrnlPs.hpp index 7533803d9..42ae4b73a 100644 --- a/src/core/kernel/exports/EmuKrnlPs.hpp +++ b/src/core/kernel/exports/EmuKrnlPs.hpp @@ -26,3 +26,12 @@ namespace xbox { void_xt PsInitSystem(); }; + +xbox::ntstatus_xt NTAPI CxbxrCreateThread +( + OUT xbox::PHANDLE ThreadHandle, + OUT xbox::PHANDLE ThreadId OPTIONAL, + IN xbox::PKSTART_ROUTINE StartRoutine, + IN xbox::PVOID StartContext, + IN xbox::boolean_xt DebuggerThread +); diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index 88093c0b7..9fd11d04d 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -1432,7 +1432,7 @@ static void CxbxrKrnlInitHacks() EmuX86_Init(); // Create the interrupt processing thread xbox::HANDLE hThread; - xbox::PsCreateSystemThread(&hThread, xbox::zeroptr, CxbxKrnlInterruptThread, xbox::zeroptr, FALSE); + CxbxrCreateThread(&hThread, xbox::zeroptr, CxbxKrnlInterruptThread, xbox::zeroptr, FALSE); // Start the kernel clock thread TimerObject* KernelClockThr = Timer_Create(CxbxKrnlClockThread, nullptr, "Kernel clock thread", true); Timer_Start(KernelClockThr, SCALE_MS_IN_NS); diff --git a/src/core/kernel/support/EmuFS.cpp b/src/core/kernel/support/EmuFS.cpp index c5293a4f9..7a84c68d5 100644 --- a/src/core/kernel/support/EmuFS.cpp +++ b/src/core/kernel/support/EmuFS.cpp @@ -770,6 +770,25 @@ void EmuGenerateFS(xbox::PETHREAD Ethread, unsigned Host2XbStackBaseReserved, un } #endif + // Initialize TlsData in order to avoid xbox's APIs attempt to try access null pointer from CxbxrCreateThread. + // As far as I have seen, Xapi's CreateThread's startup function is the only one that does the tls' initialization. + // It will repeat same process yet will not cause performance impact. + // NOTE: PsCreateSystemThread's startup function does not do tls' initialization. + if (Ethread->Tcb.TlsData) { + Xbe::TLS* XbeTls = (Xbe::TLS*)CxbxKrnl_Xbe->m_Header.dwTLSAddr; + uint32_t RawTlsDataSize = XbeTls->dwDataEndAddr - XbeTls->dwDataStartAddr; + // First index is a pointer to the array of tls datas. + xbox::addr_xt* TlsData = reinterpret_cast(Ethread->Tcb.TlsData); + *TlsData = reinterpret_cast(Ethread->Tcb.TlsData) + sizeof(xbox::addr_xt); + // Set the actual tls data from xbe. + TlsData += 1; + std::memcpy(TlsData, reinterpret_cast(XbeTls->dwDataStartAddr), RawTlsDataSize); + + if (XbeTls->dwSizeofZeroFill) { + std::memset(reinterpret_cast(TlsData) + RawTlsDataSize, 0, XbeTls->dwSizeofZeroFill); + } + } + // Initialize a fake PrcbData.CurrentThread { // TODO: Do we need NtTib's overwrite in ENABLE_KTHREAD_SWITCHING usage?