本文主要介绍了Linux系统Ubuntu下的驱动开发编译环境搭建方法与步骤,仅供参考。
一、准备开发工具
开发工具主要有gcc、gdb、make
在Ubuntu中可以通过下面这个命令安装:
二、下载Linux源代码
linux源码可以通过以下几种途径获得:
1)直接去www.kernel.org下载
2)通过包管理工具下载源码
用下面指令查看可用的源码包:
linux-source – Linux kernel source with Ubuntu patches
linux-source-2.6.32 – Linux kernel source for version 2.6.32 with Ubuntu patches
在Ubuntu中可以通过下面这个命令下载:
$apt-get install linux-source-(版本号)
下载后的文件linux-source-2.6.32.tar.bz2在/usr/src目录中,解压:
解压后在/usr/src目录下产生了一个linux-source-2.6.32源码目录
三、编译内核
依次执行下列命令(必须都执行,否则编译错误,如果不是root用户,命令前加sudo):
配置内核
或
如果当前运行内核打开了CONFIG_IKCONFIG_PROC参数,则可以
编译内核
2.6版本后前两步不需要,直接make即可
3)安装模块
执行结束之后,会在/lib/modules下生成新的目录/lib/modules/2.6.32.44+drm33.19
四、生成镜像文件
1)生成内核镜像文件
执行完成后将在arch/i386/boot/目录下生成bzImage镜像文件,使用下面命令安装到系统的/boot目录下:
sh /usr/src/linux-source-2.6.32/arch/x86/boot/install.sh 2.6.32.44+drm33.19 arch/x86/boot/bzImage System.map "/boot"
命令完成后在/boot目录下,将多了vmlinuz-2.6.32.44+drm33.19和System.map-2.6.32.44+drm33.19两个文件
或者直接拷贝
2)生成要载入ramdisk的映像文件
如果linux系统安装在scsi磁盘上,这步是必须的,否则可以跳过。我的linux是装在vmware上的,用的是虚拟的scsi磁盘,所以必须要这一步。输入命令:
第二个参数是版本号,必须和/lib/modules/目录下新内核对应的模块的文件夹名字一致,即2.6.32.44+drm33.19 。
五、使用新编译的内核
Ubuntu采用Grub引导,要使用新内核,必须配置grub。
1) 更改grub配置,显示启动菜单
注释GRUB_HIDDEN_TIMEOUT=0语句,及改成#GRUB_HIDDEN_TIMEOUT=0后保存
2)更新启动配置文件
执行命令后,该命令自动搜索/boot文件夹,将相应的镜像加入/boot/grub/grub.cfg启动菜单,并根据/etc/default/grub内容更新配置文件。更新后,将增加如下内容:
手工更改配置文件
因为是SCSI,须手工加入启动时需要的ramdisk的映像文件, initrd开头部分:
修改完成并保存后,重新启动系统,应该出现让你选择内核的菜单。
六、准备Helloworld源代码和Makefile文件
Helloworld.c内容:
Makefile内容:
保存文件后,编译通过。如果出现
或
的错误,都是因为Makefile的格式不对, $(MAKE)和 rm -rf *.o *前面的空格都应该是一个TAB键。
七、编译并安装模块
1)编译
编译前,请先编译新内核,否则出现警告信息
2)安装模块
3)移除模块
4)查看模块信息
八、查看输出信息
cat /proc/kmsg 会一直打印,需要Ctrl-C手动终止
dmesg 或 dmesg | tail -N ,N为一数字,表示显示最后N行
九、问题及解决方法
Building modules, stage 2.
/usr/src/linux-source-2.6.32/scripts/Makefile.modpost:42: include/config/auto.conf: No such file or directory
make[2]: *** No rule to make target `include/config/auto.conf'. Stop.
make[1]: *** [modules] Error 2
make[1]: Leaving directory `/usr/src/linux-source-2.6.32'
make: *** [all] Error 2
解决:
使用正在运行的内核的头文件编译出的模块,不会出现该问题
insmod: error inserting 'hellomod.ko': -1 Invalid module format
此时,你用
你在最后一行应该看到类似下面的提示:
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 '
解决办法:(按照下面说的无法解决,只有加载新内核才不出问题)
那该怎么办呢?最简单的办法就是:修改源目录下的Makefie
把Makefile第1-4行的值改为当前内核一样的值
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 24
EXTRAVERSION = .2
NAME = Err Metey! A Heury Beelge-a Ret!
那怎么确定你当前内核的值是多少呢?
注意:重新编译内核和不编译内核后得到的模块文件,在安装时显示的信息一样,但dmesg | tail显示的信息不同。
insmod: error inserting 'helloworld.ko': -1 Invalid module format
不能安装的模块的信息:
android@android23:~/work/test/helloworld$ modinfo helloworld.ko
filename: helloworld.ko
license: Dual BSD/GPL
srcversion: 31FE72DA6A560C890FF9B3F
depends:
vermagic: 2.6.32.21 SMP mod_unload modversions 586
能安装的模块的信息:
android@android23:~/work/test/helloworld$ modinfo helloworld.ko
filename: helloworld.ko
license: Dual BSD/GPL
srcversion: 31FE72DA6A560C890FF9B3F
depends:
vermagic: 2.6.32-21-generic SMP mod_unload modversions 586
"make mrproper" , "cp /boot/config-$(uname -r) .config" , "make oldconfig" , "make prepare" , "make scripts"
编译模块时出下面错误
WARNING: Symbol version dump /usr/src/linux-source-2.6.32/Module.symvers
is missing; modules will have no dependencies and modversions.
解决:
编译Linux内核源码后,再编译模块
以下方法也试过,不起作用:
Linux内核模块加载报错”no symbol version for struct_module”解决办法
进入内核源码目录,发现少了文件Module.symvers ,重新编译内核源码make vmlinuz后,生成Module.symvers文件。再次编译iscsi_trgt内核模块,加载成功。问题得到解决。
Linux内核编译 CONFIG_MODVERSIONS 作用
关于Linux内核编译 CONFIG_MODVERSIONS 作用的两篇文章整理。
一般情况下,如果没有选择CONFIG_MODVERSIONS,这些符号是正常的字串;如果选择了CONFIG_MODVERSIONS,这些符号就会在后面加一段校验字串。这样做的目的是避免模块不正确加载情况下,使得Linux内核崩溃。
参考一、
如果内核选择了CONFIG_MODVERSIONS选项,你的模块的Makefile要增加以下几行
或者在你的C源文件里增加
这样就可以在编译内核模块时,如果模块里引用了内核符号表,就可以自动计算校验字串,而不会在加载模块时出现unresloved symbol的错误了。
参考二、
当你的内核在编译时使能了CONFIG_MODVERSIONS选项,那么你插入的模块可以是一下两种情况:
1.编译时没有带CONFIG_MODVERSIONS选项,但版本必须与内核的版本一致;
2.编译时如果带有CONFIG_MODVERSIONS选项,那么模块的版本将没有限制;
而通常内核在编译是带有CONFIG_MODVERSIONS选项的,所以就出现了文章开头出现的情况:内核和模块的版本不一致。同时我们也就找到了相应的解决办法--在模块编译时选择CONFIG_MODVERSIONS选项,这样我们就可以解决版本不匹配的问题了。
我们需要这源文件(c文件)中加上下面的宏定义:
然后编译就可以了。