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:

  1. 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*

    ReplyDelete
  2. >_< 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)...

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

    ReplyDelete

this is the right place for quickstuff