内核模块学习--编译自己的第一个内核模块hello_module

来源:互联网 发布:linux 命令行浏览器 编辑:程序博客网 时间:2024/05/21 17:02

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模块

原创粉丝点击