tools: add firmware recovery helpers
authorPaul Fertser <fercerpav@gmail.com>
Mon, 30 Dec 2013 18:33:43 +0000 (22:33 +0400)
committerSpencer Oliver <spen@spen-soft.co.uk>
Wed, 8 Jan 2014 22:18:33 +0000 (22:18 +0000)
This adds a set of helper functions with the aim to make it possible
to flash mass-market devices without RTFMing altogether (i.e. to
obsolete GPL-violating proprietary tjtag and other similar software).

Real-life tested on an RT-N16 and WRT54GL.

Change-Id: I197a9b28a5f386803f081057c4b4ebf2f9c447b1
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/1850
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
doc/openocd.texi
tcl/tools/firmware-recovery.tcl [new file with mode: 0644]

index d2a225961dabcd337fcf9910ff480bd97225b1e4..59b5b7d6805e3ba6906531e8ac304ec6aa978f24 100644 (file)
@@ -7973,6 +7973,17 @@ storage bit in the device is tested as zero and as one.
 Run all of the above tests over a specified memory region.
 @end deffn
 
+@section Firmware recovery helpers
+@cindex Firmware recovery
+
+OpenOCD includes an easy-to-use script to faciliate mass-market
+devices recovery with JTAG.
+
+For quickstart instructions run:
+@example
+openocd -f tools/firmware-recovery.tcl -c firmware_help
+@end example
+
 @node TFTP
 @chapter TFTP
 @cindex TFTP
diff --git a/tcl/tools/firmware-recovery.tcl b/tcl/tools/firmware-recovery.tcl
new file mode 100644 (file)
index 0000000..718de0b
--- /dev/null
@@ -0,0 +1,108 @@
+echo "\n\nFirmware recovery helpers"
+echo "Use -c firmware_help to get help\n"
+
+set known_boards {
+    "asus-rt-n16               ASUS RT-N16"
+    "linksys-wrt54gl           Linksys WRT54GL v1.1"
+}
+
+proc firmware_help { } {
+    echo "
+Your OpenOCD command should look like this:
+openocd -f interface/<jtag adapter>.cfg -f tools/firmware-recovery.tcl -c \"<commands>*; shutdown\"
+
+Where:
+<jtag adapter> is one of the supported devices, e.g. ftdi/jtagkey2
+<commands> are firmware-recovery commands separated by semicolon
+
+Supported commands:
+firmware_help                  get this help
+list_boards                    list known boards and exit
+board <name>                   select board you work with
+list_partitions                        list partitions of the currently selected board
+dump_part <name> <filename>    save partition's contents to a file
+erase_part <name>              erase the given partition
+flash_part <name> <filename>   erase, flash and verify the given partition
+ram_boot <filename>            load binary file to RAM and run it
+adapter_khz <freq>             set JTAG clock frequency in kHz
+
+For example, to clear nvram and reflash CFE on an RT-N16 using TUMPA, run:
+openocd -f interface/ftdi/tumpa.cfg -f tools/firmware-recovery.tcl \\
+       -c \"board asus-rt-n16; erase_part nvram; flash_part CFE cfe-n16.bin; shutdown\"
+\n\n"
+    shutdown
+}
+
+# set default, can be overriden later
+adapter_khz 1000
+
+proc get_partition { name } {
+    global partition_list
+    dict get $partition_list $name
+}
+
+proc partition_desc { name } { lindex [get_partition $name] 0 }
+proc partition_start { name } { lindex [get_partition $name] 1 }
+proc partition_size { name } { lindex [get_partition $name] 2 }
+
+proc list_boards { } {
+    global known_boards
+    echo "List of the supported boards:\n"
+    echo "Board name\t\tDescription"
+    echo "-----------------------------------"
+    foreach i $known_boards {
+       echo $i
+    }
+    echo "\n\n"
+}
+
+proc board { name } {
+    script [find board/$name.cfg]
+}
+
+proc list_partitions { } {
+    global partition_list
+    set fstr "%-16s%-14s%-14s%s"
+    echo "\nThe currently selected board is known to have these partitions:\n"
+    echo [format $fstr Name Start Size Description]
+    echo "-------------------------------------------------------"
+    for {set i 0} {$i < [llength $partition_list]} {incr i 2} {
+       set key [lindex $partition_list $i]
+       echo [format $fstr $key [partition_start $key] [partition_size $key] [partition_desc $key]]
+    }
+    echo "\n\n"
+}
+
+# Magic to work with any targets, including semi-functional
+proc prepare_target { } {
+    init
+    catch {halt}
+    catch {reset init}
+    catch {halt}
+}
+
+proc dump_part { name filename } {
+    prepare_target
+    dump_image $filename [partition_start $name] [partition_size $name]
+}
+
+proc erase_part { name } {
+    prepare_target
+    flash erase_address [partition_start $name] [partition_size $name]
+}
+
+proc flash_part { name filename } {
+    prepare_target
+    flash write_image erase $filename [partition_start $name] bin
+    echo "Verifying:"
+    verify_image $filename [partition_start $name]
+}
+
+proc ram_boot { filename } {
+    global ram_boot_address
+    prepare_target
+    load_image $filename $ram_boot_address bin
+    resume $ram_boot_address
+}
+
+echo ""