Skip to content

Commit

Permalink
Improve DLDI patching
Browse files Browse the repository at this point in the history
Fixes DLDI when booting from firmware
  • Loading branch information
Hydr8gon committed May 17, 2022
1 parent 89b2edb commit 77a76ff
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 54 deletions.
13 changes: 2 additions & 11 deletions src/cartridge.cpp
Expand Up @@ -64,13 +64,14 @@ bool Cartridge::loadRom(std::string path)
return true;
}

void Cartridge::loadRomSection(uint32_t offset, uint32_t size)
void Cartridge::loadRomSection(size_t offset, size_t size)
{
// Load a section of the current ROM file into memory
if (rom) delete[] rom;
rom = new uint8_t[size];
fseek(romFile, offset, SEEK_SET);
fread(rom, sizeof(uint8_t), size, romFile);
core->dldi.patchRom(rom, offset, size);
}

void Cartridge::writeSave()
Expand Down Expand Up @@ -306,16 +307,6 @@ void CartridgeNds::directBoot()
core->memory.write<uint32_t>(1, ramAddr7 + i, U8TO32(rom, offset + i));
}
}

// Scan the initial ARM9 binary for a DLDI header and patch the driver if found
for (int i = ramAddr9; i < ramAddr9 + size9; i += 0x40)
{
if (core->memory.read<uint32_t>(0, i) == 0xBF8DA5ED)
{
core->dldi.patchDriver(i);
break;
}
}
}

uint64_t CartridgeNds::encrypt64(uint64_t value)
Expand Down
2 changes: 1 addition & 1 deletion src/cartridge.h
Expand Up @@ -60,7 +60,7 @@ class Cartridge
bool saveDirty = false;
std::mutex mutex;

void loadRomSection(uint32_t offset, uint32_t size);
void loadRomSection(size_t offset, size_t size);

private:
std::string romName, saveName;
Expand Down
7 changes: 7 additions & 0 deletions src/defines.h
Expand Up @@ -52,4 +52,11 @@
#define U8TO32(data, index) ((data)[index] | ((data)[(index) + 1] << 8) | ((data)[(index) + 2] << 16) | ((data)[(index) + 3] << 24))
#define U8TO64(data, index) ((uint64_t)U8TO32(data, (index) + 4) << 32) | (uint32_t)U8TO32(data, index)

// Macro that stores a 32-bit value to an 8-bit array
#define U32TO8(data, index, value) \
(data)[(index) + 0] = (uint8_t)((value) >> 0); \
(data)[(index) + 1] = (uint8_t)((value) >> 8); \
(data)[(index) + 2] = (uint8_t)((value) >> 16); \
(data)[(index) + 3] = (uint8_t)((value) >> 24);

#endif // DEFINES_H
72 changes: 42 additions & 30 deletions src/dldi.cpp
Expand Up @@ -28,33 +28,45 @@ Dldi::~Dldi()
fclose(sdImage);
}

void Dldi::patchDriver(uint32_t address)
void Dldi::patchRom(uint8_t *rom, size_t offset, size_t size)
{
// Patch the DLDI driver to use the HLE functions
core->memory.write<uint8_t> (0, address + 0x0F, 0x0E); // Size of driver in terms of 1 << n (16KB)
core->memory.write<uint32_t>(0, address + 0x40, address); // Address of driver
core->memory.write<uint32_t>(0, address + 0x64, 0x00000023); // Feature flags (read, write, NDS slot)
core->memory.write<uint32_t>(0, address + 0x68, address + 0x80); // Address of startup()
core->memory.write<uint32_t>(0, address + 0x6C, address + 0x84); // Address of isInserted()
core->memory.write<uint32_t>(0, address + 0x70, address + 0x88); // Address of readSectors(sector, numSectors, buf)
core->memory.write<uint32_t>(0, address + 0x74, address + 0x8C); // Address of writeSectors(sector, numSectors, buf)
core->memory.write<uint32_t>(0, address + 0x78, address + 0x90); // Address of clearStatus()
core->memory.write<uint32_t>(0, address + 0x7C, address + 0x94); // Address of shutdown()
core->memory.write<uint32_t>(0, address + 0x80, DLDI_START); // startup()
core->memory.write<uint32_t>(0, address + 0x84, DLDI_INSERT); // isInserted()
core->memory.write<uint32_t>(0, address + 0x88, DLDI_READ); // readSectors(sector, numSectors, buf)
core->memory.write<uint32_t>(0, address + 0x8C, DLDI_WRITE); // writeSectors(sector, numSectors, buf)
core->memory.write<uint32_t>(0, address + 0x90, DLDI_CLEAR); // clearStatus()
core->memory.write<uint32_t>(0, address + 0x94, DLDI_STOP); // shutdown()
funcAddress = address + 0x80;

LOG("Patched DLDI driver at 0x%X\n", address);
}

