郭國法,董輝,張開生
(陜西科技大學 電氣與信息工程學院,西安 710021)
U-Boot移植過程中兩種代碼重定位技術(shù)研究
郭國法,董輝,張開生
(陜西科技大學 電氣與信息工程學院,西安 710021)
針對ARM架構(gòu)的U-Boot移植過程中處理器種類繁多、啟動方式多樣化這一問題,提出了兩種代碼重定位技術(shù)。該代碼重定位技術(shù)實現(xiàn)了在任何一種存儲器上均能夠啟動U-Boot程序,并對兩種技術(shù)進行了比較。實驗表明,選擇使鏈接地址固定的代碼重定位技術(shù)可以實現(xiàn)U-Boot的高效移植。
嵌入式系統(tǒng);U-Boot;代碼重定位技術(shù);移植
嵌入式Linux系統(tǒng)包括BootLoader、內(nèi)核、文件系統(tǒng)和應(yīng)用程序。上電或復位后,首先執(zhí)行的是BootLoader程序,BootLoader初始化硬件設(shè)備,創(chuàng)建好C程序運行環(huán)境,然后引導內(nèi)核,內(nèi)核啟動后掛接文件系統(tǒng),最后啟動init進程,執(zhí)行應(yīng)用程序。對于嵌入式系統(tǒng),BootLoader依賴于實際的硬件和應(yīng)用環(huán)境,因此要為嵌入式系統(tǒng)建立一個通用、標準的BootLoader是非常困難的。不過,大部分BootLoader仍然具有很多共性,某些BootLoader也能夠支持多種體系結(jié)構(gòu)的嵌入式系統(tǒng)。例如U-Boot同時支持PowerPC、ARM、MIPS和X86等體系結(jié)構(gòu),支持的開發(fā)板有上百種。通常,它們能夠自動從存儲介質(zhì)上啟動,引導操作系統(tǒng)啟動,并且大部分可以支持串口和以太網(wǎng)接口。
U-Boot是由開源項目PPCBoot發(fā)展起來的,ARMboot并入了PPCBoot,PPCBoot和其他一些架構(gòu)的BootLoader合稱U-Boot。U-Boot的功能強大,涵蓋了絕大部分處理器構(gòu)架,提供大量外設(shè)驅(qū)動,支持多個文件系統(tǒng),附帶調(diào)試、腳本、引導等工具,特別支持Linux,為板級移植做了大量的工作。
U-Boot啟動分為兩個階段。第一階段主要包含依賴于CPU體系結(jié)構(gòu)的硬件初始化代碼,通常都用匯編語言來實現(xiàn)。第二階段通常用C語言完成,以便實現(xiàn)更復雜的功能,也使程序有更好的可讀性和可移植性,最終調(diào)用內(nèi)核。
第一階段包括:① 硬件設(shè)備初始化;② 加載U-Boot第二階段代碼到RAM空間;③ 設(shè)置棧;④ 跳轉(zhuǎn)到第二階段代碼入口。
第二階段包括:① 初始化本階段使用的硬件設(shè)備;② 檢測系統(tǒng)內(nèi)存映射;③ 將內(nèi)核從Flash讀取到RAM中;④ 為內(nèi)核設(shè)置啟動參數(shù);⑤ 調(diào)用內(nèi)核。
2.1 代碼重定位技術(shù)由來
什么是代碼重定位?在嵌入式系統(tǒng)中,系統(tǒng)上電后,將代碼從一個存儲區(qū)域拷貝到另一個存儲區(qū)域,然后跳轉(zhuǎn)到拷貝的那個存儲區(qū)域執(zhí)行代碼,這就是代碼重定位。ARM系列的處理器支持多種啟動方式[2],包括NAND Flash,NOR Flash,eMMC,SD卡啟動,如圖1所示。
圖1 ARM存儲器結(jié)構(gòu)示意圖
系統(tǒng)上電或復位后,其過程如圖2所示,U-Boot程序把自身的程序從存儲介質(zhì)拷貝到片外SDRAM,跳轉(zhuǎn)到SDRAM執(zhí)行U-Boot程序,然后引導操作系統(tǒng),操作系統(tǒng)掛接根文件系統(tǒng),最后執(zhí)行應(yīng)用程序??梢夾RM架構(gòu)處理器的U-Boot移植中都涉及到代碼重定位問題。
圖2 系統(tǒng)從上電或復位到執(zhí)行應(yīng)用程序的過程
2.2 ARM架構(gòu)微處理器兩種啟動方式
CPU上電或復位后首先執(zhí)行0地址處的代碼,按照0地址所在RAM是否在CPU內(nèi)部,將啟動方式分為兩類:片外0地址啟動方式,NOR Flash啟動;片內(nèi)iRAM起始地址啟動方式,NAND Flash、eMMC、SD卡啟動?,F(xiàn)結(jié)合ARM9 架構(gòu)的S3C2440芯片對兩種啟動方式做介紹。
2.2.1 片內(nèi)iRAM起始地址啟動方式
ARM架構(gòu)微處理器大多采用統(tǒng)一編址方式,部分處理器的片內(nèi)iRAM起始地址不是0,之所以不是從0開始,是因為0地址開始是廠家固化好的一段引導程序,就是圖2中處理器自動完成部分,為了統(tǒng)一,統(tǒng)稱為片內(nèi)iRAM起始地址啟動方式,除了NOR Flash啟動外,其他啟動方式都是片內(nèi)iRAM起始地址啟動方式。以NAND Flash為例,NAND Flash可以存儲程序,要執(zhí)行程序唯一的方法就是把程序讀到RAM中,然后在RAM執(zhí)行程序。對于S3C2440處理器,當系統(tǒng)上電或復位后,芯片內(nèi)部固化的程序判斷是從NAND Flash啟動,然后把NAND Flash的前4 KB內(nèi)容拷貝到片內(nèi)iRAM,從片內(nèi)iRAM的0地址處開始執(zhí)行U-Boot程序。U-Boot程序里面的代碼重定位程序會將NOR Flash中的U-Boot程序整個拷貝到片外RAM(SDARM)中去,清除bss段,bss段在程序運行時存放未初始化的全局變量,然后將程序指針指向外部RAM(SDARM)中執(zhí)行程序,即完成重定位功能。
移植支持NAND Flash啟動的U-Boot,其難點在于片內(nèi)iRAM的大小只有4 KB,而一般編譯出來的uboot.bin文件的大小從150 KB到350 KB大小不等,肯定大于RAM自帶的4 KB空間,所以就把CPU初始化代碼和重定位代碼鏈接到U-Boot程序的最前面4 KB,并且匯編部分都使用位置無關(guān)代碼,所以重定位功能必須在U-Boot程序的前4 KB代碼完成。
2.2.2 片外0地址啟動方式
NOR Flash可以像內(nèi)存一樣讀,但是不能像內(nèi)存一樣寫,所以程序可以在NOR Flash上執(zhí)行[3]。對于S3C2440處理器,當系統(tǒng)上電或復位后,芯片內(nèi)部固化的程序判斷是從NOR Flash啟動,然后從0地址處開始執(zhí)行程序。由于NOR Flash不能像內(nèi)存一樣寫, 而且我們的目的是讓U-Boot程序在片外RAM(SDARM)中運行,所以NOR Flash也需要代碼重定位。代碼重定位程序會將NOR Flash 中的U-Boot程序整個拷貝到片外RAM(SDARM)中去,清除bss段,然后將程序指針指向外部RAM(SDARM)中執(zhí)行程序,完成代碼重定位。
這里介紹兩種代碼重定位技術(shù):一種是在Makefile[4]編譯前把鏈接地址固定;另一種是先把U-Boot代碼拷貝到SDRAM中,然后程序自己修改鏈接地址,現(xiàn)分別對這兩種方法做介紹。
3.1 固定鏈接地址的代碼重定位技術(shù)
鏈接地址是程序?qū)嶋H運行的地址。將U-Boot程序拷貝到鏈接地址的起始地址處,然后執(zhí)行“l(fā)dr pc,=_start_armboot”,程序會跳轉(zhuǎn)到SDRAM執(zhí)行U-Boot程序。主要解決以下問題:從什么地方拷貝?拷貝多大?拷貝到什么地方去?如何拷貝?下面針對這些問題對固定鏈接地址的U-Boot代碼重定位方法做論述。
① 首先將鏈接地址設(shè)置為片外RAM中的某個地址值,由于U-Boot的版本差別,其修改方法也不一樣,對于U-Boot201003,在board目錄下開發(fā)板目錄里面的config.mk文件,有一行內(nèi)容“TEXT_BASE=0x33F0 0000”,意思是鏈接地址的起始地址是0x33F0 0000,也就是U-Boot在SDRAM里面的起始地址是0x33F0 0000。
② 完成拷貝函數(shù),拷貝函數(shù)從存儲器把U-Boot程序拷貝到SDRAM的0x33F0 0000地址處,由于拷貝過程太復雜,所以用C語言完成。C語言運行需要棧,先設(shè)置棧,棧的設(shè)置比較靈活,就是把sp指針指向一塊沒有使用的內(nèi)存[5],因為iRAM大小只有4 KB,SDRAM要64 MB,顯然要把棧設(shè)置到SDRAM,設(shè)置好棧后就可以由匯編跳轉(zhuǎn)到C語言來執(zhí)行拷貝函數(shù)了。
③ 修改鏈接腳本,對于NAND Flash啟動,要考慮第一階段代碼小于4 KB。上面講過方法,就是修改鏈接腳本,把第一階段用到的.o目標文件放在前面4 KB,最后把生成的U-Boot二進制文件反匯編,鏈接起始地址0x33F0 0000加4 KB等于0x33F0 1000,觀察U-Boot第一階段用到的函數(shù)是不是都小于0x33F0 1000,要是小于,則鏈接腳本修改正確。
④ 前4 KB內(nèi)容必須使用位置無關(guān)代碼[6]完成,所謂位置無關(guān)代碼就是不管這條指令是在0地址還是其他地址執(zhí)行,都能跳轉(zhuǎn)到指定的位置。那么這條指令就是位置無關(guān)代碼。
通過上述步驟可以得知,拷貝函數(shù)從存儲器的0地址開始拷貝uboot.bin文件,拷貝到SDRAM的0x33F0 0000處,拷貝大小為從uboot.bin文件的__bss_start段鏈接地址減去.text段鏈接地址。
固定鏈接地址的重定位代碼分析:
#define CONFIG_SYS_INIT_SP_ADDR 0X30000f80
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
bl nand_init_ll
mov r0, #0 //源
ldr r1, _TEXT_BASE //目的
ldr r2, _bss_start_ofs //大小
bl copy_code_to_sdram
ldr pc, =_start_armboot
首先宏定義了棧的地址,然后把sp指針指向該地址,bic sp、sp、#7指令使得sp以8字節(jié)對齊;相對跳轉(zhuǎn)指令跳轉(zhuǎn)到C語言nand_init_ll程序,完成NAND Flash初始化;然后給r0、r1、r2寄存器賦值作為下一步copy_code_to_sdram函數(shù)的參數(shù),相對跳轉(zhuǎn)指令bl跳轉(zhuǎn)執(zhí)行copy_code_to_sdram函數(shù),完成uboot.bin拷貝到SDRAM;最后一條指令ldr pc, =_start_armboot在下一個機器周期到來后跳轉(zhuǎn)到SDRAM的_start_armboot執(zhí)行U-Boot第二階段[7]。
3.2 修改鏈接地址的代碼重定位技術(shù)
U-Boot的鏈接地址是0,程序運行時訪問全局變量、靜態(tài)變量,調(diào)用函數(shù)所使用的地址是“基于0地址編譯得到的地址”。現(xiàn)在把程序復制到SDRAM需要修改代碼,把“基于0地址編譯得到的地址”修改為基于新地址。
程序里面有些地址在鏈接時候不能確定,要到運行前才能確定。此處用到的方法就是修改代碼,讓函數(shù)使用新地址。比如,原來程序的鏈接地址是0,變量的地址是0x100,復制程序到SDRAM的地址0x3200 0000,那么變量的鏈接地址就要做相應(yīng)的修改,把0x100改為0x3200 0100,這樣程序在0x3200 0100地址處便能找到這個變量[1],過程可以表示為:
舊鏈接地址+拷貝目的地址=新鏈接地址
那么如何知道舊地址存在哪里?編譯u-boot.bin的時候加-pie選項,就會生成地址信息[8],存在“.rel”、“dynsym”這些段里,U-Boot程序運行的時候就根據(jù)這些段里的信息修改代碼。把生成的ELF格式的可執(zhí)行文件U-Boot用arm-linux-objdump-Du-boot>u-boot.dis命令反匯編,生成u-boot.dis文件,找到.rel段,如圖3所示。從圖中可以看出,rel段的起始位置為_ _rel_dyn_start,中間每隔一行有一個標記位0x17,每行為32個二進制位,占4個字節(jié),重定位函數(shù)里面修改代碼算法就是根據(jù)這些特點修改U-Boot.bin程序的。
圖3 反匯編代碼里的部分.rel段
在U-Boot-2012.03中使用的代碼重定位函數(shù)為Relocate_code(addr_sp,id,addr),該函數(shù)有3個參數(shù),分別是addr_sp、id和addr,其中addr_sp為棧的地址,id為gd_t數(shù)據(jù)結(jié)構(gòu)地址,addr為拷貝到SDARM的目的地址。
圖4 修改uboot.bin 文件原理圖
修改部分的代碼由匯報指令完成,現(xiàn)將其原理做簡單介紹。如圖4所示,為了說明修改算法原理,列舉兩個變量*A和D,指針變量A等于_ _rel_dyn_start_ofs的鏈接地址,D為A所指向的地址處的數(shù)值,V為偏移值,其值等于把u_boot拷貝到SDRAM的目的地址,給A加上偏移得到新的鏈接地址,然后把舊的值B賦給新的地址,一直循環(huán),直到A等于_ _dyn_end_ofs,完成u_boot代碼修改。
3.3 兩種技術(shù)比較
上面介紹的兩種代碼的重定位技術(shù)各有優(yōu)劣。固定鏈接地址的代碼重定位技術(shù)相比修改鏈接地址的代碼重定位技術(shù)代碼簡單,便于移植。然而修改鏈接地址的代碼重定位技術(shù)可以把uboot.bin文件復制到SDARM的任何地方,但是代碼很復雜,加-pie選項使得程序龐大,不利于NAND Flash啟動。綜合以上分析,推薦使用第一種方法完成代碼重定位。
3.4 S3C2440平臺上U-Boot移植
結(jié)合以上分析,使用固定鏈接地址的代碼重定位技術(shù),并選擇交叉編譯工具鏈arm-Linux-gcc4.3.2在Ubuntu16上對mini2440進行了U-Boot移植。按照第3.1節(jié)的步驟完成代碼重定位部分代碼,并修改時鐘和串口初始化函數(shù),使其支持DM9000網(wǎng)卡,圖 5為NOR Flash啟動的U-Boot界面。
圖5 NOR Flash啟動的U-boot界面
[1] 韋東山.嵌入式Linux 應(yīng)用開發(fā)完全手冊[M].北京:人民郵電出版社,2008:242-243.
[2] 田澤.嵌入式系統(tǒng)開發(fā)與應(yīng)用[M].北京:北京航空航天大學出版社,2010:19-21,83-190.
[3] 周書林,邱磊,唐桂軍.同時支持Nand Flash和Nor Flash啟動的啟動加載程序設(shè)計實現(xiàn)[J].科學技術(shù)與工程,2010,10(2):17-21.
[4] 柯敏毅,劉文鎖.BootLoader下Makefile文件的分析研究[J].計算機與信息技術(shù),2009,22(1):84.
[5] Lukasz Czech.On dynamics of automata with a stack[J].International Journal of Computer Mathematics,2015,92(3):486-497.
[6] 黃振華,李外云,劉錦高.ARM的位置無關(guān)程序設(shè)計在BootLoader中的應(yīng)用[J].單片機與嵌入式系統(tǒng)應(yīng)用,2008,8(1):22-25.
[7] 盧偉,潘煉.U-Boot在S3C2440上的移植[J].微型機與應(yīng)用,2010,29(24):4-11.
[8] angrad.u-boot2012.04.01移植到mini2440[EB/OL].[2017-02].http:∥blog.chinaunix.net/uid-22609852-id-3515982.html.
郭國法(教授),主要研究方向為電氣控制方面的研究;董輝(在讀碩士),主要研究方向為嵌入式Linux系統(tǒng)開發(fā)與應(yīng)用;張開生(教授),主要研究方向為嵌入式系統(tǒng)開發(fā)與應(yīng)用。
Research on Two Kinds of Code Relocation Technique in U-Boot
Guo Guofa,Dong Hui,Zhang Kaisheng
(College of Electrical and Information Engineering,Shanxi University of Science and Technology,Xi'an 710021,China)
Aiming at the problem that the ARM processor has a wide variety of processors and the diversity of the boot mode in the process of U-Boot porting,two kinds of code relocation technology are proposed.It is achieved that each memory can start the U-Boot program,which is compared with the other.The experiment results show that the code relocation technique to fix the link address can realize the efficient transplantation of U-Boot.
embedded system;U-Boot;code repositioning technology;transplantation
TP277
A
?士然
2017-02-20)