by shigemk2

当面は技術的なことしか書かない

Fedora20でHello Worldのカーネルモジュールを作成するまでの軌跡

f:id:shigemk2:20140621000801p:plain

概要

Hello worldを出力するだけの簡単なカーネルモジュールを作りたかった。

まずはカーネルコンパイルから

生まれたてのFedoraでuname -rしたら3.11で、まずは3.15のカーネルをコンパイルすることから始めたいと思った。

The Linux Kernel Archives

最終目標は

$ uname -r 
3.15.0

(なんかごにょごにょしている間に最新の安定版が3.15.1になっていた)

最新Linuxカーネルコンパイルに挑戦 (3.5.1/3.7.0) | Lab Notebook:

公式から3.15.0カーネルモジュールをダウンロードして、所定の場所に配置する。

$ tar xvf linux-3.15.tar.xz 
$ sudo mv linux-3.15/ /usr/src/
$ cd /usr/src/
$ sudo ln -s linux-3.15/ linux

/boot/.configを/usr/src/linuxに持ってきつつ、make menuconfigを実行すると、 やれgccがないとかncurse-devel持って来いとか言われるのでその通りにしてみる。

sudo cp /boot/config-3.11.10-301.fc20.x86_64 ./.config
sudo make menuconfig
sudo yum install -y gcc
sudo make menuconfig
sudo yum install -y ncurses-devel
sudo make menuconfig

make menuconfigでconfig画面が出て来るけど、特に設定はせずに次へ進む。

perlがないと怒られるモジュールがあるので、perlを入れてからmake -j4と make modules_installを実行する

sudo yum install -y perl
sudo make -j4
sudo make modules_install

カーネルのインストールのため、 bzImage, System.map, .configを/bootの下にコピーする。

既存のやつはrmせずにバックアップを取って置いた。

sudo cp System.map /boot/System.map-custom-3.15
sudo cp .config /boot/config-custom-3.15
sudo cp ./arch/x86_64/boot/bzImage /boot/vmlinuz-custom-3.15
cd /boot/
sudo mv System.map-3.11.10-301.fc20.x86_64{,.bak}
sudo mv config-3.11.10-301.fc20.x86_64{,.bak}
sudo mv vmlinuz-3.11.10-301.fc20.x86_64{,.bak}
sudo ln -s System.map-custom-3.15 System.map
sudo ln -s config-custom-3.15 config
sudo ln -s vmlinuz-custom-3.15 vmlinuz

さあ、ここで問題だ LILOってなんだよ

碌にブートローダの知識もないまま臨んできてしまっているので、 FedoraのブートローダがLILOじゃなくGRUB2であることも知らなかった。

なので、

$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg

しました。エラーもなかったので、再起動しました。

で、not syncing: VFSがどうとかで起動しなくなる。 どうやら、initrdファイルがないことが原因のカーネルパニックらしい。

[SOLVED] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0) - FedoraForum.org

Linuxのinitrdファイルの作成

なので、mkinitrdコマンドでinitrdファイルを作る。

sudo mkinitrd /boot/initrd-3.15.img 3.15
sudo grub2-mkconfig -o /boot/grub2/grub.cfg

ここまでやってもう一度再起動したら、エラーも出ずに起動できました。

$ uname -r
3.15.0

以上、カーネルコンパイルでした。

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

Linux Kernel 2.6.x プログラミングガイド

↑のリンクをなぞって、hello.cとMakefileを作る。

hello.c

#include <linux/module.h>   // required by all modules
#include <linux/kernel.h>   // required by printk()
#include <linux/init.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Zoe");

// Start/Init function
static int hello_init(void) {
    printk(KERN_ALERT "Hello world!\n");
    return 0;
}

// End/Cleanup function
static void hello_exit(void) {
    printk(KERN_ALERT "Goodbye world!\n");
}

module_init(hello_init);
module_exit(hello_exit);

Makefile

obj-m   := hello.o

KDIR    := /lib/modules/$(shell uname -r)/build
PWD     := $(shell pwd)

default:
    $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

もう分かっていると思うけど、Makefileのインデントはタブじゃないといけません。

$ make -C /lib/modules/`uname -r`/build SUBDIRS=(ファイルのある場所) modules

ファイルのある場所なので、hello.cとMakefileはどこでも構わないと思います。

これもコンパイルが通った。

/var/log/messagesが、ない

モジュールを組込む。

$ su
# /sbin/insmod hello.ko

で、tail -f /var/log/messagesを調べたら、カーネルモジュールからhello worldが出力されていることを確認できるのだが、 おなじみのファイルである/var/log/messagesが、ない。

これは調べるのは簡単だった。

2. Fedora の変更点 - システム管理者向け

$ journalctl -f

これがtail -f /var/log/messagesと同等の役割を果す。

# /sbin/rmmod hello.ko

これをやると、↑のキャッチ画像のように出力されていた。

感想

難しかったです(小並感)

他のツールと違って、前提となる知識が豊富で、やりながら色んなことを勉強させられている感じがたまらなく良いと思いました。