本 Howto では、ターゲットボードで動作する Linux カーネルモジュールを作成する方法と、作成したカーネルモジュールをターゲットボードで動作させる方法を説明します。
カーネルモジュールとは、必要なときに動的にカーネルにロードまたはアンロードし、カーネルの機能を拡張することができるプログラムです。通常、デバイスドライバなどに使用されます。
本 Howto では、ロード時とアンロード時にメッセージを表示するだけの、簡単なカーネルモジュールを作成します。ビルドは、atmark-distに手を加えない、Out of Treeでおこないます。なお、使用する Linux カーネルは、2.6系を想定しています。
おおまかな手順は下記のようになります。
- atmark-distを使用して、カーネルをビルドする。
- カーネルモジュールをビルドする。
- カーネルイメージにモジュールを組み込む
- カーネルにモジュールをロード/アンロードする。
1. atmark-distを使用して、カーネルをビルドする。
カーネルモジュールを作成する前の準備として、atmark-dist Developpers Guideなどを参考に、ターゲットボード用のカーネルをビルドしてください。ターゲットボードで動作しているカーネルのバージョンと、ビルドに使用するカーネルのバージョンは一致している必要があります。
2. カーネルモジュールをビルドする。
今回はOut of Treeコンパイルで作成するので、まず、atmark-distの外にソースファイルとMakefileを用意します。作成するカーネルモジュールのモジュール名は、hello とします。
[PC ~]$ ls
atmark-dist
[PC ~]$ mkdir hello_module
[PC ~]$ ls
atmark-dist hello_module
[PC ~]$ ls hello_module
Makefile hello.c
hello.cは下記のものを使用します。
/*
* Kernel Module Sample
* file name: hello.c
*/
#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL v2");
/* インストール時に実行 */
static int hello_init(void) {
printk(KERN_ALERT "Hello World!\n");
return 0;
}
/* アンインストール時に実行 */
static void hello_exit(void) {
printk(KERN_ALERT "Goodbye World!\n");
}
module_init(hello_init);
module_exit(hello_exit);
Makefileは下記のものを使用します。
MODULES = hello.o
ifneq ($(KERNELRELEASE), )
obj-m := $(MODULES)
#CFLAGS_MODULE += -DDEBUG
else
ROOTDIR ?= ../atmark-dist
ROMFSDIR = $(ROOTDIR)/romfs
include $(ROOTDIR)/.config
include $(ROOTDIR)/config.arch
MAKEARCH = $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE)
LINUXDIR = $(CONFIG_LINUXDIR)
KERNELRELEASE = ${shell make -sC $(ROOTDIR)/$(LINUXDIR) kernelrelease}
all: modules romfs
modules:
$(MAKEARCH) -C $(ROOTDIR)/$(LINUXDIR) M=${shell pwd} modules
romfs:
make -C $(ROOTDIR) INSTALL_MOD_DIR=kernel \
M=${shell pwd} modules_install
$(ROOTDIR)/user/busybox/examples/depmod.pl -b \
$(ROMFSDIR)/lib/modules/$(KERNELRELEASE) &> /dev/null
clean:
-rm -f *.[oas] *.ko *.mod.c .*.d .*.tmp .*.cmd *.symvers
-rm -rf .tmp_versions
distclean: clean
-rm -f *~
endif
MODULES には <モジュール名>.o[1] を、ROOTDIR には atmark-dist のディレクトリを指定してください。
準備ができたら、カーネルモジュールをビルドします。ビルドには make コマンドで moduels ターゲットを使用します。ビルドが完了するとモジュールファイル hello.ko がディレクトリ内に生成されます。
[PC ~]$ cd hello_module
[PC ~/hello_module]$ make modules
[PC ~/hello_module]$ ls
Makefile hello.c hello.ko hello.mod.c hello.mod.o hello.o
3. カーネルイメージにモジュールを組み込む
手順2. で作成した、モジュールファイル hello.ko を、そのままターゲットボードへコピーしても動作させることもできますが、今回はカーネルイメージにモジュールを組み込む方法を紹介します。
モジュールファイルを atmark-dist の romfs ディレクトリにインストールするために、make コマンドで romfs ター ゲットを指定します。[2][3]
[PC ~/hello_module]$ make romfs
[PC ~/hello_module]$ ls ../atmark-dist/romfs/lib/modules/2.6.12.3-a9-13/kernel/
hello.ko
次に、atmark-dist のディレクトリに移動して、make image を実行することで、hello.ko モジュールを含んだターゲットボード用のイメージファイルがimage ディレクトリに生成されます。
[PC ~/hello_module]$ cd ../atmark-dist/
[PC ~/atmark-dist]$ make image
[PC ~/atmark-dist]$ ls images/
linux.bin linux.bin.gz romfs.img romfs.img.gz
4. カーネルにモジュールをロード/アンロードする。
ターゲットボードに、作成したカーネル及びユーザーランドのイメージを書き込みます。
カーネルモジュールのロードは、insmodでおこないます。[3]
[armadillo ~]# insmod /lib/modules/2.6.12.3-a9-13/kernel/hello.ko
Hello World!
現在カーネルにロードされているモジュールは、lsmod または /proc/modules によって調べることができます。
[armadillo ~]# lsmod
Module Size Used by Not tainted
hello 928 0 - Live 0xbf000000
[armadillo ~]# cat /proc/modules
hello 928 0 - Live 0xbf000000
アンロードはrmmodでおこなうことができます。
[armadillo ~]# rmmod hello
Goodbye World!
[armadillo ~]# lsmod
Module Size Used by Not tainted
本 Howto で使用したソースコードは、下記から取得することができます。
[1] 最終的に作成されるカーネルモジュールは、<モジュール名>.ko という名前になりますが、MODULES に指定するのは <モジュール名>.o という名前です。
[2] 事前に、atmark-dist ディレクトリでmake をおこない、romfs ディレクトリを作成しておく必要があります。
[3] パス中の「2.6.12.3-a9-13」の部分は、カーネルのバージョンによって変わりますので、適宜読みかえてください。