1. 程式人生 > 其它 >Linux核心移植介紹

Linux核心移植介紹

技術標籤:linux核心

LINUX 核心移植

一、核心移植概述
二、Linux核心的目錄
三、 核心配置
四、Kbuild Makefile
五、編譯連線核心
六、核心啟動過程
七、系統環境變數的設定方法
八、實驗步奏
與其它作業系統相比,Linux最大的特點:它是一款遵循GPL(General Public License GNU通用公共許可證(簡稱為GPL),是由自由軟體基金會發行的用於計算機軟體的許可證。)的作業系統,我們可以自由地使用、修改、和擴充套件它。正是由於這一特色,Linux受到越來越多人士的青睞。於是,一個經常會被探討的問題出現了,即關於Linux系統的移植。對於作業系統而言,這種移植通常是跨平臺的、與硬體相關的,即硬體系統結構、甚至CPU不同。下面就讓我們來看看在Linux系統移植方面,我們都需要做些什麼。

Linux系統移植的兩大部分
對於系統移植而言,Linux系統實際上由兩個比較獨立的部分組成:即核心部分和系統部分。
通常啟動一個Linux系統的過程是這樣的:
1、一個不隸屬於任何作業系統的載入程式將Linux部分核心調入記憶體,並將控制權交給記憶體中Linux核心的第一行程式碼。
2、此後Linux要將自己的剩餘部分全部載入到記憶體(如果有的話,視硬體平臺的不同而不同),初始化所有裝置,在記憶體中建立好所需的資料結構(有關程序、裝置、記憶體等)。到此為止Linux核心的工作告一段落,核心已經控制了所有硬體裝置。
3、至於操作和使用這些硬體裝置,則輪到系統部分上場了。核心載入根裝置並啟動init守護程序,init守護程序會根據配置檔案載入檔案系統、配置網路、服務程序、終端等。一旦終端初始化完畢,我們就會看到系統的歡迎介面了。
小結一下:
(1)核心部分初始化和控制硬體裝置,為記憶體管理、程序管理、裝置讀寫等工作做好一切準備。
(2)系統部份載入必需的裝置,配置各種環境以便使用者可以使用整個系統。

一、核心移植概述

1、RedHat 分兩個系列:
Red Hat Enterprise Linux(企業版) Red Hat 9.0 (2.4)
Fedora Core(桌面版) ( 2.6.18)

2、Linux 核心版本號:
Linux的版本號又分為兩部分:核心(kernel)與發行套件 (distribution)版本。
核心版本指的是在Linus領導下的開發小組開發出的系統核心的版本號,目前最新的的 版本的序號大約是 2.6.34 (3.8.8 —2013-4-17釋出)

X.Y.ZZ-WWW
X代表型別。X.Y是版本號。其中Y為偶數是穩定版本,奇數是開發版本,一般有一些新的 東西加入,是不一定很穩定的測試版本,如2.1,2.3。ZZ是次版本號,此版本號不分奇偶,每1-2個月釋出一個。

測試版本為主版本號+次版本號+測試號。如 2.6.12-rcl.

而一些組織或廠家將Linux系統 核心與應用軟體和文件包裝起來,並提供一些安裝介面和系統設定與管理工具,這樣就構 成了一個發行套件,例如最常見的Slackware,RedHat,Debian等等。 實際上發 行套件就是Linux的一個大軟體包而已。相對於 核心版本, 發行套件的版本號隨釋出者 的不同而不同,與系統核心的版本號是相對獨立的,例如Slackware3.5,RedHat5.1, Debian1.3.1等等。

3、新版本的核心的釋出有兩種形式
一種是full/ Source版本,一般是tar.gz或者是.bz2檔案。
另外一種是patch檔案,即補丁。 patch檔案一般只有幾十K到幾百K,但是patch檔案是針對於特定的版本的,你需要找到自己對應的版本才能使用。
例如:你有2.6.9的原始碼,但想移到2.6.10。就可以獲得2.6.10的補丁檔案,應用patch來修改2.6.9原始檔。
$ cd /usr/src/linux
$ patch –pl < …/patch-2.6.10

