《嵌入式Linux開(kāi)發(fā)技術(shù)及實(shí)踐》課件第4章_第1頁(yè)
《嵌入式Linux開(kāi)發(fā)技術(shù)及實(shí)踐》課件第4章_第2頁(yè)
《嵌入式Linux開(kāi)發(fā)技術(shù)及實(shí)踐》課件第4章_第3頁(yè)
《嵌入式Linux開(kāi)發(fā)技術(shù)及實(shí)踐》課件第4章_第4頁(yè)
《嵌入式Linux開(kāi)發(fā)技術(shù)及實(shí)踐》課件第4章_第5頁(yè)
已閱讀5頁(yè),還剩144頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第4章系統(tǒng)構(gòu)建4.1概述

4.2交叉編譯環(huán)境4.3Linux內(nèi)核

4.4內(nèi)核編譯配置

4.5內(nèi)核移植 4.6構(gòu)建根文件系統(tǒng)

4.7Linux內(nèi)核啟動(dòng)分析4.1概述

一個(gè)完整的嵌入式Linux系統(tǒng)包括四個(gè)主要的軟件層:Bootloader、Linux內(nèi)核、根文件系統(tǒng)和應(yīng)用程序。

1)?Bootloader

Bootloader是系統(tǒng)上電復(fù)位后執(zhí)行的第一段代碼,除了進(jìn)行硬件資源的初始化以及建立內(nèi)存空間的映射功能外,它還有一個(gè)最主要的功能就是加載Linux內(nèi)核,即把內(nèi)核從外部存儲(chǔ)器復(fù)制到內(nèi)存中并跳到內(nèi)核入口處執(zhí)行,從而開(kāi)啟了Linux操作系統(tǒng)的運(yùn)行。

2)?Linux內(nèi)核一旦內(nèi)核開(kāi)始執(zhí)行,它將通過(guò)驅(qū)動(dòng)程序初始化所有硬件,初始化完成后,內(nèi)核掛載某個(gè)文件系統(tǒng)作為根文件系統(tǒng),這樣便進(jìn)入了嵌入式應(yīng)用階段。Linux內(nèi)核資源比較多,用戶可根據(jù)所選用的處理器來(lái)進(jìn)行適當(dāng)?shù)牟眉艉驼{(diào)整,以使其適用自己的開(kāi)發(fā)板系統(tǒng)。

3)根文件系統(tǒng)根文件系統(tǒng)是Linux系統(tǒng)的核心部分,做為系統(tǒng)文件和數(shù)據(jù)的存儲(chǔ)區(qū)域,包含了Linux系統(tǒng)正常運(yùn)行時(shí)所需要的最基本內(nèi)容,例如系統(tǒng)使用的軟件命令、庫(kù)文件以及嵌入式系統(tǒng)基本的配置文件。用戶也可根據(jù)需要進(jìn)行根文件系統(tǒng)制作,在滿足系統(tǒng)基本性能要求的基礎(chǔ)上精簡(jiǎn)系統(tǒng),盡可能地減少不必要的資源浪費(fèi)。

4)應(yīng)用程序此處所指的應(yīng)用程序是指用戶基于特定應(yīng)用開(kāi)發(fā)的程序,可以說(shuō)是嵌入式系統(tǒng)開(kāi)發(fā)的主要工作。前面三個(gè)軟件層都是為了應(yīng)用程序的成功運(yùn)行所做的鋪墊,應(yīng)用程序所實(shí)現(xiàn)的功能是嵌入式Linux系統(tǒng)開(kāi)發(fā)的最終目標(biāo)。本章所描述的嵌入式Linux系統(tǒng)的構(gòu)建主要是對(duì)Linux內(nèi)核和根文件系統(tǒng)的定制過(guò)程。在此之前首先要介紹交叉編譯環(huán)境的搭建過(guò)程。

4.2交叉編譯環(huán)境

所謂交叉編譯,就是指在一個(gè)平臺(tái)上(如X86架構(gòu))生成可以在另一個(gè)平臺(tái)(如ARM架構(gòu))上執(zhí)行的代碼。通常,將交叉編譯環(huán)境建立在PC上,運(yùn)行環(huán)境設(shè)定在開(kāi)發(fā)板上,這種情況下PC被稱(chēng)為宿主機(jī),開(kāi)發(fā)板被稱(chēng)為目標(biāo)機(jī)。

arm-linux-gcc作為基于ARM平臺(tái)的編譯器,其編譯出來(lái)的程序可以在ARM平臺(tái)上直接運(yùn)行。本書(shū)編譯內(nèi)核及文件系統(tǒng)所采用的交叉編譯器均為arm-linux-gcc-3.4.5,本節(jié)將以此為例,介紹交叉環(huán)境的搭建。

下述內(nèi)容用于實(shí)現(xiàn)任務(wù)描述4.D.1——搭建arm-linux-gcc交叉編譯環(huán)境。具體步驟如下:

1.解壓縮arm-linux-gcc-3.4.5.tar.gz將arm-linux-gcc-3.4.5.tar.gz解壓縮到“/usr/arm-linux-gcc”目錄下,具體操作如圖4-1所示。

圖4-1解壓縮arm-linux-gcc-3.4.5.tar.gz

2.將arm-linux-gcc加入系統(tǒng)命令路徑將arm-linux-gcc命令的存儲(chǔ)路徑追加賦值給環(huán)境變量PATH,以便arm-linux-gcc能被系統(tǒng)所調(diào)用,具體操作如圖4-2所示。

圖4-2arm-linux-gcc命令加入系統(tǒng)命令路徑

3.將arm-linux-gcc開(kāi)機(jī)后自動(dòng)加入系統(tǒng)命令路徑編輯“/etc/profile”文件,添加將arm-linux-gcc存儲(chǔ)路徑追加賦值給系統(tǒng)環(huán)境變量PATH的命令,實(shí)現(xiàn)開(kāi)機(jī)自動(dòng)加載arm-linux-gcc命令的要求,具體操作如圖4-3所示。

圖4-3修改profile實(shí)現(xiàn)arm-linux-gcc開(kāi)機(jī)自動(dòng)加入系統(tǒng)命令路徑4.3Linux內(nèi)核

Linux內(nèi)核在內(nèi)核官方網(wǎng)站上發(fā)布。表4-1列出了Linux內(nèi)核的部分重要發(fā)展事件

表4-1Linux內(nèi)核的重要發(fā)展事件

Linux的版本有一定的命名規(guī)則。通常來(lái)說(shuō),Linux內(nèi)核版本由下列形式組成:

VERSION.PATCHLEVEL.SUBLEVEL.EXTRAVERSION。其中:

VERSION為主版本號(hào),有結(jié)構(gòu)性變化時(shí)才會(huì)更改。

PATCHLEVEL為此版本號(hào),有新增功能時(shí)會(huì)改變,偶數(shù)為穩(wěn)定版,奇數(shù)為測(cè)試版。

SUBLEVEL為版本修訂號(hào),表示對(duì)此版本的修訂次數(shù)或補(bǔ)丁包數(shù)。

EXTRAVERSION為擴(kuò)展版本號(hào),此版本修訂最新穩(wěn)定版本出現(xiàn)的問(wèn)題。本書(shū)中所采用的內(nèi)核版本為linux-2.6.22,版本號(hào)可以從內(nèi)核源碼根目錄下的Makefile文件看到,如圖4-4所示。

圖4-4Makefile文件中的Linux版本說(shuō)明

4.3.1Linux內(nèi)核特點(diǎn)

Linux系統(tǒng)作為在嵌入式開(kāi)發(fā)領(lǐng)域首選的操作系統(tǒng),有著以下非常顯著的特點(diǎn):

可移植性。這是Linux系統(tǒng)最重要的特點(diǎn),Linux用戶可以根據(jù)系統(tǒng)開(kāi)發(fā)的需求定制自己的Linux內(nèi)核,使操作系統(tǒng)小而精練。

支持多種體系結(jié)構(gòu)。Linux內(nèi)核支持的硬件平臺(tái)非常廣泛,大多數(shù)體系結(jié)構(gòu)的處理器均可在Linux系統(tǒng)上運(yùn)行,例如32位處理器體系結(jié)構(gòu)或64位處理器體系結(jié)構(gòu),處理器帶MMU或不帶MMU。

開(kāi)源性。Linux內(nèi)核全部源碼遵守GPL協(xié)議,所有源碼均可在官方網(wǎng)站上免費(fèi)獲取,因此節(jié)省了開(kāi)發(fā)成本,提高了開(kāi)發(fā)效率。

4.3.2內(nèi)核結(jié)構(gòu)在Linux-2.6.22目錄下,可以看到Linux內(nèi)核源碼的組成,如圖4-5所示。Linux內(nèi)核源碼文件數(shù)目達(dá)到2萬(wàn)多個(gè),但是都有條理地位于各目錄中,這些目錄組織結(jié)構(gòu)非常嚴(yán)謹(jǐn),并且每個(gè)目錄都有不同的作用。

圖4-5Linux內(nèi)核源碼結(jié)構(gòu)圖

各目錄所存放文件的內(nèi)容如下:

arch:包含和硬件體系結(jié)構(gòu)相關(guān)的代碼,每個(gè)架構(gòu)的CPU在arch目錄下都有一個(gè)相應(yīng)的子目錄,例如“arch/arm/”、“arch/i386/”等。

block:塊設(shè)備通用函數(shù)。

crypto:常用加密和散列算法,還有一些壓縮和CRC校驗(yàn)算法。

Documentation:關(guān)于內(nèi)核各部分的通用解釋和注釋。

drivers:設(shè)備驅(qū)動(dòng)程序,每個(gè)不同的驅(qū)動(dòng)都占用一個(gè)子目錄,例如“drivers/block”為塊設(shè)備驅(qū)動(dòng)程序,“drivers/char”為字符設(shè)備驅(qū)動(dòng)程序。

fs:所支持的文件系統(tǒng)。每種文件系統(tǒng)對(duì)應(yīng)一個(gè)子目錄,例如“fs/ext2”、“fs/jffs2”等。

include:內(nèi)核頭文件。例如,和系統(tǒng)相關(guān)的頭文件被放置在“include/linux”子目錄下,和ARM體系結(jié)構(gòu)相關(guān)的頭文件被放置在“include/asm-arm/”子目錄下。

init:內(nèi)核初始化代碼,其中main.c文件中的start_kernel函數(shù)是內(nèi)核引導(dǎo)后運(yùn)行的。

ipc:進(jìn)程間通信的代碼。

kernel:內(nèi)核的最核心部分代碼,包括進(jìn)程管理、進(jìn)程調(diào)度、中斷處理器等。和處理器平臺(tái)相關(guān)的一部分代碼放在“arch/*/kernel”目錄下。

lib:內(nèi)核用到的庫(kù)函數(shù)代碼。和處理器相關(guān)的庫(kù)函數(shù)代碼位于“arch/*/lib”下。

