電源投入後からOS起動までの間に出番となるブートローダー U-BOOT というものがどんなものか、いじりながら徐々にわかってきた気がします。組込み基板系ではほぼ定番といっていいほど使われているようです。
ここでは間違いがあるかもしれませんが、わかった範囲や理解した範囲を記録しておこうと思います。
U-BOOT とは何か
電源投入後 CPU はあるプログラムを実行開始します。この実行部分はメーカーが独自に用意している部分で通常変更不可です。
その後、U-BOOT の SPL, U-BOOT 本体と順番にロードされ、最後に Linux Kernel が実行されるようになります。つまり、Linux Kernel を起動できるようにするまでの準備がUBOOTの主な役割となっているようです(実際には Linux と限らないようですが)。
変更不可といった部分はいわゆるブートROMになるのだと思います。UBOOT は組み込み版の Grub といったところでしょうか。
そして U-BOOT SPL とは、 “Secondary Program Loader” の略だそうです。
ここでは、以下の処理をやっているようです。
- DRAMなど大容量メインメモリ初期化
- シリアルIOの初期化
- タイマー/クロックの初期化
- U-BOOT の本体をロード
このSPLの実行前状態では使用できるメモリにも制限がある(チップ内蔵SRAMしか使えない)のでブートシーケンスが分かれているのは意味があります。U-BOOT 本体が使えるようになるときには、シリアル経由でコマンド操作およびログ確認できるという状態になっています。
U-BOOT 本体では、後続の OS のカーネルイメージのロードおよび実行を行います。
ここで U-BOOT 高機能なのはカーネルイメージのロード方法が色々とあるからです。
- Ethernetからロード
- Serialからのロード
- 内蔵MMCやSDカードなどフラッシュメモリからロード
簡単に見ただけでも上記のように選択可能でした。またロードする位置もメモリの番地を指定することが可能でした。ロード後はアドレス指定して実行を移すことができるようになっています。
若干 U-BOOT SPL と本体との役割切り分けが曖昧な箇所があるかもしれませんが、内部的には2段構造となっているということだけは間違いないと思います。
U-BOOTのコンソール
基板とPCをシリアルケーブルでつないで、電源投入直後のタイミングで U-BOOT のコンソール画面を操作します。モノにもよるでしょうが、時間猶予があるタイミングでキーを押すと、コンソール画面で操作可能状態となるようです。
U-BOOTにも設定パラメータがあります。これらの一覧はコマンド “printenv” で確認することができます。
また “saveenv” で設定内容を保存することができます。設定の変更は “setenv 名前 値” といった感じで行います。
開発の初期などは U-BOOT のコンソールに入るのが確実な時があります。
毎回キーをタイプするのは大変です。このときには、 autostart の設定を切ってしまうのが簡単です。
猶予時間は、 bootdelay という変数に格納されています。
これを以下のようにして -1 にすると毎回コンソールで停止します。
# setenv bootdelay -1 # saveenv
U-BOOTの在処
本家 http://www.denx.de/wiki/U-Boot/WebHome で公開されています。
GitHub にも https://github.com/u-boot/u-boot とあるのでミラーされているのかもしれません。
実際に稼働している U-BOOT はどこに格納されているかについてですが、ストレージ領域の先頭部分に格納されているようです。
手元の MIPS Creator CI20 の場合ですが、起動可能にした SDカードを作る際に以下のようにしています。
$ dd if=/dev/zero of=/dev/sdx bs=1K seek=256 count=32 $ dd if=spl/u-boot-spl.bin of=/dev/sdx obs=512 seek=1 $ dd if=u-boot.img of=/dev/sdx obs=1K seek=14
当たり前といえばそれまでですが、パーティション領域外に記録されています。これを考慮して、後続のデータ格納用パーティションを作成する必要があります。U-BOOT を記録する前の SD カードは次ののようにパーティションを作成していました。
$ sfdisk /dev/sdx -L << EOF 2M,,L EOF
先頭 2MB 分は無視して、後続の部分でパーティションを作成しています。U-BOOT のデータが大きくなった場合にはこの部分も変更が必要になると思われます。
比較: Raspberry Pi
Raspberry Pi では若干状況が異なるようです。Raspberry Pi にも U-BOOT があるようですが、上記で説明したブートROMに該当する部分が大きくなります。
というのも Raspberry Pi では電源投入後に稼働するのは GPU コアです。これが起動してから ARM CPU が有効化されるといったシーケンスとなります。
GPU が起動して CPU に制御が回ってくる間の部分に U-BOOT が挟まると思われます。
U-BOOT の前には、 bootcode.bin, loader.bin が処理されることとなるようです。この部分ある意味、ブートROM 相当して考えることができそうです。
U-BOOTの操作例
簡単ですが U-BOOT のコンソールに触れてみたいと思います。
ここでは Ubuntu と MIPS Creator CI20 をシリアル接続した環境で作業しています。
また SDカードからの起動に設定してあり、この SD カードは上記で述べた書き込みを適用したモノです。
起動直後に version まで表示させてみたものがこちらです。
今の状態を確認するために printenv を実行させてみました
今回の SDカードのパーティション領域には直接動かせるプログラムを格納しました。
このパーティション領域は ext4 でフォーマットしてあります。
これをコンソールから以下のコマンド実行で確認してみたいと思います。
ci20# ext4ls mmc 0 /
実行してみたものがこちらです。ファイルが存在していることが確認できますね。
ext4ls の他にも fatls, ubifsls といったバリエーションが存在します。
フォーマットに合わせて使い分けることができます。
なおコマンドの説明は help オプション付きで実行すると出てきます。
ext4ls の場合は、以下のような感じで出力されました.
ci20# help ext4ls ext4ls - list files in a directory (default /) Usage: ext4ls <dev[:part]> [directory] - list files from 'dev' on 'interface' in a 'directory' </dev[:part]>
プログラムを実行する その1
早速プログラムを呼び出してみたいと思います。
ここでは先ほど用意してあったファイルをロードして実行を行います。
ci20# ext4load mmc 0 0x8001000 /CI20_01_led.bin 72 bytes read in 23 ms (2.9 KiB/s)
このようにアドレスを指定してコードのバイナリをロードします。
このロードしたアドレスから実行してみます。
これには以下のコマンドを使います。
ci20# go 0x8001000 ## Starting application at 0x08001000 ...
実際にはこのプログラムはLEDをブルーに発行させるものだったので、実行すると色が変わりました。
このアドレスはプログラムで指定されていたものをそのまま使っています。
PICのビルドだったりハードウェア的に許されているのであれば、任意のアドレスに転送して実行ができると思います。
プログラムを実行する その2
先ほどの内容でも実行はできます。
ただし、SDカードなどのストレージに保存しておかなければなりません。
U-BOOT ではネットワークも使用可能なので tftptboot が使えたりします。
これにしてもサーバー側の準備が必要になるため仕組みを作るまでが少々かかります。
ここでは別の方法を紹介したいと思います。
先ほどのファイルの中に CI20_01_led.srec というファイルがありました。
これは実は SDカードの中に置くものではないです。
シリアル接続している側で使うファイルです。
この srec は、モトローラSフォーマット形式というものだそうです。
この解説はこちらが丁寧にされているので興味のある方は参照してみてください。 (2017/01/28確認 どうやらページ削除となってしまっているようです、残念)
この srec ファイルの中身をシリアルで転送するとロードまで完了という状態となります。
U-BOOT のコンソールでこのロード処理をするために、 loads コマンドを実行します。
実行すると待ち状態になるので、その後はターミナルソフト側でファイル転送コマンドで送り込むことになります。
ci20# loads ## Ready for S-Record download ...
この状態で gtkterm のメニューから “File/Send Raw file” コマンドを選び、srecのファイルを選びます。
これで処理が完了すると以下のような状態となります。
見ての通りロードが完了しています。
あとは先ほどと同じように Start Addr の番地から実行開始すればプログラムが動作します。
ci20# go 0x8001000 ## Starting application at 0x08001000 ...
プログラムの作成過程で srec 形式を作っておく必要はありますが、
SDカードの抜き差しなどが不要のため、割とおすすめできそうな方法だと考えてます。