Unpatch XSetProcessQuantumLength + moved unused xapi patched to standalone file + added code to handle xbox user APCs in SignalObjectAndWait

This commit is contained in:
ergo720 2022-01-18 19:41:05 +01:00
parent e208c73586
commit e9cc351bba
12 changed files with 390 additions and 436 deletions

View File

@ -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),

View File

@ -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);
}

View File

@ -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();
}

View File

@ -14,6 +14,8 @@
#include "types.h"
#define X_THREAD_QUANTUM 60
namespace xbox
{
// ******************************************************************

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -101,6 +101,7 @@ std::mutex xbox::KiApcListMtx;
xbox::void_xt xbox::KiInitSystem()
{
KiUniqueProcess.StackCount = 0;
KiUniqueProcess.ThreadQuantum = X_THREAD_QUANTUM;
InitializeListHead(&KiWaitInListHead);

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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);