mm:內(nèi)存管理代碼。和處理器平臺(tái)相關(guān)的內(nèi)存管理代碼放在“arch/*/mm”目錄下。

net:網(wǎng)絡(luò)相關(guān)代碼,實(shí)現(xiàn)了各種常見(jiàn)的網(wǎng)絡(luò)協(xié)議。

scripts:用于配置、編譯內(nèi)核的腳本文件。

security:與安全、密鑰相關(guān)的代碼。

sound:常用音頻設(shè)備的驅(qū)動(dòng)程序。

usr:用戶代碼,用來(lái)制作initrd的鏡像,作為內(nèi)核啟動(dòng)后掛接的第一個(gè)文件系統(tǒng)。除了各個(gè)源碼子目錄以外,內(nèi)核根目錄下還包含了配置編譯文件和內(nèi)核說(shuō)明文檔。其中:

Makefile、Konfig:配置、編譯內(nèi)核所必須用到的文件。

README:對(duì)內(nèi)核目錄的一些說(shuō)明和配置編譯內(nèi)核的簡(jiǎn)單介紹。

COPYING:GPL版權(quán)說(shuō)明。

CREDITS:對(duì)Linux做出很大貢獻(xiàn)的開(kāi)發(fā)者信息。

MAINTARINERS:此版本內(nèi)核維護(hù)人員列表。

REPORTING-BUGS:此版本內(nèi)核有關(guān)BUG的內(nèi)容。另外在內(nèi)核的每個(gè)子目錄下,都有一個(gè)Makefile和readme文件,要想對(duì)內(nèi)核源碼有更好的了解,應(yīng)仔細(xì)閱讀這兩個(gè)文件。4.4內(nèi)核編譯配置

Linux內(nèi)核中各目錄下的文件均為源程序,若想移植到嵌入式系統(tǒng)的開(kāi)發(fā)板中,必須經(jīng)過(guò)配置、編譯鏈接的過(guò)程形成可執(zhí)行的Linux內(nèi)核二進(jìn)制文件。編譯內(nèi)核之前,用戶需要對(duì)內(nèi)核完成必要的配置。

Linux內(nèi)核源碼提供了一套內(nèi)核配置系統(tǒng),能夠?qū)?nèi)核支持的多種體系結(jié)構(gòu)以及各種各樣的驅(qū)動(dòng)程序等源碼形成內(nèi)核配置菜單選項(xiàng)。內(nèi)核配置系統(tǒng)由以下三部分組成:

配置工具:包括配置命令以及用戶“配置界面”。

Makefile:分布在內(nèi)核源碼中,定義了Linux的編譯規(guī)則。

配置文件Kconfig:存在于內(nèi)核的各級(jí)目錄中,用戶選擇的一些“配置選項(xiàng)”最終在這些文件中形成。

4.4.1配置工具不同的內(nèi)核配置方式,需要不同的配置工具來(lái)完成,scripts目錄下提供了各種內(nèi)核配置工具。下面詳細(xì)介紹幾種配置工具的使用方法。

makeconfig:字符界面配置方式。這種配置方式會(huì)依次遍歷內(nèi)核所有的配置項(xiàng),要求用戶逐個(gè)回答內(nèi)核中上千個(gè)配置選項(xiàng)提示。該工具會(huì)耗費(fèi)用戶太多的時(shí)間,一般不建議使用。

makemenuconfig:基于光標(biāo)菜單配置方式,在配置選項(xiàng)時(shí),只需要移動(dòng)光標(biāo)進(jìn)行選項(xiàng)的選擇即可,使用比較簡(jiǎn)單。本書(shū)基于此種方式進(jìn)行內(nèi)核配置。makexconfig:基于QT圖形界面方式。當(dāng)用戶使用這個(gè)工具對(duì)Linux內(nèi)核進(jìn)行配置時(shí),界面下方會(huì)出現(xiàn)與這個(gè)配置項(xiàng)相關(guān)的幫助信息和簡(jiǎn)單描述。

4.4.2內(nèi)核Makefile

Linux內(nèi)核是根據(jù)其根目錄下Makefile進(jìn)行編譯的,“Documentation/kbuild/Makefile.txt”文件詳細(xì)描述了內(nèi)核Makefile的作用及用法。

1.概述

Linux內(nèi)核源碼中含有多個(gè)Makefile,分布在內(nèi)核的各級(jí)目錄中。Linux內(nèi)核中的Makefile以及相關(guān)的文件組成如下:

頂層Makefile,是整個(gè)內(nèi)核配置、編譯的總體控制文件。通過(guò)讀取配置文件.config,遞歸編譯內(nèi)核代碼樹(shù)的相關(guān)目錄。

處理器相關(guān)Makefile,位于arch/$(ARCH)目錄下,為頂層Makefile提供與具體硬件體系結(jié)構(gòu)相關(guān)的信息。例如在本書(shū)中$(ARCH)=ARM。

其他Makefile,主要為整個(gè)Makefile體系提供各自模塊的目標(biāo)文件定義,上層Makefile根據(jù)它所定義的目標(biāo)來(lái)完成各自模塊的編譯。

公共編譯規(guī)則文件,由Makefile.build、Makefile.clean、Makefile.lib等文件組成,位于scripts目錄中,定義了編譯所需要的規(guī)則和定義。

內(nèi)核配置文件.config,通過(guò)調(diào)用makemenuconfig等命令,用戶可以選擇需要的配置來(lái)生成相應(yīng)的目標(biāo)文件。

2.頂層Makefile

Linux內(nèi)核的配置編譯是由頂層目錄的Makefile整體管理的。

1)指定體系結(jié)構(gòu)與編譯器

Makefile文件通過(guò)ARCH變量和CROSS_COMPILE變量指定體系結(jié)構(gòu)和編譯器,相關(guān)代碼如下。

【代碼4-1】Makefile

//指定體系結(jié)構(gòu)與交叉編譯器

ARCH ?=

CROSS_COMPILE ?=

#Architectureaspresentincompile.h

UTS_MACHINE:=$(ARCH)

//默認(rèn)配置文件.configKCONFIG_CONFIG ?=.config本書(shū)所用體系結(jié)構(gòu)為arm,交叉編譯器為arm-linux-,因此可做如下修改?!臼纠?-1】指定體系結(jié)構(gòu)與編譯器ARCH ?=armCROSS_COMPILE ?=arm-linux-

2)決定內(nèi)核根目錄下將被編譯進(jìn)內(nèi)核的子目錄除了由ARCH指定與體系結(jié)構(gòu)相關(guān)的子目錄外,頂層Makefile還指定通用目錄列表。根據(jù)配置文件,這些目錄中的相關(guān)文件將被編譯進(jìn)內(nèi)核。通用目錄列表包括:head-y、init-y、drivers-y、net-y、libs-y和core-y,相關(guān)代碼如下。

【代碼4-2】Makefile

init-y :=init/

drivers-y :=drivers/sound/

net-y :=net/

libs-y :=lib/

core-y :=usr/

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/$(ARCH)/kernel/vmlinux.ldsexportKBUILD_VMLINUX_OBJS:=$(vmlinux-all)

4.4.3配置文件Kconfig

Kconfig用來(lái)配置內(nèi)核,也就是用來(lái)生成各種配置界面的源文件。配置內(nèi)核的主Kconfig文件為“arch/$(ARCH)/Kconfig”文件。內(nèi)核的配置工具先讀取主Kconfig文件來(lái)生成主配置界面,此為所有配置文件的總?cè)肟?,然后主Kconfig文件調(diào)用其他目錄中的Kconfig文件,依次遞歸生成各個(gè)配置界面供用戶配置內(nèi)核,最后生成配置文件“.config”。

1.關(guān)鍵字

Kconfig配置文件描述了菜單選項(xiàng),每行都以一個(gè)關(guān)鍵字開(kāi)頭。Kconfig中使用的關(guān)鍵字以及關(guān)鍵字的用法如表4-2所示。

表4-2Kconfig菜單關(guān)鍵字

2.?config

config是Kconfig文件中最基本的要素,用來(lái)生成配置菜單選項(xiàng)或者進(jìn)行多項(xiàng)選擇等。config也可以用于生成一個(gè)變量,這個(gè)變量以及變量值會(huì)被寫(xiě)入配置文件“.config”中,作為用戶配置內(nèi)核時(shí)的選項(xiàng)選擇。config語(yǔ)法為:

"config"<symbol>

<configoptions>其中:

symbol為一個(gè)新的菜單項(xiàng)。

option為新菜單的屬性和選項(xiàng),由變量類(lèi)型、依賴(lài)關(guān)系、默認(rèn)值以及幫助等組成。

變量類(lèi)型。config選項(xiàng)有5種變量類(lèi)型,即bool類(lèi)型、tristate類(lèi)型、string字符串、hex十六進(jìn)制、integer整型。其中tristate類(lèi)型和string類(lèi)型為基本類(lèi)型。bool取值只有兩種,即y和n。tristate變量有三種形式,即y、n和m。tristate取值為y時(shí),對(duì)應(yīng)的文件被編進(jìn)內(nèi)核;取值為m時(shí),對(duì)應(yīng)的文件被編成模塊;取值為n時(shí),對(duì)應(yīng)的文件沒(méi)有被使用。

依賴(lài)關(guān)系,用dependson表示,每個(gè)選項(xiàng)都有其自己的依賴(lài)關(guān)系。這些依賴(lài)關(guān)系決定了選項(xiàng)是否是可見(jiàn)的,只有父選項(xiàng)可見(jiàn)時(shí),子選項(xiàng)才可見(jiàn)。

默認(rèn)值由關(guān)鍵字default指定,若用戶沒(méi)有對(duì)配置選項(xiàng)進(jìn)行更改,則執(zhí)行默認(rèn)操作。

幫助,用關(guān)鍵字help或者h(yuǎn)elp表示。當(dāng)遇到一行的縮進(jìn)比第一行的縮進(jìn)距離小時(shí),表示幫助信息結(jié)束。一個(gè)典型的config示例如圖4-6所示,用于配置CONFIG_JFFS2_FS_?POSIX_ACL選項(xiàng)。源碼位于“fs/Kconfig”。

圖4-6config示例

此段代碼包含了一個(gè)配置菜單選項(xiàng)所有的元素,說(shuō)明如下:

(1)代碼1269行config為關(guān)鍵字,表示一個(gè)配置選項(xiàng)開(kāi)始,選項(xiàng)名稱(chēng)為CONFIG_JFFS2_FS_POSIX_ACL。

(2)代碼1270行說(shuō)明配置選項(xiàng)類(lèi)型為“bool”類(lèi)型?!癑FFS2POSIXAccessControlLists”字符串為提示信息,在配置界面中可通過(guò)光標(biāo)選中。

(3)代碼1271行為依賴(lài)關(guān)系,表明只有JFFS2_FS_XATTR選項(xiàng)被選中時(shí),此選項(xiàng)才會(huì)在界面出現(xiàn)。

(4)代碼1272行表示此選項(xiàng)默認(rèn)為“y”。

(5)代碼1274~1280行為幫助信息,當(dāng)遇到一行的縮進(jìn)比第一行的縮進(jìn)距離小時(shí),表示幫助信息結(jié)束。

4.4.4配置選項(xiàng)在命令行下執(zhí)行makemenuconfig后,將出現(xiàn)內(nèi)核配置主界面,如圖4-7所示。配置主界面為樹(shù)狀菜單形式組織,主菜單下面有若干子菜單,子菜單下面又有若干配置選項(xiàng),每個(gè)子菜單或配置選項(xiàng)根據(jù)它們是否存在依賴(lài)關(guān)系而決定其是否顯示在配置界面上。

圖4-7菜單形式的內(nèi)核配置主界面

1.配置使用方法配置界面上方為此形式的內(nèi)核配置方法,使用方法如下:

按【上/下】鍵高亮選中配置選項(xiàng),按回車(chē)鍵進(jìn)入。進(jìn)入配置選項(xiàng)也可以通過(guò)使用熱鍵選擇,在配置選項(xiàng)的名稱(chēng)中有一個(gè)高亮字母,直接在配置界面輸入此字母即可。

按【左/右】鍵選擇<Exit>按鈕,再按回車(chē)鍵退出配置界面,或者按【Esc】鍵退出。

按【Tab】鍵可以在<Select>、<Exit>和<Help>按鈕中循環(huán)選中。

要修改配置選項(xiàng),先高亮選中該選項(xiàng),按【Y】鍵將選項(xiàng)編譯進(jìn)內(nèi)核,對(duì)應(yīng)顯示為“*”;按【M】鍵將選項(xiàng)編譯為模塊,對(duì)應(yīng)顯示為“M”;按【N】鍵將不使用此選項(xiàng),對(duì)應(yīng)顯示為“”。也可以用【空格】鍵循環(huán)選擇。

2.配置選項(xiàng)說(shuō)明本節(jié)以主菜單選項(xiàng)與子菜單DeviceDrivers選項(xiàng)為例進(jìn)行說(shuō)明。Linux內(nèi)核配置主菜單的選項(xiàng)說(shuō)明如表4-3所示。

表4-3Linux內(nèi)核配置主菜單選項(xiàng)說(shuō)明

Linux內(nèi)核配置DeviceDrivers菜單選項(xiàng)說(shuō)明如表4-4所示,所有的硬件驅(qū)動(dòng)程序都能在本菜單目錄中被配置進(jìn)內(nèi)核。

表4-4Linux內(nèi)核設(shè)備驅(qū)動(dòng)配置菜單說(shuō)明

Linux內(nèi)核中的配置選項(xiàng)眾多,因篇幅有限,本節(jié)中只列出了內(nèi)核主配置菜單與設(shè)備驅(qū)動(dòng)程序配置菜單,若想對(duì)內(nèi)核配置選項(xiàng)有更多的了解,可以參考網(wǎng)上的相關(guān)資料。4.5內(nèi)核移植

所謂內(nèi)核移植就是將內(nèi)核從一個(gè)硬件平臺(tái)轉(zhuǎn)移到另外一個(gè)硬件平臺(tái)上運(yùn)行。一般是從一個(gè)與開(kāi)發(fā)板相匹配的Linux內(nèi)核開(kāi)始,進(jìn)行適當(dāng)?shù)牟眉艋蛟黾?。在嵌入式Linux系統(tǒng)開(kāi)發(fā)中,在用戶的硬件系統(tǒng)中,CPU和其運(yùn)行的硬件平臺(tái)都是根據(jù)項(xiàng)目的特定需求來(lái)進(jìn)行開(kāi)發(fā)的,例如本書(shū)中所用的CPU為ARM9系列S3C2440,開(kāi)發(fā)板為根據(jù)項(xiàng)目需求而進(jìn)行設(shè)計(jì)的。有關(guān)arm體系結(jié)構(gòu)的目標(biāo)板硬件平臺(tái)的數(shù)據(jù)結(jié)構(gòu)定義在“include/asm-arm/mach/arch.h”文件中,代碼如下所示。

【代碼4-3】arch.h/**linux/include/asm-arm/mach/arch.h*#ifndef__ASSEMBLY__structtag;structmeminfo;structsys_timer;structmachine_desc{

/* *Note!Thefirstfourelementsareused *byassemblercodeinhead-armv.S */ unsignedint nr; /*architecturenumber */ unsignedint phys_io; /*startofphysicalio */ unsignedint io_pg_offst; /*byteoffsetforio*pagetabeentry */

