この記事を書いた動機

 最近linuxのカーネルパラメータとか、コンフィグをいじる機会があったって、どうやっていじるんだっけとなったので、メモを残そうということになった。

 いつものように、基本は自分のために書いてるというのもあって、他人が見るためのコンテンツとしてはクオリティは終わってるので、そこは承知ください。。。。

環境

 ここには、簡易的にどんな環境でやることについて書いているか、記録してみる。

  • arch linux
  • linux kernel version: 6.9.7
  • UEFIに対応したハードウェア環境
  • grub をブートローダーとして使っている
  • x86 系列の 64 bit CPU (Intel の core i シリーズとか、ryzenとか、、、)

カーネルをビルドする

今使っているlinuxのバージョンを確認

uname -r
6.9.7

作業用のフォルダを作成

 いろいろ、コンフィグだのカーネル本体だのをいじくりまわして散らかるので、一つのフォルダにそれらをまとめる。

mkdir ~/kernel
cd ~/kernel

linux をダウンロード

 linux archivesから、自分の使っているlinuxのバージョンに合った、linux をダウンロードしてくる。私の場合は、以下のように、リンクを改変することで、バージョンを合わせた。

 linuxのダウンロードには、ブラウザから直接ダウンロードボタンを押したり、リンクを踏むことでできたり、gitが使えたりする。いろいろあるが、めんどくさかったので、wgetコマンドを使った。

wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.9.7.tar.xz

ダウンロードしたカーネルを展開する

 tarコマンドで以下のようにして、適当に中身を展開する。

tar xfv linux-6.9.7.tar.xz
cd linux-6.9.7

# オプションのヒント
# x: extract    (抽出)
# f: file       (展開するファイルを指定する)
# v: verbose    (途中経過の表示ができる)

カーネル設定ファイルをコピー

 linuxでは、何も設定がないところからスタートする場合は、たぶん自分で以下のようにして、一つ一つコンフィグを設定していくっぽいが、そんなことを一からしていたら日が暮れてしまうので、今動いているカーネルの設定を使いまわす。

make menuconfig

... # 何かしらのメニューがしばらくすると表示され、圧倒的な量の設定項目があることに圧倒されるまでがセット。。。

 linuxカーネルのバージョンを合わせたのは、バージョンがあっていないと、新たにカーネルの設定が追加されていたりして、その設定をするのが面倒だし、それで動かなかったらさらに面倒だからである。arch linuxの場合だと以下のようにして、設定をコピーできる。

# 現在のカーネルの設定をコピー
cp /proc/config.gz ./

# gzipコマンドでコンフィグを展開
gzip -d config.gz # decompress の d で展開できる

# makeしたときにコンフィグが認識されるように、ファイル名を変更
mv config ./.config

カーネルの設定を変更する

# 設定画面でポチポチするならこっち
make menuconfig

# 直接エディターでいじりたいならこっち
code .config
nvim .config
... 

 今回は以下の設定項目を変更してみた。なんか間違っている気がするが、とにかくASPMに関して、カーネルの設定を変更したかったのでしてみた。

  • 変更前
CONFIG_PCIEASPM=y
CONFIG_PCIEASPM_DEFAULT=y
# CONFIG_PCIEASPM_POWERSAVE is not set
# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set
# CONFIG_PCIEASPM_PERFORMANCE is not set
  • 変更後
CONFIG_PCIEASPM=y
# CONFIG_PCIEASPM_DEFAULT=y
CONFIG_PCIEASPM_POWERSAVE=y
CONFIG_PCIEASPM_POWER_SUPERSAVE=y
# CONFIG_PCIEASPM_PERFORMANCE is not set

 やってから気づいたが、たぶん本来は以下のように、default、powersave、performance うち一つだけ選んで設定すればいい模様。。。とにかく動いたので良しとしているが。。。

# CONFIG_PCIEASPM_DEFAULT=y
CONFIG_PCIEASPM_POWERSAVE=y
# CONFIG_PCIEASPM_POWER_SUPERSAVE=y
# CONFIG_PCIEASPM_PERFORMANCE is not set

 ちなみに、ここのサイトを見てなんとなく違うかなと気づいた。
  3.7. Active-State Power Management | Red Hat

カーネルをコンパイルする

 linuxカーネルを設定に基づいて、ビルドさせる。-j オプションで、複数のCPUコアを使うように設定しておかないと、とんでもない時間がかかる。基本的にはCPUのコア数と相談して設定した方がいいともう。

# カーネル本体をビルド
make -j 32
# make -j [cpuのコア数かスレッド数あたりに設定]

モジュールを何とかする

モジュールをコンパイルする

make modules -j 32

モジュールのインストール

 ここでは、管理者権限を付与してコマンドを実行しないと、モジュールをインストールできないので、sudo を使っている。

