Merge pull request #1612 from LukeUsher/selectively-unpatch-fiber

Selectively unpatch Fiber functions, fixes Futurama
This commit is contained in:
Luke Usher 2019-05-14 21:23:54 +01:00 committed by GitHub
commit 2515d0a2cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 6 deletions

View File

@ -45,6 +45,7 @@ const uint32_t PATCH_ALWAYS = 1 << 0;
const uint32_t PATCH_HLE_D3D = 1 << 1;
const uint32_t PATCH_HLE_DSOUND = 1 << 2;
const uint32_t PATCH_HLE_OHCI = 1 << 3;
const uint32_t PATCH_IS_FIBER = 1 << 4;
#define PATCH_ENTRY(Name, Func, Flags) \
{ Name, { &Func, Flags} }
@ -369,9 +370,9 @@ std::map<const std::string, const xbox_patch_t> g_PatchTable = {
PATCH_ENTRY("XInputSetState", XTL::EMUPATCH(XInputSetState), PATCH_HLE_OHCI),
// XAPI
PATCH_ENTRY("ConvertThreadToFiber", XTL::EMUPATCH(ConvertThreadToFiber), PATCH_ALWAYS),
PATCH_ENTRY("CreateFiber", XTL::EMUPATCH(CreateFiber), PATCH_ALWAYS),
PATCH_ENTRY("DeleteFiber", XTL::EMUPATCH(DeleteFiber), PATCH_ALWAYS),
PATCH_ENTRY("ConvertThreadToFiber", XTL::EMUPATCH(ConvertThreadToFiber), PATCH_IS_FIBER),
PATCH_ENTRY("CreateFiber", XTL::EMUPATCH(CreateFiber), PATCH_IS_FIBER),
PATCH_ENTRY("DeleteFiber", XTL::EMUPATCH(DeleteFiber), PATCH_IS_FIBER),
PATCH_ENTRY("GetExitCodeThread", XTL::EMUPATCH(GetExitCodeThread), PATCH_ALWAYS),
PATCH_ENTRY("GetThreadPriority", XTL::EMUPATCH(GetThreadPriority), PATCH_ALWAYS),
PATCH_ENTRY("OutputDebugStringA", XTL::EMUPATCH(OutputDebugStringA), PATCH_ALWAYS),
@ -379,7 +380,7 @@ std::map<const std::string, const xbox_patch_t> g_PatchTable = {
PATCH_ENTRY("SetThreadPriority", XTL::EMUPATCH(SetThreadPriority), PATCH_ALWAYS),
PATCH_ENTRY("SetThreadPriorityBoost", XTL::EMUPATCH(SetThreadPriorityBoost), PATCH_ALWAYS),
PATCH_ENTRY("SignalObjectAndWait", XTL::EMUPATCH(SignalObjectAndWait), PATCH_ALWAYS),
PATCH_ENTRY("SwitchToFiber", XTL::EMUPATCH(SwitchToFiber), PATCH_ALWAYS),
PATCH_ENTRY("SwitchToFiber", XTL::EMUPATCH(SwitchToFiber), PATCH_IS_FIBER),
PATCH_ENTRY("XMountMUA", XTL::EMUPATCH(XMountMUA), PATCH_ALWAYS),
PATCH_ENTRY("XMountMURootA", XTL::EMUPATCH(XMountMURootA), PATCH_ALWAYS),
PATCH_ENTRY("XSetProcessQuantumLength", XTL::EMUPATCH(XSetProcessQuantumLength), PATCH_ALWAYS),
@ -389,6 +390,38 @@ std::map<const std::string, const xbox_patch_t> g_PatchTable = {
std::unordered_map<std::string, subhook::Hook> g_FunctionHooks;
inline bool TitleRequiresUnpatchedFibers()
{
static bool detected = false;
static bool result = false;
// Prevent running the check every time this function is called
if (detected) {
return result;
}
// Array of known games that require the fiber unpatch hack
DWORD titleIds[] = {
0x46490002, // Futurama PAL
0x56550008, // Futurama NTSC
0
};
DWORD* pTitleId = &titleIds[0];
while (*pTitleId != 0) {
if (g_pCertificate->dwTitleId == *pTitleId) {
result = true;
break;
}
pTitleId++;
}
detected = true;
return result;
}
// NOTE: EmuInstallPatch do not get to be in XbSymbolDatabase, do the patches in Cxbx project only.
inline void EmuInstallPatch(std::string FunctionName, xbaddr FunctionAddr)
{
@ -413,6 +446,14 @@ inline void EmuInstallPatch(std::string FunctionName, xbaddr FunctionAddr)
printf("HLE: %s: Skipped (LLE OHCI Enabled)\n", FunctionName.c_str());
return;
}
// HACK: Some titles require unpatched Fibers, otherwise they enter an infinte loop
// while others require patched Fibers, otherwise they outright crash
// This is caused by limitations of Direct Code Execution and Cxbx-R's threading model
if ((patch.flags & PATCH_IS_FIBER) && TitleRequiresUnpatchedFibers()) {
printf("HLE: %s: Skipped (Game requires unpatched Fibers)\n", FunctionName.c_str());
return;
}
g_FunctionHooks[FunctionName].Install((void*)(FunctionAddr), (void*)patch.patchFunc);
printf("HLE: %s Patched\n", FunctionName.c_str());

View File

@ -167,6 +167,10 @@ XBSYSAPI EXPORTNUM(169) xboxkrnl::PVOID NTAPI xboxkrnl::MmCreateKernelStack
PVOID addr = (PVOID)g_VMManager.AllocateSystemMemory(DebuggerThread ? DebuggerType : StackType,
XBOX_PAGE_READWRITE, NumberOfBytes, true);
// Since this is creating a stack (which counts DOWN) we must return the *end* of the address range, not the start
// Test cases: DOA3, Futurama
addr = (PVOID)((uint32_t)addr + NumberOfBytes + PAGE_SIZE);
RETURN(addr);
}
@ -184,8 +188,10 @@ XBSYSAPI EXPORTNUM(170) xboxkrnl::VOID NTAPI xboxkrnl::MmDeleteKernelStack
LOG_FUNC_ARG(StackLimit)
LOG_FUNC_END;
ULONG actualStackSize = ((VAddr)StackBase - (VAddr)StackLimit) + PAGE_SIZE;
g_VMManager.DeallocateSystemMemory(IS_SYSTEM_ADDRESS(StackBase) ? StackType : DebuggerType,
(VAddr)StackBase, (VAddr)StackBase - (VAddr)StackLimit + PAGE_SIZE);
(VAddr)StackBase - (VAddr)actualStackSize, actualStackSize);
}
// ******************************************************************

View File

@ -627,7 +627,12 @@ void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData)
// Fixup the TIB self pointer :
NewPcr->NtTib.Self = XbTib;
// Set the stack base - TODO : Verify this, doesn't look right?
NewPcr->NtTib.StackBase = pNewTLS;
NewPcr->NtTib.StackBase = pNewTLS;
// Write the Xbox stack base to the Host, allows ConvertThreadToFiber to work correctly
// Test case: DOA3
__writefsdword(TIB_StackBase, (DWORD)NewPcr->NtTib.StackBase);
__writefsdword(TIB_StackLimit, (DWORD)NewPcr->NtTib.StackLimit);
}
// Set flat address of this PCR