還是先找到入口
上文《u-boot.bin生成過程追蹤》,我們探討了u-boot.bin的生成過程。在文章開頭的地方,我們講到終極目標,並且找到了主Makefile的終極目標所在。本文探討u-boot.imx文件的生成,因很多內容跟上文都一樣,所以在閱讀本文之前,還需要閱讀下上文的內容。
還是跟u-boot.bin一樣,我們在ALL-y裏面尋找u-boot.imx的定義。不過可惜,我們好像沒找到,但是這是不可能的,如果ALL-y裏面沒有指定u-boot.imx,那麼一定不會編譯出u-boot.imx。我們不妨打印一下這個ALL-y看看,我在主Makefile802頁加了一個打印,如下:
all: $(ALL-y)
@echo aaaaaaaaaaaaaaaaaa
@echo $(ALL-y)
@echo bbbbbbbbbbbbbbbbbb
我們看到如下輸出:
aaaaaaaaaaaaaaaaaa
checkarmreloc u-boot.imx u-boot.srec u-boot.bin u-boot.sym System.map u-boot.cfg binary_size_check
bbbbbbbbbbbbbbbbbb
看到沒有,這裏是有u-boot.imx的。那麼這個是在哪裏加入的呢?這裏我們就要略微動下腦子了,這個u-boot.imx後綴是imx,而且我們清楚,這個東西是NXP imx平臺特有的一個uboot鏡像,所以這個東西不大可能在主Makefile裏面直接寫進去。那一定是跟平臺相關的,但是跟平臺相關,東西也挺多,要找這個玩意在哪裏,也是有點困難啊。到了這裏了,咱不得不祭出我們搜索的法寶,有需要的朋友可以拿去,挺好用的一個工具,命令如下:
sunke@droresrv:~/work/MYiR-iMX-Uboot$ find . -type f -name "*" | xargs grep "u-boot.imx"
這裏我們全文遞歸查找字符串u-boot.imx。這裏輸出會比較多,我們把重要的輸出拿出來看:
./arch/arm/config.mk:ALL-y += u-boot.imx
ifeq ($(CONFIG_OF_SEPARATE),y)
ALL-y += u-boot-dtb.imx
else
ALL-y += u-boot.imx
endif
看到沒,這個config.mk裏面追加了u-boot.imx到ALL-y變量裏面。我們可以通過打印,驗證一下,是否真的是這裏引入了u-boot.imx。這裏我也不列出來了,我打印了之後發現確實是這裏引入的,大家可以自己試下。哪裏引入的u-boot.imx我們知道了,這個u-boot.imx的構建規則入口又在哪裏呢?我並沒有在主Makefile裏面找到u-boot.imx的規則,但是我找到了這條規則,主Makefile第839行:
%.imx: %.bin
$(Q)$(MAKE) $(build)=arch/arm/imx-common $@
這是個模式規則,u-boot.imx會匹配這個規則。這裏又見到我們的老朋友build了,我們還是同樣的方式,展開一下:
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.build obj=arch/arm/imx-common u-boot.imx
這裏轉向去執行Makefile.build,obj變量使Makefile.build會引入arch/arm/imx-common/Makefile,我們在這個Makefile裏面找到了u-boot.imx規則,第57行:
u-boot.imx: u-boot.bin $(IMX_CONFIG) FORCE
$(call if_changed,mkimage)
怎麼樣,這個入口終於被我們找到了。
先看一下依賴
上面我們找到了u-boot.imx的入口,我們看到它依賴u-boot.bin,這個u-boot.bin我們已經在《u-boot.bin生成過程追蹤》裏面分析過了,想要追蹤的可以看那裏。另外,u-boot.imx還依賴$(IMX_CONFIG),我們通過打印的方式看到,這個展開之後如下:
board/myir/mys_imx6ull/imximage.cfg.cfgtmp
這個文件實際上是imx image header中的DCD數據,其規則定義在arch/arm/imx-common/Makfile裏面,第48行,如下:
IMX_CONFIG = $(CONFIG_IMX_CONFIG:"%"=%).cfgtmp
其中定義了CONFIG_IMX_CONFIG變量,我們在include/autoconf.mk裏面找到了這個變量的定義:
CONFIG_IMX_CONFIG="board/myir/mys_imx6ull/imximage.cfg"
$(IMX_CONFIG)還有一個規則,arch/arm/imx-common/Makfile第50行,如下:
quiet_cmd_cpp_cfg = CFGS $@
cmd_cpp_cfg = $(CPP) $(cpp_flags) -x c -o $@ $<
IMX_CONFIG = $(CONFIG_IMX_CONFIG:"%"=%).cfgtmp
$(IMX_CONFIG): %.cfgtmp: % FORCE
$(Q)mkdir -p $(dir $@)
$(call if_changed_dep,cpp_cfg)
這裏$(IMX_CONFIG)這個目標是通過cpp_cfg命令生成的,我們可以看到,這個命令使用了$(CPP),CPP變量在主Makefile的第341行有定義,如下:
CPP = $(CC) -E
就是調用了gcc的-E選項而已,這個命令的詳細展開及運行,大家可以自己分析一下,這裏先不展開。我們重點看下u-boot.imx目標的命令。
再來看下命令
我們現在重點來展開分析u-boot.imx的命令,其調用了mkimage命令,這個通過if_changed函數展開之後,也就是命令cmd_mkimage。我們在Makefile.lib文件裏面找到了這個命令的定義,Makefile.lib第435行,如下:
# Additional commands for U-Boot
#
# mkimage
# ---------------------------------------------------------------------------
quiet_cmd_mkimage = MKIMAGE $@
cmd_mkimage = $(objtree)/tools/mkimage $(MKIMAGEFLAGS_$(@F)) -d $< $@ \
$(if $(KBUILD_VERBOSE:1=), >/dev/null)
這個調用了tools/mkimage程序,我們展開一下這個變量的值:
./tools/mkimage $(MKIMAGEFLAGS_$(@F)) -d u-boot.bin u-boot.imx >/dev/null
這裏面有個$(MKIMAGEFLAGS_$(@F)),其中$(@F)是表示目標文件的完整文件名中除目錄以外的部分。在這裏其值就是依賴文件u-boot.imx。於是這個變量就編程"$(MKIMAGEFLAGS_u-boot.imx)",這個變量在arch/arm/imx-common/Makefile裏面定義,第54行:
MKIMAGEFLAGS_u-boot.imx = -n $(filter-out $< $(PHONY),$^) -T imximage \
-e $(CONFIG_SYS_TEXT_BASE)
這裏我們直接展開如下:
MKIMAGEFLAGS_u-boot.imx = -n board/myir/mys_imx6ull/imximage.cfg.cfgtmp -T imximage -e 0x87800000
於是,整個cmd_mkimage命令展開就變成:
./tools/mkimage -n board/myir/mys_imx6ull/imximage.cfg.cfgtmp -T imximage -e 0x87800000 -d u-boot.bin u-boot.imx >/dev/null
看到沒,這個就是最終生成u-boot.imx的命令,要看明白裏面的具體生成過程,那麼就需要去研究下mkimage程序的原理了。本文因爲只追蹤u-boot.imx的生成過程,具體生成原理這裏就不贅述了,後續有機會分析uboot源代碼時再詳細展開吧。