はじめに (対象読者・この記事でわかること)
この記事は、組み込みLinux開発に携わる方、Linuxカーネルのビルドに興味がある方、特にU-Bootブートローダ環境でカスタムカーネルを導入したい方を対象としています。
この記事を読むことで、Linuxカーネルの特殊なイメージ形式であるuImageの概念を理解し、LinuxカーネルのソースコードからuImageとデバイスツリー(DTB)をビルドする方法、そしてU-Bootブートローダを介してそれらをターゲットボードにロードし、ブートさせる一連の手順を習得できます。組み込みシステム開発で頻繁に遭遇するuImageの扱いに戸惑うことがなくなるでしょう。
前提知識
この記事を読み進める上で、以下の知識があるとスムーズです。 - Linuxコマンドラインの基本的な操作 - クロスコンパイルの概念(特にARMアーキテクチャ向け) - U-Bootブートローダに関する基本的な理解
Linux KernelにおけるuImageとは?その必要性
Linuxカーネルイメージには、いくつかの種類があります。一般的なPC環境ではvmlinuzや圧縮されたbzImage/zImageが使われますが、組み込みシステム、特にU-Bootブートローダを使用するARMアーキテクチャのボードでは、uImageという形式がよく利用されます。
uImageは、標準的なカーネルイメージにU-Bootが理解できる特殊なヘッダ情報が付加されたものです。このヘッダには、イメージのサイズ、ロードアドレス、エントリーポイント、OSタイプ、アーキテクチャ、イメージタイプ、圧縮タイプなどのメタデータが含まれています。U-Bootはこのヘッダを読み取ることで、イメージがLinuxカーネルであることを認識し、正しいアドレスにロードして実行することができます。
なぜuImageが必要なのでしょうか?それは、U-Bootが単純なバイナリイメージをロードするだけでなく、ロードするイメージの種類やそのプロパティを事前に知る必要があるためです。これにより、U-Bootはより柔軟かつ安全にカーネルをブートできます。また、現代のARM Linuxでは、ハードウェア構成を記述するデバイスツリーバイナリ(DTB: Device Tree Blob)が不可欠です。uImageはDTBと連携してロードされることが多く、DTBをカーネルイメージとは別にロードしたり、あるいはuImage内にDTBを組み込んだりする方法があります。
uImageのビルドとU-Boot環境へのインストール手順
ここからは、実際にLinuxカーネルのソースコードからuImageをビルドし、U-Bootを介してターゲットボードにインストールする具体的な手順を解説します。
前提準備: 開発環境のセットアップ
ターゲットボード向けにカーネルをビルドするには、クロスコンパイラとU-Bootツールが必要です。
-
クロスコンパイラのインストール: ターゲットのARMアーキテクチャに合ったクロスコンパイラをインストールします。例えば、Debian/Ubuntu系の場合は以下のコマンドでインストールできます。
bash sudo apt update sudo apt install gcc-arm-linux-gnueabihf build-essential libncurses-dev -
mkimageツールのインストール:uImageを生成するために必要なmkimageコマンドは、U-Bootツールの一部です。bash sudo apt install u-boot-tools -
Linuxカーネルソースの取得: ビルドしたいLinuxカーネルのソースコードを
gitでクローンします。bash git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git cd linux必要に応じて特定のバージョンにチェックアウトしてください。
ステップ1: カーネルソースの取得と設定
クローンしたカーネルソースのディレクトリに入り、ターゲットボードに合わせた設定を行います。
-
ビルドディレクトリの作成 (オプションだが推奨): ソースツリー外にビルドディレクトリを作成することで、ソースツリーをクリーンに保てます。
bash mkdir ../linux_build export KERNEL_OUT_DIR=$(readlink -f ../linux_build) -
クロスコンパイラパスの設定: ビルド時に使用するクロスコンパイラのプレフィックスを
CROSS_COMPILE環境変数に設定します。bash export ARCH=arm export CROSS_COMPILE=arm-linux-gnueabihf- -
デフォルトコンフィグの適用: ターゲットボードに合わせたデフォルトコンフィグファイルを適用します。
<board_defconfig>はターゲットボードのdefconfig名に置き換えてください(例:multi_v7_defconfig,am335x_evm_defconfigなど)。これらのファイルはarch/arm/configs/以下にあります。bash make O=$KERNEL_OUT_DIR <board_defconfig> -
設定のカスタマイズ (必要に応じて):
menuconfigを使って、カーネルオプションをカスタマイズします。bash make O=$KERNEL_OUT_DIR menuconfigここで、CONFIG_ARM=y、CONFIG_UBOOT_COMPAT=yなどが有効になっていることを確認してください。General setup->U-Boot / RedBoot firmware compatibilityなどでU-Boot互換性が有効になっているか確認できます。
ステップ2: uImageとDTBのビルド
設定が完了したら、いよいよuImageとDTBをビルドします。
Bashmake O=$KERNEL_OUT_DIR uImage dtbs
このコマンドはuImage (arch/arm/boot/uImage) と、指定したボード用のDTBファイル(arch/arm/boot/dts/*.dtb)を生成します。ビルドには時間がかかる場合があります。-jオプションで並列ビルドを行うと高速化できます(例: make -j$(nproc) O=$KERNEL_OUT_DIR uImage dtbs)。
ビルドが成功すると、$KERNEL_OUT_DIR/arch/arm/boot/uImageと$KERNEL_OUT_DIR/arch/arm/boot/dts/以下にDTBファイルが生成されます。
ステップ3: uImageとDTBのインストールとU-Boot設定
ビルドしたuImageとDTBファイルをターゲットボードに転送し、U-Bootからブートさせます。転送方法はSDカード、NFS、TFTPなど、環境によって異なります。ここでは、SDカードのFATパーティションに配置し、U-Bootからロードする例を挙げます。
-
ファイルの転送: ビルドした
uImageと、ターゲットボードに対応するDTBファイル(例:am335x-evm.dtb)をSDカードの第一パーティション(FAT32形式)のルートディレクトリにコピーします。```bash sudo cp $KERNEL_OUT_DIR/arch/arm/boot/uImage /media/$USER/BOOT/ sudo cp $KERNEL_OUT_DIR/arch/arm/boot/dts/am335x-evm.dtb /media/$USER/BOOT/
/media/$USER/BOOT/ はSDカードのマウントポイントに置き換えてください
```
-
U-Bootからのブート: ターゲットボードを起動し、U-Bootプロンプト(
=>)が表示されたら以下のコマンドを実行します。 (アドレスはボードのRAM構成によって適宜変更してください。0x80000000はカーネルロードアドレス、0x81000000はDTBロードアドレスの例です。)text => fatload mmc 0:1 0x80000000 uImage => fatload mmc 0:1 0x81000000 am335x-evm.dtb => setenv bootargs console=ttyS0,115200 root=/dev/mmcblk0p2 rw rootwait # ルートファイルシステムやコンソール設定 => bootm 0x80000000 - 0x81000000*fatload mmc 0:1: SDカードのパーティション1からファイルをロードします。 *0x80000000:uImageをロードするメモリのアドレス。 *uImage: SDカード上のファイル名。 *bootargs: Linuxカーネルに渡す起動引数。ルートファイルシステムやコンソールポートなどを指定します。 *bootm:uImageをブートするコマンド。-はRAMディスクを使用しないことを示します。0x81000000はDTBのアドレスです。 -
boot.scrによるスクリプト化: U-Bootコマンドを毎回手入力するのは手間がかかります。boot.scrというスクリプトファイルを作成することで、自動的にこれらのコマンドを実行できます。まず、
boot.txtというテキストファイルを作成します。```text
boot.txt の例
setenv bootargs console=ttyS0,115200 root=/dev/mmcblk0p2 rw rootwait fatload mmc 0:1 0x80000000 uImage fatload mmc 0:1 0x81000000 am335x-evm.dtb bootm 0x80000000 - 0x81000000 ```
次に、
mkimageを使ってこのテキストファイルをU-Bootが解釈できるboot.scrバイナリファイルに変換します。bash mkimage -A arm -O linux -T script -C none -d boot.txt boot.scr生成されたboot.scrファイルをuImageやDTBと同様にSDカードのFATパーティションにコピーします。U-Bootは起動時に自動的にこのboot.scrを探して実行します。
ハマった点やエラー解決
mkimageコマンドが見つからない
症状: make uImageコマンドやmkimage -A ...コマンドを実行した際に、mkimage: command not foundのようなエラーが表示される。
原因: u-boot-toolsパッケージがインストールされていないため、mkimageコマンドがシステムパス上に存在しません。
解決策: u-boot-toolsパッケージをインストールします。
Bashsudo apt install u-boot-tools
CROSS_COMPILEが正しく設定されていない、またはコンパイラが見つからない
症状: makeコマンド実行時に、「arm-linux-gnueabihf-gcc: command not found」や「No rule to make target 'uImage'」といったエラーが表示される。
原因: CROSS_COMPILE環境変数が正しく設定されていないか、指定されたクロスコンパイラがシステムパス上にありません。
解決策:
1. export CROSS_COMPILE=arm-linux-gnueabihf- のように、コンパイラのプレフィックスを正しく設定しているか確認します。
2. which arm-linux-gnueabihf-gccを実行し、クロスコンパイラがパス上に存在するか確認します。存在しない場合は、クロスコンパイラがインストールされているディレクトリをPATH環境変数に追加します。
bash
export PATH=/opt/toolchains/arm-linux-gnueabihf/bin:$PATH # 例
DTBが見つからない、またはU-BootがDTBを認識しない
症状: U-Bootのbootmコマンドでカーネルが起動しない、または起動してもDTB関連のエラーが出て停止する。
原因:
1. DTBファイルがターゲットボードに転送されていない、またはファイル名が間違っている。
2. U-Bootのfatloadコマンドで指定したDTBファイルのパスやアドレスが間違っている。
3. ロードしたDTBファイルが、実際に使用しているボードと一致しない(カーネルがDTBを解釈できない)。
解決策:
1. uImageと一緒に正しいDTBファイルをSDカードにコピーし、ファイル名を確認します。
2. U-Bootプロンプトでfatloadコマンドが成功しているか(bytes readの表示)を確認します。ロードアドレスも正確か再確認します。
3. make O=$KERNEL_OUT_DIR dtbsでビルドされたDTBファイルが、実際にターゲットボードで使用されているdefconfigと対応するものであることを確認します。必要であれば、カーネルソースのarch/arm/boot/dts/ディレクトリにある該当の.dtsファイルを確認し、DTBを再ビルドします。
U-BootがuImageを認識しない
症状: bootmコマンド実行時に「Bad magic number」や「Wrong Image Format」のようなエラーが表示される。
原因: ロードされたイメージがuImage形式として正しくない可能性があります。
1. mkimageコマンドが正しく実行されていない。
2. make uImage時に何らかのエラーが発生していた。
3. コピー中にファイルが破損した。
解決策:
1. $KERNEL_OUT_DIR/arch/arm/boot/uImageが正しく生成されているか確認します。
2. mkimage -l $KERNEL_OUT_DIR/arch/arm/boot/uImageを実行し、uImageのヘッダ情報が正しく表示されるか確認します。表示されない場合は、ビルドプロセスに問題がある可能性があります。
3. ファイルの転送方法を再確認し、ファイルが破損していないことを保証します。
解決策
上記のエラーは、多くの場合、開発環境の準備不足やコマンドの入力ミス、パスの誤りなどが原因で発生します。問題が発生した場合は、エラーメッセージを注意深く読み、以下の点を確認することが重要です。
- 環境変数:
ARCH、CROSS_COMPILE、KERNEL_OUT_DIRが正しく設定されているか。 - ツールのインストール:
mkimageやクロスコンパイラが正しくインストールされ、パスが通っているか。 - コンフィグ: ターゲットボードに合った
defconfigが適用されているか、menuconfigでU-Boot互換性が有効になっているか。 - ビルド出力:
makeコマンドの出力にエラーがないか、uImageやdtbファイルが期待通りの場所に生成されているか。 - ファイル転送: ターゲットボードにコピーしたファイルが破損しておらず、正しい場所に配置されているか。
- U-Bootコマンド:
fatloadやbootmの引数(アドレス、ファイル名)が正確か。
これらのチェックリストを順に確認することで、多くの問題は解決できるはずです。
まとめ
本記事では、Linux KernelのuImageに関する基本的な知識から、そのビルド、そしてU-Boot環境へのインストール方法までを詳細に解説しました。
- uImageの理解:
uImageはU-Bootがカーネルを認識し、ブートするために必要なヘッダ情報を持つ特殊なカーネルイメージ形式です。 - ビルドプロセス: クロスコンパイラと
u-boot-toolsを準備し、カーネルソースの設定、make uImage dtbsコマンドでuImageとデバイスツリー(DTB)を生成します。 - U-Bootへの導入: 生成された
uImageとDTBをターゲットボードに転送し、U-Bootのfatloadとbootmコマンド、またはboot.scrを利用してカーネルを起動させます。
この記事を通して、U-Bootブートローダを使用する組み込みシステムで、カスタムLinuxカーネルを導入する基礎的なスキルと、トラブルシューティングの基本的な考え方を得られたことでしょう。
今後は、initramfsの導入によるルートファイルシステムの起動、カスタムデバイスツリーの作成、カーネルデバッグ手法など、さらに発展的な内容についても記事にする予定です。
参考資料
- Linux Kernel Documentation: kbuild/makefiles.rst
- U-Boot Documentation: Command
mkimage - U-Boot Documentation: Command
bootm