sudo make modules_install

 モジュールのインストールを怠ると、linuxカーネル読み込み時に、カーネルに必要な部品が見つからないみたいな感じになる。ext4のファイルシステムとかわからないとか言われて、主要なパーティションからデータが読み込めないなどして、起動しなくなってしまう。

カーネルイメージの配置

カーネルをコンパイルするで作成した、linux本体を配置する。通常は、カーネルをコンパイルしたときから、移動していなければ、以下の相対パスのところにある。

./arch/x86_64/boot/bzImage

 私の環境ではカーネルは、以下に示すフォルダ入っている

/boot

# カーネル本体はこんな感じで入っている
/boot/vmlinuz-linux

 ということなので、今回は、vmlinuz-linux-customとして、作ったカーネルを配置することにする。ちなみに、コマンド実行時には、sudoで管理者権限も付与する。

sudo cp ./arch/x86_64/boot/bzImage /boot/vmlinuz-linux-custom

mkinitcpio を何とかする

そもそも mkinitcpio ってなにしたいの?

 私もよく分からなかったので、調べてみたら、arch wikiにこんなことが書いてあった。

 mkinitcpio は初期 RAM ディスク環境を作成するために使われる Bash スクリプトです。mkinitcpio(8) man ページより:

 初期 ram ディスクは非常に小さい環境(初期ユーザー空間)であり、様々なカーネルモジュールをロードして init にコントロールを移す前に必要なことをセットアップします。これにより、root ファイルシステムを暗号化したりソフトウェア RAID アレイに root を載せたりすることが可能になります。mkinitcpio はカスタムフックによって簡単に拡張することができ、実行時の自動検知など様々な機能を持っています。

 伝統的には、ブートプロセスの初めにハードウェアを検知したりタスクの初期化を行うのはカーネルで、それから root ファイルシステムがマウントされ init にコントロールが移されます。しかしながら、先端技術が生まれるにつれ、こういった作業は複雑になりつつあります。

 今日、root ファイルシステムが載るハードウェアは SCSI から SATA、USB ドライブまで様々にわたり、それらハードウェアはそれぞれのメーカーによって作られたいろんなドライブコントローラによってコントロールされています。しかも、root ファイルシステムは暗号化されたり圧縮されたりする可能性もあります; ソフトウェア RAID アレイや論理ボリュームグループに含まれるかもしれません。複雑になったものをシンプルに扱う方法はユーザースペース (初期RAMディスク) へ管理を譲渡することです。参照: /dev/brain0 » Blog Archive » Early Userspace in Arch Linux

 ということらしい。。。要は、OS起動時の複雑な部分を吸収するための、いろいろドライバとか載っているメモリ上に読み込まれるイメージを起動用に作るために、mkinitcpio というコマンドがあるということでいいっぽい?

プリセットの定義

 mkinitcpio コマンドでは、/etc/mkinitcpio.d にあるプリセットに従って、RAM イメージが作られるっぽい。私の環境ではデフォルトで linux.preset というファイルがあり、以下の様な構成になっていた。

# mkinitcpio preset file for the 'linux' package

#ALL_config="/etc/mkinitcpio.conf"
ALL_kver="/boot/vmlinuz-linux"

PRESETS=('default' 'fallback')

#default_config="/etc/mkinitcpio.conf"
default_image="/boot/initramfs-linux.img"
#default_uki="/efi/EFI/Linux/arch-linux.efi"
#default_options="--splash /usr/share/systemd/bootctl/splash-arch.bmp"

#fallback_config="/etc/mkinitcpio.conf"
fallback_image="/boot/initramfs-linux-fallback.img"
#fallback_uki="/efi/EFI/Linux/arch-linux-fallback.efi"
fallback_options="-S autodetect"

 今回は、この定義をパクッてきて、作成したカーネル用のプリセットを作成する。

cd /etc/mkinitcpio.d
sudo cp linux.preset ./linux-custom.preset

 また、今回は /boot にマウントしている、EFI パーティションのサイズが小さすぎて、全部は入らない。そこで、fallback のオプションを外し、起動に必要な最低限の RAM イメージだけ作成するように、以下のように設定を変更した。

# 管理者権限を使い、好きなエディターで開く
sudo nvim linux-custom.preset


# ここから、今回作成した設定例
# mkinitcpio preset file for the 'linux' package

#ALL_config="/etc/mkinitcpio.conf"
ALL_kver="/boot/vmlinuz-linux-custom"

PRESETS=('default')

#default_config="/etc/mkinitcpio.conf"
default_image="/boot/initramfs-linux-custom.img"
#default_uki="/efi/EFI/Linux/arch-linux.efi"
#default_options="--splash /usr/share/systemd/bootctl/splash-arch.bmp"

#fallback_config="/etc/mkinitcpio.conf"
#fallback_image="/boot/initramfs-linux-fallback-custom.img"
#fallback_uki="/efi/EFI/Linux/arch-linux-fallback.efi"
#fallback_options="-S autodetect"

 主な変更点は以下のとおりである。

  • fallback イメージの無効化
