32位ARM嵌入式處理器具有高效能、低軾耗的特性,已被廣泛應用於消費電子產品、無線通訊和網路通訊等領域。uCLinux是專門為無MMU處理器設計 的嵌入式作業系統,支援ARM、Motorola等微處理器。目前國內外採用ARM- uCLinux作為嵌入式系統非常普遍。而嵌入式系統的啟動引導技術是嵌入式系統開發的一個痛點。系統啟動引導的成功與否決定了應用程式的運行環境是否能 正確構建,即系統啟動成功是應用正確啟動並執行前提。
常用的嵌入式系統啟動方法是先通過JTAG將嵌入式作業系統核心與進Flash,再由其帶的引導程式bootloader完成嵌放式系統的啟動引導工作。 這種方法要藉助昂貴的JTAG裝置完成作業系統核心的燒寫工作,並且不能方便地更新嵌入式系統中的軟體平台。本文提出一種基於ARM-uCLinux嵌入 式系統的啟動引導方案,不但可以通過簡易的串口方便地更新嵌入式系統內的軟體平台,而且成功解決了這種架構的嵌入式系統的啟動、初始化、作業系統核心的固 化和引導等問題。本文簡略說明ARM- uCLinux嵌入式系統的硬體平台和軟體平台;描述系統引導程式bootloader的設計,闡述設計時考慮的因素和需解決的技術痛點,給出一套可行的 引導程式流程;針對uCLinux核心的引導程式,說明uCLinux核心的載入和初始化過程。
1 系統組成
典型的ARM嵌入式系統硬體平台一般包括一個以ARM為核心的處理器、儲存空間和必要的外部介面與裝置。在本系統中,採用內嵌ARM7TDMI的 Samsung公司的S3C4510處理器,儲存空間使用2MB的Flash和16MB的SDRAM,外部介面除了用於下載和通訊的串口,還配備了一個以太 網介面,以支援S3C4510的網路功能。
軟體平台由以下部分組成:系統引導程式、嵌入式作業系統核心、檔案系統。系統引導程式通常也稱為bootloader,代碼量雖少,但是作用非常大,相當 於PC上的BIOS,負責將作業系統核心固化到Flash中和系統初始化工作,然後將系統控制權交給作業系統。嵌入式作業系統核心是嵌入式系統加電運行後 的管理平台,負責即時性任務和多任務的管理。ARM7TDMI是一款沒有MMU的處理器,因此採用uCLinux作為本系統的作業系統核心。 uCLinux是Linux是一個分支,專為無MMU的處理器設計,它繼承了Linux強大的網路功能和多任務管理功能,並對記憶體管理和進程管理進行了改 寫,滿足無MMU處理器的開發要求。檔案系統是嵌入式系統軟體平台佔用儲存量最大的一部分,也是與使用者開發最相關的一部分。它儲存了系統設定檔、系統程 序、使用者應用程式和必需的驅動程式。
軟體平台固化在Flash中。通常根據軟體平台的內容對Flash的地址空間進行分區,一般分三個區,分別豐放bootloader、uCLinux核心 和檔案系統。分區的方式一般有兩種:一種是根據三個部分預定的儲存空量,允許bootloader、核心和檔案系統擁有自己固定的分區和首地址;另一種就 是按照這三部分的實際分配區間,一個部分緊跟著另一個部分後儲存,沒有固定的分區和首地址。通常採用第一種方式,雖然可能會浪費一部分Flash空間,但 是方便核心的載入和檔案系統的掛載,同時也利於系統的調試和開發。而如果充分利用Flash的儲存區間,節約成本,那麼可採用第二種方式。
2 系統引導程式的設計
系統引導程式bootloader是嵌入式系統加電後執行的第一個程式,進行功能設計時首先要考慮以下問題:
(1)將uCLinux核心和檔案系統固化在Flash中
目地uCLinux核心和檔案系統固化在Flash的手段很多。主機可以通過JTAG口,將核心和檔案系統的映像檔案燒寫到指定的Flash位置上;也可 以通過乙太網路介面,將映像檔案下載到Flash中;另外還可以通過串口燒寫到Flash。前兩種方法的下載速度比後一種方法快得多。在本系統中,採用串口 燒寫Flash。這是因為一方面配置一個串口方便且廉價,而JTAG燒寫還要配置昂貴的 JTAG模擬器和相關的驅動程式以及協議轉換程式,網口下載還要有乙太網路支援;另一方面uCLinux預設通過串口列印其啟動並執行資訊,那麼串口不但可以提 供燒寫Flash的功能,還可作為調試uCLinux核心的通道。
在本系統中,Flash在剛開始時,只儲存了bootloader,還沒有儲存uCLinux核心和檔案系統。因此bootloader在系統加電完成初始化工作後,要初始化一條連結主機和目標機的串口通道,並提供串口下載功能。
(2)系統初始化
因為系統剛加電時,作業系統的核心還沒有被載入,系統的初始化工作由bootloader完成。它主要是將系統、初始化儲存系統、配置ARM各種模式下的資料棧、使能屏常中斷、根據需要切換處理器模式和狀態。
(3)uCLinux核心載入方式
固化在Flash中的uCLinux核心有兩種運行方式:一種方式是直接在Flash中運行uCLinux內建的引導程式;另一種方式是將固化在Flash中的核心先拷貝到SDRAM的某一段地址區間,再從該段地址區間的首地址運行uCLinux核心。
第一種方式是bootloader進行系統初始化工作後,跳到核心固化在Flash中的首地址處,將控制權交給uCLinux,開始在Flash中 逐句執行核心內建的引導程式,由該引導程式完成核心的載入工作。這種方式是目前很多嵌入式系統啟動核心所採用的方式,也是本系統採用的核心載入方式。
第二種方式是bootloader完成系統初始化工作後,把核心的映像檔案由Flash拷貝到SDRAM中,再從SDRAM中執行uCLinux核心的引導程式,載入uCLinux核心。
第二種載入方式在SDRAM中運行程式,因此執行速度比第一種方式快一些,並且可以通過 RAM快速引導技術實現這種載入方式。其主要是針對NAND型Flash的情況。與NOR型Flash最大的不同點是:NOR型Flash使用記憶體隨機讀 取技術,與SDRAM一樣,可以直接執行儲存在Flash中的程式;而NAND一樣,可以直接記憶體隨機讀取技術,它是一次讀取一整塊記憶體,因此不能直接執 行儲存在NAND型Flash中的程式,必須把NAND型Flash中的程式先拷貝到SDRAM,再在SDRAM中執行該程式。但是NAND型Flash 價格比NOR型Flash廉價,所以很多嵌入式系統還是採用NOR型Flash(幾百K位元組)+NAND型Flash(幾MB)的儲存模式。其中NOR 型Flash存放可執行檔且代碼量小的bootloader和一些必要的資料,而NAND型Flash儲存儲存量較大的核心和檔案系統。
在本系統中,由於採用NOR型Flash儲存bootloader、核心和檔案系統,所以可以直接存取核心所在地址區間的首地址,執行核心自己的引導程式,而且核心內建的引導程式功能強大,可以方便地核心的載入,向核心傳遞有關的硬體參數。本系統採用第一種載入方式。
(4)自舉模式和核心啟動模式的切換
Bootloader一般要實現兩種啟動模式:自舉模式和核心啟動模式。自舉模式也稱為 bootstrap模式,該模式的主要作用是目標機通過串口與主機通訊,可以接收主機發送過來的映像檔案,例如核心、檔案系統和應用程式,並將其固化在 Flash中,也可以將Flash中的映像檔案上傳到主機。核心啟動模式允許嵌入式系統加電啟動後載入uCLinux核心,將系統交由uCLinux操作 系統管理。
在本系統中,採用一個開關實現兩種模式的切抽象。在系統的Flash中只有 bootloader時,首先將開關拔上去,提示系統進入自舉模式,加電啟動後,bootloader根據開關的狀態,進入自舉模式,接收主機發送過來的 核心和檔案系統的映像檔案。接著將開關拔下來,提示系統進入核心啟動模式,再按鏈,bootloader根據此時的開關狀態進入核心啟動模式,載入核心和 檔案系統,由作業系統接管系統。以後也可以根據需要,設定開關的狀態,以提示系統進入不同的啟動模式。
(5)地址映射表的配置和重新對應
地址映射表的配置包括設定Flash地址空間、SDRAM地址空間、外部I/O位址範圍和處理器寄存器位址範圍。ARM處理器加電後執行在地址0x0處的 代碼,因此在加電啟動時,首先將儲存了bootlader的Flash地址空間設定為 0x0-0x200000,將SDRAM的地址空間設定為0x1000000-0x2000000,當核心引導程式將核心拷貝到SDRAM後,再設定 SDRAM的地址空間為0x00x1000000,而Flash的地址空間為0x1800000-0x1A00000。這需要在核心引導程式中對 Flash和SDRAM的地址空間進行重新對應。
本文採用的系統啟動引導方案流程圖1。
3 uCLinux核心的載入和初始化
本啟動方案中採用uCLinux內建的引導程式載入核心。該引導程式碼在 linux/arch/armnommu/boot/compressed目錄,其中Head.s的作用最關鍵,它完成了載入核心的大部分工作; Misc.c則提供載入核心所需要的子程式,其中解壓核心的子程式是Head.s調用的重要程式,另外核心的載入還必須知道系統必要的硬體資訊,該硬體信 息在hardware.h中並被Head.s所引用。
當bootloader將控制權交給核心的引導程式時,第一個執行的程式就是 Head.s。下面基於本系統介紹Head.s載入核心的主要過程。Head.s首先配置S3C4510的系統寄存器;再初始化S3C4510的ROM、 RAM以及匯流排等控制寄存器,將Flash和SDRAM的位址範圍分別設定為0x0-0x200000和0x1000000-0x2000000;接著將 核心的映像檔案從Flash拷貝到SDRAM,並將Flash和SDRAM的地址區間分別重新對應為0x1800000-0x1A00000和0x0- 0x1000000;然後調用Misc.c中的解壓核心功能(decompress_kernel),對拷貝到SDRAM的核心映像檔案進行解壓縮;最後 跳轉到執行調用核心功能(call_kernel),將控制權交給解壓後的uCLinux系統。
執行Call_kernel函數實際上是執行linux/init/main.c中的start_kernel函數,中包括處理器結構的初始化、中斷的初始化、進程相關的初始化以及記憶體初始化等重要工作。
該啟動引導方案實現了自舉模式和核心啟動模式以及兩種模式的切換,使得開人員既可以採用自舉模式方便地燒寫Flash,更新嵌入式系統中的軟體平台,又能 夠切換到核心啟動模式,自動安全地啟動系統;其次,本方案採用簡易的串口通道作業主機與目標系統的通訊渠道,既可以方便地將作業系統核心、檔案系統和其他 應用下載到目標系統中,又可以作為調試uCLinux核心和應用程式通道;此外針對 ARM7TDMI的無MMU特性,採用修改後的uCLinux核心引導程式載入作業系統和初始化作業系統環境,解決核心載入的地址重新對應問題和作業系統的 記憶體管理問題。