關(guān)于三星S3C44B0X目標(biāo)板的uClinux Bootloader
關(guān)于三星S3C44B0X目標(biāo)板的uClinux Bootloader
(Implementing Bootloader for uClinux on Samsung S3C44B0X Board)
上海交通大學(xué)計算機(jī)科學(xué)與工程系 盛磊
(Department of Computer Science & Engineering, Shanghai Jiaotong University Lei SHENG)
摘要: S3C44B0X是常用的一款基于ARM7TDMI內(nèi)核的RISC處理器。uClinux操作系統(tǒng)可以很好地支持此類無MMU的處理器。本文介紹了在S3C44B0X目標(biāo)板上移植uClinux的重要步驟之一:Bootloader開發(fā)的概念和過程。
關(guān)鍵詞: S3C44B0X;uClinux;Bootloader;ARM Kernel XIP
本文于2005年1月13日收到。盛磊:工程碩士,主要從事嵌入式系統(tǒng)開發(fā)和半導(dǎo)體存儲器應(yīng)用等方面的研究。
uClinux是為控制領(lǐng)域設(shè)計的嵌入式Linux操作系統(tǒng),它沿襲了主流Linux的大部分特性,并進(jìn)行了一定幅度的裁減。其設(shè)計主要針對沒有內(nèi)存管理單元(MMU)的微處理器,例如基于ARM7TDMI內(nèi)核的S3C44B0X。
嵌入式Linux系統(tǒng)通常由三部份組成:Bootloader、Kernel和File System。其中Bootloader是在系統(tǒng)啟動之后、Kernel運(yùn)行之前所執(zhí)行的第一段代碼,其任務(wù)是為調(diào)用Kernel準(zhǔn)備必要的軟硬件環(huán)境。由此可見,Bootloader是非常依賴于硬件和操作系統(tǒng)的。所謂依賴于硬件,是指Bootloader的實現(xiàn)與處理器體系架構(gòu)和板級硬件資源密切相關(guān);所謂依賴于操作系統(tǒng),是指不同操作系統(tǒng)的內(nèi)核對調(diào)用方式和運(yùn)行環(huán)境有不同的要求。
理論上,uClinux在引導(dǎo)時并非一定需要一個獨(dú)立于Kernel Image的Bootloader Image。然而將Bootloader與Kernel分開設(shè)計能夠使軟件架構(gòu)更加清晰,也有助于靈活地支持多種引導(dǎo)方式,實現(xiàn)必要的輔助功能。uClinux Bootloader的主要任務(wù)可概括如下:
● 引導(dǎo)和初始化
● 加載uClinux Kernel
● 設(shè)置內(nèi)核啟動參數(shù)
● 調(diào)用uClinux Kernel
● 輔助功能:文件下載、Flash燒寫、人機(jī)界面等
對于常見架構(gòu)的處理器,一般都能找到現(xiàn)成的Bootloader,但其結(jié)構(gòu)往往較為復(fù)雜,且仍需要針對具體的目標(biāo)板進(jìn)行移植。當(dāng)然,也可以選擇自行開發(fā)Bootloader。由于Bootloader Image在物理上獨(dú)立于Kernel Image,因此不一定跟隨Linux選用GNU作為開發(fā)工具。對于ARM處理器,完全可以使用ADS或RVDS等集成環(huán)境來開發(fā)Bootloader。
1.引導(dǎo)和初始化
1.1 硬件初始化階段一
S3C44B0X在上電或復(fù)位后,程序從位于地址0x0的Reset Exception Vector處開始執(zhí)行,因此需要在這里放置Bootloader的第一條指令:b ResetHandler,跳轉(zhuǎn)到標(biāo)號ResetHandler處進(jìn)行第一階段的硬件初始化,主要內(nèi)容為:關(guān)WDT,關(guān)中斷,配置PLL和時鐘,初始化Memory Controller。這里比較重要的是配置PLL的輸出頻率,S3C44B0X最高能夠支持66MHz;如果目標(biāo)板上使用DRAM/SDRAM,應(yīng)當(dāng)據(jù)此計算刷新頻率等相關(guān)參數(shù)。
1.2 建立異常向量表
ARM7TDMI內(nèi)核規(guī)定:包括Reset Exception Vector在內(nèi)的異常向量表的基地址是0x0,所以存放Bootloader的Flash基地址也必須是0x0;而S3C44B0X處理器又不支持Remap,這意味著一旦發(fā)生中斷,程序就要跳轉(zhuǎn)到Flash中的異常向量表(中斷屬于異常的一種)。uClinux會在RAM里建立自己的二級異常向量表(基地址缺省為0x0C000000);所以編寫B(tài)ootloader時,0x0處的一級異常向量表只需簡單地包含向二級異常向量表的跳轉(zhuǎn):
b ResetHandler ;Reset Handler
ldr pc,=0x0c000004 ;Undefined Instruction Handler
ldr pc,=0x0c000008 ;Software Interrupt Handler
ldr pc,=0x0c00000c ;Prefetch Abort Handler
ldr pc,=0x0c000010 ;Data Abort Handler
b . ;Reserved
ldr pc,=0x0c000018 ;IRQ Handler
ldr pc,=0x0c00001c ;FIQ Handler
如果在Bootloader運(yùn)行過程中不必響應(yīng)中斷,那么上面的配置已能滿足要求。如果某些Bootloader功能要求使用中斷(例如用Timer Interrupt實現(xiàn)精確定時),那么Bootloader必須在同樣的位置建立自己的二級異常向量表,以便同uClinux保持一致。這張表應(yīng)存放在Flash中,并由Bootloader復(fù)制到RAM地址0x0C000000處。
1.3 初始化各種處理器模式
ARM7TDMI內(nèi)核支持7種處理器模式:User,F(xiàn)IQ,IRQ,Supervisor,Abort,System和Undefined。Bootloader需要依次切換到每種模式,初始化該模式的程序狀態(tài)寄存器(SPSR)和堆棧指針(SP)。S3C44B0X在上電或復(fù)位后處于Supervisor模式;本步驟中應(yīng)該在最后切換回Supervisor模式,即Bootloader后續(xù)部份仍將運(yùn)行在Supervisor模式下。
1.4 section重定位
對于ADS或RVDS等開發(fā)工具,一個ARM程序通常由RO、RW和ZI三個section組成,其中RO是代碼和常量,RW是已初始化的全局變量,ZI是未初始化的全局變量(在GNU中對應(yīng)的概念是TEXT、DATA和BSS)。RO代碼既可以在Flash中運(yùn)行,也可以在RAM中運(yùn)行??紤]到Bootloader可能需要燒寫Flash,而燒寫時處理器無法從Flash中讀取指令,因此應(yīng)將RO和RW復(fù)制到RAM中,并將ZI清零。RO復(fù)制完畢之后,程序就可以跳轉(zhuǎn)到RAM中運(yùn)行。若不考慮燒寫Flash,則Bootloader不必復(fù)制RO,程序始終在Flash中運(yùn)行。
1.5 填寫中斷向量表
中斷向量表一般位于RAM地址的最高端,存放著各個ISR的入口地址。由于IRQ Exception為全部中斷所共用,因此必須在IRQ Exception服務(wù)例程中根據(jù)中斷狀態(tài)寄存器來判斷中斷源并調(diào)用相應(yīng)的ISR。各個ISR的入口地址需要在這一步里填寫。
另外,S3C44B0X的中斷控制器支持Vectored和Non-Vectored兩種中斷處理模式,其中前者是Samsung自行開發(fā)的模式,并不被大多數(shù)ARM處理器所支持??紤]到代碼的可移植性,上面只討論了Non-Vectored Mode。
1.6 硬件初始化階段二
遵循“必要”原則繼續(xù)對硬件資源進(jìn)行初始化,包括S3C44B0X內(nèi)置的GPIO、Cache、中斷控制器和UART等。Bootloader中暫未用到的設(shè)備可以留待使用之前再進(jìn)行初始化。
S3C44B0X內(nèi)置有數(shù)據(jù)/指令合一的8KB Cache,且允許按照地址范圍設(shè)置兩個Non-Cacheable的區(qū)間。合理的配置是打開對RAM地址區(qū)間的Cache,關(guān)閉對其它地址區(qū)間的Cache,以避免可能存在的Cache一致性問題。
1.7 建立人機(jī)界面
引導(dǎo)過程的最后一步是在串行終端上建立人機(jī)交互界面。常見的做法是先等待固定的時間,若未接收到用戶輸入,則直接從Flash中加載或調(diào)用uClinux Kernel;若接收到用戶輸入,則顯示菜單模式或命令行模式的交互界面,并等待進(jìn)一步的命令。
2. 加載uClinux Kernel
Bootloader是否需要執(zhí)行加載操作,取決于uClinux Kernel Image的類型。根據(jù)不同的配置方式,可以生成以下幾種uClinux Kernel Image:
2.1 非壓縮,非XIP
XIP(eXecute In Place)是指在存放代碼的位置上就地運(yùn)行程序;而非XIP就是指在運(yùn)行之前需要對代碼進(jìn)行重定位。該類型的uClinux Kernel Image以非壓縮格式存放在Flash中,需由Bootloader加載到RAM然后調(diào)用。該類型在開發(fā)調(diào)試階段最為常用。
2.2 非壓縮,XIP
該類型的uClinux Kernel Image以非壓縮格式存放在Flash中,不需加載,由Bootloader直接調(diào)用。復(fù)制Data段和清零BSS段的工作由Kernel自行完成。該類型常用于RAM空間非常有限的系統(tǒng)中,缺點是程序在Flash中運(yùn)行的速度稍慢。
2.3 RAM自解壓
壓縮格式的uClinux Kernel Image由開頭的一段自解壓代碼和其后的壓縮數(shù)據(jù)組成。由于是以壓縮格式存放,因此Kernel只能以非XIP方式運(yùn)行。RAM自解壓的uClinux Kernel Image存放在Flash中,由Bootloader加載到RAM中的臨時空間,然后調(diào)用自解壓代碼。Kernel被解壓到最終的目標(biāo)空間然后運(yùn)行;壓縮鏡像所占據(jù)的臨時空間在隨后由uClinux回收利用。該類型占用Flash較少,且運(yùn)行速度較快,在最終產(chǎn)品中更為常見。
2.4 ROM自解壓
解壓縮代碼也能夠以XIP的方式在Flash中運(yùn)行。ROM自解壓的uClinux Kernel Image存放在Flash中,不需加載,由Bootloader直接調(diào)用其自解壓代碼,將uClinux Kernel解壓到最終的目標(biāo)空間并運(yùn)行之。與RAM自解壓相比,ROM自解壓并不真正節(jié)省RAM,而且解壓縮的速度較慢,因此實用價值不大。
3. 設(shè)置內(nèi)核啟動參數(shù)
Linux 2.4版本以后的內(nèi)核都期望以標(biāo)記列表(tagged list)的形式來接收啟動參數(shù)。每個標(biāo)記存放在一個tag結(jié)構(gòu)中,每個tag結(jié)構(gòu)由標(biāo)識被傳遞參數(shù)的tag_header結(jié)構(gòu)以及隨后的參數(shù)值組成。通常由Bootloader設(shè)置的啟動參數(shù)有:ATAG_MEM、ATAG_CMDLINE、ATAG_SERIAL等。啟動參數(shù)的標(biāo)記列表以ATAG_CORE開始,以ATAG_NONE結(jié)束,代碼示例如下。其中0x0C000100是內(nèi)核啟動參數(shù)在RAM中的基地址,Bootloader應(yīng)當(dāng)將要傳遞的啟動參數(shù)復(fù)制到該處RAM中;指針params的類型是struct tag。宏tag_next()以指向當(dāng)前標(biāo)記的指針為參數(shù),計算下一個標(biāo)記的起始地址。
params = (struct tag *)0x0C000100;
params->hdr.tag = ATAG_CORE;
params->hdr.size = tag_size(tag_core);
params->u.core.flags = 0;
params->u.core.pagesize = 0;
params->u.core.rootdev = 0;
params = tag_next(params);
......
params->hdr.tag = ATAG_NONE;
params->hdr.size = 0;
對應(yīng)地,在Linux內(nèi)核源碼arch/armnommu/mach-s3c44b0/arch.c中設(shè)置內(nèi)核啟動參數(shù)在RAM中的基地址:
MACHINE_START (S3C44B0, "44B0")
......
BOOT_PARAMS (0x0C000100)
......
MACHINE_END
4. 調(diào)用uClinux Kernel
Bootloader調(diào)用Kernel的方法是直接跳轉(zhuǎn)到其第一條指令處。對于ARM處理器,在跳轉(zhuǎn)時應(yīng)當(dāng)滿足下列條件:r0=0;r1=Machine ID;禁止IRQ和FIQ;處理器運(yùn)行在Supervisor模式;關(guān)閉MMU;關(guān)閉Data Cache。
對于S3C44B0X,它沒有MMU,其Cache是指令與數(shù)據(jù)合一的,因此只能全部關(guān)閉。
各種ARM處理器的Machine ID均由www.arm.linux.org.uk分配;S3C44B0X的Machine ID是178。據(jù)此,用C代碼實現(xiàn)的Kernel調(diào)用示例如下,其中r0和r1的值通過參數(shù)傳遞:
void (*CallKernel)(int zero, int mach) = (void (*)(int, int))KERNEL_ADDR;
CallKernel(0, 178);
5. 輔助功能
完整的Bootloader還應(yīng)該允許更新Flash中存放的uClinux Kernel Image以及Bootloader自身。為此,必要的輔助功能包括:從主機(jī)下載文件到目標(biāo)板的RAM;用RAM中的數(shù)據(jù)燒寫Flash;以及實現(xiàn)上述操作所需的人機(jī)交互接口,這里就不贅述了。
參考文獻(xiàn):
[1] 李善平,劉文峰等,Linux與嵌入式系統(tǒng),清華大學(xué)出版社,2003年1月
[2] 詹榮開,嵌入式系統(tǒng)Boot Loader技術(shù)內(nèi)幕,2003年12月
[3] ARM Architecture Reference Manual, ARM, 2000
[4] S3C44B0X RISC Microprocessor User's Manual, Samsung, 2002
評論