Preserve original IO status block and context for ApcRoutine

Fixes cases where guest's APC routine/completion callback
does not receive the original IO status block variable,
but it assumed it did (it's allowed as per WinAPI docs).

Fixes Project Gotham Racing deadlocking after intro movies
This commit is contained in:
Silent 2020-11-05 21:06:29 +01:00
parent 8415397067
commit 0411f27c65
No known key found for this signature in database
GPG Key ID: AE53149BB0C45AF1
3 changed files with 37 additions and 4 deletions

View File

@ -1648,10 +1648,17 @@ XBSYSAPI EXPORTNUM(219) xbox::ntstatus_xt NTAPI xbox::NtReadFile
CxbxDebugger::ReportFileRead(FileHandle, Length, Offset); CxbxDebugger::ReportFileRead(FileHandle, Length, Offset);
} }
if (ApcRoutine != nullptr) {
// Pack the original parameters to a wrapped context for a custom APC routine
CxbxIoDispatcherContext* cxbxContext = new CxbxIoDispatcherContext(IoStatusBlock, ApcRoutine, ApcContext);
ApcRoutine = CxbxIoApcDispatcher;
ApcContext = cxbxContext;
}
NTSTATUS ret = NtDll::NtReadFile( NTSTATUS ret = NtDll::NtReadFile(
FileHandle, FileHandle,
Event, Event,
(PVOID)ApcRoutine, ApcRoutine,
ApcContext, ApcContext,
IoStatusBlock, IoStatusBlock,
Buffer, Buffer,
@ -2043,8 +2050,8 @@ XBSYSAPI EXPORTNUM(232) xbox::void_xt NTAPI xbox::NtUserIoApcDispatcher
dwErrorCode = RtlNtStatusToDosError(IoStatusBlock->Status); dwErrorCode = RtlNtStatusToDosError(IoStatusBlock->Status);
} }
LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine = (LPOVERLAPPED_COMPLETION_ROUTINE)ApcContext; LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine = reinterpret_cast<LPOVERLAPPED_COMPLETION_ROUTINE>(ApcContext);
LPOVERLAPPED lpOverlapped = (LPOVERLAPPED)CONTAINING_RECORD(IoStatusBlock, OVERLAPPED, Internal); LPOVERLAPPED lpOverlapped = reinterpret_cast<LPOVERLAPPED>(IoStatusBlock);
(CompletionRoutine)(dwErrorCode, dwTransferred, lpOverlapped); (CompletionRoutine)(dwErrorCode, dwTransferred, lpOverlapped);
@ -2168,10 +2175,17 @@ XBSYSAPI EXPORTNUM(236) xbox::ntstatus_xt NTAPI xbox::NtWriteFile
CxbxDebugger::ReportFileWrite(FileHandle, Length, Offset); CxbxDebugger::ReportFileWrite(FileHandle, Length, Offset);
} }
if (ApcRoutine != nullptr) {
// Pack the original parameters to a wrapped context for a custom APC routine
CxbxIoDispatcherContext* cxbxContext = new CxbxIoDispatcherContext(IoStatusBlock, ApcRoutine, ApcContext);
ApcRoutine = CxbxIoApcDispatcher;
ApcContext = cxbxContext;
}
NTSTATUS ret = NtDll::NtWriteFile( NTSTATUS ret = NtDll::NtWriteFile(
FileHandle, FileHandle,
Event, Event,
(PVOID)ApcRoutine, ApcRoutine,
ApcContext, ApcContext,
IoStatusBlock, IoStatusBlock,
Buffer, Buffer,

View File

@ -191,6 +191,14 @@ void CxbxFormatPartitionByHandle(HANDLE hFile)
printf("Formatted EmuDisk Partition%d\n", CxbxGetPartitionNumberFromHandle(hFile)); printf("Formatted EmuDisk Partition%d\n", CxbxGetPartitionNumberFromHandle(hFile));
} }
void NTAPI CxbxIoApcDispatcher(PVOID ApcContext, xbox::PIO_STATUS_BLOCK /*IoStatusBlock*/, xbox::ulong_xt Reserved)
{
CxbxIoDispatcherContext* cxbxContext = reinterpret_cast<CxbxIoDispatcherContext*>(ApcContext);
std::get<xbox::PIO_APC_ROUTINE>(*cxbxContext)(
std::get<LPVOID>(*cxbxContext),std::get<xbox::PIO_STATUS_BLOCK>(*cxbxContext), Reserved);
delete cxbxContext;
}
const std::string MediaBoardRomFile = "Chihiro\\fpr21042_m29w160et.bin"; const std::string MediaBoardRomFile = "Chihiro\\fpr21042_m29w160et.bin";
const std::string DrivePrefix = "\\??\\"; const std::string DrivePrefix = "\\??\\";
const std::string DriveSerial = DrivePrefix + "serial:"; const std::string DriveSerial = DrivePrefix + "serial:";

View File

@ -304,4 +304,15 @@ int CxbxGetPartitionNumberFromHandle(HANDLE hFile);
std::string CxbxGetPartitionDataPathFromHandle(HANDLE hFile); std::string CxbxGetPartitionDataPathFromHandle(HANDLE hFile);
void CxbxFormatPartitionByHandle(HANDLE hFile); void CxbxFormatPartitionByHandle(HANDLE hFile);
// Ensures that an original IoStatusBlock gets passed to the completion callback
// Used by NtReadFile and NtWriteFile
using CxbxIoDispatcherContext = std::tuple<xbox::PIO_STATUS_BLOCK, xbox::PIO_APC_ROUTINE, PVOID>;
void NTAPI CxbxIoApcDispatcher
(
PVOID ApcContext,
xbox::PIO_STATUS_BLOCK IoStatusBlock,
xbox::ulong_xt Reserved
);
#endif #endif