bool Dldi::isFunction(uint32_t address)
{
// Check if an address points to a DLDI function
return (funcAddress != 0 && address >= funcAddress && address < funcAddress + 0x18);
// Scan the ROM for DLDI drivers and patch them if found
for (size_t i = 0; i < size; i += 0x40)
{
// Check for the DLDI magic number
if (U8TO32(rom, i) != 0xBF8DA5ED)
next:
continue;

// Check for the DLDI magic string
const char *str = " Chishm\0";
for (size_t j = 0; j < 8; j++)
{
if (rom[i + 4 + j] != str[j])
goto next;
}

// Patch the DLDI driver to use the HLE functions
rom[i + 0x0F] = 0x0E; // Size of driver in terms of 1 << n (16KB)
uint32_t address = U8TO32(rom, i + 0x40); // Address of driver
U32TO8(rom, i + 0x64, 0x00000023); // Feature flags (read, write, NDS slot)
U32TO8(rom, i + 0x68, address + 0x80); // Address of startup()
U32TO8(rom, i + 0x6C, address + 0x84); // Address of isInserted()
U32TO8(rom, i + 0x70, address + 0x88); // Address of readSectors(sector, numSectors, buf)
U32TO8(rom, i + 0x74, address + 0x8C); // Address of writeSectors(sector, numSectors, buf)
U32TO8(rom, i + 0x78, address + 0x90); // Address of clearStatus()
U32TO8(rom, i + 0x7C, address + 0x94); // Address of shutdown()
U32TO8(rom, i + 0x80, DLDI_START); // startup()
U32TO8(rom, i + 0x84, DLDI_INSERT); // isInserted()
U32TO8(rom, i + 0x88, DLDI_READ); // readSectors(sector, numSectors, buf)
U32TO8(rom, i + 0x8C, DLDI_WRITE); // writeSectors(sector, numSectors, buf)
U32TO8(rom, i + 0x90, DLDI_CLEAR); // clearStatus()
U32TO8(rom, i + 0x94, DLDI_STOP); // shutdown()

// Confirm that a driver has been patched
LOG("Patched DLDI driver at ROM offset 0x%X\n", offset + i);
patched = true;
}
}

int Dldi::startup()
Expand All @@ -70,7 +82,7 @@ int Dldi::isInserted()
return (sdImage ? 1 : 0);
}

int Dldi::readSectors(int sector, int numSectors, uint32_t buf)
int Dldi::readSectors(bool cpu, int sector, int numSectors, uint32_t buf)
{
if (!sdImage) return 0;

Expand All @@ -84,13 +96,13 @@ int Dldi::readSectors(int sector, int numSectors, uint32_t buf)

// Write the data to memory
for (int i = 0; i < size; i++)
core->memory.write<uint8_t>(0, buf + i, data[i]);
core->memory.write<uint8_t>(cpu, buf + i, data[i]);

delete[] data;
return 1;
}

int Dldi::writeSectors(int sector, int numSectors, uint32_t buf)
int Dldi::writeSectors(bool cpu, int sector, int numSectors, uint32_t buf)
{
if (!sdImage) return 0;

Expand All @@ -100,7 +112,7 @@ int Dldi::writeSectors(int sector, int numSectors, uint32_t buf)
// Read data from memory
uint8_t *data = new uint8_t[size];
for (int i = 0; i < size; i++)
data[i] = core->memory.read<uint8_t>(0, buf + i);
data[i] = core->memory.read<uint8_t>(cpu, buf + i);

// Write the data to the SD image
fseek(sdImage, offset, SEEK_SET);
Expand Down
10 changes: 5 additions & 5 deletions src/dldi.h
Expand Up @@ -41,20 +41,20 @@ class Dldi
Dldi(Core *core): core(core) {}
~Dldi();

void patchDriver(uint32_t address);
bool isFunction(uint32_t address);
void patchRom(uint8_t *rom, size_t offset, size_t size);
bool isPatched() { return patched; }

int startup();
int isInserted();
int readSectors(int sector, int numSectors, uint32_t buf);
int writeSectors(int sector, int numSectors, uint32_t buf);
int readSectors(bool cpu, int sector, int numSectors, uint32_t buf);
int writeSectors(bool cpu, int sector, int numSectors, uint32_t buf);
int clearStatus();
int shutdown();

private:
Core *core;

uint32_t funcAddress = 0;
bool patched = false;
FILE *sdImage = nullptr;
};

Expand Down
14 changes: 7 additions & 7 deletions src/interpreter.cpp
Expand Up @@ -1527,16 +1527,16 @@ int Interpreter::handleReserved(uint32_t opcode)
return blx(opcode); // BLX label

// If a DLDI function was jumped to, HLE it and return
if (core->dldi.isFunction(*registers[15] - 8))
if (core->dldi.isPatched())
{
switch (opcode)
{
case DLDI_START: *registers[0] = core->dldi.startup(); break;
case DLDI_INSERT: *registers[0] = core->dldi.isInserted(); break;
case DLDI_READ: *registers[0] = core->dldi.readSectors(*registers[0], *registers[1], *registers[2]); break;
case DLDI_WRITE: *registers[0] = core->dldi.writeSectors(*registers[0], *registers[1], *registers[2]); break;
case DLDI_CLEAR: *registers[0] = core->dldi.clearStatus(); break;
case DLDI_STOP: *registers[0] = core->dldi.shutdown(); break;
case DLDI_START: *registers[0] = core->dldi.startup(); break;
case DLDI_INSERT: *registers[0] = core->dldi.isInserted(); break;
case DLDI_READ: *registers[0] = core->dldi.readSectors(cpu, *registers[0], *registers[1], *registers[2]); break;
case DLDI_WRITE: *registers[0] = core->dldi.writeSectors(cpu, *registers[0], *registers[1], *registers[2]); break;
case DLDI_CLEAR: *registers[0] = core->dldi.clearStatus(); break;
case DLDI_STOP: *registers[0] = core->dldi.shutdown(); break;
}
return bx(14);
}
Expand Down

0 comments on commit 77a76ff

Please sign in to comment.