DM355のインストールディスクを作る 後編

inagaki inagaki

こんにちは、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のバイナリは割とハックしやすいと思います。ブートローダ程度のものなら皆さんもハックしてみてはいかがでしょうか?

DM355のインストールディスクを作る 後編” への1件のコメント

コメントは受け付けていません。