組込みLinux Beaglebone Black でやってみる その3 ブートスクリプト boot.scr 記述例と作り方

boot.scrは、U-BOOTコマンドをバッチ実行するバイナリ化されたブート用スクリプトファイルです。 各転送やブートの設定を自動で実行出来るように記述します。 組込みLinuxでU-BOOTを使う場合、このboot.scrは非常に重要なのでここで少し紹介しておきます。

boot.scrの構成

  • U-BOOTシェルコマンドで記述
  • ブート用の環境変数に値設定
  • 新しい環境変数の定義と初期値設定

テキストファイルを作成

U-BOOTシェルコマンドでスクリプトとしてテキストファイルを作り、mkimageでバイナリ化する。 テキストファイル名はなんでも構いませんが、バイナリ化ファイル名はboot.scrでなければなりません。 拡張子はtxtでもcmdでもOK。 以下の例は、microSDからブートし、TFTPでホストPCからKernel ImageのuImageとデバイスツリーの.dtbをDDRにロードして、Kernelが立ち上がって、microSDの第2パーティションをファイルシステムext3のルートFSとしてマウントしています。 このページの下の方でboot.scrに変換しています。

boot_sd_tftp.cmd
echo **************Wowowo ichiri************
setenv ipaddr 192.168.27.2
setenv serverip 192.168.27.1
setenv loadaddr 0x82000000
setenv fdtaddr 0x88000000
echo ********** Booting from microSD ... *******
setenv autoload no
tftpboot ${loadaddr} uImage
tftpboot ${fdtaddr} am335x-boneblack.dtb
setenv bootargs console=ttyS0,115200n8 noinitrd rootfstype=ext3 root=/dev/mmcblk0p2 rw mem=512m debug rootwait
bootm ${loadaddr} - ${fdtaddr}

例で使われているコマンド等説明

  • echoは、画面上に文字表示させる。 ””で囲っても囲わなくてもOK。
  • setenvは、変数に値を設定。 setenv ipaddr 192.168.27.2はU-BOOTの予約環境変数のipaddrにBBBのアドレスとして設定している。 serveripも予約環境変数で、U-BOOTでtftpやnfsを使う時にサーバーのアドレスとして設定する。 これらのアドレスや環境変数はKernelが起動するとbootargs以外は引き継がない。アドレスはなくなるので初期設定シェルスクリプトで設定が必要。
  • tfptbootは、予め設定されたtftpサーバーからuImageや.dtbをtftp通信でダウンロードして、DDRの指定アドレスから格納しています。
  • bootmは、uImageと.dtbがDDRに格納されている先頭アドレスを指定して、DDRメモリからKernelを起動するコマンド。
  • ${変数名} で変数の値を代入できる。
  • 変数は、複数のコマンドを保持できる。 複数コマンドを保持する場合『;』で区切る。
  • 変数にコマンドが入っていると、run 変数名で実行することができる。

実行内容説明

  1. 行目は、正常にboot.scrが呼び出されたら、『**********Wowowo ichiri************』が表示されます。 表示されなかったら、何かの問題でboot.scrが認識されていないことになります。
  2. 行目は、自分自身(この場合BBB)のIPアドレスを示すU-BOOT予約環境変数 ipaddrにIPアドレスを設定しています。 サーバーと同じネットマスク(この場合、192.168.27)でなければなりません。
  3. 行目は、TFTPサーバーとしてのホストPC(私の場合、uBuntu PC)のLANポートのIPアドレスをU-BOOTに登録しています。 U-BOOTがBBBからTFTP通信をする時、serveripのIPアドレスでサーバーを探しに行きます。 ホストPC側でもLANポートのIPアドレスをこのserveripと同じに設定しておく必要があります。 またTFTPサーバーとしての設定が必要ですが、次の回で説明します。
