TP-Link Archer C7 v1/v2 JTAG u-boot recovery using ST-Link v2 USB adapter clone known as Baite

Recently came up with solution to use cheap chinese ST Link v2 clone JTAG adapter with MIPS CPUs, for which even supplier claimed it doesn't support MIPS (and indeed it doesn't, at least not with ST firmware and software). Support for this clone known as Baite has been added to dirtyjtag firmware which can be run with urjtag software, and from some testing it seems functional, except for missing/untested low level commands.
Since these commands are not needed for OpenOCD as the software communicates directly with SPI flash chip, I've decided to try to make it work.

As a result, here is tutorial on how to flash this Baite adapter and use it to recover Archcer C7 v1 router that had broken u-boot flashed, it is likely this will work for v2 and v3 versions, possibly for v4 and v5 but these use newer QCA956X socs and I'm not sure they even have JTAG headers on board.

Download Versaloon firmware (md5 ed4f8fee72e27a4297248d572c784583) for the adapter and flash it to the device following this procedure:

Get USB-UART adapter, in this case CP2102 was used and connect it to Baite as shown in the photo.

Plug in the USB-UART adapter to your PC and flash Versaloon firmware by issuing these commands:

Important: Do not plug in Baite adapter to USB port at this point!

stm32flash -k /dev/ttyUSB0
stm32flash -u /dev/ttyUSB0
stm32flash -o /dev/ttyUSB0
stm32flash -w Versaloon-STM32F103C8_Baite.bin -v /dev/ttyUSB0

Note: this was done on ubuntu 16.04.6, other OS may recognize USB-UART different than ttyUSB0, -k and -u parameters disable flash read/write protection, -o erases flash and -w writes firmware to it

Disconnect the USB-UART adapter from Baite and verify that the new firmware is running properly by plugging in Baite to your PC. lsusb should display 0483:a038 STMicroelectronics ID.

Disconnect Baite from PC and proceed with JTAG connection to the router. You need to connect 5 pins to the board: TCK, TMS, TDI, TDO and GND.

Wiring schematics:

Next plug in Baite to your PC, and short CS pin of the SPI flash chip on router to one of the router's GND pins. Power on router and remove the object used to short CS pin after few seconds (when ethernet LEDs go off)

Now run the actual debug program, OpenOCD:

openocd -f interface/vsllink.cfg -f target/ath79.cfg

It should display the following content:

Open On-Chip Debugger 0.10.0+dev-00916-g42cee46 (2019-06-20-15:01)
Licensed under GNU GPL v2
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html
jtag
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : Versaloon(0x22)by Simon(compiled on Jun 21 2019)
Info : USB_TO_XXX abilities: 0x00000008:0x00000083:0xC0000007
Info : clock speed 100 kHz
Info : JTAG tap: ath79.cpu tap/device found: 0x00000001 (mfg: 0x000 (<invalid>), part: 0x0000, ver: 0x0)
Info : Listening on port 3333 for gdb connections

Now open telnet session in another terminal and issue reset command to verifiy things are working:

telnet 127.0.0.1 4444
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Open On-Chip Debugger
> reset
JTAG tap: ath79.cpu tap/device found: 0x00000001 (mfg: 0x000 (<invalid>), part: 0x0000, ver: 0x0)

Issue halt command to enter debug mode:

> halt
MIPS32 with MIPS16 support implemented
target halted in MIPS32 mode due to debug-request, pc: 0xbfc005ec

Issue reset-init command to disable flash remap:

> reset init
JTAG tap: ath79.cpu tap/device found: 0x00000001 (mfg: 0x000 (<invalid>), part: 0x0000, ver: 0x0)
target halted in MIPS32 mode due to debug-request, pc: 0xbfc005ec

Try to detect SPI flash chip:

> flash probe 0
Found flash device 'win w25q64fv/jv' (ID 0x001740ef)
flash 'ath79' found at 0xbf000000

Show more info about SPI flash chip:

> flash info 0
#0 : ath79 at 0xbf000000, size 0x00800000, buswidth 0, chipwidth 0
	#  0: 0x00000000 (0x10000 64kB) protected
	#  1: 0x00010000 (0x10000 64kB) protected
	#  2: 0x00020000 (0x10000 64kB) protected
	#  3: 0x00030000 (0x10000 64kB) protected
	#  4: 0x00040000 (0x10000 64kB) protected
	#  5: 0x00050000 (0x10000 64kB) protected
	#  6: 0x00060000 (0x10000 64kB) protected
	#  7: 0x00070000 (0x10000 64kB) protected
	#  8: 0x00080000 (0x10000 64kB) protected
	#  9: 0x00090000 (0x10000 64kB) protected
	# 10: 0x000a0000 (0x10000 64kB) protected
	# 11: 0x000b0000 (0x10000 64kB) protected
	# 12: 0x000c0000 (0x10000 64kB) protected
	# 13: 0x000d0000 (0x10000 64kB) protected
	# 14: 0x000e0000 (0x10000 64kB) protected
	# 15: 0x000f0000 (0x10000 64kB) protected
	# 16: 0x00100000 (0x10000 64kB) protected
	# 17: 0x00110000 (0x10000 64kB) protected
	# 18: 0x00120000 (0x10000 64kB) protected
	# 19: 0x00130000 (0x10000 64kB) protected
	# 20: 0x00140000 (0x10000 64kB) protected
	# 21: 0x00150000 (0x10000 64kB) protected
	# 22: 0x00160000 (0x10000 64kB) protected
	# 23: 0x00170000 (0x10000 64kB) protected
	# 24: 0x00180000 (0x10000 64kB) protected
	# 25: 0x00190000 (0x10000 64kB) protected
	# 26: 0x001a0000 (0x10000 64kB) protected
	# 27: 0x001b0000 (0x10000 64kB) protected
	# 28: 0x001c0000 (0x10000 64kB) protected
	# 29: 0x001d0000 (0x10000 64kB) protected
	# 30: 0x001e0000 (0x10000 64kB) protected
	# 31: 0x001f0000 (0x10000 64kB) protected
	# 32: 0x00200000 (0x10000 64kB) protected
	# 33: 0x00210000 (0x10000 64kB) protected
	# 34: 0x00220000 (0x10000 64kB) protected
	# 35: 0x00230000 (0x10000 64kB) protected
	# 36: 0x00240000 (0x10000 64kB) protected
	# 37: 0x00250000 (0x10000 64kB) protected
	# 38: 0x00260000 (0x10000 64kB) protected
	# 39: 0x00270000 (0x10000 64kB) protected
	# 40: 0x00280000 (0x10000 64kB) protected
	# 41: 0x00290000 (0x10000 64kB) protected
	# 42: 0x002a0000 (0x10000 64kB) protected
	# 43: 0x002b0000 (0x10000 64kB) protected
	# 44: 0x002c0000 (0x10000 64kB) protected
	# 45: 0x002d0000 (0x10000 64kB) protected
	# 46: 0x002e0000 (0x10000 64kB) protected
	# 47: 0x002f0000 (0x10000 64kB) protected
	# 48: 0x00300000 (0x10000 64kB) protected
	# 49: 0x00310000 (0x10000 64kB) protected
	# 50: 0x00320000 (0x10000 64kB) protected
	# 51: 0x00330000 (0x10000 64kB) protected
	# 52: 0x00340000 (0x10000 64kB) protected
	# 53: 0x00350000 (0x10000 64kB) protected
	# 54: 0x00360000 (0x10000 64kB) protected
	# 55: 0x00370000 (0x10000 64kB) protected
	# 56: 0x00380000 (0x10000 64kB) protected
	# 57: 0x00390000 (0x10000 64kB) protected
	# 58: 0x003a0000 (0x10000 64kB) protected
	# 59: 0x003b0000 (0x10000 64kB) protected
	# 60: 0x003c0000 (0x10000 64kB) protected
	# 61: 0x003d0000 (0x10000 64kB) protected
	# 62: 0x003e0000 (0x10000 64kB) protected
	# 63: 0x003f0000 (0x10000 64kB) protected
	# 64: 0x00400000 (0x10000 64kB) protected
	# 65: 0x00410000 (0x10000 64kB) protected
	# 66: 0x00420000 (0x10000 64kB) protected
	# 67: 0x00430000 (0x10000 64kB) protected
	# 68: 0x00440000 (0x10000 64kB) protected
	# 69: 0x00450000 (0x10000 64kB) protected
	# 70: 0x00460000 (0x10000 64kB) protected
	# 71: 0x00470000 (0x10000 64kB) protected
	# 72: 0x00480000 (0x10000 64kB) protected
	# 73: 0x00490000 (0x10000 64kB) protected
	# 74: 0x004a0000 (0x10000 64kB) protected
	# 75: 0x004b0000 (0x10000 64kB) protected
	# 76: 0x004c0000 (0x10000 64kB) protected
	# 77: 0x004d0000 (0x10000 64kB) protected
	# 78: 0x004e0000 (0x10000 64kB) protected
	# 79: 0x004f0000 (0x10000 64kB) protected
	# 80: 0x00500000 (0x10000 64kB) protected
	# 81: 0x00510000 (0x10000 64kB) protected
	# 82: 0x00520000 (0x10000 64kB) protected
	# 83: 0x00530000 (0x10000 64kB) protected
	# 84: 0x00540000 (0x10000 64kB) protected
	# 85: 0x00550000 (0x10000 64kB) protected
	# 86: 0x00560000 (0x10000 64kB) protected
	# 87: 0x00570000 (0x10000 64kB) protected
	# 88: 0x00580000 (0x10000 64kB) protected
	# 89: 0x00590000 (0x10000 64kB) protected
	# 90: 0x005a0000 (0x10000 64kB) protected
	# 91: 0x005b0000 (0x10000 64kB) protected
	# 92: 0x005c0000 (0x10000 64kB) protected
	# 93: 0x005d0000 (0x10000 64kB) protected
	# 94: 0x005e0000 (0x10000 64kB) protected
	# 95: 0x005f0000 (0x10000 64kB) protected
	# 96: 0x00600000 (0x10000 64kB) protected
	# 97: 0x00610000 (0x10000 64kB) protected
	# 98: 0x00620000 (0x10000 64kB) protected
	# 99: 0x00630000 (0x10000 64kB) protected
	#100: 0x00640000 (0x10000 64kB) protected
	#101: 0x00650000 (0x10000 64kB) protected
	#102: 0x00660000 (0x10000 64kB) protected
	#103: 0x00670000 (0x10000 64kB) protected
	#104: 0x00680000 (0x10000 64kB) protected
	#105: 0x00690000 (0x10000 64kB) protected
	#106: 0x006a0000 (0x10000 64kB) protected
	#107: 0x006b0000 (0x10000 64kB) protected
	#108: 0x006c0000 (0x10000 64kB) protected
	#109: 0x006d0000 (0x10000 64kB) protected
	#110: 0x006e0000 (0x10000 64kB) protected
	#111: 0x006f0000 (0x10000 64kB) protected
	#112: 0x00700000 (0x10000 64kB) protected
	#113: 0x00710000 (0x10000 64kB) protected
	#114: 0x00720000 (0x10000 64kB) protected
	#115: 0x00730000 (0x10000 64kB) protected
	#116: 0x00740000 (0x10000 64kB) protected
	#117: 0x00750000 (0x10000 64kB) protected
	#118: 0x00760000 (0x10000 64kB) protected
	#119: 0x00770000 (0x10000 64kB) protected
	#120: 0x00780000 (0x10000 64kB) protected
	#121: 0x00790000 (0x10000 64kB) protected
	#122: 0x007a0000 (0x10000 64kB) protected
	#123: 0x007b0000 (0x10000 64kB) protected
	#124: 0x007c0000 (0x10000 64kB) protected
	#125: 0x007d0000 (0x10000 64kB) protected
	#126: 0x007e0000 (0x10000 64kB) protected
	#127: 0x007f0000 (0x10000 64kB) protected
 
