mirror of
https://github.com/LNH-team/pico-loader.git
synced 2026-01-10 08:29:29 +01:00
107 lines
4.0 KiB
C++
107 lines
4.0 KiB
C++
#include "common.h"
|
|
#include <string.h>
|
|
#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;
|
|
}
|