4、linux核心和版本查詢命令
方法一:
命令: uname -a
作用: 檢視系統核心版本號及系統名稱

方法二:
命令: cat /proc/version
作用: 檢視目錄"/proc"下version的資訊,也可以得到當前系統的核心版本號及系統名稱
5、LINUX核心特點:
1、可移植性
2、模組化
3、穩定性
4、開放原始碼。有各種驅動程式和應用程式可以利用。

6、核心移植
是指將軟體從一個平臺遷移到另一個平臺:
1、從一個硬體平臺移植到另一個硬體平臺
2、從一個作業系統移植到另一個作業系統
3、從一種軟體庫環境移植到另一個軟體庫環境

7、軟體進行移植的容易程度即可移植性
核心移植工作主要是修改跟硬體平臺相關的配置(主要是開發板初始化和驅動程式),一般不涉及linux核心通用的程式。

在Linux核心裡,每一個處理器指令集對應一個獨立的體系結構architecture,比如alpha, arm, i386, mips, ppc。每個體系結構可以有若干變種variant,或不同配置的硬體machin統稱sub-architecture。

由於linux可移植的特點,並且已經支援了各種體系結構的很多公板。找到類似的公板做為參考。
Linux 2.6 核心對已經支援S3C2410處理器的多種公板。(/arch/arm/mach-s3c2410/mach- )例如SMDK2410、Simtec-BAST、Thorcom-VR1000,還支援常用的學習板,如mini2440。
Cpu級的移植  板級的移植

8、選擇參考板的原則:
處理器相同或類似
外圍介面電路相同或類似
已經支援參考板
已驅動基本介面

9、Linux作業系統移植包括:
工具鏈移植
核心移植
應用程式移植

10、Linux核心的平臺相關程式碼
Linux核心對多平臺有很好的支援
核心的對外部介面是統一的,並且與平臺無關 open close read write
核心的大多數程式碼也是與平臺無關的
主要的體系結構相關程式碼存在於
arch/architecture
include/asm-architecture
比如arm體系的平臺相關程式碼主要是
arch/arm
include/asm-arm

