Example #1
0
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;
}
Example #2
0
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;
}