记第一次写Linux Driver

时间:2021-01-16 16:44:23
2.6之后,驱动可以以模块的方式加载到内核中执行。我们在自己的机器上写driver要配合对应的内核树,
以便和源代码树中的目标文件相连。怎么建立这个内核源码树呢?可以从官网下载相对应的内核源码,编译之。

首先,看看我的内核版本。

[linc@localhost ~]$ uname -r2.6.35.6-45.fc14.i686

那么去官网www.kernel.org下载2.6.35.6的源码吧。
在首页找不到你要的版本不要急,点击FTP的链接,找到你想要的版本吧。
创建个目录,将源码解压在其中。(tar xfvz yourfile)
编译的第一项是内核配置,我的系统的Fedora,出现了点问题:
在源码目录下root执行make menuconfig,
  出现错误:

  *** Unable to find the ncurses libraries or the  *** required header files.  *** 'make menuconfig' requires the ncurses libraries.  ***  *** Install ncurses (ncurses-devel) and try again.  ***  make[1]: *** [scripts/kconfig/dochecklxdialog] 错误 1  make: *** [menuconfig] 错误 

解决办法:
这是由于ncurses图形库导致的,下载它就好了。
  yum install ncurses
  yum install ncurses-devel
这次继续执行,出现配置界面。按如下来操作:
Loadable module support ---->
选择Module versioning support(按Y就ok),这个功能可以让你使用其他版本的内核模块。


接下来就可以编译了:
还是此目录下,执行make。很长时间,根据机器配置而异。喝茶去吧。
接着编译压缩形式的内核,make bzImage

[root@localhost linux-2.6.35.6]# make bzImage  CHK     include/linux/version.h  CHK     include/generated/utsrelease.h  CALL    scripts/checksyscalls.sh  CHK     include/generated/compile.h  CHK     include/linux/version.hmake[2]: `scripts/unifdef' is up to date.  TEST    posttestSucceed: decoded and checked 1249053 instructionsKernel: arch/x86/boot/bzImage is ready  (#2)
继续编译模块并将它们安装到系统标准位置:
make modules
make modules_install
完成后,/lib/modules/下多了个2.6.35.6目录。


至此,我们的内核树算是建立完成。
下面写个hello world来检验一下吧。

#include <linux/init.h>#include <linux/module.h>MODULE_LICENSE("Dual BSD/GPL");static int hello_init(void){        printk(KERN_ALERT "Hello,world.i am linc.\n");        return 0;}static void hello_exit(void){        printk(KERN_ALERT "Goodbye, i am linc.\n");}module_init(hello_init);module_exit(hello_exit);
写个makefile来编译它:
#如果已经定义KERNELRELEASE,说明是从内核构造系统调用的,#可利用其内建语句ifneq ($(KERNELRELEASE),)obj-m := test.o#否则是从命令行调用的,需要使用内核构造系统else        KDIR := /lib/modules/2.6.35.6/buildall:        make -C $(KDIR) M=$(PWD) modulesclean:        rm -f *.ko *.o *.mod.o *.mod.c *.symversendif

编译:
[root@localhost drivers]# make
make -C /lib/modules/2.6.35.6/build M=/home/linc/linux/workspace/drivers modules
make[1]: Entering directory `/usr/src/kernels/linux-2.6.35.6'
  CC [M]  /home/linc/linux/workspace/drivers/test.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/linc/linux/workspace/drivers/test.mod.o
  LD [M]  /home/linc/linux/workspace/drivers/test.ko
make[1]: Leaving directory `/usr/src/kernels/linux-2.6.35.6'


安装和卸载:

insmod test.ko

rmmod test.ko

如果此时仍然遇到问题:

[root@localhost drivers]# insmod test.ko insmod: error inserting 'test.ko': -1 Invalid module format
我们看一下具体详细信息:

[root@localhost drivers]# dmesg | tail[  356.269653] test: version magic '2.6.35.6 SMP mod_unload modversions 686 ' should be '2.6.35.6-45.fc14.i686 SMP mod_unload 686 '
说明ko的kernel版本与当前运行的版本仍然不一致。此时我尝试重新编译内核,结果仍然一样。就参考

Linux 2.6.x 内核模块加载错误 “Invalid module format” 解决办法》 将版本强制修改一下,让其保持一致。方法如下:

找到utsrelease.h文件,在源码树下linux-2.6.35.6/include/generated。将版本号修改。重新编译,发现仍有错误:

[ 1149.371180] test: version magic '2.6.35.6-45.fc14.i686 SMP mod_unload modversions 686 ' should be '2.6.35.6-45.fc14.i686 SMP mod_unload 686 '
对比上述信息,发现我的VERMAGIC_STRING多了一个词“modversions”,好吧,为了一直,索性将linux-2.6.35.6/include/linux/vermagic.h文件中对VERMAGIC_STRING做

下调整。去掉MODULE_VERMAGIC_MODVERSIONS信息。如下:

#include <generated/utsrelease.h>#include <linux/module.h>/* Simply sanity version stamp for modules. */#ifdef CONFIG_SMP#define MODULE_VERMAGIC_SMP "SMP "#else#define MODULE_VERMAGIC_SMP ""#endif#ifdef CONFIG_PREEMPT#define MODULE_VERMAGIC_PREEMPT "preempt "#else#define MODULE_VERMAGIC_PREEMPT ""#endif#ifdef CONFIG_MODULE_UNLOAD#define MODULE_VERMAGIC_MODULE_UNLOAD "mod_unload "#else#define MODULE_VERMAGIC_MODULE_UNLOAD ""#endif#ifdef CONFIG_MODVERSIONS#define MODULE_VERMAGIC_MODVERSIONS "modversions "#else#define MODULE_VERMAGIC_MODVERSIONS ""#endif#ifndef MODULE_ARCH_VERMAGIC#define MODULE_ARCH_VERMAGIC ""#endif#define VERMAGIC_STRING                                                 \        UTS_RELEASE " "                                                 \        MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT                     \        MODULE_VERMAGIC_MODULE_UNLOAD MODULE_ARCH_VERMAGIC

至此,重新编译模块。一切正常。

[root@localhost drivers]# insmod test.ko[root@localhost drivers]# rmmod test.ko[root@localhost drivers]# dmesg | tail[ 1586.792291] Hello,world.i am linc.[ 1696.536632] Goodbye, i am linc.


参考:
http://blog.csdn.net/xuxinyl/article/details/6996433
http://www.cnblogs.com/Jezze/archive/2011/12/23/2299871.html

《Linux设备驱动程序》第二章