ATH79 flash information:
  Device 'win w25q64fv/jv' (ID 0x001740ef)

Saving previously written u-boot area content:

> dump_image ubootbad.bin 0x9f000000 0x20000
dumped 131072 bytes in 404.372253s (0.317 KiB/s)

Remove protection from u-boot blocks in SPI flash:

> flash protect 0 0 1 off
cleared protection for sectors 0 through 1 on flash bank 0

Erase u-boot section on the flash before writing new u-boot:

> flash erase_sector 0 0 1
erased sectors 0 through 1 on flash bank 0 in 2.167238s

Write working u-boot image to the SPI flash chip:

> flash write_image uboot.bin 0xbf000000
writing 256 bytes to flash page @0x00000000
writing 256 bytes to flash page @0x00000100
writing 256 bytes to flash page @0x00000200
.....
writing 256 bytes to flash page @0x0001fc00
writing 256 bytes to flash page @0x0001fd00
writing 256 bytes to flash page @0x0001fe00
wrote 131072 bytes from file uboot.bin in 7880.783203s (0.016 KiB/s)

Now your router has restored working u-boot in the SPI flash chip, power it off, disconnect the Baite adapter, power it back on and let it boot or reflash firmware/art using tftp-serial method.

Troubleshooting:

If you get this error on openocd starting