# 変更前
PRESETS=('default' 'fallback')
...
#fallback_config="/etc/mkinitcpio.conf"
fallback_image="/boot/initramfs-linux-fallback.img"
#fallback_uki="/efi/EFI/Linux/arch-linux-fallback.efi"
fallback_options="-S autodetect"

# 変更後
PRESETS=('default')
...
#fallback_config="/etc/mkinitcpio.conf"
#fallback_image="/boot/initramfs-linux-fallback-custom.img"
#fallback_uki="/efi/EFI/Linux/arch-linux-fallback.efi"
#fallback_options="-S autodetect"
  • 今回作成したカーネルへの場所と作成される RAM イメージの保存場所を指定
# 変更前
ALL_kver="/boot/vmlinuz-linux"
...
default_image="/boot/initramfs-linux.img"

# 変更後
ALL_kver="/boot/vmlinuz-linux-custom"
...
default_image="/boot/initramfs-linux-custom.img"

とにかくイメージを作る

 このメモリ上に読み込まれるイメージを作るには、以下のようにする。個々で指定する名前は、プリセットの定義で作成した設定名前に依存する模様。ファイル名.preset という感じで、ファイル名の部分が今回指定する名前になる。

# 部分的に RAM イメージを更新、作成
sudo mkinitcpio -P linux-custom

# 全部のプリセットに対してやりたいときは、何も指定しない
sudo mkinitcpio -P

 ちなみに、全部のプリセットに対して mkinitcpio -P コマンドを実行すると、ディスクの空きが十分になくて、作成した RAM イメージが書き込めなかったときに、再起動したら起動できないなんてことになりかねないと思う。

 安全策として、すでにあるのはいじらないで、今回新しく作ったものだけに対して操作を行うのがたぶん無難だと思う。

grub の設定を更新する

 ブートローダーの更新を行う。今回は grub を使っているので、grub-mkconfig で自動的にコンフィグを生成させる。

 grub-mkconfig コマンドは、/boot とかにあるカーネルとかを見つけて、自動で新しく作成したカーネルイメージを認識してくれる。そのため、起動時の選択肢として認識して、余り細かいことは気にせずに、grub ブートローダーのコンフィグを勝手に作ってくれる。

# 実際に更新を行う
sudo grub-mkconfig -o /boot/grub/grub.cfg

# 以下は実行結果
# [sudo] userName のパスワード:
# Generating grub configuration file ...

# こんな感じで、作成したカーネルも見つけてもらえる
# Linux イメージを見つけました: /boot/vmlinuz-linux-custom
# Found initrd image: /boot/initramfs-linux-custom.img
# Linux イメージを見つけました: /boot/vmlinuz-linux
# Found initrd image: /boot/initramfs-linux.img
# Found fallback initrd image(s) in /boot:  initramfs-linux-fallback.img

# Warning: os-prober will not be executed to detect other bootable partitions.
# Systems on them will not be added to the GRUB boot configuration.
# Check GRUB_DISABLE_OS_PROBER documentation entry.
# Adding boot menu entry for UEFI Firmware Settings ...
# 完了

 多分、ここまでくれば、新しく作ったカーネルで起動できる所まで、あわよくばうまく行くはずである。

カーネルパラメータについて

 カーネルパラメータとは、OS起動時に GRUB で指定できる、カーネルの設定のことであったと思う。例えばこれは、グラフィック関連の挙動を設定したり、機能の有効、無効の制御、ドライバやハードウェアのブラックリストなどの管理を行えたりする。今回はここまで書こうかと思ったが、疲れたのでいったんお休みにする。。。

補足

カーネルを配置したり、mkinitcpio -P をする前に、、、

 今回は、起動時、UEFIに認識され、まず最初に読み込まれるデータが入っている、/boot フォルダについていろいろしていた。

 しかし、/boot フォルダに対して、正しくパーティションがマウントされていないと、うまく変更を反映できなかったり、カーネルとその部品であるモジュール間でバージョンがちぐはぐになって、とにかくうまく起動してくれなくなってしまう。

 事前にこれら問題を防ぐには、作業前に mount コマンドを実行して、正しくマウントできているか確認するといいかもしれない。

mount | grep /boot

# 正常にマウントされているときの出力例
/dev/sdb1 on /boot type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,utf8,errors=remount-ro)

# 正常にマウントされていないときは、たぶん何も出てこない

 このような状況下では、パテーションのマウント情報が入っている、/etc/fstab あたりも確認するといいかもしれない。

 多分そのファイルがなくて、一応起動はそれでもするのだが、いざというときに、/boot フォルダに対して何もパテーションがマウントされていないということになっていることがある。

 まあ、設定し忘れる事なんていくらでもあるし、気づいたときに適当にインストールメディアから fstab を生成してやれば、事なきを得られそうである。

参考にしたサイト