uboot 映象為 uboot.bin,linux 映象為 zimage
嵌入式裝置中的分割槽表是自己定義的,uboot 和核心中的分割槽表應一致
核心執行前必須載入到 ddr 中指定的位址處
uboot 需要提供核心必要的引數
uboot 啟動核心有兩種方式,一種是等待倒計時結束後直接啟動核心,一種是在 uboot 命令列中使用 boot 命令啟動核心
其**分別如下
其中 parse_string_outer 的作用是解析 boot 引數並執行
uboot 啟動核心的步驟/*------------------倒計時----------------------*/
s = getenv ("bootcmd");
if (bootdelay >= 0 && s && !abortboot (bootdelay))
/*------------------命令列----------------------*/
int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *ar**)
u_boot_cmd(
boot, 1, 1, do_bootd,
"boot - boot default, i.e., run 'bootcmd'\n",
null
);/*-----------------相關巨集定義----------------------*/
#ifdef config_bootargs
"bootargs=" config_bootargs "\0"
#endif
#ifdef config_bootcommand
"bootcmd=" config_bootcommand "\0"
#endif
#define config_bootargs "console=ttysac2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext3"
#define config_bootcommand "movi read kernel 30008000; movi read rootfs 30b00000 300000; bootm 30008000 30b00000"
本文使用的開發板 x210 將映象存放在 sd 卡中,要載入到 ddr 中需要使用到 movi 指令
movi 提供了對 inand/sd 卡的操作,movi read 用來讀取 inand/sd 卡中的內容到ddr中;movi write 用來將ddr中的內容寫入到 inand/sd 卡中
上面的**中 bootcmd 中的命令就是用來載入 kernel rootfs 到 ddr
通過movi read kernel 30008000
可以知道,核心載入到了 0x30008000 的位置
linux 直接編譯得到 elf 檔案,叫 vmlinux 或 vmlinuz。這種檔案會比較大,為了燒錄方便,會使用 objcopy 工具製作成映象檔案,叫 image(從78m精簡成了7.5m)
早期使用的軟盤比較小,image 對與軟盤來說還是太大了,放不下。linux 對 image 做進一步的壓縮,並在壓縮檔案前端附加了一部分解壓縮**,形成 zimage
uboot 可以使用 mkimage 工具,在 zimage 前面加上64位元組的uimage的頭資訊,形成 uimage
核心的載入啟動是通過 do_bootm 完成的
前面介紹過,映象檔案分為兩個部分,頭部以及真正的核心
所以 do_bootm 會先對映象進行頭部資訊的校驗,然後再進行核心的啟動
頭部資訊的結構體如下
typedef struct image_header image_header_t;
在 do_bootm 中就是通過 ih_os 判斷映象的型別,然後使用相應的方法啟動核心
這裡的映象是 linux 映象,所以使用的是 do_bootm_linux, do_bootm_linux 的引數大部分是通過 do_bootm 傳遞的
啟動的引數bootm 30008000
,告訴 uboot 去 30008000 這個位址去找映象檔案
映象的程式入口叫做 entrypoint ,在 do_bootm_linux 中使用 ep 儲存,映象的程式入口在頭資訊的 ih_ep 中,可以通過讀取頭資訊得到
得到 ep 後,通過thekernel = (void (*)(int, int, uint))ep;
將 ep 格式化後傳遞給 thekernel ,這樣 thekernel 函式就指向了記憶體中載入的os映象的真正入口位址
前面也提到了,每個開發板在 uboot 中都有唯一的機器碼,這個編碼用來驗證開發板與 uboot 是否匹配,這個機器碼還會傳到核心中再次驗證。這個機器碼獲取的第一順序備選是環境變數machid,第二順序備選是gd->bd->bi_arch_num(x210_sd.h 中的 #define mach_type 2456)
接下來就是傳參的過程。先看看 linux 的 documentation/arm/booting 中對 cpu 暫存器設定的描述
通過讀取 r0 r1 r2 這三個暫存器的值來設定 cpu ,r0 固定為0,r1 為前面提到的機器碼,r2 為存放啟動引數 tag 結構體的首位址- cpu register settings
r0 = 0,
r1 = machine type number discovered in (3) above.
r2 = physical address of tagged list in system ram, or
physical address of device tree block (dtb) in system ram
所以在 do_bootm_linux 通過thekernel (0, machid, bd->bi_boot_params);
完成傳參的過程
傳參是通過 struct tag 這個結構體完成的,獲取引數就是獲取乙個個 tag 的過程。這些 tag 也有著規定的格式,do_bootm_linux 中通過 setup_start_tag 和 setup_end_tag 函式設定 tag 的開始和結束,這個函式的作用就是設定當前 tag 的型別為 atag_core 和 atag_none ,用作 tag 起始終止位置的判別
需要注意的是,傳參是乙個很重要的過程,核心啟動不成功與傳參錯誤有很大關係
第一步:將核心搬移到ddr中
第二步:校驗核心格式、crc等
第三步:準備傳參
第四步:跳轉執行核心
u-boot 啟動核心解析
uboot啟動核心
假設bootcmd nand read.jffs2 0x30007fc0 kernel bootm 0x30007fc0 1 nand read.jffs2 0x30007fc0 kernel nand read.jffs2 0x30007fc0 kernel 從nand讀出核心 從 讀?從kern...
uboot啟動核心
經過了前面的的一系列準備,終於要啟動核心了。在uboot分析二中,提到過下面的這個函式 void main loop void 在啟動核心的時候在uboot裡面用到什麼命令呢?bootcmd 命令 nand.read.jffs 0x30007f00 kernel 從nand的kernel 分割槽讀核...
uboot分析 uboot啟動核心
u boot啟動核心概述 u boot啟動完成後,最終進入到main loop 迴圈中。若在bootdelay倒計時為0之前,u boot控制台有輸入,則進入命令解析 執行的迴圈 若控制台無輸入,u boot將啟動核心。u boot啟動核心可歸結為以下四個步驟 1 將核心搬移至ddr中 2 校驗核心...