Linux设备驱动归纳总结(一):内核的相关基础概念

目录

一.Linux设备驱动的作用:

二.内核代码树介绍:

三.内核补丁:

四.内核中的Makefile:

五.子目录下的Makefile和Kconfig:

六.内核和模块的编译

七.总结


.Linux设备驱动的作用:

1.1 内核: 用于管理软硬件资源,并提供运行环境。如分配4G虚拟空间等。linux设备驱动:是连接硬件和内核之间的桥梁。 

1.2 应用层:包括POSIX接口,LIBC,图形库等,用于给用户提供访问 内核的接口。属于用户态,ARM运行在用户模式(usr) 者系统模式(sys)下。

1.3 内核层:应用程序调用相关接口后,会通过系统调用,执行SWI切换ARM的工作模式到超级用户(svc)模式下,根据用 户函数的要求执行相应的操作。

1.4 硬件层:硬件设备,当用户需要操作硬件时,内核会根据驱动接口 操作硬件设备

1.5 图结构:

1.6 对比生活酒店服务图解:

.内核代码树介绍:

 

|-arch : 包含和硬件体系结构相关的代码

|-block : 硬盘调度算法,不是驱动

|-firmware : 固件,如BOIS

|-Documentation: 标准官方文档

|-dirver : linux设备驱动

|-fs : 内核所支持的文件体系

|-include 头文件。linux/module.h linux/init.h 常用库。

|-init 库文件代码,C库函数在内核中的实现。

       init/main.c ->start_kernel->内核执行第一条代码

|-ipc : 进程件通信

|-mm 内存管理

|-kernel : 内核核心部分,包括进程调度等

|-net 网络协议

|-sound : 所有音频相关

其中,跟设备驱动有关并且经常查阅的文件夹有:

init,include (linux, asm-arm),drivers,arch 等文件夹。

.内核补丁:

3.1 补丁说明:

一般都是基于某个版本内核生成的,用于升级旧内核。

打补丁需要注意:

1.对应版本的补丁只能用于对应版本的内核。

2.如果在已打补丁的内核再打补丁,需要先卸载原来补丁。

3.2 打补丁的方法:

1.制作补丁:

diff -Nur linux-2.6.30/ linux-2.6.30.1/ > linux-2.6.30.1.patch

命令:diff -Nur 旧版本  新版本 > 目标补丁.patch

2.打补丁:

cd linux-2.6.30  //注意在原文件夹的目录中打补丁

patch -p1 < ../linux-2.6.30.1.patch //-p1是忽略一级目录

3.恢复:

cd linux-2.6.30 //注意在原文件夹的目录中打补丁

patch -R < ../linux-2.6.30.1.patch //撤销补丁

.内核中的Makefile

对于内核,Makefile分为5类:

Documentation/kbuild/makefiles.txt描述如下:

Makefile 总Makefile,控制内核的编译

.config  内核配置文件,配置内核时生成, 如make menuconfig后

arch/$(ARCH)/Makefile  对应体系结构的Makefile

scripts/Makefile.*           Makefile共用的规则

kbuild Makefiles 各子目录下的Makefile,被上层的Makefile调用。

简单来说,编译内核会执行以下两步骤,它们分别干了以下的事情。

4.1 如果第一次编译menuconfig进行配置,就会生成.config,保存好配置,下次编译就直接拷贝在内核文件夹根目录即可,减少重复工作量。

4.2 make menuconfig

4.2.1由总rcMakefile决定编译的体系结构(ARCH). 编译工具(CROSS_COMPILE),并知道需要进去哪些内核根下的哪些目录进行编译。

4.2.2arch/$(ARCH)/Makefile,决定arch/$(ARCH)下还有 的哪些目录和文件需要编译。

4.2.3知道了需要编译的目录后,递归的进入哪些目录下,读取每一个Kconfig的信息,生成了图形配置的界面。

4.2.4通过我们在图形配置界面中选项为[*][M]或者[]

4.2.5保存并退出配置,会根据配置生成一份新的配置文件.config,并在同时生成include/config/auto.conf(这是.config的去注释版)。文件里面保存着CONFIG_XXXX等变量应该取y还是取m

4.3 make

根据Makefile包含的目录和配置文件的要求,进去个子目录进行编译,最后会在各子目录下 生成一个.o或者.a文件,然后总Makefile指定的连接脚本 arch/$(ARCH)/kernel/vmlinux.lds生成vmlinux,并通过 压缩编程bzImage,或者按要求在对应的子目录下编译成 模块。。

但是,具体是怎么生成配置文件的呢?

4.3.1 在总Makefile中,根据以下语句进入需要编译的目录

# Objects we will link into vmlinux / subdirs we need to visit

init-y := init/

