Monday, January 21, 2008

dldi - chishm & stub

Well, i was trying to allow SEDS to be distributed as a single .nds file, while it actually requires plenty of stubs to be installed on the flash card in order to re-load fresh updates of itself (or to return to the "runme" root program). Making sure that stubs (and runme) are downloaded on demand was quite easy, but then i stumbled upon an unexpected difficulty: DLDI patching.

As most modern linkers perform that "driver patching" automatically when loading our homebrew, we tend to forget that they even exists (especially me, since i'm owning a pre-DLDI linker that works with built-in drivers of the libfat :P). Arialia first notified me of that i was missing something in the process... Then began the hide-and-seek game with (undocumented?) process of loading and patching code with DLDI drivers.


Lick said on gbadev.org:>
Chishm has already proven that it works. His VRAM boot stub gets patched before it's executed. There's hackery involved so check its source.
me:>
thanks. I'll google that.


A bit of googling could not locate chishm's source for the NDS loader, but crawling the forum did. One of the nice things chishm does in his loader is to reuse the DLDI driver of the current binary to patch the loader (and the program to be loaded). Let's see how it works.

pDH = (data_t*)(((u32*)(&_io_dldi)) -24);
pAH = &(binData[patchOffset]);

The first entry in the IOinterfaces table is reserved for DLDI devices. Note that the DLDI patcher will *keep* this "placeholder" interface so that, once patched, the driver's description is still at _io_dldi ^_^. Moreover, right before the actual ioInterface structure, we can find a placeholder for the DLDI header, including code/data sizes, and location of the Global Offset Table required for patching.

if (*((u32*)(pDH + DO_ioType)) == DEVICE_TYPE_DLDI) {
// No DLDI patch
return false;
}

One of the tricks involved is that, if no DLDI driver is installed, the ioInterface's "type" is set at compile-time to the "DLDI" string. Once patched, it gets replaced with the vendor/product mini-id (e.g. SCSD for Supercard, securedigital or MPCF for "media player, compactflash", etc).

The rest is just going smoothly. I initially feared that the restriction of 16-bits access to the VRAM would doom the entire loading process, but obviously, it does not apply when VRAM is mapped as "LCD" (plain CPU access, offscreen). That's nice.

3 comments:

PypeBros said...

ARM9: FIFO Init
ARM7: Booting
ARM7: Ready
ARM9: FAT Init

Guru Meditation Error!
data abort!
pc: 0ffffffc addr: 0ffffffc
r0: 04000200
r1 06865960
r2 0000e000
r3 0000e880
r4 023f001c
r5 06820000
r6 00000000
r7 00000000
r8: 00000000
r9 00000000
r10 00000000
r11 00000000
r12 0b0bb910
sp 0b003cc8
lr 06861174
pc 10000004

stack : 0 06865298 0 06820000 0 0 0 0
0 6860e64 0B000000 0 0 0680164 0*

PypeBros said...

>_< i just managed to get the patched exec_stub.arm9 dumped to a file... all the edited areas are garbage :P

e.g. i have text_start = 0x0b0bb2c0 while i'd have expected 0x6865900 (from manually patched stub)...

PypeBros said...

"Position in file : 00005900
position in memory: 06865900
patch base address: 0200ff80
relocation offset : 04855980
patched successfully.