OS・実行環境

ブートローダー

電源投入後に最初に動き、OSを起動するプログラム。

概要

ブートローダー(Bootloader)は、組み込み機器・PCなどのコンピュータシステムで、電源投入後に最初に実行されるプログラムです。ハードウェアの基本的な初期化を行い、OSやメインプログラムをメモリにロードして実行を開始させる役割を担います。

組み込みLinuxシステムでは、BootROM(SoC内蔵の変更不可なROM)→一次ブートローダー(SPL/ATF)→U-Boot→Linuxカーネルというように、複数段階で起動処理が進みます。マイコン向けのベアメタル・RTOSシステムでも、最小限のブートローダー(スタートアップコード)が必ず存在します。

ブートローダーはシステムの「信頼の起点(Root of Trust)」であり、セキュアブートの実装やOTA(Over-The-Air)更新処理でも中心的な役割を果たします。

歴史・背景

PC向けブートローダーの歴史は1980年代のBIOS(Basic Input/Output System)から始まります。BIOSは電源投入時にCPUが実行するファームウェアで、デバイス初期化とOSブートを担いました。2000年代にはより高機能なUEFI(Unified Extensible Firmware Interface)に移行しています。

組み込みLinux向けのブートローダーとして最も普及したのはU-Boot(Das U-Boot)で、2000年代初頭から多くのSBC・組み込みSoCで採用されました。

マイコン向けでは、NordicのnRFシリーズのBootloader、STM32のシステムブートローダー(製造時フラッシュ書き込み用)など、各メーカーがマイコン固有のブートローダーを提供しています。DFU(Device Firmware Upgrade)やBluetooth OTAブートローダーは組み込みIoT機器で広く使われています。

ARMv8-A以降では、ARM Trusted Firmware(ATF / TF-A)が信頼境界を管理するEL3(Exception Level 3)のブートコードとして標準化され、セキュリティ強化されたブート手順が整備されています。

技術仕様

組み込みLinuxの多段ブートシーケンス

現代のARMベース組み込みLinuxでは、以下の多段構成が一般的です:

電源投入(Power-On Reset)

【Stage 0】BootROM(SoC内蔵・変更不可)
  - CPUコアの最低限初期化
  - 起動デバイスの選択(SD/eMMC/NAND/NOR/USB等)
  - 次段ブートローダーの読み込み・実行

【Stage 1】一次ブートローダー(SPL / TF-A BL2)
  - DDR SDRAM初期化(最重要:メインRAMの初期化)
  - 次段ブートローダーをRAMへロード

【Stage 2】U-Boot / TF-A BL31
  - 全ペリフェラル初期化
  - コンソール・ネットワーク初期化
  - Linuxカーネル・DTBをRAMへロード
  - セキュアブート(署名検証)

【Stage 3】Linuxカーネル(+initramfs)
  - カーネル本体の展開・実行
  - デバイスドライバ初期化

【Stage 4】ユーザースペース init(systemd等)

MCUブートシーケンス(Cortex-M)

マイコン(ARM Cortex-M)では起動がシンプルです:

電源投入

Cortex-Mコア:フラッシュ先頭(0x08000000)を読む

ベクタテーブル[0]:スタックポインタを設定
ベクタテーブル[1]:Reset_Handlerアドレスへジャンプ

Reset_Handler(スタートアップコード)
  - .data セクション初期化(ROM→RAM コピー)
  - .bss  セクション ゼロクリア
  - SystemInit()

main()

MCU向け応用ブートローダー(DFU・OTA対応)

組み込みIoT機器では、フィールドでのファームウェア更新のため専用ブートローダーを実装します:

【フラッシュレイアウト例(STM32F4)】

0x08000000 - 0x0800FFFF: Bootloader(64KB)
0x08010000 - 0x0807FFFF: Application(448KB)
0x08080000 - 0x080FFFFF: Update slot(512KB)

【起動フロー】
1. ブートローダー起動
2. 更新フラグを確認
3. フラグあり:Updateスロットの署名を検証
4. 検証OK:ApplicationスロットへUpdateスロットをコピー
5. Applicationを起動

ブートローダーの選択

ブートローダー対象用途
U-BootARM/MIPS等の組み込みSoC組み込みLinuxのデファクトスタンダード
BareboxARMなどU-Bootより近代的な設計
GRUBx86系PCデスクトップLinux・サーバー
UEFIx86 / ARM64高性能機器・UEFI準拠
MCUbootARM Cortex-MIoT MCU向け安全ブートローダー
nRF BootloadernRFシリーズNordic BLE OTA専用
STM32 BootloaderSTM32ST製マイコン組み込み版

動作原理

DDR初期化の重要性

