1,下载源码
xin@xin-desktop:~$ sudo apt-get source linux-image-2.6.32-38-generic
最终安装在目录:/usr/src/linux-2.6.32/
2,编写源码hello_module.c和Makefile
(1)新建一个目录mytest
xin@xin-desktop:~/mytest$ vi hello_module.c
#include <linux/init.h> /* printk() */
#include <linux/module.h> /* __init __exit */
static int __init hello_init(void) /*模块加载函数,通过insmod命令加载模块时,被自动执行*/
{
printk(KERN_INFO " Hello World enter\n");
return 0;
}
static void __exit hello_exit(void) /*模块卸载函数,当通过rmmod命令卸载时,会被自动执行*/
{
printk(KERN_INFO " Hello World exit\n ");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_AUTHOR("xin"); /*模块作者,可选*/
MODULE_LICENSE("Dual BSD/GPL"); /*模块许可证明,描述内核模块的许可权限,必须*/
MODULE_DESCRIPTION("A simple Hello World Module"); /*模块说明,可选*/
(2)写一个Makefile文件:
内容如下:
#目标文件
obj-m :=hello_module.o
#当模块有多个文件组成时,添加本句
#module-objs := file1.o file.o
#内核路径,根据实际情况换成自己的内核路径,嵌入式的换成嵌入式,PC机的指定PC机路>径
KDIR :=/usr/src/linux-2.6.32/
#模块源文件路径
PWD := $(shell pwd)
all:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
@rm -rf *.mod.*
@rm -rf .*.cmd
@rm -rf *.o
@rm -rf Module.*
clean:
rm -rf *.ko
3,编译
xin@xin-desktop:~/mytest$ make
make: Entering directory `/usr/src/linux-2.6.32'
ERROR: Kernel configuration is invalid.
include/linux/autoconf.h or include/config/auto.conf are missing.
Run 'make oldconfig && make prepare' on kernel src to fix it.
WARNING: Symbol version dump /usr/src/linux-2.6.32/Module.symvers
is missing; modules will have no dependencies and modversions.
........................................
........................................
解决方法:
xin@xin-desktop:/usr/src/linux-2.6.32$ sudo make oldconfig
xin@xin-desktop:/usr/src/linux-2.6.32$ sudo make prepare
再次编译:
xin@xin-desktop:~/mytest$ make
还是有错:
make: Entering directory `/usr/src/linux-2.6.32'
WARNING: Symbol version dump /usr/src/linux-2.6.32/Module.symvers
is missing; modules will have no dependencies and modversions.
CC [M] /home/xin/mytest/hello_module.o
Building modules, stage 2.
MODPOST 1 modules
/bin/sh: scripts/mod/modpost: not found
make[1]: *** [__modpost] 错误 127
make: *** [modules] 错误 2
make: Leaving directory `/usr/src/linux-2.6.32'
看到提示说没有scripts/mod/modpost,那我们就编译它
xin@xin-desktop:/usr/src/linux-2.6.32$ make scripts
HOSTCC scripts/genksyms/genksyms.o
SHIPPED scripts/genksyms/lex.c
SHIPPED scripts/genksyms/parse.h
SHIPPED scripts/genksyms/keywords.c
HOSTCC scripts/genksyms/lex.o
SHIPPED scripts/genksyms/parse.c
HOSTCC scripts/genksyms/parse.o
HOSTLD scripts/genksyms/genksyms
CC scripts/mod/empty.o
HOSTCC scripts/mod/mk_elfconfig
MKELF scripts/mod/elfconfig.h
HOSTCC scripts/mod/file2alias.o
HOSTCC scripts/mod/modpost.o
HOSTCC scripts/mod/sumversion.o
HOSTLD scripts/mod/modpost
HOSTCC scripts/kallsyms
HOSTCC scripts/conmakehash
OK,好了
再来解决这一个warning(前面没有关注,后面发现这个还是致命的):
WARNING: Symbol version dump /usr/src/linux-2.6.32/Module.symvers
is missing; modules will have no dependencies and modversions.
原因:通常头核心包中是没有 Module.symvers 这个文件的,要想获取这个文件只能到下载相同版本核心的头文件,是下载不是
apt-get install !!!,只有下载的头文件中才有这个Module.symvers。把Module.symvers 复制到核心包中。
然后重新编译驱动:xin@xin-desktop:~/mytest$ make
将解决这个warning,同时也解决了版本不正确的问题。
(我不知道有多少人会碰上这样的问题,反正google中我发现没有人能说明白这个问题)
4,加载模块
xin@xin-desktop:~/mytest$ ls
hello_module.c modules.order hello_module.ko Makefile
xin@xin-desktop:~/mytest$ sudo insmod hello_module.ko
xin@xin-desktop:~/mytest$ lsmod | grep hello_module
hello_module 593 0
ps:
不解决上面的warning,是可以编译成功的。但是在执行加载后
xin@xin-desktop:~/mytest$ sudo insmod hello_module.ko
报错:insmod: error inserting 'hellomod.ko': -1 Invalid module format
查了很多资料,普遍的观点是:
内核无法加载模块的原因是因为记载版本号的字符串(正规说法:版本印戳)和当前正在运行的内核模块的不一样,叫vermagic
此时,可用sudo tail /var/log/messages
你在最后一行应该看到类似下面的提示:
Dec 19 13:42:29 localhost kernel: hellomod: version magic '2.6.24.2 SMP mod_unload 686 4KSTACKS ' should be '2.6.27.7-134.fc10.i686 SMP mod_unload 686 4KSTACKS '
而我的只显示:
Mar 29 16:57:34 xin-desktop kernel: [ 6964.464931] hello_module: no symbol version for module_layout
但是通过modinfo和 uname -r的比较确实不一样
我按照提供的办法,修改源目录下的Makefie
把Makefile第1-4行的值改为当前内核一样的值
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 32
EXTRAVERSION = .54+drm33.21
NAME = Man-Eating Seals of Antiquity
确定你当前内核的值,通过
vi /lib/modules/`uname -r`/build/Makefile
但是,我这样改过之后,还是又上面加载不上的问题,而且版本号跟写进Makefile的不是一样的,编译完成的是这样的:
2.6.32.57+drm33.23 SMP mod_unload modversions 586。
即便我把/usr/src/linux-2.6.32内核源码中的Makefile改了,也是这样的,我一直没有搞清楚,到底内核版本号是在哪里设置的。
最后,消除了这个warning后,虽然内核版本号仍不一样,但是可以加载了。
当前已经加载的内核模块video的信息:
xin@xin-desktop:~/mytest$ modinfo video
filename: /lib/modules/2.6.32-38-generic/kernel/drivers/acpi/video.ko
license: GPL
description: ACPI Video Driver
author: Bruno Ducrot
srcversion: A52E70043443277D9757C8E
alias: acpi*:LNXVIDEO:*
depends: output
vermagic: 2.6.32-38-generic SMP mod_unload modversions 586
parm: brightness_switch_enabled:bool
hello_module的信息:
xin@xin-desktop:~/mytest$ modinfo hello_module.ko
filename: hello_module.ko
alias: a simplest module
description: A simple Hello World Module
license: Dual BSD/GPL
author: xin
srcversion: B757E1EEAD29F16BF0B6737
depends:
vermagic: 2.6.32.57+drm33.23 SMP mod_unload modversions 586
注意到 两者的vermagic是不一样的,但是可以加载hello_module.ko模块