Merge pull request #2339 from RadWolfie/improve-thread-setup
Improve Xbox Thread Setup
This commit is contained in:
commit
5f7b9417b0
|
@ -177,6 +177,7 @@ file (GLOB CXBXR_HEADER_EMU
|
|||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlKe.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlKi.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlLogging.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlPs.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/init/CxbxKrnl.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/init/KrnlPatches.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/memory-manager/PhysicalMemory.h"
|
||||
|
|
|
@ -1401,7 +1401,7 @@ typedef struct _KTIMER
|
|||
ULARGE_INTEGER DueTime; // 0x10
|
||||
LIST_ENTRY TimerListEntry; // 0x18
|
||||
struct _KDPC *Dpc; // 0x20
|
||||
long_xt Period; // 0x24
|
||||
long_xt Period; // 0x24
|
||||
}
|
||||
KTIMER, *PKTIMER;
|
||||
|
||||
|
@ -1424,7 +1424,7 @@ typedef void_xt (NTAPI *PKSTART_ROUTINE)
|
|||
// * opposed to 1.
|
||||
// *
|
||||
// ******************************************************************
|
||||
typedef void_xt (*PKSYSTEM_ROUTINE)
|
||||
typedef void_xt (NTAPI *PKSYSTEM_ROUTINE)
|
||||
(
|
||||
IN PKSTART_ROUTINE StartRoutine OPTIONAL,
|
||||
IN PVOID StartContext OPTIONAL
|
||||
|
@ -1435,7 +1435,7 @@ struct _KDPC;
|
|||
// ******************************************************************
|
||||
// * PKDEFERRED_ROUTINE
|
||||
// ******************************************************************
|
||||
typedef void_xt (__stdcall *PKDEFERRED_ROUTINE)
|
||||
typedef void_xt (NTAPI *PKDEFERRED_ROUTINE)
|
||||
(
|
||||
IN struct _KDPC *Dpc,
|
||||
IN PVOID DeferredContext,
|
||||
|
@ -1474,6 +1474,14 @@ typedef struct _DPC_QUEUE_ENTRY
|
|||
}
|
||||
DPC_QUEUE_ENTRY, *PDPC_QUEUE_ENTRY;
|
||||
|
||||
|
||||
// ******************************************************************
|
||||
// * NPX_STATE flags
|
||||
// ******************************************************************
|
||||
// Source: ReactOS
|
||||
#define NPX_STATE_NOT_LOADED 0xA
|
||||
#define NPX_STATE_LOADED 0x0
|
||||
|
||||
// ******************************************************************
|
||||
// * KFLOATING_SAVE
|
||||
// ******************************************************************
|
||||
|
@ -1492,6 +1500,21 @@ typedef struct _KFLOATING_SAVE
|
|||
}
|
||||
KFLOATING_SAVE, *PKFLOATING_SAVE;
|
||||
|
||||
// ******************************************************************
|
||||
// * KTHREAD_STATE
|
||||
// ******************************************************************
|
||||
// Source: ReactOS
|
||||
typedef enum _KTHREAD_STATE
|
||||
{
|
||||
Initialized,
|
||||
Ready,
|
||||
Running,
|
||||
Standby,
|
||||
Terminated,
|
||||
Waiting,
|
||||
Transition
|
||||
} KTHREAD_STATE, * PKTHREAD_STATE;
|
||||
|
||||
#define DISPATCHER_OBJECT_TYPE_MASK 0x7
|
||||
// ******************************************************************
|
||||
// * KOBJECTS
|
||||
|
@ -1529,7 +1552,7 @@ typedef void_xt (NTAPI *PKNORMAL_ROUTINE)
|
|||
// ******************************************************************
|
||||
// * PKKERNEL_ROUTINE
|
||||
// ******************************************************************
|
||||
typedef void_xt (*PKKERNEL_ROUTINE)
|
||||
typedef void_xt (NTAPI *PKKERNEL_ROUTINE)
|
||||
(
|
||||
IN struct _KAPC *Apc,
|
||||
IN OUT PKNORMAL_ROUTINE *NormalRoutine,
|
||||
|
@ -1541,7 +1564,7 @@ typedef void_xt (*PKKERNEL_ROUTINE)
|
|||
// ******************************************************************
|
||||
// * PKRUNDOWN_ROUTINE
|
||||
// ******************************************************************
|
||||
typedef void_xt (*PKRUNDOWN_ROUTINE)
|
||||
typedef void_xt (NTAPI *PKRUNDOWN_ROUTINE)
|
||||
(
|
||||
IN struct _KAPC *Apc
|
||||
);
|
||||
|
@ -1549,7 +1572,7 @@ typedef void_xt (*PKRUNDOWN_ROUTINE)
|
|||
// ******************************************************************
|
||||
// * PKSYNCHRONIZE_ROUTINE
|
||||
// ******************************************************************
|
||||
typedef boolean_xt (*PKSYNCHRONIZE_ROUTINE)
|
||||
typedef boolean_xt (NTAPI *PKSYNCHRONIZE_ROUTINE)
|
||||
(
|
||||
IN PVOID SynchronizeContext
|
||||
);
|
||||
|
@ -1557,7 +1580,7 @@ typedef boolean_xt (*PKSYNCHRONIZE_ROUTINE)
|
|||
// ******************************************************************
|
||||
// * PKSERVICE_ROUTINE
|
||||
// ******************************************************************
|
||||
typedef boolean_xt (*PKSERVICE_ROUTINE)
|
||||
typedef boolean_xt (NTAPI *PKSERVICE_ROUTINE)
|
||||
(
|
||||
IN struct _KINTERRUPT *Interrupt,
|
||||
IN PVOID ServiceContext
|
||||
|
@ -1636,8 +1659,8 @@ PS_STATISTICS, *PPS_STATISTICS;
|
|||
typedef struct _RTL_CRITICAL_SECTION
|
||||
{
|
||||
DISPATCHER_HEADER Event; // 0x00
|
||||
long_xt LockCount; // 0x10
|
||||
long_xt RecursionCount; // 0x14
|
||||
long_xt LockCount; // 0x10
|
||||
long_xt RecursionCount; // 0x14
|
||||
HANDLE OwningThread; // 0x18
|
||||
}
|
||||
RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;
|
||||
|
@ -1654,7 +1677,7 @@ typedef struct _NT_TIB
|
|||
union
|
||||
{
|
||||
PVOID FiberData; // 0x10 for TIB
|
||||
ulong_xt Version; // 0x10 for TEB (?)
|
||||
ulong_xt Version; // 0x10 for TEB (?)
|
||||
}
|
||||
u_a;
|
||||
PVOID ArbitraryUserPointer; // 0x14
|
||||
|
@ -1753,6 +1776,40 @@ typedef struct _KQUEUE
|
|||
}
|
||||
KQUEUE, *PKQUEUE, *RESTRICTED_POINTER PRKQUEUE;
|
||||
|
||||
// ******************************************************************
|
||||
// * KSTART_FRAME
|
||||
// ******************************************************************
|
||||
typedef struct _KSTART_FRAME
|
||||
{
|
||||
PKSYSTEM_ROUTINE SystemRoutine;
|
||||
PKSTART_ROUTINE StartRoutine;
|
||||
PVOID StartContext;
|
||||
} KSTART_FRAME, *PKSTART_FRAME;
|
||||
|
||||
// ******************************************************************
|
||||
// * KSWITCHFRAME
|
||||
// ******************************************************************
|
||||
typedef struct _KSWITCHFRAME
|
||||
{
|
||||
PVOID ExceptionList;
|
||||
dword_xt Unknown;
|
||||
PVOID RetAddr;
|
||||
} KSWITCHFRAME, *PKSWITCHFRAME;
|
||||
|
||||
// Exception record flags
|
||||
// Source: ReactOS
|
||||
// NOTE: Do not exclude X_ prefix, they will conflict with the macros provided by Windows
|
||||
#define X_EXCEPTION_NONCONTINUABLE 0x01
|
||||
#define X_EXCEPTION_UNWINDING 0x02
|
||||
#define X_EXCEPTION_EXIT_UNWIND 0x04
|
||||
#define X_EXCEPTION_STACK_INVALID 0x08
|
||||
#define X_EXCEPTION_NESTED_CALL 0x10
|
||||
#define X_EXCEPTION_TARGET_UNWIND 0x20
|
||||
#define X_EXCEPTION_COLLIDED_UNWIND 0x40
|
||||
#define X_EXCEPTION_UNWIND (X_EXCEPTION_UNWINDING | X_EXCEPTION_EXIT_UNWIND | X_EXCEPTION_TARGET_UNWIND | X_EXCEPTION_COLLIDED_UNWIND)
|
||||
|
||||
#define X_EXCEPTION_CHAIN_END 0xFFFFFFFF
|
||||
|
||||
// ******************************************************************
|
||||
// * EXCEPTION_DISPOSITION
|
||||
// ******************************************************************
|
||||
|
@ -1925,11 +1982,14 @@ typedef struct _ETHREAD
|
|||
LARGE_INTEGER CreateTime; // 0x110
|
||||
LARGE_INTEGER ExitTime; // 0x118
|
||||
ntstatus_xt ExitStatus; // 0x120
|
||||
uchar_xt Unknown[0x8]; // 0x124
|
||||
LIST_ENTRY ReaperLink; // 0x124
|
||||
HANDLE UniqueThread; // 0x12C
|
||||
PVOID StartAddress; // 0x130
|
||||
LIST_ENTRY IrpList; // 0x134
|
||||
PVOID DebugData; // 0x13C
|
||||
}
|
||||
ETHREAD, *PETHREAD;
|
||||
static_assert(sizeof(ETHREAD) == 0x130);
|
||||
static_assert(sizeof(ETHREAD) == 0x140);
|
||||
|
||||
// ******************************************************************
|
||||
// * PCREATE_THREAD_NOTIFY_ROUTINE
|
||||
|
@ -1954,13 +2014,13 @@ typedef struct _KPRCB
|
|||
struct _KTHREAD* NextThread; // 0x04, KPCR : 0x2C
|
||||
struct _KTHREAD* IdleThread; // 0x08, KPCR : 0x30
|
||||
|
||||
ulong_xt Unknown1[7]; // 0x0C, KPCR : 0x34
|
||||
ulong_xt Unknown1[7]; // 0x0C, KPCR : 0x34
|
||||
|
||||
LIST_ENTRY DpcListHead; // 0x28, KPCR : 0x50
|
||||
ulong_xt DpcRoutineActive; // 0x30, KPCR : 0x58
|
||||
ulong_xt DpcRoutineActive; // 0x30, KPCR : 0x58
|
||||
|
||||
// This completes the total size of the structure (presumably)
|
||||
uchar_xt Unknown[0x224];
|
||||
uchar_xt Unknown[0x224];
|
||||
}
|
||||
KPRCB, *PKPRCB;
|
||||
|
||||
|
@ -1977,7 +2037,7 @@ typedef struct _KPCR
|
|||
struct _NT_TIB NtTib; // 0x00
|
||||
struct _KPCR *SelfPcr; // 0x1C
|
||||
struct _KPRCB *Prcb; // 0x20
|
||||
uchar_xt Irql; // 0x24
|
||||
uchar_xt Irql; // 0x24
|
||||
struct _KPRCB PrcbData; // 0x28
|
||||
}
|
||||
KPCR, *PKPCR;
|
||||
|
@ -2532,6 +2592,13 @@ typedef struct _FLOATING_SAVE_AREA
|
|||
dword_xt Cr0NpxState;
|
||||
} FLOATING_SAVE_AREA, *PFLOATING_SAVE_AREA;
|
||||
#pragma pack(pop)
|
||||
static_assert(sizeof(_FLOATING_SAVE_AREA) == 0x204);
|
||||
|
||||
typedef struct _FX_SAVE_AREA {
|
||||
FLOATING_SAVE_AREA FloatSave;
|
||||
ulong_xt Unknown[3];
|
||||
} FX_SAVE_AREA, *PFX_SAVE_AREA;
|
||||
static_assert(sizeof(_FX_SAVE_AREA) == 0x210);
|
||||
|
||||
typedef struct _CONTEXT
|
||||
{
|
||||
|
|
|
@ -266,7 +266,9 @@ xbox::void_xt NTAPI xbox::KeInitializeTimer
|
|||
xbox::void_xt xbox::KeEmptyQueueApc()
|
||||
{
|
||||
PKTHREAD kThread = KeGetCurrentThread();
|
||||
KeEnterCriticalRegion();
|
||||
kThread->ApcState.ApcQueueable = FALSE;
|
||||
KeLeaveCriticalRegion();
|
||||
|
||||
KiApcListMtx.lock();
|
||||
for (int Mode = KernelMode; Mode < MaximumMode; ++Mode) {
|
||||
|
@ -280,6 +282,150 @@ xbox::void_xt xbox::KeEmptyQueueApc()
|
|||
KiApcListMtx.unlock();
|
||||
}
|
||||
|
||||
// Source: ReactOS (modified to fit in xbox compatibility layer)
|
||||
template<bool IsHostThread>
|
||||
xbox::void_xt xbox::KeInitializeThread(
|
||||
IN OUT PKTHREAD Thread,
|
||||
IN PVOID KernelStack,
|
||||
IN ulong_xt KernelStackSize,
|
||||
IN ulong_xt TlsDataSize,
|
||||
IN PKSYSTEM_ROUTINE SystemRoutine,
|
||||
IN PKSTART_ROUTINE StartRoutine,
|
||||
IN PVOID StartContext,
|
||||
IN PKPROCESS Process
|
||||
)
|
||||
{
|
||||
/* ReactOS's KeInitThread inline code begin */
|
||||
|
||||
/* Initialize the Dispatcher Header */
|
||||
Thread->Header.Type = xbox::ThreadObject;
|
||||
Thread->Header.Size = sizeof(xbox::KTHREAD) / sizeof(xbox::long_xt);
|
||||
// ThreadControlFlags
|
||||
// DebugActive
|
||||
Thread->Header.SignalState = 0;
|
||||
InitializeListHead(&Thread->Header.WaitListHead);
|
||||
|
||||
/* Initialize the Mutant List */
|
||||
InitializeListHead(&Thread->MutantListHead);
|
||||
|
||||
#if 0 // Not used or not yet reverse engineered
|
||||
/* Set swap settings */
|
||||
Thread->EnableStackSwap = TRUE;
|
||||
Thread->IdealProcessor = 1;
|
||||
Thread->SwapBusy = FALSE;
|
||||
Thread->KernelStackResident = TRUE;
|
||||
Thread->AdjustReason = AdjustNone;
|
||||
#endif
|
||||
|
||||
#if 0 // Not used or not yet reverse engineered
|
||||
/* Initialize the lock */
|
||||
KeInitializeSpinLock(&Thread->ThreadLock);
|
||||
#endif
|
||||
|
||||
#if 0 // Not used or not yet reverse engineered
|
||||
/* Setup the Service Descriptor Table for Native Calls */
|
||||
Thread->ServiceTable = KeServiceDescriptorTable;
|
||||
#endif
|
||||
|
||||
/* Setup APC Fields */
|
||||
InitializeListHead(&Thread->ApcState.ApcListHead[xbox::KernelMode]);
|
||||
InitializeListHead(&Thread->ApcState.ApcListHead[xbox::UserMode]);
|
||||
Thread->KernelApcDisable = 0;
|
||||
Thread->ApcState.Process = &KiUniqueProcess;
|
||||
Thread->ApcState.ApcQueueable = TRUE;
|
||||
Thread->ApcState.Process->ThreadQuantum = KiUniqueProcess.ThreadQuantum;
|
||||
|
||||
/* Initialize the Suspend APC */
|
||||
KeInitializeApc(
|
||||
&Thread->SuspendApc,
|
||||
Thread,
|
||||
KiSuspendNop,
|
||||
zeroptr,
|
||||
KiSuspendThread,
|
||||
KernelMode,
|
||||
zeroptr);
|
||||
|
||||
/* Initialize the Suspend Semaphore */
|
||||
KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 2);
|
||||
|
||||
/* Setup the timer */
|
||||
xbox::KeInitializeTimer(&Thread->Timer);
|
||||
xbox::PKWAIT_BLOCK TimerWaitBlock = &Thread->TimerWaitBlock;
|
||||
TimerWaitBlock->Object = &Thread->Timer;
|
||||
TimerWaitBlock->WaitKey = (xbox::cshort_xt)X_STATUS_TIMEOUT;
|
||||
TimerWaitBlock->WaitType = xbox::WaitAny;
|
||||
TimerWaitBlock->Thread = Thread;
|
||||
TimerWaitBlock->NextWaitBlock = zeroptr;
|
||||
|
||||
/* Link the two wait lists together */
|
||||
TimerWaitBlock->WaitListEntry.Flink = &Thread->Timer.Header.WaitListHead;
|
||||
TimerWaitBlock->WaitListEntry.Blink = &Thread->Timer.Header.WaitListHead;
|
||||
|
||||
#if 0 // Not used or not yet reverse engineered
|
||||
/* Set the TEB and process */
|
||||
Thread->Teb = Teb;
|
||||
Thread->Process = Process;
|
||||
#endif
|
||||
|
||||
/* Set the Thread Stacks */
|
||||
Thread->StackBase = KernelStack;
|
||||
Thread->StackLimit = reinterpret_cast<PVOID>(reinterpret_cast<ulong_ptr_xt>(KernelStack) - KernelStackSize);
|
||||
|
||||
/* Initialize the Thread Context */
|
||||
KiInitializeContextThread(Thread, TlsDataSize, SystemRoutine, StartRoutine, StartContext);
|
||||
|
||||
/* Set the Thread to initialized */
|
||||
Thread->State = Initialized;
|
||||
|
||||
/* ReactOS's KeInitThread inline code end */
|
||||
|
||||
/* ReactOS's KeStartThread inline code begin */
|
||||
// NOTE: The cxbxr's kernel initialization will not be insert into ThreadListHead of Process.
|
||||
if constexpr (!IsHostThread) {
|
||||
/* Setup static fields from parent */
|
||||
Thread->DisableBoost = Process->DisableBoost;
|
||||
Thread->Quantum = Process->ThreadQuantum;
|
||||
|
||||
/* Setup volatile data */
|
||||
Thread->Priority = Process->BasePriority;
|
||||
Thread->BasePriority = Process->BasePriority;
|
||||
|
||||
/* Lock the Dispatcher Database */
|
||||
UCHAR orig_irql = KeRaiseIrqlToDpcLevel();
|
||||
|
||||
/* Insert the thread into the process list */
|
||||
InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
|
||||
/* Increase the stack count */
|
||||
Process->StackCount++;
|
||||
|
||||
/* Release lock and return */
|
||||
KfLowerIrql(orig_irql);
|
||||
}
|
||||
/* ReactOS's KeStartThread inline code end */
|
||||
}
|
||||
template
|
||||
xbox::void_xt xbox::KeInitializeThread<true>(
|
||||
IN OUT PKTHREAD Thread,
|
||||
IN PVOID KernelStack,
|
||||
IN ulong_xt KernelStackSize,
|
||||
IN ulong_xt TlsDataSize,
|
||||
IN PKSYSTEM_ROUTINE SystemRoutine,
|
||||
IN PKSTART_ROUTINE StartRoutine,
|
||||
IN PVOID StartContext,
|
||||
IN PKPROCESS Process
|
||||
);
|
||||
template
|
||||
xbox::void_xt xbox::KeInitializeThread<false>(
|
||||
IN OUT PKTHREAD Thread,
|
||||
IN PVOID KernelStack,
|
||||
IN ulong_xt KernelStackSize,
|
||||
IN ulong_xt TlsDataSize,
|
||||
IN PKSYSTEM_ROUTINE SystemRoutine,
|
||||
IN PKSTART_ROUTINE StartRoutine,
|
||||
IN PVOID StartContext,
|
||||
IN PKPROCESS Process
|
||||
);
|
||||
|
||||
// Forward KeLowerIrql() to KfLowerIrql()
|
||||
#define KeLowerIrql(NewIrql) \
|
||||
KfLowerIrql(NewIrql)
|
||||
|
|
|
@ -38,5 +38,17 @@ namespace xbox
|
|||
IN PKTIMER Timer
|
||||
);
|
||||
|
||||
template<bool IsHostThread = false>
|
||||
void_xt KeInitializeThread(
|
||||
IN OUT PKTHREAD Thread,
|
||||
IN PVOID KernelStack,
|
||||
IN ulong_xt KernelStackSize,
|
||||
IN ulong_xt TlsDataSize,
|
||||
IN PKSYSTEM_ROUTINE SystemRoutine,
|
||||
IN PKSTART_ROUTINE StartRoutine,
|
||||
IN PVOID StartContext,
|
||||
IN PKPROCESS Process
|
||||
);
|
||||
|
||||
void_xt KeEmptyQueueApc();
|
||||
}
|
||||
|
|
|
@ -945,3 +945,115 @@ xbox::PLARGE_INTEGER FASTCALL xbox::KiComputeWaitInterval
|
|||
return NewTime;
|
||||
}
|
||||
}
|
||||
|
||||
// Source: ReactOS
|
||||
xbox::void_xt NTAPI xbox::KiSuspendNop(
|
||||
IN PKAPC Apc,
|
||||
IN PKNORMAL_ROUTINE* NormalRoutine,
|
||||
IN PVOID* NormalContext,
|
||||
IN PVOID* SystemArgument1,
|
||||
IN PVOID* SystemArgument2
|
||||
)
|
||||
{
|
||||
/* Does nothing */
|
||||
UNREFERENCED_PARAMETER(Apc);
|
||||
UNREFERENCED_PARAMETER(NormalRoutine);
|
||||
UNREFERENCED_PARAMETER(NormalContext);
|
||||
UNREFERENCED_PARAMETER(SystemArgument1);
|
||||
UNREFERENCED_PARAMETER(SystemArgument2);
|
||||
}
|
||||
|
||||
// Source: ReactOS
|
||||
xbox::void_xt NTAPI xbox::KiSuspendThread(
|
||||
IN PVOID NormalContext,
|
||||
IN PVOID SystemArgument1,
|
||||
IN PVOID SystemArgument2
|
||||
)
|
||||
{
|
||||
/* Non-alertable kernel-mode suspended wait */
|
||||
KeWaitForSingleObject(
|
||||
&KeGetCurrentThread()->SuspendSemaphore,
|
||||
Suspended,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
zeroptr);
|
||||
}
|
||||
|
||||
xbox::void_xt NTAPI xbox::KiThreadStartup(void_xt)
|
||||
{
|
||||
PKSTART_FRAME StartFrame;
|
||||
PKSWITCHFRAME SwitchFrame;
|
||||
|
||||
/* Get the start and trap frames */
|
||||
SwitchFrame = reinterpret_cast<PKSWITCHFRAME>(KeGetCurrentThread()->KernelStack);
|
||||
StartFrame = reinterpret_cast<PKSTART_FRAME>(SwitchFrame + 1);
|
||||
|
||||
/* Lower to Passive level */
|
||||
KfLowerIrql(PASSIVE_LEVEL);
|
||||
|
||||
// NOTE: if assert is triggered, then thread-switching may have been processed.
|
||||
// If it does, then verify xbox thread's StackBase is from MmCreateKernelStack instead of host's stack and was not deleted by MmDeleteKernelStack.
|
||||
// Otherwise, feel free to clear this reminder message.
|
||||
assert(0);
|
||||
|
||||
/* Call the system routine */
|
||||
StartFrame->SystemRoutine(StartFrame->StartRoutine, StartFrame->StartContext);
|
||||
|
||||
/* We do not return as it is a top function */
|
||||
PsTerminateSystemThread(X_STATUS_NO_MEMORY);
|
||||
}
|
||||
|
||||
// Source: ReactOS (modified to fit in xbox compatibility layer)
|
||||
xbox::void_xt xbox::KiInitializeContextThread(
|
||||
IN PKTHREAD Thread,
|
||||
IN ulong_xt TlsDataSize,
|
||||
IN PKSYSTEM_ROUTINE SystemRoutine,
|
||||
IN PKSTART_ROUTINE StartRoutine,
|
||||
IN PVOID StartContext
|
||||
)
|
||||
{
|
||||
addr_xt StackAddress = reinterpret_cast<addr_xt>(Thread->StackBase);
|
||||
|
||||
/* Setup the Fx Area */
|
||||
StackAddress -= sizeof(FX_SAVE_AREA);
|
||||
PFX_SAVE_AREA FxSaveArea = reinterpret_cast<PFX_SAVE_AREA>(StackAddress);
|
||||
std::memset(FxSaveArea, 0, sizeof(FX_SAVE_AREA));
|
||||
|
||||
/* Set the stub FX area */
|
||||
FxSaveArea->FloatSave.ControlWord = 0x27F;
|
||||
FxSaveArea->FloatSave.MXCsr = 0x1F80;
|
||||
|
||||
/* No NPX State */
|
||||
Thread->NpxState = NPX_STATE_NOT_LOADED;
|
||||
|
||||
/* Setup the Stack for TlsData dynamic sized array */
|
||||
TlsDataSize = ALIGN_UP(TlsDataSize, ulong_xt);
|
||||
StackAddress -= TlsDataSize; // TlsData section (optional)
|
||||
if (TlsDataSize) {
|
||||
Thread->TlsData = reinterpret_cast<PVOID>(StackAddress);
|
||||
// Title will process which section of TlsData will be fill with data and zero'd.
|
||||
// So, we leave this untouched.
|
||||
}
|
||||
else {
|
||||
Thread->TlsData = zeroptr;
|
||||
}
|
||||
|
||||
/* Setup the Stack for KiThreadStartup and Context Switching */
|
||||
StackAddress -= sizeof(KSTART_FRAME);
|
||||
PKSTART_FRAME StartFrame = reinterpret_cast<PKSTART_FRAME>(StackAddress);
|
||||
StackAddress -= sizeof(KSWITCHFRAME);
|
||||
PKSWITCHFRAME CtxSwitchFrame = reinterpret_cast<PKSWITCHFRAME>(StackAddress);
|
||||
|
||||
/* Now setup the remaining data for KiThreadStartup */
|
||||
StartFrame->StartContext = StartContext;
|
||||
StartFrame->StartRoutine = StartRoutine;
|
||||
StartFrame->SystemRoutine = SystemRoutine;
|
||||
|
||||
/* And set up the Context Switch Frame */
|
||||
CtxSwitchFrame->RetAddr = KiThreadStartup;
|
||||
CtxSwitchFrame->Unknown = 0x200; // TODO: Find out what this field is.
|
||||
CtxSwitchFrame->ExceptionList = reinterpret_cast<PVOID>(X_EXCEPTION_CHAIN_END);
|
||||
|
||||
/* Save back the new value of the kernel stack. */
|
||||
Thread->KernelStack = reinterpret_cast<PVOID>(CtxSwitchFrame);
|
||||
}
|
||||
|
|
|
@ -146,6 +146,32 @@ namespace xbox
|
|||
IN PLARGE_INTEGER DueTime,
|
||||
IN OUT PLARGE_INTEGER NewTime
|
||||
);
|
||||
|
||||
// Source: ReactOS
|
||||
void_xt NTAPI KiSuspendNop(
|
||||
IN PKAPC Apc,
|
||||
IN PKNORMAL_ROUTINE* NormalRoutine,
|
||||
IN PVOID* NormalContext,
|
||||
IN PVOID* SystemArgument1,
|
||||
IN PVOID* SystemArgument2
|
||||
);
|
||||
|
||||
// Source: ReactOS
|
||||
void_xt NTAPI KiSuspendThread(
|
||||
IN PVOID NormalContext,
|
||||
IN PVOID SystemArgument1,
|
||||
IN PVOID SystemArgument2
|
||||
);
|
||||
|
||||
void_xt NTAPI KiThreadStartup(void_xt);
|
||||
|
||||
xbox::void_xt KiInitializeContextThread(
|
||||
IN PKTHREAD Thread,
|
||||
IN ulong_xt TlsDataSize,
|
||||
IN PKSYSTEM_ROUTINE SystemRoutine,
|
||||
IN PKSTART_ROUTINE StartRoutine,
|
||||
IN PVOID StartContext
|
||||
);
|
||||
};
|
||||
|
||||
extern xbox::KPROCESS KiUniqueProcess;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
|
||||
#include <core\kernel\exports\xboxkrnl.h> // For PsCreateSystemThreadEx, etc.
|
||||
#include "EmuKrnlPs.hpp"
|
||||
#include "core\kernel\exports\EmuKrnlKi.h"
|
||||
#include "core\kernel\exports\EmuKrnlKe.h"
|
||||
#include <process.h> // For __beginthreadex(), etc.
|
||||
|
@ -55,10 +56,8 @@ namespace NtDll
|
|||
// PsCreateSystemThread proxy parameters
|
||||
typedef struct _PCSTProxyParam
|
||||
{
|
||||
IN xbox::PVOID StartRoutine;
|
||||
IN xbox::PVOID StartContext;
|
||||
IN xbox::PVOID SystemRoutine;
|
||||
IN xbox::PVOID Ethread;
|
||||
IN xbox::ulong_xt TlsDataSize;
|
||||
}
|
||||
PCSTProxyParam;
|
||||
|
||||
|
@ -72,7 +71,8 @@ void LOG_PCSTProxy
|
|||
xbox::PVOID StartRoutine,
|
||||
xbox::PVOID StartContext,
|
||||
xbox::PVOID SystemRoutine,
|
||||
xbox::PVOID Ethread
|
||||
xbox::PVOID Ethread,
|
||||
xbox::ulong_xt TlsDataSize
|
||||
)
|
||||
{
|
||||
LOG_FUNC_BEGIN
|
||||
|
@ -80,6 +80,7 @@ void LOG_PCSTProxy
|
|||
LOG_FUNC_ARG(StartContext)
|
||||
LOG_FUNC_ARG(SystemRoutine)
|
||||
LOG_FUNC_ARG(Ethread)
|
||||
LOG_FUNC_ARG(TlsDataSize)
|
||||
LOG_FUNC_END;
|
||||
}
|
||||
|
||||
|
@ -97,32 +98,49 @@ static unsigned int WINAPI PCSTProxy
|
|||
// Copy params to the stack so they can be freed
|
||||
PCSTProxyParam params = *iPCSTProxyParam;
|
||||
delete iPCSTProxyParam;
|
||||
|
||||
LOG_PCSTProxy(
|
||||
params.StartRoutine,
|
||||
params.StartContext,
|
||||
params.SystemRoutine,
|
||||
params.Ethread);
|
||||
#ifndef ENABLE_KTHREAD_SWITCHING
|
||||
unsigned Host2XbStackBaseReserved = 0;
|
||||
__asm mov Host2XbStackBaseReserved, esp;
|
||||
unsigned Host2XbStackSizeReserved = EmuGenerateStackSize(Host2XbStackBaseReserved, params.TlsDataSize);
|
||||
__asm sub esp, Host2XbStackSizeReserved;
|
||||
#endif
|
||||
|
||||
// Do minimal thread initialization
|
||||
EmuGenerateFS(CxbxKrnl_TLS, CxbxKrnl_TLSData, static_cast<xbox::PETHREAD>(params.Ethread));
|
||||
xbox::PETHREAD eThread = static_cast<xbox::PETHREAD>(params.Ethread);
|
||||
#ifndef ENABLE_KTHREAD_SWITCHING
|
||||
EmuGenerateFS(eThread, Host2XbStackBaseReserved, Host2XbStackSizeReserved);
|
||||
#else
|
||||
EmuGenerateFS(eThread);
|
||||
#endif
|
||||
xbox::PKSTART_FRAME StartFrame = reinterpret_cast<xbox::PKSTART_FRAME>(reinterpret_cast<xbox::addr_xt>(eThread->Tcb.KernelStack) + sizeof(xbox::KSWITCHFRAME));
|
||||
|
||||
auto routine = (xbox::PKSYSTEM_ROUTINE)params.SystemRoutine;
|
||||
LOG_PCSTProxy(
|
||||
StartFrame->StartRoutine,
|
||||
StartFrame->StartContext,
|
||||
StartFrame->SystemRoutine,
|
||||
params.Ethread,
|
||||
params.TlsDataSize);
|
||||
|
||||
auto routine = (xbox::PKSYSTEM_ROUTINE)StartFrame->SystemRoutine;
|
||||
// Debugging notice : When the below line shows up with an Exception dialog and a
|
||||
// message like: "Exception thrown at 0x00026190 in cxbx.exe: 0xC0000005: Access
|
||||
// violation reading location 0xFD001804.", then this is AS-DESIGNED behaviour!
|
||||
// (To avoid repetitions, uncheck "Break when this exception type is thrown").
|
||||
routine(xbox::PKSTART_ROUTINE(params.StartRoutine), params.StartContext);
|
||||
routine(StartFrame->StartRoutine, StartFrame->StartContext);
|
||||
|
||||
// This will also handle thread notification :
|
||||
LOG_TEST_CASE("Thread returned from SystemRoutine");
|
||||
xbox::PsTerminateSystemThread(X_STATUS_SUCCESS);
|
||||
|
||||
#ifndef ENABLE_KTHREAD_SWITCHING
|
||||
__asm add esp, Host2XbStackSizeReserved;
|
||||
#endif
|
||||
|
||||
return 0; // will never be reached
|
||||
}
|
||||
|
||||
// Placeholder system function, instead of XapiThreadStartup
|
||||
void PspSystemThreadStartup
|
||||
xbox::void_xt NTAPI PspSystemThreadStartup
|
||||
(
|
||||
IN xbox::PKSTART_ROUTINE StartRoutine,
|
||||
IN PVOID StartContext
|
||||
|
@ -151,6 +169,64 @@ static xbox::void_xt PspCallThreadNotificationRoutines(xbox::PETHREAD eThread, x
|
|||
}
|
||||
}
|
||||
|
||||
// Source: ReactOS
|
||||
xbox::LIST_ENTRY PspReaperListHead;
|
||||
xbox::void_xt NTAPI PspReaperRoutine(
|
||||
IN xbox::PKDPC Dpc,
|
||||
IN xbox::PVOID DeferredContext,
|
||||
IN xbox::PVOID SystemArgument1,
|
||||
IN xbox::PVOID SystemArgument2
|
||||
)
|
||||
{
|
||||
using namespace xbox;
|
||||
xbox::PLIST_ENTRY NextEntry;
|
||||
PETHREAD Thread;
|
||||
//PSTRACE(PS_KILL_DEBUG, "Context: %p\n", Context);
|
||||
|
||||
/* Write magic value and return the next entry to process */
|
||||
NextEntry = PspReaperListHead.Flink;
|
||||
|
||||
/* Start loop */
|
||||
while (NextEntry != &PspReaperListHead) {
|
||||
/* Get the first Thread Entry */
|
||||
Thread = CONTAINING_RECORD(NextEntry, ETHREAD, ReaperLink);
|
||||
|
||||
RemoveEntryList(NextEntry);
|
||||
|
||||
// Currently, only kernel's stack portion reside on the host's stack.
|
||||
// Once we have our own kernel thread switching implement or in virtual environment.
|
||||
// Then enable ENABLE_KTHREAD_SWITCHING macro for any further implement needed.
|
||||
#ifdef ENABLE_KTHREAD_SWITCHING
|
||||
/* Delete this entry's kernel stack */
|
||||
MmDeleteKernelStack(Thread->Tcb.StackBase, Thread->Tcb.StackLimit);
|
||||
#else
|
||||
// Backup plan in case if certain titles did not let new thread start.
|
||||
// And therefore still have the xbox's kernel stack allocated.
|
||||
if (MmIsAddressValid(Thread->Tcb.StackBase)) {
|
||||
MmDeleteKernelStack(Thread->Tcb.StackBase, Thread->Tcb.StackLimit);
|
||||
}
|
||||
#endif
|
||||
Thread->Tcb.StackBase = zeroptr;
|
||||
|
||||
/* Move to the next entry */
|
||||
NextEntry = NextEntry->Flink;
|
||||
|
||||
/* Dereference this thread */
|
||||
ObfDereferenceObject(Thread);
|
||||
}
|
||||
}
|
||||
|
||||
static xbox::KDPC PsReaperDpc;
|
||||
xbox::void_xt xbox::PsInitSystem()
|
||||
{
|
||||
#ifdef ENABLE_KTHREAD_SWITCHING
|
||||
assert(0); // NOTE: Verify all defined ENABLE_KTHREAD_SWITCHING check are implemented
|
||||
#endif
|
||||
/* Setup the reaper */
|
||||
InitializeListHead(&PspReaperListHead);
|
||||
KeInitializeDpc(&PsReaperDpc, PspReaperRoutine, zeroptr);
|
||||
}
|
||||
|
||||
// ******************************************************************
|
||||
// * 0x00FE - PsCreateSystemThread()
|
||||
// ******************************************************************
|
||||
|
@ -222,20 +298,19 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx
|
|||
LOG_FUNC_ARG(SystemRoutine)
|
||||
LOG_FUNC_END;
|
||||
|
||||
// TODO : Arguments to use : TlsDataSize, DebuggerThread
|
||||
|
||||
// use default kernel stack size if lesser specified
|
||||
if (KernelStackSize < KERNEL_STACK_SIZE)
|
||||
KernelStackSize = KERNEL_STACK_SIZE;
|
||||
|
||||
// Double the stack size, this is to account for the overhead HLE patching adds to the stack
|
||||
KernelStackSize *= 2;
|
||||
uint32_t hKernelStackSize = KernelStackSize * 2;
|
||||
|
||||
// round up to the next page boundary if un-aligned
|
||||
KernelStackSize = RoundUp(KernelStackSize, PAGE_SIZE);
|
||||
hKernelStackSize = RoundUp(hKernelStackSize, PAGE_SIZE);
|
||||
|
||||
// create thread, using our special proxy technique
|
||||
{
|
||||
// create thread, using our special proxy technique
|
||||
{
|
||||
PETHREAD eThread;
|
||||
ntstatus_xt result = ObCreateObject(&PsThreadObjectType, zeroptr, sizeof(ETHREAD) + ThreadExtensionSize, reinterpret_cast<PVOID *>(&eThread));
|
||||
if (!X_NT_SUCCESS(result)) {
|
||||
|
@ -244,6 +319,17 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx
|
|||
|
||||
std::memset(eThread, 0, sizeof(ETHREAD) + ThreadExtensionSize);
|
||||
|
||||
// Create kernel stack for xbox title to able write on stack instead of host.
|
||||
PVOID KernelStack = MmCreateKernelStack(KernelStackSize, DebuggerThread);
|
||||
|
||||
if (!KernelStack) {
|
||||
ObfDereferenceObject(eThread);
|
||||
RETURN(X_STATUS_INSUFFICIENT_RESOURCES);
|
||||
}
|
||||
|
||||
// Start thread initialization process here before insert and create thread
|
||||
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
|
||||
result = ObInsertObject(eThread, zeroptr, 0, &eThread->UniqueThread);
|
||||
if (!X_NT_SUCCESS(result)) {
|
||||
|
@ -266,16 +352,14 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx
|
|||
*ThreadId = eThread->UniqueThread;
|
||||
}
|
||||
|
||||
// PCSTProxy is responsible for cleaning up this pointer
|
||||
// PCSTProxy is responsible for cleaning up this pointer
|
||||
PCSTProxyParam *iPCSTProxyParam = new PCSTProxyParam;
|
||||
iPCSTProxyParam->StartRoutine = (PVOID)StartRoutine;
|
||||
iPCSTProxyParam->StartContext = StartContext;
|
||||
iPCSTProxyParam->SystemRoutine = (PVOID)SystemRoutine; // NULL, XapiThreadStartup or unknown?
|
||||
iPCSTProxyParam->Ethread = eThread;
|
||||
iPCSTProxyParam->TlsDataSize = TlsDataSize;
|
||||
|
||||
unsigned int ThreadId;
|
||||
HANDLE handle = reinterpret_cast<HANDLE>(_beginthreadex(NULL, KernelStackSize, PCSTProxy, iPCSTProxyParam, CREATE_SUSPENDED, &ThreadId));
|
||||
if (handle == NULL) {
|
||||
HANDLE handle = reinterpret_cast<HANDLE>(_beginthreadex(NULL, hKernelStackSize, PCSTProxy, iPCSTProxyParam, CREATE_SUSPENDED, &ThreadId));
|
||||
if (handle == zeroptr) {
|
||||
delete iPCSTProxyParam;
|
||||
ObpClose(eThread->UniqueThread);
|
||||
ObfDereferenceObject(eThread);
|
||||
|
@ -288,8 +372,6 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx
|
|||
ObfReferenceObject(eThread);
|
||||
|
||||
KeQuerySystemTime(&eThread->CreateTime);
|
||||
InsertTailList(&KiUniqueProcess.ThreadListHead, &eThread->Tcb.ThreadListEntry);
|
||||
KiUniqueProcess.StackCount++;
|
||||
RegisterXboxHandle(*ThreadHandle, handle);
|
||||
HANDLE dupHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, ThreadId);
|
||||
assert(dupHandle);
|
||||
|
@ -368,15 +450,43 @@ XBSYSAPI EXPORTNUM(258) xbox::void_xt NTAPI xbox::PsTerminateSystemThread
|
|||
LOG_FUNC_ONE_ARG(ExitStatus);
|
||||
|
||||
xbox::PETHREAD eThread = xbox::PspGetCurrentThread();
|
||||
eThread->Tcb.HasTerminated = 1;
|
||||
|
||||
KfLowerIrql(PASSIVE_LEVEL);
|
||||
|
||||
if (eThread->UniqueThread && g_iThreadNotificationCount) {
|
||||
PspCallThreadNotificationRoutines(eThread, FALSE);
|
||||
}
|
||||
|
||||
EmuKeFreeThread(ExitStatus);
|
||||
// Don't do this in EmuKeFreeThread because we only increment the thread ref count in PsCreateSystemThreadEx
|
||||
ObfDereferenceObject(eThread);
|
||||
KeEmptyQueueApc();
|
||||
|
||||
// Emulate our exit strategy for GetExitCodeThread
|
||||
KeQuerySystemTime(&eThread->ExitTime);
|
||||
eThread->ExitStatus = ExitStatus;
|
||||
eThread->Tcb.Header.SignalState = 1;
|
||||
if (!IsListEmpty(&eThread->Tcb.Header.WaitListHead)) {
|
||||
// TODO: Implement KiWaitTest's relative objects usage
|
||||
//KiWaitTest()
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (GetNativeHandle(eThread->UniqueThread)) {
|
||||
NtClose(eThread->UniqueThread);
|
||||
eThread->UniqueThread = xbox::zeroptr;
|
||||
}
|
||||
|
||||
// Remove thread from the process
|
||||
RemoveEntryList(&eThread->Tcb.ThreadListEntry);
|
||||
eThread->Tcb.State = Terminated;
|
||||
KiUniqueProcess.StackCount--;
|
||||
|
||||
// PspReaperRoutine technically free'd the memory allocation from MmCreateKernelStack function.
|
||||
// Therefore is run from another thread.
|
||||
InsertTailList(&PspReaperListHead, &((PETHREAD)eThread)->ReaperLink);
|
||||
KeInsertQueueDpc(&PsReaperDpc, NULL, NULL);
|
||||
|
||||
EmuKeFreePcr();
|
||||
|
||||
_endthreadex(ExitStatus);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
#pragma once
|
||||
|
||||
namespace xbox
|
||||
{
|
||||
void_xt PsInitSystem();
|
||||
};
|
|
@ -50,29 +50,9 @@ namespace NtDll
|
|||
#undef RtlFillMemory
|
||||
#undef RtlMoveMemory
|
||||
#undef RtlZeroMemory
|
||||
#undef EXCEPTION_NONCONTINUABLE
|
||||
#undef EXCEPTION_UNWINDING
|
||||
#undef EXCEPTION_EXIT_UNWIND
|
||||
#undef EXCEPTION_STACK_INVALID
|
||||
#undef EXCEPTION_NESTED_CALL
|
||||
#undef EXCEPTION_TARGET_UNWIND
|
||||
#undef EXCEPTION_COLLIDED_UNWIND
|
||||
#undef EXCEPTION_UNWIND
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
// Exception record flags
|
||||
// Source: ReactOS
|
||||
// NOTE: don't put these in xboxkrnl.h, they will conflict with the macros provided by Windows
|
||||
#define EXCEPTION_NONCONTINUABLE 0x01
|
||||
#define EXCEPTION_UNWINDING 0x02
|
||||
#define EXCEPTION_EXIT_UNWIND 0x04
|
||||
#define EXCEPTION_STACK_INVALID 0x08
|
||||
#define EXCEPTION_NESTED_CALL 0x10
|
||||
#define EXCEPTION_TARGET_UNWIND 0x20
|
||||
#define EXCEPTION_COLLIDED_UNWIND 0x40
|
||||
#define EXCEPTION_UNWIND (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND | EXCEPTION_TARGET_UNWIND | EXCEPTION_COLLIDED_UNWIND)
|
||||
|
||||
xbox::dword_xt WINAPI RtlAnsiStringToUnicodeSize(const xbox::STRING *str)
|
||||
{
|
||||
return (str->Length + sizeof(ANSI_NULL)) * sizeof(WCHAR);
|
||||
|
@ -1503,7 +1483,7 @@ XBSYSAPI EXPORTNUM(303) xbox::void_xt NTAPI xbox::RtlRaiseStatus
|
|||
|
||||
EXCEPTION_RECORD record;
|
||||
record.ExceptionCode = Status;
|
||||
record.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
|
||||
record.ExceptionFlags = X_EXCEPTION_NONCONTINUABLE;
|
||||
record.ExceptionRecord = NULL;
|
||||
record.NumberParameters = 0;
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "core\kernel\exports\EmuKrnl.h"
|
||||
#include "core\kernel\exports\EmuKrnlKi.h"
|
||||
#include "core\kernel\exports\EmuKrnlKe.h"
|
||||
#include "core\kernel\exports\EmuKrnlPs.hpp"
|
||||
#include "EmuShared.h"
|
||||
#include "core\hle\D3D8\Direct3D9\Direct3D9.h" // For CxbxInitWindow, EmuD3DInit
|
||||
#include "core\hle\DSOUND\DirectSound\DirectSound.hpp" // For CxbxInitAudio
|
||||
|
@ -112,7 +113,7 @@ std::atomic_bool g_bEnableAllInterrupts = true;
|
|||
// Set by the VMManager during initialization. Exported because it's needed in other parts of the emu
|
||||
size_t g_SystemMaxMemory = 0;
|
||||
|
||||
HANDLE g_CurrentProcessHandle = 0; // Set in CxbxKrnlMain
|
||||
HANDLE g_CurrentProcessHandle = 0; // Set in CxbxKrnlEmulate
|
||||
|
||||
bool g_CxbxPrintUEM = false;
|
||||
ULONG g_CxbxFatalErrorCode = FATAL_ERROR_NONE;
|
||||
|
@ -1015,6 +1016,9 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res
|
|||
// and capture any crash from this point and beyond. Useful for capture live crash and generate crash report.
|
||||
g_ExceptionManager = new ExceptionManager();
|
||||
|
||||
// Set current process handle in order for CxbxKrnlShutDown to work properly.
|
||||
g_CurrentProcessHandle = GetCurrentProcess(); // OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
|
||||
|
||||
// First of all, check if the EmuShared version matches the emu version and abort otherwise
|
||||
char GitVersionEmuShared[GitVersionMaxLength];
|
||||
g_EmuShared->GetGitVersion(GitVersionEmuShared);
|
||||
|
@ -1068,8 +1072,6 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res
|
|||
int BootFlags;
|
||||
g_EmuShared->GetBootFlags(&BootFlags);
|
||||
|
||||
g_CurrentProcessHandle = GetCurrentProcess(); // OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
|
||||
|
||||
// Set up the logging variables for the kernel process during initialization.
|
||||
log_sync_config();
|
||||
|
||||
|
@ -1250,6 +1252,10 @@ static void CxbxrKrnlInitHacks()
|
|||
void(*Entry)(),
|
||||
int BootFlags)
|
||||
{
|
||||
unsigned Host2XbStackBaseReserved = 0;
|
||||
__asm mov Host2XbStackBaseReserved, esp;
|
||||
unsigned Host2XbStackSizeReserved = EmuGenerateStackSize(Host2XbStackBaseReserved, 0);
|
||||
__asm sub esp, Host2XbStackSizeReserved;
|
||||
// Set windows timer period to 1ms
|
||||
// Windows will automatically restore this value back to original on program exit
|
||||
// But with this, we can replace some busy loops with sleeps.
|
||||
|
@ -1404,10 +1410,11 @@ static void CxbxrKrnlInitHacks()
|
|||
|
||||
// Create a kpcr for this thread. This is necessary because ObInitSystem needs to access the irql. This must also be done before
|
||||
// CxbxInitWindow because that function creates the xbox EmuUpdateTickCount thread
|
||||
EmuGenerateFS<true>(nullptr, nullptr, xbox::zeroptr);
|
||||
EmuGenerateFS<true>(xbox::zeroptr, Host2XbStackBaseReserved, Host2XbStackSizeReserved);
|
||||
if (!xbox::ObInitSystem()) {
|
||||
CxbxrKrnlAbortEx(LOG_PREFIX_INIT, "Unable to intialize ObInitSystem.");
|
||||
}
|
||||
xbox::PsInitSystem();
|
||||
xbox::KiInitSystem();
|
||||
|
||||
// initialize graphics
|
||||
|
@ -1507,7 +1514,8 @@ static void CxbxrKrnlInitHacks()
|
|||
|
||||
xbox::PsCreateSystemThread(&hThread, xbox::zeroptr, CxbxLaunchXbe, Entry, FALSE);
|
||||
|
||||
EmuKeFreePcr<true>();
|
||||
EmuKeFreePcr();
|
||||
__asm add esp, Host2XbStackSizeReserved;
|
||||
|
||||
// This will wait forever
|
||||
std::condition_variable cv;
|
||||
|
|
|
@ -115,10 +115,8 @@
|
|||
// = 0x104/260 */ LIST_ENTRY ThreadListEntry;
|
||||
// = 0x10C/268 */ UCHAR _padding[4];
|
||||
|
||||
template void EmuGenerateFS<true>(Xbe::TLS *pTLS, void *pTLSData, xbox::PETHREAD Ethread);
|
||||
template void EmuGenerateFS<false>(Xbe::TLS *pTLS, void *pTLSData, xbox::PETHREAD Ethread);
|
||||
template void EmuKeFreePcr<true>();
|
||||
template void EmuKeFreePcr<false>();
|
||||
template void EmuGenerateFS<true>(xbox::PETHREAD Ethread, unsigned XboxStackBaseReserved, unsigned XboxStackSizeReserved);
|
||||
template void EmuGenerateFS<false>(xbox::PETHREAD Ethread, unsigned XboxStackBaseReserved, unsigned XboxStackSizeReserved);
|
||||
|
||||
NT_TIB *GetNtTib()
|
||||
{
|
||||
|
@ -194,61 +192,16 @@ void EmuKeSetPcr(xbox::KPCR *Pcr)
|
|||
__writefsdword(TIB_ArbitraryDataSlot, (DWORD)Pcr);
|
||||
}
|
||||
|
||||
template<bool IsHostThread>
|
||||
void EmuKeFreePcr()
|
||||
{
|
||||
xbox::PKPCR Pcr = EmuKeGetPcr();
|
||||
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) - TLS_ALIGNMENT_OFFSET;
|
||||
Size = xbox::zero;
|
||||
Status = xbox::NtFreeVirtualMemory(&Dummy, &Size, XBOX_MEM_RELEASE); // free tls
|
||||
assert(Status == X_STATUS_SUCCESS);
|
||||
}
|
||||
if constexpr (IsHostThread) {
|
||||
// This only happens for the kernel initialization thread of cxbxr
|
||||
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
|
||||
using namespace xbox;
|
||||
PVOID Pcr = EmuKeGetPcr();
|
||||
ulong_xt Size = zero;
|
||||
ntstatus_xt Status = NtFreeVirtualMemory(&Pcr, &Size, XBOX_MEM_RELEASE); // free pcr
|
||||
assert(Status == X_STATUS_SUCCESS);
|
||||
__writefsdword(TIB_ArbitraryDataSlot, NULL);
|
||||
}
|
||||
|
||||
void EmuKeFreeThread(xbox::ntstatus_xt ExitStatus)
|
||||
{
|
||||
// Free all kernel resources that were allocated fo this thread
|
||||
|
||||
xbox::KeEmptyQueueApc();
|
||||
|
||||
xbox::PETHREAD eThread = xbox::PspGetCurrentThread();
|
||||
|
||||
xbox::KeQuerySystemTime(&eThread->ExitTime);
|
||||
eThread->Tcb.HasTerminated = 1;
|
||||
|
||||
RemoveEntryList(&eThread->Tcb.ThreadListEntry);
|
||||
|
||||
// Emulate our exit strategy for GetExitCodeThread
|
||||
eThread->ExitStatus = ExitStatus;
|
||||
eThread->Tcb.Header.SignalState = 1;
|
||||
|
||||
if (GetNativeHandle(eThread->UniqueThread)) {
|
||||
xbox::NtClose(eThread->UniqueThread);
|
||||
eThread->UniqueThread = xbox::zeroptr;
|
||||
}
|
||||
|
||||
EmuKeFreePcr();
|
||||
}
|
||||
|
||||
__declspec(naked) void EmuFS_RefreshKPCR()
|
||||
{
|
||||
// Backup all registers, call EmuKeGetPcr and then restore all registers
|
||||
|
@ -679,81 +632,33 @@ void EmuInitFS()
|
|||
EmuLogEx(CXBXR_MODULE::INIT, LOG_LEVEL::DEBUG, "Done patching FS Register Accesses\n");
|
||||
}
|
||||
|
||||
// Get Xbox's TIB StackBase address from thread's StackBase.
|
||||
xbox::PVOID EmuGetTIBStackBase(xbox::PVOID ThreadStackBase) {
|
||||
xbox::addr_xt StackBaseAddr = reinterpret_cast<xbox::addr_xt>(ThreadStackBase);
|
||||
StackBaseAddr -= sizeof(xbox::FX_SAVE_AREA);
|
||||
return reinterpret_cast<xbox::PVOID>(StackBaseAddr);
|
||||
}
|
||||
|
||||
// generate stack size reserved for xbox threads to write on.
|
||||
xbox::dword_xt EmuGenerateStackSize(xbox::addr_xt& espBaseAddress, xbox::ulong_xt TlsDataSize) {
|
||||
using namespace xbox;
|
||||
dword_xt StackSize = espBaseAddress & 15; // Fix 16 byte alignment
|
||||
espBaseAddress -= StackSize;
|
||||
StackSize += sizeof(FX_SAVE_AREA);
|
||||
TlsDataSize = ALIGN_UP(TlsDataSize, ulong_xt);
|
||||
StackSize += TlsDataSize; // (optional)
|
||||
StackSize += sizeof(KSTART_FRAME);
|
||||
StackSize += sizeof(KSWITCHFRAME);
|
||||
return StackSize;
|
||||
}
|
||||
|
||||
// generate fs segment selector
|
||||
template<bool IsHostThread>
|
||||
void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData, xbox::PETHREAD Ethread)
|
||||
void EmuGenerateFS(xbox::PETHREAD Ethread, unsigned Host2XbStackBaseReserved, unsigned Host2XbStackSizeReserved)
|
||||
{
|
||||
void *pNewTLS = nullptr;
|
||||
xbox::PVOID base;
|
||||
xbox::ulong_xt size;
|
||||
|
||||
// Be aware that TLS might be absent (for example in homebrew "Wolf3d-xbox")
|
||||
if (pTLS != nullptr) {
|
||||
// copy global TLS to the current thread
|
||||
{
|
||||
uint32_t dwCopySize = 0;
|
||||
uint32_t dwZeroSize = pTLS->dwSizeofZeroFill;
|
||||
|
||||
if (pTLSData != NULL) {
|
||||
// Make sure the TLS Start and End addresses are within Xbox virtual memory
|
||||
if (pTLS->dwDataStartAddr >= XBE_MAX_VA || pTLS->dwDataEndAddr >= XBE_MAX_VA) {
|
||||
// ignore
|
||||
}
|
||||
else {
|
||||
dwCopySize = pTLS->dwDataEndAddr - pTLS->dwDataStartAddr;
|
||||
}
|
||||
}
|
||||
|
||||
/* + HACK: extra safety padding 0x100 */
|
||||
base = xbox::zeroptr;
|
||||
size = dwCopySize + dwZeroSize + 0x100 + 0xC;
|
||||
xbox::NtAllocateVirtualMemory(&base, 0, &size, XBOX_MEM_RESERVE | XBOX_MEM_COMMIT, XBOX_PAGE_READWRITE);
|
||||
pNewTLS = (void*)base;
|
||||
xbox::RtlZeroMemory(pNewTLS, dwCopySize + dwZeroSize + 0x100 + 0xC);
|
||||
/* Skip the first 12 bytes so that TLSData will be 16 byte aligned (addr returned by NtAllocateVirtualMemory is 4K aligned) */
|
||||
pNewTLS = (uint8_t*)pNewTLS + TLS_ALIGNMENT_OFFSET;
|
||||
|
||||
if (dwCopySize > 0) {
|
||||
memcpy((uint8_t*)pNewTLS + 4, pTLSData, dwCopySize);
|
||||
}
|
||||
|
||||
#ifdef _DEBUG_TRACE
|
||||
// dump raw TLS data
|
||||
if (pNewTLS == nullptr) {
|
||||
EmuLog(LOG_LEVEL::DEBUG, "TLS Non-Existant (OK)");
|
||||
} else {
|
||||
EmuLog(LOG_LEVEL::DEBUG, "TLS Data Dump...");
|
||||
if (g_bPrintfOn) {
|
||||
for (uint32_t v = 4; v < dwCopySize + 4; v++) {// Note : Don't dump dwZeroSize
|
||||
|
||||
uint8_t *bByte = (uint8_t*)pNewTLS + v;
|
||||
|
||||
if (v % 0x10 == 0) {
|
||||
EmuLog(LOG_LEVEL::DEBUG, "0x%.8X:", (xbox::addr_xt)bByte);
|
||||
}
|
||||
|
||||
// Note : Use printf instead of EmuLog here, which prefixes with GetCurrentThreadId() :
|
||||
printf(" %.2X", *bByte);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// prepare TLS
|
||||
{
|
||||
if (pTLS->dwTLSIndexAddr != 0) {
|
||||
*(xbox::addr_xt*)pTLS->dwTLSIndexAddr = xbox::zero;
|
||||
}
|
||||
|
||||
// dword @ pTLSData := pTLSData
|
||||
if (pNewTLS != nullptr)
|
||||
*(void**)pNewTLS = pNewTLS;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate the xbox KPCR structure
|
||||
base = xbox::zeroptr;
|
||||
size = sizeof(xbox::KPCR);
|
||||
|
@ -769,21 +674,26 @@ void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData, xbox::PETHREAD Ethread)
|
|||
//
|
||||
// Once we simulate thread switching ourselves, we can update PrcbData.CurrentThread
|
||||
// and simplify this initialization, by using only one KPCR for the single Xbox processor.
|
||||
//
|
||||
//
|
||||
// One way to do our own (preemprive) thread-switching would be to use this technique :
|
||||
// http://www.eran.io/implementing-a-preemptive-kernel-within-a-single-windows-thread/
|
||||
// See https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/issues/146 for more info.
|
||||
|
||||
// Copy the Nt TIB over to the emulated TIB :
|
||||
NT_TIB* hTib = GetNtTib();
|
||||
{
|
||||
memcpy(XbTib, GetNtTib(), sizeof(NT_TIB));
|
||||
memcpy(XbTib, hTib, sizeof(NT_TIB));
|
||||
// Fixup the TIB self pointer :
|
||||
NewPcr->NtTib.Self = XbTib;
|
||||
// Set the stack base - TODO : Verify this, doesn't look right?
|
||||
NewPcr->NtTib.StackBase = pNewTLS;
|
||||
|
||||
// NOTE: The actual issue was TlsData was not within Host's stack which is now implemented.
|
||||
// But instead of direct Host's stack, (which should not be tampered from Host's kernel stack block!)
|
||||
// we allocated through inline asm to reserve xbox stack dynamically in order to have xbox's kernel stack reside in
|
||||
// host's stack (in permitted function's stack usage).
|
||||
// Write the Xbox stack base to the Host, allows ConvertThreadToFiber to work correctly
|
||||
// Test case: DOA3
|
||||
// Test case:
|
||||
// * DoA2
|
||||
// * DoA3
|
||||
// NOTE: This is disabled due to cause of corruption to host's TIB and
|
||||
// silent crash for xbox threads creation.
|
||||
// Test case:
|
||||
|
@ -810,6 +720,8 @@ void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData, xbox::PETHREAD Ethread)
|
|||
|
||||
if constexpr (IsHostThread) {
|
||||
// This only happens for the kernel initialization thread of cxbxr
|
||||
// Another thing to note, we do not insert into xbox's system as it will not be used in running xbox environment.
|
||||
// Instead it will be sleeping until title/user make a decision what to do next.
|
||||
assert(Ethread == xbox::zeroptr);
|
||||
|
||||
base = xbox::zeroptr;
|
||||
|
@ -817,39 +729,61 @@ void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData, xbox::PETHREAD Ethread)
|
|||
xbox::NtAllocateVirtualMemory(&base, 0, &size, XBOX_MEM_RESERVE | XBOX_MEM_COMMIT, XBOX_PAGE_READWRITE);
|
||||
Ethread = (xbox::PETHREAD)base;
|
||||
xbox::RtlZeroMemory(Ethread, sizeof(xbox::ETHREAD)); // Clear, to prevent side-effects on random contents
|
||||
// Emulate kernel stack size as we can't use exact size.
|
||||
xbox::ulong_xt KernelStackSize = Host2XbStackBaseReserved - reinterpret_cast<xbox::ulong_xt>(hTib->StackLimit);
|
||||
// Since the cxbxr's kernel initialization occur there, we do not create a new thread
|
||||
// and therefore doesn't need to set any additional System/Start details set in the xbox's kernel stack.
|
||||
xbox::KeInitializeThread<IsHostThread>(
|
||||
&Ethread->Tcb,
|
||||
(xbox::PVOID)Host2XbStackBaseReserved,
|
||||
KernelStackSize,
|
||||
xbox::zero,
|
||||
xbox::zeroptr, // Unused (SystemRoutine)
|
||||
xbox::zeroptr, // Unused (StartRoutine)
|
||||
xbox::zeroptr, // Unused (StartContext)
|
||||
xbox::zeroptr); // Unused (&KiUniqueProcess)
|
||||
}
|
||||
#ifndef ENABLE_KTHREAD_SWITCHING
|
||||
else {
|
||||
// Otherwise, xbox::PsCreateSystemThreadEx is called and xbox::KeInitializeThread is already called from it.
|
||||
// But we need to carry the reserved part onto host's stack to able align with xbox and host sharing the same stack in a new thread.
|
||||
// Since we are using direct execution than in virtualization environment.
|
||||
// Tcb.StackBase always point at the beginning of kernel stack (DOWN).
|
||||
xbox::addr_xt xStackBase = reinterpret_cast<xbox::addr_xt>(Ethread->Tcb.StackBase);
|
||||
xbox::addr_xt xStackLimit = reinterpret_cast<xbox::addr_xt>(Ethread->Tcb.StackLimit);
|
||||
xbox::addr_xt xTlsData = reinterpret_cast<xbox::addr_xt>(Ethread->Tcb.TlsData);
|
||||
xbox::addr_xt xKernelStack = reinterpret_cast<xbox::addr_xt>(Ethread->Tcb.KernelStack);
|
||||
xbox::dword_xt xKernelStackSize = xStackBase - xKernelStack;
|
||||
assert(xKernelStackSize <= Host2XbStackSizeReserved);
|
||||
PVOID hKernelStack = reinterpret_cast<PVOID>(Host2XbStackBaseReserved - xKernelStackSize);
|
||||
std::memcpy(hKernelStack, Ethread->Tcb.KernelStack, xKernelStackSize);
|
||||
// Update TlsData address if used
|
||||
if (Ethread->Tcb.TlsData) {
|
||||
Ethread->Tcb.TlsData = reinterpret_cast<xbox::PVOID>(Host2XbStackBaseReserved - (xStackBase - xTlsData));
|
||||
}
|
||||
// Set stacks addresses
|
||||
Ethread->Tcb.StackBase = reinterpret_cast<xbox::PVOID>(Host2XbStackBaseReserved);
|
||||
Ethread->Tcb.StackLimit = hTib->StackLimit; // Always point to host's StackLimit.
|
||||
Ethread->Tcb.KernelStack = hKernelStack;
|
||||
// We can safely delete kernel stack as there is no virtualization environment implemented.
|
||||
xbox::MmDeleteKernelStack(reinterpret_cast<xbox::PVOID>(xStackBase), reinterpret_cast<xbox::PVOID>(xStackLimit));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Initialize a fake PrcbData.CurrentThread
|
||||
{
|
||||
// TODO: Do we need NtTib's overwrite in ENABLE_KTHREAD_SWITCHING usage?
|
||||
// Set the stack details over to NtTib's structure.
|
||||
NewPcr->NtTib.StackBase = EmuGetTIBStackBase(Ethread->Tcb.StackBase);
|
||||
NewPcr->NtTib.StackLimit = Ethread->Tcb.StackLimit;
|
||||
// Set PrcbData.CurrentThread
|
||||
Prcb->CurrentThread = (xbox::PKTHREAD)Ethread;
|
||||
Prcb->CurrentThread->TlsData = pNewTLS;
|
||||
// Initialize APC stuff
|
||||
InitializeListHead(&Prcb->CurrentThread->ApcState.ApcListHead[xbox::KernelMode]);
|
||||
InitializeListHead(&Prcb->CurrentThread->ApcState.ApcListHead[xbox::UserMode]);
|
||||
Prcb->CurrentThread->KernelApcDisable = 0;
|
||||
Prcb->CurrentThread->ApcState.ApcQueueable = TRUE;
|
||||
Prcb->CurrentThread->ApcState.Process = &KiUniqueProcess;
|
||||
Prcb->CurrentThread->ApcState.Process->ThreadQuantum = KiUniqueProcess.ThreadQuantum;
|
||||
// Initialize the thread header and its wait list
|
||||
Prcb->CurrentThread->Header.Type = xbox::ThreadObject;
|
||||
Prcb->CurrentThread->Header.Size = sizeof(xbox::KTHREAD) / sizeof(xbox::long_xt);
|
||||
InitializeListHead(&Prcb->CurrentThread->Header.WaitListHead);
|
||||
// Also initialize the timer associated with the thread
|
||||
xbox::KeInitializeTimer(&Prcb->CurrentThread->Timer);
|
||||
xbox::PKWAIT_BLOCK WaitBlock = &Prcb->CurrentThread->TimerWaitBlock;
|
||||
WaitBlock->Object = &Prcb->CurrentThread->Timer;
|
||||
WaitBlock->WaitKey = (xbox::cshort_xt)STATUS_TIMEOUT;
|
||||
WaitBlock->WaitType = xbox::WaitAny;
|
||||
WaitBlock->Thread = Prcb->CurrentThread;
|
||||
WaitBlock->WaitListEntry.Flink = &Prcb->CurrentThread->Timer.Header.WaitListHead;
|
||||
WaitBlock->WaitListEntry.Blink = &Prcb->CurrentThread->Timer.Header.WaitListHead;
|
||||
}
|
||||
|
||||
// Make the KPCR struct available to EmuKeGetPcr()
|
||||
EmuKeSetPcr(NewPcr);
|
||||
|
||||
EmuLog(LOG_LEVEL::DEBUG, "Installed KPCR in TIB_ArbitraryDataSlot (with pTLS = 0x%.8X)", pTLS);
|
||||
EmuLog(LOG_LEVEL::DEBUG, "Installed KPCR in TIB_ArbitraryDataSlot (with Ethread->Tcb.TlsData = 0x%.8X)", Ethread->Tcb.TlsData);
|
||||
|
||||
_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)
|
||||
|
|
|
@ -29,16 +29,20 @@
|
|||
#include "common\xbe\Xbe.h"
|
||||
#include <windows.h>
|
||||
|
||||
// Get Xbox's TIB StackBase address from thread's StackBase.
|
||||
xbox::PVOID EmuGetTIBStackBase(xbox::PVOID ThreadStackBase);
|
||||
|
||||
// generate stack size reserved for xbox threads to write on.
|
||||
// espBaseAddress will return aligned DOWN address, do not rely on return's size for offset usage.
|
||||
xbox::dword_xt EmuGenerateStackSize(xbox::addr_xt& espBaseAddress, IN xbox::ulong_xt TlsDataSize);
|
||||
|
||||
// initialize fs segment selector emulation
|
||||
extern void EmuInitFS();
|
||||
|
||||
// generate fs segment selector
|
||||
template<bool IsHostThread = false>
|
||||
void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData, xbox::PETHREAD Ethread);
|
||||
// free resources allocated for the thread
|
||||
void EmuKeFreeThread(xbox::ntstatus_xt ExitStatus = X_STATUS_ABANDONED);
|
||||
void EmuGenerateFS(xbox::PETHREAD Ethread, unsigned XboxThreadStackBaseReserved = 0, unsigned XboxThreadStackSizeReserved = 0);
|
||||
// free kpcr allocated for the thread
|
||||
template<bool IsHostThread = false>
|
||||
void EmuKeFreePcr();
|
||||
|
||||
void EmuKeSetPcr(xbox::KPCR *Pcr);
|
||||
|
@ -50,9 +54,4 @@ typedef struct
|
|||
void* functionPtr;
|
||||
}fs_instruction_t;
|
||||
|
||||
extern template void EmuGenerateFS<true>(Xbe::TLS *pTLS, void *pTLSData, xbox::PETHREAD Ethread);
|
||||
extern template void EmuGenerateFS<false>(Xbe::TLS *pTLS, void *pTLSData, xbox::PETHREAD Ethread);
|
||||
extern template void EmuKeFreePcr<true>();
|
||||
extern template void EmuKeFreePcr<false>();
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue