Linux內核移植和根文件系統製作(詳細步驟精講)

第一章移植內核

1.1 Linux內核基礎知識
1.1.1 Linux版本
1.1.2 什麼是標準內核
1.1.3 Linux操作系統的分類
1.1.4 linux內核的選擇
1.2 Linux內核啓動過程概述
1.2.1 Bootloader啓動過程
1.2.2 Linux啓動過程
1.3 Linux內核移植
1.3.1 移植內核和根件系統準備工作
1.3.2 修改Linux源碼中參數
1.3.3 配置Linux內核
1.3.4、編譯內核
第二章製作根文件系統
2.1 根文件系統預備知識
2.2、構建根文件按系統
2.2.1、建立根文件系統目錄
2.2.2、建立動態鏈接庫
2.2.3 交叉編譯Bosybox
2.2.4 建立etc目錄下的配置文件
2.2.5 製作根文件系統映像文件
第三章啓動系統
第四章總結
  
第一章移植內核
1.1 Linux內核基礎知識
在動手進行Linux內核移植之前,非常有必要對Linux內核進行一定的瞭解,下面從Linux內核的版本和分類說起。
1.1.1  Linux版本
Linux內核的版本號可以從源代碼的頂層目錄下的Makefile中看到,比如2.6.29.1內核的Makefile中:
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 29
EXTRAVERSION = .1

其中的“VERSION”和“PATCHLEVEL”組成主版本號,比如2.42.52.6等,穩定版本的德主版本號用偶數表示(比如2.6的內核),開發中的版本號用奇數表示(比如2.5),它是下一個穩定版本內核的前身。“SUBLEVEL”稱爲次版本號,它不分奇偶,順序遞增,每隔1~2個月發佈一個穩定版本。“EXTRAVERSION”稱爲擴展版本號,它不分奇偶,順序遞增,每週發佈幾次擴展本版號。
1.1.2什麼是標準內核
按照資料上的習慣說法,標準內核(或稱基礎內核)就是指主要在http://www.kernel.org/維護和獲取的內核,實際上它也有平臺屬性的。這些linux內核並不總是適用於所有linux支持的體系結構。實際上,這些內核版本很多時候並不是爲一些流行的嵌入式linux系統開發的,也很少運行於這些嵌入式linux系統上,這個站點上的內核首先確保的是在Intel X86體系結構上可以正常運行,它是基於X86處理器的內核,如對 linux-2.4.18.tar.bz2的配置make menuconfig時就可以看到,Processor type and features--->中只有386486586/K5/5x86/6x86/6x86MXPentium-ClassicPentium-MMXPentium-Pro/Celeron/Pentium-IIPentium-III/Celeron(Coppermine)Pentium-4K6/K6-II/K6-III Athlon/Duron/K7 Elan CrusoeWinchip-C6 Winchip-2 Winchip-2A/Winchip-3 CyrixIII/C3 選項,而沒有類似Samsun 2410等其他芯片的選擇。如果需要用在其他特定的處理器平臺上就需要對內核進行打補丁,形成不同的嵌入式內核。實際上,不同處理器系統的內核下載站點中提供的也往往是補丁patch而已,故原x86平臺上的內核變成了基礎內核,也被稱爲標準內核了。
1.1.3 Linux操作系統的分類
第一層次分類:以主要功能差異和發行組織區分(基礎linux系統/內核)
1、標準linux
2、μClinux
MMU支持的linux系統,運行在無MMUCPU上。
3Linux-RT
是最早在linux上實現硬實時支持的linux發行版本。
4Linux/RTAI
支持硬實時的linux,於RT-linux最大的不同之處在於RTAI定義了RTHAL,它將RTAI需要在linux中修改的部分定義成一組API接口,RTAI只使用API接口與linux交互。
5Embedix
Lineo公司開發,基於PowerPCx86平臺開發的。
6Blue Cat Linux
7Hard Hat Linux
8、其他
第二層分類:以應用的嵌入式平臺區分(嵌入式linux系統/內核,使上面第一類中的各種linux系統擴展爲對特定目標硬件的支持,成爲一種具體的嵌入式linux系統)
由於嵌入式系統的發展與linux內核的發展是不同步的,所以爲了要找一個能夠運行於目標系統上的內核,需要對內核進行選擇、配置和定製。因爲每一種系統都是國際上不同的內核開發小組維護的,因此選擇linux內核源碼的站點也不盡相同。
第二層分類中的linux系統/內核相對於第一層分類的標準內核來說,也可以稱爲嵌入式linxu系統/內核。如應用在ARM平臺上的嵌入式Linux系統通常有arm-linux(常運行在arm9平臺上),μClinux(常用在arm7平臺上),在標準linux基礎上擴展對其他的平臺的支持往往通過安裝patch實現,如armlinux就是對linux安裝rmk補丁(patch-2.4.18-rmk7.bz2)形成的,只有安裝了這些補丁,內核才能順利地移植到ARM Linux上。也有些是已經安裝好補丁的內核源碼包,如linux-2.4.18-rmk7.tar.bz2
不同處理器系統的內核/內核補丁下載站點:
處理器系統        適合的內核站點        下載方式
x86           http://www.kernel.org/              ftp, http, rsync
ARM       http://www.arm.linux.org.uk/developer/    ftp, rsync
PowerPC   http://penguinppc.org/            ftp, http, rsync, BitKeeper
MIPS          http://www.linux-mips.org/           ftp, cvs
SuperH         http://linuxsh.sourceforge.net/         cvs, BitKeeper
M68K          http://linux-m68k.org/               ftp, http
non-MMU CPUs http://www.uclinux.org/             ftp, http
這些站點不僅僅是linux內核站點,它們可能直接提供了針對你的目標硬件系統的linux內核版本。
1.1.4 linux內核的選擇
選擇內核版本是很困難的,應該與負責維護該內核的小組保持聯繫,方法是通過訂閱一些合適的郵件列表(maillist)並查看郵件中相關的重要新聞,以及瀏覽一些主要站點,可以得到該內核的最新發展動態。如針對ARMLinux內核,可以訪問http://www.arm.linux.org.uk/ 並訂閱該網站上提供的maillist就可以了。如果覺得查閱郵箱中的郵件列表耗費太多時間,那麼至少每週訪問所關心的內核網站,並閱讀Kernel Traffic提供的過去一週中在內核郵件清單中發生的重要的摘要,網址爲http://kt.zork.net/kernel-traffic 這樣就可以得到相關Linux內核的最新信息。
並不是Linux的每個版本都適合ARM-Linux的移植,可以加入其郵件列表(maillist)以獲得內核版本所支持硬件的相關信息,表中列出的資源可以幫助你找到哪些沒有列出的功能可以被你的系統支持。ARM Linux的移植,建議使用2.4.x2.6.x版本。Linux內核補丁可以到ARM Linuxftpftp://ftp.arm.linux.org.uk )下載。
1.2 Linux內核啓動過程概述
一個嵌入式 Linux 系統從軟件角度看可以分爲四個部分:引導加載程序(Bootloader),Linux 內核,文件系統,應用程序。其中 Bootloader是系統啓動或復位以後執行的第一段代碼,它主要用來初始化處理器及外設,然後調用 Linux 內核。Linux 內核在完成系統的初始化之後需要掛載某個文件系統做爲根文件系統(Root Filesystem)。根文件系統是 Linux 系統的核心組成部分,它可以做爲Linux 系統中文件和數據的存儲區域,通常它還包括系統配置文件和運行應用軟件所需要的庫。應用程序可以說是嵌入式系統的“靈魂”,它所實現的功能通常就是設計該嵌入式系統所要達到的目標。如果沒有應用程序的支持,任何硬件上設計精良的嵌入式系統都沒有實用意義。
1.2.1  Bootloader啓動過程
Bootloader在運行過程中雖然具有初始化系統和執行用戶輸入的命令等作用,但它最根本的功能就是爲了啓動 Linux 內核。
Bootloader的概念和作用
Bootloader是嵌入式系統的引導加載程序,它是系統上電後運行的第一段程序,其作用類似於 PC 機上的 BIOS。在完成對系統的初始化任務之後,它會將非易失性存儲器(通常是FlashDOC等)中的Linux 內核拷貝到 RAM 中去,然後跳轉到內核的第一條指令處繼續執行,從而啓動 Linux 內核。由此可見,Bootloader Linux 內核有着密不可分的聯繫,要想清楚的瞭解 Linux內核的啓動過程,我們必須先得認識 Bootloader的執行過程,這樣才能對嵌入式系統的整個啓動過程有清晰的掌握。
Bootloader的執行過程
不同的處理器上電或復位後執行的第一條指令地址並不相同,對於 ARM 處理器來說,該地址爲 0x00000000。對於一般的嵌入式系統,通常把 Flash 等非易失性存儲器映射到這個地址處,而 Bootloader就位於該存儲器的最前端,所以系統上電或復位後執行的第一段程序便是Bootloader。而因爲存儲 Bootloader的存儲器不同,Bootloader的執行過程也並不相同,下面將具體分析。
嵌入式系統中廣泛採用的非易失性存儲器通常是 Flash,而 Flash 又分爲 Nor Flash Nand Flash 兩種。它們之間的不同在於:Nor Flash 支持芯片內執行(XIP eXecute In Place),這樣代碼可以在Flash上直接執行而不必拷貝到RAM中去執行。而Nand Flash並不支持XIP,所以要想執行 Nand Flash 上的代碼,必須先將其拷貝到 RAM中去,然後跳到 RAM 中去執行。
3Bootloader的功能
實際應用中的 Bootloader根據所需功能的不同可以設計得很複雜,除完成基本的初始化系統和調用 Linux 內核等基本任務外,還可以執行很多用戶輸入的命令,比如設置 Linux 啓動參數,給 Flash 分區等;也可以設計得很簡單,只完成最基本的功能。但爲了能達到啓動Linux 內核的目的,所有的 Bootloader都必須具備以下功能:
(1)、初始化 RAM
因爲 Linux 內核一般都會在 RAM 中運行,所以在調用 Linux 內核之前 bootloader 必須設置和初始化 RAM,爲調用 Linux內核做好準備。初始化 RAM 的任務包括設置CPU 的控制寄存器參數,以便能正常使用 RAM 以及檢測RAM 大小等。
 (2)、初始化串口
串口在 Linux 的啓動過程中有着非常重要的作用,它是 Linux內核和用戶交互的方式之一。Linux 在啓動過程中可以將信息通過串口輸出,這樣便可清楚的瞭解 Linux 的啓動過程。雖然它並不是 Bootloader 必須要完成的工作,但是通過串口輸出信息是調試Bootloader Linux 內核的強有力的工具,所以一般的 Bootloader 都會在執行過程中初始化一個串口做爲調試端口。
(3)、檢測處理器類型
Bootloader在調用 Linux內核前必須檢測系統的處理器類型,並將其保存到某個常量中提供給 Linux 內核。Linux 內核在啓動過程中會根據該處理器類型調用相應的初始化程序。
(4)、設置 Linux啓動參數
Bootloader在執行過程中必須設置和初始化 Linux 的內核啓動參數。目前傳遞啓動參數主要採用兩種方式:即通過 struct param_struct struct tag(標記列表,tagged list)兩種結構傳遞。struct param_struct 是一種比較老的參數傳遞方式,在 2.4 版本以前的內核中使用較多。從 2.4 版本以後 Linux 內核基本上採用標記列表的方式。但爲了保持和以前版本的兼容性,它仍支持 struct param_struct 參數傳遞方式,只不過在內核啓動過程中它將被轉換成標記列表方式。標記列表方式是種比較新的參數傳遞方式,它必須以 ATAG_CORE 開始,並以ATAG_NONE 結尾。中間可以根據需要加入其他列表。Linux內核在啓動過程中會根據該啓動參數進行相應的初始化工作。
(5)、調用 Linux內核映像
Bootloader完成的最後一項工作便是調用 Linux內核。如果 Linux 內核存放在 Flash 中,並且可直接在上面運行(這裏的 Flash  Nor Flash),那麼可直接跳轉到內核中去執行。但由於在 Flash 中執行代碼會有種種限制,而且速度也遠不及 RAM 快,所以一般的嵌入式系統都是將 Linux內核拷貝到 RAM 中,然後跳轉到 RAM 中去執行。
不論哪種情況,在跳到 Linux 內核執行之前 CPU的寄存器必須滿足以下條件:r00r1=處理器類型,r2=標記列表在 RAM中的地址。
1.2.2 Linux啓動過程
Bootloader Linux 內核映像拷貝到 RAM 以後,可以通過下例代碼啓動 Linux 內核:
call_linux(0, machine_type, kernel_params_base)
其中,machine_tpye Bootloader檢測出來的處理器類型, kernel_params_base 是啓動參數在 RAM 的地址。通過這種方式將 Linux 啓動需要的參數從 bootloader傳遞到內核。
Linux 內核有兩種映像:一種是非壓縮內核,叫 Image,另一種是它的壓縮版本,叫 zImage。根據內核映像的不同,Linux 內核的啓動在開始階段也有所不同。zImage  Image經過壓縮形成的,所以它的大小比 Image 小。但爲了能使用 zImage,必須在它的開頭加上解壓縮的代碼,將 zImage 解壓縮之後才能執行,因此它的執行速度比 Image 要慢。但考慮到嵌入式系統的存儲空容量一般比較小,採用 zImage 可以佔用較少的存儲空間,因此犧牲一點性能上的代價也是值得的。所以一般的嵌入式系統均採用壓縮內核的方式。
對於ARM 系列處理器來說,zImage 的入口程序即爲 arch/arm/boot/compressed/head.S。它依次完成以下工作:開啓 MMU  Cache,調用 decompress_kernel()解壓內核,最後通過調用 call_kernel()進入非壓縮內核 Image 的啓動。下面將具體分析在此之後 Linux 內核的啓動過程。
1 Linux內核入口
Linux 非壓縮內核的入口位於文件/arch/arm/kernel/head-armv.S 中的stext 段。該段的基地址就是壓縮內核解壓後的跳轉地址。如果系統中加載的內核是非壓縮的 Image,那麼bootloader將內核從 Flash中拷貝到 RAM 後將直接跳到該地址處,從而啓動 Linux 內核。不同體系結構的 Linux 系統的入口文件是不同的,而且因爲該文件與具體體系結構有關,所以一般均用彙編語言編寫。對基於 ARM 處理的 Linux 系統來說,該文件就是head-armv.S。該程序通過查找處理器內核類型和處理器類型調用相應的初始化函數,再建立頁表,最後跳轉到 start_kernel()函數開始內核的初始化工作。檢測處理器內核類型是在彙編子函數__lookup_processor_type中完成的。通過以下代碼可實現對它的調用:
bl __lookup_processor_type
__lookup_processor_type調用結束返回原程序時,會將返回結果保存到寄存器中。其中r8 保存了頁表的標誌位,r9 保存了處理器的 ID 號,r10 保存了與處理器相關的 stru proc_info_list 結構地址。
檢測處理器類型是在彙編子函數 __lookup_architecture_type 中完成的。與 __lookup_processor_type類似,它通過代碼:“bl __lookup_processor_type”來實現對它的調用。該函數返回時,會將返回結構保存在 r5r6  r7 三個寄存器中。其中 r5 保存了 RAM 的起始基地址,r6 保存了 I/O基地址,r7 保存了 I/O的頁表偏移地址。當檢測處理器內核和處理器類型結束後,將調用__create_page_tables 子函數來建立頁表,它所要做的工作就是將 RAM 基地址開始的 4M 空間的物理地址映射到 0xC0000000 開始的虛擬地址處。對筆者的 S3C2410 開發板而言,RAM 連接到物理地址 0x30000000 處,當調用 __create_page_tables 結束後 0x30000000  0x30400000 物理地址將映射到 0xC00000000xC0400000 虛擬地址處。當所有的初始化結束之後,使用如下代碼來跳到 C 程序的入口函數 start_kernel()處,開始之後的內核初始化工作:b SYMBOL_NAME(start_kernel)
start_kernel函數
start_kernel是所有 Linux 平臺進入系統內核初始化後的入口函數,它主要完成剩餘的與硬件平臺相關的初始化工作,在進行一系列與內核相關的初始化後,調用第一個用戶進程-init 進程並等待用戶進程的執行,這樣整個 Linux 內核便啓動完畢。該函數所做的具體工作有:調用 setup_arch()函數進行與體系結構相關的第一個初始化工作;對不同的體系結構來說該函數有不同的定義。對於 ARM 平臺而言,該函數定義在arch/arm/kernel/Setup.c。它首先通過檢測出來的處理器類型進行處理器內核的初始化,然後通過 bootmem_init()函數根據系統定義的 meminfo 結構進行內存結構的初始化,最後調用paging_init()開啓 MMU,創建內核頁表,映射所有的物理內存和 IO空間。創建異常向量表和初始化中斷處理函數;初始化系統核心進程調度器和時鐘中斷處理機制;初始化串口控制檯(serial-console);ARM-Linux 在初始化過程中一般都會初始化一個串口做爲內核的控制檯,這樣內核在啓動過程中就可以通過串口輸出信息以便開發者或用戶瞭解系統的啓動進程。創建和初始化系統 cache,爲各種內存調用機制提供緩存,包括;動態內存分配,虛擬文件系統(VirtualFile System)及頁緩存。初始化內存管理,檢測內存大小及被內核佔用的內存情況;初始化系統的進程間通信機制(IPC);當以上所有的初始化工作結束後,start_kernel()函數會調用 rest_init()函數來進行最後的初始化,包括創建系統的第一個進程-init 進程來結束內核的啓動。init 進程首先進行一系列的硬件初始化,然後通過命令行傳遞過來的參數掛載根文件系統。最後 init 進程會執行用戶傳遞過來的“init=”啓動參數執行用戶指定的命令,或者執行以下幾個進程之一:
execve("/sbin/init",argv_init,envp_init)
execve("/etc/init",argv_init,envp_init)
execve("/bin/init",argv_init,envp_init)
execve("/bin/sh",argv_init,envp_init)
當所有的初始化工作結束後,cpu_idle()函數會被調用來使系統處於閒置(idle)狀態並等待用戶程序的執行。至此,整個 Linux 內核啓動完畢。
Linux 內核是一個非常龐大的工程,經過十多年的發展,它已從從最初的幾百 KB 大小發展到現在的幾百兆。清晰的瞭解它執行的每一個過程是件非常困難的事。但是在嵌入式開發過程中,我們並不需要十分清楚Linux 的內部工作機制,只要適當修改Linux 內核中那些與硬件相關的部分,就可以將Linux 移植到其它目標平臺上。通過對Linux 的啓動過程的分析,我們可以看出哪些是和硬件相關的,哪些是Linux 內核內部已實現的功能,這樣在移植Linux 的過程中便有所針對。而Linux內核的分層設計將使Linux 的移植變得更加容易。
1.3 Linux內核移植
1.3.1移植內核和根文件系統準備工作
移植內核前,保證你已經裝上了Linux系統,建立好了交叉編譯環境,我用的是虛擬機,裝的Redhat9.0系統,交叉編譯工具用的是友善之臂的arm-linux-gcc-4.3.2
開始移植Linux內核了,下面是我我使用的內核和文件系統,以及所用到的工具及獲取方法:
1Linux系統
我是在虛擬機上安裝的Redhat9.0XP系統下虛擬機設置的共享目錄是D:/share,對應的Linux系統的目錄是/mnt/hgfs/share。我將下面準備的壓縮包和文件都統一放到該目錄下。
2Linux內核
www.kernel.org/主頁,進入該網站中鏈接FTP ftp://ftp.kernel.org/pub/,在裏面進入文件夾“linux->kernel->v2.6,會出現很多版本的內核壓縮包和補丁,選中Linux-2.6.29.1.tar.bz2下載。
3、交叉編譯工具鏈
使用友善之臂提供的arm-linux-4.3.2工具鏈,沒有的到http://www.arm9.net/下載。工具鏈也可以自己做,可以參考《構建嵌入式Linux系統》一書或其它資料。
4yaffs2代碼
進入http://www.aleph1.co.uk/cgi-bin/viewcvs.cgi/,點擊“Download GNU tarball”,下載後出現cvs-root.tar.gz壓縮包。
5busybox-1.13.3
http://www.busybox.net/downloads/下載busybox,這裏下載的是busy busybox-1.13.3.tar.gz
6、根文件系統製作工具
到友善之臂http://www.arm9.net/ 網站下載根文件系統製作工具mkyaffs2image.tgz
7、友善之臂的根文件系統
在製作根文件系統時,需要用到鏈接庫,爲保證鏈接庫能用直接用友善之臂的根文件系統root_qtopia中的鏈接庫lib,到友善之臂網站http://www.arm9.net/ 下載root_qtopia.tgz
這些文件都下載到D:/share中,通過虛擬機進入Redhat9.0系統,進入/mnt/hgfs/share目錄便可訪問這些與XP共享的文件。
8、硬件平臺
       友善之臂的mini2440
1.3.2修改Linux源碼中參數
1、解壓內核源碼
mkdir /opt/studyarm
cd /mnt/hgfs/share
tar –jxvf linux-2.6.29.1.tar.bz2 –C /opt/studyarm
2進入內核目錄,修改makefile,並對內核進行默認配置進行修改
       193行,修改
       ARCH                        ?=arm
       CROSS_COMPILE   ?=arm-linux-
3修改平臺輸入時鐘
        找到內核源碼arch/arm/mach-s3c2440/mach-smdk2440.c文件,在函數 static void __init smdk2440_map_io(void)中,修改成s3c24xx_init_clocks(12000000)
4修改machine名稱(可以不改)
修改文件arch/arm/mach-s3c2440/mach-smdk2440.c,在文件中找到MACHINE_START( ),修改爲MACHINE_START(S3C2440, “Study-S3C2440”)
5修改Nand flash分區信息
修改文件kernel.git/arch/arm/plat-s3c24xx/common-smdk.c
第一,修改分區信息:
static struct mtd_partition smdk_default_nand_part[] = {
       [0] = {
       .name = "bootloader",
       .offset = 0x00000000,
       .size = 0x00030000,
       },
       [1] = {
       .name = "kernel",
       .offset = 0x00050000,
       .size = 0x00200000,
       },
       [2] = {
       .name = "root",
       .offset = 0x00250000,
       .size = 0x03DAC000,
       }
};
第二,再修改s3c2410_platform_nand_smdk_nand_info smdk_nand_info = {
.tacls = 0,
.twrph0 = 30,
.twrph1=0,
};
6修改LCD背光
修改文件/arch/arm/mach-s3c2440/mach-smdk2440.c,因爲友善的3.5寸液晶的背光控制是由S3C2440GPG4引腳來控制的,故下面的改動將開啓背光。
static void __init smdk2440_machine_init(void)
{
       s3c24xx_fb_set_platdata(&smdk2440_fb_info);
       platform_add_devices();
        s3c2410_gpio_cfgpin(S3C2410_GPF(4), S3C2410_GPIO_OUTPUT);
       s3c2410_gpio_setpin(S3C2410_GPG(4),1);   
       smdk_machine_init();
}
由於加入GPIO 所以加入頭文件 #include <mach/gpio-fns.h>
6 LCD參數修改
        這裏用的是NEC3.5英寸屏液晶屏,大小爲320x240,需要修改修改文件arch/arm/mach-s3c2440/mach-smdk2440.c
static struct s3c2410fb_display smdk2440_lcd_cfg __initdata =
{
       …
       .right_margin = 37,
       .hsync_len = 6, 
       .upper_margin =2,
       .lower_margin = 6,
       .vsync_len =2,
};
static struct s3c2410fb_mach_info smdk2440_fb_info   __initdata      ={
.default_display =0
       .gpccon         = 0xaa955699,
       .gpccon_mask      = 0xffc003cc,
       .gpcup           = 0x0000ffff,
       .gpcup_mask = 0xffffffff,
       .gpdcon         = 0xaa95aaa1,
       .gpdcon_mask      = 0xffc0fff0,
       .gpdup           = 0x0000faff,
       .gpdup_mask = 0xffffffff,
.lpcsel = 0xf82,
};
7給內核打yaffs2文件系統的補丁
cd /mnt/hgfs/share
tar –zxvf /mnt/hgfs/share/cvs-root.tar.gz –C /opt/studyarm
    cd /opt/stdudyarm/cvs/yaffs2/
./patch-ker.sh c /opt/studyarm/linux-2.6.29.1/ 
上面命令完成下面三件事情:
(1) 修改內核fs/Kconfig
    增加一行:source "fs/yaffs2/Kconfig"
(2) 修改內核fs/Kconfig
    增加一行:ojb-$(CONFIG_YAFFS_FS) +=yaffs2/
(3) 在內核fs/目錄下創建yaffs2目錄
    yaffs2源碼目錄下面的Makefile.kernel文件複製爲內核fs/yaffs2/Makefie;
    yaffs2 源碼目錄的Kconfig文件複製到內核fs/yaffs2目錄下;
    yaffs2源碼目錄下的*.c *.h文件複製到內核fs/yaffs2目錄下.
8、修改S3C2440的機器號
由於Bootloader傳遞給Linux內核的機器號爲782,爲與Bootloader傳遞參數一致,修改 arch/arm/tools/math-types文件。
s3c2440                     ARCH_S3C2440              S3C2440                    362
修改爲:
s3c2440                     ARCH_S3C2440              S3C2440                    782
另外,還可以不修改內核中的S3C2440機器號,只需修改修改Bootloader傳遞給內核的參數中的機器號就可以了。在VIVI中菜單中,按s,再按s,輸入mach_type,回車,輸入362w,保存。
1.3.3配置Linux內核
1進入Linux-2.6.29.1內核主目錄,通過以下命令將2410的默認配置文件寫到當前目錄下的.configS3C2410的配置和S3C2440差不多,,在這基礎上進行修改。
make s3c2410_defconfig              
2配置內核模塊的功能,有幾種方式可以進行界面選擇:
make menuconfig(文本選單的配置方式,在有字符終端下才能使用)
make xconfig(圖形窗口模式的配置方式,圖形窗口的配置比較直觀,必須支持Xwindow下才能使用)
make oldconfig(文本配置方式,在原內核配置的基礎修改時使用)
這裏使用make menuconfig命令。
3[*]Enable loadable module support--->
              [*]Forced module loading
              [*]Module unloading
4System Type--->
           S3C2410 Machines--->
                     [*]SMDK2410/A9M2410選上其餘不選
           S3C2440 Machines--->
                     [*]SMDK2440
                     [*]SMDK2440 with S3C2440 CPU module,其餘不選
其餘的Machines下選項全部不選(如2400241224422443
5Kernel Features--->
[*]Use the ARM EABI to compile the kernel
       注:由於所使用的的交叉編譯arm-linux-gcc-4.3.2是符合EABI標準交叉編譯器,對於浮點運行會預設硬浮點運算FPA(Float Point Architecture),而沒有FPACPU,比如SAMSUNG S3C2410/S3C2440,會使用FPE(Float Point Emulation 即軟浮點),這樣在速度上就會遇到極大的限制,使用EABI(Embedded Application Binary InteRFace)則可以對此改善處理,ARM EABI有許多革新之處,其中最突出的改進就是Float Point Performance,它使用Vector Float Point(矢量浮點),因此可以極大提高涉及到浮點運算的程序。
參考:http://www.hotchn.cn/bbs/viewthread.php?tid=130&extra=page%3D1
6Boot options-?
noinitrd root="/dev/mtdblock2" init="/linuxrc" console=ttySAC0
7Userspace binary formats--->
              [*]Kernel support for ELF binaries
其它的可以全部不選。
8選擇支持yaffs2文件系統
Filesystem--->
              Miscellaneous filesystems--->
                     <*>YAFFS2 file system support
                     [*]   Lets Yaffs do its own ECC
              Native language support
<*> Codepage 437 (United States,Canada)
<*>Simplified Chinese charset(GB2312)
<*>Traditional Chinese charset(Big5)
<*>NLS ISO 8859-1(Latin1:Western European Languages)
<*>NLS UTF-8
9Device Drivers--->
              Graphics support--->
                     <*>Support for frame buffer devices--->
                            [*]Enable firmware EDID
                            [*]Enable Video Mode Handling Helpers
                            <*>S3C2410 LCD framebuffer support
                     Console display driver support--->
                            <*>Framebuffer Console support
                            [*]Select compiled-in fonts
                            [*] VGA8x8 font
                            [*]VGA8x16 font
[*]Bootup logo--->
                            [*]Standard black and white Linux logo
                            [*]Standard 16-color Linux logo
                            [*]Standard 224-color Linux logo
Bootup logo--->選擇的那幾項,將會在系統啓動時在液晶上顯示開機logo
1.3.4、編譯內核
編譯內核需要遵守以下步驟:
1make dep
make dep的意思就是說:如果你使用程序A(比如支持特殊設備),而A需用到B(比如BA的一個模塊/子程序)。而你在做make config的時候將一個設備的驅動由內核支持改爲module,或取消支持,這將可能影響到B的一個參數的設置,需重新編譯B,重新編譯或連接A....如果程序數量非常多,你是很難手工完全做好此工作的。make dep實際上讀取配置過程生成的配置文件,來創建對應於配置的依賴關係樹,從而決定哪些需要編譯而那些不需要編譯。所以,你要make dep
2make clean
清除一些以前留下的文件,比如以前編譯生成的目標文件,這一步必須要進行。否則,即使內核配置改動過,編譯內核時還是將原來生成的目標文件進行連接,而不生成改動後的文件。
3make zImage
Linux內核有兩種映像:一種是非壓縮內核,叫 Image,另一種是它的壓縮版本,叫zImage。根據內核映像的不同,Linux內核的啓動在開始階段也有所不同。zImageImage經過壓縮形成的,所以它的大小比 Image小。但爲了能使用zImage,必須在它的開頭加上解壓縮的代碼,將 zImage解壓縮之後才能執行,因此它的執行速度比Image要慢。但考慮到嵌入式系統的存儲空容量一般比較小,採用zImage可以佔用較少的存儲空間,因此犧牲一點性能上的代價也是值得的,所以一般的嵌入式系統均採用壓縮內核的方式。
編譯完成後,會在內核目錄arch/arm/boot/下生成zImage內核映像文件。
 
=======================================================================================================
第二章製作根文件系統
2.1 根文件系統預備知識
嵌入式Linux中都需要構建根文件系統,構建根文件系統的規則在FHS(Filesystem Hierarchy Standard)文檔中,下面是根文件系統頂層目錄。
目錄
內容
bin
存放所有用戶都可以使用的、基本的命令。
sbin
存放的是基本的系統命令,它們用於啓動系統、修復系統等。
usr
裏面存放的是共享、只讀的程序和數據。
proc
這是個空目錄,常作爲proc文件系統的掛載點。
dev
該目錄存放設備文件和其它特殊文件。
etc
存放系統配置文件,包括啓動文件。
lib
存放共享庫和可加載塊(即驅動程序),共享庫用於啓動系統、運行根文件系統中的可執行程序。
boot
引導加載程序使用的靜態文件
home
用戶主目錄,包括供服務賬號鎖使用的主目錄,如FTP
mnt
用於臨時掛接某個文件系統的掛接點,通常是空目錄。也可以在裏面創建空的子目錄。
opt
給主機額外安裝軟件所擺放的目錄。
root
root用戶的主目錄
tmp
存放臨時文件,通常是空目錄。
var
存放可變的數據。
2.2、構建根文件按系統
2.2.1、建立根文件系統目錄
進入到/opt/studyarm目錄,新建建立根文件系統目錄的腳本文件create_rootfs_bash,使用命令chmod +x create_rootfs_bash改變文件的可執行權限,./create_rootfs_bash運行腳本,就完成了根文件系統目錄的創建。
#!/bin/sh
echo "------Create rootfs directons start...--------"
mkdir rootfs
cd rootfs
echo "--------Create root,dev....----------"
mkdir root dev etc boot tmp var sys proc lib mnt home
mkdir etc/init.d etc/rc.d etc/sysconfig
mkdir usr/sbin usr/bin usr/lib usr/modules
 
echo "make node in dev/console dev/null"
mknod -m 600 dev/console c 5 1
mknod -m 600 dev/null    c 1 3
 
mkdir mnt/etc mnt/jffs2 mnt/yaffs mnt/data mnt/temp
 
mkdir var/lib var/lock var/run var/tmp
 
chmod 1777 tmp
chmod 1777 var/tmp
 
echo "-------make direction done---------"
改變了tmp目錄的使用權,讓它開啓sticky位,爲tmp目錄的使用權開啓此位,可確保tmp目錄底下建立的文件,只有建立它的用戶有權刪除。儘管嵌入式系統多半是單用戶,不過有些嵌入式應用不一定用root的權限來執行,因此需要遵照根文件系統權限位的基本規定來設計。
2.2.2、建立動態鏈接庫
動態鏈接庫直接用友善之臂的,先解壓友善之臂的根文件包,拷貝lib的內容到新建的根文件目錄lib內。
cd /mnt/hgfs/share
tar –zxvf root_qtopia.tgz –C /opt/studyarm
cp –rfd /opt/studyarm/root_qtopia/lib/* /opt/studyarm/rootfs/lib/*
2.2.3交叉編譯Bosybox
Bosybox是一個遵循GPL v2協議的開源項目,它在編寫過程總對文件大小進行優化,並考慮了系統資源有限(比如內存等)的情況,使用Busybox可以自動生成根文件系統所需的binsbinusr目錄和linuxrc文件。
1、解壓busybox
cd /mnt/hgfs/share
tar –zxvf busybox-1.13.3.tar.tgz –C /opt/studyarm
2、進入源碼,修改Makefile文件:
cd /opt/studyarm/busybox-1.13.3
修改:
       CROSS_COMPILE   ?=arm-linux-      //164
       ARCH                        ?=arm                  //189
3、配置busybox
輸入make menuconfig進行配置
(1)Busybox Settings--->
             General Configuration--->
                            [*] Show verbose applet usage messages
                            [*] Store applet usage messages in compressed form
                            [*] Support –install [-s] to install applet links at runtime
                            [*] Enable locale support(system needs locale for this to work)
                            [*] Support for –long-options
                            [*] Use the devpts filesystem for unix98 PTYs
                            [*] Support writing pidfiles
                            [*] Runtime SUID/SGID configuration via /etc/busybox.config
                            [*] Suppress warning message if /etc/busybox.conf is not readable
Build Options--->
                        [*] Build BusyBox as a static binary(no shared libs)
                            [*] Build with Large File Support(for accessing files>2GB)
Installation Options->
                            []Don’t use /usr
                            Applets links (as soft-links) --->
                                   (./_install) BusyBox installation prefix
Busybox Library Tuning --->
                            (6)Minimum password legth
                            (2)MD5:Trade Bytes for Speed
                            [*]Fsater /proc scanning code(+100bytes)
                            [*]Command line editing
                            (1024)Maximum length of input
                            [*]   vi-style line editing commands
                            (15) History size
                            [*]   History saving
                            [*]   Tab completion
                            [*]Fancy shell prompts
                            (4) Copy buffer size ,in kilobytes      
[*]Use ioctl names rather than hex values in error messages
[*]Support infiniband HW
(2)Linux Module Utilities--->
                    (/lib/modules)Default directory containing modules
                     (modules.dep)Default name of modules.dep
[*]   insmod
[*]   rmmod
[*]   lsmod
[*]   modprobe
-----options common to multiple modutils
[ ] support version 2.2/2.4 Linux kernels
[*]Support tainted module checking with new kernels
[*]Support for module .aliases file
[*] support for modules.symbols file
(3)、在busybox中配置對dev下設備類型的支持
dev的創建有三種方法:
手動創建:在製作根文件系統的時候,就在dev目錄下創建好要使用的設備文件,系統掛接根文件系統後,就可以使用dev目錄下的設備文件了。
使用devfs文件系統:這種方法已經過時,具有不確定的設備映射、沒有足夠的主/次設備號、devfs消耗大量的內存。
udev:它是個用戶程序,能根據系統中硬件設備的狀態動態的更新設備文件,包括設備文件的創建、刪除等。它的操作相對複雜,但靈活性很高
mdevbusybox自帶的一個簡化版的udev,適合於嵌入式的應用埸合。其具有使用簡單的特點。它的作用,就是在系統啓動和熱插拔或動態加載驅動程序時,自動產生驅動程序所需的節點文件。在以busybox爲基礎構建嵌入式linux的根文件系統時,使用它是最優的選擇。下面的選項將增加對mdev的支持。
Linux System Utilities --->              
           [*]Support /etc/mdev.conf        
           [*]Support command execution at device addition/removal
4編譯busybox
編譯busybox到指定目錄:
cd /opt/studyarm/busybox-1.13.3
make CONFIG_PREFIX=/opt/studyarm/rootfs install
rootfs目錄下會生成目錄binsbinusr和文件linuxrc的內容。
2.2.4建立etc目錄下的配置文件
1etc/mdev.conf文件,內容爲空。
2、拷貝主機etc目錄下的passwdgroupshadow文件到rootfs/etc目錄下。
3etc/sysconfig目錄下新建文件HOSTNAME,內容爲”MrFeng”
4etc/inittab文件:
#etc/inittab
::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a –r
5etc/init.d/rcS文件:
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
runlevel=S
prevlevel=N
umask 022
export PATH runlevel prevlevel
 
echo "----------munt all----------------"
mount -a
 
echo /sbin/mdev>/proc/sys/kernel/hotplug
mdev -s
 
echo "***********************************************"
echo "****************Studying ARM*********************"
echo "Kernel version:linux-2.6.29.1"
echo "Student:Feng dong rui"
echo "Date:2009.07.15"
echo "***********************************************"
 
/bin/hostname -F /etc/sysconfig/HOSTNAME
使用以下命令改變rcS的執行權限:
Chmod +x rcS
6etc/fstab文件:
#device    mount-point     type     option     dump   fsck   order
proc          /proc        proc     defaults    0        0
none          /tmp        ramfs    defaults    0        0
sysfs         /sys          sysfs    defaults    0        0
mdev          /dev        ramfs    defaults    0        0
7 etc/profile文件:
#Ash profile
#vim:syntax=sh
 
#No core file by defaults
#ulimit -S -c 0>/dev/null 2>&1
 
USER="id -un"
LOGNAME=$USER
PS1='[/u@/h=W]#'
PATH=$PATH
HOSTNAME='/bin/hostname'
export USER LOGNAME PS1 PATH
2.2.5製作根文件系統映像文件
使用以下命令安裝好yaffs文件系統製作工具:
cd /mnt/hgfs/share
tar –zxvf mkyaffs2image.tgz –C /
/opt/studyarm目錄下,使用命令mkyaffs2image rootfs rootfs.img生成根文件系統映像文件。

 =======================================================================================================
第三章啓動系統
將前面兩章生成的內核映像文件和根文件系統映像文件下載到mini2440開發板,查看啓動信息。我成功移植啓動信息如下:
VIVI version 0.1.4 (root@capcross) (gcc version 2.95.3 20010315 (release)) #0.1.4 Mon Oct 27 10:18:15 CST 2008
MMU table base address = 0x33DFC000
Succeed memory mapping.
DIVN_UPLL0
MPLLVal [M:7fh,P:2h,S:1h]
CLKDIVN:5h
 
 
+---------------------------------------------+
| S3C2440A USB Downloader ver R0.03 2004 Jan |
+---------------------------------------------+
USB: IN_ENDPOINT:1 OUT_ENDPOINT:3
FORMAT: <ADDR(DATA):4>+<SIZE(n+10):4>+<DATA:n>+<CS:2>
NOTE: Power off/on or press the reset button for 1 sec
      in order to get a valid USB device address.
 
NAND device: Manufacture ID: 0xec, Chip ID: 0x76 (Samsung K9D1208V0M)
Found saved vivi parameters.
Press Return to start the LINUX/Wince now, any other key for vivi
Copy linux kernel from 0x00050000 to 0x30008000, size = 0x00200000 ... done
zImage magic = 0x016f2818
Setup linux parameters at 0x30000100
linux command line is: "noinitrd root="/dev/mtdblock2" init="/linuxrc" console="ttySAC0""
MACH_TYPE = 362
NOW, Booting Linux......
Uncompressing Linux.......................................................................................................................... done, booting the kernel.
Linux version 2.6.29.1 ([email protected]) (gcc version 4.3.2 (Sourcery G++ Lite 2008q3-72) ) #8 Sat Jul 18 10:37:22 CST 2009
CPU: ARM920T [41129200] revision 0 (ARMv4T), cr="c0007177"
CPU: VIVT data cache, VIVT instruction cache
Machine: Study-S3C2440
ATAG_INITRD is deprecated; please update your bootloader.
Memory policy: ECC disabled, Data cache writeback
CPU S3C2440A (id 0x32440001)
S3C24XX Clocks, (c) 2004 Simtec Electronics
S3C244X: core 405.000 MHz, memory 101.250 MHz, peripheral 50.625 MHz
CLOCK: Slow mode (1.500 MHz), fast, MPLL on, UPLL on
Built 1 zonelists in Zone order, mobility grouping on. Total pages: 16256
Kernel command line: noinitrd root="/dev/mtdblock2" init="/linuxrc" console="ttySAC0"
irq: clearing pending status 02000000
irq: clearing subpending status 00000002
PID hash table entries: 256 (order: 8, 1024 bytes)
Console: colour dummy device 80x30
console [ttySAC0] enabled
Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
Memory: 64MB = 64MB total
Memory: 60876KB available (3536K code, 293K data, 136K init)
Calibrating delay loop... 201.93 BogoMIPS (lpj=504832)
Mount-cache hash table entries: 512
CPU: Testing write buffer coherency: ok
net_namespace: 296 bytes
NET: Registered protocol family 16
S3C2410 Power Management, (c) 2004 Simtec Electronics
S3C2440: Initialising architecture
S3C2440: IRQ Support
S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics
DMA channel 0 at c4808000, irq 33
DMA channel 1 at c4808040, irq 34
DMA channel 2 at c4808080, irq 35
DMA channel 3 at c48080c0, irq 36
S3C244X: Clock Support, DVS off
bio: create slab <bio-0> at 0
SCSI subsystem initialized
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
NET: Registered protocol family 2
IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
TCP established hash table entries: 2048 (order: 2, 16384 bytes)
TCP bind hash table entries: 2048 (order: 1, 8192 bytes)
TCP: Hash tables configured (established 2048 bind 2048)
TCP reno registered
NET: Registered protocol family 1
NTFS driver 2.1.29 [Flags: R/O].
yaffs Jul 18 2009 10:31:41 Installing.
msgmni has been set to 119
io scheduler noop registered
io scheduler anticipatory registered (default)
io scheduler deadline registered
io scheduler cfq registered
Console: switching to colour frame buffer device 30x40
fb0: s3c2410fb frame buffer device
lp: driver loaded but no devices found
ppdev: user-space parallel port driver
Serial: 8250/16550 driver, 4 ports, IRQ sharing enabled
s3c2440-uart.0: s3c2410_serial0 at MMIO 0x50000000 (irq = 70) is a S3C2440
s3c2440-uart.1: s3c2410_serial1 at MMIO 0x50004000 (irq = 73) is a S3C2440
s3c2440-uart.2: s3c2410_serial2 at MMIO 0x50008000 (irq = 76) is a S3C2440
brd: module loaded
loop: module loaded
dm9000 Ethernet Driver, V1.31
Uniform Multi-Platform E-IDE driver
ide-gd driver 1.18
ide-cd driver 5.00
Driver 'sd' needs updating - please use bus_type methods
S3C24XX NAND Driver, (c) 2004 Simtec Electronics
s3c2440-nand s3c2440-nand: Tacls="1", 9ns Twrph0=4 39ns, Twrph1=1 9ns
NAND device: Manufacturer ID: 0xec, Chip ID: 0x76 (Samsung NAND 64MiB 3,3V 8-bit)
Scanning device for bad blocks
Creating 3 MTD partitions on "NAND 64MiB 3,3V 8-bit":
0x000000000000-0x000000030000 : "boot"
0x000000050000-0x000000250000 : "kernel"
0x000000250000-0x000003ffc000 : "kernel"
usbmon: debugfs is not available
ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
s3c2410-ohci s3c2410-ohci: S3C24XX OHCI
s3c2410-ohci s3c2410-ohci: new USB bus registered, assigned bus number 1
s3c2410-ohci s3c2410-ohci: irq 42, io mem 0x49000000
usb usb1: New USB device found, idVendor="1d6b", idProduct="0001"
usb usb1: New USB device strings: Mfr="3", Product="2", SerialNumber="1"
usb usb1: Product: S3C24XX OHCI
usb usb1: Manufacturer: Linux 2.6.29.1 ohci_hcd
usb usb1: SerialNumber: s3c24xx
usb usb1: configuration #1 chosen from 1 choice
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 2 ports detected
usbcore: registered new interface driver libusual
usbcore: registered new interface driver usbserial
USB Serial support registered for generic
usbcore: registered new interface driver usbserial_generic
usbserial: USB Serial Driver core
USB Serial support registered for FTDI USB Serial Device
usbcore: registered new interface driver ftdi_sio
ftdi_sio: v1.4.3:USB FTDI Serial Converters Driver
USB Serial support registered for pl2303
usbcore: registered new interface driver pl2303
pl2303: Prolific PL2303 USB to serial adaptor driver
s3c2410_udc: debugfs dir creation failed -19
mice: PS/2 mouse device common for all mice
i2c /dev entries driver
s3c2440-i2c s3c2440-i2c: slave address 0x10
s3c2440-i2c s3c2440-i2c: bus frequency set to 98 KHz
s3c2440-i2c s3c2440-i2c: i2c-0: S3C I2C adapter
S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics
s3c2410-wdt s3c2410-wdt: watchdog inactive, reset disabled, irq enabled
TCP cubic registered
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
yaffs: dev is 32505858 name is "mtdblock2"
yaffs: passed flags ""
yaffs: Attempting MTD mount on 31.2, "mtdblock2"
yaffs_read_super: isCheckpointed 0
VFS: Mounted root (yaffs filesystem) on device 31:2.
Freeing init memory: 136K
----------munt all----------------
***********************************************
****************Studying ARM*********************
Kernel version:linux-2.6.29.1
Student:Feng dong rui
Date:2009.07.15
***********************************************
 
Please press Enter to activate this console.
[@MrFeng=W]#ls
bin         etc         linuxrc     proc        sys         var
boot        home        lost+found root        tmp         www
dev         lib         mnt         sbin        usr
[@MrFeng=W]#
這期間可能會遇到這樣或那樣啓動失敗的錯誤,要麼是內核移植有問題,要麼是根文件系統沒製作好,只有到google上搜索解決問題了。我就是重複的配置和編譯、google,甚至虛擬機上的Linux系統都重新裝過,經過許多重複的勞動和思考終於移植成功了。
 =======================================================================================================


總結
參照友善的說明書熟悉了mini2440開發板的環境和使用,知道怎麼使用,並不知道該如何自己構建這樣的一個環境。在網上看到很多人從移植內核和根文件系統開始搭建開發環境,再寫設備驅動和應用程序,基本上就是圍繞着“內核--->驅動--->應用程序”這條線來的。移植內核和根文件系統,我參照了幾十篇網上的文章和一些好心網友整理的資料,終於搭建好了一個能夠正常啓動的內核和根文件系統。在這裏非常感謝網友的無私奉獻,爲感謝網友、分享學習心得,這是我寫這篇筆記的主要原因,只會索取而不奉獻怎麼行,希望我的筆記對初學者有用,我也是初學者,正在學習。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章