constchar *name; /*architecturename */ unsignedlong boot_params; /*taggedlist */ unsignedint video_start; /*startofvideoRAM */ unsignedint video_end; /*endofvideoRAM */ unsignedint reserve_lp0:1; /*neverhaslp0 */ unsignedint reserve_lp1:1; /*neverhaslp1 */

unsignedint reserve_lp2:1;/*neverhaslp2 */ unsignedint soft_reboot:1; /*softreboot */ void (*fixup)(structmachine_desc*,

structtag*,char**,

structmeminfo*);

void (*map_io)(void); /*IOmappingfunction */ void (*init_irq)(void);

structsys_timer *timer; /*systemticktimer */

void (*init_machine)(void);

};/**Setofmacrostodefinearchitecturefeatures.Thisisbuiltinto*atablebythelinker.*/#defineMACHINE_START(_type,_name) \staticconststructmachine_desc__mach_desc_##_type \__used

\__attribute__((__section__("..init")))={ \ .nr =MACH_TYPE_##_type, \ .name =_name,#defineMACHINE_END \};#endif;其中,結(jié)構(gòu)體machine_desc描述了目標(biāo)板的硬件平臺(tái),包括系統(tǒng)平臺(tái)號(hào)(nr)、I/O起始物理地址(phys_io)、系統(tǒng)平臺(tái)名稱(chēng)(*name)、啟動(dòng)參數(shù)(boot_params)以及初始化函數(shù)指針等變量。有關(guān)smdk2440參考板的定義在“arch/arm/mach-s3c2440/mach-smdk2440.c”中,代碼如下所示。

【代碼4-4】mach-smdk2440.cMACHINE_START(S3C2440,"SMDK2440") /*Maintainer:BenDooks<ben@>*/ .phys_io =S3C2410_PA_UART,

.io_pg_offst =(((u32)S3C24XX_VA_UART)>>18)&0xfffc,

.boot_params =S3C2410_SDRAM_PA+0x100,

.init_irq =s3c24xx_init_irq,

.map_io =smdk2440_map_io,

.init_machine =smdk2440_machine_init,

.timer =&s3c24xx_timer,MACHINE_END結(jié)合arch.h可知,smdk2440目標(biāo)板的系統(tǒng)平臺(tái)號(hào)為S3C2440,系統(tǒng)平臺(tái)名稱(chēng)為SMDK2440。

4.5.1移植示例下述內(nèi)容用于實(shí)現(xiàn)任務(wù)描述4.D.2——根據(jù)目標(biāo)板硬件資源移植內(nèi)核。其實(shí)現(xiàn)步驟如下:

1.選取參考板本書(shū)所用Linux內(nèi)核為L(zhǎng)inux-2.6.22,開(kāi)發(fā)板CPU是基于ARM9系列的S3C2440。Linux-2.6.22內(nèi)核已經(jīng)對(duì)S3C2410有多種硬件平臺(tái)基本的支持,如SMDK2410、SMDK2440等。S3C2440與S3C2410差別不大,本書(shū)選取SMDK2440為內(nèi)核移植的參考平臺(tái)。

2.選擇交叉編譯器為了確保編譯后的內(nèi)核能在開(kāi)發(fā)板上運(yùn)行,應(yīng)在內(nèi)核頂層Makefile里指定處理器體系結(jié)構(gòu)arm與交叉編譯器arm-linux-。

【描述4.D.2】指定交叉編譯

ARCH ?=arm

CROSS_COMPILE?=arm-linux-

3.加載配置文件使用處理器S3C2410的配置文件對(duì)內(nèi)核進(jìn)行配置,配置文件在“arch/arm/configs”目錄下。步驟如下:

(1)進(jìn)入內(nèi)核源碼目錄,在終端下執(zhí)行命令“makes3c2410_defconfig”,在內(nèi)核根目錄下生成“.config”配置文件。

(2)執(zhí)行“makemenuconfig”命令,啟動(dòng)配置界面,可以對(duì)內(nèi)核配置選項(xiàng)進(jìn)行選擇配置,配置完成后,保存配置,退出內(nèi)核配置界面,這樣所有針對(duì)開(kāi)發(fā)板所選擇的配置選項(xiàng)都保存到“.config”文件中了。

【描述4.D.2】加載配置文件

$makes3c2410_defconfig

$makemenuconfig

4.修改內(nèi)核代碼因?yàn)閘inux-2.6.22內(nèi)核所支持的smdk2440并不能完全匹配本書(shū)所用的開(kāi)發(fā)板,因此還需要對(duì)內(nèi)核源碼進(jìn)行更改。一般來(lái)說(shuō),在移植linux-2.6.22內(nèi)核時(shí),只需要做三方面的修改。

1)內(nèi)核平臺(tái)的時(shí)鐘頻率內(nèi)核支持的smdk2440開(kāi)發(fā)板所采用的晶振為16.9344MHz,而本書(shū)所用開(kāi)發(fā)板的晶振為12MHz,如果兩者時(shí)鐘不匹配,會(huì)造成在啟動(dòng)內(nèi)核時(shí)出現(xiàn)亂碼。修改內(nèi)核源碼“arch/arm/mach-s3c2440/mach-smdk2440.c”中的第163行,將16934400改為12000000即可。

【描述4.D.2】修改時(shí)鐘staticvoid__initsmdk2440_map_io(void){ s3c24xx_init_io(smdk2440_iodesc,ARRAY_SIZE(smdk2440_iodesc));

s3c24xx_init_clocks(12000000);

s3c24xx_init_uarts(smdk2440_uartcfgs,ARRAY_SIZE(smdk2440_uartcfgs));}

2)內(nèi)核MTD分區(qū)內(nèi)核中支持開(kāi)發(fā)板的NANDFlash分區(qū)必須同Bootloader中相同,否則Bootloader將不能正常啟動(dòng)內(nèi)核或內(nèi)核不能正常掛載根文件系統(tǒng)。在本書(shū)中Bootloader將256M的NANDFlash分為3個(gè)區(qū),即Boot區(qū)為2MB,Kernel區(qū)為2MB,剩余區(qū)域?yàn)槲募到y(tǒng)存儲(chǔ)區(qū)。修改內(nèi)核源碼“/arch/arm/plat-s3c24xx/common-smdk.c”中的NANDFlash分區(qū)方法與Bootloader的相同。

【描述4.D.2】修改MTD分區(qū)staticstructmtd_partitionsmdk_default_nand_part[]={ [0]={ .name ="Boot",

.size =0x00100000,

.offset =0,

},

[1]={

.name ="Kernel",

.size =0x00300000,

.offset =0x00500000,

},

[3]={ .name ="fs_yaffs",

.size =0x0c300000,

.offset =0x00800000,

}};

3)修改內(nèi)核支持yaffs2文件系統(tǒng)

yaffs文件系統(tǒng)是專(zhuān)門(mén)針對(duì)NANDFlash而開(kāi)發(fā)的一種嵌入式文件系統(tǒng)格式,支持多種操作系統(tǒng),如Linux、WindowsCE等。yaffs文件也有兩種類(lèi)型,yaffs和yaffs2,區(qū)別如下:

yaffs:針對(duì)小頁(yè)NANDFlash,頁(yè)大小為512B。yaffs也稱(chēng)為yaffs1。

yaffs2:針對(duì)大頁(yè)NANDFlash,頁(yè)大小為2KB。yaffs2向前兼容yaff。

本書(shū)中開(kāi)發(fā)板所用的NANDFlash為256MB,頁(yè)大小為2KB,所以文件系統(tǒng)需要制作為yafffs2格式。Linux-2.6.22內(nèi)核中不支持yaffs2文件系統(tǒng),現(xiàn)在需要在內(nèi)核源碼中增加對(duì)yaffs2文件系統(tǒng)的支持??梢允褂胮atch-ker.sh給內(nèi)核打補(bǔ)丁,假設(shè)“dh/work/tools/?development/”為yaffs2源碼目錄,命令如下所示。

【描述4.D.2】patch-ker.sh命令

$cdwork/tools/Development/yaffs2

$./patch-ker.shc/work/linux-2.6.22執(zhí)行完此命令后,內(nèi)核配置選項(xiàng)發(fā)生改變,需要重新對(duì)內(nèi)核進(jìn)行配置,增加yaffs2的選項(xiàng)。

4)修改其他設(shè)備驅(qū)動(dòng)程序經(jīng)過(guò)以上步驟配置的內(nèi)核,已經(jīng)可以滿足系統(tǒng)的基本需求,可以正常地啟動(dòng)內(nèi)核并掛載文件系統(tǒng),但是要使開(kāi)發(fā)板上的USB、網(wǎng)卡、SD卡、聲卡等設(shè)備正常工作,還需要相關(guān)驅(qū)動(dòng)程序的移植。有關(guān)設(shè)備驅(qū)動(dòng)程序的移植將在第5章詳細(xì)講解。