drivers-y := drivers/ sound/ firmware/

net-y := net/

libs-y := lib/

core-y := usr/

endif # KBUILD_EXTMOD

core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/

上面说明了,根目录下的init、driver、sound、firmware、net、lib、usr等目录,在编译时都会进去读取目录下的Makefile并进行编译。

4.3.2 在总Makefile中包含的目录还是不够的,内核还需要根据对应的CPU体系架构,

决定还需要将哪些子目录将要编译进内核。在总Makefile中有一个语句:

include $(srctree)/arch/$(SRCARCH)/Makefile //在这里,我定义SRCARCH = arm

可以看出,在总Makefile中进去读取相应体系 结构的Makefile->arch/$(SRCARCH)/Makefile。

arch/$(SRCARCH)/Makefile中指定arch/$(SRCARCH)路径下的哪些子目录需要被编译。

在 arch/arm/Makefile 下:

head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o

# If we have a machine-specific directory, then include it in the build.

core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/

core-y += $(machdirs) $(platdirs)

core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/

core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ)

core-$(CONFIG_VFP) += arch/arm/vfp/

drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/

libs-y := arch/arm/lib/ $(libs-y)

上面看到,指定需要进入arch/arm/kernel/、arch/arm/mm/、arch/arm/common/ 等目录编译,至于core-y、 core-$(CONFIG_FPE_NWFPE)这些是什么东西呢?

 

其中,y表示编译成模块,m表示编译进内核(上面没有,因为默认情况下ARM全部编译进 内核),但$(CONFIG_OPROFILE)又是什么呢? 这些是根据用户在make menuconfig中设置后,生成的值赋给了CONFIG_OPROFILE。

 

4.3.3 那make menuconfig后的配置信息是怎么来的?

这是由各子目录下的Kconfig提供选项功用户选择并配置。

如arch/arm/Kconfig。 所有的配置都是根据arch/$(ARCH)/Kconfig文件通过Kconfig的语法source读取 各个包含的子目录Kconfig来生成一个配置界面。每个Makefile目录下都有一个 对应的Kconfig文件,用于生成配置界面来给用户决定内核如何配置,配置后会确定一个。 CONFIG_XXX的的值(如上面的CONFIG_OPROFILE),来决定编译进内核,还是编译成模块或者不编译。

如在arch/arm/Kconfig下:

source "arch/arm/mach-clps711x/Kconfig"

source "arch/arm/mach-ep93xx/Kconfig"

source "arch/arm/mach-footbridge/Kconfig"

source "arch/arm/mach-integrator/Kconfig"

source "arch/arm/mach-iop32x/Kconfig"

source "arch/arm/mach-iop33x/Kconfig"

这些就是用来指定,需要读取以下目录下的Kconfig文件来生成一个使用make menuconfig时的配置界面。

至于子目录下的Kconfig是怎么样的,待会介绍。

总结Kconfig的作用:

1.在make menuconfig下可以配置选项;

2.在.config中确定CONFIG_XXX的的值。

3.只是读取以上的两个Makefile还是不够了,内核还会把包含的子目录一层一层的 读取它里面的Makefile和Kconfig。

 

内核的编译并不是一个Makefile搞定的,需要通过根目录下的总Makefile来包含一下子Makefile(不管是根目录下的子目录还是/arch/arm中的子目录)。而Kconfig,为用户提供一个交互界面来选择如何配置并生成配置选项。

五.子目录下的Makefile和Kconfig:

上面我一直介绍的都是两个比较大的Makefile——总Makefile和 arch/$(ARCH)/Makefile。接下来看一下实例。

 

5.1 在makefile中,y表示编译进内核,m表示编译成模块,不写代表不编译。 所以,配置最简单的方法就是,直接修改子目录的Makefile 。

先看看arch/arm/Makefile:

/*arch/arm/mach-projectName/Makefile */

obj-$(CONFIG_CPU_projectName) += irq.o

obj-$(CONFIG_CPU_projectName) += clock.o //配置时钟进入模块

obj-$(CONFIG_projectName_DMA) += dma.o

如果我要取消时钟(当然这是必须要开的,只是举例)。 可以直接修改arch/arm/mach-projectName/Makefile 将obj-$( CONFIG_CPU_projectName) += clock.o改为

obj- += clock.o

如果你想编译成模块也可以修改成:

obj-m += clock.o

5.2 在一般的编译内核时,我们都是通过”make menuconfig”进入图形界面面配置的, 接下来我实现一下如何将一个选项加入到图形配置界面中。

5.2.1 进入内核目录

cd linux-2.6.29

5.2.2 在driver目录下模拟一个名为test1驱动的文件夹

mkdir driver/test1

5.2.3 在目录下随便些一个C文件,只要不报错。

