Ubuntu 16.04でカーネルを再ビルドする

Ubuntu 16.04カーネルを再ビルドする手順を記載します。

できるかぎりUbuntu 16.04カーネルが用意している仕組みを用いるようにしている為、Makefileであるdebian/rulesを利用しており、mainlineカーネルをビルドしてインストールする方法とは異なる部分が多いです。

 

1 カーネルビルドに必要なパッケージのインストール

libncurses5-devはmake menuconfigの為にインストールします。

$ sudo apt build-dep -y linux
$ sudo apt install -y libncurses5-dev

2 ソースコードの取得

特定のバージョンのカーネルを利用したい場合はdeb-srcからソースコードを取得し、最新のバージョンや全てのバージョンのカーネルを利用したい場合はgitリポジトリからソースコードを取得します。

fakeroot debian/rules distcleanを実行した場合は以下を実行する必要があります。

fakeroot debian/rules cleanの場合は必要ありません。

$ fakeroot debian/rules debian/control
$ cp debian.master/changelog debian/

2.1 deb-srcからソースコードを取得

debian/scripts/配下のスクリプトに実行権限を与える必要があります。また一度distcleanしないとコンパイルエラーが発生します。

$ mkdir linux.ubuntu-16.04
$ cd linux.ubuntu-16.04
$ apt source linux
$ cd linux-4.4.0
$ chmod -R u+x debian/scripts/*
$ fakeroot debian/rules distclean
$ fakeroot debian/rules debian/control
$ cp debian.master/changelog debian/

2.2 gitリポジトリからソースコードを取得

deb-srcの場合とほぼ同様です。

$ git clone git://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/xenial
$ cd xenial
$ fakeroot debian/rules debian/control
$ cp debian.master/changelog debian/

3 changelogの変更

作成するdebファイル名のsuffixを変更する為にchangelogを編集します。

debchangeでchangelogを編集できます。

$ sudo apt-get install -y devscripts
$ EDITOR=emacs debchange

以下の内容を先頭に追加しました。debファイルのsuffixにubuntu1が追加されます。

linux (4.4.0-22.39ubuntu1) UNRELEASED; urgency=medium

  * Hello, Linux

 --  <hiroom2@ubuntu-16.04>  Mon, 16 May 2016 17:52:06 +0900

4 カーネルコンフィグの変更

editconfigsでカーネルコンフィグを変更します。

ここではamd64/config.flavour.genericのみを変更します。

$ fakeroot debian/rules editconfigs
dh_testdir;
/bin/bash -e debian/scripts/misc/kernelconfig editconfigs
Do you want to edit config: amd64/config.flavour.generic? [Y/n] Y
make[1]: Entering directory '/home/hiroom2/src/linux.ubuntu-16.04/linux-4.4.0'
make[2]: ディレクトリ '/home/hiroom2/src/linux.ubuntu-16.04/linux-4.4.0/build'
に入ります
  HOSTCC  scripts/basic/fixdep
  GEN     ./Makefile
  HOSTCC  scripts/kconfig/mconf.o
  SHIPPED scripts/kconfig/zconf.tab.c
  SHIPPED scripts/kconfig/zconf.lex.c
  SHIPPED scripts/kconfig/zconf.hash.c
  HOSTCC  scripts/kconfig/zconf.tab.o
  HOSTCC  scripts/kconfig/lxdialog/checklist.o
  HOSTCC  scripts/kconfig/lxdialog/util.o
  HOSTCC  scripts/kconfig/lxdialog/inputbox.o
  HOSTCC  scripts/kconfig/lxdialog/textbox.o
  HOSTCC  scripts/kconfig/lxdialog/yesno.o
  HOSTCC  scripts/kconfig/lxdialog/menubox.o
  HOSTLD  scripts/kconfig/mconf
scripts/kconfig/mconf  Kconfig

make menuconfigの画面が表示されます。

0001_make-menuconfig.png

セーブすると反映されます。

ここではamd64/config.flavour.lowlatency以降のコンフィグは使わないのでnでスキップします。

.config:4244:warning: override: M686 changes choice state
configuration written to .config

*** End of the configuration.
*** Execute 'make' to start the build or try 'make help'.

make[2]: ディレクトリ '/home/hiroom2/src/linux.ubuntu-16.04/linux-4.4.0/build' から出ます
make[1]: Leaving directory '/home/hiroom2/src/linux.ubuntu-16.04/linux-4.4.0'
Do you want to edit config: amd64/config.flavour.lowlatency? [Y/n] n
<snip>
check-config: 31/43 checks passed -- exit 1

*** ERROR: 12 config-check failures detected

config-checkスクリプトでエラーが表示されますが、もともとのコンフィグでも表示されるので無視します。

5 ソースコード変更

すでに一度ビルドを実行した後でソースコードを変更した場合は、debian/stamp/stamp-build-genericを削除してから再ビルドを実行する必要があります。

ここではinit実行前に"Hello, Linux"と表示する変更を加えます。

diff --git a/init/main.c b/init/main.c
index 9e64d70..1ecc819 100644
--- a/init/main.c
+++ b/init/main.c
@@ -933,6 +933,8 @@ static int __ref kernel_init(void *unused)
 {
        int ret;

+       printk("Hello, Linux");
+
        kernel_init_freeable();
        /* need to finish all async __init code before freeing the memory */
        async_synchronize_full();

