FreeBSD でカスタムカーネルのビルドとインストール

カスタムカーネルを構築する理由と前提

現在の FreeBSD のカーネルはモジュール方式である.多くのデバイスドライバや機能は /boot/kernel 以下のモジュールとして提供され,kldload による動的な読み込み,あるいは /boot/loader.conf への記述による起動時の読み込みが可能である.そのため,デバイスを追加で使いたいだけであれば,カーネルの再構築は必要ないことが多い.

カーネルの再構築が必要になるのは,主に次の場合である.

GENERIC 以外の構成は GENERIC ほど広くテストされていないため,構築や起動の不具合が起きる可能性がある.不具合が起きたときに自分で切り分けを行える場合に限って実施することを勧める.

このページの手順は,FreeBSD 14 以降のソースツリーを前提とする.作業はすべて root 権限で行う.

関連する外部ページ https://docs.freebsd.org/ja/books/handbook/kernelconfig/

カーネルのセキュアレベル

セキュアレベルは /etc/rc.conf で設定する.kern_securelevel_enable="YES" を指定したときに kern_securelevel の値が適用される(既定は無効,値は -1).

kern_securelevel_enable="YES"
kern_securelevel="1"

セキュアレベルが 1 以上のとき,カーネルモジュールの読み込みと取り外しは禁止される.そのため,この運用を行う場合は,必要な機能をあらかじめカーネルに静的に組み込んでおく. /etc/rc.conf の変更を有効にするためには,reboot を行ってください

参考 Web ページ: https://docs.freebsd.org/ja/books/handbook/security/

ソースコードの準備

/usr/src/UPDATING の確認

ビルドの前後に必要となる手動の作業は /usr/src/UPDATING に記載される.ビルドを始める前に,この内容を確認する.

ソースコードの取得と更新

ソースコードは git で管理する./usr/src が git の作業ツリーであるかを確認する.

cd /usr/src
git remote -v

git の作業ツリーであれば,次のコマンドで更新する.

git -C /usr/src pull

ソースコードが無い場合,あるいは「fatal: not a git repository」と表示される場合は,稼働中のバージョンに対応するブランチを指定して取得する.ブランチ名は「uname -r」の出力から決める(例: 14.3-RELEASE なら releng/14.3,14-STABLE なら stable/14).

uname -r
git clone --branch releng/14.3 https://git.FreeBSD.org/src.git /usr/src

カーネルコンフィグファイルの新規作成と編集

ハードウェアの確認

コンフィグファイルを編集する前に,実際に搭載されているハードウェアを確認する.必要なドライバを削らないためである.

dmesg
cat /var/run/dmesg.boot
pciconf -lv
ifconfig -a

カーネルコンフィグファイルの新規作成

下記のamd64のところは,マシンのアーキテクチャに応じて読み替える(amd64, arm64, i386, powerpc, riscv など). GENERIC は直接編集せず,別名でコピーしたファイルを編集する.名前はすべて大文字にするのが慣例である.

cd /usr/src/sys/amd64/conf
cp GENERIC NEWKERNEL

カーネルコンフィグファイルの編集

コンフィグファイルの各行は,デバイスやサブシステムを表すキーワードと引数からなる.「#」以降はコメントである.機能を外すときは,その行の先頭に「#」を付ける.

編集したコンフィグファイルは,/usr/src の外にバックアップを取っておく.

/etc/make.conf の設定

カーネル識別名を毎回コマンドラインで指定しない場合は,/etc/make.conf に次の行を書いておく.

KERNCONF= NEWKERNEL

既定では,カーネルの構築時にすべてのカーネルモジュールが再構築される.構築するモジュールを制限する場合は,/etc/make.conf で次の変数を指定する.

# 構築するモジュールを列挙する場合
MODULES_OVERRIDE = linux acpi

# 構築から除外するモジュールを列挙する場合
WITHOUT_MODULES = linux acpi sound

# モジュールを構築せず,カーネル本体のみを構築する場合
NO_MODULES = yes

graphics/drm-kmod や emulators/virtualbox-ose-kmod のように,カーネルのインタフェースに依存する ports を使っている場合は,PORTS_MODULES を指定しておくと,カーネルの構築時にこれらの ports も併せて再構築される.

PORTS_MODULES = drm-kmod virtualbox-ose-kmod

* CFLAGS などの最適化オプションを /etc/make.conf で独自に変更することは勧められない.ベースシステムのビルドは既定の設定で検証されており,変更するとビルドや実行時の不具合の原因になる.設定可能な項目は man make.conf と /usr/share/examples/etc/make.conf で確認する.

* プロファイル版ライブラリを生成したくない場合は,/etc/src.conf に WITHOUT_PROFILE=yes を記述する(設定可能な項目は man src.conf で確認する).

GENERIC カーネルの確保

カスタムカーネルが起動しないときの復旧用に,確実に起動する GENERIC カーネルを /boot/GENERIC に残しておく.freebsd-update によるバージョンアップでも /boot/GENERIC が必要になる.

◆ インストールメディアから取り出す場合

mount /media
cd /media/usr/freebsd-dist
tar -C/ -xvf kernel.txz boot/kernel/kernel

◆ ソースコードから構築する場合

cd /usr/src
make kernel __MAKE_CONF=/dev/null SRCCONF=/dev/null

* 「make installkernel」を実行すると,直前のカーネルが /boot/kernel.old に退避される.ただし,カーネルをインストールするたびに /boot/kernel.old は上書きされるため,起動を確認できているカーネルは別名のディレクトリ(例: /boot/GENERIC)に保存しておく.

カーネルのビルドとインストール