組み込みLinux向けブートローダーの最重要処理の1つはDDR SDRAM(メインRAM)の初期化です。SoCのBootROM実行時点では外付けDDRが使えず、SoC内部のSRAM(数十〜数百KB)しか使えません。SPLがDDRコントローラを初期化することで、初めてLinuxカーネルをメモリにロードできます:

/* U-Boot SPL のDDR初期化(擬似コード) */
void board_init_f(ulong dummy) {
    /* UART初期化 */
    preloader_console_init();
    
    /* DDR初期化 */
    ddr_init();  /* SPDロード・タイミング設定・キャリブレーション */
    
    /* DDRが使えるようになったのでU-Boot本体をロード */
    board_init_r(NULL, CONFIG_SYS_TEXT_BASE);
}

セキュアブートの仕組み

セキュアブートでは、各ステージのブートローダーが次のステージの署名を検証します:

BootROM(ハード焼き付けの公開鍵でSPLを検証)
  ↓ 署名検証OK
SPL(ATF BL1で検証、またはBootROMから委譲)
  ↓ 署名検証OK
U-Boot(BL2/BL3で検証)
  ↓ 署名検証OK
Linuxカーネル(U-Bootのfitイメージ署名検証)

A/Bパーティション(アップデートレジリエンス)

OTA更新の信頼性を高めるため、A/Bパーティション方式が使われます:

パーティション構成:
  Boot A | Boot B | System A | System B

更新フロー:
1. 現在Aで動作中
2. OTAでBに新バージョンを書き込み
3. ブートローダーのスロット設定をBに変更
4. 再起動→Bで起動
5. 起動成功確認後、Bをアクティブスロットとして確定
6. 次回OTA更新はAスロットに上書き

用途・ユースケース

組み込みLinux機器

産業用ゲートウェイ・スマートホームハブ・カーナビなど、Linuxが動く組み込み機器では必ずブートローダーが存在します。U-Bootが最もよく使われ、デバイスツリーのロードと検証を担います。

IoT機器のOTA更新

スマートスピーカー・工業センサー・スマートメーターなどのIoT機器では、フィールドでのファームウェア更新が不可欠です。MCUbootや独自ブートローダーがOTAの信頼性・セキュリティを担保します。

セキュア製品

医療機器・決済端末・産業制御機器では、改ざんを防ぐためのセキュアブートが法規制や認証で要求されます。ブートローダーが署名検証の起点として機能します。

工場でのファームウェア書き込み

量産工程では、JTAGまたはUART経由でブートローダーを使ってファームウェアを書き込みます。ST製マイコンの内蔵ROMブートローダー(UART/USB DFU対応)はよく利用されます。

実装・開発のポイント

U-Bootのビルド(Raspberry Pi 4例)

# クロスコンパイル環境
export CROSS_COMPILE=aarch64-linux-gnu-
export ARCH=arm64

# ビルド
git clone https://source.denx.de/u-boot/u-boot.git
cd u-boot
make rpi_4_defconfig
make -j$(nproc)

# 生成物
# u-boot.bin → SDカードのbootパーティションへ配置

MCUbootによるMCU向けセキュアブート

/* MCUboot対応アプリの先頭に配置するイメージヘッダー */
/* MCUbootが署名を検証してからアプリを起動する */
BOOT_IMAGE_MAGIC = 0x96f3b83d;  /* マジックナンバー */

/* 署名付きイメージ生成(imgtoolを使用) */
// imgtool sign --key signing-key.pem --header-size 0x200 \
//   --align 4 --version 1.0.0 --slot-size 0x60000 \
//   app.bin app-signed.bin

ブートローダーのデバッグ

ブートローダーのデバッグは困難を伴います(OSなしの最初期フェーズのため)。主な手法:

  1. UARTデバッグ出力: U-Bootはシリアルコンソールを初期化後にログ出力
  2. JTAG: JTAGデバッガで最初の命令からステップ実行
  3. LEDトグル: DDR初期化等の到達確認に使用
  4. U-Boot nand/mmc コマンド: インタラクティブシェルでデバイス操作を確認

他技術との比較

U-Boot vs Barebox

Bareboxは2009年頃にU-Bootから派生したブートローダーで、Linuxカーネルに近い設計(デバイスツリー・デバイスモデル・仮想ファイルシステム)を持ちます。U-Bootの方が対応SoCが圧倒的に多く、産業界での採用実績も豊富です。

MCUboot vs 独自ブートローダー

MCUbootはZephyr・Mbed OS・nRF Connectと統合された標準的なMCU向けセキュアブートローダーです。独自実装より検証済みのセキュリティコードを使えるため、IoT機器での採用が増えています。署名鍵管理・イメージヘッダー形式は標準化されており、OTAツールとの連携も容易です。

関連用語

参考リンク