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("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),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
||||
#define X_THREAD_QUANTUM 60
|
||||
|
||||
namespace xbox
|
||||
{
|
||||
// ******************************************************************
|
||||
|
|
|
@ -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<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
|
||||
// also interrupt the wait
|
||||
|
@ -240,7 +240,7 @@ std::future<bool> 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);
|
||||
|
|
|
@ -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<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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -101,6 +101,7 @@ std::mutex xbox::KiApcListMtx;
|
|||
xbox::void_xt xbox::KiInitSystem()
|
||||
{
|
||||
KiUniqueProcess.StackCount = 0;
|
||||
KiUniqueProcess.ThreadQuantum = X_THREAD_QUANTUM;
|
||||
|
||||
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
|
||||
bool Exit = false;
|
||||
auto &fut = WaitUserApc(Alertable, WaitMode, &Exit);
|
||||
auto fut = WaitApc(Alertable, WaitMode, &Exit);
|
||||
|
||||
NTSTATUS ret = NtDll::NtWaitForMultipleObjects(
|
||||
Count,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <core\kernel\exports\xboxkrnl.h>
|
||||
#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);
|
||||
|
|
|
@ -83,5 +83,6 @@ std::optional<HANDLE> GetNativeHandle(xbox::HANDLE xhandle)
|
|||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
template std::optional<HANDLE> GetNativeHandle<true>(xbox::HANDLE xhandle);
|
||||
template std::optional<HANDLE> GetNativeHandle<false>(xbox::HANDLE xhandle);
|
||||
|
|
Loading…
Reference in New Issue