二、Linux核心的目錄
Linux核心原始碼位於/usr/src/linux目錄下
/arch 子目錄包含了所有硬體結構特定的核心程式碼。核心中與具體CPU和體系結構相關的程式碼以單獨目錄存放,而相應的標頭檔案.h則分別放在/include/asm
§/arch/arm/boot 自解壓相關程式碼(不同的片上系統又有不同的自解壓程式碼,我們用的是 ./compressed/head.s)。
§/arch/arm/kernel 核心的入口點。啟用處理器、啟動init執行緒等。核心剛啟動時執行此目錄下的 head.S (字尾armo—26位的老式的ARM,armv—32位) entry-armv.S 異常處理、中斷處理的程式碼。
§/arch/arm/mm linux核心實現記憶體管理中體系結構相關的部分。
§/arch/arm/configs 各種公板預設的配置檔案
§/arch/arm/fastfce,rwfce 用軟體模擬浮點運算。
§/arch/arm/Lib 與CPU相關的函式庫
§/arch/arm/Mach-。。。 各種CPU的一些相關實現。
/crypto 這是核心本身所用的加密 API。還有一些壓縮和CRC校驗演算法。
Documentation 文件。這個目錄中包含很多關於配置核心、執行 ramdisk 等任務的實用資訊(但通常是過時的)。不過,與不同配置選項相應的幫助條目並不在這裡 —— 它們在每個原始碼目錄的 Kconfig 檔案中。
/drivers 在此目錄的子目錄中可以找到執行外圍裝置的程式碼。包括視訊驅動程式、網絡卡驅動程式、底層 SCSI 驅動程式,以及其他類似的驅動程式。例如,在 drivers/net 中可以找到大部分網絡卡驅動程式。
/Firmware firmware 名字含義是韌體,Linux 引用這個功能可能從2.6.x開始;
它的作用是讓硬體驅動通過kernel載入裝置韌體驅動;
在實際應用中,我們系統中PCI,USB裝置或許需要自己的驅動韌體,
裝置只有通過這個韌體才能驅動自己;由於韌體也在升級中,或者因為生產時
減少燒錄韌體這道工序,所以人們選擇在載入驅動的時候通過程式將韌體
傳給裝置. 所以Linux 提供了 firmware load 函式給驅動程式使用.
現在的網絡卡,尤其是智慧網絡卡、高速網絡卡,硬體效能越來越強大,承載的功能也越來越多。開發者對網絡卡內部功能的增加或修改,對已知bug的修正都離不開對網絡卡Firmware的更新。Linux作業系統對網絡卡 Firmware的更新提供了一整套機制,允許網絡卡驅動在必要時可以動態載入新的網絡卡Firmware。最新的核心中,動態載入Firmware的功能被加入到了Ethtool框架中,使得在使用者空間載入網絡卡Firmware的操作標準化。
/fs 子目錄包含了所有的檔案系統實現的程式碼。通用檔案系統的程式碼(稱做 VFS,即 Virtual File System)和各個不同檔案系統的程式碼都可以在這個目錄中找到。ext2 檔案系統是在 Linux 中最常廣泛使用的檔案系統之一。
/include 子目錄包含了建立核心程式碼時所需的大部分包含檔案。
Asm 為連結目錄,編譯之後會連結到具體的asm-XXX。
/init 子目錄包含了核心的初始化程式碼。
/ipc IPC 的意思是 程序間通訊(interprocess communication)。它包含了共享記憶體、訊號量以及其他形式 IPC 的程式碼。
/kernel 不適合放在任何其他位置的通用核心級程式碼位於此處。這裡有高層系統呼叫程式碼,排程程式、訊號處理程式碼,等等。檔名包含很多資訊。
/lib 庫檔案.。這裡是對所有核心程式碼都通用的實用例程。常見的字串操作、除錯例程,以及命令列解析程式碼都位於此處。
/mm 子目錄包含了所有記憶體管理程式碼. 這個目錄中是高層次核心管理程式碼。聯合使用這些例程以及底層的與體系結構相關的例程(通常位於 arch//mm/ 目錄中)來實現虛擬記憶體(Virtual memory,VM)。在這裡會完成早期記憶體管理(在記憶體子系統完全建立起來之前需要它),以及檔案的記憶體對映、頁快取記憶體管理、記憶體分配、RAM 中頁的清除(還有很多其他事情)。
/net子 目錄包含了核心的網路連線程式碼 。這裡是高層網路程式碼。底層網路驅動程式與此層次程式碼交換資料包,這個層次的程式碼可以根據資料包將資料傳遞給使用者層應用程式,或者丟棄資料,或者在核心中使用它。net/core 包含大部分不同的網路協議都可以使用的程式碼,和某些位於 net/ 目錄本身中的檔案一樣。特定的網路協議在 net/ 的子目錄下實現。例如,在 net/ipv4 目錄中可以找到 IP(版本 4)程式碼。
/scripts 這個目錄中包含的指令碼可用於核心的構建,但並不將任何程式碼加入到核心本身之中。例如,各種配置工具可以將它們的檔案放在這裡。
/security 在這裡可以找到不同 Linux 安全模型的程式碼,主要包含SELinux模組。
 /sound 這裡放置的是音效卡驅動程式和其他常用裝置驅動。
/usr 此目錄中的程式碼用於構建包含 root 檔案系統映像的 cpio-格式 的歸檔檔案,用於早期使用者空間。
由下圖可以看出,LINUX核心主要由程序排程、記憶體管理、虛擬檔案系統、網路介面和程序間通訊等5個子系統組成。

進入arch目錄,每個體系結構程式碼都有一個子目錄

進入arm目錄,在arm體系結構下我們可以看到很多sub-arch的子目錄

三、 核心配置
1、編譯核心需要考慮:
自己定製編譯的核心執行更快
節省記憶體、系統將擁有更多的記憶體
不需要的功能編譯進入核心可能會增加被系統攻擊者利用的漏洞
將某種功能編譯為模組方式會比編譯到核心內的方式速度要慢一些。
2、核心配置系統
Linux核心有上千個配置選項,配置複雜。通過配置系統簡化核心配置。
核心配置系統可生成核心配置選單。
配置系統包含:
Makefile
Kconfig 配置檔案
配置工具
核心配置方法:
(1)克隆建立自己的目標平臺
(a)將 linux-2.6.32.2/arch/arm/mach-s3c2440/目錄下的 mach-smdk2440.c 複製一份。命名為mach-mini2440.c
(b)看機器碼和時鐘要不要修改。
(2)直接修改Kconfig —一個選項通常對應一個功能模組
(3)參考公板\arch\arm\configs\ s3c2410_defconfig的配置拷貝自己的配置,並匯入選單。
(4)直接修改選單
通過(2)-(4)作更改的結果都會儲存到.config中,可在選單中更改一些選項,儲存退出後把.config和原來的.config比較看更改的效果。
MAKEFILE會根據.config檔案的配置決定編譯哪些檔案。
(5) 新增或者修改裝置驅動

1、Makefile
分佈在 Linux 核心原始碼中的 Makefile,定義 Linux 核心的編譯規則。
頂層目錄的Makefile管理整個Linux核心的配置編譯。
頂層 Makefile 遞迴的進入到核心的各個子目錄中,分別呼叫位於這些子目錄中的 Makefile。至於到底進入哪些子目錄,取決於核心的配置。在頂層 Makefile 中,有一句:include ( s r c t r e e ) / a r c h / (srctree)/arch/ (srctree)/arch/(SRCARCH)/Makefile,包含了特定 CPU 體系結構下的 Makefile,這個 Makefile 中包含了平臺相關的資訊。
位於各個子目錄下的 Makefile 同樣也根據 .config 給出的配置資訊,構造出當前配置下需要的原始檔列表。
Makefile 的作用是根據配置的情況,構造出需要編譯的原始檔列表,然後分別編譯,並把目的碼連結到一起,最終形成 Linux 核心二進位制檔案。

(2)配置工具
包括配置命令直譯器(對配置指令碼中使用的配置命令進行解釋)和配置使用者介面(提供基於字元介面、基於 Ncurses 圖形介面以及基於 Xwindows 圖形介面的使用者配置介面,各自對應於 Make config、Make menuconfig 和 make xconfig)。
  這些配置工具都是使用指令碼語言,如 Tcl/TK、Perl 編寫的(也包含一些用 C 編寫的程式碼)。本文並不是對配置系統本身進行分析,而是介紹如何使用配置系統。
不同的核心配置方式,通過不同的配置工具完成。script目錄下提供了這些配置工具。如menuconfig目標使用mconf(script/kconfig/)。
用到的配置工具有:
◆ config 基於互動式的文字配置介面。每個問題以線形格式出現,並被一個一個地回答,而且一旦作出了回答就不能再修改了。
◆ oldconfig 同config相似,但是使用原有的配置檔案,而且只會提問有關新核心特性的問題,對於核心升級很方便。
◆ menuconfig 一個文字模式、選單驅動的配置介面。
◆ xconfig 基於Tcl/Tk的X圖形配置介面。
現在開始配置核心,使用的工具為menuconfig。在命令列模式下執行下面的命令:
#make menuconfig

(3)Kconfig檔案
arch/$(ARCH)/Kconfig檔案是主Kconfig檔案,主Kconfig檔案呼叫其他目錄的Kconfig檔案。
這些Kconfig檔案形成樹狀關係–>樹狀選單。

選擇相應的配置時,有三種選擇,它們分別代表的含義如下:
  Y--將該功能編譯進核心
  N--不將該功能編譯進核心
  M--將該功能編譯成模組,可以在需要時動態插入到核心中。
選項中是[ ]的,要麼是空,要麼是“” ;
是<>的,可以是空、“
” 或者“M”
是()的,可以在所提供的幾個選項中選擇一項。

配置的原則
大部分選項可以使用其預設值,只有小部分需要根據使用者不同的需要選擇。
將與核心其它部分關係較遠且不經常使用的部分功能程式碼編譯成為可載入模組。
有利於減小核心的長度,減小核心消耗的記憶體;
不需要的功能就不要選;
與核心關心緊密而且經常使用的部分功能程式碼直接編譯到核心中。

3、選單項:
(1)、單個配置選項的定義:關鍵字是config,後面幾行是這個選項的屬性。

config ARCH_RPC //定義的巨集
bool “RiscPC” // 選項的型別 選擇提示
select ARCH_ACORN //依賴關係 depends 依賴關係
select FIQ
select TIMER_ACORN
help //幫助資訊
On the Acorn Risc-PC, Linux can support the internal IDE disk and
CD-ROM interface, serial and parallel port, and the floppy drive.
default y //預設值
range 2 32 //數字範圍

(2)、選單依賴關係語法說明:
= 相等則返回 “y”,否則”n”;
!=相等則返回 “n”,否則”y”;
( ) 返回表示式的值;
&& 返回 min 的結果
||返回 max 的結果

當表示式的值為 “m”“y”時,選單顯示。為“n”不顯示。

(3)、選單的組織結構
1)顯示地宣告為選單
Menu “Network device support”
Depends NET
Config NETDEVICES
……
Endmenu

