ARM Linux啟動過程分析
1. 引 言
Linux 最初是由瑞典赫爾辛基大學的學生 Linus Torvalds在1991 年開發出來的,之后在 GNU的支持下,Linux 獲得了巨大的發展。雖然 Linux 在桌面 PC 機上的普及程度遠不及微軟的 Windows 操作系統,但它的發展速度之快、用戶數量的日益增多,也是微軟所不能輕視的。而近些年來 Linux 在嵌入式領域的迅猛發展,更是給 Linux 注入了新的活力。
一個嵌入式 Linux 系統從軟件角度看可以分為四個部分[1]:引導加載程序(bootloader),
Linux 內核,文件系統,應用程序。
其中 bootloader是系統啟動或復位以后執行的第一段代碼,它主要用來初始化處理器及外設,然后調用 Linux 內核。Linux 內核在完成系統的初始化之后需要掛載某個文件系統做為根文件系統(Root Filesystem)。根文件系統是 Linux 系統的核心組成部分,它可以做為Linux 系統中文件和數據的存儲區域,通常它還包括系統配置文件和運行應用軟件所需要的庫。應用程序可以說是嵌入式系統的“靈魂”,它所實現的功能通常就是設計該嵌入式系統所要達到的目標。如果沒有應用程序的支持,任何硬件上設計精良的嵌入式系統都沒有實用意義。
從以上分析我們可以看出 bootloader 和 Linux 內核在嵌入式系統中的關系和作用。Bootloader在運行過程中雖然具有初始化系統和執行用戶輸入的命令等作用,但它最根本的功能就是為了啟動 Linux 內核。在嵌入式系統開發的過程中,很大一部分精力都是花在bootloader 和 Linux 內核的開發或移植上。如果能清楚的了解 bootloader 執行流程和 Linux的啟動過程,將有助于明確開發過程中所需的工作,從而加速嵌入式系統的開發過程。而這正是本文的所要研究的內容。
2. Bootloader
2.1 Bootloader的概念和作用Bootloader是嵌入式系統的引導加載程序,它是系統上電后運行的第一段程序,其作用類似于 PC 機上的 BIOS。在完成對系統的初始化任務之后,它會將非易失性存儲器(通常是 Flash或 DOC 等)中的Linux 內核拷貝到 RAM 中去,然后跳轉到內核的第一條指令處繼續執行,從而啟動 Linux 內核。由此可見,bootloader 和 Linux 內核有著密不可分的聯系,要想清楚的了解 Linux內核的啟動過程,我們必須先得認識 bootloader的執行過程,這樣才能對嵌入式系統的整個啟過程有清晰的掌握。
2.2 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 中去執行。實際應用中的 bootloader根據所需功能的不同可以設計得很復雜,除完成基本的初始化系統和調用 Linux 內核等基本任務外,還可以執行很多用戶輸入的命令,比如設置 Linux 啟動參數,給 Flash 分區等;也可以設計得很簡單,只完成最基本的功能。但為了能達到啟動Linux 內核的目的,所有的 bootloader都必須具備以下功能[2] :
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內核在啟動過程中會根據該啟動參數進行相應的初始化工作。
linux操作系統文章專題:linux操作系統詳解(linux不再難懂)
評論