5.編譯內(nèi)核使用命令makezImage可以生成zImage格式的內(nèi)核映像文件。

【描述4.D.2】makezImage命令

$makezImage執(zhí)行完編譯命令后,將在“/arch/arm/boot”目錄下生成zImage映像文件。此時(shí),內(nèi)核的移植工作已經(jīng)完成,利用Bootloader將zImage文件燒寫(xiě)到NANDFlash的“Kernel”分區(qū)中后,啟動(dòng)內(nèi)核,如圖4-8所示。

圖4-8內(nèi)核啟動(dòng)畫(huà)面

從圖中可以看見(jiàn)內(nèi)核已經(jīng)正常啟動(dòng)了。但是提示的“unabletoopenrtcdevice(不能打開(kāi)初始化的控制臺(tái))”說(shuō)明內(nèi)核沒(méi)有進(jìn)入init進(jìn)程,這是因?yàn)閮?nèi)核在啟動(dòng)后并沒(méi)有正常地掛載根文件系統(tǒng)的緣故。在本章4.6節(jié)將詳細(xì)講解根文件系統(tǒng)的構(gòu)建以及啟動(dòng)過(guò)程。

4.5.2內(nèi)核映像

Linux內(nèi)核源碼經(jīng)過(guò)編譯后,除了生成zImage的映像格式外,還支持生成多種格式的鏡像,支持不同的引導(dǎo)程序和存儲(chǔ)介質(zhì),包括vmlinux、Image、zImage、bzImage、uImage、xipImage等。

(1)?vmlinux,是可引導(dǎo)的、可壓縮的內(nèi)核鏡像(vm代表VirtualMemory)。它是由用戶對(duì)內(nèi)核源碼編譯得到,是最原始、未壓縮的內(nèi)核文件。

(2)?Image,是經(jīng)過(guò)objcopy處理的只包含二進(jìn)制數(shù)據(jù)且沒(méi)有經(jīng)過(guò)壓縮的代碼。

(3)?zImage,是ARMlinux常用的一種壓縮鏡像文件,它是由vmlinux加上解壓代碼經(jīng)gzip壓縮而成的,這種格式的Linux鏡像文件多存放在NANDFlash上。

(4)?bzImage,bz表示bigzImage,其格式與zImage類(lèi)似,但采用了不同的壓縮算法,bzImage的壓縮率更高。

(5)?uImage,是uboot專(zhuān)用的鏡像文件,它在zImage之前加上了一個(gè)長(zhǎng)度為0x40的頭信息(tag),在頭信息內(nèi)說(shuō)明了該鏡像文件的類(lèi)型、加載位置、生成時(shí)間、大小等信息。

(6)?xipImage,這種格式的Linux鏡像文件多存放在NORFlash上,且運(yùn)行時(shí)不需要拷貝到內(nèi)存SDRAM中,可以直接在NORFlash中運(yùn)行。4.6構(gòu)建根文件系統(tǒng)

4.6.1文件系統(tǒng)概述

Linux文件系統(tǒng)由文件和目錄組成,文件是用來(lái)存儲(chǔ)數(shù)據(jù)的對(duì)象,是各種信息的集合。而目錄是用來(lái)組織文件的方式,相當(dāng)于盛放文件的容器。在Linux系統(tǒng)下,一切皆為文件,也就是說(shuō),除了傳統(tǒng)意義上的文件外,系統(tǒng)中的設(shè)備也是以文件的形式進(jìn)行訪問(wèn)的,例如串口設(shè)備、USB設(shè)備等。Linux系統(tǒng)采用目錄的形式對(duì)諸多文件進(jìn)行歸納和管理。

文件系統(tǒng)類(lèi)型是指文件存儲(chǔ)于物理設(shè)備的一種格式,在PC上的文件系統(tǒng)類(lèi)型一般稱(chēng)為通用文件類(lèi)型,例如ext2文件系統(tǒng);另外還有專(zhuān)門(mén)針對(duì)嵌入式系統(tǒng)開(kāi)發(fā)的文件系統(tǒng)類(lèi)型,例如jffs文件系統(tǒng)、yaffs文件系統(tǒng)等。

本節(jié)從文件結(jié)構(gòu)和文件系統(tǒng)類(lèi)型兩方面來(lái)介紹Linux的文件系統(tǒng)。

1.文件結(jié)構(gòu)文件結(jié)構(gòu)是指文件存放在磁盤(pán)等存儲(chǔ)設(shè)備上的組織方法,主要體現(xiàn)在對(duì)文件和目錄的組織形式上。Linux采用的是樹(shù)型目錄結(jié)構(gòu),最上層是根目錄,其他的所有目錄都是從根目錄出發(fā)而生成的。微軟的DOS和Windows也都采用樹(shù)型結(jié)構(gòu),但是和Linux的樹(shù)型結(jié)構(gòu)有很大的區(qū)別,區(qū)別如下:

在DOS或Windows操作系統(tǒng)下,每個(gè)磁盤(pán)分區(qū)對(duì)應(yīng)一個(gè)樹(shù)型目錄,且關(guān)系是并列的。例如,c:\,d:\,每個(gè)分區(qū)都是一個(gè)獨(dú)立的目錄結(jié)構(gòu),且為并列關(guān)系。

在Linux操作系統(tǒng)下,整個(gè)文件系統(tǒng)是一個(gè)樹(shù)型目錄結(jié)構(gòu),且是唯一一個(gè),無(wú)論劃分為幾個(gè)分區(qū),也都是掛接在目錄樹(shù)的某個(gè)子目錄下的。

Linux的目錄被稱(chēng)為掛節(jié)點(diǎn)(mountpoint),系統(tǒng)通過(guò)掛節(jié)點(diǎn)來(lái)訪問(wèn)此目錄上的文件。例如,只要Linux根文件系統(tǒng)被掛接在根目錄“/”上,就可以訪問(wèn)根目錄下的各個(gè)子目錄及文件。

Linux系統(tǒng)遵循FHS(FilessystemHierarchyStandard,文件系統(tǒng)科學(xué)分類(lèi)標(biāo)準(zhǔn))來(lái)進(jìn)行系統(tǒng)管理。FHS定義了兩級(jí)目錄的名稱(chēng)和位置的標(biāo)準(zhǔn),分別是:

第一級(jí)目錄是關(guān)于根目錄下的主要目錄,根據(jù)名稱(chēng)就可以知道目錄中的文件內(nèi)容,例如:

/bin、/sbin、/usr目錄下為用戶可執(zhí)行命令。

/etc目錄下存放各種全局配置文件。

/dev目錄下存放設(shè)備文件。

/lib目錄下是庫(kù)文件。

第二級(jí)目錄是關(guān)于/usr和/var的深層目錄的定義。

FHS使Linux文件系統(tǒng)目錄標(biāo)準(zhǔn)化,且每個(gè)目錄都有特定的功能。

2.文件系統(tǒng)類(lèi)型文件系統(tǒng)類(lèi)型是指文件存儲(chǔ)于物理設(shè)備的一種格式,也是操作系統(tǒng)用于區(qū)別存儲(chǔ)設(shè)備上文件的方法。存儲(chǔ)設(shè)備的硬件特性決定了文件系統(tǒng)類(lèi)型的特點(diǎn)。例如,PC上的存儲(chǔ)設(shè)備、磁盤(pán)與光盤(pán)、嵌入式系統(tǒng)中的NORFlash與NANDFlash,分別對(duì)應(yīng)不同的文件系統(tǒng)類(lèi)型。

Linux操作系統(tǒng)的一大特征就是能夠支持多種類(lèi)型的文件系統(tǒng),例如ext3、swap、vfat、NFS文件系統(tǒng)等。但這幾種文件類(lèi)型為L(zhǎng)inux通用文件類(lèi)型,是針對(duì)PC上磁盤(pán)等存儲(chǔ)設(shè)備的文件組織形式體現(xiàn)。嵌入式系統(tǒng)與通用PC不同,一般沒(méi)有硬盤(pán)、光盤(pán)這類(lèi)的存儲(chǔ)設(shè)備,而是使用諸如RAM(如SDRAM)、ROM(如NANDFlash與NORFlash)等專(zhuān)為嵌入式系統(tǒng)設(shè)計(jì)的存儲(chǔ)芯片。

下面介紹幾種在嵌入式Linux系統(tǒng)中常用的文件系統(tǒng)類(lèi)型。

1)?Ramdisk

Ramdisk是基于RAM的一種文件系統(tǒng)類(lèi)型,它將一部分固定大小的內(nèi)存當(dāng)作分區(qū)來(lái)使用。它并非是一個(gè)實(shí)際的文件系統(tǒng),而是一種將實(shí)際的文件系統(tǒng)裝入內(nèi)存的機(jī)制,并且可以作為根文件系統(tǒng)。將一些經(jīng)常被訪問(wèn)而又不會(huì)更改的文件(如只讀的根文件系統(tǒng))通過(guò)Ramdisk放在內(nèi)存中,可以明顯地提高系統(tǒng)的性能。

