いろいろ試してみて分ってきたことを書いてます。 このページだけ実践がありませんが、『その3』以降は全て実践があります。
U-BOOTとは
このU-BOOTの設定次第でブートの方法や、Kernelの一部の設定をカスタマイズするWindowsでいうカスタムBIOSのようなもの。 そして、U-BOOT専用のコマンドラインも持ちKernelが完全に立ち上がるまでのデバッグもサポートしています。
ブートシーケンス
BBBのTI社製 am3358 SoCでU-BOOTを使う場合です。
- RBL(ROM Boot Loader)
- RBLはBBBに使用されているam3358 SoCの出荷前にROMに書き込まれているので変更出来ません。 挙動はテクニカルリファレンスを見て理解しなければなりません。
- RBLはam3358 SoCのSYSBOOT[15:0]端子(『BOOTシーケンス参考』)を見てSPL(Secondary Program Loader)を探すデバイスを選択します。
- am3358 Soc含むTIの場合はSPLでなく、SPLにヘッダーをつけたMLO(Memory Loader)を探しに行きます。
- MLOはTI専用ですが、U-BOOTをビルドすると、u-boot.imgと一緒にMLOもSPLも生成されます。
- RBLはMLOを探しに行く以外に、CPU周りの初期化を行います。
- MLO(Memory Loader)
- TI専用のspl(Second Program Loader)で、RBLの次に実行される初期U-BOOT。 splにU-BOOTイメージのKernelのDDRへのロードアドレス等のヘッダが付いたものがMLO。
- microSDやeMMCからUART起動をする時はsplを使いますが、それ以外の場合はMLOを使います。 今回のシリーズでは全てMLOを使います。
- MLOがデバイス(このシリーズではmicroSDがメイン)から呼び出され、SoC内の小さなRAMにロードされ実行されます。
- MLOは大規模DDR等を初期化をして、MLOと同じデバイスの同じパーティションにあるU-BOOT本体イメージのu-boot.img起動します。
- u-boot.img
- u-boot.imgは、U-BOOTをビルドすると生成されるU-BOOTイメージ。(ここではイメージとは実行可能なバイナリ形式になったファイルの事。)
- Linuxが立ち上がらなくても、Ethernet TFTPやUART通信、SDやeMMCへのアクセス等が出来るU-BOOTコマンドとU-BOOT変数が用意されています。
- u-boot.imgはDDRにロードされ実行されます。
- これでU-BOOTコマンドや変数にアクセスできるようになります。
- 次に、U-BOOTの設定で、待ち時間を設定できます。(初期値は2秒)この間に、半角スペースを押していると、U-BOOTコマンドプロンプトに移行し、ブートスクリプトboot.scrを実行せずに、手動でKernelの起動や、ブートスクリプトの検証等が可能になります。(このシリーズでも実施します。) 一度、U-BOOTコマンドプロンプトにはいると、boot.scrは実行されません。 その際は、再度RBLからの起動となります。
- U-BOOTコマンドプロンプトに移行しなければ、u-boot.imgは、ブートスクリプトboot.scrを探しに行きboot.scrに記述されている通りに実行します。(U-BOOT 2021以降はuEnv.txtが使えず、boot.scrのみ使用でき、boot.scrはU-BOOT用のブートスクリプト)
- もし、boot.scrが存在しない場合は、U-BOOTのデフォルトの動作で、U-BOOT用のLinux Kernel uImageを探しに行き、なんとかLinux Kernelを起動しようとします。
- (bootstrap)
- uImage(Linux Kernel)を圧縮(Compress)して作成した場合、圧縮されたuImageを解凍をする。 今回は圧縮していないので、このステップはありません。
- uImage(Linux Kernel:以下Kernel)
- uImageは、Linux Kernelする際に、uImage指定をすると生成されるU-BOOT用のKernelイメージ。
- uImageは通常のLinux Kernel zImageにU-BOOT用のヘッダー情報を付け足したものです。
- u-boot.imgがuImageを起動すると、u-boot.imgは権限をKernelに渡すので、ここからはU-BOOTコマンドは使えません。U-BOOT領域も削除されていると思います。
- Kernelは回路構成や情報が入ったデバイスツリー(.dtb:Device Tree Blob)を見てKernelに組み込まれたドライバをインストールしデバイスを使用出来るようにします。
- この際、KernelはEthernetやUART、SD、eMMCへのアクセスやその他のデバイスをドライバを起動します。
- これらのドライバ、例えばEthernetのドライバはu-bootのEthernetドライバとは全く別のドライバです。
- u-bootは軽量にするために、簡単なTFTP等しかマウント出来ません。 Kernelは更にセキュリティの高いNFS等もマウントできます。
- ドライバでデバイスアクセスを可能にしたら、Kernelはルートファイルシステム(ルートFS)をマウントしてファイルにアクセス出来るようにします。
- ドライバーは、非常に沢山あるため、全てをKernelに入れてしまうと、Kernelが肥大化して、eMMCなどに収まらなくなるので、特に組込の場合は、Kernelに組み込むドライバーは最小限にして、残りのドライバは、取り込まないか、モジュール(ファイルのまま)として予めルートFSにインストールしておきます。 これらはKernelをビルドする際に設定できます。
- すると、ルートFSがマウントされると、それらのドライバーも使用可能となる。 どのドライバーをKernelに組み込むかはKernelをビルドする際に設定できます。
- Kernelにドライバを組み込むメリットは、マウントするのに必要なものは組み込んでおきます。(Kernelを最小化するにはinitramfsを使う方法もあります。) それと高速化が必要なドライバは入れておきます。 デメリットはKernelの肥大化と、どのドライバを入れたかファイルを見てもわからないことです。
- Init(初期化)
- その後、Kernelは/sbin/init, /etc/init, /bin/init, /bin/shの順番に初期化コマンドを実行します。
- 今回のシリーズでは、組込用ではルートFSを軽量にできる人気の高いBusyBoxを使います。
- そのBusyBoxでは/sbin/initが起動され、/sbin/initからrcSというシェルスクリプトファイルが呼び出されます。
- /sbin/iniはBusyBoxが生成しているためです。
- 初期化の前にルートFSは既にマウントされているため、Linuxシェルコマンドを使用できます。
- rcSファイルに、他のドライバの起動やSSH用のsshdやTelnet用のtelnetdを設定や駆動するなどするスクリプトを書いておきます。 また量産用には、rootの設定や初期ユーザーの設定等も記述しておけます。
- これらが完了すると、ログイン画面が現れてLinux Distroの起動完了します。(ログイン設定なしの場合はコマンドプロンプトが現れる)*本来の意味のLinuxとはLinux Kernelの事で、uBuntuやCentOS等は、Linux Distributionと呼ばれるようです。 なので上記ではKernelと区別するため、Linux Distroと表現しました。
U-BOOT コマンドプロンプト
今回はU-BOOTを使ってLinuxをブートします。 U-BOOTはいろいろな機能があり、どの機能を使うか設定出来るので非常に便利です。 U-BOOTはLinuxが立ち上がる前に、各種通信(Ethernet:TFTP、UART:Xmodem、Ymodem、Zmode等、USB)やデバイスアクセス(SD/eMMC、SPI/I2C通信NAND/NOR Flash)等を使用でき、それらの通信やデバイス経由でのLinuxのブートができます。 U-BOOT用のブートスクリプト(バッチファイルのようなもの)のboot.scrでの自動ブートもできますが、U-BOOT コマンドプロンプトに入ってU-BOOTコマンドプロンプトで、Linuxをブートすることもできまるのです。
U-BOOTコマンドプロンプトに入るには、BBBをブートし直している間、『半角スペース』を押したままにしているとU-BOOTプロンプトに入ることができます。 BBBのeMMCに組み込まれたU-BOOTの待ち時間は0秒なので、電源を入れる前から、minicomなどの端末から半角スペースを押した状態で電源を入れて、U-BOOTコマンドプロンプトに入るまで待たなければなりません。 私の場合は、U-BOOTをビルドする前に、menuconfigでBOOT_DELAYを=4秒としています。
// 私の場合、U-BOOTコマンドプロンプトにはいると、『=>』が表示されるので、 // 以下は『=>』をU-BOOTコマンドプロンプトを表しています。 => printenv // u-boot予約変数と、作った変数とその値の一覧表示 => printenv bootargs //U-BOOTからKernelに引数を渡す変数表示 => load mmc 0:2 0x82000000 /boot/uImage // image_header をDDRにコピー『重要』 4002080 bytes read in 285 ms (13.4 MiB/s) => md 0x82000000 10 // 4変数を読み出し。 mdは32bit単位で読み出し 82000000: 56190527 62153da1 50d07e51 e0103d00 '..V.=.bQ~.P.=.. 82000010: 00800080 00800080 d58b5329 00020205 ........)S...... 82000020: 73676e41 6d6f7274 382e332f 2f30312e Angstrom/3.8.10/ 82000030: 67616562 6f62656c 0000656e 00000000 beaglebone...... => imi 0x82000000 // image_headerのinformationを表示する ## Checking Image at 82000000 ... Legacy image found Image Name: Angstrom/3.8.10/beaglebone Created: 2013-04-29 19:56:00 UTC Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 4002016 Bytes = 3.8 MiB uImage Load Address: 80008000 Entry Point: 80008000 Verifying Checksum ... OK type struct image_header{ uint32_t ih_magic }
データ型(md:メモリーダンプ時)
普通はあまりメモリーダンプ(メモリーに直接値を書き込む事。例えばアドレス0x80000000に0x0000_a000を書き込むなど。)は使わないと思いますが、デバッグ時再ビルドする時間より、数箇所だけの変更で確認する場合などに使います。
私の場合mdはKernel立ち上げでトラブった時に、どこで止まっているかKernelの内部ログを覗くために使いました。
U-BOOTプロンプトで見るuint32_tの数値は以下のようになる。U-BOOTプロンプト上 e0103d00 ==> 実際 003d10e0 これはヘッダの64バイトを含まないサイズを表す(4002016)
U-BOOTコマンド・変数 一覧消してしまったU-BOOTコマンド・変数 一覧
まだほとんど埋めれていません。 順次埋めていきます。
コマンド・予約変数 | 説明 | |
---|---|---|
? | コマンド | 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 イメージの uboot 用アプリケーションの実行.. |
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 setexpr setexpr | コマンド | 評価の結果により環境変数に値を書き込む また、指定のフォーマットで値を設定する => 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 | コマンド | 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 | コマンド | uboot 用アプリケーションの実行 |
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 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 | コマンド | 変数を指定しないと、変数一覧を表示 |
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 | コマンド | uboot のバージョンの表示 |
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) | 予約変数 | |
uenvcmd | uEnv.txt専用変数 | uEnv.txtの最後の行に書くお決まりの変数名。 u-boot.imgはuEnv.txt内の左辺のuenvcmdを見ると、その右辺を実行していく |
root | bootargs引数 | マウントする場所を指定 rwがないと書き込みできない root=/dev/nfs rw |
rootfsstype | bootargs引数 | SDの第2パーティションにルートFSがあり、フォーマットがext4のとき rootfstype=ext4 NFSにルートFSがある時 rootfstype=nfs |
console | bootargs引数 | UARTコンソール入出力ポート名と転送Baudrateとフォーマット指定 console=ttyS0,115200n8 |
debug | bootargs引数 | Kernelブート詳細メッセージ表示 |
今回のLinux取得
以下からzipをダウンロードして展開。 上記ファイルは、 /arch/arm/boot/compressed/にあるアセンブリファイル。 BOOTからKernelに制御を渡さず、Bootstrapに来るのは、LinuxイメージはCompressedされているので、まずBootstrapがLinuxイメージDecompress(解凍)する。
Architecture specific initialization
- CPU specific intialization
- Check for valid processor architecture
- Page table inits
- Initialize and prepare MMU for the identified Processor architecture
- Enable MMU to support virtual memory
- Calls “start kernel” function of the main.c
Kernel の解凍はしない。
microSDカードに起動用ファイルを入れるには
基本手順
- パーティション作成
- ファイルシステムタイプ指定してそれぞれのパーティションをフォーマット
- bootフラグを付ける
- それから各種ファイルを指定のパーティションにコピーする
uBuntuの場合
この方法は『組込み Linux Beaglebone Black でやってみる その1 microSDで起動』を参考にしてください。
後はファイルやディレクトリの転送だけ。
私の場合、/dev/mmcblk1p1/は/media/ichiri/BOOT/としてuBuntuのファイルシステムに自動的にマウントされてたので、LinuxのcpコマンドやuBuntuのGUIのファイルエクスプローラでコピーしても使えました。
マウントされていない時は、mountコマンドで手動でマウントするか、ddコマンドでコピーするようです。
sudo dd if=u-boot.img of=/dev/mmcblk1p1
ddコマンドでSDの/BOOT/内に書き込まれる。(ddだとマウントしなくても良い?)
Windowsの場合
uBuntuのみの検証しています。 以下のWindows用は未検証です。 一応将来のメモとして残しています。
- Linuxイメージダウンロード
- 解凍
- Windowsの場合win32 disk imageソフトで上記イメージをSDカードに転送
- SDカードをEject
- BBBにSDカードを挿し起動
- Beagleboard.orgからイメージをダウンロードした場合、/opt/scripts/tools/eMMC/init-eMMC-flasher-v3.sh
- もしflash用の.shファイルがあれば、uEnv.txt(boot.scr同様)内に、以下を記述
cmdline=init=/opt/scripts/tools/eMMC/init-eMMC-flasher-v3.sh
- flashには20分かかる
cmdline=init=/opt/scripts/tools/eMMC/init-eMMC-flasher-v3.sh
eMMCに起動用ファイルを入れるには
これも未検証ので、将来eMMCに転送する際の備忘録です。
基本手順
- SDカードでFlasherスクリプトでeMMCに転送する
- SDカードでLinuxを立ち上げる
- eMMCのfatファイルシステムの第1パーティションとext4ファイルシステムの第1パーティションを作る
- それらのfatパーティションとext4パーティションをフォーマットする
- fatパーティションには”boot”フラグを付ける
- fatパーティションにMLO、SPL、u-boot.img、boot.scr、uImage、dtb(,intramfs)をコピーする
- ext4パーティションにルートファイルシステムをコピーする
fatとext4のパーティション作成方法
//自動スクリプト時は # fdisk 1G /dev/mmcblk1p1 // eMMC パーティション作成 mmcblk1がeMMCの場合 # fdisk /dev/mmcblk1p2 //mmcblk1p2は第2パーティション //以下、手動の場合におすすめ # cfdisk /dev/mmcblk1 // eMMC パーティション作成 mmcblk1がeMMCの場合 // コマンド例 ---cfdiskをすると、パーティション作成モードに入り簡単に // n:空き領域から新しいパーティション作成。 パーティションサイズを聞いてくる // b:選択しているパーティションにbootフラグを付ける
初期化してファイルシステムを作る
# mkfs.fat -F 16 /dev/mmcblk1p1 // eMMCのパーティション1がmmcblk1p1。 eMMCの場合はLabelを付けない。 # mkfs.ext4 /dev/mmcblk1p2 // -c ファイルシステム作成前にデバイスに対して不良ブロック検査実施 (保証されていないがほとんど場合使用可能)
eMMCのパーティションにコピーする
// /dev/mmcblk1p1や/dev/mmcblk1p2を/mediaにmountして、必要ファイルをコピーか転送してunmountする。 // uBuntu ではmmcblk1がSDカード。 BBBではmmcblk0がmicroSDカード。 $ cd /media $ sudo mkdir ichiri $ mount /dev/mmcblk1p1 /media/ichiri $ cp ..... /media/ichiri // 必要ファイルをコピー後、アンマウントする $ unmount /media/ichiri
Boot flagを付ける
$ fdisk /dev/mmcblk0 // パーティション番号はつけない Command(m for help): a // aはbootフラグをトグル Partition number (a,2, default 2): 1 //bootフラグはいつもパーティション1 The bootable flag on partition 1 is enabled now. Command (m for help): w //これで書き込み The partition table has been altered. Syncing disks. $ fdisk -l //これで全てのパーティションを見て、ちゃんとbootフラグがONになっているか確認
uEnv.txt、boot.scrとは
SPLやMLOで開始して、U-BOOTイメージが展開された後、Linuxイメージを展開する前に、uEnv.txtやboot.scr(ブートスクリプト)に沿ってLinux Kernelイメージ(uImage)、dtb、initramfs(*initramfsは使用しない場合もある)が展開される。 uEnv.txtもboot.scrもU-BOOTのコマンドを実行してKernelを立ち上げるバッチスクリプトのようなもの。 U-BOOT-2021以降はboot.scrしか受け付けてくれませんでした。 なので、このシリーズではboot.scrで進めていくので、uEnv.txtは使いません。
U-BOOT source treeとは
- U-BOOTのソースコードファイル、ディレイクトリ群全体の事
- architecture毎に用意されているので、自作の場合は、/archディレクトリに移動
- 開発ボードを使用している場合はメーカーごとに用意されているので、BBBの場合は/board/ti/am335xにある ボード専用のboard.cによって設定されている board initializationがここにある
USBのネットワーク設定する場合
USBでもIPアドレスを設定して、Ethernetプロトコルを走らせることが出来ます。 そうすればBBBをUSB~ホストPC経由~ホストPCのWifi経由でインターネット接続できます。
uBuntuの場合
BBBに設定
//minicom BBB console # cd /opt/scripts/boot/ # sudo sh autoconfigure_usbo.sh //<---not needed in my case # ping //返ってくるのを確認する # sudo vi /etc/resolv.conf nameserver 8.8.8.8 <-------DNSと同じIPを入れる nameserver 8.8.4.4 # route add default gw 192.168.7.1 usb0 # route add default gw 192.168.6.1 usb1
uBuntuに設定
//uBuntu console $ ifconfig //これでBBBとUSB接続しているIPアドレスがみれる $ ping //返ってくるのを確認する $ echo 1 > /proc/sys/net/ipv4/ip_forward //これでIPポート転送(フォワード)を許可する $ sudo iptables --table nat --append POSTROUTING --out-interface wlp2s0 -j MASQUERADE //wlp2s0がWifiです $ sudo iptables --append FORWARD --in-interface enx94a9a87a3c95 -j ACCEPT //enx94a9a87a3c95がホストPC側のUSB
//minicom BBB console # ping www.google.com //これでpingが返ってきます
上記でBBBとUSB接続〜uBuntu PCのWifi経由でBBBはapt updateなどができるようになる。
Windowsの場合
WindowsはIPv4 Propertyで同じドメイン設定と、DNS 8.8.8.8 と 8.8.4.4を設定。
BBBに設定
# sudo route add default gw 192.168 7.1 usb0 // BBBは192.168.7.2で、uBuntuのUSBが192.168.7.1 # sudo vi /etc/resolv.conf nameserver 8.8.8.8 <-------GoogleのDNSのIPアドレスを入れておく nameserver 8.8.4.4
組込みLinuxを進める時に役に立つかもしれない豆知識
Control Flow
Bootloaderのプロセスは
- MLO/SPLが起動され以下のプログラムが実行される
- start.S (Assembly file)
- /u-boot/arch/cpu/armv7/start.S
- head.S –u-boot
- misc.c —u-boot
- またhead.S —u-boot
- head-common.c —kernel
- main.c —kernel
- init —busybox
- rcS —ルートFS
- start.S (Assembly file)
bootm.c (U-BOOT)
- bootmはDDRに先頭アドレス指定でロードしたuImageと.dtb(デバイスツリー)を指定してブートするメモリーブートコマンド。
- u-boot-xxxxx/arch/arm/lib/bootm.cのboot_jump_linux()関数でkernelを起動するシーケンスが記述されている。
- 上記関数内の kernel_entry(0, machid, r2); —Kernel にr2:FTD(.dtb)の場所を渡している
- r1:machine ID
- r2:DDRのFDTのアドレス(ポインタ)
- r10は選択されたProcessorタイプの構造体を保持する。
ichiri@ichiri-VPCF128FJ:~/Downloads/u-boot-2017.05-rc2$ grep -r "bootm_headers_t" * include/image.h:} bootm_headers_t; // ここにあるのがわかる。 他にもいろいろ表示される。
head.S misc.c (Bootstrap loader)
- .Sはアセンブラ言語(これはarch dependentなので/linux/arch下にある)
- .cはC言語。 しかし、インラインにアセンブラが使われている標準CでないC言語
- 上記の両方は、バイナリにビルドするためにGCC(GNU C Complier)が必要
- この後使用するコンパイラはarm-linux-gnueabihf-
head.S
- /linux/arch/arm/kernel/head.S(CPU専用のLow level(Assembly) CPU Initialization)
- 今回のSoC AM3358 SoCのCPUはArm Cortex-A8なので、Arm用のhead.S
- プロセッサーのアーキテクチャーを確認する
- テーブルのページ初期化
- プロセッサーのMMU(メモリ管理ユニット)の初期化
- head.S内の重要ルーティン Start:
main.c in /linux/init
- Architectureに依存しない初期化
- 重要なファイル
- *start_kernel()でいろいろな初期設定をする
- kernel_init()で初期化で使用した関数のメモリーを開放する。
- Initで使用するのはPID 1
- 初期化のデバッグ時はカスタマイズしてデバッグプログラムを書き込んだりする場合もある。
U-BOOT確認
U-BOOTコマンド
ビルド時間やコンパイラのバージョンも見れるので、デバッグ時には便利でです。
=> vsersion U-Boot 2022.10 (Feb 15 2023 - 11:54:00 +0900) arm-linux-gnueabihf-gcc (Linaro GCC 7.5-2019.12) 7.5.0 GNU ld (GNU Binutils for Ubuntu) 2.34
ルートFSマウント後
$ strings /dev/mtd0 | grep U-Boot
コメント