Unpatch XSetProcessQuantumLength + moved unused xapi patched to standalone file + added code to handle xbox user APCs in SignalObjectAndWait
This commit is contained in:
parent
e208c73586
commit
e9cc351bba
|
@ -364,7 +364,7 @@ std::map<const std::string, const xbox_patch_t> g_PatchTable = {
|
||||||
PATCH_ENTRY("SwitchToFiber", xbox::EMUPATCH(SwitchToFiber), PATCH_IS_FIBER),
|
PATCH_ENTRY("SwitchToFiber", xbox::EMUPATCH(SwitchToFiber), PATCH_IS_FIBER),
|
||||||
PATCH_ENTRY("XMountMUA", xbox::EMUPATCH(XMountMUA), PATCH_ALWAYS),
|
PATCH_ENTRY("XMountMUA", xbox::EMUPATCH(XMountMUA), PATCH_ALWAYS),
|
||||||
PATCH_ENTRY("XMountMURootA", xbox::EMUPATCH(XMountMURootA), 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("timeKillEvent", xbox::EMUPATCH(timeKillEvent), PATCH_ALWAYS),
|
||||||
PATCH_ENTRY("timeSetEvent", xbox::EMUPATCH(timeSetEvent), PATCH_ALWAYS),
|
PATCH_ENTRY("timeSetEvent", xbox::EMUPATCH(timeSetEvent), PATCH_ALWAYS),
|
||||||
PATCH_ENTRY("XReadMUMetaData", xbox::EMUPATCH(XReadMUMetaData), PATCH_ALWAYS),
|
PATCH_ENTRY("XReadMUMetaData", xbox::EMUPATCH(XReadMUMetaData), PATCH_ALWAYS),
|
||||||
|
|
|
@ -896,200 +896,6 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XInputSetLightgunCalibration)
|
||||||
RETURN(ret);
|
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 {
|
typedef struct {
|
||||||
LPFIBER_START_ROUTINE lpStartRoutine;
|
LPFIBER_START_ROUTINE lpStartRoutine;
|
||||||
LPVOID lpParameter;
|
LPVOID lpParameter;
|
||||||
|
@ -1172,216 +978,6 @@ xbox::LPVOID WINAPI xbox::EMUPATCH(ConvertThreadToFiber)
|
||||||
|
|
||||||
RETURN(pRet);
|
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
|
// * patch: SignalObjectAndWait
|
||||||
|
@ -1394,7 +990,6 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(SignalObjectAndWait)
|
||||||
bool_xt bAlertable
|
bool_xt bAlertable
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
LOG_FUNC_BEGIN
|
LOG_FUNC_BEGIN
|
||||||
LOG_FUNC_ARG(hObjectToSignal)
|
LOG_FUNC_ARG(hObjectToSignal)
|
||||||
LOG_FUNC_ARG(hObjectToWaitOn)
|
LOG_FUNC_ARG(hObjectToWaitOn)
|
||||||
|
@ -1402,7 +997,15 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(SignalObjectAndWait)
|
||||||
LOG_FUNC_ARG(bAlertable)
|
LOG_FUNC_ARG(bAlertable)
|
||||||
LOG_FUNC_END;
|
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);
|
RETURN(dwRet);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
|
@ -14,6 +14,8 @@
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
#define X_THREAD_QUANTUM 60
|
||||||
|
|
||||||
namespace xbox
|
namespace xbox
|
||||||
{
|
{
|
||||||
// ******************************************************************
|
// ******************************************************************
|
||||||
|
|
|
@ -210,13 +210,13 @@ const DWORD IrqlMasks[] = {
|
||||||
0x00000000, // IRQL 31 (HIGH_LEVEL)
|
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)
|
static void WINAPI EndWait(ULONG_PTR Parameter)
|
||||||
{
|
{
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
std::future<bool> WaitUserApc(xbox::boolean_xt Alertable, xbox::char_xt WaitMode, bool *Exit)
|
std::future<bool> 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
|
// NOTE: kThread->Alerted is currently never set. When the alerted mechanism is implemented, the alerts should
|
||||||
// also interrupt the wait
|
// also interrupt the wait
|
||||||
|
@ -240,7 +240,7 @@ std::future<bool> WaitUserApc(xbox::boolean_xt Alertable, xbox::char_xt WaitMode
|
||||||
(Alertable == TRUE) &&
|
(Alertable == TRUE) &&
|
||||||
(WaitMode == xbox::UserMode)) {
|
(WaitMode == xbox::UserMode)) {
|
||||||
xbox::KiExecuteUserApc();
|
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
|
// in the case it didn't terminate already
|
||||||
HANDLE nativeHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, Id);
|
HANDLE nativeHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, Id);
|
||||||
assert(nativeHandle);
|
assert(nativeHandle);
|
||||||
|
|
|
@ -104,6 +104,6 @@ extern HalSystemInterrupt HalSystemInterrupts[MAX_BUS_INTERRUPT_LEVEL + 1];
|
||||||
bool DisableInterrupts();
|
bool DisableInterrupts();
|
||||||
void RestoreInterruptMode(bool value);
|
void RestoreInterruptMode(bool value);
|
||||||
void CallSoftwareInterrupt(const xbox::KIRQL SoftwareIrql);
|
void CallSoftwareInterrupt(const xbox::KIRQL SoftwareIrql);
|
||||||
std::future<bool> WaitUserApc(xbox::boolean_xt Alertable, xbox::char_xt WaitMode, bool *Exit);
|
std::future<bool> WaitApc(xbox::boolean_xt Alertable, xbox::char_xt WaitMode, bool *Exit);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -140,12 +140,10 @@ xbox::KPCR* WINAPI EmuKeGetPcr()
|
||||||
|
|
||||||
// See EmuKeSetPcr()
|
// See EmuKeSetPcr()
|
||||||
Pcr = (xbox::PKPCR)__readfsdword(TIB_ArbitraryDataSlot);
|
Pcr = (xbox::PKPCR)__readfsdword(TIB_ArbitraryDataSlot);
|
||||||
|
|
||||||
if (Pcr == nullptr) {
|
// If this fails, it's a bug: it means we are executing xbox code from a host thread, and we have forgotten to initialize
|
||||||
// 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
|
||||||
// the xbox thread first
|
assert(Pcr);
|
||||||
CxbxrKrnlAbort("KeGetPCR returned nullptr: Was this called from a non-xbox thread?");
|
|
||||||
}
|
|
||||||
|
|
||||||
return 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
|
// We can't remove NtDll::NtDelayExecution until all APCs queued by Io are implemented by our kernel as well
|
||||||
// Test case: Metal Slug 3
|
// Test case: Metal Slug 3
|
||||||
bool Exit = false;
|
bool Exit = false;
|
||||||
auto &fut = WaitUserApc(Alertable, WaitMode, &Exit);
|
auto fut = WaitApc(Alertable, WaitMode, &Exit);
|
||||||
|
|
||||||
NTSTATUS ret = NtDll::NtDelayExecution(Alertable, (NtDll::LARGE_INTEGER *)Interval);
|
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,
|
// 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)!
|
// don't do that if the priority is higher then normal (so our own)!
|
||||||
if(Priority <= THREAD_PRIORITY_NORMAL) {
|
if (Priority <= THREAD_PRIORITY_NORMAL) {
|
||||||
HANDLE nhandle;
|
BOOL result = SetThreadPriority(*nativeHandle, Priority);
|
||||||
// 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 (!result) {
|
if (!result) {
|
||||||
EmuLog(LOG_LEVEL::WARNING, "SetThreadPriority failed: %s", WinError2Str().c_str());
|
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();
|
//WaitStatus = (NTSTATUS)KiSwapThread();
|
||||||
|
|
||||||
//if (WaitStatus == X_STATUS_USER_APC) {
|
//if (WaitStatus == X_STATUS_USER_APC) {
|
||||||
// TODO: KiDeliverUserApc();
|
// KiExecuteUserApc();
|
||||||
//}
|
//}
|
||||||
|
|
||||||
// If the thread was not awakened for an APC, return the Wait Status
|
// 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
|
// So unlock the dispatcher database, lower the IRQ and return the status
|
||||||
KiUnlockDispatcherDatabase(Thread->WaitIrql);
|
KiUnlockDispatcherDatabase(Thread->WaitIrql);
|
||||||
if (WaitStatus == X_STATUS_USER_APC) {
|
if (WaitStatus == X_STATUS_USER_APC) {
|
||||||
//TODO: KiDeliverUserApc();
|
KiExecuteUserApc();
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN(WaitStatus);
|
RETURN(WaitStatus);
|
||||||
|
@ -2426,7 +2415,7 @@ XBSYSAPI EXPORTNUM(159) xbox::ntstatus_xt NTAPI xbox::KeWaitForSingleObject
|
||||||
WaitStatus = (NTSTATUS)KiSwapThread();
|
WaitStatus = (NTSTATUS)KiSwapThread();
|
||||||
|
|
||||||
if (WaitStatus == X_STATUS_USER_APC) {
|
if (WaitStatus == X_STATUS_USER_APC) {
|
||||||
// TODO: KiDeliverUserApc();
|
KiExecuteUserApc();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the thread was not awakened for an APC, return the Wait Status
|
// If the thread was not awakened for an APC, return the Wait Status
|
||||||
|
@ -2478,7 +2467,7 @@ NoWait:
|
||||||
KiUnlockDispatcherDatabase(Thread->WaitIrql);
|
KiUnlockDispatcherDatabase(Thread->WaitIrql);
|
||||||
|
|
||||||
if (WaitStatus == X_STATUS_USER_APC) {
|
if (WaitStatus == X_STATUS_USER_APC) {
|
||||||
// TODO: KiDeliverUserApc();
|
KiExecuteUserApc();
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN(WaitStatus);
|
RETURN(WaitStatus);
|
||||||
|
|
|
@ -101,6 +101,7 @@ std::mutex xbox::KiApcListMtx;
|
||||||
xbox::void_xt xbox::KiInitSystem()
|
xbox::void_xt xbox::KiInitSystem()
|
||||||
{
|
{
|
||||||
KiUniqueProcess.StackCount = 0;
|
KiUniqueProcess.StackCount = 0;
|
||||||
|
KiUniqueProcess.ThreadQuantum = X_THREAD_QUANTUM;
|
||||||
|
|
||||||
InitializeListHead(&KiWaitInListHead);
|
InitializeListHead(&KiWaitInListHead);
|
||||||
|
|
||||||
|
|
|
@ -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
|
// Because user APCs from NtQueueApcThread are now handled by the kernel, we need to wait for them ourselves
|
||||||
bool Exit = false;
|
bool Exit = false;
|
||||||
auto &fut = WaitUserApc(Alertable, WaitMode, &Exit);
|
auto fut = WaitApc(Alertable, WaitMode, &Exit);
|
||||||
|
|
||||||
NTSTATUS ret = NtDll::NtWaitForMultipleObjects(
|
NTSTATUS ret = NtDll::NtWaitForMultipleObjects(
|
||||||
Count,
|
Count,
|
||||||
|
|
|
@ -313,8 +313,8 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log ThreadID identical to how GetCurrentThreadID() is rendered :
|
// 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]",
|
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, ThreadId);
|
*ThreadHandle, eThread->UniqueThread, handle, ThreadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN(X_STATUS_SUCCESS);
|
RETURN(X_STATUS_SUCCESS);
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <core\kernel\exports\xboxkrnl.h>
|
#include <core\kernel\exports\xboxkrnl.h>
|
||||||
#include "core\kernel\exports\EmuKrnl.h" // For InitializeListHead(), etc.
|
#include "core\kernel\exports\EmuKrnl.h" // For InitializeListHead(), etc.
|
||||||
#include "core\kernel\exports\EmuKrnlKe.h"
|
#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\EmuFS.h" // For fs_instruction_t
|
||||||
#include "core\kernel\support\NativeHandle.h"
|
#include "core\kernel\support\NativeHandle.h"
|
||||||
#include "core\kernel\init\CxbxKrnl.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]);
|
InitializeListHead(&Prcb->CurrentThread->ApcState.ApcListHead[xbox::UserMode]);
|
||||||
Prcb->CurrentThread->KernelApcDisable = 0;
|
Prcb->CurrentThread->KernelApcDisable = 0;
|
||||||
Prcb->CurrentThread->ApcState.ApcQueueable = TRUE;
|
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
|
// Initialize the thread header and its wait list
|
||||||
Prcb->CurrentThread->Header.Type = xbox::ThreadObject;
|
Prcb->CurrentThread->Header.Type = xbox::ThreadObject;
|
||||||
Prcb->CurrentThread->Header.Size = sizeof(xbox::KTHREAD) / sizeof(xbox::long_xt);
|
Prcb->CurrentThread->Header.Size = sizeof(xbox::KTHREAD) / sizeof(xbox::long_xt);
|
||||||
|
|
|
@ -83,5 +83,6 @@ std::optional<HANDLE> GetNativeHandle(xbox::HANDLE xhandle)
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template std::optional<HANDLE> GetNativeHandle<true>(xbox::HANDLE xhandle);
|
template std::optional<HANDLE> GetNativeHandle<true>(xbox::HANDLE xhandle);
|
||||||
template std::optional<HANDLE> GetNativeHandle<false>(xbox::HANDLE xhandle);
|
template std::optional<HANDLE> GetNativeHandle<false>(xbox::HANDLE xhandle);
|
||||||
|
|
Loading…
Reference in New Issue