vim test1.c

我的test1.c如下:

 void foo()

{

 ;

}

5.2.4 vim Makefile //在目录下编写一个简单的Makefile

Makefile文件编写如下:

obj-$(CONFIG_TEST1) += test1.o

CONFIG_TEST1是决定test1是否编译进内核或者编译成模块的。这就是通 过同一目录下的Kconfig来在配置界面中生成选项,由用户在make menuconfig中选择。

5.2.5所以还要同一目录下写一个Kconfig:

vim Kconfig

Kconfig修改如下:

menu "test1 driver here" //这是在图形配置显示的

config TEST1

bool "xiaobai test1 driver" //这同样也是在图形配置显示的

help

This is test1 //这个也是在图形配置显示的。

说白了,就是在图形配置的driver下多了一个配置选项,用户配置后将 CONFIG_TEST1的值存放在.config中,Makefile通过读取.config的去注 释版include/config/auto.conf读取到CONFIG_TEST的值,再进行编译。

 

但是,以上几步还不能达到目的,因为虽然在总Makefile中已经包含了 目录driver,但是driver目录的Makefile中并没有包含test目录。因此 需要在driver/Makefile中添加:

obj-$(CONFIG_STAGING) += staging/

obj-y += platform/

obj-$(CONFIG_TEST1) += test1/ //这是我添加的

虽然Makefile中已经包含了,但这样还是不行。因为当需要配置ARM时, ARM结构下的Kconfig并没有包含test的Kconfig。这样的话就不会出现在 图形配置界面中,因此在arch/arm/Kconfig中添加:

menu "Device Drivers" //要在Device Drivers这个选项里面添加

source "drivers/base/Kconfig"

source "drivers/connector/Kconfig"

source "drivers/test/Kconfig" //这是我添加的

大功告成!

这样,make menuconfig界面写的Driver Devices下就多了一个 "test1 friver here"的目录,里面有一个配置选项"xiaobai test1 driver"。

 

Kconfig文件的语法在documentation/kbuild/kconfig-language.txt文件中 有详细的讲解,上面我只是简单实现了一下,都是皮毛。

六.内核和模块的编译

 

编译内核很简单,只需要配置完毕后执行make命令,将指定的文件编译进内核

bzImage或者编译成模块。

make = make bzImage + make modules

因此如果值编译内核,即只编译配置文件中-y选项,可以直接用命令

make bzImage

如果值编译模块,即只编译配置文件中的-m选项,可以之直接使用命令

make modules

模块可以编译当然也可以清除,使用命令

make modules clean

如果只想单独编译一个模块,可以使用命令

make M=drivers/test/ modules //只单独编译drivers/test中的.ko

make M=drivers/test/ modules clean //清除

上面的是在内核目录下的操作,但当我写驱动时,我并不可能在内核目录下编

写,但我编译时却要依赖内核中的规则和Makefile,所以就有了以下的方法,

同时这也是一般的编写驱动时Makefile的格式。

指定内核Makefile并单独编译

make -C /root/linux-2.6.29 M=`pwd` module

make -C /root/linux-2.6.29 M=`pwd` module clean

//-C 指定内核Makefile的路径,可以使用相对路径。

//-M 指定要编译的文件的路径,同样课使用相对路径。

编译生成的模块可以指定存放的目录

make -C /root/linux-2.6.29 M=`pwd` modules_install INSTALL_MOD_PATH=/nfsroot

七、总结

内核编译时大体上究竟是怎么样的一个过程。

7.1 一般我们会想将一份项目的默认配置拷贝到内核跟目录下并改名为.config。

7.2 make menuconfig

7.2.1、由总Makefile决定编译的体系结构(ARCH). 编译工具(CROSS_COMPILE),并知道需要进去哪些内核根下的哪些目录进行编译。

7.2.2、由arch/$(ARCH)/Makefile,决定arch/$(ARCH)下还有 的哪些目录和文件需要编译。

7.2.3、知道了需要编译的目录后,递归的进入哪些目录下,读取每一个Kconfig的信息,生成了图形配置的界面。

7.2.4、通过我们在图形配置界面中选项为[*]、[M]或者[]。

7.2.5、保存并退出配置,会根据配置生成一份新的配置文件.config,并在同时生成include/config/auto.conf(这是.config的去注释版)。文件里面保存着CONFIG_XXXX等变量应该取y还是取m。

7.3 make

根据Makefile包含的目录和配置文件的要求,进去个子目录进行编译,最后会在各子目录下 生成一个.o或者.a文件,然后总Makefile指定的连接脚本 arch/$(ARCH)/kernel/vmlinux.lds生成vmlinux,并通过 压缩编程bzImage,或者按要求在对应的子目录下编译成 模块。

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部