Open On-Chip Debugger 0.10.0+dev-00916-g42cee46 (2019-06-20-15:01)
Licensed under GNU GPL v2
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html
jtag
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : Versaloon(0x22)by Simon(compiled on Jun 21 2019)
Error: (null) command 0x00 failed with 0x7f
Error: Fail to initialize usbtoxxx.

it's because versaloon have some bugs. Simply run again:

openocd -f interface/vsllink.cfg -f target/ath79.cfg

If dumping image exits to prompt

> dump_image boot.bin 0x9f000000 0x20000
 
>

it may indicate problems with JTAG wiring (unconfirmed) or bug in openocd (i've compiled master version, you can try older/stable openocd release) First several attempts to read flash this way worked for me, even with adapter khz 150, but later it always failed (no matter if set khz to 1, 10 ,50, 80 or 100), sometimes it managed to read part of flash and then the process was interrupted. Slow flash reading still works, e.g: flash read_bank 0 blk1 0x00010000 0x10000

update: adapter speeds tested thoroughly, at 300khz connection is not possible, lowered to 270khz and so far more than 10 read/write cycles completed without any data coruption (no failed attempts). at this rate it takes 3m40s to read 128KB of u-boot data and about 45 min to write (modified u-boot from @pepe2k), or somewhat less than 1h30m if writing tplink u-boot

Note: When u-boot is partially damaged (but still no output on serial console) it is required to pull CS pin of the SPI flash to GND, in order to enter JTAG mode. When u-boot is completely erased, or damaged from the first sector in flash then CS pin remains low on bootstrap (after initial transition from high to low) and it is not required to short GND pin to CS for JTAG to work.

3 Likes

Do you know wether or not we can also use non Baite ST-Link v2 clones?
Where do i get a working uboot.bin (for archer v2)?
Great tutorial and thanks a lot for your work!

if you have a software (fw) running on these that can operate with openocd there should be no problems.

u-boot should be in original firmware upgrade file

1 Like

Thanks for your fast reply! Can you hint me a little more towards finding uboot? I checked the original Firmware and used binwalker but had no luck yet. Im not an expert by any means and would be thankful if could get some more into detail about that!

Edit:Just because i hate to ask for help without any own effort, does this look like a valid uboot.bin?
https://www.file-upload.net/download-13724944/boot.bin.html
I extracted it from the original firmware bin using a hex editor.

1 Like

yes it looks valid, try to flash it

1 Like

Will do as soon as i get my ST-Link tomorrow. Probably coming back with more questions then, but even in case it works instantly ill report back to confirm v2 can be recovered the same way.

Got my adapter (which, by luck, is a Baite as well) today and flashed it. openocd starts and i can telnet, however, issuing halt will throw an error. Any ideas?

console output openocd:

sudo openocd -f interface/vsllink.cfg -f target/ath79.cfg
[sudo] Passwort für user: 
Open On-Chip Debugger 0.10.0+dev-00931-g101345270 (2019-09-19-17:30)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "jtag". To override use 'transport select <transport>'.
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : Versaloon(0x22)by Simon(compiled on Jun 21 2019)
Info : USB_TO_XXX abilities: 0x00000008:0x00000083:0xC0000007
Info : clock speed 100 kHz
Info : JTAG tap: ath79.cpu tap/device found: 0x00000001 (mfg: 0x000 (<invalid>), part: 0x0000, ver: 0x0)
Info : Listening on port 3333 for gdb connections
Info : accepting 'telnet' connection on tcp/4444
Info : JTAG tap: ath79.cpu tap/device found: 0x00000001 (mfg: 0x000 (<invalid>), part: 0x0000, ver: 0x0)
Error: Failed to enter Debug Mode!
Info : Halt timed out, wake up GDB.
Error: timed out while waiting for target halted

telnet console output:

telnet 127.0.0.1 4444      
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Open On-Chip Debugger
> reset
JTAG tap: ath79.cpu tap/device found: 0x00000001 (mfg: 0x000 (<invalid>), part: 0x0000, ver: 0x0)
> halt
Failed to enter Debug Mode!
Halt timed out, wake up GDB.
timed out while waiting for target halted

isa info not available, failed to read cp0 config register: 0
target halted in MIPS32 mode due to debug-request, pc: 0x00000000

last two lines appear upon shutting the router down.

did you short CS to GND when powerin on router?

1 Like

Yes. Should it stay low after powering on? I get ~2V between CS and GND after removing the cable i used to short it.

no, it should be around 2V after you remove cable, at least that's how it is on v1. can you put multimeter probes between CS and GND, then power the router on and tell what voltages it reads during first 5-10 seconds?

1 Like

power on -> instant: goes up to ~4V -> 0.1s 1.97V and stays like that.
Its a cheap multimeter though. ^^

Edit: Just curious, did you have the ath79.cfg included in your install of oocd? I pulled mine from git using the AUR (im on Arch) and had to add it myself, just copied it from the openwrt forum. (and added the adapter_khz because otherwise openocd would complain)

# Atheros ATH79 MIPS SoC.
# tested on AP83 and AP99 reference board
#
# source: https://forum.openwrt.org/viewtopic.php?pid=297299#p297299

if { [info exists CHIPNAME] } {
   set _CHIPNAME $CHIPNAME
} else {
   set _CHIPNAME ath79
}

if { [info exists ENDIAN] } {
   set _ENDIAN $ENDIAN
} else {
   set _ENDIAN big
}

if { [info exists CPUTAPID] } {
   set _CPUTAPID $CPUTAPID
} else {
   set _CPUTAPID 0x00000001
}

jtag_ntrst_assert_width 200
jtag_ntrst_delay 1
adapter_khz 100

reset_config trst_only

jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUTAPID

set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME mips_m4k -endian $_ENDIAN -chain-position $_TARGETNAME

$_TARGETNAME configure -event reset-init {
	# disable flash remap
	mww 0xbf000004 0x43
}

# serial SPI capable flash
# flash bank <driver> <base> <size> <chip_width> <bus_width>
set _FLASHNAME $_CHIPNAME.flash
flash bank $_FLASHNAME ath79 0xbf000000 0x01000000 0 0 $_TARGETNAME 

that might be a problem, on v1 it also spikes to 3-4V on power up, then drops to 0V for a fraction of a second and returns to ~2.7V... mine was also cheap, $10 DT9208A, but was able to capture this change

where did you put the .cfg file? don't remember now, but it seems i didn't have it, at least search for ath79 in openocd build dir throws out ath79.c only

as specified in your openocd command its looking for the file in /target (full path, at least on arch, is usr/share/openocd/scripts/target) and thats where i put it.

Just measured again, for a very short time my multimeter drops its reading between 4V and 2V to something way lower, 0.6V is what i could see. Sadly my good multimeter is broken, need to get a new one soon.

that means dropped to 0, it's just slow mm that can't update true value in such a short time, before the voltage rises again.

i checked ath79.cfg it is identical, except for adapter_khz. no idea why you need to add that here. can you post vsllink.cfg?

#
# Versaloon Link -- VSLLink
#
# http://www.versaloon.com/
#

interface vsllink

And this is the error i get from oocd when not specifying the speed: An adapter speed is not selected in the init script. Insert a call to adapter_khz or jtag_rclk to proceed.

that file should have adapter_khz 100 and below, what you're missing:
transport select jtag

doesnt change anything, despite i dont need to specify adapter_khz in ath79.cfg anymore...

try cloning and building version i've used: 0.10.0+dev-00916-g42cee46; re-check wiring also

1 Like

Same again:

Open On-Chip Debugger 0.10.0+dev-00916-g42cee465c (2019-09-19-20:35)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
adapter speed: 100 kHz

Info : auto-selecting first available session transport "jtag". To override use 'transport select <transport>'.
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : Versaloon(0x22)by Simon(compiled on Jun 21 2019)
Info : USB_TO_XXX abilities: 0x00000008:0x00000083:0xC0000007
Info : clock speed 100 kHz
Info : JTAG tap: ath79.cpu tap/device found: 0x00000001 (mfg: 0x000 (<invalid>), part: 0x0000, ver: 0x0)
Info : Listening on port 3333 for gdb connections
Info : accepting 'telnet' connection on tcp/4444
Info : JTAG tap: ath79.cpu tap/device found: 0x00000001 (mfg: 0x000 (<invalid>), part: 0x0000, ver: 0x0)
Error: Failed to enter Debug Mode!
Info : Halt timed out, wake up GDB.
Error: timed out while waiting for target halted

Sorry that it took so long, im not used to git anymore. Im also not sure why i got 00916-g42cee465c instead of 00916-g42cee46, is there any difference? Also, vsllink.cfg reverted to what i posted previously.

I double checked wiring, its everything as described.

Got it to halt!

Can you double check wether i fried my serial connector GND line or if its not connected to jtag GND at all? Im getting inf resistance between them, but used it to connect my ST-Link because i already had pins on it.