boot_sd_tftp.cmd
echo **************Wowowo ichiri************
setenv ipaddr 192.168.27.2
setenv serverip 192.168.27.1
  1. 行目は、uImageをDDRにロードする先頭アドレス用のU-BOOT予約環境変数の、loadaddrに、アドレス0x82000000を設定しています。 通常、BBB用のdefconfigファイルを指定してU-BOOTをビルドするので、loadaddrには既に0x82000000、ftdaddrには0x88000000が入っているので、これらの行は書いても書かなくても構いません。 因みに、BBBの場合、DDRのベースアドレスは0x80000000と決まっており、その情報はMLOのヘッダに書かれていて、MLOのではu-boot.imgを0x80000000にロードします。 なので、余裕を持って、uImageは0x82000000に書かれるようになっていますが、u-boot.imgが肥大化したり、uImageが肥大化した時は、お互い上書きされて動作品かならないように、ロードアドレスを調整したり、不要機能を削ってイメージファイルを小さくする必要があります。
  2. 行目は、.dtbをDDRにロードする先頭アドレス用のU-BOOT予約環境変数の、ftdaddrに、アドレス0x88000000を設定しています。
  3. 行目は、『Booting from microSD』と表示します。 これでここまでは正常に実行されたことが分かります。
  4. 行目は、boot.scrで起動をかけていくので、U-BOOTに組み込まれた自動ブートをしない様に、U-BOOT予約環境変数のautoloadにnoを設定してます。
boot_sd_tftp.cmd
setenv loadaddr 0x82000000
setenv ftdaddr 0x88000000
echo ********** Booting from microSD ... *******
setenv autoload no

  1. 行目は、TFTP通信を使って、uImageファイルをダウンロードしてDDRのloadaddrのアドレスにロードします。 loadaddrは上で0x82000000で設定しています。 ${変数名}で変数内の値を取り出します。 TFTPはTrivial File Transfer Protocolで通常のTCPのFTPでなく、UDPでしょうもない(Trivial:ささいな)FTPという意味です。 しかし、サイズを軽量にしなければならないu-boot.imgでTFTPで実行できると、UARTに比べ転送速度が格段に速いので非常に重宝します。
  2. 行目は、同様に、デバイスツリーをDDRのftdaddrの値のアドレスにロードしています。
boot_sd_tftp.cmd
tftpboot ${loadaddr} uImage
tftpboot ${ftdaddr} am335x-boneblack.dtb
  1. 行目は、Kernelに引数を引き渡すことが出来る、U-BOOT予約環境変数のbootargsに各種設定をせっていしています。
    • consoleは、Kernelが立ち上がってもttyS0という名前で、115200n8設定で通信するように設定
    • noinitrdは、initrd(initramfsの前身)は使用せず、uImageだけでルートファイルシステムを立ち上げるのでinitrdを探してエラーで落ちるなとの指定。
    • rootfstypeは、マウントしたルートFSのファイルシステムはext3だと指定。(通常はext4が一番良いいのですが、私のmicroSDはext3で設定してしまったのでext3としています。) ext4だと指定は不要と思います。
    • rootはルートFSが格納されているデバイスとパーティションを示しています。 mccblk0p2はmicroSDの第2パーティション。 rwにしておかないと、書き込みが出来ず、ルートFSが立ち上がらない。 エラーログも取れない。
    • memは、Kernelにどれだけのメモリーを使っていいか指定しています。
    • debugは、Kernelが立ち上がって、ルートFS をマウントして初期化スクリプト完了まで、詳細なKernelメッセージを表示する指定です。 量産時は不要ですが、デバッグ時は助けになります。
    • rootwaitは、ルートFSをマウントする際いろいろなデバイスドライバが起動するまで時間がかかりエラーで落ちないよう、待つ指定を入れています。 すぐ起動がかかれば無視されるので、お決まりで入れておいたほうが良いです。
  2. 行目は、uImageのloadaddrと.dtbのftdaddrを指定して、メモリからブートをしています。
boot_sd_tftp.cmd
setenv bootargs console=ttyS0,115200n8 noinitrd rootfstype=ext3 root=/dev/mmcblk0p2 rw mem=512m debug rootwait
bootm ${loadaddr} - ${ftdaddr}

