【Linux】制作U-Boot烧写镜像到SD卡的过程(上篇)
在嵌入式Linux操作系統(tǒng)中,需要將三樣東西(BootLoader、內(nèi)核kernel、根文件系統(tǒng))傳輸?shù)侥繕税逯小R话愣?#xff0c;U-Boot燒寫到SD卡中,而內(nèi)核、根文件系統(tǒng)都采用TFTP的方式傳輸?shù)侥繕税?#xff0c;然后通過U-Boot的命令進行啟動。
那么U-Boot是如何燒寫到SD卡中的呢?
為了檢測U-Boot是否真正少燒寫到了SD卡中,本文通過修改U-Boot下的U-boot/arch/arm/cpu/armv7/start.S文件,在該文件中增加對GPIO的操作,來對LED進行點亮操作,這樣如果U-Boot順利燒寫到SD卡中,開機運行后就會點亮LED。
S5PV210啟動機制
S5PV210的啟動機制如下所示:
S5PV210的啟動過程有三個步驟組成,其中,iROM是平臺獨立的,存儲在片內(nèi)內(nèi)存中,即芯片應該固化好的;First boot,也是平臺獨立的,但是它存儲在外部內(nèi)存中(如nandflash\sd卡等),也就是說,這部分代碼由用戶去實現(xiàn);second boot,是平臺相關(guān)的,存儲在外部內(nèi)存,是真正的boot loader代碼。一般稱iROM過程為BL0,稱First Boot Loader為BL1,稱second boot loader為BL2。
具體過程為:
S5PV210的燒寫過程
本文策略
本文通過修改start.S文件,在start.S文件中增加點亮LED的內(nèi)容,然后對start.S進行編譯,編譯完成后,制作成16kB大小的內(nèi)容,燒寫到SD卡中。
在start.S文件末尾增加GPIO的初始化部分和點亮的部分:
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的第一位清零,回寫到r12str r12, [r11]mov pc, lr然后在文件reset過程中調(diào)用這兩個過程即可:
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文件是做什么的呢?是怎么寫的呢?可以關(guān)注博主下一篇文章。
HeaderInfo
上文提到BL1過程的部分文件大小僅僅為16KB的大小,而u-boot.bin的大小遠遠超過,而且在16KB的內(nèi)容中包含一個叫做HeaderInfo的東西,u-boot.bin中顯然沒有。
本文的內(nèi)容不涉及BL2的過程,僅僅需要BL1過程即可,即點亮LED等就好了。也就是說,本文只需要制作一個16KB大小的文件,將該文件燒寫到SD卡中,到目標板中運行就行了。LED的程序肯定在前16KB的內(nèi)容中。至于后面的LB2過程,以后的文章中再講怎么操作。
那么HeaderInfo的東西是怎么生成的呢?在文件mkv210_image.c中詳細介紹了整個過程:
/* 在BL0階段,iRom內(nèi)固化的代碼需要讀取nandflash或SD卡前16K的內(nèi)容,* 并比對前16字節(jié)中的校驗和是否正確,正確則繼續(xù),錯誤則停止。*/ #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個參數(shù)if (argc != 3) //參數(shù)數(shù)目不對{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 打開源binfp = fopen(argv[1], "rb"); //打開文件if( fp == NULL) //打開失敗{printf("source file open error\n");free(Buf);return -1;}// 3.2 獲取源bin長度fseek(fp, 0L, SEEK_END); //指針移動到文件末尾fileLen = ftell(fp); //獲取文件長度fseek(fp, 0L, SEEK_SET); //指針移動到文件開始// 3.3 源bin長度不得超過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); //復制移動// 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. 計算校驗和// 4.1 從第16byte開始統(tǒng)計buffer中共有幾個1a = Buf + SPL_HEADER_SIZE;for(i = 0, checksum = 0; i < IMG_SIZE - SPL_HEADER_SIZE; i++)checksum += (0x000000FF) & *a++;// 4.2 將校驗和保存在buffer[8~15]a = Buf + 8;*( (unsigned int *)a ) = checksum;// 5. 拷貝buffer中的內(nèi)容到目的bin// 5.1 打開目的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ù)組元素個數(shù),為int類型;
- argv = argument vector :表示傳入main函數(shù)的指針數(shù)組,為char*[ ]類型。第一個數(shù)組元素argv[0]是程序名稱,并且包含程序所在的完整路徑。argc至少為1,即argv數(shù)組至少包含程序名。
也就是說,當編譯并運行main()函數(shù)的時候:
gcc mkv210_image.c -o mkv210 //編譯文件 ./mkv210 u-boot.bin u-boot.16k //運行文件,三個參數(shù)(第一個參數(shù)必須是本文件)通過這段程序的運行,就可以將u-boot.bin生成u-boot.16k,該文件僅有16k的大小,并且包含HeaderInfo。
hexdump查看二進制文件
當編譯文件時,需要將.c文件通過預編譯變成.i文件,再通過編譯變成.s文件,再通過匯編變成.o文件,最后進行鏈接變成不帶后綴名的文件。
但是不帶后綴名的文件內(nèi)不僅僅是二進制的內(nèi)容,里面還包括許多的鏈接內(nèi)容、注釋內(nèi)容等等,因此文件大小一般比較大,不能直接燒寫到目標板中。而.bin后綴的文件刪除了這部分的內(nèi)容,僅僅只有二進制的文件,可以燒寫到目標板中。
因此,如果想要分析二進制文件采用不帶后綴的文件,想要燒寫到目標板中,采用.bin后綴的文件。
hexdump -C u-boot.16k | less //-C 輸出規(guī)范的十六進制和ASCII碼運行結(jié)果如圖所示:
查看uboot.bin:
arm-linux-objdump -S u-boot | less運行結(jié)果如圖所示:
注意到,u-boot里面第一句reset的二進制表達是ea000014,而在u-boot.16k中的表達是140000ea(第二行,去掉前16字節(jié)的HeaderInfo)。
這就涉及到大小端的問題了,可以查看鏈接:大小端問題。
一般而言,處理器以小端模式為主,硬盤等存儲設備以大選模式為主,網(wǎng)絡通信都是大端模式(先傳高位,再傳低位)。
燒寫到SD卡
燒寫到SD卡,一般采用的是dd命令:
sudo dd iflag=dsync oflag=dsync if=u-boot.16k of=/dev/sdb seek=1前兩個選項iflag和oflag表示采取異步的方式,if表示輸入文件,of表示輸出設備,seek表示從第幾個扇區(qū)開始燒寫。
dev是設備(device)的英文縮寫。/dev這個目錄對所有的用戶都十分重要。因為在這個目錄中包含了所有Linux系統(tǒng)中使用的外部設備。但是這里并不是放的外部設備的驅(qū)動程序,這一點和windows、dos操作系統(tǒng)不一樣。它實際上是一個訪問這些外部設備的端口。我們可以非常方便地去訪問這些外部設備,和訪問一個文件、一個目錄沒有任何區(qū)別。
檢測結(jié)果
插入SD卡到目標板,上電,LED就會按照程序執(zhí)行。
總結(jié)
以上是生活随笔為你收集整理的【Linux】制作U-Boot烧写镜像到SD卡的过程(上篇)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 柱状图怎么设置xy轴_excel表格xy
- 下一篇: Linux基础知识与实操-篇三: 文件压