Some time ago I experimented with making my own custom firmwares for the Nintendo DS.
The DS firmware is stored on a 256KB rewritable flash memory chip (NVRAM).
NVRAM can be rewritten via the SPI bus on ARM 7, and in pages (256 byte chunks) only.
libnds provides abstractions for writing to NVRAM (source/arm7/firmware.c), however, the writeFirmwarePage
function is declared static
, so you can't access it. You must either remove the static
qualifier and recompile the library, or just copy the function to your project.
There is a small section at the end of the firmware which stores your username, birthday, WiFi settings, etc, that can be rewritten freely. However, the rest of the firmware (containing the ARM 7 and ARM 9 binaries, and additional data) is protected and can only be rewritten whilst the SL1 terminal is shorted.
If you have a hardware flasher like darkfader does, you can directly flash data to the NVRAM chip.
Since I didn't, I injected my custom firmwares into FlashMe, and used the modified installer to flash my firmwares for a while, but this was just a temporary solution.
I then updated Olimar's hbfirmware to be compatible with the latest versions of libnds and devkitARM instead. This worked, but was very messy code, and sound and text didn't work (so I had no idea when flashing was complete).
Finally, I wrote my own firmware flashing tool from scratch (fwManager). This tool allows you to store multiple firmwares on your flashcard under the /firmwares
directory, and flash them easily (without having to recompile an installer).
I could now flash my own code to the firmware!
Since I didn't think I'd be able to make anything better than the stock firmware, I went with a different approach, and tried to turn an old DS into a wireless gaming controller. The results are pleasing!
There is something deeply satisfying about adding some personalisation to your systems, even if it is just a minor text change (changing the carrier name of an iPhone for example).
There are 5 sections to the official DS firmwares, which are concealed behind compression and encryption, and are verified with checksums.
My main sources of code for extracting and injecting data from the firmware were fwunpack by Chishm, and Lick's firmware tool; which in turn, take code from VisualBoyAdvance, hbmenu, and probably others.
It was difficult to understand how most of it worked since they rely extensively on reverse engineered code (probably generated with Hex-Rays Decompiler).
In addition, most of the process is fairly cryptic anyway. Take a look at this for example:
r1=*(u16*)&firmware[0x14];
tmp=r1&7;
r0=*(u16*)&firmware[0x0c];
r0=r0*(4<<tmp);
tmp=(r1>>3)&7;
r2=*(u16*)&firmware[0x0e];
r2=0x2800000-r2*(4<<tmp);
Even after giving everything meaningful names, it is still somewhat confusing:
arm9romAddress = firmwareHeader->arm9romAddress * (4 << (firmwareHeader->shift & 7));
arm9ramAddress = 0x02800000 - (firmwareHeader->arm9ramAddress * (4 << ((firmwareHeader->shift >> 3) & 7)));
After clobbering together lots of code from lots of different places, I was eventually able to extract and inject data into the gui section (part 5) of the firmware. I open sourced it on GitHub: guiTool.
From there, I modified the "Touch the Touch Screen to continue" text. Tested that my firmware worked with DeSmuME, and eventually flashed it to firmware of a real DS using fwManager.