ブートローダーの役割と移植アーキテクチャ
ARM ベースの Linux 組み込みシステムにおいて、プロセッサの電源投入直後に実行される最初のソフトウェアはブートローダー(Bootloader)である。その主要な責務はクロック初期化、DRAM コントローラのセットアップ、そしてストレージデバイス(eMMC/NAND/SDカード等)からカーネルイメージをメモリ領域へ展開し、エントリポイントをジャンプさせることだ。PC アーキテクチャでいう BIOS/UEFI に相当する存在であり、NXP 製 i.MX シリーズのような SoC では標準的な U-Boot が広く採用されている。
公式レポジトリのソースコードは汎用的なサポートに留まるため、実機開発ではベンダーが独自に HAL やデフォルト設定をオーバーライドしたポートバージョンを使用するのが一般的である。本稿では、i.MX6ULL 系プロセッサを搭載したカスタム評価ボードを対象に、既存の移植版 U-Boot をビルドし、SD メモリ経由で起動させるまでの一連の手順を解説する。
Cross-Compilation 環境の準備とスクリプト最適化
Ninja/Make システムを用いたビルドには ncurses ライブラリが必須となる。Ubuntu ベースのホスト環境であれば以下のコマンドで依存パッケージを導入できる。
sudo apt-get update && sudo apt-get install -y libncurses-dev flex bison
ワークスペースを作成し、配布されたアーカイブを展開する。
以降のビルドフローでは、クロスコンパイラパス、ターゲット構成ファイル、並列ジョブ数を明示的に定義することでミスを防ぎ、再現性を高めるアプローチを取る。
#!/bin/bash
# build_uboot.sh: i.MX6ULL Target U-Boot Build Script
export CROSS_COMPILE="arm-linux-gnueabihf-"
export ARCH="arm"
export TARGET_CONFIG="mx6ull_14x14_ddr512_emmc_defconfig"
export JOB_COUNT=$(nproc) # ホストコア数に基づいて自動調整
echo "[1/3] Cleaning previous build artifacts..."
make distclean
echo "[2/3] Applying target configuration: ${TARGET_CONFIG}"
make "${ARCH} CROSS_COMPILE=${CROSS_COMPILE}" "${TARGET_CONFIG}"
echo "[3/3] Compiling U-Boot (Parallel jobs: ${JOB_COUNT})..."
make V=1 "${ARCH} CROSS_COMPILE=${CROSS_COMPILE}" -j"${JOB_COUNT}"
if [ $? -eq 0 ]; then
echo "Build completed successfully. Output binary: u-boot.imx"
else
echo "Build failed. Please check compiler path or dependencies."
exit 1
fi
このスクリプトは単なるコマンドの羅列ではなく、変数管理とエラーチェックを組み込んだものに変更している。`distclean` で中間ファイルを削除し、`defconfig` でハードウェア固有のオプション(メモリアクセスタイミングや周辺デバイスの有効化)を読み込む。最後に `-j` オプションでマルチコア活用を図る。スクリプトを実行可能にして呼び出す。
chmod +x build_uboot.sh
./build_uboot.sh
イメージヘッダの変換(u-boot.bin → u-boot.imx)
純粋な ELF/binary ファイルである `u-boot.bin` は、i.MX シリーズの ROM プログラムにより直接実行できない。起動プロセスを確立するためには、IVT(Image Vector Table)、DCD(Device Configuration Data)、および BROM ヘッダを含むカプセル化形式に変換する必要がある。これは通常、ツールチェーンに含まれる `mkimage` ユーティリティによって自動化される。
- IVT: エントリアドレス、データ・タイプ、サイズ等のメタデータを含む構造体。
- DCD: リフレッシュレートや IO 設定など、外部メモリ初期化のためのビットマップリスト。
- BROM Header: ブートメディアの種類や読み込み先アドレスを指定する固定フォーマット。
ビルド成功後、ディレクトリルートに生成される `u-boot.imx` が実際に書き込むべき最終イメージとなる。
メディアへの書き込みとファームウェア起動検証
i.MX シリーズのブートマジックを用いた書き込みツール(例:imxdownload または nxptools)を通じて SD カードへ転送する。デバイスノードの誤指定によるデータ破損を防ぐため、以下のように入出力先を厳密に確認する処理を含む。
#!/bin/bash
# flash_sdcard.sh
TARGET_IMG="u-boot.imx"
DEVICE="/dev/mmcblk0" # 実際のマウントポイントに合わせて変更必須
if [ ! -b "$DEVICE" ]; then
echo "Error: Block device $DEVICE not found."
echo "Usage: lsblk | grep mmcblk"
exit 1
fi
chmod +x ./imxdownload
echo "Flashing $TARGET_IMG to $DEVICE ..."
./imxdownload "$TARGET_IMG" "$DEVICE"
echo "Flash operation finished."
sudo sync
書き込み完了後、対象基板の DIP スイッチまたはショートジャンパーを「SD ブート」モードに設定する。USB-TTL ケーブルで UART0 ポートに接続し、ターミナルエミュレータ(baud: 115200, 8N1)を開く。リセットキーを押下すると、以下のような初期化シーケンスが表示される。
U-Boot 2016.03 (Jul 15 2024 - 15:57:22 +0900) for i.MX6ULL-EVK
CPU: Freescale i.MX6ULL rev1.2 at 396 MHz
Reset cause: POR
Board: MX6ULL 14x14 EVK
I2C: ready
DRAM: 512 MiB
PMIC: PFUZE300 DEV_ID=0x33 REVID=0x11
MMC: FSL_SDHC: 0, FSL_SDHC: 1
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Net: FEC1
Hit any key to stop autoboot: 0
=>
各出力項目の技術的意味合いを以下に整理する。
| 出力内容 | 技術的意味 |
|---|---|
| rev1.2 at 396MHz | silicon revision および現在の CPU クロック周波数。初期状態は低クロック駆動であることが一般的。 |
| Reset cause: POR | Power-On Reset による起動を示す。POR_B ピンのロジックハイレベル状態を検出。 |
| FSL_SDHC: 0, 1 | SysTick 互換の MMC コントローラ検出。コントローラ 0 は外部 SD/MMC、1 は eMMC パスに該当。 |
| *** Warning - bad CRC... | NVRAM/EEPROM 内の环境变量に不整合が発生した旨。初回起動時またはフラッシュ消去後に常時表示される。 |
| FEC1 | Ethernet MAC コントローラが認識された状態。MAC アドレスは U-Boot env の ethaddr で別途割り当てが必要。 |
カウントダウンタイマー(デフォルト 3 秒)内で Enter キーを入力すると、自動的にカーネル展開フローがスキップされインタラクティブシェルが起動する。ここで環境変数の編集(`setenv`)、ネットワーク転送(`dhcp`/`tftp`)、メモリダイアグニクス(`md`/`mm`)、パーティショニング操作(`fatload`/`ext4load`)などが可能になる。特に `fdt addr` や `bootm` といったサブコマンドは、デバイスツリーブロックの操作や二次ブートロードの実行において必須となる。