Make Ps functions use Ob to create thread handles

This commit is contained in:
ergo720 2021-12-29 21:17:19 +01:00
parent 484a2c3f47
commit 9082891903
12 changed files with 142 additions and 156 deletions

View File

@ -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 <time.h>
#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);

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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];

View File

@ -31,6 +31,7 @@
#include <core\kernel\exports\xboxkrnl.h> // For PsCreateSystemThreadEx, etc.
#include "core\kernel\exports\EmuKrnlKi.h"
#include <process.h> // For __beginthreadex(), etc.
#include <float.h> // 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<PETHREAD>(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<PVOID *>(&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<HANDLE>(_beginthreadex(NULL, KernelStackSize, PCSTProxy, iPCSTProxyParam, CREATE_SUSPENDED, reinterpret_cast<unsigned int*>(&dwThreadId)));
HANDLE handle = reinterpret_cast<HANDLE>(_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,

View File

@ -93,9 +93,6 @@ DebugMode CxbxrKrnl_DebugMode = DebugMode::DM_NONE;
std::string CxbxrKrnl_DebugFileName = "";
Xbe::Certificate *g_pCertificate = NULL;
/*! thread handles */
static std::vector<HANDLE> 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) {

View File

@ -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;

View File

@ -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<xbox::PKPCR>(__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<xbox::PBYTE>(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<xbox::PBYTE>(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<xbox::PETHREAD>(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<PVOID *>(&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

View File

@ -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