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)) とか