Menu 與Endmenu 之間 構成Network device support的子選單,所有子項繼承這選單的依賴關係。

2)通過依賴關係確定選單的結構
config REISERFS_FS
tristate “Reiserfs support”
help
Stores not just filenames but the files themselves in a balanced
tree. Uses journaling.

config REISERFS_CHECK
bool “Enable reiserfs debug mode”
depends on REISERFS_FS

REISERFS_CHECK依賴於REISERFS_FS,只有REISERFS_FS不是“n”,才顯示。

各配置選項的意思見〈Linux核心的主要配置〉文件。

3)新增與開發板平臺支援的選項:
/arch/arm/kconfig 是核心主配置檔案。從檔案中可以找到:
menu “System Type” #定義了各個選單項
choice #choice 語句可以在選單中生成一個多選項
prompt “ARM system type” #prompt 選擇提示 #系統平臺選擇項列表
default ARCH_RPC
。。。
config ARCH_S3C2410
bool “Samsung S3C2410” #對於S3C2410 處理器的支援
。。。
source “arch/arm/mach-s3c2410/Kconfig” #定義了各種S3C2410處理器開發板的選項,和其支援的選項。

4)除了手動配置選單外,還可以通過匯入預配置檔案(頂層目錄的 .config)進行配置,選單會自動讀取指定的配置檔案:

