2013年2月25日月曜日

ARM QEMUでU-Bootを動かす

ブートローダの一種であるDas U-Bootは組み込みLinuxのブートにも良く使われていて、BeagleboardをいじっていたときにはAndroidを起動するときにカーネルパラメータを渡すのによくいじっていました。今回はそのU-BoolをQEMUで動かす練習。

まずはU-BootのFTPサーバからダウンロード。続いて解凍してコンフィギュレーションしてビルドする定番の流れです。
本稿執筆時点ではu-boot-2013.01.tar.bz2までリリースされていたんですが、u-boot-2010.12.tar.bz2以降では、ビルドが失敗したり、実行がうまくいかなかったりしたので、やや古いですが上記を選んでいます。コンフィギュレーションターゲットの対応とか、ツールチェインとの相性とかが原因かと思いますが、詳しくは調べてません。


さて、できあがったバイナリを確認。
u-bootがコンパイルされたバイナリで、さらにobjdumpでセクションギャップに0xFFをフィルした上でRAWバイナリにしたのがu-boot.binでしょうか。0xFFフィルは、一つのフェイルセーフですかね。NOPとかの有効な命令だと危なそうですし。0xFFフィルは、実際のFlashメモリ内の各ビットの初期値が1であるため、無用な書き込みを減らして効率化と書き込み回数の温存を図るための「おまじない」らしいです(参考)。コメント欄でのご指摘ありがとうございました。
早速QEMUで実行してみます。
で、U-Bootのコマンド待ちになるわけですね。
printenvで環境変数一覧を表示できます。bootargsはカーネルパラメータですね。コマンド一覧はhelpで表示可能です。

で、このU-Bootのバイナリに、前回作ったinitのバイナリをマージします。そのために、リンカスクリプトを少し細工してビルドし直しておきます。
先頭アドレスの位置が0x10000から0x100000になっています。
これをmkimageコマンドを使ってU-Bootがロード可能なフォーマットに変換します。
で、先ほど作ったU-BootのRAWバイナリと一つのイメージの中にまとめます。

このイメージをQEMUで実行するわけですが、その前にマージしたinitのイメージのブートアドレスを調べておきます。
まず、statでu-boot.binのサイズを調べます。それに65536を足して16進形式で出力しています。これは、QEMUが-kernelパラメータで指定されたイメージを65536、すなわち0x10000だけオフセットした場所に配置するからです。catコマンドでtest.uimgをu-boot.binの直後に配置したので、その先頭は0x10000にu-boot.binのサイズを足したアドレスになるということです。
ではイメージを起動してみます。
起動前に調べた0x253DCの位置にあるはずのinitのイメージを確認してみます。
よさげです。ではブート。
起動しましたー!

参考情報

Using QEMU for Embedded Systems Development, Part 3 - LINUX For You
U-boot for ARM on QEMU - Balau

2 件のコメント:

  1. 通りがかりの者です。「0xFFフィル」はFLASHに書き込む際に、無用な書き込み動作を減らすためではないでしょうか。FLASHメモリは新品の状態で全バイト0xFFと聞いた事があります。違ってたらゴメンナサイ。

    返信削除
  2. コメントありがとうございます。調べましたところ、ご指摘のとおり、Flashメモリの各ビット初期値が1であることから、書き込みの効率化とFlashメモリの寿命温存のために0xFFでフィルする、というのが正しい理由のようです。ご教示ありがとうございます。

    返信削除