カーネルだけを再構築する場合の手順である. ソースツリーを更新した場合は,カーネルだけでなくシステム(world)も併せて更新する.その場合は,次の「システムとカーネルのビルドとインストール」の手順による.

  1. カーネルのビルド操作

    KERNCONF には,作成したカーネルコンフィグファイルの名前を書く.「script ...」を実行しておくと,以下「exit」までの出力が /var/tmp/buildkernel.out に記録される.エラーの確認に役立つ.

    -j に指定する数は CPU のスレッド数を目安にする(スレッド数は「sysctl -n hw.ncpu」で確認できる).

    script /var/tmp/buildkernel.out
    cd /usr/src
    make -j4 buildkernel KERNCONF=NEWKERNEL
    

    GENERIC カーネルを再構築する場合

    カーネルコンフィグファイルを作成していない場合は,KERNCONF=GENERIC を指定する.

    script /var/tmp/buildkernel.out
    cd /usr/src
    make -j4 buildkernel KERNCONF=GENERIC
    
  2. script の終了
    exit
    
  3. カーネルのインストール操作

    KERNCONF には,作成したカーネルコンフィグファイルの名前を書く.新しいカーネルが /boot/kernel/kernel にインストールされ,直前のカーネルが /boot/kernel.old に退避される.

    cd /usr/src
    make installkernel KERNCONF=NEWKERNEL
    

    GENERIC カーネルをインストールする場合

    cd /usr/src
    make installkernel KERNCONF=GENERIC
    
  4. 再起動
    shutdown -r now
    
  5. 確認

    起動後,カーネルの識別名とバージョンを確認する.

    uname -a
    
* カーネルが起動しない場合

起動時のメニューで「Escape to loader prompt」を選び,loader のプロンプトで,起動実績のあるカーネルを指定して起動する.

boot kernel.old

/boot/GENERIC に保存したカーネルを使う場合は次のようにする.

unload
load /boot/GENERIC/kernel
boot

起動後,/var/log/messages と「dmesg」の出力を確認し,コンフィグファイルを見直したうえで再構築を行う.

システムとカーネルのビルドとインストール

ソースコードからシステム全体(world)とカーネルを更新する手順である.world とカーネルはバージョンを揃える必要がある.片方だけを更新すると,ps や vmstat などのコマンドが正しく動作しないことがある.

etcupdate の準備

設定ファイルのマージには etcupdate を使う(mergemaster は FreeBSD 14 で削除された). etcupdate を初めて使う場合は,ソースコードの更新と world の構築を行う前に,次のコマンドで基準となる /etc のデータベースを作成しておく.これを行わないと,初回のマージで誤った差分や不要な衝突が生じることがある.

etcupdate extract
etcupdate diff

「etcupdate diff」の出力を確認し,不要になったローカルの変更を整理しておくと,以後の更新での衝突が減る.

システムのビルド

  1. /usr/src/UPDATING に目を通す

    ビルドの前後に必要な手動の作業が記載されている.

  2. システムのビルド操作

    「script ...」を実行しておくと,以下「exit」までの出力が /var/tmp/makeworld.out に記録される.エラーの確認に役立つ.ビルドには時間がかかる.

    script /var/tmp/makeworld.out
    cd /usr/src
    make -j4 buildworld
    
  3. ビルドの結果の確認

    エラーメッセージが出ていないことを確認する.

  4. script の終了
    exit
    
  5. カーネルのビルドとインストール

    KERNCONF には,作成したカーネルコンフィグファイルの名前を書く.カーネルコンフィグファイルを作成していない場合は KERNCONF=GENERIC を指定する.

    cd /usr/src
    make -j4 buildkernel KERNCONF=NEWKERNEL
    make installkernel KERNCONF=NEWKERNEL
    
  6. 再起動

    新しいカーネルで起動する.

    shutdown -r now
    

システムのインストール

  1. (オプション)シングルユーザモードで起動

    稼働中のプロセスの影響を避けるため,シングルユーザモードで作業することができる.

    shutdown now
    fsck -p
    mount -u /
    mount -a -t ufs
    swapon -a
    
  2. システム設定ファイルのバックアップ

    更新の前に /etc のコピーを作成しておく.問題が起きたときに /etc.org のファイルを参照できる.

    cp -Rp /etc /etc.org
    
  3. installworld の前に必要な設定ファイルの更新

    installworld の実行に必要となるアカウントやグループなどの設定ファイルを先に更新する.

    etcupdate -p
    
  4. システムのインストール

    インストールの処理は逐次実行される.make installworld では -j を指定しない

    cd /usr/src
    make installworld
    
  5. 設定ファイルのマージ

    残りの設定ファイルを更新する.衝突が生じた場合は,「etcupdate resolve」で解決する.

    etcupdate -B
    etcupdate resolve
    
  6. 再起動
    shutdown -r now
    
  7. 不要ファイルの削除

    新しいバージョンで使われなくなったファイルを削除する.

    cd /usr/src
    make delete-old
    
  8. バージョンの確認
    uname -a
    freebsd-version -ku
    

(オプション)古いライブラリの削除

古い共有ライブラリを削除する.削除したライブラリを参照する既存のアプリケーションは動作しなくなるため,すべてのアプリケーションを新しいシステムで再構築するか,パッケージを更新した後に実行する

cd /usr/src
make delete-old-libs

更新後のアプリケーションの扱い

メジャーバージョンをまたぐ更新では ABI が変わるため,インストール済みのアプリケーションを更新する必要がある.また,カーネルモジュールを含む ports やパッケージは,カーネルと同じソースツリーで構築されている必要がある.

パッケージで運用している場合は,次のコマンドでバージョン番号が変わっていないパッケージも含めて入れ替える.

pkg-static upgrade -f

ports で運用している場合は,該当の ports を入れ直す.

cd /usr/ports/カテゴリ/ソフトウェア名
make deinstall
make clean
make
make reinstall