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:
commit
5d222c10a0
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
// ******************************************************************
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue