一文详解Linux内核源码组织结构

概要:本文内容包含linux源码树结构分析、linux makefile分析、kconfig文件分析、linux内核配置选项分析。这些知识是为了理解内核文件的组织形式,为具体移植内核做知识准备。
一, linux源码树结构分析 对linux源码树下个子目录内包含的内容进行列表罗列:
arch:体系结构相关的代码,每一个子目录代表一种架构 block:块设备的通用函数 crypot:常用加密和散列算法、压缩和crc校核算法 fs:linux支持的文件系统,每一个子目录代表一种文件系统 include:内核头文件:基本头文件(include/linux )、驱动或功能部件头文件(例:include/mtd )、体系相关头文件(linux/asm-arm ) driver:所有的驱动程序,每一个子目录代表一类驱动程序 init:内核的初始化程序,其中main.c中的start_kernel函数是内核引导后执行的第一个函数 ipc:进程间通信代码 kernel:内核管理的核心代码,与体系相关的代码在/arch/$(arch)/kernel lib:内核用到的库函数,与处理器相关的库函数位于/arch/$(arch)/lib mm:内存管理代码,与处理器体系相关的位于/arch/$(arch)/mm net:与网络相关的代码,每一个子目录对应于网络的一个方面 security:安全、密钥相关的代码 sound:音频相关的驱动程序 usr:用来制作一个压缩的cpio归档文件:initrd的镜像,它可以作为内核启动后挂载的第一个文件系统 script:用于配置、编译内核的脚本文件 documet:内核文档 二,linux makefile分析 主要从三个方面讲解:编译哪些文件、如何编译文件、如何连接文件
(1)linux makefile的分类
顶层makefile:总体上控制着内核的编译 arch/$(arch)/makefile:决定哪些和体系相关的代码参加编译 .config:配置文件,内核配置时产生,所有的makefile都根据这个文件编译内核(包括顶层的和各分成的makefile) scripts/makefile.*:makefile公用的通用规则、脚本等 */makefile:负责该目录下文件的编译 (2)编译哪些文件
顶层makefile决定哪些目录中的文件将编译进内核
init-y := init/ drivers-y := drivers/ sound/ firmware/ net-y := net/ libs-y := lib/ core-y := usr/ ... core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ 顶层makefile将13个子目录分成5个部分:init-y、drivers-y、net-y、libs-y、core-y
顶层通过下列语句包含和体系架构有关的makefile。仔细观察可以看到/arch子目录的根目录下是没有makefile文件的,而其它各子目录都是有makefile。
include $(srctree)/arch/$(srcarch)/makefile ... srcarch := $(arch) 所以在编译内核之前先要确定arch
arch ?= $(subarch) cross_compile ?= ... subarch := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ -e s/arm.*/arm/ -e s/sa110/arm/ \ -e s/s390x/s390/ -e s/parisc64/parisc/ \ -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ -e s/sh[234].*/sh/ ) 默认的arch不是我们需要的,所以要进行修改
arch ?= arm cross_compile ?=arm-linux- $$(srctree)/arch/$(srcarch)/makefile对内核的内容进行了扩充
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)...head-y := arch/arm/kernel/head$(mmuext).o arch/arm/kernel/init_task.o 可以看到一个新元素head-y,它还有一个特殊的地方,它是直接对应着两个文件,而不是目录。之所以分成两个是为了同时支持有无mmu的cpu,它们对应着两个不同的head$(mmuext).o 文件,由变量mmuext控制,可以在配置时设定。
至此我们知道了编译时将进入哪些文件进行编译。编译时依次进入init-y、core-y、libs-y、drivers-y、net-y中列的目录调用其中的makefile进行编译,每一个子目录都会生成build-in.o(libs-y所列的目录下有可能生成lib.a)。最后head-y列出的文件和build-in.o、lib.a一起连接成vmlinux。
在配置内核时,将会产生.config文件,makefile将会在.config文件中添加下面两行。
config_kernelversion = 2.6.32.2config_arch = arm 有可能是版本原因,在2.6.32.2版本中并没有上面两个语句,有下面两句。
#linux kernel version = 2.6.32.2config_arm = y 观察.config文件会发现变量的值主要有两种y、m,各级的makefile将会根据这些变量的值来决定编译哪些文件,同时是编译进内核,还是作为内核模块存在。
obj-y中定义的.o文件将由当前目录下的.c、.s文件及子目录下的build-in.o文件编译连接得到的。
注意:obj-y中定义的.o文件的顺序是由意义的。
下面是一段取自子目录中的makefile文件内容,在该目录下有ioat和ipu子目录
obj-$(config_dma_engine) += dmaengine.o obj-$(config_net_dma) += iovlock.o obj-$(config_dmatest) += dmatest.o obj-$(config_intel_ioatdma) += ioat/ obj-$(config_intel_iop_adma) += iop-adma.o obj-$(config_fsl_dma) += fsldma.o obj-$(config_mv_xor) += mv_xor.o obj-$(config_dw_dmac) += dw_dmac.o obj-$(config_at_hdmac) += at_hdmac.o obj-$(config_mx3_ipu) += ipu/ obj-$(config_txx9_dmac) += txx9dmac.o obj-$(config_sh_dmae) += shdma.o obj-m中定义的.o文件是由的当前目录下的.c、.s文件编译生成,它们不会与build-in.o一起编译进入内核。而是被编译成.ko文件,作为模块存在。
当.o文件由单文件编译而成时,用下面的语句:
obj-$(config_isdn_ppp_bsdcomp) += isdn_bsdcomp.o 当.o文件由多文件编译而成时,用下面的语句:
obj-$(config_isdn) +=isdn.oisdn-objs := isdn_net_lib.o isdn_v110.o isdn_commen.o 编写驱动程序时,也是以这种方式编写makefile。
lib-y中定义的.o文件是由的当前目录下的.c、.s文件编译生成,他们被打包成当前目录下的lib.a文件。同时出现在lib-y和obj-y中的文件,不会被包含进lib.a文件。
obj-y和obj-m可以用来指定进入下一级目录。
(3)怎么编译这些文件
怎么编译文件就是意味着编译选项和连接选项是什么。
这些选项分成3类:全局的(适用整个代码树)、局部的(适用单个makefile)、个体的(适用单个文件)。
全局选项是在顶层makefile和arch/$(arch)/makefile中定义的,这些选项是cflags、aflags、ldflags、arflags,它们分别是编译c文件的选项,编译汇编文件的选项,连接文件的选项,制作库文件的选项。
局部选项在各自子目录中定义,名称为:extra_cflags、extra_afalgs、extra_ldfalgs、extra_arflags.
对单文件设定编译选项,可以用clfags_$@、aflags_$@,前者对c文件,后者对汇编文件。
注意:3类选项是一起使用的,在scripts/makefile.lib中可以看到:
_c_flags = $(cflags) $(extra_cflgas) $(cfalgs_$(baseterget.o)) 如何连接文件
在顶层makefile文件中有如下语句:
init-y := $(patsubst %/, %/built-in.o, $(init-y))core-y := $(patsubst %/, %/built-in.o, $(core-y))drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y))net-y := $(patsubst %/, %/built-in.o, $(net-y))libs-y1 := $(patsubst %/, %/lib.a, $(libs-y))libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y))libs-y := $(libs-y1) $(libs-y2) 可以看出以后的连接是相当于着五种built-in.o文件和head-o文件的连接。
之后对这些文件再次进行合并
vmlinux-init := $(head-y) $(init-y)vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)vmlinux-all := $(vmlinux-init) $(vmlinux-main)vmlinux-lds := arch/$(srcarch)/kernel/vmlinux.lds 可以看出初始化代码由两部分组成head-y和init-y两部分组成,而且head-y是在init-y的前面。所以总的代码顺序是arch/arm/kernel/head.o(假设有mmu,没有的话是head_nommu.o)、arch/arm/kernel/init_task.o、init/build-in.o。
连接脚本是arch/$(srcarch)/kernel/vmlinux.lds,它由arch/$(srcarch)/kernel/vmlinux.lds.s生成。
具体连接细节可以查看上面的文件内容。
三,内核的kconfig分析 内核配置工具读取各个kconfig文件,生成配置界面共开放人员配置内核,最后生成配置文件.config。
关于kconfig的最权威资料在/documentations/kbuild/kconfig-language.txt
kconfig语法分析:
kconfig的基本要素:config ;config经常被其它条目包含,用来生成菜单和多项选择。config jffs2_fs_wbuf_verify bool verify jffs2 write-buffer reads depends on jffs2_fs_writebuffer default n help this causes jffs2 to read back every page written through the write-buffer, and check for errors. 上述代码是config的常用方式:
config jffs2_fs_wbuf_verify 在配置界面中配置了该选项后,会在.config中出现 config_jffs2_fs_wbuf_verify = y或者m.
bool verify jffs2 write-buffer reads 在配置界面中将会显示verify jffs2 write-buffer reads选项,bool是变量的类型,一共有5种变量类型:bool、tristate、 string 、hex 、int,bool变量有两种取值y,m;tristate变量有三种取值y,m,n;string可以取字符串;hex取十六进制数;int取十进制数。
depends on jffs2_fs_writebuffer 代表只有在jffs2_fs_writebuffer被配置时,才会进行该选项的配置。
default n 代表默认的情况下是选择n
select fs_posix_acl 代表在该选项被选种时,会将fs_posix_acl也选种。
help this causes jffs2 to read back every page written through the write-buffer, and check for errors. 当在配置时按h时会显示该信息。
menu条目
配置界面的主界面是由根目录下makefile中arch配置决定的,当选择arm时,/arch/arm中的kconfig文件将会用来生成主目录。
下面的内容摘自/arch/arm/kconfig
mainmenu linux kernel configuration 设定主目录的名称
menu system type 将会创建system type子目录
choice条目
choice将多个类似的配置选项组合在一起,供用户多选和单选
choice prompt memory split default vmsplit_3g help select the desired split between kernel and user memory. if you are not absolutely sure what you are doing, leave this option alone! config vmsplit_3g bool 3g/1g user/kernel split config vmsplit_2g bool 2g/2g user/kernel split config vmsplit_1g bool 1g/3g user/kernel splitendchoice prompt memory split 上述代码给出提示信息,选中之后就可以进行选择配置
choice条目中定义的变量类型只能是bool和tristate,当配置的代码编译入内核时为bool,只能有一个条目选择为y;当编译成模块时为tristate或bool,为bool时,也只能是一个为y,当为tristate时,可以有多个m。
comment条目
comment条目用于提供帮助信息,出现在配置界面的第一行。
comment at least one emulation must be selected source条目
用于包含其他kconfig文件
source drivers/cpuidle/kconfig 菜单形式的配置界面的操作方法
配置界面中[*]、、[ ]分别表示相应的文件被编译进内核、编译成模块、没有被编译。
load an alertnate configuration file save an alertnate configuration file 当执行第一条语句时,将.config外的config文件加载,当执行第二条时,表示存储成处.config 外的config文件。
四,linux内核配置选项 与移植密切相关的内容是system type、device driver。
内核配置主界面内容
code maturity level options:代码成熟度选项,包含一些正在开发的或者不成熟的代码和驱动程序,一般不用设置 general setup:常规设置,比如增加附加的内核版本号、支持内存页交换功能、system v进程间通信等。除非很熟悉其中的内容,否则一般使用默认配置 loadable module support:可加载模块支持:一般都会打开可加载模块支持(enable loadable module support )、允许卸载已经加载的模块(module unloading)、让内核通过运行modprobe来自动加载模块(automatic kernel module loading) block layer:块设备层:用于设置块设备的一些总体参数,比如是否支持大于2tb的块设备、是否支持大于2tb的文件、设置io调度器,使用默认值即可 system type:系统类型:选择cpu的架构、开发板类型等于开发板相关的配置选项 bus support:pcmcia 、cardbus总线的支持,对于arm开发板不需要设置 kernel feature :用于设置内核的一些参数,比如是否支持内核抢占,是否支持动态修改系统时钟 boot option:启动参数:比如设置默认的命令行参数等,一般不用理会 floating point emulation:浮点运算仿真功能:因为linux内核不支持硬件浮点运算,所以要选择一个浮点仿真器,一般选择”nwfpe math emulaiton” userspace binary formats:可执行文件格式:一般都选择elf、a.out格式 power management options:电源管理选项 networking:网络协议选项:一般都选择”networking support“以支持网络功能。通常可以在选择”networking support“后,使用默认配置 device driver:设备驱动程序:几乎包含了linux的所有的驱动程序 file systems:文件系统:选择支持的文件系统 profiling support:对系统的或顶进行分析,仅供内核开发者使用 kernel hacking:调试内核时的各种选项:linux设备驱动程序中有详细描述 security options:安全选项:一般使用默认选项 cryptographic options:加密选项 library routines:库子程序:比如crc32检验函数、zlib压缩函数等。不包含在内核源码中的第三方内核模块可能需要这些库,可以全不全,内核中若有其他部分依赖它,会自动选项 在配置内核的时候按照顺序进行,因为前面的配置会影响后面的。


智能手环的PCB设计的注意事项
桥式整流电路计算公式及输出电压波形图
辉芒微兼容ST003系列MCU芯片的的推荐说明
FPN(特征金字塔网络)的直觉、架构和表现简要介绍
乐播乐投荣获“年度优秀智慧盒子”,创造大小屏互联“无线”可能
一文详解Linux内核源码组织结构
巴塞罗那绽放中国智能 百度国际化组团亮相MWC
探讨自动驾驶在传感器选型和布置上考虑的问题
微机电系统(MEMS)的基本工艺和应用
RCC式开关电源及应用技术方案
芯原科技获认定为2023年临港新片区企业研发创新机构
使用高速Micro的串口-Using the High-Sp
工控机的作用与特点
iQOO 618优惠多多:直降1400元,五折爆款等你来抢
食品添加剂检测仪对食品行业的分析
全球首款柔性可穿戴体温计进入量产
电路板、工控电路板、信号板等维修的技术处理及维修方法
大讲解PATHRROT X2信道模拟器在NB-IoT测试中的应用
永磁电机中常用的磁铁材质有哪些?
测量电机的好坏要怎样测量