ブートローダー (U-Boot) 仕様

本章では、 Armadillo-600シリーズのブートローダーである U-Boot の起動モードや利用することができる機能について説明します。

[注記]

Armadillo-200 シリーズ、400シリーズでは、ブートローダーに Hermit を使用していました。 Armadillo-600シリーズ では、他の最近の Armadillo シリーズ (Armadillo-IoT など) に合せ、U-Boot を採用しています。

U-Boot は Open Source で開発されているブートローダーで、特に組み込み機器に良く使われています。 U-Boot のマニュアルは、 Denx Software Engineering の U-Boot のページ (https://www.denx.de/wiki/U-Boot/WebHome) からアクセスできます。

9.1. U-Boot の起動モード

U-Boot はブートローダーなので、OS を起動するのが仕事です。しかし OS を起動する以外にも、いろいろと便利な機能が U-Boot には備わっています。

Armadillo-600シリーズ の U-Boot には 2つの起動モードがあります。「保守モード」と「オートブートモード」です。 Armadillo-600シリーズ に接続している USBシリアル変換アダプターのスライドスイッチによって、モードを切り替えることができます。 Armadillo-400シリーズの Hermit にもあった機能です。このモード切り換えは、 GPIO によって実現しています。 U-Boot 本家にはまだマージされておらず、 Armadillo-600シリーズ 用の U-Boot に独自実装されている機能です。

また、U-Boot バージョンat5以降では、Armadillo-600シリーズ のユーザースイッチ(SW1) [12]を押しながら [13]電源を投入した場合、スライドスイッチの状態に関係なく保守モードでブートローダーが起動します。

ブートローダーが起動すると、USBシリアル変換アダプタのスライドスイッチの状態により、2つのモードのどちらかに遷移します。USBシリアル変換アダプタのスライドスイッチの詳細については、「スライドスイッチの設定について」を参照してください。

表9.1 ブートローダー起動モード

起動モードの種別説明

保守モード

各種設定が可能なU-Bootコマンドプロンプトが起動します。

オートブートモード

電源投入後、自動的にLinuxカーネルを起動させます。


表9.2 各種スイッチの状態とブートローダー起動モード

起動モードの種別スライドスイッチユーザースイッチ [a]

保守モード

外側

押す

押さない

内側

押す

オートブートモード

押さない

[a] U-Boot バージョンat5以降のみ対応


[注記]

USBシリアル変換アダプタが未接続の場合オートブートモードとなり、Linuxが起動します。

U-Boot が起動すると、U-Boot のバージョンや、ビルド時間、CPUの情報、DRAMのサイズなどボード情報が表示されます。

U-Boot 2018.03-at8 (Feb 17 2020 - 19:19:11 +0900)

CPU:   Freescale i.MX6ULL rev1.1 at 396 MHz
Reset cause: POR
I2C:   ready
DRAM:  512 MiB
MMC:   FSL_SDHC: 0, FSL_SDHC: 1
Loading Environment from MMC... OK
In:    serial
Out:   serial
Err:   serial
PMIC: PFUZE3000 DEV_ID=0x30 REV_ID=0x11
Net:   FEC
=>

図9.1 U-Bootの起動


が U-Boot のプロンプトです。プロンプトが出るのは保守モードの時だけです。Armadillo-600シリーズ では U-Boot のプロンプトが表示され、コマンド入力を受け付ける状態を「保守モード」と呼んでいます。

9.2. U-Boot の機能

U-Boot の 機能を使うには U-Boot のコマンドプロンプトからコマンドを入力します。コマンドプロンプトは保守モードにすることで表示されます。

U-Bootの保守モードでは、U-Bootのバージョン番号を表示したり、あるメモリアドレスの値を表示したり Linuxカーネルの起動オプションの設定などを行うことができます。保守モードで利用できる有用なコマンドは、プロンプトで help と入力すると表示されます。

=> help
?       - alias for 'help'
base    - print or set address offset
bdinfo  - print Board Info structure
boot    - boot default, i.e., run 'bootcmd'
bootd   - boot default, i.e., run 'bootcmd'
bootefi - Boots an EFI payload from memory
bootm   - boot application image from memory
bootp   - boot image via network using BOOTP/TFTP protocol
clocks  - display clocks
cmp     - memory compare
config  - print .config
cp      - memory copy
crc32   - checksum calculation
dcache  - enable or disable data cache
dhcp    - boot image via network using DHCP/TFTP protocol
echo    - echo args to console
editenv - edit environment variable
env     - environment handling commands
ext2load- load binary file from a Ext2 filesystem
ext2ls  - list files in a directory (default /)
ext4load- load binary file from a Ext4 filesystem
ext4ls  - list files in a directory (default /)
ext4size- determine a file's size
ext4write- create a file in the root directory
fatinfo - print information about filesystem
fatload - load binary file from a dos filesystem
fatls   - list files in a directory (default /)
fatsize - determine a file's size
fdt     - flattened device tree utility commands
fstype  - Look up a filesystem type
fsuuid  - Look up a filesystem UUID
fuse    - Fuse sub-system
grepenv - search environment variables
help    - print command description/usage
icache  - enable or disable instruction cache
load    - load binary file from a filesystem
loadb   - load binary file over serial line (kermit mode)
loads   - load S-Record file over serial line
loadx   - load binary file over serial line (xmodem mode)
loady   - load binary file over serial line (ymodem mode)
loop    - infinite loop on address range
loopw   - infinite write loop on address range
ls      - list files in a directory (default /)
md      - memory display
md5sum  - compute MD5 message digest
meminfo - display memory information
mm      - memory modify (auto-incrementing address)
mmc     - MMC sub system
mmcinfo - display MMC info
mw      - memory write (fill)
nm      - memory modify (constant address)
part    - disk partition related commands
ping    - send ICMP ECHO_REQUEST to network host
printenv- print environment variables
reset   - Perform RESET of the CPU
run     - run commands in an environment variable
save    - save file to a filesystem
saveenv - save environment variables to persistent storage
setenv  - set environment variables
sha1sum - compute SHA1 message digest
size    - determine a file's size
strings - display strings
tftpboot- boot image via network using TFTP protocol
usb     - USB sub-system
version - print monitor, compiler and linker version
=>

図9.2 U-Bootコマンドのヘルプを表示


各コマンドのヘルプを表示するにはU-Bootコマンドのヘルプを表示のようにします。

=> help [コマンド]

図9.3 U-Bootコマンドのヘルプを表示


良く使うと思われるコマンドを以下で説明します。

boot
環境変数 bootcmd に指定されているコマンドを実行。デフォルトでは Linuxを起動。オートブートモード時はこのコマンドが呼ばれている
env
U-Boot の環境変数に関連したコマンド (下記で詳しく説明)
ext4load
Ext4ファイルシステムからファイルをメモリにロード
ext4ls
Ext4ファイルシステムにあるファイルをリスト
fuse
CPUの内部 Fuse の値の読み書き
help
コマンド一覧、または指定されたコマンドのヘルプを表示
mmc
MMC/SD 関連のコマンド群 「mmc コマンド」 で詳しく説明
ping
ICMP ECHO_REQUEST を送信
run
環境変数に登録されているコマンドの実行
tftpboot
TFTP による起動
usb
USB関連のコマンド群
version
U-Boot のバージョン番号表示

help で表示されるコマンドには、Git のようにサブコマンドを持つものがあります。 envusb などがそうです。 help env とすることで、 指定したコマンドのサブコマンドが表示されます。

9.2.1. envコマンド

=> help env
env - environment handling commands

Usage:
env default [-f] -a - [forcibly] reset default environment
env default [-f] var [...] - [forcibly] reset variable(s) to their default values
env delete [-f] var [...] - [forcibly] delete variable(s)
env edit name - edit environment variable
env exists name - tests for existence of variable
env export [-t | -b | -c] [-s size] addr [var ...] - export environment
env grep [-e] [-n | -v | -b] string [...] - search environment
env import [-d] [-t [-r] | -b | -c] addr [size] - import environment
env print [-a | name ...] - print environment
env run var [...] - run commands in an environment variable
env save - save environment
env set [-f] name [arg ...]

=>

図9.4 envコマンドのヘルプを表示


env default
環境変数をリセット
env delete
指定した環境変数を削除
env grep
指定した文字列を環境変数から検索
env print
指定した環境変数を表示します。指定が無ければ、すべて表示。 printenv コマンドと同じ
env save
環境変数を eMMC に保存。 saveenv コマンドと同じ。「U-Boot の環境変数」 で詳しく説明
env set
環境変数を設定。 setenv コマンドと同じ

9.2.2. mmc コマンド

=> mmc
mmc - MMC sub system

Usage:
mmc info - display info of the current MMC device
mmc read addr blk# cnt
mmc write addr blk# cnt
mmc erase blk# cnt
mmc rescan
mmc part - lists available partition on current mmc device
mmc dev [dev] [part] - show or set current mmc device [partition]
mmc list - lists available devices
mmc hwpartition [args...] - does hardware partitioning
  arguments (sizes in 512-byte blocks):
    [user [enh start cnt] [wrrel {on|off}]] - sets user data area attributes
    [gp1|gp2|gp3|gp4 cnt [enh] [wrrel {on|off}]] - general purpose partition
    [check|set|complete] - mode, complete set partitioning completed
  WARNING: Partitioning is a write-once setting once it is set to complete.
  Power cycling is required to initialize partitions after set to complete.
mmc setdsr <value> - set DSR register value

=>

図9.5 mmcコマンドのヘルプを表示


mmc info
現在指定されている MMCデバイスの情報を表示
mmc list
ボード上の MMCデバイスのリストを表示
mmc dev
現在指定されている MMCデバイスを表示。または指定された番号で示されるMMCデバイスを選択

9.3. U-Boot の環境変数

U-Boot は、環境変数を持つことができます。デフォルトの環境変数は、U-Boot をビルドした時に値が決定します。実行に環境変数を変更したり、変更した環境変数を保存したりすることも可能です。

env print コマンドで、現在設定されているすべての環境変数を表示できます。

=> env print
baudrate=115200
bootcmd=run setup_mmcargs; ext4load mmc 0:2 ${loadaddr} /boot/uImage; ext4load m
mc 0:2 0x83000000 /boot/${fdt_file}; bootm ${loadaddr} - 0x83000000;
bootdelay=0
enable_pf3000_lpm=no
ethact=FEC
fdt_file=a640.dtb 1
loadaddr=0x82000000
setup_bootcmd_usb=setenv bootcmd run setup_usbargs\\; usb start\\; ext4load usb
0:2 \\${loadaddr} /boot/uImage\\; ext4load usb 0:2 0x83000000 /boot/\\${fdt_file
}\\; usb stop\\; bootm \\${loadaddr} - 0x83000000\\;
setup_mmcargs=setenv bootargs root=/dev/mmcblk0p2 rootwait ${optargs};
setup_usbargs=setenv bootargs root=/dev/sda2 rootwait rw ${optargs};
stderr=serial
stdin=serial
stdout=serial
stop_nr3225sa_alarm=no;
tftpboot=tftpboot uImage; tftpboot 0x83000000 ${fdt_file}; bootm ${loadaddr} - 0
x83000000;
usbboot=run setup_bootcmd_usb; boot;

Environment size: 826/524284 bytes
=>

1

fdt_file変数のデフォルト値は、Armadillo-640では "a640.dtb"、Armadillo-610では "a610.dtb" となります。

または env print コマンドで変数を指定すると、その変数の値だけを表示することも可能です。

=> env print loadaddr
loadaddr=0x82000000
=>

新しく変数を追加したり、すでに設定されている値を変更するには env set を使います。

=> env set hello world
=> env print hello
hello=world
=> env set hello armadillo
=> env print hello
hello=armadillo
=>

不要な変数を削除するには env delete を使います。

=> env delete hello
=> env print hello
## Error: "hello" not defined
=>

環境変数を保存するには env save コマンドを使います。

=> env set hello armadillo
=> env save
Saving Environment to MMC... Writing to MMC(0)... OK
=>

....電源入れなおし....

U-Boot 2018.03-at8 (Feb 14 2020 - 10:21:57 +0900)

CPU:   Freescale i.MX6ULL rev1.1 at 396 MHz
Reset cause: POR
I2C:   ready
DRAM:  512 MiB
MMC:   FSL_SDHC: 0, FSL_SDHC: 1
Loading Environment from MMC... OK
In:    serial
Out:   serial
Err:   serial
PMIC: PFUZE3000 DEV_ID=0x30 REV_ID=0x11
Net:   FEC

=> env print hello
hello=armadillo
=>

表示された文字からも分るように、Armadillo-600シリーズでは環境変数を MMC の 0番、つまりオンボード eMMC に保存します。U-Boot の環境変数が保存される場所は、オンボード eMMC の先頭から 512 KByte オフセットです。eMMC の 1 MByte オフセットから第1パーティションが始まっているので、環境変数を保存できるのは 512 KByte になります。 eMMC のアドレスマップについては 表3.4「eMMCメモリマップ」 を参照してください。

環境変数をデフォルト値に戻したい場合は env default コマンドを使います。

=> env print bootdelay
bootdelay=0
=> env set bootdelay 1
=> env print bootdelay
bootdelay=1
=> env default bootdelay
=> env print bootdelay
bootdelay=0
=>

もし、すべての環境変数をデフォルト値に戻したい場合は、 オプション -a を付けてください。

=> env default -a
## Resetting to default environment
=>

図9.6 全ての環境変数をデフォルト値に戻す


[注記]

特定の変数は、値を変更するタイミングで U-Boot の関数が実行されます。環境変数 baudrate もそのうちの1つです。つまり値が変更されるだけでなく、実際にボーレートが変更されます。

他にも値の変更できなくなっていたり、変更回数が決まっているものもあります。環境変数 ethaddr もその1つです。それらの変数は、変更する必要はあまり無いと思いますが、もし変更する場合には U-Boot のマニュアルを参照してください。

9.4. U-Boot が Linux を起動する仕組み

U-Boot は、 boot コマンドによって、OS を起動します。 boot コマンドは、 環境変数 bootcmd に登録されているコマンドを実行するコマンドです。つまり run bootcmd と同じ意味です。

=> env print loadaddr
loadaddr=0x82000000
=> env print bootcmd
bootcmd=run setup_mmcargs; ext4load mmc 0:2 ${loadaddr} /boot/uImage; ext4load m
mc 0:2 0x83000000 /boot/${fdt_file}; bootm ${loadaddr} - 0x83000000;
=> run bootcmd
7229976 bytes read in 221 ms (31.2 MiB/s)
28291 bytes read in 55 ms (502 KiB/s)
## Booting kernel from Legacy Image at 82000000 ...
   Image Name:   Linux-4.14-at28
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    7229912 Bytes = 6.9 MiB
   Load Address: 82000000
   Entry Point:  82000000
   Verifying Checksum ... OK
## Flattened Device Tree blob at 83000000
   Booting using the fdt blob at 0x83000000
   Loading Kernel Image ... OK
   Loading Device Tree to 9eef9000, end 9ef02e82 ... OK

Starting kernel ...

環境変数 bootcmd には複数のコマンドが ; で区切られて並んでいます。 U-Boot の run コマンドは、並んでいるコマンドを順次実行していきます。

bootcmd=ext4load mmc 0:2 ${loadaddr} /boot/uImage; ext4load mmc 0:2 0x83000000 /boot/${fdt_file}; bootm ${loadaddr} - 0x83000000;

最初のコマンドは ext4load です。このコマンドは、0 番目の MMC デバイスにある、 2 番目パーティションにアクセスし /boot/uImage を、環境変数 loadaddr で指定されているメモリアドレスにロードします。コマンドで環境変数を参照するには、変数を ${…} でくくります。出荷状態では、オンボード eMMC の第2パーティションが EXT4 でフォーマットされており、 /boot/ ディレクトリに uImage というファイル名で Linux カーネルが配置されています。つまり最初のコマンドは、Linux カーネルをメモリにロードしているわけです。

=> help ext4load
ext4load - load binary file from a Ext4 filesystem

Usage:
ext4load <interface> [<dev[:part]> [addr [filename [bytes [pos]]]]]
    - load binary file 'filename' from 'dev' on 'interface'
      to address 'addr' from ext4 filesystem
=>

同じコマンドを U-Boot のプロンプトで手で実行しても、同じ動作結果になります。コマンドを1つだけ入力するときは ; を付けても付けなくても問題ありません。

=> ext4load mmc 0:2 ${loadaddr} /boot/uImage
6601520 bytes read in 206 ms (30.6 MiB/s)
=>
[注記]

Armadillo-600シリーズ では 512 MByte (0x20000000) の DRAM が 0x80000000 から 0xA0000000 までマップされています。この情報は bdinfo コマンドで確認することができます。

次のコマンドも同じく ext4load で、環境変数 fdt_file で指定されているファイルをメモリアドレス 0x83000000 にロードしている事が分ります。環境変数 fdt_file は、他の環境変数とは異なり、デフォルト値がArmadilloの起動時に決まります。Armadillo-640では fdt_file=a640.dtb 、Armadillo-610では fdt_file=a610.dtb となります。このファイルは「Device Tree Blob (dtb)」というもので、ボードのデバイス情報が記録されています。最近の Linuxカーネルでは必須のファイルです。このファイルのロードアドレスは、 uImage と異なり変数になっておらず値 (0x83000000) がそのまま記載されています。ファイルがある場所は、 uImage と同じくオンボード eMMC の第2パーティションで /boot/ です。

=> ext4load mmc 0:2 0x83000000 /boot/${fdt_file}
27838 bytes read in 55 ms (494.1 KiB/s)
=>

これで、Linuxを起動するために必要なファイル 2つ (uImagea640.dtb または a610.dtb) をメモリに配置することができました。次のコマンド bootm で実際に Linux をブートします。 bootm コマンドは、引数に 3つのアドレスを取ります。

bootm ${loadaddr} - 0x83000000

1つ目が、Linuxカーネルを置いたアドレス (${loadaddr} == 0x82000000)、2つ目が initrd のアドレスですが Armadillo-600シリーズ では使用してないので - を書きます。3つ目が Device Tree Blob を置いたアドレス (0x83000000) です。 U-Boot は Linux 以外も起動することができるので、 bootm のヘルプでは Linuxカーネルを "Application image" と記載しています。

=> help bootm
bootm - boot application image from memory

Usage:
bootm [addr [arg ...]]
    - boot application image stored in memory
        passing arguments 'arg ...'; when booting a Linux kernel,
        'arg' can be the address of an initrd image
        When booting a Linux kernel which requires a flat device-tree
        a third argument is required which is the address of the
        device-tree blob. To boot that kernel without an initrd image,
        use a '-' for the second argument. If you do not pass a third
        a bd_info struct will be passed instead
   :
   :
=>

実際に bootm コマンドを使って Linux を起動してみます。ここではあえて loadaddr ではなく 0x82000000 を入力してみます。

=> bootm 0x82000000 - 0x83000000
## Booting kernel from Legacy Image at 82000000 ...
   Image Name:   Linux-4.14-at28
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    7229912 Bytes = 6.9 MiB
   Load Address: 82000000
   Entry Point:  82000000
   Verifying Checksum ... OK
## Flattened Device Tree blob at 83000000
   Booting using the fdt blob at 0x83000000
   Loading Kernel Image ... OK
   Loading Device Tree to 9eef9000, end 9ef02e82 ... OK

Starting kernel ...

このように、手で入力しても手順さえ間違わなければ、Linux を起動することができます。もちろん uImage の場所やファイル名を変更しても、 U-Boot で正しく指定すれば同様に動作します。

9.5. U-Boot から見た eMMC / SD

起動コマンドから分るように Armadillo-600シリーズ では、オンボード eMMC が 0 番目の MMCデバイスです。これは mmc list コマンドでも確認できます。

=> mmc list
FSL_SDHC: 0 (eMMC)
FSL_SDHC: 1

MMCデバイス情報は mmc info コマンドで表示できます。 mmc info コマンドは、引数でどのデバイスかを指定するのではなく、事前に mmc dev コマンドで使うデバイスを指定しておく必要があります。

=> mmc dev
switch to partitions #0, OK
mmc0(part 0) is current device

mmc dev コマンドでデバイス番号を指定しないと、現在指定されているデバイスを表示します。

=> mmc info
Device: FSL_SDHC
Manufacturer ID: 13
OEM: 14e
Name: S0J35
Bus Speed: 52000000
Mode : MMC High Speed (52MHz)
Rd Block Len: 512
MMC version 5.1
High Capacity: Yes
Capacity: 3.5 GiB
Bus Width: 8-bit
Erase Group Size: 512 KiB
HC WP Group Size: 8 MiB
User Capacity: 3.5 GiB ENH WRREL
User Enhanced Start: 0 Bytes
User Enhanced Size: 3.5 GiB
Boot Capacity: 31.5 MiB ENH
RPMB Capacity: 4 MiB ENH
GP1 Capacity: 8 MiB ENH WRREL
GP2 Capacity: 8 MiB ENH WRREL
GP3 Capacity: 8 MiB ENH WRREL
GP4 Capacity: 8 MiB ENH WRREL

これが、オンボード eMMC の情報です。次に 1番目のデバイスを指定してみます。 microSDカードが装着されていれば、次のように表示されます。

=> mmc dev 1
switch to partitions #0, OK
mmc1 is current device
=> mmc info
Device: FSL_SDHC
Manufacturer ID: 2
OEM: 544d
Name: SA08G
Bus Speed: 50000000
Mode : SD High Speed (50MHz)
Rd Block Len: 512
SD version 3.0
High Capacity: Yes
Capacity: 7.2 GiB
Bus Width: 4-bit
Erase Group Size: 512 Bytes
=>

カードの種類によって表示される値は異なります。もし SDカードに入れている Linux カーネルを起動する場合は、先の ext4load コマンドでデバイス 1 を指定すれば良いことが分ります。

=> ext4load mmc 1:1 ${loadaddr} /boot/uImage

上記の例は、 microSD の 1番目のパーティションにある /boot/uImage をロードする例です。

9.6. Linuxカーネル起動オプション

Linuxカーネルは、ブートローダーから「カーネルパラメーター」と呼ばれる起動オプションを受けとる事ができます。U-Boot では 環境変数 bootargs に入っている文字列を Linux に渡します。

Armadillo-600シリーズ では bootargs の値は setup_mmcargs 変数の内部で一旦setenvすることで以下のように設定しています

setup_mmcargs=setenv bootargs root=/dev/mmcblk0p2 rootwait ${optargs};

この文字列で、ルートファイルシステムが /dev/mmcblk0p2 であり、mmcblk0 がみつかるまで待つ (rootwait) ように指示しています。 前述の通り Armadillo-600シリーズ では オンボード eMMC が 0 番目の MMCデバイスです。Armadillo-600シリーズでは初期出荷時に、オンボード eMMCの第2パーティションに Debian をインストールして出荷しているので 「オンボード eMMC、つまり 0番目の MMCデバイスの第2パーティション」を表わす /dev/mmcblk0p2 を指定しています。

もし microSDカードに、Debian を構築し、そのパーティションをルートファイルシステムとして指定したい場合、

=> setenv setup_mmcargs setenv bootargs root=/dev/mmcblk1p1 rootwait ${optargs};

としてください。 前述の通り microSD は 1番目の MMCデバイスなので root=/dev/mmcblk1p1 で microSD の第1パーティションという意味になります。

[注記]

Linuxカーネル起動オプション

Linuxカーネルには様々な起動オプションがあります。詳しくは、Linuxの解説書や、Linuxカーネルのソースコードに含まれているドキュメント (Documentation/kernel-parameters.txt) を参照してください。



[12] Armadiilo-610 では開発セット同梱の拡張ボード上に搭載されています。

[13] Armadillo-610 においては、拡張インターフェース(Armadillo-610: CON2)の43ピンにHighを印加している時、ユーザースイッチを押している状態と同様の挙動をします。