概要
Hello worldを出力するだけの簡単なカーネルモジュールを作りたかった。
まずはカーネルコンパイルから
生まれたてのFedoraでuname -rしたら3.11で、まずは3.15のカーネルをコンパイルすることから始めたいと思った。
最終目標は
$ 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であることも知らなかった。
@shigemk2 make installのあとはgrub-mkconfigでgrubのコンフィグ作れます。 grub-mkconfig -o /boot/grub/grub.cfgで。fedoraだとgrub2-mkconfigかな。
— ご注文はゆゆ式です (@masami256) 2014, 6月 16
なので、
$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg
しました。エラーもなかったので、再起動しました。
で、not syncing: VFSがどうとかで起動しなくなる。 どうやら、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
以上、カーネルコンパイルでした。
カーネルモジュールをコンパイルする
↑のリンクをなぞって、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が、ない。
これは調べるのは簡単だった。
$ journalctl -f
これがtail -f /var/log/messagesと同等の役割を果す。
# /sbin/rmmod hello.ko
これをやると、↑のキャッチ画像のように出力されていた。
感想
難しかったです(小並感)
他のツールと違って、前提となる知識が豊富で、やりながら色んなことを勉強させられている感じがたまらなく良いと思いました。