Review remarks + use PsCreateSystemThread to start all xbox threads
This commit is contained in:
parent
6320dd5539
commit
06f34134ff
|
@ -25,6 +25,8 @@
|
|||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#include <core\kernel\exports\xboxkrnl.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
@ -142,34 +144,28 @@ void Timer_Shutdown()
|
|||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
TimerMtx.lock();
|
||||
counter++;
|
||||
|
||||
}
|
||||
TimerList.clear();
|
||||
TimerMtx.unlock();
|
||||
}
|
||||
|
||||
// Thread that runs the timer
|
||||
void ClockThread(TimerObject* Timer)
|
||||
void NTAPI ClockThread(void *TimerArg)
|
||||
{
|
||||
uint64_t NewExpireTime;
|
||||
|
||||
TimerObject *Timer = static_cast<TimerObject *>(TimerArg);
|
||||
if (!Timer->Name.empty()) {
|
||||
CxbxSetThreadName(Timer->Name.c_str());
|
||||
}
|
||||
if (Timer->IsXboxTimer) {
|
||||
InitXboxThread();
|
||||
g_AffinityPolicy->SetAffinityXbox();
|
||||
} else {
|
||||
if (!Timer->IsXboxTimer) {
|
||||
g_AffinityPolicy->SetAffinityOther();
|
||||
}
|
||||
|
||||
NewExpireTime = GetNextExpireTime(Timer);
|
||||
uint64_t NewExpireTime = GetNextExpireTime(Timer);
|
||||
|
||||
while (true) {
|
||||
if (GetTime_NS(Timer) > NewExpireTime) {
|
||||
if (Timer->Exit.load()) {
|
||||
Timer_Destroy(Timer);
|
||||
EmuKeFreeThread();
|
||||
return;
|
||||
}
|
||||
Timer->Callback(Timer->Opaque);
|
||||
|
@ -213,7 +209,13 @@ TimerObject* Timer_Create(TimerCB Callback, void* Arg, std::string Name, bool Is
|
|||
void Timer_Start(TimerObject* Timer, uint64_t Expire_MS)
|
||||
{
|
||||
Timer->ExpireTime_MS.store(Expire_MS);
|
||||
std::thread(ClockThread, Timer).detach();
|
||||
if (Timer->IsXboxTimer) {
|
||||
xbox::HANDLE hThread;
|
||||
xbox::PsCreateSystemThread(&hThread, xbox::zeroptr, ClockThread, Timer, FALSE);
|
||||
}
|
||||
else {
|
||||
std::thread(ClockThread, Timer).detach();
|
||||
}
|
||||
}
|
||||
|
||||
// Retrives the frequency of the high resolution clock of the host
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "core\kernel\init\CxbxKrnl.h"
|
||||
#include "core\kernel\support\Emu.h"
|
||||
#include "core\kernel\support\EmuFS.h"
|
||||
#include "core\kernel\support\NativeHandle.h"
|
||||
#include "EmuShared.h"
|
||||
#include "..\FixedFunctionState.h"
|
||||
#include "core\hle\D3D8\ResourceTracker.h"
|
||||
|
@ -221,7 +222,7 @@ static xbox::dword_xt *g_Xbox_D3DDevice; // TODO: This should b
|
|||
// Static Function(s)
|
||||
static DWORD WINAPI EmuRenderWindow(LPVOID);
|
||||
static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
static DWORD WINAPI EmuUpdateTickCount(LPVOID);
|
||||
static xbox::void_xt NTAPI EmuUpdateTickCount(xbox::PVOID Arg);
|
||||
static inline void EmuVerifyResourceIsRegistered(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTextureStage, DWORD dwSize);
|
||||
static void UpdateCurrentMSpFAndFPS(); // Used for benchmarking/fps count
|
||||
static void CxbxImpl_SetRenderTarget(xbox::X_D3DSurface *pRenderTarget, xbox::X_D3DSurface *pNewZStencil);
|
||||
|
@ -627,12 +628,15 @@ void CxbxInitWindow(bool bFullInit)
|
|||
CxbxKrnl_hEmuParent = NULL;
|
||||
|
||||
// create timing thread
|
||||
if (bFullInit)
|
||||
if (bFullInit && !bLLE_GPU)
|
||||
{
|
||||
HANDLE hThread = CreateThread(nullptr, 0, EmuUpdateTickCount, nullptr, 0, nullptr);
|
||||
xbox::HANDLE hThread;
|
||||
xbox::PsCreateSystemThread(&hThread, xbox::zeroptr, EmuUpdateTickCount, xbox::zeroptr, FALSE);
|
||||
// We set the priority of this thread a bit higher, to assure reliable timing :
|
||||
SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL);
|
||||
g_AffinityPolicy->SetAffinityOther(hThread);
|
||||
auto nativeHandle = GetNativeHandle(hThread);
|
||||
assert(nativeHandle);
|
||||
SetThreadPriority(*nativeHandle, THREAD_PRIORITY_ABOVE_NORMAL);
|
||||
g_AffinityPolicy->SetAffinityOther(*nativeHandle);
|
||||
}
|
||||
|
||||
/* TODO : Port this Dxbx code :
|
||||
|
@ -2141,21 +2145,12 @@ std::chrono::steady_clock::time_point GetNextVBlankTime()
|
|||
}
|
||||
|
||||
// timing thread procedure
|
||||
static DWORD WINAPI EmuUpdateTickCount(LPVOID)
|
||||
static xbox::void_xt NTAPI EmuUpdateTickCount(xbox::PVOID Arg)
|
||||
{
|
||||
CxbxSetThreadName("Cxbx Timing Thread");
|
||||
|
||||
// since callbacks come from here
|
||||
InitXboxThread();
|
||||
|
||||
EmuLog(LOG_LEVEL::DEBUG, "Timing thread is running.");
|
||||
|
||||
// We check for LLE flag as NV2A handles it's own VBLANK if LLE is enabled!
|
||||
if (bLLE_GPU) {
|
||||
EmuKeFreeThread();
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto nextVBlankTime = GetNextVBlankTime();
|
||||
|
||||
while(true)
|
||||
|
|
|
@ -999,15 +999,14 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(SignalObjectAndWait)
|
|||
|
||||
// Because user APCs from NtQueueApcThread are now handled by the kernel, we need to wait for them ourselves
|
||||
bool Exit = false;
|
||||
auto fut = WaitApc(bAlertable, UserMode, &Exit);
|
||||
auto async_bool = WaitApc(bAlertable, UserMode, &Exit);
|
||||
|
||||
dword_xt dwRet = SignalObjectAndWait(hObjectToSignal, hObjectToWaitOn, dwMilliseconds, bAlertable);
|
||||
|
||||
Exit = true;
|
||||
bool result = fut.get();
|
||||
return result ? X_STATUS_USER_APC : dwRet;
|
||||
bool result = async_bool.get();
|
||||
|
||||
RETURN(dwRet);
|
||||
RETURN(result ? X_STATUS_USER_APC : dwRet);
|
||||
}
|
||||
|
||||
// ******************************************************************
|
||||
|
|
|
@ -154,7 +154,7 @@ void CallSoftwareInterrupt(const xbox::KIRQL SoftwareIrql)
|
|||
case PASSIVE_LEVEL:
|
||||
KiUnexpectedInterrupt();
|
||||
break;
|
||||
case APC_LEVEL: // = 1
|
||||
case APC_LEVEL: // = 1 HalpApcInterrupt
|
||||
xbox::KiExecuteKernelApc();
|
||||
break;
|
||||
case DISPATCH_LEVEL: // = 2
|
||||
|
@ -221,10 +221,9 @@ std::future<bool> WaitApc(xbox::boolean_xt Alertable, xbox::char_xt WaitMode, bo
|
|||
// NOTE: kThread->Alerted is currently never set. When the alerted mechanism is implemented, the alerts should
|
||||
// also interrupt the wait
|
||||
xbox::PKPCR Kpcr = EmuKeGetPcr();
|
||||
DWORD Id = GetCurrentThreadId();
|
||||
|
||||
// This new thread must execute APCs in the context of the calling thread
|
||||
return std::async(std::launch::async, [Kpcr, Alertable, WaitMode, Id, Exit]() {
|
||||
return std::async(std::launch::async, [Kpcr, Alertable, WaitMode, Exit]() {
|
||||
EmuKeSetPcr(Kpcr);
|
||||
xbox::PETHREAD eThread = reinterpret_cast<xbox::PETHREAD>(Kpcr->Prcb->CurrentThread);
|
||||
|
||||
|
@ -242,15 +241,12 @@ std::future<bool> WaitApc(xbox::boolean_xt Alertable, xbox::char_xt WaitMode, bo
|
|||
xbox::KiExecuteUserApc();
|
||||
// Queue a native APC to the calling thread to forcefully terminate the wait of the WinApi functions,
|
||||
// in the case it didn't terminate already
|
||||
HANDLE nativeHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, Id);
|
||||
assert(nativeHandle);
|
||||
[[maybe_unused]] BOOL ret = QueueUserAPC(EndWait, nativeHandle, 0);
|
||||
[[maybe_unused]] BOOL ret = QueueUserAPC(EndWait, *GetNativeHandle(eThread->UniqueThread), 0);
|
||||
assert(ret);
|
||||
CloseHandle(nativeHandle);
|
||||
EmuKeSetPcr(nullptr);
|
||||
return true;
|
||||
}
|
||||
Sleep(0);
|
||||
SwitchToThread();
|
||||
if (*Exit) {
|
||||
EmuKeSetPcr(nullptr);
|
||||
return false;
|
||||
|
@ -502,7 +498,7 @@ XBSYSAPI EXPORTNUM(163) xbox::void_xt FASTCALL xbox::KiUnlockDispatcherDatabase
|
|||
}
|
||||
|
||||
if (OldIrql < DISPATCH_LEVEL) {
|
||||
// This is wrong: this should perform a thread switch and check the kthread of the new selected thread for pending APCs.
|
||||
// FIXME: this is wrong, it should perform a thread switch and check the kthread of the new selected thread for pending APCs.
|
||||
// We can't perform our own threads switching now, so we will just check the current thread
|
||||
|
||||
if (KeGetCurrentThread()->ApcState.KernelApcPending) {
|
||||
|
|
|
@ -567,13 +567,13 @@ XBSYSAPI EXPORTNUM(99) xbox::ntstatus_xt NTAPI xbox::KeDelayExecutionThread
|
|||
// We can't remove NtDll::NtDelayExecution until all APCs queued by Io are implemented by our kernel as well
|
||||
// Test case: Metal Slug 3
|
||||
bool Exit = false;
|
||||
auto fut = WaitApc(Alertable, WaitMode, &Exit);
|
||||
auto async_bool = WaitApc(Alertable, WaitMode, &Exit);
|
||||
|
||||
NTSTATUS ret = NtDll::NtDelayExecution(Alertable, (NtDll::LARGE_INTEGER *)Interval);
|
||||
|
||||
Exit = true;
|
||||
bool result = fut.get();
|
||||
return result ? X_STATUS_USER_APC : ret;
|
||||
bool result = async_bool.get();
|
||||
RETURN(result ? X_STATUS_USER_APC : ret);
|
||||
}
|
||||
|
||||
// ******************************************************************
|
||||
|
|
|
@ -882,25 +882,22 @@ xbox::void_xt FASTCALL xbox::KiWaitSatisfyAll
|
|||
return;
|
||||
}
|
||||
|
||||
template<bool KernelApc>
|
||||
template<xbox::MODE ApcMode>
|
||||
static xbox::void_xt KiExecuteApc()
|
||||
{
|
||||
xbox::PKTHREAD kThread = xbox::KeGetCurrentThread();
|
||||
|
||||
int ApcMode;
|
||||
if constexpr (KernelApc) {
|
||||
if constexpr (ApcMode == xbox::KernelMode) {
|
||||
kThread->ApcState.KernelApcPending = FALSE;
|
||||
ApcMode = xbox::KernelMode;
|
||||
}
|
||||
else {
|
||||
kThread->ApcState.UserApcPending = FALSE;
|
||||
ApcMode = xbox::UserMode;
|
||||
}
|
||||
|
||||
// Even though the apc list is per-thread, it's still possible that another thread will access it while we are processing it below
|
||||
xbox::KiApcListMtx.lock();
|
||||
while (!IsListEmpty(&kThread->ApcState.ApcListHead[ApcMode])) {
|
||||
if (KernelApc && (kThread->KernelApcDisable != 0)) {
|
||||
if ((ApcMode == xbox::KernelMode) && (kThread->KernelApcDisable != 0)) {
|
||||
xbox::KiApcListMtx.unlock();
|
||||
return;
|
||||
}
|
||||
|
@ -910,7 +907,7 @@ static xbox::void_xt KiExecuteApc()
|
|||
Apc->Inserted = FALSE;
|
||||
xbox::KiApcListMtx.unlock();
|
||||
|
||||
// NOTE: we never use KernelRoutine
|
||||
// NOTE: we never use KernelRoutine because that is only used for kernel APCs, which we currently don't use
|
||||
if (Apc->NormalRoutine != xbox::zeroptr) {
|
||||
(Apc->NormalRoutine)(Apc->NormalContext, Apc->SystemArgument1, Apc->SystemArgument2);
|
||||
}
|
||||
|
@ -924,10 +921,10 @@ static xbox::void_xt KiExecuteApc()
|
|||
|
||||
xbox::void_xt xbox::KiExecuteKernelApc()
|
||||
{
|
||||
KiExecuteApc<true>();
|
||||
KiExecuteApc<KernelMode>();
|
||||
}
|
||||
|
||||
xbox::void_xt xbox::KiExecuteUserApc()
|
||||
{
|
||||
KiExecuteApc<false>();
|
||||
KiExecuteApc<UserMode>();
|
||||
}
|
||||
|
|
|
@ -1029,6 +1029,8 @@ XBSYSAPI EXPORTNUM(206) xbox::ntstatus_xt NTAPI xbox::NtQueueApcThread
|
|||
LOG_FUNC_ARG(ApcReserved)
|
||||
LOG_FUNC_END;
|
||||
|
||||
// Test case: Metal Slug 3, possibly other SNK games too
|
||||
|
||||
PETHREAD Thread;
|
||||
ntstatus_xt result = ObReferenceObjectByHandle(ThreadHandle, &PsThreadObjectType, reinterpret_cast<PVOID *>(&Thread));
|
||||
if (!X_NT_SUCCESS(result)) {
|
||||
|
@ -2199,7 +2201,7 @@ XBSYSAPI EXPORTNUM(235) xbox::ntstatus_xt NTAPI xbox::NtWaitForMultipleObjectsEx
|
|||
|
||||
// Because user APCs from NtQueueApcThread are now handled by the kernel, we need to wait for them ourselves
|
||||
bool Exit = false;
|
||||
auto fut = WaitApc(Alertable, WaitMode, &Exit);
|
||||
auto async_bool = WaitApc(Alertable, WaitMode, &Exit);
|
||||
|
||||
NTSTATUS ret = NtDll::NtWaitForMultipleObjects(
|
||||
Count,
|
||||
|
@ -2209,8 +2211,8 @@ XBSYSAPI EXPORTNUM(235) xbox::ntstatus_xt NTAPI xbox::NtWaitForMultipleObjectsEx
|
|||
(NtDll::PLARGE_INTEGER)Timeout);
|
||||
|
||||
Exit = true;
|
||||
bool result = fut.get();
|
||||
return result ? X_STATUS_USER_APC : ret;
|
||||
bool result = async_bool.get();
|
||||
RETURN(result ? X_STATUS_USER_APC : ret);
|
||||
}
|
||||
|
||||
// ******************************************************************
|
||||
|
|
|
@ -64,6 +64,7 @@ PCSTProxyParam;
|
|||
|
||||
xbox::PCREATE_THREAD_NOTIFY_ROUTINE g_pfnThreadNotification[PSP_MAX_CREATE_THREAD_NOTIFY] = { xbox::zeroptr };
|
||||
int g_iThreadNotificationCount = 0;
|
||||
static std::mutex PspThreadNotificationMtx;
|
||||
|
||||
// Separate function for logging, otherwise in PCSTProxy __try wont work (Compiler Error C2712)
|
||||
void LOG_PCSTProxy
|
||||
|
@ -82,16 +83,6 @@ void LOG_PCSTProxy
|
|||
LOG_FUNC_END;
|
||||
}
|
||||
|
||||
// Overload which doesn't change affinity
|
||||
void InitXboxThread(xbox::PVOID Ethread)
|
||||
{
|
||||
// initialize FS segment selector
|
||||
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)
|
||||
}
|
||||
|
||||
// PsCreateSystemThread proxy procedure
|
||||
// Dxbx Note : The signature of PCSTProxy should conform to System.TThreadFunc !
|
||||
static unsigned int WINAPI PCSTProxy
|
||||
|
@ -113,9 +104,8 @@ static unsigned int WINAPI PCSTProxy
|
|||
params.SystemRoutine,
|
||||
params.Ethread);
|
||||
|
||||
|
||||
// Do minimal thread initialization
|
||||
InitXboxThread(params.Ethread);
|
||||
EmuGenerateFS(CxbxKrnl_TLS, CxbxKrnl_TLSData, static_cast<xbox::PETHREAD>(params.Ethread));
|
||||
|
||||
auto routine = (xbox::PKSYSTEM_ROUTINE)params.SystemRoutine;
|
||||
// Debugging notice : When the below line shows up with an Exception dialog and a
|
||||
|
@ -150,6 +140,17 @@ xbox::PETHREAD xbox::PspGetCurrentThread()
|
|||
return reinterpret_cast<PETHREAD>(KeGetCurrentThread());
|
||||
}
|
||||
|
||||
static xbox::void_xt PspCallThreadNotificationRoutines(xbox::PETHREAD eThread, xbox::boolean_xt Create)
|
||||
{
|
||||
std::unique_lock lck(PspThreadNotificationMtx);
|
||||
for (int i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++) {
|
||||
if (g_pfnThreadNotification[i]) {
|
||||
EmuLog(LOG_LEVEL::DEBUG, "Calling pfnNotificationRoutine[%d] (0x%.8X)", i, g_pfnThreadNotification[i]);
|
||||
(*g_pfnThreadNotification[i])(eThread, eThread->UniqueThread, Create);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ******************************************************************
|
||||
// * 0x00FE - PsCreateSystemThread()
|
||||
// ******************************************************************
|
||||
|
@ -250,14 +251,9 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx
|
|||
RETURN(result);
|
||||
}
|
||||
|
||||
// Call thread notification routine(s)
|
||||
// Call the thread notification routine(s)
|
||||
if (g_iThreadNotificationCount) {
|
||||
for (int i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++) {
|
||||
if (g_pfnThreadNotification[i]) {
|
||||
EmuLog(LOG_LEVEL::DEBUG, "Calling pfnNotificationRoutine[%d] (0x%.8X)", i, g_pfnThreadNotification[i]);
|
||||
(*g_pfnThreadNotification[i])(eThread, eThread->UniqueThread, TRUE);
|
||||
}
|
||||
}
|
||||
PspCallThreadNotificationRoutines(eThread, TRUE);
|
||||
}
|
||||
|
||||
// Create another handle to pass back to the title in the ThreadHandle argument
|
||||
|
@ -298,6 +294,7 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx
|
|||
KiUniqueProcess.StackCount++;
|
||||
RegisterXboxHandle(*ThreadHandle, handle);
|
||||
HANDLE dupHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, ThreadId);
|
||||
assert(dupHandle);
|
||||
RegisterXboxHandle(eThread->UniqueThread, dupHandle);
|
||||
|
||||
g_AffinityPolicy->SetAffinityXbox(handle);
|
||||
|
@ -371,15 +368,10 @@ XBSYSAPI EXPORTNUM(258) xbox::void_xt NTAPI xbox::PsTerminateSystemThread
|
|||
{
|
||||
LOG_FUNC_ONE_ARG(ExitStatus);
|
||||
|
||||
// Call thread notification routine(s)
|
||||
// Call the thread notification routine(s)
|
||||
xbox::PETHREAD eThread = xbox::PspGetCurrentThread();
|
||||
if (eThread->UniqueThread && g_iThreadNotificationCount) {
|
||||
for (int i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++) {
|
||||
if (g_pfnThreadNotification[i]) {
|
||||
EmuLog(LOG_LEVEL::DEBUG, "Calling pfnNotificationRoutine[%d] (0x%.8X)", i, g_pfnThreadNotification[i]);
|
||||
(*g_pfnThreadNotification[i])(eThread, eThread->UniqueThread, FALSE);
|
||||
}
|
||||
}
|
||||
PspCallThreadNotificationRoutines(eThread, FALSE);
|
||||
}
|
||||
|
||||
EmuKeFreeThread(ExitStatus);
|
||||
|
|
|
@ -141,9 +141,10 @@ void SetupPerTitleKeys()
|
|||
|
||||
}
|
||||
|
||||
void CxbxLaunchXbe(void(*Entry)())
|
||||
xbox::void_xt NTAPI CxbxLaunchXbe(xbox::PVOID Entry)
|
||||
{
|
||||
Entry();
|
||||
EmuLogInit(LOG_LEVEL::DEBUG, "Calling XBE entry point...");
|
||||
static_cast<void(*)()>(Entry)();
|
||||
}
|
||||
|
||||
// Entry point address XOR keys per Xbe type (Retail, Debug or Chihiro) :
|
||||
|
@ -345,14 +346,10 @@ void TriggerPendingConnectedInterrupts()
|
|||
}
|
||||
}
|
||||
|
||||
static unsigned int WINAPI CxbxKrnlInterruptThread(PVOID param)
|
||||
static xbox::void_xt NTAPI CxbxKrnlInterruptThread(xbox::PVOID param)
|
||||
{
|
||||
CxbxSetThreadName("CxbxKrnl Interrupts");
|
||||
|
||||
// Make sure Xbox1 code runs on one core :
|
||||
InitXboxThread();
|
||||
g_AffinityPolicy->SetAffinityXbox();
|
||||
|
||||
#if 0
|
||||
InitSoftwareInterrupts();
|
||||
#endif
|
||||
|
@ -364,9 +361,7 @@ static unsigned int WINAPI CxbxKrnlInterruptThread(PVOID param)
|
|||
Sleep(1);
|
||||
}
|
||||
|
||||
EmuKeFreeThread();
|
||||
|
||||
return 0;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
static void CxbxKrnlClockThread(void* pVoid)
|
||||
|
@ -1412,6 +1407,14 @@ static void CxbxrKrnlInitHacks()
|
|||
EmuLogInit(LOG_LEVEL::DEBUG, "Determining CPU affinity.");
|
||||
g_AffinityPolicy = AffinityPolicy::InitPolicy();
|
||||
|
||||
// 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);
|
||||
if (!xbox::ObInitSystem()) {
|
||||
CxbxrKrnlAbortEx(LOG_PREFIX_INIT, "Unable to intialize ObInitSystem.");
|
||||
}
|
||||
xbox::KiInitSystem();
|
||||
|
||||
// initialize graphics
|
||||
EmuLogInit(LOG_LEVEL::DEBUG, "Initializing render window.");
|
||||
CxbxInitWindow(true);
|
||||
|
@ -1492,13 +1495,6 @@ static void CxbxrKrnlInitHacks()
|
|||
|
||||
EmuInitFS();
|
||||
|
||||
InitXboxThread();
|
||||
g_AffinityPolicy->SetAffinityXbox();
|
||||
if (!xbox::ObInitSystem()) {
|
||||
CxbxrKrnlAbortEx(LOG_PREFIX_INIT, "Unable to intialize ObInitSystem.");
|
||||
}
|
||||
xbox::KiInitSystem();
|
||||
|
||||
#ifdef CHIHIRO_WORK
|
||||
// If this title is Chihiro, Setup JVS
|
||||
if (g_bIsChihiro) {
|
||||
|
@ -1508,16 +1504,15 @@ static void CxbxrKrnlInitHacks()
|
|||
|
||||
EmuX86_Init();
|
||||
// Create the interrupt processing thread
|
||||
DWORD dwThreadId;
|
||||
HANDLE hThread = (HANDLE)_beginthreadex(NULL, NULL, CxbxKrnlInterruptThread, NULL, NULL, (unsigned int*)&dwThreadId);
|
||||
xbox::HANDLE hThread;
|
||||
xbox::PsCreateSystemThread(&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);
|
||||
|
||||
EmuLogInit(LOG_LEVEL::DEBUG, "Calling XBE entry point...");
|
||||
CxbxLaunchXbe(Entry);
|
||||
xbox::PsCreateSystemThread(&hThread, xbox::zeroptr, CxbxLaunchXbe, Entry, FALSE);
|
||||
|
||||
EmuKeFreeThread();
|
||||
EmuKeFreePcr<true>();
|
||||
|
||||
// FIXME: Wait for Cxbx to exit or error fatally
|
||||
Sleep(INFINITE);
|
||||
|
@ -1578,11 +1573,12 @@ static void CxbxrKrnlInitHacks()
|
|||
void CxbxrKrnlSuspendThreads()
|
||||
{
|
||||
xbox::PLIST_ENTRY ThreadListEntry = KiUniqueProcess.ThreadListHead.Flink;
|
||||
std::vector<NtDll::HANDLE> threads;
|
||||
std::vector<HANDLE> threads;
|
||||
threads.reserve(KiUniqueProcess.StackCount);
|
||||
|
||||
xbox::KPCR* Pcr = EmuKeGetPcr();
|
||||
|
||||
// Don't use EmuKeGetPcr because that asserts kpcr
|
||||
xbox::KPCR* Pcr = reinterpret_cast<xbox::PKPCR>(__readfsdword(TIB_ArbitraryDataSlot));
|
||||
|
||||
// If there's nothing in list entry, skip this step.
|
||||
if (!ThreadListEntry) {
|
||||
return;
|
||||
|
|
|
@ -184,8 +184,6 @@ extern ULONG g_CxbxFatalErrorCode;
|
|||
|
||||
extern size_t g_SystemMaxMemory;
|
||||
|
||||
void InitXboxThread(xbox::PVOID Ethread = xbox::zeroptr);
|
||||
|
||||
/*! thread local storage structure */
|
||||
extern Xbe::TLS *CxbxKrnl_TLS;
|
||||
|
||||
|
|
|
@ -45,6 +45,8 @@
|
|||
#undef RtlZeroMemory
|
||||
#endif
|
||||
|
||||
#define TLS_ALIGNMENT_OFFSET 12
|
||||
|
||||
// NT_TIB (Thread Information Block) offsets - see https://www.microsoft.com/msj/archive/S2CE.aspx
|
||||
#define TIB_ExceptionList offsetof(NT_TIB, ExceptionList) // = 0x00/0
|
||||
#define TIB_StackBase offsetof(NT_TIB, StackBase) // = 0x04/4
|
||||
|
@ -113,6 +115,11 @@
|
|||
// = 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>();
|
||||
|
||||
NT_TIB *GetNtTib()
|
||||
{
|
||||
return (NT_TIB *)__readfsdword(TIB_LinearSelfAddress);
|
||||
|
@ -187,10 +194,10 @@ void EmuKeSetPcr(xbox::KPCR *Pcr)
|
|||
__writefsdword(TIB_ArbitraryDataSlot, (DWORD)Pcr);
|
||||
}
|
||||
|
||||
void EmuKeFreePcr(xbox::HANDLE UniqueThread)
|
||||
template<bool IsHostThread>
|
||||
void EmuKeFreePcr()
|
||||
{
|
||||
xbox::PKPCR Pcr = EmuKeGetPcr();
|
||||
|
||||
xbox::PVOID Dummy;
|
||||
xbox::ulong_xt Size;
|
||||
xbox::ntstatus_xt Status;
|
||||
|
@ -198,12 +205,13 @@ void EmuKeFreePcr(xbox::HANDLE UniqueThread)
|
|||
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;
|
||||
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 (UniqueThread == reinterpret_cast<xbox::HANDLE>(GetCurrentThreadId())) {
|
||||
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
|
||||
|
@ -218,8 +226,7 @@ void EmuKeFreePcr(xbox::HANDLE UniqueThread)
|
|||
|
||||
void EmuKeFreeThread(xbox::ntstatus_xt ExitStatus)
|
||||
{
|
||||
// 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
|
||||
// Free all kernel resources that were allocated fo this thread
|
||||
|
||||
xbox::KeEmptyQueueApc();
|
||||
|
||||
|
@ -234,13 +241,12 @@ void EmuKeFreeThread(xbox::ntstatus_xt ExitStatus)
|
|||
eThread->ExitStatus = ExitStatus;
|
||||
eThread->Tcb.Header.SignalState = 1;
|
||||
|
||||
xbox::HANDLE UniqueThread = eThread->UniqueThread;
|
||||
if (GetNativeHandle(eThread->UniqueThread)) {
|
||||
xbox::NtClose(eThread->UniqueThread);
|
||||
eThread->UniqueThread = NULL;
|
||||
eThread->UniqueThread = xbox::zero;
|
||||
}
|
||||
|
||||
EmuKeFreePcr(UniqueThread);
|
||||
EmuKeFreePcr();
|
||||
}
|
||||
|
||||
__declspec(naked) void EmuFS_RefreshKPCR()
|
||||
|
@ -674,7 +680,8 @@ void EmuInitFS()
|
|||
}
|
||||
|
||||
// generate fs segment selector
|
||||
void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData, xbox::PVOID Ethread)
|
||||
template<bool IsHostThread>
|
||||
void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData, xbox::PETHREAD Ethread)
|
||||
{
|
||||
void *pNewTLS = nullptr;
|
||||
xbox::PVOID base;
|
||||
|
@ -704,7 +711,7 @@ void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData, xbox::PVOID Ethread)
|
|||
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 + 12;
|
||||
pNewTLS = (uint8_t*)pNewTLS + TLS_ALIGNMENT_OFFSET;
|
||||
|
||||
if (dwCopySize > 0) {
|
||||
memcpy((uint8_t*)pNewTLS + 4, pTLSData, dwCopySize);
|
||||
|
@ -801,23 +808,22 @@ void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData, xbox::PVOID Ethread)
|
|||
NewPcr->Irql = PASSIVE_LEVEL; // See KeLowerIrql;
|
||||
}
|
||||
|
||||
if constexpr (IsHostThread) {
|
||||
// This only happens for the kernel initialization thread of cxbxr
|
||||
assert(Ethread == xbox::zeroptr);
|
||||
|
||||
base = xbox::zeroptr;
|
||||
size = sizeof(xbox::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
|
||||
}
|
||||
|
||||
// Initialize a fake PrcbData.CurrentThread
|
||||
{
|
||||
// If it is nullptr, it means we are creating this thread from cxbxr, otherwise we were created from PsCreateSystemThreadEx
|
||||
xbox::PETHREAD EThread = static_cast<xbox::PETHREAD>(Ethread);
|
||||
if (EThread == xbox::zeroptr) {
|
||||
// Since this a host thread that we use to execute xbox code, we do not need to create ob handles for this thread
|
||||
base = xbox::zeroptr;
|
||||
size = sizeof(xbox::ETHREAD);
|
||||
xbox::NtAllocateVirtualMemory(&base, 0, &size, XBOX_MEM_RESERVE | XBOX_MEM_COMMIT, XBOX_PAGE_READWRITE);
|
||||
EThread = (xbox::ETHREAD *)base; // Clear, to prevent side-effects on random contents
|
||||
xbox::RtlZeroMemory(EThread, sizeof(xbox::ETHREAD));
|
||||
EThread->UniqueThread = reinterpret_cast<xbox::HANDLE>(GetCurrentThreadId());
|
||||
}
|
||||
|
||||
EThread->Tcb.TlsData = pNewTLS;
|
||||
// Set PrcbData.CurrentThread
|
||||
Prcb->CurrentThread = (xbox::KTHREAD*)EThread;
|
||||
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]);
|
||||
|
@ -844,4 +850,7 @@ void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData, xbox::PVOID Ethread)
|
|||
EmuKeSetPcr(NewPcr);
|
||||
|
||||
EmuLog(LOG_LEVEL::DEBUG, "Installed KPCR in TIB_ArbitraryDataSlot (with pTLS = 0x%.8X)", pTLS);
|
||||
|
||||
_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)
|
||||
}
|
||||
|
|
|
@ -33,11 +33,13 @@
|
|||
extern void EmuInitFS();
|
||||
|
||||
// generate fs segment selector
|
||||
extern void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData, xbox::PVOID Ethread);
|
||||
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);
|
||||
// free kpcr allocated for the thread
|
||||
void EmuKeFreePcr(xbox::HANDLE UniqueThread);
|
||||
template<bool IsHostThread = false>
|
||||
void EmuKeFreePcr();
|
||||
|
||||
void EmuKeSetPcr(xbox::KPCR *Pcr);
|
||||
xbox::KPCR *_stdcall EmuKeGetPcr();
|
||||
|
@ -48,4 +50,9 @@ 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
|
||||
|
|
|
@ -45,6 +45,7 @@ void RegisterXboxHandle(xbox::HANDLE xhandle, HANDLE nhandle)
|
|||
if (ret.second == false) {
|
||||
// This can happen when an ob handle has been destroyed, but then a thread switch happens before the first thread
|
||||
// got a chance to remove the old handle from g_RegisteredHandles with RemoveXboxHandle
|
||||
// Test case: dashboard
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto timeout = now + std::chrono::milliseconds(2000);
|
||||
while (now <= timeout) {
|
||||
|
|
|
@ -536,21 +536,21 @@ void NVNetDevice::Reset()
|
|||
|
||||
bool NVNetDevice::GetMacAddress(std::string adapterName, void* pMAC)
|
||||
{
|
||||
IP_ADAPTER_INFO AdapterInfo[128];
|
||||
PIP_ADAPTER_INFO pAdapterInfo;
|
||||
ULONG dwBufferLength = sizeof(AdapterInfo);
|
||||
// AdapterInfo is too large to be allocated on the stack, and will cause a crash in debug builds when _chkstk detects it
|
||||
PIP_ADAPTER_INFO pAdapterInfo = new IP_ADAPTER_INFO[128];
|
||||
ULONG dwBufferLength = sizeof(IP_ADAPTER_INFO) * 128;
|
||||
|
||||
DWORD dwStatus = GetAdaptersInfo(AdapterInfo, &dwBufferLength);
|
||||
DWORD dwStatus = GetAdaptersInfo(pAdapterInfo, &dwBufferLength);
|
||||
if (dwStatus != ERROR_SUCCESS) {
|
||||
delete[] pAdapterInfo;
|
||||
return false;
|
||||
}
|
||||
|
||||
pAdapterInfo = AdapterInfo;
|
||||
|
||||
// Find the specified adapter
|
||||
do {
|
||||
if (strcmp(pAdapterInfo->AdapterName, adapterName.c_str()) == 0) {
|
||||
memcpy(pMAC, pAdapterInfo->Address, 6);
|
||||
delete[] pAdapterInfo;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -558,6 +558,7 @@ bool NVNetDevice::GetMacAddress(std::string adapterName, void* pMAC)
|
|||
|
||||
} while (pAdapterInfo);
|
||||
|
||||
delete[] pAdapterInfo;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue