作者:圍補
本來啟動方式這節不是什么復雜的事兒,不過想簡單的說清楚明白,還真是不知道怎么組織。畢竟文字跟有聲語言表達有別。但願簡單的東西別讓我講的太復雜!
Arm板系統文件一般有三個——bootloader(uboot)、kernel(uImage)及根文件系統(rootfs)。在arm板上電后,按uboot->kernel->rootfs的順序依次啟動。由於開發板上有多種存儲介質,三個文件可以放在任何可以存儲的介質上,因此也就導致文件的多種啟動方式。本文就來討論,以上三個文件對應不通存放位置的不同啟動配置。
一般開發板上會有flash(Nor or NAND),mmc,emmc,sd卡等。系統文件可以燒寫在其中的任意一種上,因此也就對應不通的啟動。在開發過程中,有時經常需要改動內核,或者修改應用程序,如果每次都修改后都重新燒寫到板上的存儲介質,會比較麻煩。因此,為方便調試,uImage和rootfs還可以從網絡啟動,即nfs啟動。但uboot只能從板上介質啟動。
啟動過程其實是先將要啟動的文件從存儲位置拷貝到內存空間,再在內存中運行。因此所謂不同位置啟動,也就是從不同位置拷貝而已。
下面我們以開發板啟動為例,分別介紹三個文件從不同位置啟動的過程方法。我使用的開發板上有emmc和兩個sd卡。我們按照啟動順序,依次介紹。
首先是uboot啟動。Uboot是三個系統文件中第一個啟動的,對它的拷貝工作由cpu中的固件決定。固件中支持從幾個位置拷貝uboot,它就能存放在幾個位置上。至於每次啟動具體從其中的哪里開始,硬件撥碼開關決定,對應撥碼在開發板手冊上能查到。啟動之前,先將uboot的二進制文件拷貝到對應介質。有兩種不同方法燒寫,如下:
1. uboot二進制文件拷貝到emmc,是通過芯片供應商的下載工具軟件燒寫完成;
2. 拷貝到sd卡是在linux下,通過dd命令完成的。
燒寫完成后,將啟動撥碼撥到對應位置即可啟動uboot。
然后介紹kernel文件(uImange)和rootfs的啟動。如上所述,uImage和rootfs可以從emmc、sd卡或nfs拷貝到內核啟動。具體的啟動位置由uboot中的參數傳遞的內容決定。這些參數的內容在uboot中有寫死的值,也可以在uboot啟動階段進入到命令輸入界面,修改這些參數的值,來改變啟動位置。(作者:圍補)
進入uboot命令界面后,輸入如下一段命令,修改啟動參數,並重啟。
setenv loadaddr 0x10800000
setenv bootargs_base 'setenv bootargsconsole=ttymxc0,115200'
setenv bootargs_mmc 'setenv bootargs${bootargs} root=/dev/mmcblk0p1 rootwait rw video=mxcfb1:dev=ldb,LDB-XGA,if=RGB666video=mxcfb0:dev=hdmi,1920x1080M@60,if=RGB24 ip=dhcp'
setenv bootcmd_mmc 'run bootargs_basebootargs_mmc;mmc dev 1;mmc read ${loadaddr} 0x800 0x2000;bootm'
setenv bootcmd 'run bootcmd_mmc'
saveenv
run bootcmd
命令輸入完后,重啟開發板,即可按照上述命令中設置的參數來啟動系統。
下面我們來分析一下uboot階段輸入的啟動參數的意義,以便讀者自己修改相關內容,讓板子從自己需要的位置啟動。
首先介紹幾個命令。是在上面看到最多的setenv命令,該命令使用來設置或刪除某個環境變量的。當setenv后面只帶一個參數,該參數必須為已有的變量名,輸入命令回車后該變量即被刪除;當setenv后面有多個參數,將把其后第一個參數作為環境變量,后面其他參數作為該變量的值或內容。
第二個要解釋的命令mmc。在uboot命令界面中敲入mmc,回車,能夠看到其多個用法:
Usage:
mmc read addr blk# cnt
mmc write addr blk# cnt
mmc erase blk# cnt
mmc rescan
mmc part - lists available partition on currentmmc device
mmc dev [dev] [part] - show or set current mmcdevice [partition]
mmc bootpart [dev] [part] - show or set bootpartition
mmc list - lists available devices
解釋一下其中幾個用法:
mmc read addr blk# cnt 用來將硬盤(emmc/sd)中的內容讀取到內存中。其中addr指內存中的目標位置起始地址,blk#指被拷貝內容起始存儲塊的塊號,cnt指要被拷貝的塊數。一般每個塊的大小為512byte。
mmc dev [dev] [part] - show or set current mmc device [partition] 顯示或設置當前設備。命令mmc dev即為顯示當前是哪個device;mmc dev #意為設置“#”為當前設備。
第三個命令saveenv是保存環境變量的意思。環境變量設置后,使用該指令保存,下次重啟時會按照上次保存的設置啟動,就不用再次設置了。
最后,run命令比較明顯,“運行”的意思。一般加在某內容為可執行命令的變量前。
再來說明一下變量。在上述參數設置命令中,參數bootargs和bootcmd是uboot的參數,其功能和名稱不能被改變,其他都是用戶自定義的變量,可以改變其名稱。其中bootargs代表由uboot傳給內核的參數;bootcmd是uboot啟動時,系統自動加載的命令序列。如果設置了啟動參數后,想讓系統下次自動按照本次設置的方式啟動,則一定要把拷貝和啟動內核的語句設置為bootcmd的值,否則下次啟動無法自動加載並啟動內核。(作者圍補)
介紹完重要的命令及uboot環境變量后,我們再來看上面的啟動參數設置命令行:
setenv loadaddr 0x10800000
setenv bootargs_base 'setenv bootargsconsole=ttymxc0,115200'
setenv bootargs_mmc 'setenv bootargs${bootargs} root=/dev/mmcblk0p1 rootwait rwvideo=mxcfb1:dev=ldb,LDB-XGA,if=RGB666video=mxcfb0:dev=hdmi,1920x1080M@60,if=RGB24 ip=dhcp'
setenv bootcmd_mmc 'run bootargs_basebootargs_mmc;mmc dev 1;mmc read ${loadaddr} 0x800 0x2000;bootm'
setenv bootcmd 'run bootcmd_mmc'
saveenv
run bootcmd
按照上面對命令和參數的講解,做一些變量的替換之后,可以看到,此處只做了兩件事,一是設置環境變量bootargs的值,二是設置bootcmd的值,並保存。其中bootargs的值傳遞給內核,用來初始化一些設備和啟動rootfs;bootcmd的值用來啟動內核,即自動加載的命令序列。(最后一句run bootcmd是啟動,不再是設置命令了。)
對上述命令中,采用如此多自定義變量的原因是,有些調試工具命令行輸入不能過長,因此用中間自定義變量縮短一次性輸入的命令行長度。我們將不必要的自定義變量做替換掉,然后來分析其內容。
setenv bootargs console=ttymxc0,115200root=/dev/mmcblk0p1 rootwait rw video=mxcfb1:dev=ldb,LDB-XGA,if=RGB666 video=mxcfb0:dev=hdmi,1920x1080M@60,if=RGB24ip=dhcp
setenv bootcmd 'mmc dev 1;mmc read0x10800000 0x800 0x2000;bootm'
saveenv
run bootcmd
將自定義變量替代掉后,能看到,參數設置其實就是做了對兩個系統環境變量賦值的工作。下面具體分析各變量值得內容。
對bootargs的賦值,對要是跟rootfs啟動相關。內容是一個很大的字符串,不同項之間由空格隔開,也可以把由空格隔開的多項看做是多個參數。
第一項是console=ttymxc0,115200是選擇操作台,並設置波特率。
中間幾項root=/dev/mmcblk0p1 rootwait rw,是對rootfs啟動位置設置root=/dev/mmcblk0p1是指從設備mmcblk0的p1分區掛載rootfs。那么mmcblk0到底是哪個設備呢?由於文件系統的掛載是在kernel啟動后進行的,而內核啟動后會安裝linux的分配方式給現有設備分配名稱,因此可對應區分設備。我使用的開發板上,emmc即為mmcblk0設備,sd安裝掛載順序依次后排。如果多個卡槽在系統啟動前都插上了sd卡,系統會安裝sd卡槽所在接口號依次分配設備名稱號。比如,兩個sd卡槽,slot2和slot3(對應總線號),只插一個sd開始,無論在哪個槽都是mmcblk1;但兩個都插上sd時,在slot2中的是mmcblk1,slot3中的則是mmcblk2。Ok,至此,從哪個設備掛載rootfs已經很清楚了。后面兩個參數,rw是聲明啟動權限,即以讀寫方式啟動;rootwait是指等待設備/dev/mmcblk0p1設備就緒后才嘗試掛載rootfs。如果沒有此參數,linux內核啟動時可能會在存儲設備尚未就緒是就嘗試掛載rootfs,此時肯定掛載失敗,那么啟動也就失敗了。
最后的幾個參數,video=mxcfb1:dev=ldb,LDB-XGA,if=RGB666video=mxcfb0:dev=hdmi,1920x1080M@60,if=RGB24 ip=dhcp,是做一些設備初始化的,主要是對視頻設備和網絡,對不需要視頻設備的嵌入式系統可以不設置此項,ip也可以單獨設置。
然后是第二個環境變量bootcmd的設置,主要跟kernel啟動相關。
setenv bootcmd 'mmc dev 1;mmc read0x10800000 0x800 0x2000;bootm'
設置bootcmd內容為命令序列,用用單引號包圍,命令間由分號分隔。
按照上面對mmc命令的講解,第一個命令mmc dev 1,意思是將dev 1設置為當前設備。這里就是uImage啟動(拷貝)的位置。在我使用的開發板上,dev 1指放在卡槽slot2中的sd卡。此處由於linux內核沒有啟動,設備名稱不能按照linux分配方式確定。在我使用的開發板上,dev 2是放在卡槽slot3中的sd卡,dev3是emmc。對此句做相應修改,即可更改內核啟動位置。
mmc read 0x10800000 0x800 0x2000這句大家也應該可以明白意思了,即將存儲設備上從塊號0x800開始的0x2000個存儲塊的東西拷貝到內存0x10800000開始的空間內。
bootm也是uboot命令,用於加載uboot能辨認的操作系統映像。
以上,已經講完在uboot階段修改啟動參數,進而更改啟動位置的命令的含義,讀者可對應修改,是系統各文件從相應位置啟動。另外nfs部分,有時間在加進入。
此處僅作個人總結,入對您有所幫助無上榮幸!——作者圍補