刚接触内核模块,现在只知道编译内核模块有两种方式,一种是在内核源码树外编译,另一种是在内核源码树内编译。
这篇文章是有关内核源码树之外编译的情况。
首先搭建环境:
内核源码树:我的ubunut10.10安装后有自带的内核源码树,在lib/modules/2.6.35-22-generic目录下有build文件。
新建一个文件夹:假设我的是~/Desktop/driverStudy/hello,在这个文件夹下新建两个文件hello.c、Makefile。
hello.c:
#include
#include
#include
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);
MODULE_LICENSE("Dual BSD/GPL");头文件说明:
/linux/init.h: module_init()、module_exit()
/linux/module.h:MODULE_LICENSE()
/linux/kernel.h:printk(),KERN_ALERT
Makefile:
ifeq ($(KERNELRELEASE),)
KERNELDIR ?=/lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
else
obj-m := hello.o
endif
进入~/Desktop/driverStudy/hello目录,输入make,之后执行的步骤如下:
1.首先会判断ifeq ($(KERNELRELEASE),),KERNELRELEASE是内核源码树下Makefile中定义的一个宏。显然执行make后判断ifeq ($(KERNELRELEASE),)时KERNELRELEASE是空的,所以向下执行,不进行跳转。
2.KERNELDIR ?=/lib/modules/$(shell uname -r)/build,如果没有定义KERNELDIR ,那么定义为/lib/modules/$(shell uname -r)/build,即/lib/modules/2.6.35-22-generic/build,$(shell pwd)的值为/root/Desktop/driverStudy/hello
3.make的默认目标是mudules(如果把modules和modules_install换一下位置,应该默认是modules_install?,这里插一句make modules和make modules_install的区别,分别是生成相应的模块和把模块拷贝到需要的目录中),执行$(MAKE) -C $(KERNELDIR) M=$(PWD) modules,替换后得到:
make -C /lib/modules/2.6.35-22-generic/build M=/root/Desktop/driverStudy/hello modules
4.对3中的make语句要重点分析:首先它进入/lib/modules/2.6.35-22-generic/build目录读取build下的Makefile文件,并从中得到一些信息,例如变量KERNELRELEASE在这时被赋值,读取内核源码树的Makefile之后,会到M表示的目录下执行该目录下的Makefile文件。
5.M表示的目录是什么呢?正是/root/Desktop/driverStudy/hello,就是我们执行make的目录,所以上面的Makefile再一次被调用,但是此时的KERNELRELEASE已经在4中被赋值了,所以直接执行else之后的语句,即obj-m := hello.o,生成了hello.o文件。
6.此时MODPOST程序将被调用,生成hello.mod.c文件,最后链接hello.o和hello.mod.c文件,生成hello.ko模块文件。把1-5称为stage1,6为stage2。
以下是我的build log
root@yin-vm:~/Desktop/driverStudy/hello# make
make -C /lib/modules/2.6.35-22-generic/build M=/root/Desktop/driverStudy/hello modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.35-22-generic'
CC [M] /root/Desktop/driverStudy/hello/hello.o
Building modules, stage 2.
MODPOST 1 modules
CC /root/Desktop/driverStudy/hello/hello.mod.o
LD [M] /root/Desktop/driverStudy/hello/hello.ko
make[1]: Leaving directory `/usr/src/linux-headers-2.6.35-22-generic'
之后是一些安装模块及测试的情况,直接贴Log了:
root@yin-vm:~/Desktop/driverStudy/hello# insmod hello.ko
root@yin-vm:~/Desktop/driverStudy/hello# dmesg|tail
[ 442.658198] vmci 0000:00:07.7: PCI INT A -> GSI 16 (level, low) -> IRQ 16
[ 442.660608] Found vmci/PCI at 0x1080, irq 16.
[ 442.661212] VMCIUtil: Host capability check: PASSED
[ 442.662897] Registered vmci device.
[ 447.577853] audit_printk_skb: 9 callbacks suppressed
[ 447.578001] type=1400 audit(1416796755.035:15): apparmor="DENIED" operation="capable" parent=13431 profile="/usr/sbin/cupsd" pid=13436 comm="serial" capability=21 capname="sys_admin"
[ 1069.590461] pcnet32 0000:02:01.0: eth0: link up
[ 1069.594377] ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
[ 3841.719888] hrtimer: interrupt took 8690229 ns
[13123.785160] Hello,World
root@yin-vm:~/Desktop/driverStudy/hello# lsmod|grep hello
hello 692 0
root@yin-vm:~/Desktop/driverStudy/hello# rmmod hello.ko
root@yin-vm:~/Desktop/driverStudy/hello# lsmod|grep hello
root@yin-vm:~/Desktop/driverStudy/hello#
root@yin-vm:~/Desktop/driverStudy/hello# insmod hello.ko
root@yin-vm:~/Desktop/driverStudy/hello# modinfo hello.ko
filename: hello.ko
license: Dual BSD/GPL
srcversion: A8507261C23010472BCCA44
depends:
vermagic: 2.6.35-22-generic SMP mod_unload modversions 686
root@yin-vm:~/Desktop/driverStudy/hello# cat /proc/modules | grep hello
hello 692 0 - Live 0xe0894000
root@yin-vm:~/Desktop/driverStudy/hello# ls /sys/module/
8250 ehci_hcd ipv6 mptbase powernow_k7 shpchp snd_timer vmblock
ac97_bus eisa_bus kernel mptscsih ppdev snd soundcore vmci
acpi floppy keyboard mptspi printk snd_ac97_codec speedstep_lib vmhgfs
acpi_cpufreq fuse kgdboc netpoll processor snd_ens1371 speedstep_smi vmware_balloon
acpiphp gameport libata parport psmouse snd_page_alloc spurious vmxnet
agpgart gx_suspmod longhaul parport_pc rfkill snd_pcm sr_mod vsock
apparmor hello lp pcie_aspm sbs snd_rawmidi tcp_cubic vt
battery i2c_piix4 md_mod pciehp scsi_mod snd_seq thermal wmi
binfmt_misc i8042 mii pci_hotplug scsi_transport_spi snd_seq_device uhci_hcd
cpufreq_nforce2 intel_agp mmc_core pci_slot serio_raw snd_seq_midi usbcore
debug_core intel_idle mousedev pcnet32 sg