boot.scrバイナリファイルに変換

  • mkimageで以下の様に、boot_sd_tftp.cmdテキストファイル(ファイル名は何でも構いません)をboot.scrに変換します。
  • そして、boot.scrはMLO, u-boot.imgと一緒にmicroSDの第1パーティションにコピーします。
    • -A : architecture
    • -O : operating system
    • -C : compression type
    • -T : type
    • -a : load address
    • -e : entry point
    • -d : data file
    • -n : image nage
$ mkimage -A arm -O linux -T script -C none -a 0 -e 0 -d boot_sd_tftp.cmd boot.scr

mkimageコマンドはU-BOOTには含まれていません。 別途、aptでインストールが必要です。

$ sudo apt update
$ sudo apt install u-boot-tools  //私の場合はこちらでインストールしました。
// 又は、sudo apt install uboot-mkimage  //こっちは試していませんが、mkimageだけインストールするので少ない容量のはずです。

mkimageはboot.scr以外にも色々なイメージファイルを生成できます。 生成できるイメージタイプを以下でリストアップします。

$ mkimage -T list

boot.scr中身

バックアップを取ってからboot.scrを見ます。 boot.scrは、記述した文字列の先頭にバイナリのヘッダが追加されます。 なので中身を見ると元の文字列が見えるのでデバッグ時には便利です。  バイナリ部分を削除して文字部分を編集して、再度mkimageでboot.scrに変換するとboot.scrを編集できます。

boot.scr実行例

u-boot.imgがboot.scrを見つけて、呼び出し実行すると、以下のようなメッセージがminicomに表示されます。

Found U-Boot script /boot.scr          // Found となる                                         
734 bytes read in 4 ms (178.7 KiB/s)   // バイト数が表示される(上記のファイルとは異なるので数値は異なると思います)                                         
## Executing script at 80000000        // MLOはDDRの0x8000000にロードされboot.scrを呼び出しています                                         
**************Wowowo ichiri************                                                                                             
********** Booting from microSD ... *******                                                      
link up on port 0, speed 100, full duplex                                       
Using cpsw device                       // TIのEthernetサービスcpswが立ち上がって                                        
TFTP from server 192.168.27.1; our IP address is 192.168.27.2     //TFTPサーバーを検知して              
Filename 'uImage'.                                                              
Load address: 0x82000000                //uImageをDDRの0x82000000に転送開始したのが分かります                                      
Loading: ######################
  :
  :

(参考)その他のboot.scr if文、for文

if文

if test "${boot_target}" = "mmc0" || test "${boot_target}" = "mmc1"; then
    if run loadimage; then
       run mmcboot;
    fi
fi

for文

for boot_target in ${boot_targets};
do
    echo item ${c};
done
item 1
item 2
item 3

||で条件実行

左辺が真であれば、右辺は実行されない。 偽であれば実行される。





U-BOOTコマンド、変数一覧

その2でも紹介しましたが、上記boot.scrの参考用にここにも入れておきます。

コマンド・予約変数説明
?コマンドhelpと同じ
addrmapコマンド32bit CPU用の仮想物理メモリマップを表示する
=> addrmap
vaddr paddr size
================ ================ ================
e0000000 fe0000000 00100000
00000000 00000000 04000000
04000000 04000000 04000000
80000000 c00000000 10000000
90000000 c10000000 10000000
a0000000 fe1000000 00010000
askenvコマンド­標準入力からの入力で環境変数を設定...

=> askenv env1;echo $?
Please enter 'env1': val1
autoscrコマンドメモリ上のスクリプトの実行
baseコマンド­標準入力からの入力で環境変数を設定...
bdinfoコマンドボードの情報を表示
bootコマンドブートコマンド
bootelfコマンドELF イメージの u­boot 用アプリケーションの実行..
bootm $kernel_addr $dtb_addrコマンド指定した番地に格納されているカーネルとinitを起動させる。
//指定したKernelアドレスとdtbアドレスを指定してブートを開始する
bootm 0x82000000 - 0x88000000

