在Ubuntu10.04下驱动开发环境搭建
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
在Ubuntu10.04驱动开发环境搭建
一、准备开发工具
开发工具主要有gcc、gdb、make
在Ubuntu中可以通过下面这个命令安装:
$apt-get install build-essential
我没有执行上面的命令,因为我在之前编译过Android,相关工具已经配置好了:
$sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev libc6-dev x11proto-core-dev libx11-dev libgl1-mesa-dev g++-multilib mingw32 tofrodos libncurses5-dev
二、下载Linux源代码
linux源码可以通过以下几种途径获得:
1)直接去下载
2)通过包管理工具下载源码
用下面指令查看可用的源码包:
$ sudo apt-cache search linux-source
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-(版本号)
$sudo apt-get install linux-source-2.6.32
下载后的文件linux-source-2.6.32.tar.bz2在/usr/src目录中,解压:
$su – root
$cd /usr/src
$tar jxvf linux-source-2.6.32.tar.bz2
解压后在/usr/src目录下产生了一个linux-source-2.6.32源码目录
三、编译内核
依次执行下列命令(必须都执行,否则编译错误,如果不是root用户,命令前加sudo):1)配置内核
$su – root
$cd /usr/src/linux-source-2.6.32
$make config
或
$make menuconfig
或者
$ sudo cp ../linux-headers-2.6.32-21-generic/.config ./.config
如果当前运行内核打开了CONFIG_IKCONFIG_PROC参数,则可以
$zcat /proc/config.gz > .config
$make oldconfig
2)编译内核
2.6版本后前两步不需要,直接make即可
$make prepare
$make scripts
$make
3)安装模块
$make modules 这一步不需要
$make module_install
执行结束之后,会在/lib/modules下生成新的目录/lib/modules/2.6.32.44+drm33.19
四、生成镜像文件
1)生成内核镜像文件
$make bzImage
执行完成后将在arch/i386/boot/目录下生成bzImage镜像文件,使用下面命令安装到系统的/boot目录下:
$sudo make install
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两个文件
或者直接拷贝
$ sudo cp arch/i386/boot/bzImage /boot/vmlinuz-2.6.32.44+drm33.19
2)生成要载入ramdisk的映像文件
如果linux系统按照在scsi磁盘上,这部是必须的,否则可以跳过。
我的linux是装在vmware上的,用的是虚拟的scsi磁盘,所以必须要这一步。
输入命令:
mkinitramfs -o /boot/initrd.img-linux2.6.32.44+drm33.19 2.6.32.44+drm33.19
第二个参数是版本号,必须和/lib/modules/目录下新内核对应的模块的文件夹名字一致,即2.6.32.44+drm33.19 。
五、使用新编译的内核
Ubuntu采用Grub引导,要使用新内核,必须配置grub。
1) 更改grub配置,显示启动菜单
$su – root
$gedit /etc/default/grub &
注释GRUB_HIDDEN_TIMEOUT=0语句,及改成#GRUB_HIDDEN_TIMEOUT=0后保存
2)更新启动配置文件
$update-grub
执行命令后,该命令自动搜索/boot文件夹,将相应的镜像加入/boot/grub/grub.cfg启动菜单,并根据/etc/default/grub内容更新配置文件。
更新后,将增加如下内容:
menuentry 'Ubuntu, with Linux 2.6.32.44+drm33.19' --class ubuntu --class gnu-linux --class gnu --class os {
recordfail
insmod ext2
set root='(hd0,5)'
search --no-floppy --fs-uuid --set 4aaa411a-c1ab-4c9e-94bf-770717be6d9a
linux /vmlinuz-2.6.32.44+drm33.19 root=/dev/sda8 ro quiet splash
}
menuentry 'Ubuntu, with Linux 2.6.32.44+drm33.19 (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os {
recordfail
insmod ext2
set root='(hd0,5)'
search --no-floppy --fs-uuid --set 4aaa411a-c1ab-4c9e-94bf-770717be6d9a
echo 'Loading Linux 2.6.32.44+drm33.19 ...'
linux /vmlinuz-2.6.32.44+drm33.19 root=/dev/sda8 ro single
echo 'Loading initial ramdisk ...'
}
3)手工更改配置文件
因为是SCSI,须手工加入启动时需要的ramdisk的映像文件, initrd开头部分:menuentry 'Ubuntu, with Linux 2.6.32.44+drm33.19' --class ubuntu --class gnu-linux --class gnu --class os {
recordfail
insmod ext2
set root='(hd0,5)'
search --no-floppy --fs-uuid --set 4aaa411a-c1ab-4c9e-94bf-770717be6d9a
linux /vmlinuz-2.6.32.44+drm33.19 root=/dev/sda8 ro quiet splash
initrd /initrd.img-linux2.6.32.44+drm33.19
}
menuentry 'Ubuntu, with Linux 2.6.32.44+drm33.19 (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os {
recordfail
insmod ext2
set root='(hd0,5)'
search --no-floppy --fs-uuid --set 4aaa411a-c1ab-4c9e-94bf-770717be6d9a
echo 'Loading Linux 2.6.32.44+drm33.19 ...'
linux /vmlinuz-2.6.32.44+drm33.19 root=/dev/sda8 ro single
echo 'Loading initial ramdisk ...'
initrd /initrd.img-linux2.6.32.44+drm33.19
}
修改完成并保存后,重新启动系统,应该出现让你选择内核的菜单。
六、准备Helloworld源代码和Makefile文件
$mkdir hello
$cd hello
$gedit Helloworld.c Makefile &
Helloworld.c内容:
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
printk(KERN_ALERT "Hello, world\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
Makefile内容:
#Makefile 2.6
ifneq ($(KERNELRELEASE),)
#kbuild syntax dependency relationship of files and target modules are listed here.
mymodule-objs:=helloworld.o
obj-m:=helloworld.o
else
PWD:=$(shell pwd)
#为正在运行的内核编译模块,使用下列配置
KVER?=$(shell uname -r)
#KDIR:=/lib/modules/$(KVER)/build
#或使用/usr/src/linux-headers-2.6.32-21-generic目录
#不是为正在运行的内核编译模块,使用下列配置
#KDIR:=/usr/src/linux-2.6.32.21/
KDIR:=/usr/src/linux-source-2.6.32/
all:
$(MAKE) -C $(KDIR) M=$(PWD)
clean:
@rm -rf .*.com *.o *.mod.c *.ko .tmp_versions modules.order Module.symvers endif
七、编译并安装模块
1)编译
编译前,请先编译新内核,否则出现警告信息
$cd ~/hello
$make
2)安装模块
$sudo insmod helloworld.ko
3)移除模块
$rmmod helloworld
4)查看模块信息
$sudo modinfo helloworld
$lsmod 列出所有模块
八、查看输出信息
cat /proc/kmsg 会一直打印,需要Ctrl-C手动终止
dmesg 或dmesg | tail -N ,N为一数字,表示显示最后N行
cat /var/log/message
九、问题及解决方法:
1
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
解决:
$make scripts
2, Invalid module format问题
使用正在运行的内核的头文件编译出的模块,不会出现该问题
insmod: error inserting 'hellomod.ko': -1 Invalid module format
此时,你用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 '
解决办法:(按照下面说的无法解决,只有加载新内核才不出问题)
那该怎么办呢?最简单的办法就是:修改源目录下的Makefie
把
最Makefile第1-4行的值改为当前内核一样的值
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 24
EXTRAVERSION = .2
NAME = Err Metey! A Heury Beelge-a Ret!
那怎么确定你当前内核的值是多少呢?
vi /lib/modules/`uname -r`/build/Makefile
注意:重新编译内核和不编译内核后得到的模块文件,在安装时显示的信息一样,但dmesg | tail显示的信息不通。
3
$insmod helloworld.ko
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"
4,编译模块时出下面错误
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要增加以下几行
CFLAGS += -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h
或者在你的C源文件里增加
#ifdef CONFIG_MODVERSIONS
#define MODVERSIONS
#include <linux/modversions.h>
#endif
这样就可以在编译内核模块时,如果模块里引用了内核符号表,就可以自动计算校验字串,而不会在加载模块时出现unresloved symbol的错误了。
二、
但是当你的内核在编译时使能了CONFIG_MODVERSIONS选项,那么你插入的模块可以是一下两种情况:
1,编译时没有带CONFIG_MODVERSIONS选项,但版本必须与内核的版本一致;
2,编译时如果带有CONFIG_MODVERSIONS选项,那么模块的版本将没有限制;
而通常内核在编译是带有CONFIG_MODVERSIONS选项的,所以就出现了文章开头出现的情况:内核和模块的版本不一致。
同时我们也就找到了相应的解决办法--在模块编译时选择CONFIG_MODVERSIONS选项,这样我们就可以解决版本不匹配的问题了。
我们需要这源文件(c文件)中加上下面的宏定义:
#ifdef CONFIG_MODULES
#ifdef CONFIG_MODVERSIONS
#MODFLAGS += -DMODVERSIONS -include $(HPA TH)/linux/modversions.h
#endif
#endif
然后编译就可以了。