前章で実際にArmadilloを動かしてみて、Armadilloとはどのようなコンピューターなのか、大体のイメージが掴めたと思います。
この章では、Armadilloがどのようなソフトウェアで構成されていて、それらがどのように動いているのか、その仕組みを詳しく説明していきます。
Armadilloは、以下のソフトウェアによって動作します。
ブートローダーは、電源投入後、最初に動作するソフトウェアです。
Armadillo-600シリーズではU-bootブートローダー(以降、単にU-bootと記述します)を使用します。
U-bootは、二つの動作モードを持っています。
一つは、オートブートモードです。
オートブートモードでは、カーネルイメージをブートデバイス[]から読み出し、メモリに展開してからカーネルに制御を移します。
この動作は、「ブートローダーが行う処理」で詳しく説明します。
もう一つの動作モードは保守モードで、コンソールにプロンプトを表示し、ユーザーが入力したコマンドに応じてU-Bootの環境変数の変更などを行えます。
Linuxカーネルは、プロセス管理(スケジューリング)、時間管理、メモリ管理、デバイスドライバ、プロトコルスタック、ファイルシステムなどのOSとしてのコア機能を提供します。
Armadillo-600シリーズでは、標準のカーネルとして Linux を使用します。
Linuxカーネルの初期化処理については、「カーネルの初期化処理」で詳しく説明します。
ユーザーランドとは、アプリケーションプログラムやライブラリ、設定ファイル、データファイル、デバイスファイルなどLinuxシステムが動作する上で必要なカーネル以外のものをいいます。
| カーネルとユーザーランドとのインターフェース |
---|
Linuxカーネルは、ユーザーランドで動作するプログラムとの唯一のAPI(Application Program Interface)として、システムコールを提供します。
ユーザーランドのプログラムは、必ずシステムコールを通してカーネルの機能を呼び出します。 |
Linuxシステムでは、ユーザーランドのファイルとディレクトリ[]同士の位置関係を階層的な木構造として表現します。
ファイルとディレクトリの木構造をファイルシステムといいます。
また、木構造の最上位に位置するディレクトリをルートディレクトリといいます。
全てのファイルはルートディレクトリから辿ることができます。
ファイルシステムは、通常、ストレージデバイス[]に書き込まれて使用されます。
ストレージデバイスをファイルシステムと関連付け、システムから使用できるようにすることを、「マウントする」といいます。
Linuxシステムでは、任意のディレクトリにデバイスをマウントすることができます。
特に、ルートディレクトリにマウントされたファイルシステムを、ルートファイルシステムといいます。
| Windowsのファイルシステムとの違い |
---|
Windowsも階層的なファイル構造を持っていますが、Linuxシステムとは決定的な違いがあります。
それは、Linuxシステムのファイルシステムにはドライブという考え方がないことです。 Windowsでは複数のストレージデバイスがある場合、デバイスごとにドライブという形で区別し、別々の階層構造を持ちます。
一方で、Linuxシステムでは、複数のデバイスがある場合でも、ルートディレクトリから連なる一つの階層構造として表現します。
つまり、USBメモリを/mnt/usbディレクトリにマウントし、SDカードを/mnt/usb/sdディレクトリにマウントするといったことができます。
デバイスがどれだけ増えようとも、必ずルートディレクトリから辿ることができます。 |
Armadillo-600シリーズでは、ユーザーランドの標準ルートファイルシステムとして、Debian 9(stretch)を採用しています。
本章では、標準状態のArmadilloに電源を投入してから、ログイン画面が表示されるまでの起動シーケンスを詳しく説明します。
大まかな起動の流れは、以下のようになります。
ブートローダーが行う処理
-
ブートローダが起動し最低限のハードウェア初期化を行う
-
カーネルイメージをメモリにロードする
-
ブートローダーを抜けて、カーネルに実行を移す
カーネルの初期化処理
-
カーネルが様々なコアやデバイスドライバの初期化処理をおこなう
-
ルートファイルシステムをマウントする
-
カーネルがユーザーランドのinitというアプリケーションプログラムを実行する
ユーザーランドの初期化処理
-
systemdがシステム初期化処理を実行する
-
systemdがsystemd-logind.serviceを起動する
-
systemdがserial-getty@ttymxc0.serviceを起動する
-
systemd-logindがログイン画面を表示する
Armadilloシリーズは、汎用CPUボードという性格上、ユーザーが書き換え可能なフラッシュメモリを搭載しています。
Armadillo-640では、ジャンパの設定を変更することで、microSDカードとeMMCのどちらからブートローダーを起動するのか選択できます。
ユーザーが操作を誤ってeMMCの内容を消去してしまっても、microSDカードからブートローダーを起動することで復旧が可能です。
表6.1 ジャンパの設定と起動デバイス
JP1 | JP2 | 起動デバイス |
---|
オープン | ショート | eMMC |
ショート | ショート | microSD |
| ジャンパのオープン、ショートとは |
---|
-
-
「オープン」とはジャンパピンにジャンパソケットを接続していない状態です。
-
-
「ショート」とはジャンパピンにジャンパソケットを接続している状態です。
|
起動したU-bootは、最低限のハードウェアの初期化を行った後、自分自身をメモリ(RAM)にコピーします。
その後の動作は、スライドスイッチの設定によって決定されます。
スライドスイッチを、図6.1「スライドスイッチの設定」の 1 側に設定しておくと保守モード、2 側に設定しておくとオートブートモードとなります。
-
-
ブートローダーは保守モードになります。保守モードでは、ブートローダーのコマンドプロンプトが起動します。
-
-
ブートローダーはオートブートモードになります。オートブートモードでは、ブートローダーのコマンドプロンプトが表示されず、OSを自動起動します。
スライドスイッチを、図6.1「スライドスイッチの設定」の 1 側に設定した状態で起動すると、U-Bootは保守モードとなります。
保守モードの場合、U-Bootは、コンソールにプロンプトを表示してコマンド入力待ち状態となります。
保守モードでは、U-Bootの環境変数の変更などを行うことができます。
boot コマンドを実行することで、U-Bootはカーネルを起動するための処理を開始します。
参考として、図6.2「U-boot保守モード時の表示」に保守モード起動時のシリアルコンソールへの表示を示します。
スライドスイッチを、図6.1「スライドスイッチの設定」の 2 側に設定した状態で起動すると、U-Bootはオートブートモードとなります。
これが通常運用での設定です。
オートブートモードの場合、U-Bootは、コマンド入力待ち状態になることなく、自動的にカーネルを起動するための処理を開始します。
次にU-Bootは、環境変数で設定されたストレージデバイスからLinuxカーネルイメージとDTB(Device Tree Blob)をメモリにロードします。
| |
---|
Device Treeは、ハードウェア情報を記述したデータ構造体です。
ハードウェアの差分をDevice Treeに記述することによって、1つのLinuxカーネルイメージを複数のハードウェアで利用することができるようになります。 DTB(Device Tree Blob)は、Device Tree Source(Device Treeを記述したソースファイル)をビルドして生成されるバイナリファイルです。 |
その後、ブートローダーを抜け、カーネルの開始番地へ実行を移します。
この一連の処理を、Linuxカーネルをブートすると表現します。
U-BootがLinuxカーネルをブートするときの、コンソールへの出力を図6.3「U-Bootオートブートモード時の表示」に示します。
|
U-Bootはシリアルの初期化が完了すると自身のバージョンを表示します。
|
|
この行から数行に渡って、ロードされたカーネルの情報を表示されます。
|
|
この行から数行に渡って、ロードされたDevice Tree Blobの情報を表示します。
|
|
この行以降は、カーネルが表示しています。
|
ブートローダーから実行を移されると、ようやくLinuxカーネルが動作を開始します。
Armadilloのカーネル起動ログの例として、Armadillo-640の起動ログを図6.4「Armadillo-640カーネルブートログ」に示します。
|
ブートローダーから実行が移ると、カーネルはまず自身のバージョン、CPUアーキテクチャ、マシン名、メモリの状態などを表示します。
|
|
カーネルパラメータは、「root=/dev/mmcblk0p2 rootwait」が使用されています。
|
|
ここから、各デバイスやカーネル内部の初期化処理が始まります。
|
|
eMMCの第1から第3パーティションが認識されています。
|
|
eMMCの第2パーティションをマウントしています。
|
カーネルは、初期化処理が終えた後、 initramfs を一時的なルートファイルシステムとしてマウントし、initramfs 上のルートディレクトリにあるinitを実行します。
initramfsのinitは、procfs []やsysfsのマウントや、systemd-udevd の起動などを行います。
その後、/dev/mmcblk0p2[](eMMCの第2パーティション)を本当のルートファイルシステムとしてマウントし、/sbin/init を実行します。
Armadillo-640(systemd を使用するユーザーランド)では、/sbin/initは/lib/systemd/systemdへのシンボリックリンクとなっており、実際にはsystemdというアプリケーションプログラムが実行されます。
起動時の処理状況を表示するシステムコンソールには、/dev/console を使用します。
/dev/consoleの実体は、Device Treeの/chosen/stdout-pathで指定したデバイスがデフォルトとして使用されます。
このデバイスは、カーネルパラメータのconsoleオプションを指定することで変更することができます。
図6.4「Armadillo-640カーネルブートログ」で示したように、Armadillo-640では標準ではconsoleが指定されていません。
Armadillo-640の標準イメージでは、/chosen/stdout-pathに UART1 (/dev/ttymxc0) が指定されているため、/dev/ttymxc0 がシステムコンソールとして使われます。
| Systemdの概要 |
---|
SystemdとはLinuxのシステム管理デーモンの一つです。
高速なシステム起動/終了や設定ファイルによるシステム管理の共通化、柔軟なプロセス起動を行うことができます。 Linuxの起動を行う処理は今までSysVinitが広く用いられてきました。
しかし、並列処理ができない事や、タイマー起動やプロセス起動を行う事ができず、柔軟な起動を行うことができないという問題を抱えていました。
この問題を解決するためにSystemdが登場し、多くのLinuxディストリビューションで採用されるようになりました。 Debian GNU/Linuxでは、Debian 8.0 コードネーム: jessieから、デフォルトのシステム管理デーモンにSystemdが使われています。 Systemdでは、プロセスの起動やファイルシステムのマウントなどの処理を "Unit" という単位で管理します。
あるUnitが起動した後に起動する、あるUnitと同時に起動する、など細かな制御が可能です。 |
Systemdはまず、Systemd unit generators(もしくは単にGenerators)と呼ばれるプログラム群[]を実行します。
Armadillo-640ではこれらのプログラムは /lib/systemd/system-generators ディレクトリに配置されています。
表6.2 Systemd unit generators
名称 | 説明 |
---|
systemd-cryptsetup-generator
| /etc/crypttab を元に Unit を生成するジェネレータ
|
systemd-debug-generator
| ランタイムデバッグシェルを有効にし、起動時に特定のユニットをマスクするためのジェネレータ |
systemd-fstab-generator
| /etc/fstab を元に Unit []を生成するジェネレータ
|
systemd-getty-generator
| カーネルコンソールを使用する serial-getty@.service Unit []を自動的に生成するジェネレータ |
systemd-gpt-auto-generator
| GPTパーティションタイプのGUIDに基づいて、ルートパーティション、 /home パーティション、および /srv パーティションを自動的に検出してマウントし、スワップパーティションを検出して有効にするジェネレータ |
systemd-hibernate-resume-generator
| カーネルパラメータ resume= の値に従って systemd-hibernate-resume@.service Unit を生成するジェネレータ |
systemd-rc-local-generator
| /etc/rc.local []を起動時に、 /usr/sbin/halt をシャットダウン時に実行するようにするためジェネレータ
|
systemd-system-update-generator
| /system-update が存在する場合に、起動プロセスを system-update.target に自動的にリダイレクトするジェネレータ
|
systemd-sysv-generator
| SysV init のスクリプトをSystemd上で実行するための Unit を自動的に生成するジェネレータ |
次に Systemd は、すべてのUnitファイルを読み込み、各Unitの依存関係にしたがって各起動処理を行います。
この時に、serial-getty@ttymxc0.service および systemd-logind.service が起動され、systemd-logind によってログイン画面が表示されます。
| |
---|
Systemd が起動した Unit の順番は systemd-analyze コマンドで調べることができます。 次のように systemd-analyze に plot 引数を付けて実行すると、各Unitの起動順序、起動時間などがわかる画像ファイル(SVG形式)が生成されます。 [armadillo ~]# systemd-analyze plot > /home/atmark/systemd-analyze.prot.svg この画像ファイルをATDEで表示するには eog コマンドを実行します。
なお、SVG形式の画像ファイルはFirefox などのWebブラウザでも表示することができます。 [ATDE ~]$ eog systemd-analyze.prot.svg |
6.3. ルートファイルシステムのディレクトリ構成
Linuxシステムでのディレクトリ構成には、デファクトスタンダード(事実上の標準)となっている構成があります。
それぞれのディレクトリに何を格納するかということも、慣習的に決まっています。
それぞれのディレクトリには特定の役割がありますので、それを理解することで、ファイルを探す場合にどのディレクトリを探せばよいか、また、ファイルを追加する場合にどのディレクトリに置けば適切かということが分かります。
| ディレクトリ構成の標準規格 |
---|
ディレクトリ構成の標準規格としてFHS(Filesystem Hierarchy Standard : ファイルシステム階層標準)があります。 すべてのLinuxシステムがこの標準に従っているわけではありませんが、特別な理由がない限り、FHSに従ったディレクトリ構成とするのが望ましいでしょう。 |
Armadillo-600シリーズのルートファイルシステムの主なディレクトリの構成は、以下のようになっています。
表6.3 ディレクトリ構成
ディレクトリ | ディレクトリの内容
|
---|
/ | ルートディレクトリ、ルートファイルシステムのマウントポイント |
/bin | 基本的なユーザーコマンドの実行ファイル |
/boot | 起動に必要なファイル |
/dev | デバイスファイル |
/etc | 設定ファイル |
/home | ホームディレクトリ |
/home/atmark | atmarkユーザーのホームディレクトリ |
/lib | 基本的なライブラリ |
/media | CD-ROMやUSBメモリなどのリムーバブルメディアのマウントポイント |
/mnt | 一時的にマウントするファイルシステムのマウントポイント |
/opt | サードパーティが提供する追加データ・アプリケーション |
/opt/license | Armadilloのライセンス情報 |
/proc | procfsのマウントポイント(プロセス情報) |
/root | rootユーザーのホームディレクトリ |
/run | 再起動後に保持されない揮発性のランタイムデータ |
/sbin | 基本的なシステム管理用コマンドの実行ファイル |
/srv | システム上で運用されているサーバが使うデータを格納するディレクトリ |
/sys | sysfsのマウントポイント(システム情報) |
/tmp | 一時的なファイル |
/usr | ユーザー共有情報ファイル |
/usr/bin | 必須でないユーザーコマンドの実行ファイル |
/usr/sbin | 必須でないシステム管理者用コマンドの実行ファイル |
/usr/lib | 必須でないライブラリ |
/var | 頻繁に更新されるファイル |
/var/log | ログが保存されるディレクトリ |
アプリケーションの実行ファイルは、/bin、/usr/bin、/sbin、/usr/sbinディレクトリに置かれます。
これらのディレクトリ内にあるファイルが、シェルでコマンドを入力したときに検索されます。
そしてコマンドと同じファイル名のファイルがこれらのディレクトリに合った場合、そのファイルが実行されます。
ユーザーごとのホームディレクトリは/homeディレクトリに用意されています。
Armadillo-600シリーズでは、atmark ディレクトリがあります。
rootユーザーでログインした場合のホームディレクトリは、/rootディレクトリになります。
ライブラリファイルは/libまたは/usr/libディレクトリに置かれます。
共有ライブラリを使用するプログラムを実行する場合は、これらのディレクトリ内に共有ライブラリを置いておく必要があります[]。
/devディレクトリには、デバイスファイルが置かれます。
デバイスファイルは、デバイスを仮想的にファイルとして表したものです。
デバイスファイルに対して操作を実行することにより、デバイスを制御することができます。
例として、Armadillo-640では、/dev/ttymxc2はCON3/CON4のシリアルインターフェースのシリアルデバイスをファイルとして表したものです。
/dev/ttymxc2に対してデータの読み書きをすることで、シリアルデバイスからデータを受信/送信することができます。
/proc、/sysディレクトリ内のファイルを操作することで、プロセス、システムの状態を参照、変更することができます。
/procにはprocfs、/sysにはsysfsがマウントされています。
procfs、sysfsはカーネル内部のデータ構造にアクセスすることができる機能を提供する仮想的なファイルシステムです。
カーネルメッセージやアプリケーションの動作ログなどは/var/logディレクトリに保存します。