Olimex CS-E9302日記 - JTAG 接続 FLASHのバックアップ

OpenOCD を使ってJTAG経由でFLASHのバックアップをとる。 要するに、FLASHメモリのダンプを開発PCのファイルに落とすのである。 RedBootだとFLASHに書き込むことはできるが、FLASHの中身を吸い出すことはできない。

openocd のマニュアルを見ると、dump_image というコマンドがある。これでFLASHの番地からデータを吸い出すことができる。

作業の前に、RedBootでFLASHのアドレスを確認しておく。

RedBoot> fis list
Name              FLASH addr  Mem addr    Length      Entry point
RedBoot           0x60000000  0x60000000  0x00040000  0x00000000
RedBoot config    0x60FC0000  0x60FC0000  0x00001000  0x00000000
FIS directory     0x60FE0000  0x60FE0000  0x00020000  0x00000000
netbsd            0x60040000  0x00200000  0x00500000  0x00200000
netbsd_install    0x60540000  0x00200000  0x00500000  0x00200000
ramdisk.gz        0x60A40000  0x00800000  0x00300000  0x00800000
zImage            0x60D40000  0x00080000  0x00140000  0x00080000

ついでにRedBootの設定も確認しておく。

RedBoot> fconfig -l
Run script at boot: true
Boot script: 
.. fis load ramdisk.gz
.. fis load zImage
.. exec -r 0x800000 -s 0x800000 -c "console=ttyAM root=/dev/ram"

Boot script timeout (1000ms resolution): 5
Use BOOTP for network configuration: false
Gateway IP address: 0.0.0.0
Local IP address: 192.168.0.93
Local IP address mask: 255.255.255.0
Default server IP address: 192.168.0.59
DNS server IP address: 0.0.0.0
Set eth0 network hardware address [MAC]: true
eth0 network hardware address [MAC]: 0x00:0x00:0x00:0x00:0x54:0x33
GDB connection port: 9000
Force console for special debug messages: false
Network debug at boot time: false

前回と同じ手順で、openocd を起動しtelnetで接続する。

$ openocd -f openocd.cfg

別の端末で telnet 実行

$ telnet 0.0.0.0 4444
...
Escape character is '^]'.
Open On-Chip Debugger
>

FLASHの全体を dump_image する前に、少しだけダンプを取ってうまくいくかどうかを確認する。試しに上の ramdisk.gz の領域の最初の20byte だけダンプしてみる。

> dump_image aaa.img 0x60a40000 20  ← 4の倍数でないと怒られる
dumped 20 byte in 0s 539us
>

ダンプしたファイルと ramdisk.gz の原本を比較する。

$ od aaa.img
0000000 067074 137671 067207 137671 107074 137671 106450 000024
0000020 106450 000024
0000024
$ od -N 20 ramdisk.gz
0000000 105437 004010 044775 044174 001400 060562 062155 071551
0000020 000153 136754
0000024

残念ながら全然違っている。

原因は、MMUがONになっているせいだと思われる。openocd が接続する前にボードのLinuxが起動して、仮想メモリが実行されて、MMUがONになっているのである。おそらく上で見たaaa.imgは、initプロセスのプロセス空間のダンプになっているのであろう。

MMUをOFFにする方法 → openocd.cfg を変更する。リセットした直後のMMUがOFFの状態で止まるようにする。

$ vi openocd.cfg
telnet 4444
gdb_port 3333
interface parport
parport_cable wiggler
jtag_device 4 0x1 0xf 0xe
daemon_startup reset   ← 変更
target arm920t little reset_init 0 ← 変更
flash bank cfi 0x60000000 0x10000000 2 2 0

再度 openocd 起動

$ openocd -f openocd.cfg ← openocd 起動

もう一度 telnetで接続して、ramdisk.gz 領域のダンプを取ってみる。

$ telnet 0.0.0.0 4444
...
Open On-Chip Debugger
>
> dump_image aaa.img 0x60a40000 20
dumped 20 byte in 0s 49548us

ダンプしたファイルと ramdisk.gz の原本を比較する。

$ od aaa.img
0000000 105437 004010 044775 044174 001400 060562 062155 071551
0000020 000153 136754
0000024
$ od -N 20 ramdisk.gz
0000000 105437 004010 044775 044174 001400 060562 062155 071551
0000020 000153 136754
0000024

今回はばっちり一致している。

(メモ:soft_reset_halt コマンドはうまくいかなかった。ダンプが全部 0 になる。)

全FLASH領域をダンプしてバックアップする。

↓ telnet 端末
> dump_image backup.img 0x60000000 0x1000000
dumped 16777216 byte in 3535s 89682us ← たったの16Mbyteだが、一時間くらいかかる

これでFLASHのバックアップがとれた。

backup.img から ramdisk.gz の部分を抜き出して原本と一致することを確認する。

ダンプイメージの中で、ramdisk.gz の開始位置は、FLASH上のアドレスからオフセット0x60000000 を差っぴいて、0xA40000=10747904である。

また、ファイルサイズは

$ ls -al ramdisk.gz
-r-xr-xr-x 1 homerun homerun 2889696 2008-07-15 15:55 ramdisk.gz

ダンプイメージから ramdisk.gz の部分を抜き出す。

$ tail -c+10747905 backup.img | head -c 2889696 > aaa.img

ここで tail コマンドの -c+ オプションは序数指定(例えば先頭は -c+1)。なので10747904+1 を指定している。

原本と比較する

$ diff aaa.img ramdisk.gz
$

OK、一致している。

(メモ) 16進数→10進変換コマンド $printf とか $((0xAA)) とか