2)?Ramfs/tmpfs

Ramfs/tmpfs也是基于RAM的一種文件系統(tǒng)類(lèi)型,工作于虛擬文件系統(tǒng)(VFS)層,不能格式化,可以創(chuàng)建多個(gè),在創(chuàng)建時(shí)可以指定其最大能使用的內(nèi)存大小。它把所有的文件都放在RAM中,所以讀/寫(xiě)操作發(fā)生在RAM中,這樣既避免了對(duì)Flash存儲(chǔ)器的讀寫(xiě)損耗,也提高了數(shù)據(jù)讀寫(xiě)速度。

3)?Cramfs(CompressedROMFileSystem)

Cramfs是一種基于MTD驅(qū)動(dòng)程序的只讀壓縮文件系統(tǒng)。該文件系統(tǒng)以壓縮方式存儲(chǔ),在運(yùn)行時(shí)解壓縮,由于Cramfs是采用分頁(yè)壓縮的方式存放檔案的,故在讀取檔案時(shí),只針對(duì)目前實(shí)際讀取的部分分配內(nèi)存,對(duì)尚沒(méi)有讀取的部分不分配內(nèi)存空間。Cramfs映像通常是放在Flash中,但是也能放在別的文件系統(tǒng)里。

4)?jffs2(JournallingFlashFileSystemv2,日志閃存文件系統(tǒng)版本2)

jffs2是基于NORFlash的一種文件系統(tǒng)類(lèi)型,主要用于NOR型閃存,基于MTD驅(qū)動(dòng)層。其特點(diǎn)是可讀寫(xiě)的、支持?jǐn)?shù)據(jù)壓縮的、基于哈希表的日志型文件系統(tǒng),并提供了崩潰/掉電安全保護(hù),提供“寫(xiě)平衡”支持等。缺點(diǎn)主要是當(dāng)文件系統(tǒng)已滿或接近滿時(shí),因?yàn)槔占年P(guān)系而使jffs2的運(yùn)行速度大大放慢。

5)?yaffs/yaffs2(YetAnotherFlashFileSystem)

yaffs/yaffs2是專(zhuān)為NANDFlash而設(shè)計(jì)的一種日志型文件系統(tǒng)。其特點(diǎn)為讀取速度快,掛載時(shí)間短、內(nèi)存占用小、支持多種平臺(tái)等。yaffs/yaffs2自帶NANDFlash的驅(qū)動(dòng),并且為嵌入式系統(tǒng)提供了直接訪問(wèn)文件系統(tǒng)的API,用戶可以直接對(duì)文件系統(tǒng)進(jìn)行操作。

4.6.2根文件系統(tǒng)根文件系統(tǒng)是內(nèi)核啟動(dòng)時(shí)所掛接的第一個(gè)文件系統(tǒng),其中包括了支持Linux系統(tǒng)正常運(yùn)行的基本內(nèi)容以及提供給用戶使用的基礎(chǔ)架構(gòu)和應(yīng)用軟件,例如基本命令、基本配置文件、依賴(lài)的庫(kù)文件等。一個(gè)典型的Linux根文件系統(tǒng)目錄結(jié)構(gòu)如圖4-9所示。

圖4-9根文件系統(tǒng)目錄結(jié)構(gòu)圖

從圖中可以看出,Linux跟文件系統(tǒng)的所有文件都被組織在一個(gè)樹(shù)型目錄結(jié)構(gòu)之中,樹(shù)的頂層是根目錄,根目錄中包含多個(gè)子目錄,子目錄中包含著文件或者其他目錄。各個(gè)子目錄或者文件的名稱(chēng)都具有獨(dú)特的含義,解釋了其中的內(nèi)容及功能。表4-5說(shuō)明Linux文件系統(tǒng)中各子目錄中的文件或目錄的功能。

表4-5Linux文件系統(tǒng)目錄功能

續(xù)表

4.6.3Busybox

Linux內(nèi)核啟動(dòng)后首先要掛接根文件系統(tǒng),嵌入式Linux系統(tǒng)也是同樣的啟動(dòng)過(guò)程,但是,由于Linux根文件系統(tǒng)中包含很多內(nèi)容,單就一個(gè)子目錄/bin下的基本命令而言,就有幾兆字節(jié)的大小,可想而知,通過(guò)開(kāi)發(fā)板上僅有的存儲(chǔ)空間來(lái)存放幾十兆字節(jié)的根文件系統(tǒng),顯然是不現(xiàn)實(shí)的。因此,在嵌入式開(kāi)發(fā)過(guò)程中,應(yīng)當(dāng)在滿足系統(tǒng)基本性能要求的前提下適當(dāng)?shù)鼐?jiǎn)系統(tǒng)的應(yīng)用程序,去除冗余,而不致于浪費(fèi)開(kāi)發(fā)板有限的存儲(chǔ)資源。

1.?Busybox概述

Busybox是一個(gè)用來(lái)定制根文件系統(tǒng)的工具,可以起到精簡(jiǎn)文件系統(tǒng)的作用。用戶可以根據(jù)需求對(duì)根文件系統(tǒng)進(jìn)行配置、編譯和安裝,最終形成的最基本的根文件系統(tǒng)僅有幾兆字節(jié)的大小。

Busybox工程于1996年發(fā)起,到目前為止已是一個(gè)很成功的開(kāi)源軟件。Busybox集成了一百多個(gè)最常用的Linux命令(如init、ls、cp、rm等)和工具軟件,具有了shell的功能,甚至還集成了一個(gè)http服務(wù)器和一個(gè)telnet服務(wù)器,并且支持glibc和uClibc,用戶可以非常方便地在Busybox中定制所需要的應(yīng)用程序。使用Busybox可以有效地減小bin程序的容量,動(dòng)態(tài)鏈接的Busybox工具一般在幾百千字節(jié)左右,這使得Busybox在嵌入式開(kāi)發(fā)過(guò)程中具有不言而喻的優(yōu)勢(shì)。

Busybox安裝完成后,在安裝目錄中就已經(jīng)形成了一個(gè)根文件系統(tǒng)模型,然后在/dev目錄下創(chuàng)建必要的設(shè)備節(jié)點(diǎn),在/etc目錄下創(chuàng)建基本的配置文件,在/lib目錄下添加必要的庫(kù)文件,這樣就完成了一個(gè)最小根文件系統(tǒng)的制作。本書(shū)以Busybox-1.7.0為例講解Busybox在構(gòu)建嵌入式Linux根文件系統(tǒng)中的應(yīng)用。從官方網(wǎng)站/downloads可以下載busybox-1.7.0.tar.bz2,解壓后得到busybox-1.7.0源碼。

2.?Busybox的安裝假設(shè)Busybox源碼目錄為“/work/tools/busybox-1.7.0”,可以按照以下步驟進(jìn)行安裝。

1)指定交叉編譯器修改根目錄下的Makefile,將CPU體系結(jié)構(gòu)指定為arm,編譯器為交叉編譯器arm-linux-。

【示例4-2】Busybox指定交叉編譯

175ARCH ?=arm

176CROSS_COMPILE ?=arm-linux-

2)配置在Busybox源碼目錄下,運(yùn)行“makemenuconfig”命令,進(jìn)入Busybox配置界面,如圖4-10所示。圖4-10Busybox配置界面

【示例4-3】Busybox配置

$cdwork/tools/busybox-1.7.0/

$makemenuconfig

Busybox將所有配置選項(xiàng)主要分為兩大部分:Busyboxsetting:編譯和安裝Busybox的一些選項(xiàng),包括一些通用設(shè)置、編譯調(diào)試選項(xiàng)、安裝路徑以及Busybox的性能微調(diào)選項(xiàng)。

Applets:應(yīng)用命令集。Busybox將支持的幾百個(gè)命令分類(lèi)存放,需要時(shí)只需在各個(gè)大類(lèi)下選擇想要的命令即可。用戶可以根據(jù)需求進(jìn)行工具配置,配置選項(xiàng)的具體說(shuō)明如表4-6所示。

表4-6Busybox配置選項(xiàng)說(shuō)明

一般情況下,配置Busybox時(shí)直接使用默認(rèn)配置即可,配置完成后將配置存入“.config”文件。如有特殊需要,可進(jìn)行配置選項(xiàng)更改。下面以配置Busyboxsetting選項(xiàng)為例進(jìn)行說(shuō)明,其界面如圖4-11所示。

圖4-11Busyboxsetting配置選項(xiàng)

各個(gè)配置選項(xiàng)說(shuō)明如表4-7所示。表4-7busyboxsetting配置選項(xiàng)說(shuō)明

3)編譯運(yùn)行Busybox命令進(jìn)行make的編譯過(guò)程。

【示例4-4】Busybox編譯

$make