6 ファイル名のバージョン変更(bad know-how)

changelogを変更しただけではdebファイルの名前が変更されるだけで、その中身のカーネルイメージ等のファイル名は変更されません。

debファイルをインストールすると既存のカーネルイメージが上書きされてしまいます。

 

こういう場合は通常、カーネルコンフィグのCONFIG_LOCALVERSIONを用いるのですが、CONFIG_LOCALVERSIONを有効にするとdebian/rulesでビルドエラーが発生してしまいます。

 

そこで、相当強引な方法ですが、abi_suffixを用いてファイル名の末尾にsuffixを追加します

。abi_suffixに-helloを設定することで、ファイル名のバージョンに無理やり-helloというsuffixを加えることで上書きを回避します。

$ export abi_suffix=-hello

abi_suffixを使とxenial/drivers/hv/hv.cがコンパイルエラーになるのを防ぐ為に、debian/rulesを編集します。

diff --git a/debian/rules.d/0-common-vars.mk b/debian/rules.d/0-common-vars.mk
index 1c87ebd..2b1fa67 100644
--- a/debian/rules.d/0-common-vars.mk
+++ b/debian/rules.d/0-common-vars.mk
@@ -224,7 +224,7 @@ kmake = make ARCH=$(build_arch) \
        CONFIG_DEBUG_SECTION_MISMATCH=y \
        KBUILD_BUILD_VERSION="$(uploadnum)" \
        LOCALVERSION= localver-extra= \
-       CFLAGS_MODULE="-DPKG_ABI=$(abinum)"
+       CFLAGS_MODULE="-DPKG_ABI=$(shell echo $(abinum) | sed 's/$(abi_suffix)//g')"
 ifneq ($(LOCAL_ENV_CC),)
 kmake += CC=$(LOCAL_ENV_CC) DISTCC_HOSTS=$(LOCAL_ENV_DISTCC_HOSTS)
 endif

abi_suffixをexportした後、ebian/controlを作成しなおしてください。

debian/controlで-helloが付いたファイル名が記載されます。

$ fakeroot debian/rules debian/control

7 ビルド

一度ビルドを実行している場合の為に、いくつかのファイルを削除します。

$ rm -rf debian/stamps/stamp-build-generic
$ rm -rf debian/linux-image-extra-*/lib/modules/*/kernel/kernel

ビルド時間を短縮する為、do_tools=falseでlinux-cloud-toolsを生成しないようにします。

lowlatencyというflavorのカーネルをビルドするにはbinary-genericをbinary-lowlatencyに変更して下さい。

より多くのCPUコアを持つ環境ならば、parallel=2の値をコア数の分だけ大きくするとビルド速度が向上します。

$ DEB_BUILD_OPTIONS=parallel=2 do_tools=false no_dumpfile=1 \
fakeroot debian/rules binary-generic

ひとつ上のディレクトリにdebファイルが作成されました。

$ ls ../*.deb
linux-headers-4.4.0-22-hello-generic_4.4.0-22.39ubuntu1_amd64.deb
linux-image-4.4.0-22-hello-generic_4.4.0-22.39ubuntu1_amd64.deb
linux-image-extra-4.4.0-22-hello-generic_4.4.0-22.39ubuntu1_amd64.deb

debファイルをインストールします。

4.4.0-22-helloというsuffixを持つファイルがインストールされています。

$ sudo dpkg -i linux-image-4.4.0-22-hello-generic_4.4.0-22.39ubuntu1_amd64.deb
$ ls /boot/
System.map-4.4.0-21-generic        initrd.img-4.4.0-22-generic
System.map-4.4.0-22-generic        initrd.img-4.4.0-22-hello-generic
System.map-4.4.0-22-hello-generic
initrd.img-4.4.0-22-mykernel-generic
abi-4.4.0-21-generic               lost+found
abi-4.4.0-22-generic               memtest86+.bin
abi-4.4.0-22-hello-generic         memtest86+.elf
config-4.4.0-21-generic            memtest86+_multiboot.bin
config-4.4.0-22-generic            vmlinuz-4.4.0-21-generic
config-4.4.0-22-hello-generic      vmlinuz-4.4.0-22-generic
grub                               vmlinuz-4.4.0-22-hello-generic
initrd.img-4.4.0-21-generic

buntu 16.04を再起動します。

$ sudo reboot

ESCキーでGRUBメニューを表示させ、"Advanced options for Ubuntu"を選択させると先ほど追加したカーネルのエントリが追加されています。

0002_GRUB-menu.png

カーネルログにHello, Worldと追加され、カーネルのバージョンも変わりました。

$ dmesg | grep -2 "Hello, Linux"
[    0.029550] Freeing SMP alternatives memory: 28K (ffffffff820b3000 - ffffffff820ba000)
[    0.034677] ftrace: allocating 31906 entries in 125 pages
[    0.064341] Hello, Linux
[    0.064360] smpboot: Max logical packages: 1
[    0.064362] smpboot: APIC(0) Converting physical 0 to logical package 0
$ $ uname -r
4.4.0-22-hello-generic