diff --git a/src/core/hle/Patches.cpp b/src/core/hle/Patches.cpp index 2703bcaee..85d6eb41f 100644 --- a/src/core/hle/Patches.cpp +++ b/src/core/hle/Patches.cpp @@ -364,7 +364,7 @@ std::map g_PatchTable = { PATCH_ENTRY("SwitchToFiber", xbox::EMUPATCH(SwitchToFiber), PATCH_IS_FIBER), PATCH_ENTRY("XMountMUA", xbox::EMUPATCH(XMountMUA), PATCH_ALWAYS), PATCH_ENTRY("XMountMURootA", xbox::EMUPATCH(XMountMURootA), PATCH_ALWAYS), - PATCH_ENTRY("XSetProcessQuantumLength", xbox::EMUPATCH(XSetProcessQuantumLength), PATCH_ALWAYS), + //PATCH_ENTRY("XSetProcessQuantumLength", xbox::EMUPATCH(XSetProcessQuantumLength), PATCH_ALWAYS), PATCH_ENTRY("timeKillEvent", xbox::EMUPATCH(timeKillEvent), PATCH_ALWAYS), PATCH_ENTRY("timeSetEvent", xbox::EMUPATCH(timeSetEvent), PATCH_ALWAYS), PATCH_ENTRY("XReadMUMetaData", xbox::EMUPATCH(XReadMUMetaData), PATCH_ALWAYS), diff --git a/src/core/hle/XAPI/Xapi.cpp b/src/core/hle/XAPI/Xapi.cpp index 4b4aa8c27..93eeb1f86 100644 --- a/src/core/hle/XAPI/Xapi.cpp +++ b/src/core/hle/XAPI/Xapi.cpp @@ -896,200 +896,6 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XInputSetLightgunCalibration) RETURN(ret); } -#if 0 -// ****************************************************************** -// * patch: SetThreadPriorityBoost -// ****************************************************************** -xbox::bool_xt WINAPI xbox::EMUPATCH(SetThreadPriorityBoost) -( - HANDLE hThread, - bool_xt DisablePriorityBoost -) -{ - - - LOG_FUNC_BEGIN - LOG_FUNC_ARG(hThread) - LOG_FUNC_ARG(DisablePriorityBoost) - LOG_FUNC_END; - - if (const auto &nativeHandle = GetNativeHandle(hThread)) { - BOOL bRet = SetThreadPriorityBoost(*nativeHandle, DisablePriorityBoost); - if (bRet == FALSE) { - EmuLog(LOG_LEVEL::WARNING, "SetThreadPriorityBoost Failed!"); - } - RETURN(bRet); - } - else { - RETURN(0); - } -} -#endif - -#if 0 -// ****************************************************************** -// * patch: SetThreadPriority -// ****************************************************************** -xbox::bool_xt WINAPI xbox::EMUPATCH(SetThreadPriority) -( - HANDLE hThread, - int nPriority -) -{ - - - LOG_FUNC_BEGIN - LOG_FUNC_ARG(hThread) - LOG_FUNC_ARG(nPriority) - LOG_FUNC_END; - - if (const auto &nativeHandle = GetNativeHandle(hThread)) { - BOOL bRet = SetThreadPriority(*nativeHandle, nPriority); - if (bRet == FALSE) { - EmuLog(LOG_LEVEL::WARNING, "SetThreadPriority Failed!"); - } - RETURN(bRet); - } - else { - RETURN(0); - } -} -#endif - - -#if 0 -// ****************************************************************** -// * patch: GetThreadPriority -// ****************************************************************** -int WINAPI xbox::EMUPATCH(GetThreadPriority) -( - HANDLE hThread -) -{ - - - LOG_FUNC_ONE_ARG(hThread); - - if (const auto &nativeHandle = GetNativeHandle(hThread)) { - int iRet = GetThreadPriority(*nativeHandle); - if (iRet == THREAD_PRIORITY_ERROR_RETURN) { - EmuLog(LOG_LEVEL::WARNING, "GetThreadPriority Failed!"); - } - RETURN(iRet); - } - else { - RETURN(THREAD_PRIORITY_ERROR_RETURN); - } -} -#endif - -#if 0 -// ****************************************************************** -// * patch: GetExitCodeThread -// ****************************************************************** -xbox::bool_xt WINAPI xbox::EMUPATCH(GetExitCodeThread) -( - HANDLE hThread, - LPDWORD lpExitCode -) -{ - - - LOG_FUNC_BEGIN - LOG_FUNC_ARG(hThread) - LOG_FUNC_ARG(lpExitCode) - LOG_FUNC_END; - - if (const auto &nativeHandle = GetNativeHandle(hThread)) { - RETURN(GetExitCodeThread(*nativeHandle, (::LPDWORD)lpExitCode)); - } - else { - RETURN(0); - } -} -#endif - -// ****************************************************************** -// * patch: XapiThreadStartup -// ****************************************************************** -xbox::void_xt WINAPI xbox::EMUPATCH(XapiThreadStartup) -( - dword_xt dwDummy1, - dword_xt dwDummy2 -) -{ - LOG_FUNC_BEGIN - LOG_FUNC_ARG(dwDummy1) - LOG_FUNC_ARG(dwDummy2) - LOG_FUNC_END; - - typedef int (__stdcall *pfDummyFunc)(dword_xt dwDummy); - - pfDummyFunc func = (pfDummyFunc)dwDummy1; - - func(dwDummy2); - - // TODO: Call thread notify routines ? - - /* - __asm - { - push dwDummy2 - call dwDummy1 - } - */ - - //_asm int 3; -} - -// ****************************************************************** -// * patch: XRegisterThreadNotifyRoutine -// ****************************************************************** -xbox::void_xt WINAPI xbox::EMUPATCH(XRegisterThreadNotifyRoutine) -( - PXTHREAD_NOTIFICATION pThreadNotification, - bool_xt fRegister -) -{ - LOG_FUNC_BEGIN - LOG_FUNC_ARG(pThreadNotification) - LOG_FUNC_ARG(fRegister) - LOG_FUNC_END; - - if(fRegister) - { - // I honestly don't expect this to happen, but if it does... - if(g_iThreadNotificationCount >= 16) - CxbxrKrnlAbort("Too many thread notification routines installed\n"); - - // Find an empty spot in the thread notification array - for(int i = 0; i < 16; i++) - { - // If we find one, then add it to the array, and break the loop so - // that we don't accidently register the same routine twice! - if(g_pfnThreadNotification[i] == NULL) - { - g_pfnThreadNotification[i] = (PVOID)pThreadNotification->pfnNotifyRoutine; - g_iThreadNotificationCount++; - break; - } - } - } - else - { - // Go through each routine and nullify the routine passed in. - for(int i = 0; i < 16; i++) - { - if(pThreadNotification->pfnNotifyRoutine == g_pfnThreadNotification[i]) - { - g_pfnThreadNotification[i] = NULL; - g_iThreadNotificationCount--; - break; - } - } - } -} - typedef struct { LPFIBER_START_ROUTINE lpStartRoutine; LPVOID lpParameter; @@ -1172,216 +978,6 @@ xbox::LPVOID WINAPI xbox::EMUPATCH(ConvertThreadToFiber) RETURN(pRet); } - -#if 0 // Handled by NtQueueApcThread -// ****************************************************************** -// * patch: QueueUserAPC -// ****************************************************************** -xbox::dword_xt WINAPI xbox::EMUPATCH(QueueUserAPC) -( - PAPCFUNC pfnAPC, - HANDLE hThread, - dword_xt dwData -) -{ - LOG_FUNC_BEGIN - LOG_FUNC_ARG_TYPE(PVOID, pfnAPC) - LOG_FUNC_ARG(hThread) - LOG_FUNC_ARG(dwData) - LOG_FUNC_END; - - dword_xt dwRet = 0; - - // If necessary, we can just continue to emulate NtQueueApcThread (0xCE). - // I added this because NtQueueApcThread fails in Metal Slug 3. - - HANDLE hApcThread = NULL; - if(!DuplicateHandle(g_CurrentProcessHandle, hThread, g_CurrentProcessHandle, &hApcThread, THREAD_SET_CONTEXT,FALSE,0)) - EmuLog(LOG_LEVEL::WARNING, "DuplicateHandle failed!"); - - dwRet = QueueUserAPC(pfnAPC, hApcThread, dwData); - if(!dwRet) - EmuLog(LOG_LEVEL::WARNING, "QueueUserAPC failed!"); - - RETURN(dwRet); -} -#endif - -#if 0 // Handled by WaitForSingleObject -// ****************************************************************** -// * patch: GetOverlappedResult -// ****************************************************************** -xbox::bool_xt WINAPI xbox::EMUPATCH(GetOverlappedResult) -( - HANDLE hFile, - LPOVERLAPPED lpOverlapped, - LPDWORD lpNumberOfBytesTransferred, - bool_xt bWait -) -{ - LOG_FUNC_BEGIN - LOG_FUNC_ARG(hFile) - LOG_FUNC_ARG(lpOverlapped) - LOG_FUNC_ARG(lpNumberOfBytesTransferred) - LOG_FUNC_ARG(bWait) - LOG_FUNC_END; - - BOOL bRet = GetOverlappedResult( hFile, lpOverlapped, lpNumberOfBytesTransferred, bWait ); - -// if(bWait) -// bRet = TRUE; // Sucker... - - RETURN(bRet); -} -#endif - -// ****************************************************************** -// * patch: XLaunchNewImageA -// ****************************************************************** -xbox::dword_xt WINAPI xbox::EMUPATCH(XLaunchNewImageA) -( - LPCSTR lpTitlePath, - PLAUNCH_DATA pLaunchData -) -{ - // Note : This can be tested using "Innocent tears", - // which relaunches different xbes between scenes; - // One for menus, one for fmvs, etc. - // - // Other titles do this too (like "DOA2 Ultimate", - // and probably "Panzer Dragoon Orta"), but these - // titles don't come this far as-of yet. - - LOG_FUNC_BEGIN - LOG_FUNC_ARG(lpTitlePath) - LOG_FUNC_ARG(pLaunchData) - LOG_FUNC_END; - - // TODO : This patch can be removed once NtOpenSymbolicLinkObject() - // and NtQuerySymbolicLinkObject() work together correctly. - // Also, XLaunchNewImageA() depends on XeImageHeader() and uses - // XWriteTitleInfoAndReboot() and indirectly XWriteTitleInfoNoReboot() - - // Update the kernel's LaunchDataPage : - { - if (xbox::LaunchDataPage == xbox::zeroptr) - { - PVOID LaunchDataVAddr = xbox::MmAllocateContiguousMemory(sizeof(xbox::LAUNCH_DATA_PAGE)); - if (!LaunchDataVAddr) - { - RETURN(X_STATUS_NO_MEMORY); - } - xbox::LaunchDataPage = (xbox::LAUNCH_DATA_PAGE*)LaunchDataVAddr; - } - - xbox::LaunchDataPage->Header.dwTitleId = g_pCertificate->dwTitleId; - xbox::LaunchDataPage->Header.dwFlags = 0; // TODO : What to put in here? - xbox::LaunchDataPage->Header.dwLaunchDataType = LDT_TITLE; - - xbox::MmPersistContiguousMemory((PVOID)xbox::LaunchDataPage, PAGE_SIZE, TRUE); - - if (pLaunchData != xbox::zeroptr) - // Save the launch data - memcpy(&(xbox::LaunchDataPage->LaunchData[0]), pLaunchData, sizeof(LAUNCH_DATA)); - - if (lpTitlePath == xbox::zeroptr) - { - // If no path is specified, then the xbe is rebooting to dashboard - char szDashboardPath[xbox::max_path] = { 0 }; - XboxDevice* rootDevice = CxbxDeviceByDevicePath(DeviceHarddisk0Partition2); - if (rootDevice != nullptr) - sprintf(szDashboardPath, "%s\\xboxdash.xbe", rootDevice->HostDevicePath.c_str()); - - if (PathFileExists(szDashboardPath)) - { - PopupInfo(nullptr, "The title is rebooting to dashboard"); - lpTitlePath = "C:\\xboxdash.xbe"; - xbox::LaunchDataPage->Header.dwLaunchDataType = LDT_FROM_DASHBOARD; - // Other options include LDT_NONE, LDT_FROM_DEBUGGER_CMDLINE and LDT_FROM_UPDATE - } - else - CxbxrKrnlAbort("The xbe rebooted to Dashboard and xboxdash.xbe could not be found"); - } - - strncpy(&(xbox::LaunchDataPage->Header.szLaunchPath[0]), lpTitlePath, 520); - } - - // Note : While this patch exists, HalReturnToFirmware() calls - // MmPersistContiguousMemory on LaunchDataPage. When this - // patch on XLaunchNewImageA is removed, remove the call to - // MmPersistContiguousMemory from HalReturnToFirmware() too!! - - xbox::HalReturnToFirmware(xbox::ReturnFirmwareQuickReboot); - - // If this function succeeds, it doesn't get a chance to return anything. - RETURN(ERROR_GEN_FAILURE); -} - -#if 0 // patch disabled -// ****************************************************************** -// * patch: XGetLaunchInfo -// ****************************************************************** -xbox::dword_xt WINAPI xbox::EMUPATCH(XGetLaunchInfo) -( - PDWORD pdwLaunchDataType, - PLAUNCH_DATA pLaunchData -) -{ - - - // TODO : This patch can be removed once we're sure all XAPI library - // functions indirectly reference our xbox::LaunchDataPage variable. - // For this, we need a test-case that hits this function, and run that - // with and without this patch enabled. Behavior should be identical. - // When this is verified, this patch can be removed. - LOG_TEST_CASE("Unpatching test needed"); - - LOG_FUNC_BEGIN - LOG_FUNC_ARG(pdwLaunchDataType) - LOG_FUNC_ARG(pLaunchData) - LOG_FUNC_END; - - dword_xt ret = ERROR_NOT_FOUND; - - if (xbox::LaunchDataPage != NULL) - { - // Note : Here, CxbxRestoreLaunchDataPage() was already called, - // which has loaded LaunchDataPage from a binary file (if present). - - // A title can pass data only to itself, not another title (unless started from the dashboard, of course) : - if ( (xbox::LaunchDataPage->Header.dwTitleId == g_pCertificate->dwTitleId) - || (xbox::LaunchDataPage->Header.dwLaunchDataType == LDT_FROM_DASHBOARD) - || (xbox::LaunchDataPage->Header.dwLaunchDataType == LDT_FROM_DEBUGGER_CMDLINE)) - { - *pdwLaunchDataType = xbox::LaunchDataPage->Header.dwLaunchDataType; - memcpy(pLaunchData, &(xbox::LaunchDataPage->LaunchData[0]), sizeof(LAUNCH_DATA)); - - // Now that LaunchDataPage is retrieved by the emulated software, free it : - MmFreeContiguousMemory(xbox::LaunchDataPage); - xbox::LaunchDataPage = NULL; - - ret = ERROR_SUCCESS; - } - } - - RETURN(ret); -} -#endif - -// ****************************************************************** -// * patch: XSetProcessQuantumLength -// ****************************************************************** -xbox::void_xt WINAPI xbox::EMUPATCH(XSetProcessQuantumLength) -( - dword_xt dwMilliseconds -) -{ - - LOG_FUNC_ONE_ARG(dwMilliseconds); - - // TODO: Implement? - LOG_IGNORED(); -} // ****************************************************************** // * patch: SignalObjectAndWait @@ -1394,7 +990,6 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(SignalObjectAndWait) bool_xt bAlertable ) { - LOG_FUNC_BEGIN LOG_FUNC_ARG(hObjectToSignal) LOG_FUNC_ARG(hObjectToWaitOn) @@ -1402,7 +997,15 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(SignalObjectAndWait) LOG_FUNC_ARG(bAlertable) LOG_FUNC_END; - dword_xt dwRet = SignalObjectAndWait( hObjectToSignal, hObjectToWaitOn, dwMilliseconds, bAlertable ); + // 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); + + dword_xt dwRet = SignalObjectAndWait(hObjectToSignal, hObjectToWaitOn, dwMilliseconds, bAlertable); + + Exit = true; + bool result = fut.get(); + return result ? X_STATUS_USER_APC : dwRet; RETURN(dwRet); } diff --git a/src/core/hle/XAPI/Xapi.cpp.unused-patches b/src/core/hle/XAPI/Xapi.cpp.unused-patches new file mode 100644 index 000000000..976a261b0 --- /dev/null +++ b/src/core/hle/XAPI/Xapi.cpp.unused-patches @@ -0,0 +1,355 @@ +xbox::bool_xt WINAPI xbox::EMUPATCH(SetThreadPriorityBoost) +( + HANDLE hThread, + bool_xt DisablePriorityBoost +) +{ + + + LOG_FUNC_BEGIN + LOG_FUNC_ARG(hThread) + LOG_FUNC_ARG(DisablePriorityBoost) + LOG_FUNC_END; + + if (const auto &nativeHandle = GetNativeHandle(hThread)) { + BOOL bRet = SetThreadPriorityBoost(*nativeHandle, DisablePriorityBoost); + if (bRet == FALSE) { + EmuLog(LOG_LEVEL::WARNING, "SetThreadPriorityBoost Failed!"); + } + RETURN(bRet); + } + else { + RETURN(0); + } +} + +xbox::bool_xt WINAPI xbox::EMUPATCH(SetThreadPriority) +( + HANDLE hThread, + int nPriority +) +{ + + + LOG_FUNC_BEGIN + LOG_FUNC_ARG(hThread) + LOG_FUNC_ARG(nPriority) + LOG_FUNC_END; + + if (const auto &nativeHandle = GetNativeHandle(hThread)) { + BOOL bRet = SetThreadPriority(*nativeHandle, nPriority); + if (bRet == FALSE) { + EmuLog(LOG_LEVEL::WARNING, "SetThreadPriority Failed!"); + } + RETURN(bRet); + } + else { + RETURN(0); + } +} + +int WINAPI xbox::EMUPATCH(GetThreadPriority) +( + HANDLE hThread +) +{ + + + LOG_FUNC_ONE_ARG(hThread); + + if (const auto &nativeHandle = GetNativeHandle(hThread)) { + int iRet = GetThreadPriority(*nativeHandle); + if (iRet == THREAD_PRIORITY_ERROR_RETURN) { + EmuLog(LOG_LEVEL::WARNING, "GetThreadPriority Failed!"); + } + RETURN(iRet); + } + else { + RETURN(THREAD_PRIORITY_ERROR_RETURN); + } +} + +xbox::bool_xt WINAPI xbox::EMUPATCH(GetExitCodeThread) +( + HANDLE hThread, + LPDWORD lpExitCode +) +{ + + + LOG_FUNC_BEGIN + LOG_FUNC_ARG(hThread) + LOG_FUNC_ARG(lpExitCode) + LOG_FUNC_END; + + if (const auto &nativeHandle = GetNativeHandle(hThread)) { + RETURN(GetExitCodeThread(*nativeHandle, (::LPDWORD)lpExitCode)); + } + else { + RETURN(0); + } +} + +xbox::void_xt WINAPI xbox::EMUPATCH(XapiThreadStartup) +( + dword_xt dwDummy1, + dword_xt dwDummy2 +) +{ + LOG_FUNC_BEGIN + LOG_FUNC_ARG(dwDummy1) + LOG_FUNC_ARG(dwDummy2) + LOG_FUNC_END; + + typedef int (__stdcall *pfDummyFunc)(dword_xt dwDummy); + + pfDummyFunc func = (pfDummyFunc)dwDummy1; + + func(dwDummy2); + + // TODO: Call thread notify routines ? + + /* + __asm + { + push dwDummy2 + call dwDummy1 + } + */ + + //_asm int 3; +} + +xbox::void_xt WINAPI xbox::EMUPATCH(XRegisterThreadNotifyRoutine) +( + PXTHREAD_NOTIFICATION pThreadNotification, + bool_xt fRegister +) +{ + LOG_FUNC_BEGIN + LOG_FUNC_ARG(pThreadNotification) + LOG_FUNC_ARG(fRegister) + LOG_FUNC_END; + + if(fRegister) + { + // I honestly don't expect this to happen, but if it does... + if(g_iThreadNotificationCount >= 16) + CxbxrKrnlAbort("Too many thread notification routines installed\n"); + + // Find an empty spot in the thread notification array + for(int i = 0; i < 16; i++) + { + // If we find one, then add it to the array, and break the loop so + // that we don't accidently register the same routine twice! + if(g_pfnThreadNotification[i] == NULL) + { + g_pfnThreadNotification[i] = (PVOID)pThreadNotification->pfnNotifyRoutine; + g_iThreadNotificationCount++; + break; + } + } + } + else + { + // Go through each routine and nullify the routine passed in. + for(int i = 0; i < 16; i++) + { + if(pThreadNotification->pfnNotifyRoutine == g_pfnThreadNotification[i]) + { + g_pfnThreadNotification[i] = NULL; + g_iThreadNotificationCount--; + break; + } + } + } +} + +xbox::dword_xt WINAPI xbox::EMUPATCH(QueueUserAPC) +( + PAPCFUNC pfnAPC, + HANDLE hThread, + dword_xt dwData +) +{ + LOG_FUNC_BEGIN + LOG_FUNC_ARG_TYPE(PVOID, pfnAPC) + LOG_FUNC_ARG(hThread) + LOG_FUNC_ARG(dwData) + LOG_FUNC_END; + + dword_xt dwRet = 0; + + // If necessary, we can just continue to emulate NtQueueApcThread (0xCE). + // I added this because NtQueueApcThread fails in Metal Slug 3. + + HANDLE hApcThread = NULL; + if(!DuplicateHandle(g_CurrentProcessHandle, hThread, g_CurrentProcessHandle, &hApcThread, THREAD_SET_CONTEXT,FALSE,0)) + EmuLog(LOG_LEVEL::WARNING, "DuplicateHandle failed!"); + + dwRet = QueueUserAPC(pfnAPC, hApcThread, dwData); + if(!dwRet) + EmuLog(LOG_LEVEL::WARNING, "QueueUserAPC failed!"); + + RETURN(dwRet); +} + +xbox::bool_xt WINAPI xbox::EMUPATCH(GetOverlappedResult) +( + HANDLE hFile, + LPOVERLAPPED lpOverlapped, + LPDWORD lpNumberOfBytesTransferred, + bool_xt bWait +) +{ + LOG_FUNC_BEGIN + LOG_FUNC_ARG(hFile) + LOG_FUNC_ARG(lpOverlapped) + LOG_FUNC_ARG(lpNumberOfBytesTransferred) + LOG_FUNC_ARG(bWait) + LOG_FUNC_END; + + BOOL bRet = GetOverlappedResult( hFile, lpOverlapped, lpNumberOfBytesTransferred, bWait ); + +// if(bWait) +// bRet = TRUE; // Sucker... + + RETURN(bRet); +} + +xbox::dword_xt WINAPI xbox::EMUPATCH(XLaunchNewImageA) +( + LPCSTR lpTitlePath, + PLAUNCH_DATA pLaunchData +) +{ + // Note : This can be tested using "Innocent tears", + // which relaunches different xbes between scenes; + // One for menus, one for fmvs, etc. + // + // Other titles do this too (like "DOA2 Ultimate", + // and probably "Panzer Dragoon Orta"), but these + // titles don't come this far as-of yet. + + LOG_FUNC_BEGIN + LOG_FUNC_ARG(lpTitlePath) + LOG_FUNC_ARG(pLaunchData) + LOG_FUNC_END; + + // TODO : This patch can be removed once NtOpenSymbolicLinkObject() + // and NtQuerySymbolicLinkObject() work together correctly. + // Also, XLaunchNewImageA() depends on XeImageHeader() and uses + // XWriteTitleInfoAndReboot() and indirectly XWriteTitleInfoNoReboot() + + // Update the kernel's LaunchDataPage : + { + if (xbox::LaunchDataPage == xbox::zeroptr) + { + PVOID LaunchDataVAddr = xbox::MmAllocateContiguousMemory(sizeof(xbox::LAUNCH_DATA_PAGE)); + if (!LaunchDataVAddr) + { + RETURN(X_STATUS_NO_MEMORY); + } + xbox::LaunchDataPage = (xbox::LAUNCH_DATA_PAGE*)LaunchDataVAddr; + } + + xbox::LaunchDataPage->Header.dwTitleId = g_pCertificate->dwTitleId; + xbox::LaunchDataPage->Header.dwFlags = 0; // TODO : What to put in here? + xbox::LaunchDataPage->Header.dwLaunchDataType = LDT_TITLE; + + xbox::MmPersistContiguousMemory((PVOID)xbox::LaunchDataPage, PAGE_SIZE, TRUE); + + if (pLaunchData != xbox::zeroptr) + // Save the launch data + memcpy(&(xbox::LaunchDataPage->LaunchData[0]), pLaunchData, sizeof(LAUNCH_DATA)); + + if (lpTitlePath == xbox::zeroptr) + { + // If no path is specified, then the xbe is rebooting to dashboard + char szDashboardPath[xbox::max_path] = { 0 }; + XboxDevice* rootDevice = CxbxDeviceByDevicePath(DeviceHarddisk0Partition2); + if (rootDevice != nullptr) + sprintf(szDashboardPath, "%s\\xboxdash.xbe", rootDevice->HostDevicePath.c_str()); + + if (PathFileExists(szDashboardPath)) + { + PopupInfo(nullptr, "The title is rebooting to dashboard"); + lpTitlePath = "C:\\xboxdash.xbe"; + xbox::LaunchDataPage->Header.dwLaunchDataType = LDT_FROM_DASHBOARD; + // Other options include LDT_NONE, LDT_FROM_DEBUGGER_CMDLINE and LDT_FROM_UPDATE + } + else + CxbxrKrnlAbort("The xbe rebooted to Dashboard and xboxdash.xbe could not be found"); + } + + strncpy(&(xbox::LaunchDataPage->Header.szLaunchPath[0]), lpTitlePath, 520); + } + + // Note : While this patch exists, HalReturnToFirmware() calls + // MmPersistContiguousMemory on LaunchDataPage. When this + // patch on XLaunchNewImageA is removed, remove the call to + // MmPersistContiguousMemory from HalReturnToFirmware() too!! + + xbox::HalReturnToFirmware(xbox::ReturnFirmwareQuickReboot); + + // If this function succeeds, it doesn't get a chance to return anything. + RETURN(ERROR_GEN_FAILURE); +} + +xbox::dword_xt WINAPI xbox::EMUPATCH(XGetLaunchInfo) +( + PDWORD pdwLaunchDataType, + PLAUNCH_DATA pLaunchData +) +{ + + + // TODO : This patch can be removed once we're sure all XAPI library + // functions indirectly reference our xbox::LaunchDataPage variable. + // For this, we need a test-case that hits this function, and run that + // with and without this patch enabled. Behavior should be identical. + // When this is verified, this patch can be removed. + LOG_TEST_CASE("Unpatching test needed"); + + LOG_FUNC_BEGIN + LOG_FUNC_ARG(pdwLaunchDataType) + LOG_FUNC_ARG(pLaunchData) + LOG_FUNC_END; + + dword_xt ret = ERROR_NOT_FOUND; + + if (xbox::LaunchDataPage != NULL) + { + // Note : Here, CxbxRestoreLaunchDataPage() was already called, + // which has loaded LaunchDataPage from a binary file (if present). + + // A title can pass data only to itself, not another title (unless started from the dashboard, of course) : + if ( (xbox::LaunchDataPage->Header.dwTitleId == g_pCertificate->dwTitleId) + || (xbox::LaunchDataPage->Header.dwLaunchDataType == LDT_FROM_DASHBOARD) + || (xbox::LaunchDataPage->Header.dwLaunchDataType == LDT_FROM_DEBUGGER_CMDLINE)) + { + *pdwLaunchDataType = xbox::LaunchDataPage->Header.dwLaunchDataType; + memcpy(pLaunchData, &(xbox::LaunchDataPage->LaunchData[0]), sizeof(LAUNCH_DATA)); + + // Now that LaunchDataPage is retrieved by the emulated software, free it : + MmFreeContiguousMemory(xbox::LaunchDataPage); + xbox::LaunchDataPage = NULL; + + ret = ERROR_SUCCESS; + } + } + + RETURN(ret); +} + +xbox::void_xt WINAPI xbox::EMUPATCH(XSetProcessQuantumLength) +( + dword_xt dwMilliseconds +) +{ + + LOG_FUNC_ONE_ARG(dwMilliseconds); + + // TODO: Implement? + LOG_IGNORED(); +} diff --git a/src/core/kernel/common/ps.h b/src/core/kernel/common/ps.h index 564f96e54..0e4ce266c 100644 --- a/src/core/kernel/common/ps.h +++ b/src/core/kernel/common/ps.h @@ -14,6 +14,8 @@ #include "types.h" +#define X_THREAD_QUANTUM 60 + namespace xbox { // ****************************************************************** diff --git a/src/core/kernel/exports/EmuKrnl.cpp b/src/core/kernel/exports/EmuKrnl.cpp index 73007fe24..2cc6fafdc 100644 --- a/src/core/kernel/exports/EmuKrnl.cpp +++ b/src/core/kernel/exports/EmuKrnl.cpp @@ -210,13 +210,13 @@ const DWORD IrqlMasks[] = { 0x00000000, // IRQL 31 (HIGH_LEVEL) }; -// This helper function is used to signal NtDll waiting functions that the wait has been satisfied by an xbox user APC +// This helper function is used to signal WinApi waiting functions that the wait has been satisfied by an xbox user APC static void WINAPI EndWait(ULONG_PTR Parameter) { // Do nothing } -std::future WaitUserApc(xbox::boolean_xt Alertable, xbox::char_xt WaitMode, bool *Exit) +std::future WaitApc(xbox::boolean_xt Alertable, xbox::char_xt WaitMode, bool *Exit) { // NOTE: kThread->Alerted is currently never set. When the alerted mechanism is implemented, the alerts should // also interrupt the wait @@ -240,7 +240,7 @@ std::future WaitUserApc(xbox::boolean_xt Alertable, xbox::char_xt WaitMode (Alertable == TRUE) && (WaitMode == xbox::UserMode)) { xbox::KiExecuteUserApc(); - // Queue a native APC to the calling thread to forcefully terminate the wait of the NtDll functions, + // 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); diff --git a/src/core/kernel/exports/EmuKrnl.h b/src/core/kernel/exports/EmuKrnl.h index 6fcd98c63..3e83d5330 100644 --- a/src/core/kernel/exports/EmuKrnl.h +++ b/src/core/kernel/exports/EmuKrnl.h @@ -104,6 +104,6 @@ extern HalSystemInterrupt HalSystemInterrupts[MAX_BUS_INTERRUPT_LEVEL + 1]; bool DisableInterrupts(); void RestoreInterruptMode(bool value); void CallSoftwareInterrupt(const xbox::KIRQL SoftwareIrql); -std::future WaitUserApc(xbox::boolean_xt Alertable, xbox::char_xt WaitMode, bool *Exit); +std::future WaitApc(xbox::boolean_xt Alertable, xbox::char_xt WaitMode, bool *Exit); #endif diff --git a/src/core/kernel/exports/EmuKrnlKe.cpp b/src/core/kernel/exports/EmuKrnlKe.cpp index 9d3f22384..5edf67c9f 100644 --- a/src/core/kernel/exports/EmuKrnlKe.cpp +++ b/src/core/kernel/exports/EmuKrnlKe.cpp @@ -140,12 +140,10 @@ xbox::KPCR* WINAPI EmuKeGetPcr() // See EmuKeSetPcr() Pcr = (xbox::PKPCR)__readfsdword(TIB_ArbitraryDataSlot); - - if (Pcr == nullptr) { - // If we reach here, it's a bug: it means we are executing xbox code from a host thread, and we have forgotten to initialize - // the xbox thread first - CxbxrKrnlAbort("KeGetPCR returned nullptr: Was this called from a non-xbox thread?"); - } + + // If this fails, it's a bug: it means we are executing xbox code from a host thread, and we have forgotten to initialize + // the xbox thread first + assert(Pcr); return Pcr; } @@ -571,7 +569,7 @@ 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 = WaitUserApc(Alertable, WaitMode, &Exit); + auto fut = WaitApc(Alertable, WaitMode, &Exit); NTSTATUS ret = NtDll::NtDelayExecution(Alertable, (NtDll::LARGE_INTEGER *)Interval); @@ -1657,17 +1655,8 @@ XBSYSAPI EXPORTNUM(143) xbox::long_xt NTAPI xbox::KeSetBasePriorityThread // This would work normally, but it will slow down the emulation, // don't do that if the priority is higher then normal (so our own)! - if(Priority <= THREAD_PRIORITY_NORMAL) { - HANDLE nhandle; - // Verify if the thread is the same as current thread. - // Then use special handle to correct the problem for Windows' call usage. - if (Thread == KeGetCurrentPrcb()->CurrentThread) { - nhandle = NtCurrentThread(); - } - else { - nhandle = *nativeHandle; - } - BOOL result = SetThreadPriority(nhandle, Priority); + if (Priority <= THREAD_PRIORITY_NORMAL) { + BOOL result = SetThreadPriority(*nativeHandle, Priority); if (!result) { EmuLog(LOG_LEVEL::WARNING, "SetThreadPriority failed: %s", WinError2Str().c_str()); } @@ -2221,7 +2210,7 @@ XBSYSAPI EXPORTNUM(158) xbox::ntstatus_xt NTAPI xbox::KeWaitForMultipleObjects //WaitStatus = (NTSTATUS)KiSwapThread(); //if (WaitStatus == X_STATUS_USER_APC) { - // TODO: KiDeliverUserApc(); + // KiExecuteUserApc(); //} // If the thread was not awakened for an APC, return the Wait Status @@ -2252,7 +2241,7 @@ XBSYSAPI EXPORTNUM(158) xbox::ntstatus_xt NTAPI xbox::KeWaitForMultipleObjects // So unlock the dispatcher database, lower the IRQ and return the status KiUnlockDispatcherDatabase(Thread->WaitIrql); if (WaitStatus == X_STATUS_USER_APC) { - //TODO: KiDeliverUserApc(); + KiExecuteUserApc(); } RETURN(WaitStatus); @@ -2426,7 +2415,7 @@ XBSYSAPI EXPORTNUM(159) xbox::ntstatus_xt NTAPI xbox::KeWaitForSingleObject WaitStatus = (NTSTATUS)KiSwapThread(); if (WaitStatus == X_STATUS_USER_APC) { - // TODO: KiDeliverUserApc(); + KiExecuteUserApc(); } // If the thread was not awakened for an APC, return the Wait Status @@ -2478,7 +2467,7 @@ NoWait: KiUnlockDispatcherDatabase(Thread->WaitIrql); if (WaitStatus == X_STATUS_USER_APC) { - // TODO: KiDeliverUserApc(); + KiExecuteUserApc(); } RETURN(WaitStatus); diff --git a/src/core/kernel/exports/EmuKrnlKi.cpp b/src/core/kernel/exports/EmuKrnlKi.cpp index 30dac5a41..f06976f2d 100644 --- a/src/core/kernel/exports/EmuKrnlKi.cpp +++ b/src/core/kernel/exports/EmuKrnlKi.cpp @@ -101,6 +101,7 @@ std::mutex xbox::KiApcListMtx; xbox::void_xt xbox::KiInitSystem() { KiUniqueProcess.StackCount = 0; + KiUniqueProcess.ThreadQuantum = X_THREAD_QUANTUM; InitializeListHead(&KiWaitInListHead); diff --git a/src/core/kernel/exports/EmuKrnlNt.cpp b/src/core/kernel/exports/EmuKrnlNt.cpp index d91ceefb1..e0718f9a5 100644 --- a/src/core/kernel/exports/EmuKrnlNt.cpp +++ b/src/core/kernel/exports/EmuKrnlNt.cpp @@ -2199,7 +2199,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 = WaitUserApc(Alertable, WaitMode, &Exit); + auto fut = WaitApc(Alertable, WaitMode, &Exit); NTSTATUS ret = NtDll::NtWaitForMultipleObjects( Count, diff --git a/src/core/kernel/exports/EmuKrnlPs.cpp b/src/core/kernel/exports/EmuKrnlPs.cpp index f4c69f332..e9a00c814 100644 --- a/src/core/kernel/exports/EmuKrnlPs.cpp +++ b/src/core/kernel/exports/EmuKrnlPs.cpp @@ -313,8 +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], Native ThreadId : [0x%.4X]", - *ThreadHandle, eThread->UniqueThread, ThreadId); + EmuLog(LOG_LEVEL::DEBUG, "Created Xbox proxy thread. Handle : 0x%X, ThreadId : [0x%.4X], Native Handle : 0x%X, Native ThreadId : [0x%.4X]", + *ThreadHandle, eThread->UniqueThread, handle, ThreadId); } RETURN(X_STATUS_SUCCESS); diff --git a/src/core/kernel/support/EmuFS.cpp b/src/core/kernel/support/EmuFS.cpp index 9b2664c1d..d4223feba 100644 --- a/src/core/kernel/support/EmuFS.cpp +++ b/src/core/kernel/support/EmuFS.cpp @@ -31,6 +31,7 @@ #include #include "core\kernel\exports\EmuKrnl.h" // For InitializeListHead(), etc. #include "core\kernel\exports\EmuKrnlKe.h" +#include "core\kernel\exports\EmuKrnlKi.h" #include "core\kernel\support\EmuFS.h" // For fs_instruction_t #include "core\kernel\support\NativeHandle.h" #include "core\kernel\init\CxbxKrnl.h" @@ -819,6 +820,8 @@ void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData, xbox::PVOID Ethread) 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); diff --git a/src/core/kernel/support/NativeHandle.cpp b/src/core/kernel/support/NativeHandle.cpp index 459e6cdfe..4b24e3bff 100644 --- a/src/core/kernel/support/NativeHandle.cpp +++ b/src/core/kernel/support/NativeHandle.cpp @@ -83,5 +83,6 @@ std::optional GetNativeHandle(xbox::HANDLE xhandle) return it->second; } } + template std::optional GetNativeHandle(xbox::HANDLE xhandle); template std::optional GetNativeHandle(xbox::HANDLE xhandle);