bool tryPatch(void *data, size_t size) { // Find the DSDI reserved space in the file addr_t patchOffset = quickFind(static_cast<data_t *>(data), dldiMagicString, size, sizeof(dldiMagicString) / sizeof(char)); // no DLDI section if (patchOffset < 0) return false; data_t *pDH = mpcf_dldi; data_t *pAH = static_cast<data_t *>(data) + patchOffset; if (pDH[DO_driverSize] > pAH[DO_allocatedSpace]) { printf("Not enough space for patch. Available %d bytes, need %d bytes\n", 1 << pAH[DO_allocatedSpace], 1 << pDH[DO_driverSize]); return false; } if (memcmp(&pAH[DO_friendlyName], "Default (No interface)", 22)) { printf("Would have been a candidate for auto-patch DLDI, but there was already a patch installed."); return false; } //----should be able to patch OK----- addr_t memOffset; // Offset of DLDI after the file is loaded into memory addr_t relocationOffset; // Value added to all offsets within the patch to fix it properly addr_t ddmemOffset; // Original offset used in the DLDI file addr_t ddmemStart; // Start of range that offsets can be in the DLDI file addr_t ddmemEnd; // End of range that offsets can be in the DLDI file addr_t ddmemSize; // Size of range that offsets can be in the DLDI file addr_t addrIter; memOffset = readAddr(pAH, DO_text_start); if (!memOffset) memOffset = readAddr(pAH, DO_startup) - DO_code; ddmemOffset = readAddr(pDH, DO_text_start); relocationOffset = memOffset - ddmemOffset; printf("AUTO-PATCHING DLDI to MPCF! Lucky you!\n\n"); printf("Old driver: %s\n", &pAH[DO_friendlyName]); printf("New driver: %s\n", &pDH[DO_friendlyName]); printf("\n"); printf("Position in file: 0x%08X\n", patchOffset); printf("Position in memory: 0x%08X\n", memOffset); printf("Patch base address: 0x%08X\n", ddmemOffset); printf("Relocation offset: 0x%08X\n", relocationOffset); printf("\n"); ddmemStart = readAddr(pDH, DO_text_start); ddmemSize = 1 << pDH[DO_driverSize]; ddmemEnd = ddmemStart + ddmemSize; // Remember how much space is actually reserved pDH[DO_allocatedSpace] = pAH[DO_allocatedSpace]; // Copy the DLDI patch into the application memcpy(pAH, pDH, sizeof(mpcf_dldi)); // Fix the section pointers in the header writeAddr(pAH, DO_text_start, readAddr(pAH, DO_text_start) + relocationOffset); writeAddr(pAH, DO_data_end, readAddr(pAH, DO_data_end) + relocationOffset); writeAddr(pAH, DO_glue_start, readAddr(pAH, DO_glue_start) + relocationOffset); writeAddr(pAH, DO_glue_end, readAddr(pAH, DO_glue_end) + relocationOffset); writeAddr(pAH, DO_got_start, readAddr(pAH, DO_got_start) + relocationOffset); writeAddr(pAH, DO_got_end, readAddr(pAH, DO_got_end) + relocationOffset); writeAddr(pAH, DO_bss_start, readAddr(pAH, DO_bss_start) + relocationOffset); writeAddr(pAH, DO_bss_end, readAddr(pAH, DO_bss_end) + relocationOffset); // Fix the function pointers in the header writeAddr(pAH, DO_startup, readAddr(pAH, DO_startup) + relocationOffset); writeAddr(pAH, DO_isInserted, readAddr(pAH, DO_isInserted) + relocationOffset); writeAddr(pAH, DO_readSectors, readAddr(pAH, DO_readSectors) + relocationOffset); writeAddr(pAH, DO_writeSectors, readAddr(pAH, DO_writeSectors) + relocationOffset); writeAddr(pAH, DO_clearStatus, readAddr(pAH, DO_clearStatus) + relocationOffset); writeAddr(pAH, DO_shutdown, readAddr(pAH, DO_shutdown) + relocationOffset); if (pDH[DO_fixSections] & FIX_ALL) // Search through and fix pointers within the data section of the file for (addrIter = readAddr(pDH, DO_text_start) - ddmemStart; addrIter < readAddr(pDH, DO_data_end) - ddmemStart; ++addrIter) if (ddmemStart <= readAddr(pAH, addrIter) && readAddr(pAH, addrIter) < ddmemEnd) writeAddr(pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset); if (pDH[DO_fixSections] & FIX_GLUE) // Search through and fix pointers within the glue section of the file for (addrIter = readAddr(pDH, DO_glue_start) - ddmemStart; addrIter < readAddr(pDH, DO_glue_end) - ddmemStart; ++addrIter) if (ddmemStart <= readAddr(pAH, addrIter) && readAddr(pAH, addrIter) < ddmemEnd) writeAddr(pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset); if (pDH[DO_fixSections] & FIX_GOT) // Search through and fix pointers within the Global Offset Table section of the file for (addrIter = readAddr(pDH, DO_got_start) - ddmemStart; addrIter < readAddr(pDH, DO_got_end) - ddmemStart; ++addrIter) if (ddmemStart <= readAddr(pAH, addrIter) && readAddr(pAH, addrIter) < ddmemEnd) writeAddr(pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset); if (pDH[DO_fixSections] & FIX_BSS) // Initialise the BSS to 0 memset(&pAH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start)); return true; }
static bool dldiPatchLoader (data_t *binData, u32 binSize, bool clearBSS) { addr_t memOffset; // Offset of DLDI after the file is loaded into memory addr_t patchOffset; // Position of patch destination in the file addr_t relocationOffset; // Value added to all offsets within the patch to fix it properly addr_t ddmemOffset; // Original offset used in the DLDI file addr_t ddmemStart; // Start of range that offsets can be in the DLDI file addr_t ddmemEnd; // End of range that offsets can be in the DLDI file addr_t ddmemSize; // Size of range that offsets can be in the DLDI file addr_t addrIter; data_t *pDH; data_t *pAH; size_t dldiFileSize = 0; // Find the DLDI reserved space in the file patchOffset = quickFind (binData, dldiMagicLoaderString, binSize, sizeof(dldiMagicLoaderString)); if (patchOffset < 0) { // does not have a DLDI section return false; } pDH = (data_t*)(io_dldi_data); pAH = &(binData[patchOffset]); if (*((u32*)(pDH + DO_ioType)) == DEVICE_TYPE_DLDI) { // No DLDI patch return false; } if (pDH[DO_driverSize] > pAH[DO_allocatedSpace]) { // Not enough space for patch return false; } dldiFileSize = 1 << pDH[DO_driverSize]; memOffset = readAddr (pAH, DO_text_start); if (memOffset == 0) { memOffset = readAddr (pAH, DO_startup) - DO_code; } ddmemOffset = readAddr (pDH, DO_text_start); relocationOffset = memOffset - ddmemOffset; ddmemStart = readAddr (pDH, DO_text_start); ddmemSize = (1 << pDH[DO_driverSize]); ddmemEnd = ddmemStart + ddmemSize; // Remember how much space is actually reserved pDH[DO_allocatedSpace] = pAH[DO_allocatedSpace]; // Copy the DLDI patch into the application vramcpy (pAH, pDH, dldiFileSize); // Fix the section pointers in the header writeAddr (pAH, DO_text_start, readAddr (pAH, DO_text_start) + relocationOffset); writeAddr (pAH, DO_data_end, readAddr (pAH, DO_data_end) + relocationOffset); writeAddr (pAH, DO_glue_start, readAddr (pAH, DO_glue_start) + relocationOffset); writeAddr (pAH, DO_glue_end, readAddr (pAH, DO_glue_end) + relocationOffset); writeAddr (pAH, DO_got_start, readAddr (pAH, DO_got_start) + relocationOffset); writeAddr (pAH, DO_got_end, readAddr (pAH, DO_got_end) + relocationOffset); writeAddr (pAH, DO_bss_start, readAddr (pAH, DO_bss_start) + relocationOffset); writeAddr (pAH, DO_bss_end, readAddr (pAH, DO_bss_end) + relocationOffset); // Fix the function pointers in the header writeAddr (pAH, DO_startup, readAddr (pAH, DO_startup) + relocationOffset); writeAddr (pAH, DO_isInserted, readAddr (pAH, DO_isInserted) + relocationOffset); writeAddr (pAH, DO_readSectors, readAddr (pAH, DO_readSectors) + relocationOffset); writeAddr (pAH, DO_writeSectors, readAddr (pAH, DO_writeSectors) + relocationOffset); writeAddr (pAH, DO_clearStatus, readAddr (pAH, DO_clearStatus) + relocationOffset); writeAddr (pAH, DO_shutdown, readAddr (pAH, DO_shutdown) + relocationOffset); if (pDH[DO_fixSections] & FIX_ALL) { // Search through and fix pointers within the data section of the file for (addrIter = (readAddr(pDH, DO_text_start) - ddmemStart); addrIter < (readAddr(pDH, DO_data_end) - ddmemStart); addrIter++) { if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) { writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset); } } } if (pDH[DO_fixSections] & FIX_GLUE) { // Search through and fix pointers within the glue section of the file for (addrIter = (readAddr(pDH, DO_glue_start) - ddmemStart); addrIter < (readAddr(pDH, DO_glue_end) - ddmemStart); addrIter++) { if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) { writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset); } } } if (pDH[DO_fixSections] & FIX_GOT) { // Search through and fix pointers within the Global Offset Table section of the file for (addrIter = (readAddr(pDH, DO_got_start) - ddmemStart); addrIter < (readAddr(pDH, DO_got_end) - ddmemStart); addrIter++) { if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) { writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset); } } } if (clearBSS && (pDH[DO_fixSections] & FIX_BSS)) { // Initialise the BSS to 0, only if the disc is being re-inited memset (&pAH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start)); } return true; }