Tuesday, July 8, 2008

MMC hack on WRT54G v2 with OpenWrt Kamikaze 7.09

To begin with, this is definitely NOT a new hack. While there are a whole bunch of postings and howtos talking about this hack, I simply would like to share some of my own experiences and thoughts in this matter. Thus I will be referring you to other sources on particular subjects rather than stuffing this blog entry with all the details.

PRECAUTION: Hacking a piece of hardware is almost NEVER for the faint hearted.

OK, let's kick it off!

1. Hack the PCB board
Simply put, we want to connect an MMC/SD card reader to several GPIO pins on the router mainboard. This is done by soldering pins of the card reader to corresponding solder points on the board. There is a pretty detailed wiki page on how to do this:
MMC Wiki
ATTENTION: Please read carefully section "3.2. WRT54G v2.2 and WRT54GS" of the page before any soldering, even if you are working on a v2! You will need a multimeter for this project, both for finding the correct pins and for detecting short circuits.

2. Customize the firmware
Soft reboot will stop working correctly after the hack; instead it will take you to the failsafe mode. If you are just interested in a solution and don't want to wet your own feet, go to the end of this section and download my compiled firmware. The details of this bug can be found in this thread:
Reboot Bug
The idea behind the workaround proposed by migube in the thread resolves this issue -- though not until we adapt his idea to Kamikaze. In Kamikaze, instead of modifying /etc/preinit, we need modify /etc/preinit.arch, and the magic place for inserting
echo '0xb8' > /proc/diag/gpiomask
is right before the line
echo '/sbin/hotplug.failsafe' > /proc/sys/kernel/hotplug
Note that the mask "0xb8" is calculated according to the gpio mask table in MMC Wiki. You can get the modified file here:
Since during the preinit stage jffs partitions haven't been mounted yet, in order to edit this file you have to build it into the firmware and reflash your hardware. To do this all you need is the ImageBuilder package. (Thanks again to the OpenWrt team for making things so easy.)
Kamikaze ImageBuilder (i686)
Kamikaze ImageBuilder (x86_64)
Unpack the archive and cd into it. Then type make to see help information. To overwrite the original preinit.arch file and build the firmware, you do the following (assuming you are at the root of the ImageBuilder folder):
$ mkdir -p files/etc
$ cp <new_preinit.arch> files/etc/preinit.arch
$ chmod +x files/etc/preinit.arch
$ make image FILES=files
Now your new firmware should be ready in bin folder. An alternative to building it yourself is to use my compiled version, which includes four extra packages than the standard set: kmod-fs-ext3, e2fsprogs, libuuid (required by e2fsprogs), and fdisk.
At last don't forget to flash it into your box. I assume all readers of this article know how to do it.

NOTE: After a soft reboot all port leds will be lit, but I haven't noticed any undesired behaviors other than this. No workaround for this is known yet. (If you know any please comment this entry.)

3. Prepare the system
Insert an empty SD card into the reader (of course only if you are not soldering on a card directly), and put your box back into shape. Everything else from now on can be done interactively from the router shell, i.e. no wires or flashing anymore.

Boot the router, let it do all the initializations, and telnet into it. Then the first thing you need is the mmc driver. As described in MMC Wiki I recommend the optimized driver by Cyril. For WRT54G v2, you need the gpio5 version. Download and copy it to /lib/modules/2.4.34/ in your box. You also need to have kmod-fs-ext3, e2fsprogs, libuuid, and fdisk installed in your box. These are already included in my compiled firmware. Now on the router load the module:
# insmod mmc
# dmesg
A successful module init should give you something like this:
[INFO] mmc_hardware_init: initializing GPIOs
[INFO] mmc_card_init: the period of a 380KHz frequency lasts 518 CPU cycles
[INFO] mmc_card_init: powering card on. sending 80 CLK
[INFO] mmc_card_init: 80 CLK sent in 43090 CPU cycles
[INFO] mmc_card_init: resetting card (CMD0)
[INFO] mmc_card_init: doing initialization loop
[INFO] mmc_card_init: card inited successfully in 488 tries (14704842 CPU cycles).
[INFO] mmc_init: MMC/SD Card ID:
02 54 4d 53 44 35 31 32 28 8b bb 5f 90 00 81 1f [INFO] Manufacturer ID : 02
[INFO] OEM/Application ID: TM
[INFO] Product name : SD512
[INFO] Product revision : 2.8
[INFO] Product SN : 8bbb5f90
[INFO] Product Date : 2008-1
[INFO] mmc_card_config: size = 500224, hardsectsize = 512, sectors = 1000448
[WARN] mmc_init: hd_sizes=500224, hd[0].nr_sects=1000448
[INFO] mmc_card_init: set_blocklen (CMD16) succeeded !
Partition check:
mmca: p1
If you see any error in dmesg, most likely there's something wrong with your soldering. Checking for short circuits or wrong pins is all that I can suggest. As mentioned in the end of MMC Wiki, the recommended way of utilizing an external SD card is to make it your new root. ExternalMedia Wiki is an excellent guide on doing it, though not exactly working on my box. I've made some slight modifications to their method, and for clarity, I will include everything here.
# fdisk /dev/mmc/disc0/disc
(Erase the partition table and create one big partition)
# reboot
# insmod mmc
# mke2fs -j /dev/mmc/disc0/part1
# mount /dev/mmc/disc0/part1 /mnt -o noatime
# cp -a /rom/* /mnt/
# mkdir -p /etc/rc.mmc.d
Save the following file to /etc/config/bootfromexternalmedia
and the following file to /sbin/init.tmp
and the following file to /etc/rc.mmc.d/S40switch
and the following file to /mnt/etc/init.d/rcS (overwrite)
and the following file to /mnt/etc/init.d/network (overwrite)
Be sure to double check the paths before overwriting any file! Finally we are going to set the correct file permissions and activate the bootfromexternalmedia hack:
# chmod +x /sbin/init.tmp /etc/rc.mmc.d/S40switch \
/mnt/etc/init.d/rcS /mnt/etc/init.d/network
# rm /sbin/init
# mv /sbin/init.tmp /sbin/init
# sync
Unmount the card and reboot your box:
# umount /mnt
# reboot
Give it a couple of minutes and try to telnet into the box. If you see the prompt, hooray! You can now install your favorite softwares and web interfaces and everything as usual, except the HUGE boost in storage! If somehow you get stuck with the box, simply unplug and plug it, then it should deactive the bootfromexternalmedia hack and take you back to the old prompt. A log file should appear as /bootfromexternalmedia.log, indicating which service choked the system.

RATIONALE: The problem with the original approach in ExternalMedia Wiki and my WRT54G v2 is that the system got stuck at network initialization, namely the step of setup_switch. My understanding is that when initializing the network switch of this board, some gpios used are also shared with our MMC hack, which in turn causes a conflict. My proposed workaround is to move the switch initialization to an earlier time, before mounting the SD card. Simple, isn't it! I've also modified it to be more debug friendly and failure recoverable.


At last, a screenshot may give you a better idea of what will happen after this hack.