5)/arch/arm/mach-s3c2410 目錄專門用來儲存 s3c2410系列處理器相關的程式。
其中:1、makefile和kconfig 是用於核心編譯的。
2、處理器相關的,如:clock.c, clock.h, cpu.c, cpu.h, s3c2410.c

核心中已經支援了各種平臺。在Makefile 中可以通過配置來選擇編譯不同的目錄。/arch/arm/makefile 完成這項任務:

machine-KaTeX parse error: Expected 'EOF', got '#' at position 48: …410 #̲定義machine-y = s…(machine-y),)
//MACHINE := arch/arm/mach-KaTeX parse error: Expected 'EOF', got '#' at position 22: …ne-y)/ #̲包含mach-s3c2410 …(word 1,$(machine-y))/ //2.6.32
else
MACHINE :=
endif

然後編譯生成頂層的vmlinux 映像。再由vmlinux壓縮為zImage.

四、Kbuild Makefile

Makefile 包含5部分:
1、.config 核心配置檔案
2、Arch/arm/Makefile 對應的體系結構的Makefile
3、頂層目錄的Makefile
4、Scripts/makefile.* 所有Kbuild Makefile 的通用規則等定義
5、各目錄下的Makefile

Kbuild 編譯過程:
1、取得.config
2、儲存版本資訊
3、建立連線符號 include/asm ,連線 /include/asm-$(ARCH)
4、遞迴地呼叫各子目錄編譯所有目標
5、生成頂層目錄 vmlinux
6、編譯生成最終的引導映像

五、編譯連線核心

先編譯連線生成頂層目錄的vmlinux ,再把vmlinux 壓縮和加上自載入程式連線成 /arch/($ARCH)/boot/zImage。

1、編譯連線vmlinux
2、生成vmlinux.lds連線指令碼(由vmlinux.lds.S生成)。
(瞭解 arch/arm/kernel/vmlinux.lds.S)
3、連線生成zImage
在 arch/arm/Makefile 中:

zImage 的前提是vmlinux,vmlinux編譯通過了才能生成zImage

zImage Image xipImage bootpImage uImage: vmlinux
4、system.map
system.map 是一個特定核心的符號表,它包含核心全域性變數和函式的地址資訊。是編譯過程中生成的。

六、核心啟動過程:

1、如果使用mkimage生成核心映象檔案的話,會在核心的前頭加上了64byte的資訊,供建立tag之用。bootm命令會首先判斷bootm xxxx 這個指定的地址xxxx是否與-a指定的載入地址相同。而這個tag建議是由bootloader提供的,在u-boot下預設是由bootm命令建立的.
(1)、在make zImage之後,用u-boot/tools/mkimage這個工具為核心加上u-boot引導所需要的檔案頭:
/mini2440/u-boot-201003-suok/tools/mkimage -n ‘linux-2.6.32’ -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008040 -d zImage uImage.img
(2)、下載核心時:
nand erase 0x80000 300000
nand write 0x30008000 0x80000 300000
set bootcmd ‘nand read 0x30008000 0x80000 300000;bootm 0x30008000’
2、典型的核心映象是zImage,它是經過壓縮的、具備自引導能力的linux核心映象。當CPU跳轉到zImage的時候,第一個執行的是自載入程式;
(1)自載入程式的主要責任是解壓zImage中的vmlinux,並且引導vmlinux;
(2)自載入程式的入口在 arch/$(ARCH)/boot/compressed/head.S檔案中。
它將呼叫函式decompress_kernel(),這個函式在檔案arch/arm/boot/compressed/misc.c中,decompress_kernel()又呼叫proc_decomp_setup(),arch_decomp_setup()進行設定,然後使用在打印出資訊“Uncompressing Linux…”後,呼叫gunzip()。將核心放於指定的位置。

3、 CPU跳轉到vmlinux的入口地址,順序執行核心啟動程式,其中包括:
(1)初始化核心各個子系統;
(2)初始化驅動程式;
(3)掛載根檔案系統;
(4)啟動使用者空間的init程序等。
核心首先檢查在命令列引數中有沒有指定核心執行的第一個應用程式;
如果沒有指定,則順序執行/sbin/init, /etc/init, /bin/init, /bin/sh;
4、 Linux核心在掛載根檔案系統之後,要執行檔案系統中的應用程式。

具體程式碼如下:
1、Start:->2、decompress_kernel->3、call_kernel->
/arch/arm/boot/compress/head.s/(其中decompress_kerne 是在/arch/arm/boot/compress /misc.c 實現)

start: // 1

wont_overwrite: mov r0, r4
mov r3, r7
bl decompress_kernel // 2 呼叫解壓核心映像的C函式
// 在 arch/arm/boot/compressed/misc.c 實現
b call_kernel // 3 呼叫跳轉到核心映像入口的子程式

call_kernel: bl cache_clean_flush // 3
bl cache_off
mov r0, #0
mov r1, r7 @ restore architecture number
mov pc, r4 @ call kernel // 5 呼叫核心

  • r4 = kernel execution address // 6 核心執行的地址

arch/arm/boot/compressed/misc.c
decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p, // 2
int arch_id)
{
arch_decomp_setup(); /解壓前的初始化/
makecrc(); /CRC 校驗/
putstr(“Uncompressing Linux…”);
gunzip(); /*呼叫解壓函式 */
putstr(" done, booting the kernel.\n");
return output_ptr;
}

現在總結一下在進入解壓後的核心入口前都做了些什麼:
(1)儲存從uboot中傳入的引數
(2)執行一段處理器相關的程式碼
(3)接著會判斷一下要不要重定位,我們這裡是不需要重定位,所以開始對bss段清零。
(4)之後初始化頁表,進行1:1對映。因為開啟cache前必須開啟mmu,所以這裡先對頁表進行初始化,然後開啟mmu和cache。
(5)這些都準備好後,判斷一下解壓核心是否會覆蓋未解壓的核心映像。如果會,則進行一些調整,然後開始解壓核心;如果不會,則直接解壓。最後是重新整理cache,關閉mmu和dcache,使 cache和tlb內容無效,跳到解壓後的核心入口執行arm相關的核心程式碼。
4、Stext->5、b start_kernel->6、setup_arch()->7、rest_init()->8、init()->9、do_basic_setup()->10、prepare_namespace()->11、execve()
/arch/arm/kernel/head.s

