【Linux】制作U-Boot烧写镜像到SD卡的过程(上篇)
在嵌入式Linux操作系統(tǒng)中,需要將三樣?xùn)|西(BootLoader、內(nèi)核kernel、根文件系統(tǒng))傳輸?shù)侥繕?biāo)板中。一般而言,U-Boot燒寫(xiě)到SD卡中,而內(nèi)核、根文件系統(tǒng)都采用TFTP的方式傳輸?shù)侥繕?biāo)板,然后通過(guò)U-Boot的命令進(jìn)行啟動(dòng)。
那么U-Boot是如何燒寫(xiě)到SD卡中的呢?
為了檢測(cè)U-Boot是否真正少燒寫(xiě)到了SD卡中,本文通過(guò)修改U-Boot下的U-boot/arch/arm/cpu/armv7/start.S文件,在該文件中增加對(duì)GPIO的操作,來(lái)對(duì)LED進(jìn)行點(diǎn)亮操作,這樣如果U-Boot順利燒寫(xiě)到SD卡中,開(kāi)機(jī)運(yùn)行后就會(huì)點(diǎn)亮LED。
S5PV210啟動(dòng)機(jī)制
S5PV210的啟動(dòng)機(jī)制如下所示:
S5PV210的啟動(dòng)過(guò)程有三個(gè)步驟組成,其中,iROM是平臺(tái)獨(dú)立的,存儲(chǔ)在片內(nèi)內(nèi)存中,即芯片應(yīng)該固化好的;First boot,也是平臺(tái)獨(dú)立的,但是它存儲(chǔ)在外部?jī)?nèi)存中(如nandflash\sd卡等),也就是說(shuō),這部分代碼由用戶去實(shí)現(xiàn);second boot,是平臺(tái)相關(guān)的,存儲(chǔ)在外部?jī)?nèi)存,是真正的boot loader代碼。一般稱iROM過(guò)程為BL0,稱First Boot Loader為BL1,稱second boot loader為BL2。
具體過(guò)程為:
S5PV210的燒寫(xiě)過(guò)程
本文策略
本文通過(guò)修改start.S文件,在start.S文件中增加點(diǎn)亮LED的內(nèi)容,然后對(duì)start.S進(jìn)行編譯,編譯完成后,制作成16kB大小的內(nèi)容,燒寫(xiě)到SD卡中。
在start.S文件末尾增加GPIO的初始化部分和點(diǎn)亮的部分:
gpio_out:ldr r11, =0xE0200280 //獲得寄存器地址ldr r12, =0x00001111 //配置成輸出狀態(tài)str r12, [r11] //將r12寄存器的值放回r11ldr r11, =0xE0200284ldr r12, =0xFstr r12, [r11]mov pc, lr.globl led1_on led1_on:ldr r11, =0xE0200284ldr r12, [r11]bic r12, r12, #1 //將r12的第一位清零,回寫(xiě)到r12str r12, [r11]mov pc, lr然后在文件reset過(guò)程中調(diào)用這兩個(gè)過(guò)程即可:
reset:bl save_boot_params/** set the cpu to SVC32 mode*/mrs r0, cpsrbic r0, r0, #0x1forr r0, r0, #0xd3msr cpsr,r0/** Setup vector:* (OMAP4 spl TEXT_BASE is not 32 byte aligned.* Continue to use ROM code vector only in OMAP4 spl)*/ #if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))/* Set V=0 in CP15 SCTRL register - for VBAR to point to vector */mrc p15, 0, r0, c1, c0, 0 @ Read CP15 SCTRL Registerbic r0, #CR_V @ V = 0mcr p15, 0, r0, c1, c0, 0 @ Write CP15 SCTRL Register/* Set vector address in CP15 VBAR register */ldr r0, =_startmcr p15, 0, r0, c12, c0, 0 @Set VBAR #endifbl gpio_out //調(diào)用bl led1_on //調(diào)用/* the mask ROM code should have PLL and others stable */ #ifndef CONFIG_SKIP_LOWLEVEL_INITbl cpu_init_cp15bl cpu_init_crit #endif修改成功后,make一下,獲得u-boot.bin文件。make文件是做什么的呢?是怎么寫(xiě)的呢?可以關(guān)注博主下一篇文章。
HeaderInfo
上文提到BL1過(guò)程的部分文件大小僅僅為16KB的大小,而u-boot.bin的大小遠(yuǎn)遠(yuǎn)超過(guò),而且在16KB的內(nèi)容中包含一個(gè)叫做HeaderInfo的東西,u-boot.bin中顯然沒(méi)有。
本文的內(nèi)容不涉及BL2的過(guò)程,僅僅需要BL1過(guò)程即可,即點(diǎn)亮LED等就好了。也就是說(shuō),本文只需要制作一個(gè)16KB大小的文件,將該文件燒寫(xiě)到SD卡中,到目標(biāo)板中運(yùn)行就行了。LED的程序肯定在前16KB的內(nèi)容中。至于后面的LB2過(guò)程,以后的文章中再講怎么操作。
那么HeaderInfo的東西是怎么生成的呢?在文件mkv210_image.c中詳細(xì)介紹了整個(gè)過(guò)程:
/* 在BL0階段,iRom內(nèi)固化的代碼需要讀取nandflash或SD卡前16K的內(nèi)容,* 并比對(duì)前16字節(jié)中的校驗(yàn)和是否正確,正確則繼續(xù),錯(cuò)誤則停止。*/ #include <stdio.h> #include <string.h> #include <stdlib.h>#define BUFSIZE (16*1024) #define IMG_SIZE (16*1024) #define SPL_HEADER_SIZE 16 #define SPL_HEADER "S5PC110 HEADER " int main (int argc, char *argv[]) {FILE *fp;char *Buf, *a;int BufLen;int nbytes, fileLen;unsigned int checksum, count;int i;// 1. 3個(gè)參數(shù)if (argc != 3) //參數(shù)數(shù)目不對(duì){printf("Usage: mkbl1 <source file> <destination file>\n");return -1;}// 2. 分配16K的bufferBufLen = BUFSIZE;Buf = (char *)malloc(BufLen);if (!Buf) //如果分配空間不夠,分配失敗{printf("Alloc buffer failed!\n");return -1;}memset(Buf, 0x00, BufLen); //這段內(nèi)存區(qū)全部清零// 3. 讀源bin到buffer// 3.1 打開(kāi)源binfp = fopen(argv[1], "rb"); //打開(kāi)文件if( fp == NULL) //打開(kāi)失敗{printf("source file open error\n");free(Buf);return -1;}// 3.2 獲取源bin長(zhǎng)度fseek(fp, 0L, SEEK_END); //指針移動(dòng)到文件末尾fileLen = ftell(fp); //獲取文件長(zhǎng)度fseek(fp, 0L, SEEK_SET); //指針移動(dòng)到文件開(kāi)始// 3.3 源bin長(zhǎng)度不得超過(guò)16K-16bytecount = (fileLen < (IMG_SIZE - SPL_HEADER_SIZE))? fileLen : (IMG_SIZE - SPL_HEADER_SIZE); //count等于16kB-16字節(jié)// 3.4 buffer[0~15]存放"S5PC110 HEADER "memcpy(&Buf[0], SPL_HEADER, SPL_HEADER_SIZE); //復(fù)制移動(dòng)// 3.5 讀源bin到buffer[16]nbytes = fread(Buf + SPL_HEADER_SIZE, 1, count, fp); if ( nbytes != count ){printf("source file read error\n");free(Buf);fclose(fp);return -1;}fclose(fp);// 4. 計(jì)算校驗(yàn)和// 4.1 從第16byte開(kāi)始統(tǒng)計(jì)buffer中共有幾個(gè)1a = Buf + SPL_HEADER_SIZE;for(i = 0, checksum = 0; i < IMG_SIZE - SPL_HEADER_SIZE; i++)checksum += (0x000000FF) & *a++;// 4.2 將校驗(yàn)和保存在buffer[8~15]a = Buf + 8;*( (unsigned int *)a ) = checksum;// 5. 拷貝buffer中的內(nèi)容到目的bin// 5.1 打開(kāi)目的binfp = fopen(argv[2], "wb");if (fp == NULL){printf("destination file open error\n");free(Buf);return -1;}// 5.2 將16k的buffer拷貝到目的bin中a = Buf;nbytes = fwrite( a, 1, BufLen, fp);if ( nbytes != BufLen ){printf("destination file write error\n");free(Buf);fclose(fp);return -1;}free(Buf);fclose(fp);return 0; }這里介紹一下main()的函數(shù)參數(shù):
- argc = argument count :表示傳入main函數(shù)的數(shù)組元素個(gè)數(shù),為int類型;
- argv = argument vector :表示傳入main函數(shù)的指針數(shù)組,為char*[ ]類型。第一個(gè)數(shù)組元素argv[0]是程序名稱,并且包含程序所在的完整路徑。argc至少為1,即argv數(shù)組至少包含程序名。
也就是說(shuō),當(dāng)編譯并運(yùn)行main()函數(shù)的時(shí)候:
gcc mkv210_image.c -o mkv210 //編譯文件 ./mkv210 u-boot.bin u-boot.16k //運(yùn)行文件,三個(gè)參數(shù)(第一個(gè)參數(shù)必須是本文件)通過(guò)這段程序的運(yùn)行,就可以將u-boot.bin生成u-boot.16k,該文件僅有16k的大小,并且包含HeaderInfo。
hexdump查看二進(jìn)制文件
當(dāng)編譯文件時(shí),需要將.c文件通過(guò)預(yù)編譯變成.i文件,再通過(guò)編譯變成.s文件,再通過(guò)匯編變成.o文件,最后進(jìn)行鏈接變成不帶后綴名的文件。
但是不帶后綴名的文件內(nèi)不僅僅是二進(jìn)制的內(nèi)容,里面還包括許多的鏈接內(nèi)容、注釋內(nèi)容等等,因此文件大小一般比較大,不能直接燒寫(xiě)到目標(biāo)板中。而.bin后綴的文件刪除了這部分的內(nèi)容,僅僅只有二進(jìn)制的文件,可以燒寫(xiě)到目標(biāo)板中。
因此,如果想要分析二進(jìn)制文件采用不帶后綴的文件,想要燒寫(xiě)到目標(biāo)板中,采用.bin后綴的文件。
hexdump -C u-boot.16k | less //-C 輸出規(guī)范的十六進(jìn)制和ASCII碼運(yùn)行結(jié)果如圖所示:
查看uboot.bin:
arm-linux-objdump -S u-boot | less運(yùn)行結(jié)果如圖所示:
注意到,u-boot里面第一句reset的二進(jìn)制表達(dá)是ea000014,而在u-boot.16k中的表達(dá)是140000ea(第二行,去掉前16字節(jié)的HeaderInfo)。
這就涉及到大小端的問(wèn)題了,可以查看鏈接:大小端問(wèn)題。
一般而言,處理器以小端模式為主,硬盤(pán)等存儲(chǔ)設(shè)備以大選模式為主,網(wǎng)絡(luò)通信都是大端模式(先傳高位,再傳低位)。
燒寫(xiě)到SD卡
燒寫(xiě)到SD卡,一般采用的是dd命令:
sudo dd iflag=dsync oflag=dsync if=u-boot.16k of=/dev/sdb seek=1前兩個(gè)選項(xiàng)iflag和oflag表示采取異步的方式,if表示輸入文件,of表示輸出設(shè)備,seek表示從第幾個(gè)扇區(qū)開(kāi)始燒寫(xiě)。
dev是設(shè)備(device)的英文縮寫(xiě)。/dev這個(gè)目錄對(duì)所有的用戶都十分重要。因?yàn)樵谶@個(gè)目錄中包含了所有Linux系統(tǒng)中使用的外部設(shè)備。但是這里并不是放的外部設(shè)備的驅(qū)動(dòng)程序,這一點(diǎn)和windows、dos操作系統(tǒng)不一樣。它實(shí)際上是一個(gè)訪問(wèn)這些外部設(shè)備的端口。我們可以非常方便地去訪問(wèn)這些外部設(shè)備,和訪問(wèn)一個(gè)文件、一個(gè)目錄沒(méi)有任何區(qū)別。
檢測(cè)結(jié)果
插入SD卡到目標(biāo)板,上電,LED就會(huì)按照程序執(zhí)行。
總結(jié)
以上是生活随笔為你收集整理的【Linux】制作U-Boot烧写镜像到SD卡的过程(上篇)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 柱状图怎么设置xy轴_excel表格xy
- 下一篇: 改变生活的态度,突破瓶颈