#include "common.h" #include #include "DldiDriver.h" void DldiDriver::Relocate(u32 targetAddress) { u32 currentAddress = _driver->driverStartAddress; if (currentAddress == targetAddress) return; u32 currentEndAddress = _driver->driverEndAddress; if (_driver->fixFlags & DLDI_FIX_ALL) { LOG_WARNING("Dldi driver uses FIX_ALL flag"); u32* ptr = (u32*)((u8*)_driver + sizeof(dldi_header_t)); u32 size = currentEndAddress - currentAddress; for (u32 i = 0; i < size; i += 4) { u32 word = *ptr; if (currentAddress <= word && word < currentEndAddress) *ptr = word - currentAddress + targetAddress; ptr++; } } else { // note that we are not going to do those fixes when we did // FIX_ALL already, since it covers them already if (_driver->fixFlags & DLDI_FIX_GLUE) { u32* ptr = (u32*)((u8*)_driver + _driver->glueStartAddress - currentAddress); u32 size = _driver->glueEndAddress - _driver->glueStartAddress; for (u32 i = 0; i < size; i += 4) { u32 word = *ptr; if (currentAddress <= word && word < currentEndAddress) *ptr = word - currentAddress + targetAddress; ptr++; } } if (_driver->fixFlags & DLDI_FIX_GOT) { u32* ptr = (u32*)((u8*)_driver + _driver->gotStartAddress - currentAddress); u32 size = _driver->gotEndAddress - _driver->gotStartAddress; for (u32 i = 0; i < size; i += 4) { u32 word = *ptr; if (currentAddress <= word && word < currentEndAddress) *ptr = word - currentAddress + targetAddress; ptr++; } } } _driver->driverStartAddress = targetAddress; _driver->driverEndAddress = _driver->driverEndAddress + targetAddress - currentAddress; _driver->glueStartAddress = _driver->glueStartAddress + targetAddress - currentAddress; _driver->glueEndAddress = _driver->glueEndAddress + targetAddress - currentAddress; _driver->gotStartAddress = _driver->gotStartAddress + targetAddress - currentAddress; _driver->gotEndAddress = _driver->gotEndAddress + targetAddress - currentAddress; _driver->bssStartAddress = _driver->bssStartAddress + targetAddress - currentAddress; _driver->bssEndAddress = _driver->bssEndAddress + targetAddress - currentAddress; _driver->startupFuncAddress = _driver->startupFuncAddress + targetAddress - currentAddress; _driver->isInsertedFuncAddress = _driver->isInsertedFuncAddress + targetAddress - currentAddress; _driver->readSectorsFuncAddress = _driver->readSectorsFuncAddress + targetAddress - currentAddress; _driver->writeSectorsFuncAddress = _driver->writeSectorsFuncAddress + targetAddress - currentAddress; _driver->clearStatusFuncAddress = _driver->clearStatusFuncAddress + targetAddress - currentAddress; _driver->shutdownFuncAddress = _driver->shutdownFuncAddress + targetAddress - currentAddress; } void DldiDriver::PrepareForUse() { if (_driver->fixFlags & DLDI_FIX_BSS) { memset((u8*)_driver + _driver->bssStartAddress - _driver->driverStartAddress, 0, _driver->bssEndAddress - _driver->bssStartAddress); } } bool DldiDriver::PatchTo(dldi_header_t* stub) { if (_driver->dldiMagic != DLDI_MAGIC) return false; u32 stubSize = stub->stubSize; if (stubSize < _driver->driverSize) { LOG_ERROR("Dldi stub of size %d is not large enough for driver of size %d\n", stubSize, _driver->driverSize); return false; } u32 targetAddress = stub->driverStartAddress; u32 driverSize = 1 << _driver->driverSize; memcpy(stub, _driver, driverSize); stub->stubSize = stubSize; auto newDriver = DldiDriver(stub); newDriver.Relocate(targetAddress); newDriver.PrepareForUse(); return true; }