前 言
本文引用地址:http://www.eepw.com.cn/article/171586.htm隨著計算機硬體技術的不斷發展,功能強大、資源豐富的嵌入式晶片,成為研究人員開發專業應用領域產品的首選。三星公司生產的S3C44B0晶片,採用ARM7TDM I內核,具有功耗小、成本低的特點,是一款專門針對移動終端及PDA手持設備市場的產品。近幾年,源碼開放的L inux系統迅速發展,很快成為跨平臺作業系統中的佼佼者,並且出現了專門針對嵌入式系統的產品———uClinux。在S3C44B0晶片上移植 uClinux作業系統,能夠充分發揮該晶片系統資源豐富(相對單片機而言)的特點,開發出功能強大的應用產品。
嵌入式系統的啟動引導程序與硬體嚴格相關,對編寫人員的要求較高,而在移植uClinux後又大大增加了引導程序的複雜程度,因此這部分代碼往往是各個嵌入式產品開發廠商嚴格保密的部分。下面將以一款市場上成熟的基於S3C44B0晶片的嵌入式開發板為藍本,對引導uClinux內核的過程進行分析。
系統引導過程分析
嵌入式系統中uClinux內核的系統引導過程通常可以分為3個階段,即boot階段、系統初始化階段和uClinux內核引導階段。通常情況下boot階段和系統初始化階段的工作由一段被稱為bootloader的代碼完成,而內核引導則是由事先編譯好了的uClinux可執行鏡像來實現。
系統內存組織
由於嵌入式系統的硬體環境千差萬別,即使選用同一種型號的嵌入式晶片,其外圍設備也大不相同,特別是存儲設備的組織,將直接關係到引導程序的實現。對於 S3C44B0晶片,其生產廠家規定在系統加電自舉後,從0x00000000處開始執行(其他晶片如ARM9系列可以通過地址映射改變該地址) ,故此處通常安排的是Flash 地址空間,用於保存bootloader啟動代碼以及uClinux映象。對於S3C44B0 晶片, RAM 地址被固定在0x0c000000到0x0fffffff的64兆,開發人員可以根據自己的需要再組織RAM,如本開發板存儲器地址安排如下:
此外,考慮到Flash運行速度的問題,通常採取的做法是將系統初始化階段的代碼和uClinux內核鏡像拷貝到RAM中執行。下面將分3個階段分析系統引導過程。
boot階段
boot階段的主要工作是設置系統中斷向量、完成對CPU內部寄存器的初始化、系統RAM初始化、為運行C程序組織堆棧、拷貝初始化階段代碼到RAM、跳轉到C程序入口。該階段代碼直接在Flash中運行,為提高執行效率採用彙編語言編寫。
(1) 設置中斷向量。設置S3C44B0晶片的8種系統中斷的中斷向量地址(包括復位中斷、未定義指令中斷、軟體中斷、指令預取異常中斷、數據異常中斷、地址異常中斷、IRQ 中斷和F IQ 中斷) ,該地址空間從系統RAM的起始地址開始安排。通常情況下,在Flash的起始部分,存放的就是針對各中斷向量地址的無條件跳轉指令。
__entry :
B ResetHandler
/* for reset vector */
LDR PC, = 0x0c00000c
/* 0x0c00000: 未定義指令中斷向量地址*/
……
/* 中間省略類似跳轉*/
LDR PC, = 0x0c000024
/* 0x0c000024: F IQ中斷向量地址*/
(2) CPU內部寄存器初始化。通過配置CPU運行於SVC模式(採用改變CPSC寄存器中CPU運行模式位的方式來實現) ,並設置相關寄存器,以實現對基本硬體的初始化工作,包括關閉中斷、初始化CPU通用埠和設置CPU頻率等。進入SVC模式彙編代碼如下:
MRS a1, CPSR /* 保存當前狀態寄存器值*/
BICa1, a1, #MODE_MASK /* 清除運行模式位*/
ORR a1, a1, #SUP_MODE/* 設置為超級用戶模式*/
ORR a1, a1, #LOCKOUT /* 關閉F IQ和IRQ */
MSR CPSR_cxsf, a1 /* 保存到當前狀態寄存器*/
(3) 系統RAM初始化。初始化系統RAM的主要目的是為下面使用RAM空間的操作做好準備工作,如進行代碼拷貝及堆棧初始化等。這部分工作可以分為兩個步驟。首先,根據系統配置的存儲器特性,初始化相關存儲塊控制寄存器的值, 在S3C44B0 中存儲空間被分為BANK0到BANK7共8個塊,分別由BANKCON0到BANKCON7控制各塊存儲器的讀寫時鐘數和片選時鐘數等信號參數,對於採取不同存儲晶片的嵌入式系統,可以通過查閱晶片手冊來獲取該信息,並寫入相關寄存器。
LDR r0, = rBANKCON0
LDR r1, = 0x700
STR r1, [ r0 ]
/* 中間省略BANK1到BANK6*/
LDR r0, = rBANKCON7
LDR r1, = 0x18000
STR r1, [ r0 ]
LDR r0, = rREFRESH
LDR r1, = 0xac03e1
STR r1, [ r0 ]
LDR r0, = rBANKSIZE
LDR r1, = 0x16
STR r1, [ r0 ]