OSとアプリケーションの起動
bootpコマンドBOOTP プロトコルで IPv4 アドレスを取得.
bootvxコマンド­ ELF イメージの vxWorks を起動
bootz ${loadaddr} - ${fdtaddr}コマンドbootmと同じ。zImage時に使う。
bubt ${file_name}コマンドu-bootを更新するときに使う。仕組みはtftpで$file_nameのイメージファイルを取得しFlash ROMなど適切なところにオーバライドする。 予めネットワークの設定が必要 Burn an ATF image on the Boot Nand Flash ?
cat コマンドファイル内を文字列で表示

=> cat mmc 0:1 hello
hello world
chpartコマンドアクティブパーティションの変更
cmpコマンドメモリの比較
coninfoコマンドコンソールデバイスの表示
cpコマンドメモリ間のコピー
dhcpコマンドDHCP プロトコルで IPv4 アドレスを取得
echoコマンドu-boot.imgがブートしている時に表示できる。
"ありでもなしでも動作する。 
echo ****ichiri****
echo "****ichiri****"
echpコマンドテキストを表示.
setexpr[.b, .w, .l .s] [*] [*]
setexpr[.b, .w, .l] [*]
setexpr fmt [value]...
setexpr gsub r s [t]
setexpr sub r s [t]
コマンド評価の結果により環境変数に値を書き込む

また、指定のフォーマットで値を設定する
=> setexpr foo fmt %d 0x100
=> echo $foo
256

=> setexpr foo fmt 0x%08x 63
=> echo $foo
0x00000063
cmp [.b, .w, .l, .q] addr1 addr2 countコマンドメモリの内容比較

=> cmp 0x1000000 0x101000 0xc
envコマンド環境変数操作
env default --- 指定した環境変数を初期値に戻す
env default -a --- 全ての環境変数を初期値に戻す
env delete  -- 指定した環境変数削除
env grep --- 文字列を環境変数から検索
env print --- printenvと同じ
env save --- saveenvと同じ
env set ---setenvと同じ
env import 0x80200000 No_of_bytesコマンドenv import 0x80200000 No_of_bytes
eraseコマンドフラッシュメモリの消去.
eventコマンドEVENT_SPYで発行された一覧を表示する。 デバッグ用。
もしCONFIG_EVENT_DEBUG=yでなければ、SPYのラベルは『unknown』で表示される。
exitコマンドスクリプトの終了
ext4loadコマンドext4フォーマットからファイル読み出し
fatloadコマンドfatファイルシステムからファイルを読むコマンド
flinfoコマンドファイルシステム情報の表示
for in ; do ; doneコマンドforループコマンド
=> for c in 1 2 3; do echo item ${c}; done
item 1
item 2
item 3
fpga loadb mmcコマンドu-bootからFPGAをコンフィグレーションするための変数
fsinfoコマンドフラッシュ上のファイルシステムからファイルのロード
goコマンドu­boot 用アプリケーションの実行
gpio
gpio read
gpio status [-a] [|]
コマンドGeneral Purpose IOのアクセス
gpio input:入力モード変更
gpio set:出力モード変更、出力のOn/Off
gppio clear
gpio toggle
gpio read
gpio status
help
help
コマンドhelp
imiinfoコマンドアプリケーションイメージヘッダの表示
imlsコマンドフラッシュの中にあるイメージを探す.
itestコマンド整数と文字列の比較テスト
loadコマンドファイルを読み出してデバイスに書き込み。
//SDカードのパーティション2の/boot/ディレクトリからam33x-boneblack.dtbを読み出し、DDRの0x88000000に書き込む。
load mmc 0:2 0x88000000 /boot/am33x-boneblack.dtb

またメモリから読み出してファイルに書き込むことも可能
=> load mmc 0:1 $loadaddr test.txt
260096 bytes read in 13 ms (19.1 MiB/s)
loadbコマンドシリアル経由でファイルのダウンロード(kermit モード)....
loadsコマンドシリアル経由で S レコード形式のファイルのダウンロード
loadx ?????コマンドXmodemでファイル転送?
loopコマンド指定した範囲のアドレスを読み続ける無限ループ.
lsコマンドファイルシステムの中身を一覧表示
ls [] [directory]

