From b664488274a2a353f3897f68f8005e58e231c439 Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Mon, 3 Jan 2022 11:12:45 +0100 Subject: [PATCH] Bug fixes --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 19 ---------------- src/core/kernel/common/ps.h | 3 --- src/core/kernel/exports/EmuKrnlKe.cpp | 24 ++++++++++++++++++-- src/core/kernel/exports/EmuKrnlKe.h | 6 +++-- src/core/kernel/exports/EmuKrnlKi.cpp | 11 ++++----- src/core/kernel/exports/EmuKrnlKi.h | 2 +- src/core/kernel/exports/EmuKrnlNt.cpp | 25 +++++++++++++++------ src/core/kernel/exports/EmuKrnlOb.cpp | 2 +- src/core/kernel/exports/EmuKrnlPs.cpp | 23 +++++-------------- src/core/kernel/init/CxbxKrnl.cpp | 1 + src/core/kernel/support/Emu.cpp | 1 - src/core/kernel/support/Emu.h | 1 - src/core/kernel/support/EmuFS.cpp | 27 +++++++++++------------ 13 files changed, 72 insertions(+), 73 deletions(-) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 01d5768c8..0840adb94 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -1867,8 +1867,6 @@ extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg // rendering window message procedure static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { - static bool bAutoPaused = false; - const LRESULT imguiResult = ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam); if (imguiResult != 0) return imguiResult; @@ -2035,27 +2033,10 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar { switch(wParam) { - case SIZE_RESTORED: - case SIZE_MAXIMIZED: - { - if(bAutoPaused) - { - bAutoPaused = false; - CxbxKrnlResume(); - } - } - break; - case SIZE_MINIMIZED: { if(g_XBVideo.bFullScreen) CxbxrKrnlAbort(nullptr); - - if(!g_bEmuSuspended) - { - bAutoPaused = true; - CxbxKrnlSuspend(); - } } break; } diff --git a/src/core/kernel/common/ps.h b/src/core/kernel/common/ps.h index db2539342..564f96e54 100644 --- a/src/core/kernel/common/ps.h +++ b/src/core/kernel/common/ps.h @@ -16,9 +16,6 @@ namespace xbox { - -#define PsGetCurrentThread() (CONTAINING_RECORD((KeGetCurrentThread()),ETHREAD,Tcb)) - // ****************************************************************** // * PsCreateSystemThread // ****************************************************************** diff --git a/src/core/kernel/exports/EmuKrnlKe.cpp b/src/core/kernel/exports/EmuKrnlKe.cpp index 3cc58fe3f..e38edf244 100644 --- a/src/core/kernel/exports/EmuKrnlKe.cpp +++ b/src/core/kernel/exports/EmuKrnlKe.cpp @@ -263,6 +263,26 @@ xbox::void_xt NTAPI xbox::KeInitializeTimer KeInitializeTimerEx(Timer, NotificationTimer); } +// ****************************************************************** +// * KeEmptyQueueApc() +// ****************************************************************** +xbox::void_xt xbox::KeEmptyQueueApc() +{ + PKTHREAD kThread = KeGetCurrentThread(); + kThread->ApcState.ApcQueueable = FALSE; + + KiApcListMtx.lock(); + for (int Mode = KernelMode; Mode < MaximumMode; ++Mode) { + while (!IsListEmpty(&kThread->ApcState.ApcListHead[Mode])) { + PLIST_ENTRY Entry = kThread->ApcState.ApcListHead[Mode].Flink; + PKAPC Apc = CONTAINING_RECORD(Entry, KAPC, ApcListEntry); + RemoveEntryList(Entry); + ExFreePool(Apc); + } + } + KiApcListMtx.unlock(); +} + // Forward KeLowerIrql() to KfLowerIrql() #define KeLowerIrql(NewIrql) \ KfLowerIrql(NewIrql) @@ -1027,9 +1047,9 @@ XBSYSAPI EXPORTNUM(118) xbox::boolean_xt NTAPI xbox::KeInsertQueueApc RETURN(FALSE); } else { - g_ApcListMtx.lock(); + KiApcListMtx.lock(); InsertTailList(&kThread->ApcState.ApcListHead[Apc->ApcMode], &Apc->ApcListEntry); - g_ApcListMtx.unlock(); + KiApcListMtx.unlock(); Apc->Inserted = TRUE; // We can only attempt to execute the queued apc right away if it is been inserted in the current thread, because otherwise the KTHREAD diff --git a/src/core/kernel/exports/EmuKrnlKe.h b/src/core/kernel/exports/EmuKrnlKe.h index cca37ebd9..d92b1cb96 100644 --- a/src/core/kernel/exports/EmuKrnlKe.h +++ b/src/core/kernel/exports/EmuKrnlKe.h @@ -27,14 +27,16 @@ namespace xbox { - xbox::void_xt NTAPI KeSetSystemTime + void_xt NTAPI KeSetSystemTime ( IN PLARGE_INTEGER NewTime, OUT PLARGE_INTEGER OldTime ); - xbox::void_xt NTAPI KeInitializeTimer + void_xt NTAPI KeInitializeTimer ( IN PKTIMER Timer ); + + void_xt KeEmptyQueueApc(); } diff --git a/src/core/kernel/exports/EmuKrnlKi.cpp b/src/core/kernel/exports/EmuKrnlKi.cpp index b67c95440..7cac92984 100644 --- a/src/core/kernel/exports/EmuKrnlKi.cpp +++ b/src/core/kernel/exports/EmuKrnlKi.cpp @@ -95,6 +95,7 @@ xbox::KDPC KiTimerExpireDpc; xbox::KI_TIMER_LOCK KiTimerMtx; xbox::KTIMER_TABLE_ENTRY KiTimerTableListHead[TIMER_TABLE_SIZE]; xbox::LIST_ENTRY KiWaitInListHead; +std::mutex xbox::KiApcListMtx; xbox::void_xt xbox::KiInitSystem() @@ -895,16 +896,16 @@ static xbox::void_xt KiExecuteApc() } // 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::g_ApcListMtx.lock(); + xbox::KiApcListMtx.lock(); while (!IsListEmpty(&kThread->ApcState.ApcListHead[ApcMode])) { if (KernelApc && (kThread->KernelApcDisable != 0)) { - xbox::g_ApcListMtx.unlock(); + xbox::KiApcListMtx.unlock(); return; } xbox::PLIST_ENTRY Entry = kThread->ApcState.ApcListHead[ApcMode].Flink; xbox::PKAPC Apc = CONTAINING_RECORD(Entry, xbox::KAPC, ApcListEntry); RemoveEntryList(Entry); - xbox::g_ApcListMtx.unlock(); + xbox::KiApcListMtx.unlock(); Apc->Inserted = FALSE; // NOTE: we never use KernelRoutine @@ -913,10 +914,10 @@ static xbox::void_xt KiExecuteApc() } xbox::ExFreePool(Apc); - xbox::g_ApcListMtx.lock(); + xbox::KiApcListMtx.lock(); } - xbox::g_ApcListMtx.unlock(); + xbox::KiApcListMtx.unlock(); } xbox::void_xt xbox::KiExecuteKernelApc() diff --git a/src/core/kernel/exports/EmuKrnlKi.h b/src/core/kernel/exports/EmuKrnlKi.h index b4286447b..501c53b72 100644 --- a/src/core/kernel/exports/EmuKrnlKi.h +++ b/src/core/kernel/exports/EmuKrnlKi.h @@ -48,7 +48,7 @@ namespace xbox } KI_TIMER_LOCK; // NOTE: since the apc list is per-thread, we could also create a different mutex for each kthread - std::mutex g_ApcListMtx; + extern std::mutex KiApcListMtx; void_xt KiInitSystem(); diff --git a/src/core/kernel/exports/EmuKrnlNt.cpp b/src/core/kernel/exports/EmuKrnlNt.cpp index 2dc8aa8f8..a61a88d70 100644 --- a/src/core/kernel/exports/EmuKrnlNt.cpp +++ b/src/core/kernel/exports/EmuKrnlNt.cpp @@ -716,18 +716,28 @@ XBSYSAPI EXPORTNUM(197) xbox::ntstatus_xt NTAPI xbox::NtDuplicateObject // On the xbox, the duplicated handle always has the same access rigths of the source handle const ACCESS_MASK DesiredAccess = 0; const ULONG Attributes = 0; - dword_xt nativeOptions = (Options | DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS); + const ULONG nativeOptions = (Options | DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS); - if (const auto &nativeHandle = GetNativeHandle(SourceHandle)) { + // If SourceHandle is -2 = NtCurrentThread, then we need to duplicate the handle of this thread + // Test case: Metal Slug 3 + std::optional nativeHandle; + if (SourceHandle == NtCurrentThread()) { + nativeHandle = GetNativeHandle(PspGetCurrentThread()->UniqueThread); + } + else { + nativeHandle = GetNativeHandle(SourceHandle); + } + + if (nativeHandle) { // This was a handle created by Ob PVOID Object; - status = ObReferenceObjectByHandle(SourceHandle, /*ObjectType=*/nullptr, &Object); + status = ObReferenceObjectByHandle(SourceHandle, zeroptr, &Object); if (X_NT_SUCCESS(status)) { if (ObpIsFlagSet(Options, DUPLICATE_CLOSE_SOURCE)) { NtClose(SourceHandle); } - status = ObOpenObjectByPointer(Object, OBJECT_TO_OBJECT_HEADER(Object)->Type, /*OUT*/TargetHandle); + status = ObOpenObjectByPointer(Object, OBJECT_TO_OBJECT_HEADER(Object)->Type, TargetHandle); if (!X_NT_SUCCESS(status)) { *TargetHandle = NULL; RETURN(status); @@ -2208,16 +2218,17 @@ XBSYSAPI EXPORTNUM(235) xbox::ntstatus_xt NTAPI xbox::NtWaitForMultipleObjectsEx if (Alertable && (WaitMode == UserMode)) { bool Exit = false; PETHREAD eThread = PspGetCurrentThread(); + auto &fut = std::async(std::launch::async, [eThread, &Exit]() { while (true) { - xbox::g_ApcListMtx.lock(); + xbox::KiApcListMtx.lock(); bool Empty = IsListEmpty(&eThread->Tcb.ApcState.ApcListHead[UserMode]); - xbox::g_ApcListMtx.unlock(); + xbox::KiApcListMtx.unlock(); if (Empty == false) { KiExecuteUserApc(); // Queue a native APC to the calling thread to forcefully terminate the wait in NtDll::NtWaitForMultipleObjects, // in the case it didn't terminate already - QueueUserAPC(EndWait, *GetNativeHandle(eThread->UniqueThread), 0); + BOOL t = QueueUserAPC(EndWait, *GetNativeHandle(eThread->UniqueThread), 0); return true; } Sleep(0); diff --git a/src/core/kernel/exports/EmuKrnlOb.cpp b/src/core/kernel/exports/EmuKrnlOb.cpp index 159d1fbe6..647bb07fa 100644 --- a/src/core/kernel/exports/EmuKrnlOb.cpp +++ b/src/core/kernel/exports/EmuKrnlOb.cpp @@ -1019,7 +1019,7 @@ XBSYSAPI EXPORTNUM(246) xbox::ntstatus_xt NTAPI xbox::ObReferenceObjectByHandle if (Handle == NtCurrentThread()) { if ((ObjectType == &PsThreadObjectType) || (ObjectType == NULL)) { - Object = PsGetCurrentThread(); + Object = PspGetCurrentThread(); ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); InterlockedIncrement((::PLONG)(&ObjectHeader->PointerCount)); *ReturnedObject = Object; diff --git a/src/core/kernel/exports/EmuKrnlPs.cpp b/src/core/kernel/exports/EmuKrnlPs.cpp index 0e1b0f34e..c2138a9af 100644 --- a/src/core/kernel/exports/EmuKrnlPs.cpp +++ b/src/core/kernel/exports/EmuKrnlPs.cpp @@ -32,6 +32,7 @@ #include // For PsCreateSystemThreadEx, etc. #include "core\kernel\exports\EmuKrnlKi.h" +#include "core\kernel\exports\EmuKrnlKe.h" #include // For __beginthreadex(), etc. #include // For _controlfp constants @@ -291,7 +292,8 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx } }*/ - HANDLE handle = reinterpret_cast(_beginthreadex(NULL, KernelStackSize, PCSTProxy, iPCSTProxyParam, CREATE_SUSPENDED, nullptr)); + unsigned int ThreadId; + HANDLE handle = reinterpret_cast(_beginthreadex(NULL, KernelStackSize, PCSTProxy, iPCSTProxyParam, CREATE_SUSPENDED, &ThreadId)); if (handle == NULL) { delete iPCSTProxyParam; ObpClose(eThread->UniqueThread); @@ -300,7 +302,7 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx } KiUniqueProcess.StackCount++; - RegisterXboxHandle(ThreadHandle, handle); + RegisterXboxHandle(*ThreadHandle, handle); RegisterXboxHandle(eThread->UniqueThread, handle); g_AffinityPolicy->SetAffinityXbox(handle); @@ -311,7 +313,8 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx } // Log ThreadID identical to how GetCurrentThreadID() is rendered : - EmuLog(LOG_LEVEL::DEBUG, "Created Xbox proxy thread. Handle : 0x%X, ThreadId : [0x%.4X]", *ThreadHandle, eThread->UniqueThread); + EmuLog(LOG_LEVEL::DEBUG, "Created Xbox proxy thread. Handle : 0x%X, ThreadId : [0x%.4X], Native ThreadId : [0x%.4X]", + *ThreadHandle, eThread->UniqueThread, ThreadId); } RETURN(X_STATUS_SUCCESS); @@ -405,20 +408,6 @@ XBSYSAPI EXPORTNUM(258) xbox::void_xt NTAPI xbox::PsTerminateSystemThread } }*/ - PKTHREAD kThread = KeGetCurrentThread(); - kThread->ApcState.ApcQueueable = FALSE; - - g_ApcListMtx.lock(); - for (int Mode = KernelMode; Mode < MaximumMode; ++Mode) { - while (!IsListEmpty(&kThread->ApcState.ApcListHead[Mode])) { - PLIST_ENTRY Entry = kThread->ApcState.ApcListHead[Mode].Flink; - PKAPC Apc = CONTAINING_RECORD(Entry, KAPC, ApcListEntry); - RemoveEntryList(Entry); - ExFreePool(Apc); - } - } - g_ApcListMtx.unlock(); - EmuKeFreeThread(); KiUniqueProcess.StackCount--; diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index c1685dd5f..4098ae7d0 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -42,6 +42,7 @@ #include "EmuEEPROM.h" // For CxbxRestoreEEPROM, EEPROM, XboxFactoryGameRegion #include "core\kernel\exports\EmuKrnl.h" #include "core\kernel\exports\EmuKrnlKi.h" +#include "core\kernel\exports\EmuKrnlKe.h" #include "EmuShared.h" #include "core\hle\D3D8\Direct3D9\Direct3D9.h" // For CxbxInitWindow, EmuD3DInit #include "core\hle\DSOUND\DirectSound\DirectSound.hpp" // For CxbxInitAudio diff --git a/src/core/kernel/support/Emu.cpp b/src/core/kernel/support/Emu.cpp index 5eec5646e..01b919af2 100644 --- a/src/core/kernel/support/Emu.cpp +++ b/src/core/kernel/support/Emu.cpp @@ -45,7 +45,6 @@ CRITICAL_SECTION dbgCritical; // Global Variable(s) volatile thread_local bool g_bEmuException = false; static thread_local bool bOverrideEmuException; -volatile bool g_bEmuSuspended = false; volatile bool g_bPrintfOn = true; bool g_DisablePixelShaders = false; bool g_UseAllCores = false; diff --git a/src/core/kernel/support/Emu.h b/src/core/kernel/support/Emu.h index 328b993fd..0ee0ec773 100644 --- a/src/core/kernel/support/Emu.h +++ b/src/core/kernel/support/Emu.h @@ -58,7 +58,6 @@ void EmuPrintStackTrace(PCONTEXT ContextRecord); // global flags specifying current emulation state extern volatile thread_local bool g_bEmuException; -extern volatile bool g_bEmuSuspended; // global exception patching address extern void * funcExclude[2048]; diff --git a/src/core/kernel/support/EmuFS.cpp b/src/core/kernel/support/EmuFS.cpp index a25f9d710..f327a4025 100644 --- a/src/core/kernel/support/EmuFS.cpp +++ b/src/core/kernel/support/EmuFS.cpp @@ -213,6 +213,8 @@ 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::KeEmptyQueueApc(); + xbox::PETHREAD eThread = xbox::PspGetCurrentThread(); if (eThread->UniqueThread != NULL) { xbox::NtClose(eThread->UniqueThread); @@ -782,27 +784,24 @@ void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData, xbox::PVOID Ethread) // 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(Ethread); if (EThread == xbox::zeroptr) { - // If it is nullptr, it means we are creating this thread from cxbxr, otherwise we were created from PsCreateSystemThreadEx - xbox::PETHREAD eThread; - xbox::ntstatus_xt result = xbox::ObCreateObject(&xbox::PsThreadObjectType, xbox::zeroptr, sizeof(xbox::ETHREAD), reinterpret_cast(&eThread)); - if (!X_NT_SUCCESS(result)) { - // We can't recover from here, abort execution - CxbxrKrnlAbort("ObCreateObject: failed to create new xbox thread!"); - } - std::memset(eThread, 0, sizeof(xbox::ETHREAD)); - EThread = eThread; - result = xbox::ObInsertObject(eThread, xbox::zeroptr, 0, &eThread->UniqueThread); - if (!X_NT_SUCCESS(result)) { - // We can't recover from here, abort execution - CxbxrKrnlAbort("ObInsertObject: failed to create new xbox thread!"); - } + // 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(GetCurrentThreadId()); } EThread->Tcb.TlsData = pNewTLS; // Set PrcbData.CurrentThread Prcb->CurrentThread = (xbox::KTHREAD*)EThread; + // 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; // Initialize the thread header and its wait list