4)安裝執(zhí)行安裝命令“makeCONFIG_PREFIX=../dh_fs/install”來(lái)安裝Busybox?!?./dh_fs/install”為安裝路徑。

【示例4-5】Busybox安裝

$makeCONFIG_PREFIX=../dh_fs/install安裝完成后,將在work/dh_fs/下生成/bin、/sbin、/usr目錄和linuxrc軟鏈接文件。Linuxrc指向/bin目錄下的Busybox。dh_fs目錄如圖4-12所示。

圖4-12dh_fs目錄

在/bin、/sbin目錄下的命令也是軟鏈接文件,分別指向/bin/busybox可執(zhí)行文件。/bin目錄下的命令如圖4-13所示。從/bin和/sbin目錄中可以看出,dh_fs目錄下已經(jīng)集成了大多數(shù)命令,可以滿足系統(tǒng)的需求。從dh_fs的屬性可以看出,dh_fs目前大小還不到800KB。

圖4-13/bin目錄下的命令

5)構(gòu)建/lib目錄系統(tǒng)的運(yùn)行僅僅有命令是不夠的,必須有庫(kù)的支持才行。那么應(yīng)用程序Busybox要依賴(lài)哪些庫(kù)才能正常的運(yùn)行呢?找出這些庫(kù)并把這些庫(kù)文件拷貝到work/dh_fs/lib即可。

Busybox是經(jīng)過(guò)交叉編譯的,因此它所依賴(lài)的庫(kù)文件應(yīng)該位于交叉編譯生成的glibc庫(kù)中。構(gòu)建根文件系統(tǒng)的/lib目錄有兩種方法:一是將庫(kù)文件全部拷貝到/lib中;二是利用ldd.host命令查找Busybox的依賴(lài)庫(kù),并拷貝到/lib中。

4.6.4構(gòu)建根文件系統(tǒng)構(gòu)建Linux根文件系統(tǒng)就是創(chuàng)建系統(tǒng)能夠正常運(yùn)行所需的各種目錄及文件,并能夠被內(nèi)核正確地掛接,本節(jié)將利用Busybox構(gòu)建根文件系統(tǒng)。下述內(nèi)容用于實(shí)現(xiàn)任務(wù)描述4.D.3—利用Busybox構(gòu)建根文件系統(tǒng)。其實(shí)現(xiàn)步驟如下。

(1)編譯安裝Busybox,生成/bin、/sbin、/usr/bin、/usr/sbin目錄。

(2)構(gòu)建/lib目錄。有關(guān)Busybox的編譯安裝以及添加/lib目錄的內(nèi)容已在4.6.4節(jié)詳細(xì)講解過(guò),根據(jù)步驟生成dh_fs目錄,目錄下包含vmlinux文件和4個(gè)子目錄/bin、/sbin、/usr、/lib。

(3)構(gòu)建/etc目錄。

/etc目錄存放的是系統(tǒng)程序的主配置文件,需要配置哪些文件取決于需要運(yùn)行哪些系統(tǒng)程序。即使最小的系統(tǒng)也一定會(huì)運(yùn)行1號(hào)用戶進(jìn)程init,因此需要編寫(xiě)init的主配置文件inittab。Busybox的inittab文件的語(yǔ)法、語(yǔ)義與傳統(tǒng)的inittab有所不同。

inittab文件中每個(gè)條目用來(lái)定義一個(gè)需要init啟動(dòng)的子進(jìn)程,并確定它的啟動(dòng)方式,格式為<id>:<runlevel>:<action>:<process>。例如,ttySAC0::askfirst:-/bin/sh,其中:

<id>表示子進(jìn)程要使用的控制臺(tái),若省略則使用與init進(jìn)程一樣的控制臺(tái)。

<runlevel>表示運(yùn)行級(jí)別,對(duì)于Busyboxinit程序,這個(gè)字段沒(méi)有意義。

<action>表示init進(jìn)程如何控制這個(gè)子進(jìn)程,有以下幾個(gè)方式:

sysinit:在系統(tǒng)啟動(dòng)后最先執(zhí)行,只執(zhí)行一次,init進(jìn)程等待它結(jié)束后才繼續(xù)執(zhí)行其他動(dòng)作。

wait:系統(tǒng)執(zhí)行完sysinit條目后執(zhí)行,只執(zhí)行一次,init進(jìn)程等待它結(jié)束后才繼續(xù)執(zhí)行其他動(dòng)作。

once:系統(tǒng)執(zhí)行完wait條目后執(zhí)行,只執(zhí)行一次,init進(jìn)程不等待它結(jié)束。

respawn:?jiǎn)?dòng)完once進(jìn)程后,init進(jìn)程監(jiān)測(cè)發(fā)現(xiàn)子進(jìn)程退出時(shí),重新啟動(dòng)它。

askfirst:?jiǎn)?dòng)完respawn進(jìn)程后,與respawn類(lèi)似,不過(guò)init進(jìn)程先輸出“PleasepressEntertoactivatethisconsole”,等用戶輸入回車(chē)后才啟動(dòng)子進(jìn)程。

shutdown:當(dāng)系統(tǒng)關(guān)機(jī)時(shí)執(zhí)行。

restart:Busybox中配置了CONFIG_FEATURE_USE_INITAB,并且init進(jìn)程接收到SIGUP信號(hào)時(shí)執(zhí)行,先重新讀取、解析/etc/inittab文件,再執(zhí)行restart程序。

ctrlaltdel:按下Ctrl?+?Alt?+?Del鍵時(shí)執(zhí)行,不過(guò)在串口控制臺(tái)中無(wú)法輸入它。

<process>表示進(jìn)程對(duì)應(yīng)的二進(jìn)制文件。如果前面有“-”號(hào),表示該程序是“可以與用戶進(jìn)行交互的”。編寫(xiě)最簡(jiǎn)單的“/etc/inittab”文件,內(nèi)容如下。

【描述4.D.3】inittab文件

::sysinit:/etc/init.d/rcS

::askfirst:-/bin/sh

::ctrlaltdel:/sbin/reboot

::shutdown:/bin/umount-a–r

制作最簡(jiǎn)單的腳本程序文件“/etc/init.d/rcS”,內(nèi)容如下。

【描述4.D.3】rcS腳本文件

#!/bin/sh

ifconfigeth07修改shell腳本文件“/etc/init.d/rcS”的權(quán)限,使其可被執(zhí)行,內(nèi)容如下。

【描述4.D.3】修改rcS權(quán)限

$chmoda+x/etc/init.d/rcS

(4)構(gòu)建/dev目錄。在PC中,/dev目錄下的設(shè)備文件多達(dá)幾百個(gè),而在嵌入式開(kāi)發(fā)中,可根據(jù)開(kāi)發(fā)需求進(jìn)行所需設(shè)備文件的手工創(chuàng)建。創(chuàng)建/dev目錄有兩種方法:使用用mknod命令創(chuàng)建設(shè)備文件。使用mdev應(yīng)用程序創(chuàng)建設(shè)備文件。下面分別介紹使用mknod命令和使用mdev應(yīng)用程序創(chuàng)建/dev目錄的方式。①使用mknod命令創(chuàng)建設(shè)備文件。從系統(tǒng)的啟動(dòng)過(guò)程來(lái)看,首先需要?jiǎng)?chuàng)建的設(shè)備文件包括console、null、ttySAC*和mtdbloke*,內(nèi)容如下。

【描述4.D.3】mknod創(chuàng)建設(shè)備文件

$mkdir-p/work/dh_fs/dev

$cdwork/dh_fs/dev/

$sudomknodconsolec51 //字符設(shè)備,主設(shè)備號(hào)為5,此設(shè)備號(hào)為1

$sudomknodnullc13 //字符設(shè)備,主設(shè)備號(hào)為1,此設(shè)備號(hào)為3

$sudomknodttySAC0c20164 //字符設(shè)備,主設(shè)備號(hào)為204,此設(shè)備號(hào)為64

$sudomknodmtdblock0b310 //塊設(shè)備,主設(shè)備號(hào)為31,此設(shè)備號(hào)為0

$sudomknodmtdblock1b311 //塊設(shè)備,主設(shè)備號(hào)為31,此設(shè)備號(hào)為1

$sudomknodmtdblock2b312 //塊設(shè)備,主設(shè)備號(hào)為31,此設(shè)備號(hào)為2②使用mdev創(chuàng)建設(shè)備文件。mdev是通過(guò)讀取內(nèi)核信息來(lái)創(chuàng)建設(shè)備文件的。具體過(guò)程為:操作系統(tǒng)啟動(dòng)的時(shí)候?qū)⒆R(shí)別到的所有設(shè)備的信息自動(dòng)導(dǎo)出到“/sys”目錄中,mdev根據(jù)“/sys”中的設(shè)備信息,自動(dòng)在“/dev”目錄下創(chuàng)建所有正確的設(shè)備文件。

