組み込みLinuxの魅力は、オープン・コミュニティから収集した多彩なコンポーネントと自社開発のコンポーネントを自由自在に組み合わせ、サービスを手早く構築し、これまでに無かった価値を創造できることです。今回の初心者講座ではLinuxディストリビューションの起動シーケンスを例に、Linuxディストリビューションにはどういったコンポーネントが含まれているのか、Linux上にて各コンポーネントはどのように連携しているのかについて解説いたします。また、こうしたLinuxのコンポーネント上で実行できるアプリケーションの開発方法を記事後半で解説。開発するPC(ex. Intel CPU)と異なるCPUアーキテクチャのターゲットデバイス(ex. 64bit Arm)を扱うためのクロスプラットフォーム開発の導入部を紹介いたします。是非、最後までお楽しみください。
8本すべて無料!組み込みLinuxウェビナー
組み込みLinuxの基礎知識から、Docker/コンテナ技術の開発方法、さらには起動シーケンスを理解し、実際のLinuxアプリ開発も学べる。開発デモはRaspberry Pi 4を使用しているので、受講後すぐにお試しいただくことで可能です。
視聴申込はこちらから
目次
Linux起動シーケンスの概要
Linuxへの理解を深めるため、まずLinux起動シーケンス(ブートシーケンス)の内容を追いかけ、どのようなコンポーネントが含まれ、どの順序で起動されているのかについて紹介いたします。
実行順序と各コンポーネントの役割
まず、コンポーネントの実行順序を図1に示します。
各コンポーネントの概要はそれぞれ以下の通りです。
1st-ブートローダー(primary boot loader)
1st-ブートローダーはCPUに電源が投入された際、最初に動作するプログラムです。1st-ブートローダーはリセット直後のCPUの初期化を行い、予め決められているストレージへのアクセスを行い、ストレージ内に格納された2nd-ブートローダーをメモリ上へ展開します。1st-ブートローダーは決められたストレージのみにアクセスできる非常に小さなプログラムであり、Raspberry Pi 4の1st-ブートローダーは基板上のROMに格納されています。Raspbeey Pi 4の1st-ブートローダーはmicro-SDカード上1つ目のパーティションにあるkernel*.img(2nd-ブートローダー)をメモリ上へ読み出し、実行権を譲渡します。
ROMを更新することにより、1st-ブートローダーの挙動が変化します。例えば、Raspberry Pi 4のリビジョン1.2の1st-ブートローダーはWind River Linuxに対応しWind River Linuxの起動シーケンスを開始することができますが、リビジョン1.4以降の1st-ブートローダーはWind River Linuxに非対応(Raspberry Pi 4 8GB等)となります。リビジョン1.4以降の環境では、ツールを利用してROMを更新し1st-ブートローダーを書き換えることで、Wind River Linuxを起動できるようになります。
参考:Raspberry Pi revision codes|raspberrypi.org
参考:Raspberry Pi boot modes|raspberrypi.org
組み込みLinux入門に最適な1冊
「市場投入までの期間の短縮」「サポートとメンテナンスコストの削減」「コンプライアンス問題への対応」「クラウドネイティブアーキテクチャとコンテナ技術」など、気になるTopicsを網羅したeBookが無料でダウンロードできます。是非ご覧ください。 無料のeBookをダウンロード
2nd-ブートローダー(secondary boot loader)
2nd-ブートローダーはLinuxカーネルの実行準備をするプログラムです。ストレージを初期化する機能のみを備えた1st-ブートローダーよりも高機能で大きなプログラムです。Raspberry Pi 4の2nd-ブートローダーは、Raspberry Pi 4起動用micro-SDカードの先頭パーティション(sdX1)に格納されたkernel*.imgに該当します。2nd-ブートローダーはLinuxカーネルの実行準備を行います。準備完了後、Linuxカーネルを開始します(start_kernel関数)。
参考:Linux Kernel v5.9.1のエントリポイント start_kernel
Linuxカーネル
組み込みLinuxの根幹となるLinuxカーネルは、起動時には初期化処理、定常時にはリソース管理やイベント管理処理を担当します。
起動時、Linuxカーネルは2nd-ブートローダーからstart_kernel関数として呼び出されます。Linuxカーネルはデバイスツリー情報(後述)を参照し、デバイスツリー情報に含まれている全CPUやメモリリソースの管理を開始。続いて、各ハードウェアに対応するデバイスドライバをメモリにロードし、アプリケーションからハードウェアを操作するための下準備をします。Raspberry Pi 4では、USBポート、Bluetoothインタフェース、ネットワークインタフェース、電源管理機能、各種USBデバイスの初期化がLinuxカーネルによって行われています。その後、ルートファイルシステムが格納されているmicro-SDカードの第2パーティションに、ext4ファイルシステム制御機能利用してアクセスし、/sbin/initを実行。Linuxシステム全体を管理するsystemdを開始します(図2)。
起動完了後、定常時のLinuxカーネルはデバイスからの割り込みや、アプリケーションからのシステムコールなどに応じて、各機能を中継する役割を果たします。
デバイスツリー情報(dtbファイル、dtsファイル)
Armアーキテクチャ上で実行されるLinuxは、Linuxカーネルに求められる基本的なハードウェアで共通の動作と、機器固有の動作を分離するために、機器固有の情報を個別のデバイスツリー情報として管理します。Raspberry Pi 4の場合はmicro-SDカードの先頭パーティション(sdX1)に格納されたCPU名(bcm2711)に続くdtbファイルにデバイスツリー情報が格納されています。このデバイスツリー情報は、Wind River LinuxによるLinuxディストリビューションビルド時に、setupスクリプトによりdtsファイルとして必要な情報がダウンロードされ、bitbake時にdtbファイルに変換されます。
The Devicetree Specification|devicetree.org
デバイスドライバ
Linuxカーネルは、デバイスツリー情報により取得したハードウェアの構成に基づき、各ハードウェアを制御するデバイスドライバを呼び出します。Linuxカーネルはデバイスの利用開始・終了をopen、closeインタフェースとしてアプリケーションへ提供し、デバイスドライバがopen、closeに対応する関数を初期化時にLinuxカーネルへ登録します。提供されるインタフェースには様々なバリエーションがあります(ブロックデバイス、キャラクタデバイス、など)。
systemd
systemdは事前に登録された順序に従ってLinuxディストリビューションを構成するコンポーネント、ユーザーモードサブモジュールを起動します。起動されるユーザーモードサブモジュールには、ネットワークの名前を解決するnamed機能や、ネットワークインタフェースに割り当てるIPアドレスを解決するDHCPクライアント、IPv4やIPv6についての通信制御を行うiptables機能などがあります。
journald
journaldはsystemdを構成するひとつの機能で、systemdが実行した処理をすべてロギングします。journaldコマンドを実行することにより、systemdの動作履歴を採取することが可能です(図3)。
シェルプロンプト
systemdは、ユーザー操作に必要なすべての初期化が完了した後、login機能を起動します。login機能はユーザー名とパスワードを確認し、対応するユーザーのシェルプロンプトを開始します(図4)。
Raspberry Pi 4を使ってLinuxの起動シーケンスを精密に解析してみよう
ここからは、上記で解説したLinuxの起動シーケンスを実機を使って採取・確認する方法を解説いたします。採取できる起動シーケンスには図5のようにグラフィカルに実行順序を目視できるBootChart機能など、直感的にわかりやすく、精密な解析に不可欠な情報も含まれています。是非お試しください。
BootChartを有効化したLinuxディストリビューションをビルドする
Raspberry Pi 4起動用のmicro SDカードを準備する
最初に、Raspberry Pi 4用の起動用micro SDカードを準備します。Raspberry Pi 4向けmicro SDカードの初期化方法は「micro SDの初期化方法」をご参照ください。
Wind River Linux開発環境を入手し、Linuxディストリビューションをビルドする
Wind River Linux開発環境を取得し、conf/local.confファイルにてBootChart機能を有効化、bitbakeコマンドを実行しLinuxディストリビューションをビルドします。
# 作業用ディレクトリを作成し、移動する $ mkdir ~/bootchart-on $ cd ~/bootchart-on # Wind River Linux開発環境を取得します $ git clone --recursive https://github.com/WindRiver-Labs/wrlinux-x.git # Raspberry Pi 4のBSPを取得する $ ./wrlinux-x/setup.sh --machines bcm-2xxx-rpi4 # 取得したスクリプトによりプロジェクトを準備する $ . ./environment-setup-x86_64-wrlinuxsdk-linux $ . ./oe-init-build-env build # 自動的に作業ディレクトリに移動する $ pwd /home/X/bootchart-on/build # 設定ファイルにBootChartを有効にするよう項目を追記 $ vi conf/local.conf ### (1) ネットワークからのダウンロードを有効化 BB_NO_NETWORK = '0' ### (2) BootChart機能をビルド対象に追加する(新規行を追加) IMAGE_INSTALL_append = " systemd-bootchart" ### (3) 内容を保存する # Linuxディストリビューションのビルドを開始します $ bitbake wrlinux-images-glibc-std -c populate_sdk_ext
ビルド結果をRaspberry Pi 4起動用のmicro SDカードへ格納する
ビルド後、生成されたLinuxディストリビューションは「tmp-build/deoloy/image」フォルダへ格納されます。「micro SDへのイメージ書き込み」を参考に、LinuxディストリビューションをRaspberry Pi 4起動用micro SDカードへインストールしてください。
Linuxの起動シーケンスをBoorChartを使って解析する
起動スクリプトに変更を加え、BootChart有効状態で起動する
Raspberry Pi 4の起動設定はmicro SDに格納されているcmdline.txtによって決まります。下記の手順により、cmdline.txtにBootChartを有効化する設定を追記します。
# Raspberry Pi 4起動用micro-SDカードの先頭パーティションをマウントする $ sudo mount -t vfat /dev/sdX1 /mnt # マウントポイントに移動 $ cd /mnt # 起動設定ファイルを開く $ sudo vi cmdline.txt ### 内容を以下に変更し、保存する console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 fsck.repair=yes rootwait ip=dhcp initcall_debug printk.time=y debug init=/lib/systemd/systemd-bootchart # micro SDカードを取り出す $ cd ~ $ sudo umount /mnt
BootChartを採取し、内容を確認する
上記の設定を適用したmicro-SDカードをRaspberry Pi 4へ挿入し、電源を投入するとsystemdのBootChart機能により、起動時のログの採取が自動的に開始されます。起動後、採取したBootChartを取得することができます。
# BootChartは自動的に /run/log に格納される # 作業用ディレクトリにコピーする $ cp /run/log/bootchart-20200615-2004.svg /root/ # USBメモリをRaspberry Pi 4へ挿入しマウントする $ sudo mount /dev/sdX1 /mnt # BootChartをコピーする $ sudo cp /root/* /mnt -r $ sync # USBメモリを取り出す $ sudo umount /mnt
取得したBootChartはSVG形式となっており、グラフィカルに起動シーケンスの内容を追いかけることができます(図6)。
ダウンロード – Raspberry Pi 4上で採取したBootChart(svg形式)
起動シーケンスの内容を参照できるBootChart以外のログを採取する
起動スクリプトに変更を加え、BootChart無効状態で起動する
まず、前述のBootChart機能有効設定がcmdline.txtに書き込まれていると、大量のBootChartログがすべてのログに記録されるため、無効化します。
# Raspberry Pi 4起動用micro-SDカードの先頭パーティションをマウントする $ sudo mount -t vfat /dev/sdX1 /mnt # マウントポイントに移動 $ cd /mnt # 起動設定ファイルを開く $ sudo vi cmdline.txt ### 内容を以下に変更し、保存する console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 fsck.repair=yes rootwait ip=dhcp # micro SDカードを取り出す $ cd ~ $ sudo umount /mnt
起動時のログを採取する
上記の設定を適用したmicro-SDカードをRaspberry Pi 4へ挿入し、電源を投入すると起動時のログが/var/log
に自動的に格納されます。また、dmesgコマンドとjournalctlコマンドを使うことにより、さらに詳細な情報も採取できます(図7)。
# Linuxは起動時にログを /var/log に格納する # USBメモリをRaspberry Pi 4へ挿入しマウントする $ sudo mount /dev/sdX1 /mnt $ cd /mnt # 起動ログをコピーする $ sudo cp /var/log/* /mnt -r $ dmesg > dmesg.txt $ journalctl > journalctl.txt $ sync # USBメモリを取り出す $ cd ~/ $ sudo umount /mnt
Raspberry Pi 4上のLinuxで実行できるアプリケーションをPC上で開発する
ここまで、Linuxカーネルを構成するコンポーネントと起動シーケンスについて解説しました。続いては、Wind River Linuxにより生成した自社製Linuxディストリビューションに対応したアプリケーションの開発手順を紹介いたします。少ない手順で、ターゲットデバイス向けのアプリケーションを開発用PC上でクロス開発することが可能です。是非お試しください。
なお、ビルドするソースコードは以下の内容を参考にしています。
Creating a Sample Application|Wind River Linux 19 LTS
Linuxディストリビューション向けのクロス開発環境をPC上に準備する
Wind River Linuxにより生成したLinuxディストリビューションに対応したアプリケーションをPC上で開発するにはSDKが必要となります。SDKは、Linuxディストリビューションをビルドする際にbitbake
コマンドにオプション-c populate_sdk_ext
を付与することにより生成可能です。生成されたSDKフォルダ内のスクリプトを実行することでクロス開発環境を整える、開発PCのIntel CPU上で、ターゲットであるRaspberry Pi 4のArm 64bit Cortex-A72用のアプリケーションを開発することができます。
# Linuxディストリビューションとアプリケーション開発用のSDKをビルドします $ bitbake wrlinux-images-glibc-std -c populate_sdk_ext # ビルドされたSDKはdeployディレクトリに格納されます $ ls ./tmp-glibc/deploy/sdk/ # SDKをインストールします $ cd ./tmp-glibc/deploy/sdk/ $ ./wrlinux-10.19.45.11-glibc-x86_64-bcm_2xxx-rpi4-wrlinux-image-glibc-std-sdk-ext.sh ... ### インストール先を指定します(デフォルトでは ~/wrlinux_sdk) # アプリケーション開発ツールが ~/wrlinux_sdk ディレクトリにインストールされます $ cd ~/wrlinux_sdk
64bit Arm向けのアプリケーションをPC上で開発する
# アプリケーション開発用ディレクトリを作成します $ cd ~/app_put # ツールを利用するための事前設定をする $ . ./home/(USER_NAME)/wr_linux/environment-setup-aarch64-wrs-linux # 設定に成功するとdevtoolというコマンドが使えるようになります $ devtool --help ...
サンプルプログラムは「 Creating a Sample Application|Wind River Linux 19 LTS」を参考に、main.c、math.h、math.c、LICENSE、Makefileの計5ファイルを開発用ディレクトリ内に作成してください。
# 5つのファイルを準備します $ ls main.c math.h math.c LICENSE Makefile # makeコマンドを実行するだけでアプリケーションをビルドできます $ make -e ... # 実行ファイル「fibonacci」が生成されます $ ls main.c math.h math.c LICENSE Makefile fibonacci
生成された「fibonacci」は、Raspberry Pi 4のLinuxディストリビューション上で実行することができます(図9)。
大規模な組み込みLinuxのアプリケーション開発に向けて
アプリケーション開発チームとLinuxディストリビューション開発チーム
ここまでの手順から、bitbakeコマンドにて生成したSDKを利用することで、生成したLinuxディストリビューション用のアプリケーションを簡単に開発できることを感じていただけたかと思います。大規模なシステムを開発する場合、多数のアプリケーションの新規実装や移植実装が求められるため、SDKの受け渡しだけでアプリケーション開発を開始できるWind River Linuxの提供するSDKのフレームワークは開発効率に強く貢献します。Linuxディストリビューション開発チームとアプリケーション開発チームの分担を明確化し、スムーズに開発規模を拡大することができます(図10)。
アプリケーションをLinuxディストリビューションへ統合する
さらに、Wind River Linuxのビルドシステムを使うことにより、個別に開発したLinuxアプリケーションをLinuxディストリビューションへ簡単に統合可能です。アプリケーションのソースコードとMakefileをWind River Linuxビルド環境のlayers/local
に格納し、レイヤーを定義するbbファイルを追加(図11中ではsample_application.bb)を同梱。bbファイルには、ビルド時に必要なファイルの格納先を指定しておくことで、bitbakeコマンドによりアプリケーションまで含んだシステムを生成することができます。
A Sample Application Recipe File
詳細は2020年11月開催のAPSウェビナーにて、紹介いたします。是非お申し込みください。
組み込みLinux入門に最適な1冊
「市場投入までの期間の短縮」「サポートとメンテナンスコストの削減」「コンプライアンス問題への対応」「クラウドネイティブアーキテクチャとコンテナ技術」など、気になるTopicsを網羅したeBookが無料でダウンロードできます。是非ご覧ください。 無料のeBookをダウンロード
まとめ
今回の初心者講座ではLinuxの起動シーケンスとLinuxディストリビューションを構成する主要なコンポーネントについて記事前半で、自社製Linuxディストリビューション向けの開発環境のインストールをサンプルアプリケーションのビルド手順について記事後半で解説いたしました。自社の組み込みLinux製品に新しいハードウェアなどを盛り込むと、起動シーケンスやアプリケーションの解析などが必要なケースも生まれてくるかと思います。是非ご活用ください。
次回は、自社製品をリリースするために必須とされるデバイスドライバの開発技法について紹介いたします。
Wind River Linuxについて
Wind River Linux®は、商用組み込みLinuxマーケットシェアNo.1!※の業界最先端の組み込みLinux開発プラットフォームです。最大15年の長期サポートや継続的デリバリーにも対応し、信頼性の高いエッジデバイスの開発を支援します。
※出典:VDC Reserch The Global Market IoT & Embedded Operating Systems (2018)
Wind River Linux 製品ウエブサイト Wind River Linux 製品カタログ Wind River Linux ダウンロード
Wind River Linux インタビュー記事
Wind River Linuxが誕生して15年となる。Wind River Linux誕生の背景やこれまでの取り組み、採用事例などについて話を聞いた。
Wind River Linux インタビュー記事
- Linuxは、Linus Torvaldsの米国およびその他の国における商標または登録商標です。
- Raspberry PiはRaspberry Pi財団の登録商標です。
- Wind RiverおよびVxWorksはWind River Systems, Inc.の登録商標です。
- その他記載の会社名、製品名は、それぞれの会社の商標または登録商標です。