概要:本文內(nèi)容包含Linux源碼樹結(jié)構(gòu)分析、Linux Makefile分析、Kconfig文件分析、Linux內(nèi)核配置選項(xiàng)分析。這些知識是為了理解內(nèi)核文件的組織形式,為具體移植內(nèi)核做知識準(zhǔn)備。
一, Linux源碼樹結(jié)構(gòu)分析
對Linux源碼樹下個子目錄內(nèi)包含的內(nèi)容進(jìn)行列表羅列:
- arch:體系結(jié)構(gòu)相關(guān)的代碼,每一個子目錄代表一種架構(gòu)
- block:塊設(shè)備的通用函數(shù)
- crypot:常用加密和散列算法、壓縮和CRC校核算法
- fs:Linux支持的文件系統(tǒng),每一個子目錄代表一種文件系統(tǒng)
- include:內(nèi)核頭文件:基本頭文件(include/linux )、驅(qū)動或功能部件頭文件(例:include/mtd )、體系相關(guān)頭文件(linux/asm-arm )
- driver:所有的驅(qū)動程序,每一個子目錄代表一類驅(qū)動程序
- init:內(nèi)核的初始化程序,其中main.c中的start_kernel函數(shù)是內(nèi)核引導(dǎo)后執(zhí)行的第一個函數(shù)
- ipc:進(jìn)程間通信代碼
- kernel:內(nèi)核管理的核心代碼,與體系相關(guān)的代碼在/arch/$(ARCH)/kernel
- lib:內(nèi)核用到的庫函數(shù),與處理器相關(guān)的庫函數(shù)位于/arch/$(ARCH)/lib
- mm:內(nèi)存管理代碼,與處理器體系相關(guān)的位于/arch/$(ARCH)/mm
- net:與網(wǎng)絡(luò)相關(guān)的代碼,每一個子目錄對應(yīng)于網(wǎng)絡(luò)的一個方面
- security:安全、密鑰相關(guān)的代碼
- sound:音頻相關(guān)的驅(qū)動程序
- usr:用來制作一個壓縮的cpio歸檔文件:initrd的鏡像,它可以作為內(nèi)核啟動后掛載的第一個文件系統(tǒng)
- script:用于配置、編譯內(nèi)核的腳本文件
- Documet:內(nèi)核文檔
二,Linux Makefile分析
主要從三個方面講解:編譯哪些文件、如何編譯文件、如何連接文件
(1)Linux Makefile的分類
- 頂層Makefile:總體上控制著內(nèi)核的編譯
- arch/$(ARCH)/Makefile:決定哪些和體系相關(guān)的代碼參加編譯
- .config:配置文件,內(nèi)核配置時產(chǎn)生,所有的Makefile都根據(jù)這個文件編譯內(nèi)核(包括頂層的和各分成的Makefile)
- scripts/Makefile.*:Makefile公用的通用規(guī)則、腳本等
- */Makefile:負(fù)責(zé)該目錄下文件的編譯
(2)編譯哪些文件
頂層Makefile決定哪些目錄中的文件將編譯進(jìn)內(nèi)核
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
頂層通過下列語句包含和體系架構(gòu)有關(guān)的Makefile。仔細(xì)觀察可以看到/arch子目錄的根目錄下是沒有Makefile文件的,而其它各子目錄都是有Makefile。
include $(srctree)/arch/$(SRCARCH)/Makefile
...
SRCARCH := $(ARCH)
所以在編譯內(nèi)核之前先要確定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/ )
默認(rèn)的ARCH不是我們需要的,所以要進(jìn)行修改
ARCH ?= arm
CROSS_COMPILE ?=arm-linux-
$$(srctree)/arch/$(SRCARCH)/Makefile對內(nèi)核的內(nèi)容進(jìn)行了擴(kuò)充
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,它還有一個特殊的地方,它是直接對應(yīng)著兩個文件,而不是目錄。之所以分成兩個是為了同時支持有無MMU的CPU,它們對應(yīng)著兩個不同的head$(MMUEXT).o 文件,由變量MMUEXT控制,可以在配置時設(shè)定。
至此我們知道了編譯時將進(jìn)入哪些文件進(jìn)行編譯。編譯時依次進(jìn)入init-y、core-y、libs-y、drivers-y、net-y中列的目錄調(diào)用其中的Makefile進(jìn)行編譯,每一個子目錄都會生成build-in.o(libs-y所列的目錄下有可能生成lib.a)。最后head-y列出的文件和build-in.o、lib.a一起連接成vmlinux。
在配置內(nèi)核時,將會產(chǎn)生.config文件,Makefile將會在.config文件中添加下面兩行。
CONFIG_KERNELVERSION = "2.6.32.2"
CONFIG_ARCH = "arm"
有可能是版本原因,在2.6.32.2版本中并沒有上面兩個語句,有下面兩句。
#Linux kernel version = 2.6.32.2
CONFIG_ARM = y
觀察.config文件會發(fā)現(xiàn)變量的值主要有兩種y、m,各級的Makefile將會根據(jù)這些變量的值來決定編譯哪些文件,同時是編譯進(jìn)內(nèi)核,還是作為內(nèi)核模塊存在。
obj-y中定義的.o文件將由當(dāng)前目錄下的.c、.S文件及子目錄下的build-in.o文件編譯連接得到的。
注意:obj-y中定義的.o文件的順序是由意義的。
下面是一段取自子目錄中的Makefile文件內(nèi)容,在該目錄下有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文件是由的當(dāng)前目錄下的.c、.S文件編譯生成,它們不會與build-in.o一起編譯進(jìn)入內(nèi)核。而是被編譯成.ko文件,作為模塊存在。
當(dāng).o文件由單文件編譯而成時,用下面的語句:
obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
當(dāng).o文件由多文件編譯而成時,用下面的語句:
obj-$(CONFIG_ISDN) +=isdn.o
isdn-objs := isdn_net_lib.o isdn_v110.o isdn_commen.o
編寫驅(qū)動程序時,也是以這種方式編寫Makefile。
lib-y中定義的.o文件是由的當(dāng)前目錄下的.c、.S文件編譯生成,他們被打包成當(dāng)前目錄下的lib.a文件。同時出現(xiàn)在lib-y和obj-y中的文件,不會被包含進(jìn)lib.a文件。
obj-y和obj-m可以用來指定進(jìn)入下一級目錄。
(3)怎么編譯這些文件
怎么編譯文件就是意味著編譯選項(xiàng)和連接選項(xiàng)是什么。
這些選項(xiàng)分成3類:全局的(適用整個代碼樹)、局部的(適用單個Makefile)、個體的(適用單個文件)。
全局選項(xiàng)是在頂層Makefile和arch/$(ARCH)/Makefile中定義的,這些選項(xiàng)是CFLAGS、AFLAGS、LDFLAGS、ARFLAGS,它們分別是編譯C文件的選項(xiàng),編譯匯編文件的選項(xiàng),連接文件的選項(xiàng),制作庫文件的選項(xiàng)。
局部選項(xiàng)在各自子目錄中定義,名稱為:EXTRA_CFLAGS、EXTRA_AFALGS、EXTRA_LDFALGS、EXTRA_ARFLAGS.
對單文件設(shè)定編譯選項(xiàng),可以用CLFAGS_$@、AFLAGS_$@,前者對C文件,后者對匯編文件。
注意:3類選項(xiàng)是一起使用的,在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)
可以看出以后的連接是相當(dāng)于著五種built-in.o文件和head-o文件的連接。
之后對這些文件再次進(jìn)行合并
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(假設(shè)有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生成。
具體連接細(xì)節(jié)可以查看上面的文件內(nèi)容。
三,內(nèi)核的Kconfig分析
內(nèi)核配置工具讀取各個Kconfig文件,生成配置界面共開放人員配置內(nèi)核,最后生成配置文件.config。
關(guān)于Kconfig的最權(quán)威資料在/Documentations/Kbuild/kconfig-language.txt
Kconfig語法分析:
- Kconfig的基本要素:config ;config經(jīng)常被其它條目包含,用來生成菜單和多項(xiàng)選擇。
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
在配置界面中配置了該選項(xiàng)后,會在.config中出現(xiàn) CONFIG_JFFS2_FS_WBUF_VERIFY = y或者m.
bool "Verify JFFS2 write-buffer reads"
在配置界面中將會顯示Verify JFFS2 write-buffer reads選項(xiàng),bool是變量的類型,一共有5種變量類型:bool、tristate、 string 、hex 、int,bool變量有兩種取值y,m;tristate變量有三種取值y,m,n;string可以取字符串;hex取十六進(jìn)制數(shù);int取十進(jìn)制數(shù)。
depends on JFFS2_FS_WRITEBUFFER
代表只有在JFFS2_FS_WRITEBUFFER被配置時,才會進(jìn)行該選項(xiàng)的配置。
default n
代表默認(rèn)的情況下是選擇n
select FS_POSIX_ACL
代表在該選項(xiàng)被選種時,會將FS_POSIX_ACL也選種。
help
This causes JFFS2 to read back every page written through the
write-buffer, and check for errors.
當(dāng)在配置時按H時會顯示該信息。
menu條目
配置界面的主界面是由根目錄下Makefile中ARCH配置決定的,當(dāng)選擇arm時,/arch/arm中的Kconfig文件將會用來生成主目錄。
下面的內(nèi)容摘自/arch/arm/Kconfig
mainmenu "Linux Kernel Configuration"
設(shè)定主目錄的名稱
menu "System Type"
將會創(chuàng)建System Type子目錄
choice條目
choice將多個類似的配置選項(xiàng)組合在一起,供用戶多選和單選
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 split"
endchoice
prompt "Memory split"
上述代碼給出提示信息,選中之后就可以進(jìn)行選擇配置
choice條目中定義的變量類型只能是bool和tristate,當(dāng)配置的代碼編譯入內(nèi)核時為bool,只能有一個條目選擇為y;當(dāng)編譯成模塊時為tristate或bool,為bool時,也只能是一個為y,當(dāng)為tristate時,可以有多個m。
comment條目
comment條目用于提供幫助信息,出現(xiàn)在配置界面的第一行。
comment "At least one emulation must be selected"
source條目
用于包含其他Kconfig文件
source "drivers/cpuidle/Kconfig"
菜單形式的配置界面的操作方法
配置界面中[*]、< M >、[ ]分別表示相應(yīng)的文件被編譯進(jìn)內(nèi)核、編譯成模塊、沒有被編譯。
Load an Alertnate Configuration File
Save an Alertnate Configuration File
當(dāng)執(zhí)行第一條語句時,將.config外的config文件加載,當(dāng)執(zhí)行第二條時,表示存儲成處.config 外的config文件。
四,Linux內(nèi)核配置選項(xiàng)
與移植密切相關(guān)的內(nèi)容是System Type、Device Driver。
內(nèi)核配置主界面內(nèi)容
- code maturity level options:代碼成熟度選項(xiàng),包含一些正在開發(fā)的或者不成熟的代碼和驅(qū)動程序,一般不用設(shè)置
- General setup:常規(guī)設(shè)置,比如增加附加的內(nèi)核版本號、支持內(nèi)存頁交換功能、System V進(jìn)程間通信等。除非很熟悉其中的內(nèi)容,否則一般使用默認(rèn)配置
- Loadable module support:可加載模塊支持:一般都會打開可加載模塊支持(Enable loadable module support )、允許卸載已經(jīng)加載的模塊(Module unloading)、讓內(nèi)核通過運(yùn)行modprobe來自動加載模塊(Automatic kernel module loading)
- block layer:塊設(shè)備層:用于設(shè)置塊設(shè)備的一些總體參數(shù),比如是否支持大于2TB的塊設(shè)備、是否支持大于2TB的文件、設(shè)置IO調(diào)度器,使用默認(rèn)值即可
- System Type:系統(tǒng)類型:選擇CPU的架構(gòu)、開發(fā)板類型等于開發(fā)板相關(guān)的配置選項(xiàng)
- Bus support:PCMCIA 、CardBus總線的支持,對于ARM開發(fā)板不需要設(shè)置
- Kernel Feature :用于設(shè)置內(nèi)核的一些參數(shù),比如是否支持內(nèi)核搶占,是否支持動態(tài)修改系統(tǒng)時鐘
- Boot option:啟動參數(shù):比如設(shè)置默認(rèn)的命令行參數(shù)等,一般不用理會
- Floating point emulation:浮點(diǎn)運(yùn)算仿真功能:因?yàn)長inux內(nèi)核不支持硬件浮點(diǎn)運(yùn)算,所以要選擇一個浮點(diǎn)仿真器,一般選擇”NWFPE math emulaiton”
- Userspace binary formats:可執(zhí)行文件格式:一般都選擇ELF、a.out格式
- Power management options:電源管理選項(xiàng)
- Networking:網(wǎng)絡(luò)協(xié)議選項(xiàng):一般都選擇”Networking support“以支持網(wǎng)絡(luò)功能。通??梢栽谶x擇”Networking support“后,使用默認(rèn)配置
- Device Driver:設(shè)備驅(qū)動程序:幾乎包含了Linux的所有的驅(qū)動程序
- File systems:文件系統(tǒng):選擇支持的文件系統(tǒng)
- Profiling support:對系統(tǒng)的或頂進(jìn)行分析,僅供內(nèi)核開發(fā)者使用
- Kernel hacking:調(diào)試內(nèi)核時的各種選項(xiàng):Linux設(shè)備驅(qū)動程序中有詳細(xì)描述
- security options:安全選項(xiàng):一般使用默認(rèn)選項(xiàng)
- Cryptographic options:加密選項(xiàng)
- Library routines:庫子程序:比如CRC32檢驗(yàn)函數(shù)、zlib壓縮函數(shù)等。不包含在內(nèi)核源碼中的第三方內(nèi)核模塊可能需要這些庫,可以全不全,內(nèi)核中若有其他部分依賴它,會自動選項(xiàng)
在配置內(nèi)核的時候按照順序進(jìn)行,因?yàn)榍懊娴呐渲脮绊懞竺娴摹?/p>
審核編輯:湯梓紅
-
內(nèi)核
+關(guān)注
關(guān)注
3文章
1336瀏覽量
40083 -
Linux
+關(guān)注
關(guān)注
87文章
11123瀏覽量
207895 -
源碼
+關(guān)注
關(guān)注
8文章
626瀏覽量
28965
發(fā)布評論請先 登錄
相關(guān)推薦
評論