修改/etc/init.d/rcS,內(nèi)容如下。

【描述4.D.3】mdev命令

#!/bin/sh

ifconfigeth07//設(shè)置開(kāi)發(fā)板IP地址

mount-tprocnone/proc

mount-tsysfsnone/sys//mdev通過(guò)sysfs文件系統(tǒng)獲取設(shè)備信息

echo/sbin/mdev>/proc/sys/kernel/hotplug//設(shè)置內(nèi)核,當(dāng)有設(shè)備拔插時(shí)調(diào)用mdev程序

mdev–s//在/dev目錄下生成內(nèi)核支持的所有設(shè)備的節(jié)點(diǎn)因?yàn)閙dev是通過(guò)init進(jìn)程來(lái)進(jìn)行啟動(dòng)的,在使用mdev命令之前,init進(jìn)程需要用到設(shè)備文件/dev/console和/dev/null,所以應(yīng)先用mknod命令建立這兩個(gè)設(shè)備文件。

【描述4.D.3】創(chuàng)建設(shè)備文件$mkdir-p/work/dh_fs/dev$cdwork/dh_fs/dev/$sudomknodconsolec51$sudomknodnullc13

(5)創(chuàng)建其他空目錄。其他目錄可以是空目錄,例如proc、mnt、tmp、sys、root等,可以用以下方式創(chuàng)建。

【描述4.D.3】建立空目錄

$cdwork/dh_fs/

$mkdirprocmnttmpsysroot此時(shí),dh_fs已經(jīng)是一個(gè)目錄和文件基本完整的根文件系統(tǒng)。開(kāi)發(fā)板可以將其作為NFS根文件系統(tǒng)直接啟動(dòng),也可以將其制作成yaffs2映像文件燒寫(xiě)到開(kāi)發(fā)板中。

(6)制作根文件系統(tǒng)的yaffs2映像文件。根文件系統(tǒng)已經(jīng)制作完畢,但是根文件系統(tǒng)制作的最終目的是要燒寫(xiě)到開(kāi)發(fā)板的NANDFlash中去,由以上章節(jié)可知,yaffs2類(lèi)型的文件為專(zhuān)門(mén)支持大頁(yè)面NANDFlash的映像文件類(lèi)型,本書(shū)所提供的開(kāi)發(fā)套件中的mkyaffs2image工具可完成這一制作過(guò)程。

【描述4.D.3】mkyaffs2image命令

$./mkyaffs2imagedh_fsdh_fs.yaffs2

執(zhí)行完成后,可在/work目錄中生成dh_fs.yaffs2文件,接下來(lái)就是利用Bootloader將根文件系統(tǒng)燒寫(xiě)到NANDFlash中的“fs_yaffs”分區(qū)中,燒寫(xiě)完畢后,啟動(dòng)Linux,可以看到如圖4-14所示的畫(huà)面。從圖中可以看出,內(nèi)核自檢完成后,啟動(dòng)init進(jìn)程,init進(jìn)程根據(jù)“/etc/inittab”文件來(lái)創(chuàng)建其他子進(jìn)程,并執(zhí)行腳本文件“/etc/init.d/rcS”,最后啟動(dòng)shell。

圖4-14根文件系統(tǒng)啟動(dòng)畫(huà)面4.7Linux內(nèi)核啟動(dòng)分析

zImage映像文件由兩部分組成:

初始化以及解壓縮文件head.o,其源文件在“arch/arm/boot/compressed/”下。

內(nèi)核壓縮文件piggy.o??梢?jiàn),zImage映像的入口代碼是head.o,執(zhí)行初始化代碼后解壓內(nèi)核piggy.o。解壓縮完成后,進(jìn)入內(nèi)核真正的啟動(dòng)過(guò)程。

1.內(nèi)核啟動(dòng)流程

Linux內(nèi)核啟動(dòng)流程如圖4-15所示。

圖4-15Linux內(nèi)核啟動(dòng)流程圖

Linux內(nèi)核啟動(dòng)包含兩個(gè)階段:

(1)內(nèi)核引導(dǎo)階段。此階段通常由匯編語(yǔ)言完成,需要檢查此內(nèi)核是否支持體系架構(gòu),是否支持當(dāng)前開(kāi)發(fā)板,經(jīng)過(guò)一系列的檢查后,準(zhǔn)備好內(nèi)核工作環(huán)境,調(diào)用start_kernel()進(jìn)入內(nèi)核啟動(dòng)階段。

(2)內(nèi)核啟動(dòng)階段。此階段使用C語(yǔ)言完成,需要完成內(nèi)核初始化的所有工作,并調(diào)用rest_init創(chuàng)建系統(tǒng)1號(hào)進(jìn)程,即init進(jìn)程,完成Linux系統(tǒng)啟動(dòng)。

2.內(nèi)核自引導(dǎo)程序

Linux內(nèi)核的入口是“arch/arm/kernel/?head.s”,head.s完成內(nèi)核引導(dǎo)階段的功能。首先進(jìn)入管理模式,禁止所有中斷,檢查內(nèi)核是否支持當(dāng)前CPU和當(dāng)前開(kāi)發(fā)板。代碼如下。

【代碼4-5】head.s/*arch/arm/kernel/head.s*/.section".text.head","ax" .type stext,%functionENTRY(stext) msr cpsr_c,#PSR_F_BIT|PSR_I_BIT|SVC_MODE@進(jìn)入管理模式

@禁止中斷

mrc p15,0,r9,c0,c0 @獲得CPUID bl __lookup_processor_type @調(diào)用檢查CPU類(lèi)型函數(shù)

movs r10,r5 @返回值為r5 beq __error_p @若r5為0,則出錯(cuò)

bl __lookup_machine_type @若支持此CPU,則調(diào)用檢查開(kāi)發(fā)板函數(shù)

movs r8,r5 @返回值為r5 beq __error_a @若不支持,則出錯(cuò)

bl __create_page_tables @若支持此開(kāi)發(fā)板,則創(chuàng)建頁(yè)表

.typesecondary_startup,#functionENTRY(secondary_startup) msr cpsr_c,#PSR_F_BIT|PSR_I_BIT|SVC_MODE mrc p15,0,r9,c0,c0 @獲得處理器類(lèi)型

bl __lookup_processor_type movs r10,r5 @檢查匹配

moveq r0,#'p' beq __error adr r4,__secondary_data

ldmia r4,{r5,r7,r13}

@addresstojumptoafter sub r4,r4,r5 @mmuhasbeenenabled ldr r4,[r7,r4] @getsecondary_data.pgdir adr lr,__enable_mmu @returnaddress add pc,r10,#PROCINFO_INITFUNC @initialiseprocessor

@(returncontrolreg)ENTRY(__secondary_switched) ldr sp,[r7,#4] @getsecondary_data.stack mov fp,#0 b secondary_start_kernel @跳到內(nèi)核啟動(dòng)

其中:__lookup_processor_type為檢查CPU類(lèi)型的函數(shù),在“arch/arm/kernel/head_common.s”中。函數(shù)入口為r9(CPUID),在函數(shù)中將檢查ID號(hào)是否在內(nèi)核支持的CPU類(lèi)型中。若支持,則返回值r5為當(dāng)前CPU結(jié)構(gòu)地址;若不支持,返回值r5=0。

__lookup_machine_type為檢查當(dāng)前開(kāi)發(fā)板的函數(shù)。同理,若內(nèi)核支持此開(kāi)發(fā)板,則返回此開(kāi)發(fā)板結(jié)構(gòu)地址;若不支持,返回值r5?=?0。若所有檢查都通過(guò),則通過(guò)調(diào)用__create_page_tables為創(chuàng)建一級(jí)頁(yè)表建立虛擬地址到物理地址的映射。經(jīng)過(guò)一系列的初始化過(guò)程,打開(kāi)MMU,跳轉(zhuǎn)到start_kernel()函數(shù)。

3.

Linux系統(tǒng)初始化start_kernel()函數(shù)是Linux內(nèi)核通用的初始化函數(shù),位于“/init/main.c”中。代碼如下?!敬a4-6】start_kernel()/*init/main.c*/asmlinkagevoid__initstart_kernel(void){ char*command_line;//命令行參數(shù)

externstructkernel_param__start___param[],__stop___param[];

smp_setup_processor_id();

/*

*Needtorunasearlyaspossible,toinitializethe *lockdephash: */ unwind_init();

lockdep_init();

local_irq_disable();

early_boot_irqs_off();

early_init_irq_lock_class();/**Interruptsarestilldisabled.Donecessarysetups,then*enablethem*/

lock_kernel();

tick_init();

boot_cpu_init();

page_address_init();

printk(KERN_NOTICE);

printk(linux_banner);

setup_arch(&command_line);

setup_command_line(command_line);

unwind_setup();

setup_per_cpu_areas();

smp_prepare_boot_cpu(); /*arch-specific

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論