0Linuxには、サードパーティが提供しているディストリビューションを利用することが一般的ですが、ディストリビューションによって、デスクトップ用、サーバー用など様々な利用形態を、ディストリビューションを提供している組織が想定する利用環境に応じて作成しています。その中には、組み込みシステム用ディストリビューションなども存在し、有償サポートを利用することによって、ユーザーが想定している組み込みシステムの構築を行っている組織もあります。組み込みシステムでは、サーバーやルーターといったネットはあるが画面の無い環境、ビデオレコーダーのように画面はあるがネットはない環境、自動販売機や工作機器のように画面もネットも無い環境など、様々な形態が考えられるので、ディストリビューションの、画面を見ながらCD-ROMからインストールなどのイメージとは全く違うLinuxのインストールが必要になります。このサイトでは、Buildrootという、ソースコードディストリビューションを利用して、組み込みシステムを構築していく方法を解説していきます。Buildrootは一般的なデスクトップのディストリビューションとは異なり、ソースコードオンリーのディストリビューションで、組み込みシステムにおいて必要最低限のツールをコンパイル、パッケージにするだけでなく、必要なクロスコンパイラ等もコンパイル環境に合わせて構築されるために、かなり厳密に組み込みファームウェアのバージョン管理等も行うことができます。構造も単純なため、x86のPC以外でも、各種チップメーカーから出されているリファレンスコードをBuildrootのソースツリーに組み込むことも比較的単純に行うことができます。InitプロセスLinuxカーネルは、起動すると、ルートファイルシステムをマウントし、”init”というプログラムを起動します。”init”は/etc/inittabファイルを参照し、それに記載された動作を行います。/etc/init.d/rcXXを読み込んでと書いてあるものもありますが、”init”が読むのは/etc/inittabだけです。/etc/inittabの中で、/etc/init.d/rcXXを実行しろと書いてあれば、それを読み込みますし、/etc/hogehogeを読めと書いてあればそちらを読みます。Buildroot標準の/etc/inittabを見てみましょう。-r最初のコメント欄を見ると、このファイルはBuildrootではなくてBuildrootで使用しているBusybox由来のファイルであることが分かります。システム起動直後に実行すべき項目は、sysinitとして記載されています。/procここでは、最初にporcファイルシステムをマウントしています。/この項目は、ルートファイルシステムを書き込み可能としてマウントしなおしています。これを実行しないと、次のmkdirコマンドが実行できません。/dev/ptsここでは、ptsデバイスを配置するためのディレクトリを作成しています。/dev/shmここでは、shmデバイスを配置するためのディレクトリを作成しています。-a/etc/fstabに記載されているファイルシステムのマウントを行います。/etc/hostnameHostnameの設定を行っています。scripts::sysinit:/etc/init.d/rcSここから、/etc/init.d以下のコマンドを実行して、デーモンの起動を行います。ptsや、shmを使用しないのであれば、2-4行目は削除しても問題ありません。idのフィールドは、デバイス名を記述します。起動後に、シリアルポートにもログインプロンプトを表示したい場合などでは、idに/dev/ttyS1などと書きます。次は、runlevelのフィールドですが、Busyboxの/etc/inittabでは、runlevelを無視していることがわかります。Runlevelの概念は、初期のUNIXシステムでは、カーネル起動時のオプションが数字1文字しか指定できなかったために、それを用いて、システムの起動条件を変えるために使用していたのですが、最近のLinux(UNIX)システムでは、カーネル起動時の引数をいろいろ指定することができるので、わざわざrunlevelとして使用する必要もなくなりました。今でも、デスクトップシステムでは、GUIログインと、CUIログインを区別するために利用されることもあるようですが、ほかの引数で代用することも可能ですので、なくても問題ないでしょう。“:”のフォーマットは、他のシステムの/etc/inittabとの互換性のため残してあるようです。次のフィールドは、起動条件になります。Ctrl+Alt+Delが押された場合に実行するプログラムを指定、shutdownはシャットダウンを行う場合に実行するファイルを指定します。これらによると、起動時は、特殊なファイルシステムのマウントを行い、ホスト名を設定した後で、/etc/init.d/rcSを実行するように指定されれてます。起動後は、コンソールにログインプロンプトを表示し、ログアウトされたら再度表示。Ctrl+Alt+Delが押された場合は、rebootコマンドを実行。シャットダウン時には、/etc/init.d/rcKスクリプトの実行後スワップを無効にしています。※組み込みシステムでは、”init”自体を置き換えてしまうことも可能です。8Bitマイコンから、Linux環境に移行してきた場合などは、APIやドライバはカーネル提供の物を使い、アプリケーションや、ファイルシステムなどは必要ないとした場合に、”init”をユーザーのプログラムに置き換えてしまうことによって、非常にシンプルな構成のシステムとすることも可能です。8Bitマイコンのプログラムは、それ自体でメモリ管理や、割り込み制御などを行っているので、単純に移植だけをするときなどは、移植のための工数を最小限にすることができます。次に、inittabで指定されている/etc/init.d/rc.Sを見ていきましょう。Sで始まっているファイルを、アルファベット順に実行していってます。そのうち、.shで終わるものは、再帰的にshellを起動せずに実行し、その他のファイルは、startオプションをつけて実行していってます。この再帰的にshellを実行しないことによる速度アップはたいしたことないと思われますので、あまり気にしなくてもいいでしょう。このような方式をとるメリットとしては、あるサービスを起動するにあたって、例えばWebサービスはネットワークが起動した後で起動したいとした場合、Webサービスのプログラムのインストーラーは、他のスクリプトの存在や、他のスクリプトの中身を気にせずに、S41以降の番号を起動スクリプトにつけておけばいいということになるので、デスクトップOSのように、ユーザーがプログラムを必要に応じてインストールするような環境では有利に働きます。組み込みシステムのように、ユーザーがプログラムを追加することは考えなくていいシステムであれば、こういった構成をとる必要はありません。(こちらが使いやすいと思えば、このままでもいいし、他の構成をとった方がいいのであれば、他の構成をとることもできます。)ディストリビューションで用いられているinitrdディストリビューションで用いられているLinuxのブートプロセスは、ブートローダーカーネル、initrdの読み込みカーネル起動カーネルinitrdをルートファイルシステムとしてマウントinitrdの中の”init”を起動initinitrdの中のドライバをロードinittab中で、ロードしたドライバを用いてDISKドライブをマウントDISKドライブをルートファイルシステムに変更DISKドライブ中のrcスクリプトを実行といった手順で初期化されていきますが、今回のシステムでは、ブートローダーカーネル、initrdの読み込みカーネル起動カーネルinitrdをルートファイルシステムとしてマウントinitrdの中の”init”を起動initinitrdの中のドライバをロードinitrdの中のrcスクリプトを実行といった手順となります。ルートファイルシステムは、initrdのままアプリケーションを実行することになります。これによって、ディスクドライブがない状況でLinuxが動作することになり、ファイルシステムの破損などを考慮する必要がなくなります。0x86プロセッサでの組み込みLinuxの対応作業はソースコードの改変なしでメニューの選択だけで行うことができましたが、ARMプロセッサボードを開発した場合にはソースコードの改変作業が発生します。Blobといったメカニズムによってカーネルソースコードの改変が最低限で済むよう設計されています。そのため、新規にARMプロセッサを採用したボード上にLinuxを移植しようとするときに、作業量が最も多くなると思われる部分は、ブートローダの移植になります。CPUメーカの提供しているリファレンスボードや、開発ツールメーカーの開発ボードなどでは最初からU-BootやRedBootなどのブートローダーが最初から書き込まれており、リファレンスボードでソフト、別の場所でハードの開発を並行して進めて、最後に自社のボードに乗せ換えようとする場合などで、最後の段階においてブートローダがうまく移植できないといった問題が発生することもままあります。ブートローダーの最初の部分は、メインメモリも見えない状態で動く必要がありますので、問題が発生した場合のデバックも簡単ではありません。したがって、リファレンスボードでの開発を並行して行うのであれば、ハードウェアを設計する段階で、製品とリファレンスボードでは全く同じDRAMを使用する、製品ボードにはコネクタは実装しないが、JTAGのパターンを残しておくなどの工夫が重要です。Blobの改変も少々癖があるので、最初は非常にとっつきにくいのと、デバッグがやりにくいといった欠点もありますが、慣れてしまえばなんとかなりますので、いろいろいじってみましょう。PCでは、最初からマザーボードに実装されているBIOSや、UEFIとして実装されていて、メインメモリの容量や、アクセスタイミング、キーボードや、初期メッセージを出すためのスクリーンの準備など、ハードウェアの構成に依存する部分の初期化作業を行ってくれますが、新規開発ボードではそのBIOSに相当する部分を自分で作る必要があります。ここで、実際のボードでどのようにU-Bootを移植していくのかを解説していきたいところですが、市販のリファレンスボードや、開発ボードなどでは、ブートローダーはさわるなといった感じのボードが多いですし、CPUのデーターシートがNDA契約がないと見れないボードの開発はしたくないので、実機での開発手順の公開をどのようにしていくかは検討中です。いまのところ、BeagleBoardなんかがいいのかな?と考えているところです。0前回の「組み込みシステム用Linuxを作ってみよう(1)」からの続きです仮想マシンで実行することも考えましたが、仮想マシンで動いたところで動いてる実感に乏しかったので、実機をUSBメモリで起動する方法を解説していきます。同様のことを仮想マシンで実行することも可能ですので、実機を準備するのが面倒な場合は仮想マシンで実行してみてください。前回作成した、イメージをUSBメモリーに書き込んで、USBブート可能なPCで起動してみましょう。q数値は、メモリによって異なりますが、とりあえず全体をLinuxで使用するように設定します。続いてフォーマットと、メディアにデーターを書き込むことはないので、定期的なfsckの実行を抑制するためのパラメーターの設定をします。/dev/sdb1次に、MBRを書き込みます。これは、BIOSがセクター0を読み込んでOSを起動するまでのコードが格納されているコードです。このコードは前回ブートローダーにsyslinuxを選択したため、output/build/syslinux-6.03以下にビルドされています。/dev/sdbMBRを書き込んだら、ファイルシステムをマウントして、MBR以降のブートローダーのコードを書き込みます。/mnt/usb最後に、カーネルとRAMディスクイメージをコピーして、syslinuxのブートメニューを設定してUSBメモリーをアンマウントします。/mnt/usbこれで、起動メディアの完成です。USBブート可能な、PCにメディアを刺して起動すると、今回作成したLinuxが起動するはずです。起動したLinuxでは、rootでログインして、コマンドを消したり、変な設定をしても、USBメモリを書き込み可能でマウントしない限り、再起動すると元に戻ります。書き込み可能メディアをマウントしていないので、シャットダウン処理の必要もありません。toの途中ですが、ちょっと読み物をこれから組み込みシステムを開発しようと思っている方は、大きく2つの方向からのアプローチをとっていると思います。1つは、これまで8Bitマイコンのシステムを作ってきてデーター量の増加や、扱うデバイスの複雑化などによって、より高機能なシステムを利用するためにLinuxを採用してみようというアプローチ。一方は、これまでデスクトップOSでシステムを組んできたが、専用機にすることによって、メンテナンス性の向上や、ユーザーの自由度を制限することによって、システムの安定性を望んでの組み込みLinuxを採用してみようというアプローチです。どちらからのアプローチでも、システムが完成してしまえば、それなりの効果は得られるはずです。そのためには、これまで組んできたシステムでは全く考慮しなくてよかった部分を考慮する必要が出てきます。最初にマイコンからのアプローチについて検討してみましょう。Linuxの基本は、マルチユーザー、マルチタスクのOSです。マルチユーザのOSとは、Aさんでログインしたら、Aさんの環境、BさんでログインしたらBさんの環境が準備されていることを前提としています。8Bitマイコンシステムでは、マルチユーザーを意識したものはほとんど無いと思いますので、この概念を理解して進めるかどうかによって、アプローチ方法が大きく変わります。今後、インターネットにつながって、システムとしてセキュリティを考えていかなくてなならないのであれば、マルチユーザの概念を理解しておく必要があります。ここでは、温度センサを例に解説していきましょう。一般的な温度センサであれば8Bitマイコンで十分なのですが、一定時間毎に温度を記録してグラフを出しましょう。そのグラフはPCやスマートフォンなどからWebブラウザで見えるようにしましょうとなると、LinuxなどのWebサーバーが利用できるOSを採用したほうがいいことにまります。データーも永遠に増え続けるので、誰かが操作してバックアップするなりクリアするといったメンテナンスも必要になってきます。このあたりから、マルチユーザーの機能が必要になってきます。メンテナンスを行う権限を持ったユーザーと、見ることだけが可能なユーザーといった2種類のユーザー権限を定義したシステムを考えていく必要が出てくるといった具合です。ファイルシステムいった概念も、8Bitマイコンにはなかったものです。Toのページでルートファイルシステムをどうするかなどの解説もしてきましたが、マイコンでは、OSもアプリケーションも最終的に1つの実行形式ファイルにリンクしてROMに書き込むといったアプローチが一般的であるのに対して、Linuxでは、ファイルをコピーするコマンド、システムをシャットダウンするコマンドなど、それぞれの機能を別々のファイルとして実現しています。今後、ブートローダーの移植などの話題もこのブログで取り上げていく予定ですが、ブートローダーのプログラムなどは、8Bitマイコンのプログラムに非常に似ています。逆に、一般的に使用されているブートローダの機能を拡張するだけである程度のシステムであれば実現することも可能であるともいえます。デスクトップOSからのアプローチはどうでしょうデスクトップOS(Windowsや、一般的なLinuxのディストリビューション)では、システムは、エンドユーザーが使いながら進化させていくことを前提に設計されています。文章を書きたいなら、ワードプロセッサをインストール、セキュリティを向上させるために、ウィルススキャンをインストールなどして、システムの状況は日々進化していくものとして設計されています。組み込みシステムでは、システムそのものの変更は基本的に行われません。工作機械に組み込んだコンピュータの能力が余ってるからといって、工作機械で、ゲームやネットサーフィンをしようとはユーザーも思わないでしょう。逆に、できるからといって、ネットサーフィンの機能などをつけたら、ウィルスなどで工作機械が誤動作でもしようものなら目も当てられません。そのまま、工作機械を例に話を進めますが、システム設計者は、どのような機能を実現するかだけでなく、機械を組み立てる際に設定すべき項目(モーターがいくつあって、それぞれのモーターの性能、温度センサの位置とそれぞれの意味など)と、エンドユーザーが設定すべき項目(どのモーターに何ミリ径のドリルをつけるかなど)のように、だれが何を設定し、どのように操作するかを考えながら設計する必要がります。設定項目については最低限、シンプルで目的を達成するためにわかりやすくすることが重要です。なんでもできるようにしてしまうと、Linuxなので表計算ソフトを入れてしまえということになりかねません。オープンソースなどのLinuxの便利なツールを最大限に生かしながら、ユーザーにはLinuxであることを意識させない設計が必要です。Linuxは非常にパワフルなOSで、8Bitマイコンの代わりをすることもできますし、データーセンターの巨大サーバーのようなシステムを構築することができるOSです。どのような機能を追加して、どのような機能を隠蔽していくかは設計者のセンスにかかってきます。今後、このブログで、8Bitマイコンに近い使い方や、デスクトップOS的な使い方など、様々な例をあげながら解説していく予定です。Toの解説だけでなく、考え方やアプローチの方法なども追記していきます。