ls mmc 0:1
md <.オプション> $addr <$len>コマンドMemory Dump  指定したアドレスの内容を表示する

例:md.l 0xc1932588 0x500

<オプション>
b:1バイト
w:2バイト(Word)
l:4バイト(Long:default)
q:8バイト(Quadword)

<$len> 16進
0x40 (default)
mm $addrコマンドアドレス番地を指定した後に、ライトしたい内容を16進で記述
mmc指定コマンドmmc info --現在指定されているmmcデバイス情報表示
mmc list --使用できるmmcデバイス一覧表示
mmc --- で指定したデバイス表示。 番号指定でもよい。
mtestコマンド簡単なメモリのテスト
mwコマンドnm mmと同じだが、同じアドレスを終了するまで何回も変更できる。GPIOレジスタを指定して次々値を変化させるなどで便利。
nandコマンドnand メモリへのアクセス
nand erase 0x200000 0x1e0000
nand erase.part kernel
nand erase.part rootfs
nand write 0x18100000 0x200000 0x1e0000
nand write 0x18100000 kernel 0x600000
nand write.trimffs 0x18100000 rootfs $filesize
nfs コマンドNFS プロトコルでファイルをダウンロード

nfs 0x82000000 192.168.27.1:/srv/nfs/bbb/uImage
nmコマンド同一アドレスのメモリ内容を対話的に変更
pciコマンドPCI バスの一覧と、PCI コンフィグレーションスペースのアクセス.
printenv
print
コマンド変数を指定しないと、変数一覧を表示
printenv $env
print $env
コマンド変数$envを表示する。ちなみに、printとだけ打つと全部の変数が出てくる。

printenv soc //特定の環境変数を見れる
pingコマンド­ ICMP ECHO_REQUEST パケットを指定ホストに送る
protectコマンドフラッシュメモリのプロテクトの設定
rarpbootコマンド­ RARP プロトコルで IPv4 アドレスを取得
resetコマンドCPU のリセット
run $envコマンド変数内容を実行する
sleepコマンド­ 指定した秒数遅延させる
setenv $env arg
setenv $env 'arg1 arg2'
コマンド変数を$envをセットする。
setenv serverip 192.168.27.2

スペースがある場合は囲いが必要。
setenv my_own_var 'mmc list'

シェルスクリプトのように複数のコマンドを変数を入れrunで実行することもできる。 コマンドの区切りは『;』
run my_own_var

// ログメッセージの出力先指定とルートファイルシステムの場所指定
setenv bootargs console=ttyO0,115200 root=/dev/mmcblk0p2 rw //mmcblk0p2はmmc 0:2と同じだが、bootargsには/dev/mmcblk0p2で指定する。
saveenvコマンドsetenvで内容を書き換えても揮発する。これでFlash ROMなどに値が保存される 実際のセーブ先はソースコードを見る。
soundコマンドCONFIG_CMD_SOUND=y時
sound init サウンドドライバ初期化
sound playビープを鳴らす
len: 初期値1000ms
freq:初期値400Hz

testコマンドシェルライクな test の最小限の実装.
temperature list
temperature get [thermal device name]
コマンド!ERROR! C69 -> Formula Error: Unexpected operator '>'
tftpboot アドレス ファイル名コマンドtftpサーバーのtftpルートフォルダからファイルを取得して、アドレスにロードする
tftpput address size [[hostIPaddr:]filename]コマンドClientのメモリからHostにファイルを転送する。先にファイルサイズを知る必要がある。

=> load mmc 0:1 $loadaddr test.txt
260096 bytes read in 13 ms (19.1 MiB/s)
=> tftpput $loadaddr $filesize 192.168.1.3:upload/test.txt


ums [] コマンドUSBメモリにアクセス確認

devは、mmc, sata, scsi, usb, ...

