実際に、BBBをmicroSDカードからブートし、TFTP転送でKernelイメージのuImageとデバイスツリーのam355x-boneblack.dtbをホストPCからダウンロードして起動してみます。 TFTPとNFSが出来ると、一度U-BOOTのboot.scrでのブート手順が決まれば、microSDカードを抜き差しをせずに、ホストPCだけで作業が出来るようになります。 microSDカードはスロットもカード自体も強くなく、一日何十回も繰り返し挿抜を繰り返すとスロットもエラーを起こしやすくなる可能性があります。
Ethernetを使った起動
Ethernet起動では、ブート時にEthernet経由でLinuxイメージやルートファイルなど転送します。 Ethernetの転送でもいろいろ転送があるけど、TFTPが軽快で良いみたい。 通常のAckのやり取りがあるTCP/IPでなく、TFTPはAckのないUDP/IPで通信する方法。 U-BOOTはTFTP機能が搭載されているので、Linux Kernelが立ち上がる前に、U-BOOTのu-boot.imgがBBBのmicroSD内あればTFTP転送できる。 ここではTFTP転送でのブートをしてみる。 ホストPC側にはFTPサーバーと同様にTFTPのサーバーを設定しておく必要がある。
Ethernetでの転送プロトコル種類
- TFTP —- Trivial FTP —U-BOOTに搭載されているのでこれを使います
- HTTP
- FTP
- NFS — U-BOOTに搭載されていますが、その7でKernel起動後にKernel組込ドライバからNFSを使います。
- SMTP
- etc
TFTP ブート
U-BOOT(u-boot.img) がtftp通信をサポートしているのでuImageと.dtbファイルを転送してブートする。
ここでは『その1』でダウンロードしたファイルを使います。
- MLO
- u-boot.img
- uImage
- am335x-boneblack.dtb
- initramfs
- ルートファイルシステム
microSDカード
以下の3つのファイルをmicroSDのfat16 フォーマットでbootフラグがついている/BOOT/第1パーティション入れて、BBBに挿入する。 この時、第2パーティションの/ROOFS/には、前回のままルートファイルシステムが入っている状態です。
- MLO —- U-BOOTをビルドした時に生成
- u-boot.img—- U-BOOTをビルドした時に生成
- boot.scr
microSDの/BOOT/パーティションから、以下ファイルを削除しておきます。
- am33x-boneblack.dtb
- uImage
- initramfs —- これは『その1』で入れてませんが、存在しないことを確認。
ホストPCの/var/lib/tftpboot/
ホストPC(uBuntu)の/var/lib/tftpboot/がホストPCのtftpサーバーのルートディレクトリとします。 このディレクトリに以下のファイルを入れます。 * /var/lib/tftpboot/は自動的に設定される場合もあるみたいですが、私の場合は/etc/xinetd.d/tftpにserver_argでルートとして設定する必要がありました。
- am33x-boneblack.dtb
- uImage
- initramfs —- 以下作り方を参照ください『initramfsの作り方』。『initframfsとは』
- BBB内のROMからmicroSDにMLOを探しに行く
- MLOが起動して
- u-boot.imgをDDRの先頭にロードして起動する
- boot.scrの記述を実行して
- ホストPCのIPアドレスとディレクトリアドレスとTFTPプロトコルを使ってホストPCから以下のファイルを順番にダウンロードして、boot.scrで指定したDDRアドレスに配置する
- boot.scrに書かれたDDRのアドレスを元にブートする
LANケーブル接続
BBBのLANポートとuBuntu PCのLANポートを接続します。
ホストPC(uBuntu)でTFTPサーバーのインストール〜設定〜起動
- xinetd、tftp、tftpdのインストール(以下、下のコード参照)
- /etc/xinetd.d/tftpにtftpの設定
- service tftp内の、server_args = -s /var/lib/tftpboot がtftpのルートディレクトリ指定
- ホストPCとBBBのをLAN接続する
- ホストPCのIPアドレスを設定する。 ifconfigでLANの調べて、ifconfig <LAN名> <IPアドレス>で設定する。 私のPCではLAN名はenp4s0でした。
- これらを以下の様に実行していきます。
uBuntu $ sudo apt install xinetd tftp tftpd uBuntu $ sudo vi /etc/xinetd.d/tftp //以下を記述する。 ディレクトリは先に作成する。 service tftp { protocol = udp port = 69 socket_type = dgram wait = yes user = nobody server = /usr/sbin/in.tftpd server_args = -s /var/lib/tftpboot } // TFTPサーバーのルートディレクトリ準備 uBuntu $ sudo mkdir -p /var/lib/tftpboot // /var/lib/tftpboot/ に このシリーズの『その1』ダウンロードした、tftpboot用のuImage, initramfs, am335x-boneblack.dtb を入れておく uBuntu $ cd ~/BBB_Workspace/EmbeddedLinuxBBB/pre-built-images/tftp-boot uBuntu $ sudo cp -r * /var/lib/tftpboot/ uBuntu $ sudo chmod -R 777 /var/lib/tftpboot uBuntu $ sudo chown -R nobody /var/lib/tftpboot uBuntu $ systemctl status xinetd //tftp動作状態の確認 uBuntu $ service xinetd stop //tftp停止 uBuntu $ service xinetd start //tftp動作再起動して、service tftpの/var/lib/tftpbootを確実に反映させる。 uBuntu $ ifconfig //これでLANポートの名前を調べる。 enp4s0 eth0 みたいな感じ。 wifiはwlp2s0みたいな感じ uBuntu $ sudo ifconfig enp4s0 192.168.27.1 //ifconfigでIPアドレス設定は仮設定なので、すぐ消える場合がある
minicomでU-BOOTで1コマンドずつ実行
そして、もう一つのコマンドプロンプトを開いて、minicomを立ち上げて、1行ずつ実行していきます。 1行ずつ実行するのは、動作の確認やデバッグ等で非常に有効なのでここで慣れておきましょう。 今回はまず1行ずつ実行し、U-BOOTコマンド実行にも慣れ、ブートの順番も理解していきます。
- (BBBとホストPCはUARTーUSBで接続されている状態で)sudo minicomを立ち上げて、ホストPC半角モードにして、minicomにフォーカスがあたっている状態で、
- BBBのS3(POWER)を長押しして電源を切る。
- uBuntuからmicroSDをumount(eject)して、BBBに装着する。
- S2(BOOT_SEL)を押し続けながら、S3(POWER)を押して、すぐホストPCのスペースキーを押しっぱなしにして、minicomでU-BOOTコマンドプロンプトに入る。
- プロンプトは『U-BOOT>』と表示されるか、私の場合は単に『=>』の表示となりました。
- 下のコードを1行づつ実行する。『BBB =>』はminicomでBBB側の設定という意味で、『BBB』とは表示されません。
//minicomを立ち上げて、BBB の電源を入れて、minicomで半角スペースを押しっぱなしにしてu-bootコマンドプロンプトにはいる BBB => setenv serverip 192.168.27.1 // uBuntuのLANに設定したIPアドレスと同じ BBB => setenv ipaddr 192.168.27.2 // uBuntuのLANに設定したネットマスク部は同じで、一番右の数字違い BBB => ping 192.168.27.1 // これでuBuntuとの接続確認 BBB => tftpboot 0x82000000 uImage //memory(DDR)アドレス0x82000000にuImageを書き込む BBB => tftpboot 0x88000000 am335x-boneblack.dtb //memory(DDR)アドレス0x88000000にam335x-boneblack.dtbを書き込む BBB => tftpboot 0x88080000 initramfs //memory(DDR)アドレス0x88080000にinitramfsを書き込む BBB => setenv bootargs console=ttyO0,115200 root=/dev/ram0 rw initrd=0x88080000 bootwait BBB => bootm 0x82000000 0x88080000 0x88000000 //memory(DDR)からのブート
立ち上がりました。 このようになれば成功で『その4』は完了です。 因みに、下の図でChangedとなっているのはルートFS の/etc/issueファイルを変更したからです。
参考:BBBのボタンの場所
boot.scrを準備
- 次は、boot.scrを使って、動作した上記のtftp経由でのブートの自動化をしていきます。
- U-BOOT-2021以降は、boot.scrは何も設定しなくても認識しましたがた、uEvn.txtはbootfileに=uEnv.txtと書き込んでも認識してくれませんでした。
- boot.scrはU-BOOTの予約環境変数で、boot_scripts=boot.scr.uimg boot.scr 様に指定されているので実行されます。
- boot.scrは、u-boot.imgが起動後に呼び出されて実行されるバイナリのスクリプト。
- まず、テキストエディタを使ってU-BOOTコマンドプロンプト形式で以下のテキストファイルを作成します。 拡張子は.cmdでも.txtでも構まいません。
echo **************boot_sd started************ setenv ipaddr 192.168.27.2 setenv serverip 192.168.27.1 echo ********** Booting from microSD ... ******* setenv autoload no tftpboot 0x82000000 uImage tftpboot 0x88000000 am335x-boneblack.dtb tftpboot 0x88080000 initramfs setenv bootargs console=ttyS0,115200 root=/dev/ram0 rw initrd=0x88080000 bootwait mem=512m debug rootwait bootm 0x82000000 0x88080000 0x88000000
boot.scrバイナリファイルに変換
boot_sd_tftp.cmdのあるディレクトリで以下を実行して、boot.scrを生成します。 ファイル名はboot.scrでなければなりません。
$ mkimage -A arm -O linux -T script -C none -a 0 -e 0 -d boot_sd_tftp.cmd boot.scr
mkimageは予めuBuntuにインストールしておかなければなりません。
$ sudo apt update $ sudo apt install uboot-mkimage // これか $ sudo apt install uboot-tools // これ。 これはmkimage以外のツールもインストール。
boot.scrで実行
microSDの/BOOT/にboot.scrをコピーする。 私の場合、SDカードをuBuntuに挿入すると、自動的に/media/ichiri/BOOT/と/media/ichiri/ROOFS/がマウントされるので、以下のようにコピー。 マウントの仕方は、『その1』参照ください。 dmesgでSDデバイス名を特定して、/mntか/media上にmoutすればOKです。
$ cp boot.scr /media/ichiri/BOOT/
microSDの/BOOT/に、uImage, am335x-boneblack.dtb.dtb、initramfsが存在しないことを確認。
tftpでダウンロード出来ない時の確認事項
- ダウンロードするファイルの所有(nobody)とアクセス権(777)を確認
- 次はuBuntu PCのLAN portのIPアドレス確認。 ちゃんとBBBで設定したserveripと同じになっているか確認。 違っていたら、sudo ifconfigを使ってuBuntu PCのLANのIPアドレスを設定する。 ifconfigはIPアドレスの仮設定なので、uBuntuを起動した時はまた設定しなければなりません。 そして、何度も接続するまでは、数分で消えてしまうので、何度も設定し直しが必要です。
- tftp serviceが動作している確認。
systemctl status xinetd
その他
intramfsを使わない場合のboot.scr例
intramfsも使わないのでnointrd。 ルートFSは、microSDに入っているので、root=/dev/mmcblk0p2となる。
echo **************boot_sd started************ 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}
tftp経由でファイルを取得
上記ではU-BOOTコマンドプロンプトでtftpbootコマンドでファイルを取得し、メモリ(DDR)の指定アドレスに格納した。 ここではtftpbootコマンドでなく、Linuxのコマンドプロンプトからtftpコマンドでファイルを取得しこのコマンドを実行したディレクトリにファイルを格納する。
BBB # tftp -r ichiri.txt -g 192.168.27.1 //これで ホストPCの/var/lib/tftpboot/からファイルをとってこれる。 tftpbootコマンドはu-bootのコマンド。 Linuxコマンドはtftpで、相手のIPアドレスの指定が必要。 //tftp: sendto: Network is unreachable が出たら、ifconfigでLANポートのipアドレス設定する
その他 シリアル(UART)
ボードにEthernetがない場合などに有効。 U-BOOTがシリアル通信をサポートしているので転送できる。 実際やっていないので不備があるかもしれませんが、今後使うときのために調べたことを載せておきます。
- BBBの場合、USB電源で供給せず、電源アダプターで供給し、SDを抜いて、S2を押しながら電源を入れると、UARTで転送できる。(BBBはUART転送時、4.5分以内でBOOTすれば良い)
- S2を押して起動すると、SPI0〜MMC0〜USB0~UART0の順番で起動しようとします。 UARTブート時、USB電源で供給出来ないのは、USB電源ポートもUSB機能があり、USB0となっています。 なので、UART0より先にUSB0でブートしようとしてUART0でブート出来ないからです。
- 115200,8n1
- RAMDISK or initramfs @0x88080000
- ROMブートローダーはUART経由でXmodemプロトコルでSPL(u-boot-spl.bin)を受け取るのを待つ。
- ボード上でSPLが実行されu-boot.imgを受け取るのを待つ。(*もしXmodem転送で問題があれば、Ymodemでu-boot.imgを転送する by TI)
- ボード上でu-bootが起動したら、U-BOOTコマンドを使えるので、XmodemかYmodemで他の全てのブートイメージでDDRメモリーに転送する。
- tftpboot 0x82000000 uImageそしてubootコマンドboot(bootcmd in uEnv.txt)でブートする。
- 転送必要イメージファイル
- am33x-boneblack.dtb
- initramfs
- u-boot.img —一般的なu-boot。 SDからの起動でもどんな時でも使用
- u-boot-spl.bin —2nd stage bootloader, MLOはSDやeMMC起動の場合のみ。SDやeMMCがない状態でUARTで起動する際はこのファイルを使う。 U-BOOTをビルドする時に生成される。
- uImage —U-BOOTを使用する時のkernel image。 uImage = zImage + U-BOOT用ヘッダ
- https://github.com/niekiran/EmbeddedLinuxBBB/tree/master/pre-built-images/serial-boot からサンプルを取ってきて実行できる
- sudo minicom 起動して
- S2(BOOT_SEL)を押しながらS3(POWER)でBBBを起動
- minicom上に『CCCC…』とBBBが送ってくる
- Ctrl+A ー> sでプロトコル選択。 最初はXmodemを選択。 Xmodemが動作したら、少し高速のZmodemも試してみる。
- プロトコルを選択するとuBuntu PC内のディレクトリやファイルを選択できる画面が現れるので、
- u-boot-spl.binのあるディレクトリを選択(スペースを2回押して選択)して、転送するu-boot-spl.binファイルを選択(u-boot-spl.binスペース1回、ENTER)する
- これでSPLがBBB のam3358 SoC内部のRAMに転送されて、
- SPLが起動する。
- SPLはu-boot.imgを待つので15と同様にu-boot.imgを転送する
- 転送が完了したらSPLがu-boot.imgを起動するので
- 半角スペースを押したままにしてU-BOOTコマンドプロンプトに入るのを待つ
- loadxコマンド(Xmodemでのロード)でuImage(kernel image)をDDRメモリの0x82000000に転送する。
loadx 0x82000000
*新しいu-bootは高速のZmodemも使用できる。 - uImageを選択してダウンロード (8分くらいかかる)
loadx 0x88000000
でam335x_boneblack.dtbをDDRメモリの0x88000000にダウンロードするloadx 0x88080000
でinitramfsををDDRメモリの0x88080000にダウンロードする(8分くらいかかる)- 以下をU-BOOTコマンドプロンプトから実行
setenv bootargs console=ttyS0,115200 root=/dev/ram0 rw initrd=0x88080000
bootm 0x82000000 0x88080000 0x88000000
- これでKernelが立ち上がり、デバイスツリーを読み込みドライバを割り当てて、ルートファイルシステムをマウントし、各種初期設定をしてLinuxが立ち上がる。
- bootm ${kernel_load_addr} ${initramfs_load_addr} ${dtb_load_addr} –boot from memory
UART通信プロトコル
- Xmodem
- Ymodem
- Zmodem
- Kermit
- etc
ログイン名変更
Linuxにログインした時表示されるロゴやプロンプトの表示を変更するためのファイル
- /etc/hostname —- Login name
- /etc/issue — ロゴ変更
- initramfs を作り直す必要がある
initramfsとは
- RAMの中に作るBOOT用の初期のファイルシステム。
- Linux Kernelイメージにドライバーを沢山取り込むとKernelが肥大化する。
- ブート時にルートFSをマウントするまでに必要最小限のドライバーを、ルートFSから取り込んでinitramfsバイナリファイルにしてRAMに入れることができる。
- initramfsはKernelが実行開始したら、Kernelにマウントされる。
- initramfsがロードされたDDRのメモリはルートFSがマウントされたらルートFSに入っているドライバを使用できるので、DDR内のinitramfsを削除しても良い。 これでDDRメモリを有効に使用できる。
- 例えば、自社開発商品のドライバーなどだけを入れる。
- 各商品で基板が異なり、使用するチップが異なると、ドライバが異なる。 例えば、SDカードドライバ。(SDHC、SDXCなど) その為、ルートFSのマウントまでに必要なKernelに入れ込むと、そのKernelはその商品でしか使えなくなるし、全てのドライバを入れ込むとKernelイメージが大きくなる。 Kernelが大きくなるとDDRを占有する。 これらを避けるための仕組み。
- 以前は、initrd。
initramfs作り方
- u-boot-toolsをインストールしてmkImageツールを使えるようにしておく。( u-boot-toolsのインストール)
- mkimageは、U-BOOTを使用する時、KernelイメージがuImageでなければならない。
- uImageはzImageにU-BOOT用ヘッダを付け足している。 mkimageがこのU-BOOT用ヘッダを付け足して、uImageを生成する。
- その後、ルートファイルシステムがあるディレクトリに移動してinitramfsファイルを作成する
$ sudo apt update $ sudo apt install u-boot-tools $ cd <rootfs_directory> <rootfs_directory> $ find . | cpio -H newc -o > ../initramfs.cpio <rootfs_directory> $ cat ../initramfs.cpio | gzip > ../initramfs.gz <rootfs_directory> $ mkimage -A arm -O Linux -T ramdisk -C none -a 0x80800000 -n "Root Filesystem" -d ../initramfs.gz ../initramfs
コメント