こんにちは、Cerevoの稲垣です。
前回は、DM355のブート処理を概観し、SDカード用のブートローダ (SD-UBL) を試してエラーを起こすところまで扱いました。今回はSD-UBLを分析・修正して、実際にインストールディスクを作ってみたいと思います。
メッセージを分析
SD-UBLが出すメッセージはけっこう冗長なので保存して比較してみると、ブートモードとインストールモードではカーネル (Linux) とRAMディスクのロード先が入れ替わっていることが分かります。関係するメッセージだけ引用します:
ブート時のメッセージ: * Loading kernel sdcard_read sdc_src_addr=0x00081000 dst=0x82000000 len=0x00200000 * Loading ramdisk sdcard_read sdc_src_addr=0x00281000 dst=0x80700000 len=0x00400000 インストール時のメッセージ: * Flashing kernel sdcard_read sdc_src_addr=0x00081000 dst=0x80700000 len=0x00200000 * Flashing Root FS sdcard_read sdc_src_addr=0x00281000 dst=0x82000000 len=0x00400000
SDカードにアクセスできないU-Bootを使っていますから、ロード先が入れ替わっては起動するはずがありません。しかし、ひとまずU-Bootのパラメータをデフォルトから変更すれば起動しそうです。実際にU-Bootの自動起動を中止して起動スクリプトを書き直してやると起動しました。
ただし、このままのメモリ配置では9MiBより大きなRAMディスクをロードできません。やはりSD-UBLの修正が必要です。それでハックの方針は以下のようになります:
- Linuxとramdiskのロード先アドレスを変更する
- ロードサイズを変更する
なお、インストールモードのフラッシュ書き換え機能は、ブートメッセージによれば、TIがリリースしているユーティリティをベースにしているらしいので使いません。そのTIのユーティリティはNANDフラッシュの書き込みエラー処理とかしてないっぽいので、信用できないからです。
SD-UBLを解析する
まずはディスクイメージからSD-UBLを探します。RBLの仕様はTIが公開しているDM355のARM subsystemのデータシートに書かれていますから、RBLになったつもりでディスクイメージを見ていきます……すぐに見つかりますね。ダンプしてみると、第1セクタにUBLディスクリプタが書かれています:
00000200: 00 ed ac a1 00 01 00 00 2e 00 00 00 09 00 00 00
左から順に、マジックナンバー0xa1aced00、エントリポイントが0x100、サイズが0x2eセクタ、先頭は第9セクタ、という意味です。なおUBLはメモリ空間の0x0020にロードされるので解析には注意が必要です。
位置が分かったのでSD-UBLを切り出します:
dd if=dm355_boot.sdcard of=sd-ubl.bin bs=512 skip=9 count=$((0x2e))
逆アセンブルします:
arm_v5t_le-objdump -b binary -m arm -D sd-ubl.bin > sd-ubl.s
逆アセンブルしたソースを検索してみると、ロード元のアドレス0x41000とか0x81000を引数にして同じサブルーチンが3回ほど続けて呼ばれていることが分かります。関係する部分を引用します:
2fd8: e59f3064 ldr r3, [pc, #100] ; 0x3044 2fdc: e59f4064 ldr r4, [pc, #100] ; 0x3048 2fe0: e5932000 ldr r2, [r3] ; 0x15aa4 2fe4: e1a01004 mov r1, r4 2fe8: e1a02482 mov r2, r2, lsl #9 2fec: e3a00a41 mov r0, #266240 ; 0x41000 2ff0: ebfffe76 bl 0x29d0 3044: 00015aa4 andeq r5, r1, r4, lsr #21 3048: 81080000 tsthi r8, r0 304c: 00015594 muleq r1, r4, r5 5a84: 0000012c andeq r0, r0, ip, lsr #2
ARMのgccの関数呼び出し規約ではr0からr3が引数ですので、そっちのレジスタも見てみると、ロード先とサイズも引数として渡されているらしいことが分かります (簡単に書いてますが劇的な場面ですよ)。実にExcellentなコードですね。
0x15aa4という変なアドレスにアクセスしているので解説しておきましょう。TCMは0x00000と0x10000の両方からアクセスできるようになっているので、アドレス0x15aa4は0x5aa4と同じです。さらに、UBLのロードされるアドレスは0x00020ですから、0x15aa4へのアクセスは 0x15aa4 = 0x10000 + 0x20 + 0x5a84 と分解することができ、ソースの5a84:の部分へのアクセスになるわけです。
同様に解析するとU-Boot、Linux、ramdiskのロードがほぼ同じように書かれているらしいことが分かります。ロードする長さだけは変数としてメモリ上に置いてあります (グローバル変数なのでしょう……なぜだろう)。
バイナリパッチ
結局、具体的には以下のようにバイナリエディタでハックします (Emacsでは M-x hexl-find-file):
- Linuxとramdiskのロード先はハードコードされているので入れ替える:
- 3000: e3a01482 を e59f1054 に変更
- 301c: e59f1038 を e3a01482 に変更
- グローバル(?)変数になっているそれぞれのイメージサイズを変更する:
- 5a84: U-Bootのセクタ数
- 5a88 ramdiskのバイト数
- 5a8c Linuxのバイト数
淡々と結果だけ書いてしまいましたが、ARM命令は32bit固定長なのでバイナリパッチが簡単なのです。今回は値を入れ替えたりそのままメモリ上に変数として置いてある値を書き換えるだけなのでコードも増えませんし、PC相対のディスプレースメントだけちょっと計算すればお終いです。
あとはU-Bootの環境変数を書き換えておいて、SDカードに書き込めばインストールディスクのできあがりです。好きなインストーラが起動するように仕込みましょう:
dd of=/dev/sdc bs=512 seek=9 if=sd-ubl.bin dd of=/dev/sdc bs=512 seek=520 if=uboot.bin dd of=/dev/sdc bs=512 seek=1032 if=uImage #linux dd of=/dev/sdc bs=512 seek=5128 if=fs.bin #ramdisk
おしまい
SD-UBLがバグっているので多少バイナリパッチをしましたが、ARMのバイナリは割とハックしやすいと思います。ブートローダ程度のものなら皆さんもハックしてみてはいかがでしょうか?
著者プロフィール
最近の投稿
- 02. ソフトウェア2016.12.15[15日目] 不具合を発見したときのテストレポートの心得
- 03. 組み込み2012.09.19H.263からSparkへのトランスコーディング(上)
- 03. 組み込み2012.09.09H.263からSparkへのトランスコーディング(下)
- 03. 組み込み2009.09.02GIOChannelの使い方
One thought on “DM355のインストールディスクを作る 後編”
Comments are closed.
I read your article with great pleasure. Thank you.