CONFIG_CMD_USB_MASS_STORAGE=yが必須で、CONFIG_USB_USB_GADGET と CONFIG_BLKの設定次第
usb start
usb reset
usb stop
コマンドUSBをホストとして使う時に使用
usb info
usb storage
usb dev
usb part
usb read addr blk# cnt
usb write addr blk# cnt
versionコマンドu­boot のバージョンの表示
wget address [[hostIPaddr:]path]コマンドHTTP over TCP @Port:80

=> wget ${loadaddr} 192.168.1.254:/index.html
xxd コマンド文字列やファイルを簡単にメモリに書き込める
=> xxd mmc 0:1 hello
00000000: 68 65 6c 6c 6f 20 77 6f 72 6c 64 0a 00 01 02 03 hello world.....
00000010: 04 05
IFS予約変数Hush パーサのトークンのセパレータで
autoload予約変数bootp, dhcp, rarpboot コマンドで IP アドレスを取得したあと、自動的にファイルをダウンロードするかどうかを決める
autoscript予約変数
autostart予約変数
boudrate予約変数コンソールのボーレートを設定。
9600 | 19200 | 38400 | 57600 | 115200
初期値115200
bootaddr予約変数
bootargs予約変数OS に渡す起動パラメータを設定。
bootcmd予約変数デフォルトのカーネル起動方法を設定。
起動時に自動で実行されるコマンドを入れておく変数。 tftp $kernel_addr uImage; tftp $initrd_addr initramfs: bootm $kernel_addr $initrd_addr などと書いておけば、tftpして起動する。

bootdelay予約変数
bootfile予約変数
boot_scripts予約変数setenv boot_scripts boot.scr2
boot

初期値では、boot.scrしか見ないが、別のブートスクリプトファイル名を指定してブート出来る。 デバッグ時、boot.scrで失敗した後、U-BOOTプロンプトからバックアップのboot.scr2で起動することが出来る。
dnsip2予約変数
domain予約変数
ethact予約変数
ethaddr予約変数
eth1addr予約変数
ethprime予約変数
fileaddr予約変数
filesize予約変数
ftdaddr予約変数デバイスツリーブロブの.dtbをDDRにロードする先頭アドレス。
BBBの場合は、初期値は0x88000000
gatewayip予約変数
hostname予約変数
ipaddr予約変数自身のIPアドレス
loadaddr予約変数Linux KernelのバイナリuImageをロードする先頭アドレス
BBBの場合は、初期値は0x82000000
Zynq-7000 DDRベースアドレス
0x30000000
Zynq-UltraScale+ MPSoCとVersal ACAP DDRベースアドレス
0x20000000
loads_echo予約変数
netmask予約変数255.255.255.0でスラッシュ24と同じ意味
netentry予約変数
nfsargs予約変数
nfsbase予約変数setenv nfsbase 192.168.3.91:/usr/src/mldbox/
nvlan予約変数
preboot予約変数自動起動の前に実行するコマンドを設定
rootpath予約変数
serveripclear予約変数tftpのサーバやnfsサーバドレス設定
stdin予約変数標準入力に使うデバイスを設定
stdout予約変数標準出力に使うデバイスを設定
stderr予約変数標準エラー出力に使うデバイスを設定
verify予約変数
vlanコマンド.q:8バイト(Quadword)予約変数
uenvcmduEnv.txt専用変数uEnv.txtの最後の行に書くお決まりの変数名。
u-boot.imgはuEnv.txt内の左辺のuenvcmdを見ると、その右辺を実行していく
rootbootargs引数マウントする場所を指定
rwがないと書き込みできない
root=/dev/nfs rw
rootfsstypebootargs引数SDの第2パーティションにルートFSがあり、フォーマットがext4のとき
rootfstype=ext4

NFSにルートFSがある時
rootfstype=nfs
consolebootargs引数UARTコンソール入出力ポート名と転送Baudrateとフォーマット指定
console=ttyS0,115200n8
debugbootargs引数Kernelブート詳細メッセージ表示

コメント