Merge pull request #2221 from jackchentwkh/ImageDescWithRebaseAddress

Keep ImageBuffer backup copy, handle ImageDesc with rebase address, Fix Otogi 1, Otogi 2, PGR2 booting.
This commit is contained in:
ergo720 2021-05-21 19:38:41 +02:00 committed by GitHub
commit 5d222c10a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 269 additions and 21 deletions

View File

@ -514,9 +514,9 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(IDirectSound_SetEffectData)
}
// ******************************************************************
// * patch: IDirectSound_DownloadEffectsImage
// * patch: CDirectSound_DownloadEffectsImage
// ******************************************************************
xbox::hresult_xt WINAPI xbox::EMUPATCH(IDirectSound_DownloadEffectsImage)
xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSound_DownloadEffectsImage)
(
LPDIRECTSOUND8 pThis,
LPCVOID pvImageBuffer,
@ -526,17 +526,76 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(IDirectSound_DownloadEffectsImage)
{
DSoundMutexGuardLock;
LOG_FUNC_BEGIN
LOG_FUNC_ARG(pThis)
LOG_FUNC_ARG(pvImageBuffer)
LOG_FUNC_ARG(dwImageSize)
LOG_FUNC_ARG(pImageLoc)
LOG_FUNC_ARG(ppImageDesc)
LOG_FUNC_END;
LOG_FUNC_BEGIN
LOG_FUNC_ARG(pThis)
LOG_FUNC_ARG(pvImageBuffer)
LOG_FUNC_ARG(dwImageSize)
LOG_FUNC_ARG(pImageLoc)
LOG_FUNC_ARG(ppImageDesc)
LOG_FUNC_END;
// This function is relative to DSP for Interactive 3-D Audio Level 2 (I3DL2)
LOG_NOT_SUPPORTED();
LOG_INCOMPLETE();
if (ppImageDesc) { // If the guest code request a pointer to ImageDesc structure to be returned, then we should allocate a memory and create ImageDesc.
// Code block below is reversed from Otogi.
// ImageBuffer header starts from offset ox800 and ends in offset 0x817. actual DSP code segment starts from offset 0x818.
// DWORD at offset 0x804 and offset 0x80C should be the code segment sizes in dwords.
// ImageDesc is appended after code segments. There are additional two DWORDs data for each effect appended after ImageDesc which I have no idea what they are for.
// Image buffer must be copied to internal and backed up 1st. the data might be referenced by the guest code later.
// The Code Segment Address and State address in DSEFFECTMAP aEffectMaps[1] must be rebased to the internal buffer.
// NOTE: this buffer should also be freed in IDirectSound_Release when the ref counter drops to zero, but that function is currently not implemented.
static PBYTE ImageBufferBackup = zeroptr; //The image buffer must be backed up since some game might reference ths data. ex. PGR2.
if (ImageBufferBackup != zeroptr) {
ExFreePool(ImageBufferBackup);
}
ImageBufferBackup = static_cast<PBYTE>(ExAllocatePool(dwImageSize));
if (ImageBufferBackup == zeroptr) {
return E_OUTOFMEMORY;
}
std::memcpy(ImageBufferBackup, pvImageBuffer, dwImageSize); // Copy the ImageBuffer to internal backup Buffer.
// from here, all process should base on internal image buffer.
dword_xt N1 = *(PDWORD)(ImageBufferBackup + 0x804); //Total code segment size in dwords
dword_xt N2 = *(PDWORD)(ImageBufferBackup + 0x80C); //Total state segment size in dwords
PBYTE pImageDesc = ImageBufferBackup + 0x818 + 4 * (N1 + N2); //calculate the starting address of ImageDesc in image buffer
DWORD EffectCount = ((LPDSEFFECTIMAGEDESC)pImageDesc)->dwEffectCount; //the first DWORD in ImageDesc is EffectCount.
dword_xt ImageDescSize = 8 + 32 * EffectCount; //The size of ImageDesc is two Dwords (8 bytes) + 8 DWORS (32 bytes) for each effects.
// Process the DSEFFECTMAP in internal image buffer, rebase code segmemt address and state segment address of each effect.
PBYTE pEffectMaps = (pImageDesc + 8); //EffectMaps array start from here.
for (int effect_loop = 0; effect_loop < EffectCount; effect_loop++) {
PBYTE pCodeSeg = pEffectMaps + effect_loop * 32;
*(PDWORD)pCodeSeg += (DWORD)ImageBufferBackup;
PBYTE pStateSeg = pEffectMaps + effect_loop * 32+8;
*(PDWORD)pStateSeg += (DWORD)ImageBufferBackup;
}
// NOTE: this buffer should also be freed in IDirectSound_Release when the ref counter drops to zero, but that function is currently not implemented.
static PBYTE ImageDescBuffer = zeroptr;
if (ImageDescBuffer != zeroptr) {
ExFreePool(ImageDescBuffer);
}
ImageDescBuffer = static_cast<PBYTE>(ExAllocatePool(ImageDescSize));
if (ImageDescBuffer == zeroptr) {
return E_OUTOFMEMORY;
}
// NOTE: this is very wrong. The dsp image is encrypted, and thus simply copying the original encrypted image won't do any good.
*ppImageDesc = ImageDescBuffer;
std::memcpy(*ppImageDesc, pImageDesc, ImageDescSize);
// with the code above, we could easily retrieve the address and size of ImageDesc within the image buffer.
// then we can allocate a new memory, copy the imageDesc from the image buffer to the newly allocated memory,
// then assign the newly allocated memory to the ppImageDesc. that's all.
}
return S_OK;
}

View File

@ -127,6 +127,50 @@ struct SharedDSBuffer : DSBUFFER_S {
}
};
typedef struct _DSEFFECTMAP {
LPVOID lpvCodeSegment;
DWORD dwCodeSize;
LPVOID lpvStateSegment;
DWORD dwStateSize;
LPVOID lpvYMemorySegment;
DWORD dwYMemorySize;
LPVOID lpvScratchSegment;
DWORD dwScratchSize;
} DSEFFECTMAP, *LPDSEFFECTMAP;
/*Members
lpvCodeSegment
Starting address of the DSP code segment for this effect.
dwCodeSize
Value that contains the code segment size, in DWORDs.
lpvStateSegment
Starting address of the effect state segment.
dwStateSize
Value that contains the size of the effect state segment, in DWORDs.
lpvYMemorySegment
Starting address of the DSP Y-memory segment.
dwYMemorySize
Value that contains the Y-memory segment size, in DWORDs.
lpvScratchSegment
Starting address of the scratch memory segment.
dwScratchSize
Value that contains the size of the scratch segment, in DWORDs.
*/
typedef struct _DSEFFECTIMAGEDESC {
DWORD dwEffectCount;
DWORD dwTotalScratchSize;
DSEFFECTMAP aEffectMaps[1];
} DSEFFECTIMAGEDESC, *LPDSEFFECTIMAGEDESC;
/*Members
dwEffectCount
Value that contains the number of effects in the image.
dwTotalScratchSize
Value that contains the total amount of space required by effects that use scratch space for delay lines.
aEffectMaps
Variable-length array that contains the effect descriptions.
*/
//Custom flags (4 bytes support up to 31 shifts,starting from 0)
#define DSE_FLAG_PCM (1 << 0)
#define DSE_FLAG_XADPCM (1 << 1)
@ -414,9 +458,9 @@ xbox::hresult_xt WINAPI EMUPATCH(IDirectSound_SynchPlayback)
);
// ******************************************************************
// * patch: IDirectSound_DownloadEffectsImage
// * patch: CDirectSound_DownloadEffectsImage
// ******************************************************************
xbox::hresult_xt WINAPI EMUPATCH(IDirectSound_DownloadEffectsImage)
xbox::hresult_xt WINAPI EMUPATCH(CDirectSound_DownloadEffectsImage)
(
LPDIRECTSOUND8 pThis,
LPCVOID pvImageBuffer,

View File

@ -108,16 +108,156 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(XAudioDownloadEffectsImage)
{
DSoundMutexGuardLock;
LOG_FUNC_BEGIN
LOG_FUNC_ARG(pszImageName)
LOG_FUNC_ARG(pImageLoc)
LOG_FUNC_ARG(dwFlags)
LOG_FUNC_ARG(ppImageDesc)
LOG_FUNC_END;
LOG_FUNC_BEGIN
LOG_FUNC_ARG(pszImageName)
LOG_FUNC_ARG(pImageLoc)
LOG_FUNC_ARG(dwFlags)
LOG_FUNC_ARG(ppImageDesc)
LOG_FUNC_END;
LOG_NOT_SUPPORTED();
LOG_INCOMPLETE();
return S_OK;
xbox::hresult_xt result = S_OK;
if (ppImageDesc) { //only process image section/file which the guest code asks for ImageDesc.
PBYTE pvImageBuffer;
dword_xt dwImageSize;
if (dwFlags & 1) { // dwFlags == XAUDIO_DOWNLOADFX_XBESECTION, The DSP effects image is located in a section of the XBE.
/*
//future code for loading imgae from XBE section. these codes are reversd from PGR2.
PXBEIMAGE_SECTION pImageSectionHandle=XGetSectionHandle(pszImageName); //get section handle by section name, not implemented yet.
// perhaps use pImageSectionHandle = CxbxKrnl_Xbe->FindSection(pszImageName); will be easier.
if (XeLoadSection(pImageSectionHandle) > 0) { //load section handle and get the loaded address.
//note this sction must be freed after the internal image bacup and ImageDesc was created.
//EmuKnrlXe.cpp implements XeLoadSection(). could reference that code.
pvImageBuffer = pImageSectionHandle->VirtualAddress;
}
dwImageSize=pImageSectionHandle->VirtualSize; //get section size by section handle.
result = xbox::EMUPATCH(CDirectSound_DownloadEffectsImage)(pThis_tmp, pvImageBuffer,dwImageSize,pImageLoc,ppImageDesc);
if(pImageSectionHandle<>0 && pImageSectionHandle!=-1)
XeUnloadSection(pImageSectionHandle);
*/
LOG_TEST_CASE("Loading dsp images from xbe sections is currently not yet supported");
result = S_OK;//this line should be removed once the section loading code was implemented.
}
else { // load from file
LPDIRECTSOUND8 pThis_tmp = zeroptr;
HANDLE hFile;
DWORD dwBytesRead;
// using xbox::NtCreateFile() directly instead of Host CreateFile();
OBJECT_ATTRIBUTES obj;
ANSI_STRING file_name;
IO_STATUS_BLOCK io_status_block;
RtlInitAnsiString(&file_name, pszImageName);
XB_InitializeObjectAttributes(&obj, &file_name, obj_case_insensitive, ObDosDevicesDirectory());
ntstatus_xt NtStatusCreateFile;
//LARGE_INTEGER tmp_LargeInt;
//tmp_LargeInt.QuadPart= dwImageSize;
NtStatusCreateFile = NtCreateFile(
&hFile,
FILE_GENERIC_READ, // FILE_READ_DATA, GENERIC_READ, DesiredAccess,
&obj,
&io_status_block,
zeroptr, // AllocationSize OPTIONAL, must be none zero, no effect for read acceess.
FILE_ATTRIBUTE_NORMAL, // FileAttributes,
FILE_SHARE_READ, // ShareAccess,
FILE_OPEN, // CreateDisposition,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE); // CreateOptions; CreateFileA Convert dwCreationDisposition== 3 OPEN_EXISTING to CreateOptions = 1 FILE_DIRECTORY_FILE!!?? but with 1, this will fail.
//process possible error with NtCreateFile()
if (NtStatusCreateFile < 0) {
//ULONG DOSERRORNtCreateFile=RtlNtStatusToDosError(NtStatusCreateFile);
EmuLog(LOG_LEVEL::WARNING, "%s: Image file NtCreateFile() error", __func__);
if (NtStatusCreateFile == status_object_name_collision) {
EmuLog(LOG_LEVEL::WARNING, "%s: Image file name collision", __func__);
}
else if (NtStatusCreateFile == status_file_is_a_directory) {
EmuLog(LOG_LEVEL::WARNING, "%s: Image file name is a directory or invalid", __func__);
}
hFile= INVALID_HANDLE_VALUE;
}
if (hFile != INVALID_HANDLE_VALUE) {
FILE_STANDARD_INFORMATION FileStdInfo;
NTSTATUS NtStatusQueryInfoFile = NtQueryInformationFile(
hFile,
&io_status_block,
&FileStdInfo, // FileInformation
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation); // FileInformationClass; Enumation of the file information class.
if (NtStatusQueryInfoFile >= 0) {
dwImageSize = FileStdInfo.EndOfFile.u.LowPart;
}
else {
EmuLog(LOG_LEVEL::WARNING, "%s: Image file NtQueryInformationFile() error.", __func__);
dwImageSize = 0;
}
if (dwImageSize > 0) { //proceed the process only if the file size > 0
pvImageBuffer = new BYTE[dwImageSize]; //allocate buffer to read in to image file.
//use NtReadFile() to replace host CreatFile();
ntstatus_xt NtStatusReadFile = NtReadFile(
hFile,
0, // Event OPTIONAL
0, // ApcRoutine OPTIONAL
0, // ApcContext
&io_status_block,
pvImageBuffer,
dwImageSize,
zeroptr); // ByteOffset OPTIONAL
DWORD dwBytesRead = 0;
if (NtStatusReadFile == status_pending) {
NtStatusReadFile = NtWaitForSingleObject(hFile, 0, 0);
if (NtStatusReadFile < 0){ //something wrong
EmuLog(LOG_LEVEL::WARNING, "%s: Image file NtReadFile error", __func__);
if (NtStatusReadFile != status_end_of_file) {
if ((NtStatusReadFile & 0xC0000000) == 0x80000000) { //Error happened during file reading
dwBytesRead = io_status_block.Information;
EmuLog(LOG_LEVEL::WARNING, "%s: NtReadFile read file end", __func__);
// ULONG DOSErrorNtReadFile = RtlNtStatusToDosError(NtStatusReadFile); this is supposed to be the error code of xbox::CreateFile()
}
} else {
dwBytesRead = 0;
}
}
NtStatusReadFile = io_status_block.Status;
}
if (NtStatusReadFile >= 0) {
dwBytesRead = io_status_block.Information;
}
if (dwBytesRead == dwImageSize) { // only process the image if the whole image was read successfully.
result = xbox::EMUPATCH(CDirectSound_DownloadEffectsImage)(pThis_tmp, pvImageBuffer,dwImageSize,pImageLoc,ppImageDesc);
}
else {
EmuLog(LOG_LEVEL::WARNING, "%s: Image file NtReadFile read in lenth not enough", __func__);
}
if (pvImageBuffer) {
delete[] pvImageBuffer;
}
if (hFile != INVALID_HANDLE_VALUE) {
NtClose(hFile);
}
}
}
}
}
return result;
}
// ******************************************************************

View File

@ -312,7 +312,8 @@ std::map<const std::string, const xbox_patch_t> g_PatchTable = {
PATCH_ENTRY("IDirectSound_CommitEffectData", xbox::EMUPATCH(IDirectSound_CommitEffectData), PATCH_HLE_DSOUND),
PATCH_ENTRY("IDirectSound_CreateSoundBuffer", xbox::EMUPATCH(IDirectSound_CreateSoundBuffer), PATCH_HLE_DSOUND),
PATCH_ENTRY("IDirectSound_CreateSoundStream", xbox::EMUPATCH(IDirectSound_CreateSoundStream), PATCH_HLE_DSOUND),
PATCH_ENTRY("IDirectSound_DownloadEffectsImage", xbox::EMUPATCH(IDirectSound_DownloadEffectsImage), PATCH_HLE_DSOUND),
// PATCH_ENTRY("IDirectSound_DownloadEffectsImage", xbox::EMUPATCH(IDirectSound_DownloadEffectsImage), PATCH_HLE_DSOUND),
PATCH_ENTRY("CDirectSound_DownloadEffectsImage", xbox::EMUPATCH(CDirectSound_DownloadEffectsImage), PATCH_HLE_DSOUND),
PATCH_ENTRY("IDirectSound_EnableHeadphones", xbox::EMUPATCH(IDirectSound_EnableHeadphones), PATCH_HLE_DSOUND),
PATCH_ENTRY("IDirectSound_GetCaps", xbox::EMUPATCH(IDirectSound_GetCaps), PATCH_HLE_DSOUND),
PATCH_ENTRY("IDirectSound_GetEffectData", xbox::EMUPATCH(IDirectSound_GetEffectData), PATCH_HLE_DSOUND),

View File

@ -35,6 +35,8 @@ typedef struct _OBJECT_HEADER_NAME_INFO {
OBJECT_STRING Name;
} OBJECT_HEADER_NAME_INFO, *POBJECT_HEADER_NAME_INFO;
inline constexpr dword_xt obj_case_insensitive = 0x40;
#define ObDosDevicesDirectory() ((HANDLE)-3)
#define ObWin32NamedObjectsDirectory() ((HANDLE)-4)

View File

@ -92,6 +92,8 @@ inline constexpr dword_xt status_xbe_media_mismatch = 0xC0050002L;
inline constexpr dword_xt status_object_name_invalid = 0xC0000033L;
inline constexpr dword_xt status_object_name_not_found = 0xC0000034L;
inline constexpr dword_xt status_object_name_collision = 0xC0000035L;
inline constexpr dword_xt status_file_is_a_directory = 0xC00000BAL;
inline constexpr dword_xt status_end_of_file = 0xC0000011L;
inline constexpr dword_xt status_invalid_page_protection = 0xC0000045L;
inline constexpr dword_xt status_conflicting_addresses = 0xC0000018L;
inline constexpr dword_xt status_unable_to_free_vm = 0xC000001AL;