stefan's blag and stuff

Blog – 2014-07-23 – How I bricked and debricked my Linksys WRT54GL Router

Disclaimer: This is a description of how I debricked my router with a JTAG adapter. It's not a complete step by step guide but I try to include all my links and resources which I used to gather the information and tools to accomplish this. These may help you to find your own way to reanimate your device.
Disclaimer 2: This happened to me last december, but I haven't found the time to finish this article back then.

Last weekend I was trying to update the openwrt firmware on my Linksys WRT54GL v1.1 router. For the first time I used the sysupgrade utility of openwrt. It should be the same like directly using the mtd command to write the new firmware to flash, except that I will save your config files and restore it after booting the new firmware. Actually quite nice.
Enough theory back to the real stuff. I doesn't know why exactly but after executing

$ sysupgrade bin/openwrt-brcm47xx-squashfs.trx

on the device, the green power led was blinking and blinking. After some while nothing changed, so I removed the power cord (maybe I didn't waited long enough) and replugged it. Needless to say it was blinking green again, forever. Normally a flashing power led means, that the bootloader is running and will boot the firmware soon. After some time the DMZ led should light up and signal that openwrt has started. But this never happened. It was Saturday afternoon and I just made a new paperweight. Congratulations.

Table of Contents

  1. My adhoc JTAG experiment – The setup
  2. Try some other methods to restore the firmware
  3. Opening the case of a Linksys WRT54GL router
  4. Soldering the JTAG cable
  5. Running the software
  6. Flash layout and backup
  7. Flashing a new firmware

Debricking the device

-1. My adhoc JTAG experiment – The setup

Image of router, laptop and jtag

Description of the image:

  1. The PCB of the router upside down. It's connected to power, ethernet and JTAG.
  2. The just in time made JTAG cable DLC5, soldered on a breadboard.
  3. My Thinkpad X40 notebook with an old fashioned parallel port
  4. Coffee mug. Yea, it was very late last at night.
  5. The LEDs of the router. The image was taken after I successfully flashed a new firmware. Thats why the led is shining orange constantly. In the bricked state it was blinking green.

0. Try some other methods to restore the firmware

Before soldering your own JTAG-Adapter, you should try some other debrick methods which are easier and faster. They are described in the OpenWrt wiki and in DD-Wrt wiki. For example if you enabled boot_wait in the nvram configuration (that's the bootloader config) you can try to use the TFTP-Method to flash a new firmware). Needless to say, none of these methods worked anymore.
(Note: After restoring my OpenWrt firmware, I wasn't able to successfully use the TFTP-Server in the bootloader with

$ nvram set boot_wait=on
$ nvram set boot_time=10
$ nvram set wait_time=10
$ nvram commit && reboot

(see Using the TFTP method). I check the udp port 69 with nmap and the network traffic with wireshark. No reactions. It seems the bootloader isn't working correctly.)
So, what do we have: a router with a corrupted firmware and maybe with a corrupted bootloader, too. Some basic skills in soldering and the will to fix it. I've you can't open it, you don't own it.

1. Opening the case of a Linksys WRT54GL router

Opening the router may void your warranty. But flashing an openwrt firmware may have void your warranty already. Anyway. Not until I watched this youtube video, I managed to opened the case. The trick is simply stated: You have to pull very, very hard. That's it. Note: There maybe two screws below two of the four feets. Mine has none but check this first!

2. Soldering the JTAG cable

Since I wanted to restore my firmware within some hours, I have to find a simple JTAG cable and using only electronic parts which are in my toolbox already or which I can recycle them from existing projects. A simple JTAG cable for the Linksys WRT54GL router is the Xilinx DLC5 JTAG Parallel Cable III. Search for the term DLC5 on the internet and you find a lot of tutorials to build it. I used the descriptions Unbuffered Cable, Xilinx DLC5 Cable III and JTAG-adapter.
The pin layout for the jtag port on the router pcb is documented on the WRT54G Website of the OpenWrt wiki.

Every piece of equipment and software needs some sort of debugging utility and testing until it works correctly. I checked every connection of the jtag cable with a circuit analyser whether it's connected to the correct pin and hasn't any bypass with some other pin. And this was really necessary. I noticed that the connector on the breadboard wasn't connected properly. Nothing worked until I fix it.

3. Running the software

First I tried to use urjtag tool, but I couldn't successfully get an image of the flash or reflash the device. Nevertheless I will describe it here, because I may work for you and is a good starting point to test your jtag cable.
First use your favorite package manager of your distro to install the urjtag package. In gentoo it's the package dev-embedded/urjtag, in Ubuntu it's called urjtag. After that you should check your parallel port. If theres a file /dev/parport0, you have a parallel port and your kernel is configured correctly. Since I use my own vanilla kernel with my own configuration, the device /dev/parport0 wasn't there right once, although my notebook has a parallel port in the docking station and the file /dev/lp0 is available. lp0 is the device for a line printer. For the parport0 device you have to enable the kernel configuration parameter


and recompile your kernel, load the module or restart your computer.
Now you can assemble your router and your jtag cable. Plug in the power and test the connection. In a root shell execute the command jtag and the output is

$ jtag
UrJTAG 0.10 #1502
Copyright (C) 2002, 2003 ETC s.r.o.
Copyright (C) 2007, 2008, 2009 Kolja Waschk and the respective authors

UrJTAG is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
There is absolutely no warranty for UrJTAG.

WARNING: UrJTAG may damage your hardware!
Type "quit" to exit, "help" for help.


Now it's time to define your type jtag cable. I used the DLC5 (see above).

jtag> cable DLC5 ppdev /dev/parport0

If this doesn't work because you don't have a /dev/parport0 file but you have a parallel port installed, you can use the PORTADDR method like

jtag> cable DLC5 parallel 0x3bc
Initializing parallel port at 0x3bc

I found the address 0x3bc in the Linux I/O port programming mini-HOWTO.
Now cross your fingers and type the magic command detect, then urjtag will try to use the jtag cable to communicate with our router's micro processor. If this this successful, you get the following output

jtag> detect
IR length: 8
Chain length: 1
Device Id: 00000101001101010010000101111111 (0x000000000535217F)
  Manufacturer: Broadcom
    Unknown part!
    chain.c(149) Part 0 without active instruction
    chain.c(200) Part 0 without active instruction
    chain.c(149) Part 0 without active instruction

Hurray, it's working. If not, e.g. you don't get any output or something like

jtag> detect
Warning: TDO seems to be stuck at 1

check your electrical connections with a circuit analyzer. I had this problem, because a pin wasn't properly connected (see above).

The next thing I tried was to make a flash dump with urjtag. I followed this forum thread Broadcom BCM5352 support?, because they dealt with the same Device Id 0x535217F. But the detectflash command was never successful. Since I don't have enough experience with JTAG, MIPS and urjtag to debug the issue myself, I looked for another solution.

The HairyDairyMaid utility is designed to debrick WRT54G routers. It's free software and the credit goes to HairyDairyMaid (a.k.a. - lightbulb). I didn't find an official homepage, so I got the sourcecode from the DD-Wrt people. The link is
sha1sum:   a198106be5753beaf0f4e01da295eb139bf97ef2
sha256sum: 609e3f2e0c4013261b05a76e072e511f514e12e217fcc71f6df2602d8444098c

It wasn't working out of the box and I had to tweak the code a little bit. You can get my changes from the git repository

$ git clone

After compiling HairyDairyMaid you can try it with

$ ./wrt54g  -probeonly /noemw

WRT54G/GS EJTAG Debrick Utility v4.8

Probing bus ... Done

Instruction Length set to 8

CPU Chip ID: 00000101001101010010000101111111 (0535217F)
*** Found a Broadcom BCM5352 Rev 1 CPU chip ***

    - EJTAG IMPCODE ....... : 00000000100000000000100100000100 (00800904)
    - EJTAG Version ....... : 1 or 2.0
    - EJTAG DMA Support ... : Yes

Issuing Processor / Peripheral Reset ... Done
Enabling Memory Writes ... Skipped
Halting Processor ... <Processor Entered Debug Mode!> ... Done
Clearing Watchdog ... Done

Probing Flash at (Flash Window: 0x1fc00000) ... Done

Flash Vendor ID: 00000000000000000000000011000010 (000000C2)
Flash Device ID: 00000000000000000010001010101000 (000022A8)
*** Found a MX29LV320B 2Mx16 BotB      (4MB) Flash Chip ***

    - Flash Chip Window Start .... : 1fc00000
    - Flash Chip Window Length ... : 00400000
    - Selected Area Start ........ : 00000000
    - Selected Area Length ....... : 00000000


You see, it's working nicely. I had to use /noemw otherwise my router stopped working.

4. Flash layout and backup

The WRT54GL contains 4MiB of flash memory. If your OpenWrt firmware is running, you can see the flash layout with the command cat /proc/mtd. The output is

dev:    size   erasesize  name
mtd0: 00040000 00010000   "cfe"
mtd1: 003b0000 00010000   "linux"
mtd2: 002c9800 00010000   "rootfs"
mtd3: 00170000 00010000   "rootfs_data"
mtd4: 00010000 00010000   "nvram"

From this you can guess the actual flash layout

from - to              size         name
0x000000 - 0x03FFFF    0x040000     CFE
0x040000 - 0x3EFFFF    0x3b0000     Firmware (here 'linux', also called 'kernel')
0x3F0000 - 0x400000    0x010000     nvram

For further details see The OpenWrt Flash Layout in the OpenWrt wiki. CFE is the bootloader of the device (You can get the source from the broadcom site Communications Processors Downloads. It shouldn't be possible to build your own CFE binary, because the hardware vendors may include there own setup code). The CFE will read configuration variables from the nvram (e.g. the above mentioned 'boot_wait' is such a configuration parameter). You can either use the nvram utility of OpenWrt or read it with your favorite unix tools, e.g. cat /dev/mtd4ro | strings. The Firmware is the actual operating system of your router. It maybe the original firmware or a free one like OpenWrt.

Before flashing a new firmware, I took a minute and made a backup of my flash memory. I could to this with

$ ./wrt54g -backup:kernel /noemw
$ ./wrt54g -backup:cfe /noemw
$ ./wrt54g -backup:nvram /noemw

These commands created three files in the current working directory:

'KERNEL.BIN.SAVED_20131214_235857', 'CFE.BIN.SAVED_20131215_004211' and 'NVRAM.BIN.SAVED_20131215_004553'

Based on the timestamps you can guess that this procedure took more than just a minute ;-). The JTAG interfaces is quite slow. Therefore the HairyDairyMaid utility is recommending:

* Flashing the KERNEL or WHOLEFLASH will take a very long time using JTAG *
* via this utility.  You are better off flashing the CFE & NVRAM files    *
* & then using the normal TFTP method to flash the KERNEL via ethernet.   *

In my case this approach wasn't possible, because I haven't made a backup of the CFE and the nvram before the accident. Additionally the TFTP server in the bootloader wasn't working.

5. Flashing a new firmware

The last step is flashing a new firmware. First I tried to use my OpenWrt firmware, but the router didn't come up. So I decided to use the original firmware from Linksys. You can find it on the product page Linkysys WRT54GL. Here is the direct link to the file: FW_WRT54GL_4.30.16.6_US_20130308_code.bin (sha1sum: 313a977ca262a8908eab18ad8e912e128407ee33). Running the Linksys firmware on the device I used the webinterface to flash my OpenWrt firmware again. Yeah the Linksys firmware is only useful as a sophisticated flash utility to install a real OS :-).
Later I noticed that this procedure is suggested in the DD-Wrt wiki - Recover from a bad flash:

Linksys WRT54 GL:
Linksys wrt54 GL users please note that if flashing with tftp using dd-wrt firmware gives no results, original Linksys firmware from is worth trying. If that works, do a hard reset and you can continue to flash with dd-wrt.

Ok, the overall process is clear. How to use the HairyDairyMaid program to flash the Linksys firmware/kernel? First you have to convert the .bin firmware image to a trx-file. You have to remove the first 32 bytes, e.g. you can use the tool dd

$ dd bs=32 skip=1 if=FW_WRT54GL_4.30.16.6_US_20130308_code.bin of=FW_WRT54GL_4.30.16.6_US_20130308_code.trx

Then the trx-file must be flashed to the flash location 0x040000. On boot CFE will compare the checksum of the firmware. If it's correct, it will load and execute it. More information is in the OpenWrt wiki TRX vs. TRX2 vs. BIN.
To flash it you have to rename the trx-file to KERNEL.bin, because the program wrt54g uses this specific filename. There isn't a commandline parameter for that. Instead of renaming I used a symbolic link:

$ ln -s FW_WRT54GL_4.30.16.6_US_20130308_code.trx KERNEL.BIN
$ ./wrt54g -flash:kernel /noemw

Flashing with the JTAG adapter will take some time, but afterwords you have a happily running WRT54GL router again. That's it.