Linux系统Ubuntu下的驱动开发编译环境搭建方法与步骤

目录
[隐藏]

本文主要介绍了Linux系统Ubuntu下的驱动开发编译环境搭建方法与步骤,仅供参考。

一、准备开发工具

开发工具主要有gcc、gdb、make

在Ubuntu中可以通过下面这个命令安装:

$apt-get install build-essential

二、下载Linux源代码

linux源码可以通过以下几种途径获得:

1)直接去www.kernel.org下载

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):

配置内核

$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.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 …'
}

手工更改配置文件

因为是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, worldn");
    return 0;
}
static void hello_exit(void)
{
    printk(KERN_ALERT "Goodbye, cruel worldn");
}
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

保存文件后,编译通过。如果出现

#make
Makefile:10: *** 遗漏分隔符 (您的意思是用 TAB 代替 8 个空格?)。停止。

#make
make: 没有什么可以做的为 `all'。

的错误,都是因为Makefile的格式不对, $(MAKE)和 rm -rf *.o *前面的空格都应该是一个TAB键。

七、编译并安装模块

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. include/config/auto.conf配置文件问题

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显示的信息不同。

3Invalid module format
$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.modules will have no dependencies and modversions

编译模块时出下面错误

 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 $(HPATH)/linux/modversions.h
#endif
#endif

然后编译就可以了。

点赞 (1)

发表评论

电子邮件地址不会被公开。 必填项已用*标注