ENTRY(stext) /* 4 核心入口點 */
。。。
#include “head-common.S”

/arch/arm/kernel/head-common.S
b start_kernel /* 5 由此跳到C 程式碼 */

/init/main.c
asmlinkage void __init start_kernel(void) /* 5 C 程式碼的入口 /
{…
setup_arch(&command_line); /
6 啟用處理器 /

rest_init(); /
7 呼叫此函式,啟動 init 執行緒*/
}

static void noinline rest_init(void)
{
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND); /*3 啟動init 執行緒 */……
}

tatic int __init kernel_init(void * unused)
{
do_basic_setup(); /* 9 初始化裝置驅動*/
……………….
prepare_namespace(); /* 10 掛載根檔案系統*/
………………….
init_post(); /* 啟動程序 /
}
static noinline int init_post(void)
{
run_init_process(execute_command); /
啟動使用者空間的init 程序*/
/init 程序是通過執行根檔案系統中的init程式啟動的/
/*接下來順序執行/sbin/init, /etc/init, /bin/init, /bin/sh; */
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
panic(“No init found. Try passing init= option to kernel.”);
}
init的程序號是1,從這一點就能看出,init程序是系統所有程序的起點,Linux在完成核內引導以後,就開始執行init程式。init程式需要讀取配置檔案/etc/inittab。

static void run_init_process(char init_filename) //核心首先檢查在命令列引數中有沒有指定核心執行的第一個應用程式;
{
argv_init[0] = init_filename;
kernel_execve(init_filename, argv_init, envp_init); /
11 */
}


/arch/arm/kernel/sys_arm.c
int kernel_execve(…)
{
…………
ret = do_execve((char *)filename, (char __user * __user *)argv,
(char __user * _user )envp, &regs); / do execve 是執行使用者空間的程式 */
}

/fs/exec.c
int do_execve(char * filename,…) executes a new program.
{

}

七 、 系統環境變數的設定方法
1、配置路徑
#echo $PATH

vi ~/.bashrc

在其內新增:
export PATH=/usr/local/arm/4.3.2/bin:$PATH
#reboot

2、在編譯的時候配置
#export PATH=/usr/local/arm/3.4.1/bin:$PATH

注意:
如果修改了 .bashrc路徑,需要重新啟動linux

3、編譯之前顯示編譯的版本資訊
#arm-linux-gcc –v

八、實驗步奏(MINI2440的)
1、cp config_mini2440_x35 .config
2、進入核心根目錄看Makefile中關於編譯器的字首是否如下(這裡是OK的,不用改):

3、檢視機器碼和UBOOT中的是否一致,一致核心才能啟動(這裡是OK的,不用改):
uboot/include/asm-arm/mach-types.h #define MACH_TYPE_MINI2440 1999 2.6.32/arch/arm/tools/mach-types mini2440 MACH_MINI2440 MINI2440 1999
檢視UBOOT的資訊也可看到:
即0x7cf=1999
4、make menuconfig
5、make zImage
進入/arch/arm/boot目錄,用u-boot/tools/mkimage這個工具為核心加上u-boot引導所需要的檔案頭:
/mini2440/u-boot-201003-suok/tools/mkimage -n ‘linux-2.6.32’ -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008040 -d zImage uImage.img
(解釋一下引數的意義:(具體可讀mkimage使用詳解.docx )
-A ==> set architecture to ’arch’
-O ==> set operating system to ’os’
-T ==> set image type to ’type’
-C ==> set compression type ’comp’
-a ==> set load address to ’addr’ (hex) 引數後是核心的執行地址
-e ==> set entry point to ’ep’ (hex) 引數後是入口地址
-n ==> set image name to ’name’
-d ==> use image data from ’datafile’

1)如果我們沒用mkimage對核心進行處理的話,那直接把核心下載到0x30008000再執行就行,核心會自解壓執行(不過核心執行需要一個tag來傳遞引數,而這個tag建議是由bootloader提供的,在u-boot下預設是由bootm命令建立的)。
2)如果使用mkimage生成核心映象檔案的話,會在核心的前頭加上了64byte的資訊,供建立tag之用。bootm命令會首先判斷bootm xxxx 這個指定的地址xxxx是否與-a指定的載入地址相同。
(1)如果不同的話會從這個地址開始提取出這個64byte的頭部,對其進行分析,然後把去掉頭部的核心複製到-a指定的load地址中去執行之
(2)如果相同的話那就讓其原封不同的放在那,但-e指定的入口地址會推後64byte,以跳過這64byte的頭部。)

