天天看點

嵌入式Linux系統移植介紹-四大步驟

最近在學習系統移植的相關知識,在學習和調試過程中,發現了很多問題,也解決了很多問題,但總是對于我們的開發結果有一種莫名其妙的感覺,糾其原因,主要對于我們的開發環境沒有一個深刻的認識,有時候幾個簡單的指令就可以完成非常複雜的功能,可是我們有沒有想過,為什麼會有這樣的效果?如果沒有去追問,隻是機械地完成,并且看到實驗效果,這樣做其實并沒有真正的掌握系統移植的本質。

在做每一個步驟的時候,首先問問自己,為什麼要這樣做,然後再問問自己正在做什麼?搞明白這幾個問題,我覺得就差不多了,以後不管更換什麼平台,什麼晶片,什麼開發環境,你都不會迷糊,很快就會上手。對于嵌入式的學習方法,我個人方法就是:從宏觀上把握(解決為什麼的問題),微觀上研究(解決正在做什麼的問題),下面以自己學習的arm-cortex_a8開發闆為目标,介紹下自己的學習方法和經驗。

嵌入式Linux系統移植主要由四大部分組成:

一、搭建交叉開發環境

二、bootloader的選擇和移植

三、kernel的配置、編譯、和移植

四、根檔案系統的制作

第一部分:搭建交叉開發環境

先介紹第一分部的内容:搭建交叉開發環境,首先必須得思考兩個問題,什麼是交叉環境? 為什麼需要搭建交叉環境?

先回答第一個問題,在嵌入式開發中,交叉開發是很重要的一個概念,開發的第一個環節就是搭建環境,第一步不能完成,後面的步驟從無談起,這裡所說的交叉開發環境主要指的是:在開發主機上(通常是我的pc機)開發出能夠在目标機(通常是我們的開發闆)上運作的程式。嵌入式比較特殊的是不能在目标機上開發程式(狹義上來說),因為對于一個原始的開發闆,在沒有任何程式的情況下它根本都跑不起來,為了讓它能夠跑起來,我們還必須要借助pc機進行燒錄程式等相關工作,開發闆才能跑起來,這裡的pc機就是我們說的開發主機,想想如果沒有開發主機,我們的目标機基本上就是無法開發,這也就是電子行業的一句名言:搞電子,說白了,就是玩電腦!

然後回答第二個問題,為什麼需要交叉開發環境?主要原因有以下幾點:

原因1:嵌入式系統的硬體資源有很多限制,比如cpu主頻相對較低,記憶體容量較小等,想想讓幾百MHZ主頻的MCU去編譯一個Linux kernel會讓我們等的不耐煩,相對來說,pc機的速度更快,硬體資源更加豐富,是以利用pc機進行開發會提高開發效率。

原因2:嵌入式系統MCU體系結構和指令集不同,是以需要安裝交叉編譯工具進行編譯,這樣編譯的目标程式才能夠在相應的平台上比如:ARM、MIPS、               POWEPC上正常運作。

交叉開發環境的硬體組成主要由以下幾大部分:

1.開發主機

2.目标機(開發闆)

3.二者的連結媒體,常用的主要有3中方式:(1)序列槽線 (2)USB線 (3)網線

對應的硬體媒體,還必須要有相應的軟體“媒體”支援:

1.對于序列槽,通常用的有序列槽調試助手,putty工具等,工具很多,功能都差不多,會用一兩款就可以;

2.對于USB線,當然必須要有USB的驅動才可以,一般晶片公司會提供,比如對于三星的晶片,USB下載下傳主要由DNW軟體來完成;

3.對于網線,則必須要有網絡協定支援才可以,常用的服務主要兩個

第一:tftp服務:

      主要用于實作檔案的下載下傳,比如開發調試的過程中,主要用tftp把要測試的bootloader、kernel和檔案系統直接下載下傳到記憶體中運作,而不需要預先燒錄到Flash晶片中,一方面,在測試的過程中,往往需要頻繁的下載下傳,如果每次把這些要測試的檔案都燒錄到Flash中然後再運作也可以,但是缺點是:過程比較麻煩,而且Flash的擦寫次數是由限的;另外一方面:測試的目的就是把這些目标檔案加載到記憶體中直接運作就可以了,而tftp就剛好能夠實作這樣的功能,是以,更沒有必要把這些檔案都燒錄到Flash中去

第二:nfs服務:

      主要用于實作網絡檔案的挂載,實際上是實作網絡檔案的共享,在開發的過程中,通常在系統移植的最後一步會制作檔案系統,那麼這是可以把制作好的檔案系統放置在我們開發主機PC的相應位置,開發闆通過nfs服務進行挂載,進而測試我們制作的檔案系統是否正确,在整個過程中并不需要把檔案系統燒錄到Flash中去,而且挂載是自動進行挂載的,bootload啟動後,kernel運作起來後會根據我們設定的啟動參數進行自動挂載,是以,對于開發測試來講,這種方式非常的友善,能夠提高開發效率。

      另外,還有一個名字叫samba的服務也比較重要,主要用于檔案的共享,這裡說的共享和nfs的檔案共享不是同一個概念,nfs的共享是實作網絡檔案的共享,而samba實作的是開發主機上Windows主機和Linux虛拟機之間的檔案共享,是一種跨平台的檔案共享,友善的實作檔案的傳輸。

以上這幾種開發的工具在嵌入式開發中是必備的工具,對于嵌入式開發的效率提高做出了偉大的貢獻,是以,要對這幾個工具熟練使用,這樣你的開發效率會提高很多。等測試完成以後,就會把相應的目标檔案燒錄到Flash中去,也就是等釋出産品的時候才做的事情,是以對于開發人員來說,所有的工作永遠是測試。

      通過前面的工作,我們已經準備好了交叉開發環境的硬體部分和一部分軟體,最後還缺少交叉編譯器,讀者可能會有疑問,為什麼要用交叉編譯器?前面已經講過,交叉開發環境必然會用到交叉編譯工具,通俗地講就是在一種平台上編譯出能運作在體系結構不同的另一種平台上的程式,開發主機PC平台(X86 CPU)上編譯出能運作在以ARM為核心的CPU平台上的程式,編譯得到的程式在X86 CPU平台上是不能運作的,必須放到ARM CPU平台上才能運作,雖然兩個平台用的都是Linux系統。相對于交叉編譯,平常做的編譯叫本地編譯,也就是在目前平台編譯,編譯得到的程式也是在本地執行。用來編譯這種跨平台程式的編譯器就叫交叉編譯器,相對來說,用來做本地編譯的工具就叫本地編譯器。是以要生成在目标機上運作的程式,必須要用交叉編譯工具鍊來完成。

      這裡又有一個問題,不就是一個交叉編譯工具嗎?為什麼又叫交叉工具鍊呢?原因很簡單,程式不能光編譯一下就可以運作,還得進行彙編和連結等過程,同時還需要進行調試,對于一個很大工程,還需要進行工程管理等等,是以,這裡 說的交叉編譯工具是一個由編譯器、連接配接器和解釋器組成的綜合開發環境,交叉編譯工具鍊主要由binutils(主要包括彙程式設計式as和連結程式ld)、gcc(為GNU系統提供C編譯器)和glibc(一些基本的C函數和其他函數的定義) 3個部分組成。有時為了減小libc庫的大小,也可以用别的 c 庫來代替 glibc,例如 uClibc、dietlibc 和 newlib。

      那麼,如何得到一個交叉工具鍊呢?是從網上下載下傳一個“程式”然後安裝就可以使用了嗎?回答這個問題之前先思考這樣一個問題,我們的交叉工具鍊顧名思義就是在PC機上編譯出能夠在我們目标開發平台比如ARM上運作的程式,這裡就又有一個問題了,我們的ARM處理器型号非常多,難道有專門針對我們某一款的交叉工具鍊嗎?若果有的話,可以想一想,這麼多處理器平台,每個平台專門定制一個交叉工具鍊放在網絡上,然後供大家去下載下傳,想想可能需要找很久才能找到适合你的編譯器,顯然這種做法不太合理,且浪費資源!是以,要得到一個交叉工具鍊,就像我們移植一個Linux核心一樣,我們隻關心我們需要的東西,編譯我們需要的東西在我們的平台上運作,不需要的東西我們不選擇不編譯,是以,交叉工具鍊的制作方法和系統移植有着很多相似的地方,也就是說,交叉開發工具是一個支援很多平台的工具集的集合(類似于Linux源碼),然後我們隻需從這些工具集中找出跟我們平台相關的工具就行了,那麼如何才能找到跟我們的平台相關的工具,這就是涉及到一個如何制作交叉工具鍊的問題了。

通常建構交叉工具鍊有如下三種方法:

方法一 :分步編譯和安裝交叉編譯工具鍊所需要的庫和源代碼,最終生成交叉編譯工具鍊。該方法相對比較困難,适合想深入學習建構交叉工具鍊的讀者。如果隻是想使用交叉工具鍊,建議使用下列的方法二建構交叉工具鍊。

方法二: 通過Crosstool-ng腳本工具來實作一次編譯,生成交叉編譯工具鍊,該方法相對于方法一要簡單許多,并且出錯的機會也非常少,建議大多數情況下使用該方法建構交叉編譯工具鍊。

方法三 :直接通過網上下載下傳已經制作好的交叉編譯工具鍊。該方法的優點不用多說,當然是簡單省事,但與此同時該方法有一定的弊端就是局限性太大,因為畢竟是别人建構好的,也就是固定的,沒有靈活性,是以建構所用的庫以及編譯器的版本也許并不适合你要編譯的程式,同時也許會在使用時出現許多莫名其妙的錯誤,建議讀者慎用此方法。

     crosstool-ng是一個腳本工具,可以制作出适合不同平台的交叉編譯工具鍊,在進行制作之前要安裝一下軟體:

     $ sudo apt-get install  g++  libncurses5-dev  bison  flex  texinfo automake  libtool  patch  gcj  cvs  cvsd  gawk 

     crosstool腳本工具可以在http://ymorin.is-a-geek.org/projects/crosstool下載下傳到本地,然後解壓,接下來就是進行安裝配置了,這個配置優點類似核心的配置。主要的過程有以下幾點:

     1. 設定源碼包路徑和交叉編譯器的安裝路徑

     2. 

修改交叉編譯器針對的構架

修改交叉編譯器針對的構架 

     3. 增加編譯時的并行程序數,以增加運作效率,加快編譯,因為這個編譯會比較慢。

     4. 關閉JAVA編譯器 ,減少編譯時間

     5. 編譯

     6. 添加環境變量

     7. 重新整理環境變量。

     8. 測試交叉工具鍊

     到此,嵌入式Linux系統移植四大部分的第一部分工作全部完成,接下來可以進行後續的開發了。

第二部分:bootloader的選擇和移植

一、Boot Loader 概念

       就是在作業系統核心運作之前運作的一段小程式。通過這段小程式,我們可以初始化硬體裝置、建立記憶體空間的映射圖,進而将系統的軟硬體環境帶到一個合适的狀态,以便為最終調用作業系統核心準備好正确的環境,他就是所謂的引導加載程式(Boot Loader)。

嵌入式Linux系統移植介紹-四大步驟

【圖1】Flash存儲中存放檔案的分布圖

 二、為什麼系統移植之前要先移植BootLoader?

      BootLoader的任務是引導作業系統,所謂引導作業系統,就是啟動核心,讓核心運作就是把核心加載到記憶體RAM中去運作,那先問兩個問題:第一個問題,是誰把核心搬到記憶體中去運作?第二個問題:我們說的記憶體是SDRAM,大家都知道,這種記憶體和SRAM不同,最大的不同就是SRAM隻要系統上電就可以運作,而SDRAM需要軟體進行初始化才能運作,那麼在把核心搬運到記憶體運作之前必須要先初始化記憶體吧,那麼記憶體是由誰來初始化的呢?其實這兩件事情都是由bootloader來幹的,目的是為核心的運作準備好軟硬體環境,沒有bootloadr我們的系統當然不能跑起來。

三、bootloader的分類。

      首先更正一個錯誤的說法,很多人說bootloader就是U-boot,這種說法是錯誤的,确切來說是u-boot是bootloader的一種。也就是說bootloader具有很多種類,大概的分類如下圖所示:

嵌入式Linux系統移植介紹-四大步驟

【圖2】bootloader分類圖

      由上圖可以看出,不同的bootloader具有不同的使用範圍,其中最令人矚目的就是有一個叫U-Boot的bootloader,是一個通用的引導程式,而且同時支援X86、ARM和PowerPC等多種處理器架構。U-Boot,全稱 Universal Boot Loader,是遵循GPL條款的開放源碼項目,是由德國DENX小組開發的用于多種嵌入式CPU的bootloader程式,對于Linux的開發,德國的u-boot做出了巨大的貢獻,而且是開源的。

      u-boot具有以下特點:

      ① 開放源碼;

      ② 支援多種嵌入式作業系統核心,如Linux、NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS;

      ③ 支援多個處理器系列,如PowerPC、ARM、x86、MIPS、XScale;

      ④ 較高的可靠性和穩定性;

      ⑤ 高度靈活的功能設定,适合U-Boot調試、作業系統不同引導要求、産品釋出等;

      ⑥ 豐富的裝置驅動源碼,如序列槽、以太網、SDRAM、FLASH、LCD、NVRAM、EEPROM、RTC、鍵盤等;

     ⑦ 較為豐富的開發調試文檔與強大的網絡技術支援;

      其實,把u-boot可以了解為是一個小型的作業系統。

四、u-boot的目錄結構

      * board 目标闆相關檔案,主要包含SDRAM、FLASH驅動;

      * common 獨立于處理器體系結構的通用代碼,如記憶體大小探測與故障檢測;

      * cpu 與處理器相關的檔案。如mpc8xx子目錄下含序列槽、網口、LCD驅動及中斷初始化等檔案;

      * driver 通用裝置驅動,如CFI FLASH驅動(目前對INTEL FLASH支援較好)

      * doc U-Boot的說明文檔;

      * examples可在U-Boot下運作的示例程式;如hello_world.c,timer.c;

      * include U-Boot頭檔案;尤其configs子目錄下與目标闆相關的配置頭檔案是移植過程中經常要修改的檔案;

      * lib_xxx 處理器體系相關的檔案,如lib_ppc, lib_arm目錄分别包含與PowerPC、ARM體系結構相關的檔案;

      * net 與網絡功能相關的檔案目錄,如bootp,nfs,tftp;

      * post 上電自檢檔案目錄。尚有待于進一步完善;

      * rtc RTC驅動程式;

      * tools 用于建立U-Boot S-RECORD和BIN鏡像檔案的工具;

五、u-boot的工作模式

      U-Boot的工作模式有啟動加載模式和下載下傳模式。啟動加載模式是Bootloader的正常工作模式,嵌入式産品釋出時,Bootloader必須工作在這種模式下,Bootloader将嵌入式作業系統從FLASH中加載到SDRAM中運作,整個過程是自動的。下載下傳模式就是Bootloader通過某些通信手段将核心映像或根檔案系統映像等從PC機中下載下傳到目标闆的SDRAM中運作,使用者可以利用Bootloader提供的一些令接口來完成自己想要的操作,這種模式主要用于測試和開發。

六、u-boot的啟動過程

      大多數BootLoader都分為stage1和stage2兩大部分,U-boot也不例外。依賴于cpu體系結構的代碼(如裝置初始化代碼等)通常都放在stage1且可以用彙編語言來實作,而stage2則通常用C語言來實作,這樣可以實作複雜的功能,而且有更好的可讀性和移植性。

1、 stage1(start.s代碼結構)

 U-boot的stage1代碼通常放在start.s檔案中,它用彙編語言寫成,其主要代碼部分如下:

(1) 定義入口。由于一個可執行的image必須有一個入口點,并且隻能有一個全局入口,通常這個入口放在rom(Flash)的0x0位址,是以,必須通知編譯器以使其知道這個入口,該工作可通過修改連接配接器腳本來完成。

(2)設定異常向量(exception vector)。

(3)設定CPU的速度、時鐘頻率及中斷控制寄存器。

(4)初始化記憶體控制器 。

(5)将rom中的程式複制到ram中。

(6)初始化堆棧 。

(7)轉到ram中執行,該工作可使用指令ldrpc來完成。

2、 stage2(C語言代碼部分)

lib_arm/board.c中的start armboot是C語言開始的函數,也是整個啟動代碼中C語言的主函數,同時還是整個u-boot(armboot)的主函數,該函數主要完成如下操作:

(1)調用一系列的初始化函數。

(2)初始化flash裝置。

(3)初始化系統記憶體配置設定函數。

(4)如果目标系統擁有nand裝置,則初始化nand裝置。

(5)如果目标系統有顯示裝置,則初始化該類裝置。

(6)初始化相關網絡裝置,填寫ip,c位址等。

(7)進入指令循環(即整個boot的工作循環),接受使用者從序列槽輸入的指令,然後進行相應的工作。

七、基于cortex-a8的s5pc100bootloader啟動過程分析

s5pc100支援兩種啟動方式,分别為USB啟動方式和NandFlash啟動方式:

1. S5PC100 USB啟動過程

[1] A8 reset, 執行iROM中的程式

[2] iROM中的程式根據S5PC100的配置管腳(SW1開關4,撥到4對面),判斷從哪裡啟動(USB)

[3] iROM中的程式會初始化USB,然後等待PC機下載下傳程式

[4] 利用DNW程式,從PC機下載下傳SDRAM的初始化程式到iRAM中運作,初始化SDRAM

[5] SDRAM初始化完畢,iROM中的程式繼續接管A8, 然後等待PC下載下傳程式(BootLoader)

[6] PC利用DNW下載下傳BootLoader到SDRAM

[7] 在SDRAM中運作BootLoader

2. S5PC100 Nandflash啟動過程

[1] A8 reset, 執行IROM中的程式

[2] iROM中的程式根據S5PC100的配置管腳(SW1開關4,撥到靠4那邊),判斷從哪裡啟動(Nandflash)

[3] iROM中的程式驅動Nandflash

[4] iROM中的程式會拷貝Nandflash前16k到iRAM

[5] 前16k的程式(BootLoader前半部分)初始化SDRAM,然後拷貝完整的BootLoader到SDRAM并運作

[6] BootLoader拷貝核心到SDRAM,并運作它

[7] 核心運作起來後,挂載rootfs,并且運作系統初始化腳本

八、u-boot移植(基于cortex_a8的s5pc100為例)

1.建立自己的平台

(1).下載下傳源碼包2010.03版本,比較穩定

(2).解壓後添加我們自己的平台資訊,以smdkc100為參考版,移植自己s5pc100的開發闆

(3).修改相應目錄的檔案名,和相應目錄的Makefile,指定交叉工具鍊。

(4).編譯

(5).針對我們的平台進行相應的移植,主要包括修改SDRAM的運作位址,從0x20000000

(6).“開關”相應的宏定義

(7).添加Nand和網卡的驅動代碼

(8).優化go指令

(9).重新編譯 make distclean(徹底删除中間檔案和配置檔案) make s5pc100_config(配置我們的開發闆)   make(編譯出我們的u-boot.bin鏡像檔案)

(10).設定環境變量,即啟動參數,把編譯好的u-boot下載下傳到記憶體中運作,過程如下:

1. 配置開發闆網絡

       ip位址配置:

       $setenv ipaddr 192.168.0.6               配置ip位址到記憶體的環境變量

       $saveenv                                 儲存環境變量的值到nandflash的參數區

       網絡測試:

       在開發開發闆上ping虛拟機:

       $ ping 192.168.0.157(虛拟機的ip位址)

       如果網絡測試失敗,從下面幾個方面檢查網絡:

       1. 網線連接配接好

       2. 開發闆和虛拟機的ip位址是否配置在同一個網段

       3. 虛拟機網絡一定要采用橋接(VM--Setting-->option)

       4. 連接配接開發闆時,虛拟機需要設定成靜态ip位址

    2. 在開發闆上,配置tftp伺服器(虛拟機)的ip位址

       $setenv serverip 192.168.0.157(虛拟機的ip位址)

       $saveenv

    3. 拷貝u-boot.bin到/tftpboot(虛拟機上的目錄)

    4. 通過tftp下載下傳u-boot.bin到開發闆記憶體

       $ tftp 20008000(記憶體位址即可) u-boot.bin(要下載下傳的檔案名)

       如果上面的指令無法正常下載下傳:

       1. serverip配置是否正确

       2. tftp服務啟動失敗,重新開機tftp服務

          #sudo service tftpd-hpa restart

    5. 燒寫u-boot.bin到nandflash的0位址

       $nand erase 0(起始位址)  40000(大小)                    擦出nandflash 0 - 256k的區域

       $nand write 20008000((緩存u-boot.bin的記憶體位址) 0(nandflash上u-boot的位置) 40000(燒寫大小)

    6. 切換開發闆的啟動方式到nandflash

       1. 關閉開發闆

       2. 把SW1的開關4撥到4的那邊

       3. 啟動開發闆,它就從nandflash啟動

第三部分:kernel的配置、編譯、和移植

一、将下載下傳好的linux-2.6.35.tar.bz2拷貝到主目錄下解壓

二、修改頂層目錄下的Makefile,主要修改平台的體系架構和交叉編譯器,代碼如下:

      ARCH    ?= $(SUBARCH)

      CROSS_COMPILE  ?=

      CROSS_COMPILE  ?= $(CONFIG_CROSS_COMPILE:"%"=%)

      修改以上代碼為:

      ARCH    ?= arm                                                       ---->體系架構是arm架構

     CROSS_COMPILE  ?= arm-cortex_a8-linux-gnueabi-    ---->交叉編譯器是arm-cortex_a8平台的

      注意:這兩個變量值會直接影響頂層Makefile的編譯行為,即選擇編譯哪些代碼,用什麼編譯器進行編譯。

三、拷貝标準版配置檔案,目的是得到跟我們開發闆相關的配置資訊。

$ cp arch/arm/configs/s5pc100_defconfig    .config

      這裡拷貝arch/arm/configs/s5pc100_defconfig到  .config檔案是選取跟我們開發闆相關的代碼。因為Linux支援的平台非常非常多,不僅僅是ARM處理器,當然我們編譯的時候隻需要編譯跟我們平台相關的代碼就可以了,平台相關的不需要編譯,那麼就有個問題,Linux系統中的源代碼檔案有一萬多以個,面對這麼龐大的檔案數量,我們如何去選擇呢?

       其實,我們擔心的問題也是寫作業系統的那哥們早就擔心過的問題了,隻不過人家已經把這個問題幫我們解決了,我們隻需進行很簡單的操作,就可以選擇出我們要編譯的代碼,具體的方法就是把相應平台的_deconfig直接拷貝到頂層目錄的.config檔案中,這樣.config檔案中就記錄了我們要移植平台的平台資訊,因為在配置核心時,系統會把所有的配置資訊都儲存在頂層目錄的.config檔案中。注意在第一次,進行make menuconfig時,系統會根據我們選取的平台資訊自動選取相關的代碼和子產品,是以我們隻需要進入然後再退出,選擇儲存配置資訊就行了,系統會把這些跟我們移植平台相關的所有配置資訊全部儲存在頂層目錄的.config檔案中。

四、配置核心

      $make menuconfig

     注意:第一次進去,不做任何操作,直接推出,在推出時提示是否儲存配置資訊,一定要儲存配置資訊,點選“YES”。這樣我們的.config中就已經儲存了我們開發平台的資訊。

       在這個環節,我們需要關心一個問題,make menuconfig時,系統到低都做了哪些事情?為什麼會出現圖形化的界面?圖形化的界面中的相關内容是從哪裡來的?

        圖形化的界面當然是由一個特殊的圖形庫來實作的,還記得第一次make menuconfig時,系統并沒有出現圖形化的界面,而是報錯了,并且提示我們缺少 ncurses-devel ,此時隻需要按照要求安裝一個libncurses5-dev就行了,sudo apt-get install libncurses5-dev,有了這個圖形化庫的支援,我們才能夠正常顯示圖形化界面。

       好了,圖形化界面的問題解決了,那還有另外一個問題就是圖形化界面裡面的内容是從哪裡來的?要回答這個問題,我們就要提一下Linux核心的設計思想了,Linux 核心是以子產品的方式來組織這個作業系統的,那麼,為什麼要用子產品的方式來組織呢?子產品的概念又是什麼呢?在此來一一回答這個問題。

      Linux2.6核心的源碼樹目錄下一般都會有兩個檔案:Kconfig和Makefile。分布在各目錄下的Kconfig構成了一個分布式的核心配置資料庫,每個Kconfig分别描述了所屬目錄源檔案相關的核心配置菜單。每個目錄都會存放功能相對獨立的資訊,在每個目錄中會存放各個不同的子產品資訊,比如在/dev/char/目錄下就存放了所有字元裝置的驅動程式,而這些程式代碼在核心中是以子產品的形式存在的,也就是說當系統需要這個驅動的時候,會把這個驅動以子產品的方式編譯到系統的核心中,編譯分為靜态編譯和動态編譯,靜态編譯核心體積比動态編譯的體積要大,前面已經說了每個目錄下面都會有一個Kconfig的檔案,我們還會問,這個檔案中都存放了什麼資訊?前面說了,每個目錄的Kconfig檔案描述了所屬目錄源檔案相關的核心配置菜單,有其特殊的文法格式,圖形化界面的文字正是從這個檔案中讀取出來的,如果把這個檔案中的相應目錄檔案的資訊全部删除,那麼在圖形化界面中将看不到該子產品的資訊,是以也不能進行子產品的配置。

       在核心配置make menuconfig(或xconfig等)時,系統會自動從Kconfig中讀出配置菜單,使用者配置完後儲存到.config(在頂層目錄下生成)中。在核心編譯時,主Makefile調用這個.config,(.config的重要性就展現在,它儲存了我們的所有的配置資訊,是我們選取源代碼并且進行編譯源代碼的最終依據!!!)就知道了使用者對核心的配置情況。上面的内容說明:Kconfig就是對應着核心的配置菜單。假如要想添加新的驅動到核心的源碼中,可以通過修改Kconfig來增加對我們驅動的配置菜單,這樣就有途徑選擇我們的驅動,假如想使這個驅動被編譯,還要修改該驅動所在目錄下的Makefile。是以,一般添加新的驅動時需要修改的檔案有兩種,即:Kconfig 和相應目錄的Makefile(注意不隻是兩個),系統移植的重要内容就是給核心添加和删除相應的子產品,是以主要修改的核心檔案就是Kconfig 和相應目錄的Makefile這兩個檔案。

五、編譯核心

      $make zImage

       通過上述操作我們能夠在 arch/arm/boot 目錄下生成一個 zImage 檔案,這就是經過壓縮的核心鏡像。

       核心的編譯過程是非常複雜的,注意這裡的編譯是靜态編譯,此時會執行頂層目錄下的Makefile中的zImage指令,在執行的過程中,會根據目前目錄的.config檔案去選擇編譯源代碼。編譯核心的具體步驟比較複雜,有時間會另寫文章較長的描述。

六、通過tftp網絡服務下載下傳測試核心

       setenv bootcmd tftp 20008000(記憶體位址) zImage\;go 20008000

       setenv bootargs nfs nfsroot=192.168.1.199(虛拟機的ip):/source/rootfs ip=192.168.1.200(開發闆的ip)  init=/linuxrc(第一個要啟動的使用者程序) ttySAC0,115200(設定中斷為序列槽1,波特率為:115200)     

       儲存環境變量,複位開發闆,測試是否能夠正常啟動(注意:在此之前應設定好需要nfs挂載的檔案系統,最後才能看到效果).核心測試和啟動過程也是比較複雜的,在後續的文章中會詳細介紹。

第四部分:根檔案系統的介紹

    由本文的第一張圖:Flash存儲中存放檔案的分布圖可知,檔案系統的制作和移植是系統移植的最後一道工序了,在這裡首先要提幾個問題:

    1.什麼是檔案系統?

    2.如何實作檔案系統?

    3.常用的檔案系統有哪些?為什麼需要這些檔案系統?

    下面來一一回答這些問題:

檔案系統我們在日常生活中則很少聽說,但是它确實存在,隻是名字不叫檔案系統罷了,一般叫資料庫。資料庫裡面的檔案衆多,我們如何快速準确的找到我們要的那份檔案呢?資料庫采用了分類索引的方法來實作快速查找。類似于我們學校圖書館的管理方式,一樓可能是哲學類,二樓是社科類的,三樓是電子類的,四樓是計算機類的…………等等,我們把這種進行了分類索引的資料庫叫檔案系統。

    對于計算機而言,檔案其實就是資料資料,隻能存儲在實體媒體上面,比如:硬碟,但是我們人不可能自己讀取實體媒體上的檔案,或者自己把檔案寫入實體媒體,實體媒體上檔案的讀寫隻能采用程式來完成,為了友善實作,程式又被分成了實體媒體驅動程式、内容存儲程式和檔案内容存儲程式。實體媒體驅動程式專門用于從實體媒體上存取資料;内容存儲程式用于把檔案内容和檔案屬性資訊打包;檔案内容存儲程式用于把使用者輸入形成檔案内容,或者取得檔案内容顯示出來。

我們可以把一個檔案系統(倒樹)分解成多個檔案系統(倒樹)分别存放到存儲媒體上,比如:一個存儲到CD光牒裡,一個存儲到硬碟中,在使用時,我們把CD光牒裡的檔案系統的根目錄挂到硬碟檔案系統的一個目錄下面,這樣通路這個目錄就相當于是通路CD光牒的根目錄了,找到了根目錄,我們也就可以通路整個CD光牒上的檔案系統了。

“在Linux系統中一切皆是檔案”這句話是我們學習Linux系統的時候常常聽到的一句話。雖然有些誇張,但是它揭示了檔案系統對于Linux系統的重要性;實際上檔案系統對于所有的作業系統都很重要,因為它們把大部分的硬體裝置和軟體資料以檔案的形式進行管理。Linux系統對裝置和資料的管理架構圖如下:

嵌入式Linux系統移植介紹-四大步驟

【圖3】檔案系統實作

[說明]

A. VFS(virtual file system)是虛拟檔案系統,它管理特殊檔案(虛拟檔案)、磁盤檔案和裝置檔案

B. fs_operations結構是由一系列檔案操作接口函數組成,由檔案系統層來完成,為VFS提供檔案操作;

C. 在檔案系統層,磁盤檔案要實作各種檔案系統(如:ext2),裝置檔案要實作各種抽象的裝置驅動

D. 在裝置驅動層,磁盤驅動要實作各種磁盤的驅動程式,其他裝置驅動要實作具體的裝置驅動

E. 實體層就是裝置自身

   為什麼會有不同的檔案類型?

由于存儲媒體有很多種,是以沒有辦法用一種統一的格式存放檔案系統到各種不同的存儲媒體上,而是需要多種不同的存儲格式來适應各種存儲媒體的特性,以求達到存取效率和空間使用率的最優化,這樣就需要對每種存儲格式制定一個規範,這寫規範就叫檔案系統類型。常見的檔案系統類型有:

1.Dos

  FAT16

2.windows

  FAT16、FAT32、NTFS

3.Linux

  Minix、ext、ext2 、ext3 、ISO9660 、jffs2, yaffs, yaffs2、cramfs, romfs, ramdisk, rootfs、proc、sysfs、usbfs、devpts、 tmpfs & ramfs、 NFS

    由此可見,Linux支援的檔案系統最多。以不同的媒體來分類,如下所示:

?  磁盤

    FAT16、 FAT16、FAT32、NTFS、ext、ext2 、ext3、Minix

?  CD光牒

    ISO9660、

?  Flash

    jffs2, yaffs, yaffs2、cramfs, romfs

?  記憶體

    Ramdisk、tmpfs & ramfs

?  虛拟

    rootfs、proc、sysfs、usbfs、devpts、NFS

常用的存儲媒體理論上都可以用于存儲Linux支援的檔案系統;因為我們這裡隻研究嵌入式系統,而嵌入式系統由于體積和移動特性的限制,不能采用磁盤和CD光牒,是以隻能采用flash類的儲存設備、記憶體和虛拟儲存設備作為檔案系統的存儲媒體; 

flash晶片的驅動程式是由系統來提供,是以它的存取特點完全是flash自身的特點,這時最好有更加适合flash的檔案系統——Jffs、Yaffs、Cramfs和Romfs。這些檔案系統都是嵌入式Linux系統中常用的檔案系統,可以根據特點來選擇使用它們,特點如下:

共同點

基于MTD驅動

Jffs

  A.針對NOR Flash的實作

  B.基于哈希表的日志型檔案系統

  C.采取損耗平衡技術,每次寫入時都會盡量使寫入的位置均勻分布

  D.可讀寫,支援資料壓縮

  E.崩潰/掉電安全保護

  F.當檔案系統已滿或接近滿時,因為垃圾收集的關系,運作速度大大放慢

Yaffs

  A.針對Nand Flash的實作

  B.日志型檔案系統

  C.采取損耗平衡技術,每次寫入時都會盡量使寫入的位置均勻分布

  D.可讀寫,不支援資料壓縮

  E.挂載時間短,占用記憶體小

  F.自帶Nandflash驅動,可以不使用VFS和MTD

Cramfs

  A.單頁壓縮,支援随機通路,壓縮比高達2:1

  B.速度快,效率高

  C.隻讀,有利于保護檔案系統免受破壞,提高了系統的可靠性,但是無法對其内容進行擴充

Romfs

  A.簡單的、緊湊的、隻讀的檔案系統 

  B.順序存放資料,因而支援應用程式以XIP(execute In Place,片内運作)方式運作,在系統運作時,節省RAM空間 

    特有的檔案系統類型:Ramdisk檔案系統

    在Linux系統中,記憶體經常用于存儲檔案系統,這種叫做Ramdisk,Ramdisk有兩種,一種是完全把記憶體看成實體存儲媒體,利用記憶體模拟磁盤,運用磁盤的檔案系統類型;另一種隻是在記憶體中存儲了檔案系統邏輯結構,運用tmpfs & ramfs檔案系統類型:

    tmpfs & ramfs

    1. 概述

    用實體記憶體模拟磁盤分區,挂載這種分區後,就可以跟讀寫磁盤檔案一樣讀寫這裡面的檔案,但是操作速度要比磁盤檔案快得多;是以一般應用在下面幾個方面:

    1)讀寫速度要求快的檔案應該放在這種檔案系統中

    2)磁盤分區為flash的情況下,把需要經常讀寫的檔案放在這種檔案系統中,然後定期寫回flash

    3)系統中的臨時檔案,如/tmp、/var目錄下的檔案應該放在這種檔案系統中

    4)/dev裝置檔案(因為裝置檔案随驅動和裝置的加載和解除安裝而變化),應該放在這種檔案系統中

    2. 特點 

    1)由于資料都存放在實體記憶體中,是以系統重新開機後,這個檔案系統中的資料會全部丢失

    2)ramfs在沒有指定最大的大小值情況下,會自動增長,直到用掉系統中所有的實體記憶體為止,這時會導緻系統的崩潰,建議挂載時最好限定其最大的大小值

    3)tmpfs如果指定了大小值,自動增長至大小值後,系統會限定它的大小;這個檔案系統占用的實體記憶體頁可以背置換到swap分區,但是ramfs不行

    不同的檔案系統具有不同的制作方法,有的比較複雜,有的比較簡單,在此由于篇幅限制,先不做介紹,在後續的文章中會單獨介紹檔案系統的制作。

    寫了一天,終于寫完了,總結了一下最近學的系統移植方面的知識,不是很詳細,隻是從宏觀上去把握和了解系統移植的過程,在此做一個記錄,以備後忘。

最近在學習系統移植的相關知識,在學習和調試過程中,發現了很多問題,也解決了很多問題,但總是對于我們的開發結果有一種莫名其妙的感覺,糾其原因,主要對于我們的開發環境沒有一個深刻的認識,有時候幾個簡單的指令就可以完成非常複雜的功能,可是我們有沒有想過,為什麼會有這樣的效果?如果沒有去追問,隻是機械地完成,并且看到實驗效果,這樣做其實并沒有真正的掌握系統移植的本質。

在做每一個步驟的時候,首先問問自己,為什麼要這樣做,然後再問問自己正在做什麼?搞明白這幾個問題,我覺得就差不多了,以後不管更換什麼平台,什麼晶片,什麼開發環境,你都不會迷糊,很快就會上手。對于嵌入式的學習方法,我個人方法就是:從宏觀上把握(解決為什麼的問題),微觀上研究(解決正在做什麼的問題),下面以自己學習的arm-cortex_a8開發闆為目标,介紹下自己的學習方法和經驗。

嵌入式Linux系統移植主要由四大部分組成:

一、搭建交叉開發環境

二、bootloader的選擇和移植

三、kernel的配置、編譯、和移植

四、根檔案系統的制作

第一部分:搭建交叉開發環境

繼續閱讀