はじめに
u-bootのスタンドアロンアプリのサンプルを動かす。
ターゲットはBeagleBone Black(BBB)
ただ、BBBを使うといろいろと罠がある。
動いてるu-bootが違う
SDカードにMLOを含めてu-bootやカーネルを入れたはずなのに、UARTコンソールで表示されるu-bootのバージョンが違う。
これは 電源投入時にUSERボタンを押していない場合はeMMCに書き込まれたu-bootが起動する から。
スタンドアロンアプリの作成
u-bootとスタンドアロンアプリはYoctoで作成した。
下記を実行するとu-bootが出来上がる。
$ bitbake virtual/bootloader
それと一緒にbuild/tmp/work/beaglebone_yocto-poky-linux-gnueabi/u-boot/1_2020.01-r0/build/examples/standalone
もスタンドアロンアプリが出来上がる。
今回試すバイナリは下記。
ファイル名 | 概要 |
---|---|
hello_world | elfファイル |
hello_world.bin | バイナリファイル |
これらのファイルはSDカードのbootパーティション(FAT)に書き込む。
スタンドアロンアプリの実行
elfの実行
u-bootでelfを実行するには下記のような手順になる。
- fatからメモリにファイルをロードする
- bootelfで実行する
実際には下記のようなコマンドで実行する。
=> fatload mmc 0 82000000 hello_world => bootelf 82000000 ## Starting application at 0x80300001 ... Example expects ABI version 9 Actual U-Boot ABI version 9 Hello World argc = 0 argv[0] = "<NULL>" Hit any key to exit ..
この時点で若干の違和感はあったが、とりあえず動いた。
バイナリの実行
u-bootでバイナリを実行するには下記のような手順になる。
- fatからメモリにファイルをロードする
- goで実行する
=> fatload mmc 0 80300000 hello_world.bin => go 80300000 ## Starting application at 0x80300000 ... undefined instruction pc : [<80300008>] lr : [<9ff64457>] reloc pc : [<60b9e008>] lr : [<80802457>] sp : 9df38b18 ip : 00000000 fp : 00000002 r10: 9df4ca70 r9 : 9df41eb0 r8 : 9ffd3334 r7 : 9ff79e75 r6 : 00000002 r5 : 80300000 r4 : 9df4ca74 r3 : 80300000 r2 : 9df4ca74 r1 : 9df4ca74 r0 : 00000001 Flags: nzCv IRQs off FIQs on Mode SVC_32 Code: ffff0000 ffff0000 41f0e92d 46084605 (f000460e) Resetting CPU ...
あれ?
bootelfとgoで指定するアドレスが異なるのはbootelfではu-bootがelfを解釈してプログラムを適切な場所にロードして実行するため。 bootelfの場合はファイルをロードする場所とプログラムをロードする場所が異なっている。
goの場合は直接実行するのでプログラムが実行されるアドレスへあらかじめファイルをロードする必要がある。
プログラムが実行されるアドレスの根拠はu-bootのCONFIG_STANDALONE_LOAD_ADDR
の値。
./arch/arm/config.mk:CONFIG_STANDALONE_LOAD_ADDR = 0x80300000
しかし動かない。
動かない原因
bootelf実行時のログをよく読むと下記のようになっている。
## Starting application at 0x80300001 ...
なので、下記のように実行してみた。
=> fatload mmc 0 80300000 hello_world.bin => go 80300001 ## Starting application at 0x80300001 ... Example expects ABI version 9 Actual U-Boot ABI version 9 Hello World argc = 1 argv[0] = "80300001" argv[1] = "<NULL>" Hit any key to exit ... ## Application terminated, rc = 0x0
動く。
この1バイトなに?
よくわからなかったのでつぶやいて見たところ@ciniml先生からレスが。
Thumb2?
— Kenta IDA (@ciniml) December 9, 2020
readelfすると確かにThumb-2
だ。
ファイル属性 Tag_CPU_name: "7-A" Tag_CPU_arch: v7 Tag_CPU_arch_profile: アプリケーション Tag_ARM_ISA_use: Yes Tag_THUMB_ISA_use: Thumb-2 Tag_ABI_PCS_wchar_t: 2 Tag_ABI_FP_denormal: Needed Tag_ABI_FP_exceptions: Needed Tag_ABI_FP_number_model: IEEE 754 Tag_ABI_align_needed: 8-バイト Tag_ABI_align_preserved: 末端の SP を除き 8-バイト Tag_ABI_enum_size: int Tag_ABI_optimization_goals: Aggressive Size
アドレスの最下位ビットが1だったらとび先がThumb2だったはず。0ならARM命令。
— Kenta IDA (@ciniml) December 9, 2020
1バイトってか、フラグの1ビットだった。
まとめ
Thumb2の時はアドレス指定に注意。