6、下載核心
tftp 0x30008000 uImage.img
(1)下載完後可燒進flash
nand erase 0x80000 300000
nand write 0x30008000 0x80000 300000
set bootcmd ‘nand read 0x30008000 0x80000 300000;bootm 0x30008000’
saveenv
reset
(2)也可以直接跳到剛才下載核心的地址去執行
Bootm 0x30008000

7、設定啟動引數
setenv bootargs root=/dev/nfs nfsroot=192.168.17.253:/opt/rootfs/ ip=192.168.17.100 init=/linuxrc console=ttySAC0,115200 display=sam320
saveenv
reset
6、對W35屏的補充:W35屏是320240的,而X35是240320的,所以如果是W35的屏,應對核心的/arch/arm/mach-s3c2440/mach-mini2440.c 作如下修改,其他的不變:
#elif defined(CONFIG_FB_S3C2410_X240320)
#define LCD_WIDTH 240
#define LCD_HEIGHT 320
為:
#elif defined(CONFIG_FB_S3C2410_X240320)
#define LCD_WIDTH 320
#define LCD_HEIGHT 240
八、實驗步奏(GEC2440的)
1、安裝3.4.1 工作鏈
2、配置路徑
3、解壓核心原碼
#mkdir /root/build_kernel
#mkdir /root/build_kernel/linux (路經無關)
#cd /root/build_kernel/linux

拷貝gec2440-linux-2.6.12.tar.bz2
#tar -jxvf gec2440-linux-2.6.12.tar.bz2

4、檢視makefile

vi makefile

檢視選項:
ARCH :=arm //即開啟arm特有的程式碼
CROSS_COMPILE :=/usr/local/arm/3.4.1/bin/arm-linux-
如果不是,則改過來。

5、使用預設的配置檔案
#cp /arch/arm/configs/smdk2410_defconfig .config
(.config 會自動轉換成 include/linux/autoconf.h 標頭檔案。在 include/linux/config.h 檔案中,將包含使用 include/linux/autoconfig.h 標頭檔案.
另外,.config檔案也會在下面的配置選單中導進來。

(每種參考板都有省缺核心配置檔案,在/arch/$(ARCH)/configs 目錄下。Smdk2410的省缺檔案就是/arch/arm/configs/smdk2410_defconfig )
或者執行如下命令使省缺配置生效:
#make smdk2410_defconfig

6、開啟配置選單,重新調整配置選單
#make menuconfig (此時很多警告!)

SYSTEM TYPE ---->
(0) S3C2410 UART to use for low-level messages
(ctrl + 資料)
7、編譯:
#make

編譯結束,將生成 /vmlinux及 arch/arm/boot/zImage 等。

五、下載核心
#tftp 30008000 zImage
#nand erase 40000 1c0000
#nand write 30008000 40000 1c0000

#setenv bootcmd nand read 30008000 40000 1c0000;go 30008000
#saveenv

補充:Makefile 中變數的賦值
1、“=” 直接賦值

2、“:=” 前面的變數不能使用後面的變數。
例如: y:=$(x)bar
X:=foo
則 y=bar 而不是 y=foobar

3、“?=” 例如: foo ?= bar
如果foo 沒被定義過,則 foo = bar
否則 用之前定義過的值

4、“+=” 將右邊的變數值附加給左邊的變數
例如 foo = string1
Foo+=string2
則 foo = string1string2