嵌入式Linux之uboot源碼make配置編譯正向分析


一、嵌入式Linux系統組成

嵌入式Linux系統一般由以下幾部分組成:

  • 引導加載程序,包括固化在固件中的boot代碼和BootLoader兩大部分。有些CPU在運行BootLoader之前會先運行一段固化程序,比如x86的CPU會先運行BIOS中的固件,然后才運行硬盤的第一個分區(MBR)中的BootLoader,但是在大多的嵌入式系統中,是沒有固件的,BootLoader就是上電后執行的第一個程序。 

  • linux內核:特定於嵌入式板子的定制內核以及內核的啟動參數,內核的啟動參數可以是內核默認的,也可以是由BootLoader傳遞給它的。

  • 文件系統: 包括根文件系統和建立於Flash內存設備上的文件系統,里面包含了linux系統能夠運行所必須的應用程序、庫等等,比如可以給用戶提供Linux的控制界面shell程序、動態鏈接的程序時所需要的glibc或uClibc庫等。

  • 用戶應用程序    特定於用戶的應用程序,它們也存儲在文件系統中,有時在用戶應用程序和內核層之間可能還會包括一個嵌入式圖形用戶界面,常用的嵌入式GUI有:Qtopia和MinGUI等。顯然,在嵌入式系統的固態存儲設備上有相應的分區來存儲它們。

在Flash存儲器中,它們的分布一般如下:

 二、BootLoader

Bootloader是在操作系統運行之前執行的一段小程序。通過這段小程序,我們可以初始化硬件設備、建立內存空間的映射表,從而建立適當的系統軟硬件環境,為最終調用操作系統內核做好准備。

對於嵌入式系統,Bootloader是基於特定硬件平台來實現的。因此,幾乎不可能為所有的嵌入式系統建立一個通用的Bootloader,不同的處理器架構都有不同的Bootloader。Bootloader不但依賴於CPU的體系結構,而且依賴於嵌入式系統板級設備的配置。對於2塊不同的嵌入式板而言,即使它們使用同一種處理器,要想讓運行在一塊板子上的Bootloader程序也能運行在另一塊板子上,一般也都需要修改Bootloader的源程序。 反過來,大部分Bootloader仍然具有很多共性,某些Bootloader也能夠支持多種體系結構的嵌入式系統。

例如,u-boot就同時支持PowerPC、ARM、MIPS和X86等體系結構,支持的板子有上百種。通常,它們都能夠自動從存儲介質上啟動,都能夠引導操作系統啟動,並且大部分都可以支持串口和以太網接口。

本節將對各種Bootloader總結分類,分析它們的共同特點。以u-boot為例,詳細討論Bootloader的設計與實現。

2.1 u-boot工程簡介

最早,DENX軟件工程中心的Wolfgang Denk基於8xxrom的源碼創建了ppcboot工程,並且不斷添加處理器的支持。后來,Sysgo Gmbh把ppcboot移植到ARM平台上,創建了ARMboot工程。然后以ppcboot工程和armboot工程為基礎,創建了u-boot工程。

現在u-boot已經能夠支持PowerPC、ARM、X86、MIPS體系結構的上百種開發板,已經成為功能最多、靈活性最強並且開發最積極的開放源碼BootLoader。目前仍然由DENX的Wolfgang Denk維護。

u-boot的源碼包可以從sourceforge網站下載,還可以訂閱該網站活躍的U-Boot Users郵件論壇,這個郵件論壇對於U-Boot的開發和使用都很有幫助。

u-boot軟件包下載網站:https://ftp.denx.de/pub/u-boot/

DENX相關的網站:http://www.denx.de/re/DPLG.html

u-boot git倉庫:https://gitlab.denx.de/u-boot/u-boot

2.2 u-boot源碼結構

從網站上下載得到u-boot源碼包,例如:u-boot-2016.05.tar.bz2 (最新的u-boot版本已經不支持s3c2440)。

解壓就可以得到全部u-boot源程序。在頂層目錄下有20個子目錄:

分別存放和管理不同的源程序。這些目錄中所要存放的文件有其規則,可以分為3類。 

  1. 第1類目錄與處理器體系結構或者開發板硬件直接相關; ·
  2. 第2類目錄是一些通用的函數或者驅動程序; 
  3. 第3類目錄是u-boot的應用程序、工具或者文檔。

下面列出了u-boot頂層目錄下各級目錄存放原則:

  • api: 硬件無關的功能函數的API。uboot移植時基本不用管,這些函數是uboot本身使用的。
  • arch: 與體系結構相關的代碼。比如 arm、 avr32、 m68k 等,我們現在用的是 ARM 芯片,所以只需要關心 arm 文件夾即可。
  • board:存放電路板相關的目錄文件,主要包含SDRAM、FLASH驅動,例如:samsung/smdk2410、samsung/smdk5250等目錄。
  • cmd:命令相關代碼。
  • common:common是普遍的普通的,這個文件夾下放的是一些與具體硬件無關的普遍適用的一些代碼。譬如控制台實現、crc校驗的。但是更多的主要是兩類:一類是cmd開頭的,是用來實現uboot的命令系統的;另一類是env開頭的,是用來實現環境變量的。
  • cpu: 這個目錄是SoC相關的,里面存放的代碼都是SoC相關初始化和控制代碼(譬如CPU的、中斷的、串口等SoC內部外設的,包括起始代碼start.S也在這里)。里面很多子文件夾,每一個子文件夾就是一個SoC系列。
  • configs:此文件夾為 uboot 配置文件, uboot 是可配置的,但是你要是自己從頭開始一個一個項目的配置,那就太麻煩了,因此一般半導體或者開發板廠商都會制作好一個配置文件。我們可以在這個做好的配置文件基礎上來添加自己想要的功能,這些半導體廠商或者開發板廠商制作好的配置文件統一命名為“xxx_defconfig”, xxx 表示開發板名字,這些 defconfig 文件都存放在 configs文件夾。
  • disk: 磁盤有關的。
  • doc:文檔目錄,里面存放了很多uboot相關文檔,這些文檔可以幫助我們理解uboot代碼。
  • drivers:顧名思義,驅動。這里面放的就是從linux源代碼中扣出來的原封不動的linux設備驅動,主要是開發板上必須用到的一些驅動,如網卡驅動、Inand/SD卡、NandFlash等的驅動。要知道:uboot中的驅動其實就是linux中的驅動,uboot在一定程度上移植了linux的驅動給自己用。但是linux是操作系統而uboot只是個裸機程序,因此這種移植會有不同,讓我說:uboot中的驅動其實是linux中的驅動的一部分。
  • dts:設備樹。
  • examples:示例代碼。
  • fs:filesystem,文件系統。這個也是從linux源代碼中移植過來的,用來管理Flash等資源。
  • include:頭文件目錄。uboot和linux kernel在管理頭文件時都采用了同一個思路,就是把所有的頭文件全部集中存放在include目錄下,而不是頭文件跟着自己對應的c文件。所以在uboot中頭文件包含時路徑結構要在這里去找。
  • lib:架構相關的庫文件。這類文件夾中的內容移植時基本不用管。
  • Licenses:許可證相關文件。
  • net: 網絡相關的代碼,譬如uboot中的tftp nfs ping命令 都是在這里實現的。
  • post:加電自檢程序。
  • scripts:腳本文件。
  • test:測試代碼。
  • tools:里面是一些工具類的代碼。譬如mkimage。

u-boot的源代碼包含對幾十種處理器、數百種開發板的支持。可是對於特定的開發板,配置編譯過程只需要其中部分程序。這里具體以S3C2440 ARM920T處理器為例,具體分析S3C2410處理器和開發板所依賴的程序,以及u-boot的通用函數和工具。

2.3 u-boot編譯

我們將下載的u-boot通過samba上傳到ubuntu服務器上:

復制uboot到/word/hardware路徑下,解壓u-boot-2016.tar.bz2:

cd /work/sambashare mv u-boot-2016.05.tar.bz2 /work/hardware cd /work/hardware sudo apt-get install  bzip2
tar -jxvf   u-boot-2016.05.tar.bz2 cd u-boot-2016.05

uboot的編譯分為兩步:配置、編譯。

2.3.1 配置

配置選擇所要使用的board ,我調試使用的是S3C2440,但是configs目錄下沒有smdk2440_defconfig這個文件,只有smdk2410_defconfig,因此執行如下命令,生成.config文件:

make smdk2410_defconfig

2.3.2  編譯

執行make命令,生成u-boot:

 make ARCH=arm CROSS_COMPILE=arm-linux-

CROSS-COPILE是在Makefile文件中定義的變量,是用來指定交叉工具鏈,ARCH用來指定處理器架構。此外,我們可以在u-boot的頂層Makefile中定義:

CROSS_COMPILE=arm-linux- ARCH=arm

這樣就省去了每次編譯都要在控制台輸入的麻煩。

編譯成功后會生成一個u-boot.bin,可以燒寫到開發板上,不過一般是用不起來的,需要進一步修改。

三 Source Insight加載u-boot

3.1 安裝Source Insignt

下載Source Insight,並根據安裝步驟進行安裝。

3.2 打開Source Insight

點擊上面的Project--->new project 然后彈出對話框:

這里project的名字我取成ubootProject,該project保存在我自己在G盤建立的一個文件文件夾下。 點擊OK。

3.3 共享文件夾

在之前章節我們設置過samba服務器共享路徑為/work/sambashare。而我們u-boot程序位於linux服務器的路徑為/work/hardware/u-boot-2016.05,我們將u-boot移動到/work/sambashare路徑:

windows下訪問samba服務器:步驟:網絡--->\\192.168.0.200--->Enter回車鍵:就可以看到我們共享的u-boot程序了:

3.4 映射網絡驅動器

打開我的電腦,點擊此電腦 --->映射網絡驅動器 把\\192.168.0.200\share路徑填進去,然后點擊完成:

 

然后在我的電腦以下就能夠看到例如以下截圖了:

3.5 New Project Settings

繼續回到Source Insight,進入設置頁面,這里映射的是Z盤(自己的依據實際情況而定),點擊OK:

3.6 添加文件

進入Add and Remove Project File頁面:

然后點擊確定,等待一下!成功之后選擇close。

3.7 打開項目

成功后,我們點擊右上角Project Symbal List:

3.8 增加文件類型

因為SI軟件有個特點,它只能發現自己識別了的文件類型,對於它未識別的文件視而不見。例如剛開始.s文件就不認識,要在C源文件中加入*s文件,欺騙SI軟件*.s也是C的源文件。點擊options--->File Type Options,選擇C/C++ Source File,添加*.S:

3.9 解析工程文件

點擊Project -> Synchronize Files,進行設置。

SI工作原理就是把所有的源代碼中的所有符號全部解析存儲到數據庫中,然后等我們進行符號查找時,SI不是查找文件而是查找數據庫幫我們索引符號,因此SI查找速度非常快。因此我們使用SI查閱源碼前先解析。

3.10 使用技巧之查找 

3.11 顯示行號

3.12 重新添加文件

四、make smdk2410_defconfig配置分析

Kconfig是各種配置界面的源文件,通過make menuconfig就可以打開u-boot配置界面,並可以對u-boot功能進行裁切,裁切后的配置保存到configs/smdk2410_defconfig文件。

執行配置命令make smdk2410_defconfig時先搜集所有默認的Kconfig配置,然后再用命令行指定的smdk2410_defconfig配置生成配置文件.config。

4.1 makefile基本語法

在分析u-boot編譯過程之前,你必須了解makefile語法,這里我准備了一份makefile入門博客

由於u-boot的Makefile中存在相互調用,這里介紹一下make -f和make -C區別:

  • -C選項 :Makefile中使用make -C會改變當前的工作目錄,表示到子目錄下執行子目錄的Makefile,頂層Makefile中的export的變量還有make默認的變量是可以傳遞給子目錄中的Makefile的;
  • -f選項:頂層Makefile使用make -f調用子目錄中的文件(文件名可以隨意,不一定用Makefile作為文件名,頂層Makefile中的export的變量也可以傳遞變量到底層目錄,另外在命令行中加入變量賦值選項,將覆蓋頂層Makefile中export的變量;

注意:在頂層Makefile中使用-f選項,例如make -f ./xxx/xx/build.mk 此時make命令的工作目錄仍然是頂層目錄,即CUDIR變量依然是./目錄而不是./xxx/xx/目錄。

4.2 執行make smdk2410_defconfig V=1配置命令

命令行輸入如下:

make smdk2410_defconfig V=1

V=1 指示編譯顯示詳細的輸出。默認V=0,編譯僅顯示必要的簡略信息。

configs/smdk2410_defconfig:

CONFIG_ARM=y CONFIG_TARGET_SMDK2410=y CONFIG_HUSH_PARSER=y CONFIG_SYS_PROMPT="SMDK2410 # " CONFIG_CMD_USB=y # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_DHCP=y CONFIG_CMD_PING=y CONFIG_CMD_CACHE=y CONFIG_CMD_EXT2=y CONFIG_CMD_FAT=y

編譯輸出如下:

  • 第一步:執行make -f ./scripts/Makefile.build obj=scripts/basic,編譯生成scripts/basic/fixdep工具;
  • 第二步:執行make -f ./scripts/Makefile.build obj=scripts/kconfig smdk2410_defconfig,編譯生成scripts/kcofig/conf工具;
  • 第三步:執行scripts/kconfig/conf --defconfig=arch/../configs/smdk2410_defconfig Kconfig,scripts/kconfig/conf根據smdk2410_defconfig生成.config配置文件;

其中.config文件比較重要,在后續編譯中會用到,.config部分代碼:

言歸正傳,整個配置流程的目的就是為了生成.config文件,實際上就是根據configs/smdk2410_defconfig 文件以及我們make menuconfig看到的那些默認配置(或者說是各個目錄下的Kconfig文件中有效的default項)生成的。

下面詳細分析.config文件是如何一步一步生成的。 Makefile的核心是依賴和命令,對於每個目標,首先會檢查依賴,如果依賴存在,則執行命令更新目標;如果依賴不存在,則會以依賴為目標,先生成依賴,待依賴生成后,再執行命令生成目標。 

4.3 頂層make smdk2410_defconfig規則

執行make smdk2410_defconfig命令時,u-boot根目錄下的Makefile中有唯一的規則匹配目標:

第476行:

config: scripts_basic outputmakefile FORCE $(Q)$(MAKE) $(build)=scripts/kconfig $@ %config: scripts_basic outputmakefile FORCE $(Q)$(MAKE) $(build)=scripts/kconfig $@

對於目標,smdk2410_defconfig,展開則有:

smdk2410_defconfig: scripts_basic outputmakefile FORCE $(Q)$(MAKE) $(build)=scripts/kconfig smdk2410_defconfig

build 在 scripts/Kbuild.include定義:

build := -f $(srctree)/scripts/Makefile.build obj

最終執行的命令就是:

make -f scripts/Makefile.build obj=scripts/kconfig smdk2410_defconfig

也就是我們4.2節中所說的第二步,編譯生成scripts/kcofig/conf工具。我們先來分析smdk2410_defconfig目標依賴的執行,然后再來分析該條命令。

4.4  scripts_basic依賴

目標smdk2410_defconfig的生成依賴於scripts_basic,outputmakefile和FORCE中,只有scripts_basic需要執行命令,如下:

# Basic helpers built in scripts/ PHONY += scripts_basic scripts_basic: $(Q)$(MAKE) $(build)=scripts/basic $(Q)rm -f .tmp_quiet_recordmcount

可見scripts_basic沒有進一步的依賴,展開后規則如下:

scripts_basic: $(Q) make -f ./scripts/Makefile.build obj=scripts/basic $(Q) rm -f .tmp_quiet_recordmcount

也就是我們4.2節中所說的第一步,make命令會轉到文件scripts/Makefile.build去執行。

大量實際目標的編譯都是調用scripts/Makefile.build完成的,文件script/Makefile.build的開頭會根據傳入的obj=scripts/basic參數設置src=scripts/basic:

# Modified for U-Boot
prefix := tpl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := spl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := .
endif
endif

kbuild-dir根據src變量(等於obj變量)是絕對路徑還是相對路徑來確定當前編譯的目錄,若為絕對路徑則該目錄即src變量的值,若為相對路徑則該變量就是src變量相對於源碼根目錄的目錄。kbuild-file即在該目錄下查找Kbuild文件,若能找到,則使用kbuild作為該目錄的編譯文件,若找不到則使用該目錄下的Makefile作為該目錄的編譯文件,然后將該文件包含進來。

# The filename Kbuild has precedence over Makefile
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file)

注意:具體的分析可以看這篇博客:六 makefile.build的分析,寫的很詳細。

這里展開替換后相當於:

include ./scripts/basic/Makefile

文件scripts/basic/Makefile中定義了編譯在主機上執行的工具fixdep:

hostprogs-y := fixdep always := $(hostprogs-y) # fixdep is needed to compile other host programs $(addprefix $(obj)/,$(filter-out fixdep,$(always))): $(obj)/fixdep

工具fixdep用於更新每一個生成目標的依賴文件*.cmd。

上面定義的這個$(always)在scripts/Makefile.build里會被添加到targets中:

targets += $(extra-y) $(MAKECMDGOALS) $(always)

簡而言之,scripts_basic規則:

scripts_basic: $(Q) make -f ./scripts/Makefile.build obj=scripts/basic

最終結果就是編譯scripts/basic/fixdep.c生成主機上的可執行文件fixdep。至於為什么要編譯fixdep和如何使用fixdep,會在后面介紹。

4.5 outputmakefile依賴

依賴outputmakefile:

PHONY += outputmakefile # outputmakefile generates a Makefile in the output directory, if using a # separate output directory. This allows convenient use of make in the # output directory. outputmakefile: ifneq ($(KBUILD_SRC),) $(Q)ln -fsn $(srctree) source $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \ $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL) endif

outputmakefile也沒有進一步的依賴。 如果執行如下命令:

make smdk2410_defconfig O=out

那么所有生成的目標都將放到out目錄,此時會通過outputmakefile導出一個makefile到out目錄進行編譯。 由於在當前目錄下編譯,$(KBUILD_SRC)為空,不需要導出makefile文件,outputmakefile為空目標。

4.6 FORCE依賴

PHONY += FORCE FORCE:

FORCE被定義為一個空目標。 如果一個目標添加FORCE依賴,每次編譯都會去先去執行FORCE(實際上什么都不做),然后運行命令更新目標,這樣就能確保目標每次都會被更新。在這里也就保證目標smdk2410_defconfig的命令:

$(Q)$(MAKE) $(build)=scripts/kconfig smdk2410_defconfig

總是能夠被執行。

4.7 make -f scripts/Makefile.build obj=scripts/kconfig smdk2410_defconfig

完成對目標smdk2410_defconfig依賴的更新后,接下來就是執行頂層目標的命令完成對smdk2410_defconfig的更新,也就是執行如下命令:

smdk2410_defconfig: scripts_basic outputmakefile FORCE make -f ./scripts/Makefile.build obj= scripts/kconfig smdk2410_defconfig

這個make命令會第二次轉到scripts/Makefile.build去執行。

文件script/Makefile.build的開頭會根據傳入的obj=scripts/kconfig參數設置src=scripts/kconfig。然后搜尋\$(srctree)/\$(src)子目錄下的makefile,由於src=scripts/kconfig參數不同於第一次調用的參數(src=scripts/basic),此處包含的makefile也不同於第一次的makefile了:

# The filename Kbuild has precedence over Makefile
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file)

這里替換展開后相當於:

include ./scripts/kconfig/Makefile

文件scripts/kconfig/Makefile中定義了所有匹配%config的目標:

PHONY += xconfig gconfig menuconfig config silentoldconfig update-po-config \
    localmodconfig localyesconfig

PHONY += oldnoconfig savedefconfig defconfig

PHONY += kvmconfig

PHONY += tinyconfig

對於這里傳入的smdk2410_defconfig,匹配的目標是:

%_defconfig: $(obj)/conf $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)

展開為:

smdk2410_defconfig: scripts/kconfig/conf $(Q)scripts/kconfig/conf --defconfig=arch/../configs/smdk2410_defconfig Kconfig

此處目標smdk2410_defconfig依賴於scripts/kconfig/conf,接下來檢查並生成依賴。

hostprogs-y := conf nconf mconf kxgettext qconf gconf

hostprogs-y指出conf被定義為主機上執行的程序,其依賴於另外兩個文件:

conf-objs   := conf.o  zconf.tab.o

通過編譯conf.c和zconf.tab.c生成conf-objs,並鏈接為scripts/kconfig/conf。

生成依賴后就是執行目標的命令了,這也是我們4.2節中所說的第三步:

$(Q)scripts/kconfig/conf  --defconfig=arch/../configs/rpi_3_32b_defconfig Kconfig

此處只做簡要的說明:

conf工具從根目錄下開始樹狀讀取默認的Kconfig文件,分析其配置並保存在內存中。分析完默認的Kconfig后再讀取指定文件(即arch/../configs/smdk2410_defconfig)更新得到最終的符號表,並輸出到.config文件中。

至此完成了make smdk2410_defconfig執行配置涉及的所有依賴和命令的分析。 

4.8 make defconfig配置流程簡圖

五、make編譯正向分析之頂層目標依賴

執行make進行編譯,生成可執行的二進制文件u-boot.bin或u-boot.elf。由於make編譯日志信息比較多,這里就不展開了:

 1 scripts/kconfig/conf --silentoldconfig Kconfig  2  CHK include/config.h  3  UPD include/config.h  4  GEN include/autoconf.mk  5  GEN include/autoconf.mk.dep  6  CHK include/config/uboot.release  7  UPD include/config/uboot.release  8  CHK include/generated/version_autogenerated.h  9  UPD include/generated/version_autogenerated.h  10  CHK include/generated/timestamp_autogenerated.h  11  UPD include/generated/timestamp_autogenerated.h  12  CC lib/asm-offsets.s  13  CHK include/generated/generic-asm-offsets.h  14  UPD include/generated/generic-asm-offsets.h  15  CC arch/arm/lib/asm-offsets.s  16  CHK include/generated/asm-offsets.h  17  UPD include/generated/asm-offsets.h  18  HOSTCC tools/envcrc.o  19  WRAP tools/lib/crc32.c  20  HOSTCC tools/lib/crc32.o  21  WRAP tools/common/env_embedded.c  22  HOSTCC tools/common/env_embedded.o  23  WRAP tools/lib/sha1.c  24  HOSTCC tools/lib/sha1.o  25  HOSTLD tools/envcrc  26  HOSTCC tools/gen_eth_addr  27  HOSTCC tools/img2srec  28  HOSTCC tools/mkenvimage.o  29  HOSTCC tools/os_support.o  30  HOSTLD tools/mkenvimage  31  HOSTCC tools/aisimage.o  32  HOSTCC tools/atmelimage.o  33  WRAP tools/common/bootm.c  34  HOSTCC tools/common/bootm.o  35  HOSTCC tools/default_image.o  36  WRAP tools/lib/fdtdec_common.c  37  HOSTCC tools/lib/fdtdec_common.o  38  WRAP tools/lib/fdtdec.c  39  HOSTCC tools/lib/fdtdec.o  40  HOSTCC tools/fit_common.o  41  HOSTCC tools/fit_image.o  42  HOSTCC tools/gpimage.o  43  HOSTCC tools/gpimage-common.o  44  WRAP tools/common/image-fit.c  45  HOSTCC tools/common/image-fit.o  46  HOSTCC tools/image-host.o  47  WRAP tools/common/image.c  48  HOSTCC tools/common/image.o  49  HOSTCC tools/imagetool.o  50  HOSTCC tools/imximage.o  51  HOSTCC tools/kwbimage.o  52  WRAP tools/lib/md5.c  53  HOSTCC tools/lib/md5.o  54  HOSTCC tools/lpc32xximage.o  55  HOSTCC tools/mxsimage.o  56  HOSTCC tools/omapimage.o  57  HOSTCC tools/pblimage.o  58  HOSTCC tools/pbl_crc32.o  59  WRAP tools/lib/rc4.c  60  HOSTCC tools/lib/rc4.o  61  HOSTCC tools/rkcommon.o  62  HOSTCC tools/rkimage.o  63  HOSTCC tools/rksd.o  64  HOSTCC tools/rkspi.o  65  HOSTCC tools/socfpgaimage.o  66  WRAP tools/lib/sha256.c  67  HOSTCC tools/lib/sha256.o  68  WRAP tools/common/hash.c  69  HOSTCC tools/common/hash.o  70  HOSTCC tools/ublimage.o  71  HOSTCC tools/zynqimage.o  72  WRAP tools/lib/libfdt/fdt.c  73  HOSTCC tools/lib/libfdt/fdt.o  74  WRAP tools/lib/libfdt/fdt_ro.c  75  HOSTCC tools/lib/libfdt/fdt_ro.o  76  WRAP tools/lib/libfdt/fdt_rw.c  77  HOSTCC tools/lib/libfdt/fdt_rw.o  78  WRAP tools/lib/libfdt/fdt_strerror.c  79  HOSTCC tools/lib/libfdt/fdt_strerror.o  80  WRAP tools/lib/libfdt/fdt_wip.c  81  HOSTCC tools/lib/libfdt/fdt_wip.o  82  WRAP tools/lib/libfdt/fdt_region.c  83  HOSTCC tools/lib/libfdt/fdt_region.o  84  WRAP tools/lib/libfdt/fdt_sw.c  85  HOSTCC tools/lib/libfdt/fdt_sw.o  86  HOSTCC tools/dumpimage.o  87  HOSTLD tools/dumpimage  88  HOSTCC tools/mkimage.o  89  HOSTLD tools/mkimage  90  HOSTCC tools/proftool  91  HOSTCC tools/fdtgrep.o  92  HOSTLD tools/fdtgrep  93   LD      arch/arm/cpu/built-in.o  94  CC arch/arm/cpu/arm920t/cpu.o  95  CC arch/arm/cpu/arm920t/s3c24x0/cpu_info.o  96  CC arch/arm/cpu/arm920t/s3c24x0/speed.o  97  CC arch/arm/cpu/arm920t/s3c24x0/timer.o  98   LD      arch/arm/cpu/arm920t/s3c24x0/built-in.o  99   LD      arch/arm/cpu/arm920t/built-in.o 100  AS arch/arm/cpu/arm920t/start.o 101  AS arch/arm/lib/vectors.o 102  AS arch/arm/lib/crt0.o 103  AS arch/arm/lib/relocate.o 104  CC arch/arm/lib/bootm.o 105  CC arch/arm/lib/sections.o 106  CC arch/arm/lib/stack.o 107  CC arch/arm/lib/interrupts.o 108  CC arch/arm/lib/reset.o 109  CC arch/arm/lib/cache.o 110  CC arch/arm/lib/cache-cp15.o 111   LD      arch/arm/lib/built-in.o 112  AR arch/arm/lib/lib.a 113  CC arch/arm/lib/eabi_compat.o 114   LD      board/samsung/common/built-in.o 115  CC board/samsung/smdk2410/smdk2410.o 116  AS board/samsung/smdk2410/lowlevel_init.o 117   LD      board/samsung/smdk2410/built-in.o 118  CC cmd/boot.o 119  CC cmd/bootm.o 120  CC cmd/help.o 121  CC cmd/version.o 122  CC cmd/source.o 123  CC cmd/bdinfo.o 124  CC cmd/cache.o 125  CC cmd/console.o 126  CC cmd/date.o 127  CC cmd/echo.o 128  CC cmd/elf.o 129  CC cmd/exit.o 130  CC cmd/ext2.o 131  CC cmd/fat.o 132  CC cmd/flash.o 133  CC cmd/itest.o 134  CC cmd/load.o 135  CC cmd/mem.o 136  CC cmd/misc.o 137  CC cmd/mtdparts.o 138  CC cmd/nand.o 139  CC cmd/net.o 140  CC cmd/pcmcia.o 141  CC cmd/reginfo.o 142   CC      cmd/test.o 143  CC cmd/ubi.o 144  CC cmd/ubifs.o 145  CC cmd/usb.o 146  CC cmd/ximg.o 147  CC cmd/yaffs2.o 148  CC cmd/nvedit.o 149  CC cmd/disk.o 150   LD      cmd/built-in.o 151  CC common/init/board_init.o 152   LD      common/init/built-in.o 153  CC common/main.o 154  CC common/exports.o 155  CC common/hash.o 156  CC common/cli_hush.o 157  CC common/autoboot.o 158  CC common/bootretry.o 159  CC common/board_f.o 160  CC common/board_r.o 161  CC common/bootm.o 162  CC common/bootm_os.o 163  CC common/env_attr.o 164  CC common/env_callback.o 165  CC common/env_flags.o 166  CC common/env_flash.o 167  CC common/usb.o 168  CC common/usb_hub.o 169  CC common/usb_storage.o 170  CC common/flash.o 171  CC common/splash.o 172  CC common/usb_kbd.o 173  CC common/env_common.o 174  CC common/console.o 175  CC common/dlmalloc.o 176  CC common/image.o 177  CC common/memsize.o 178  CC common/stdio.o 179  CC common/cli_simple.o 180   CC      common/cli.o 181  CC common/cli_readline.o 182  CC common/command.o 183  CC common/s_record.o 184  CC common/xyzModem.o 185   LD      common/built-in.o 186  CC common/env_embedded.o 187  CC disk/part.o 188  CC disk/part_dos.o 189   LD      disk/built-in.o 190   LD      drivers/adc/built-in.o 191   LD      drivers/block/built-in.o 192  CC drivers/crypto/fsl/sec.o 193   LD      drivers/crypto/fsl/built-in.o 194   LD      drivers/crypto/rsa_mod_exp/built-in.o 195   LD      drivers/crypto/built-in.o 196   LD      drivers/dfu/built-in.o 197   LD      drivers/hwmon/built-in.o 198  CC drivers/input/input.o 199   LD      drivers/input/built-in.o 200   LD      drivers/memory/built-in.o 201   LD      drivers/misc/built-in.o 202  CC drivers/pcmcia/tqm8xx_pcmcia.o 203   LD      drivers/pcmcia/built-in.o 204   LD      drivers/pwm/built-in.o 205  CC drivers/rtc/date.o 206  CC drivers/rtc/s3c24x0_rtc.o 207   LD      drivers/rtc/built-in.o 208   LD      drivers/soc/built-in.o 209   LD      drivers/sound/built-in.o 210   LD      drivers/spmi/built-in.o 211   LD      drivers/thermal/built-in.o 212   LD      drivers/timer/built-in.o 213   LD      drivers/tpm/built-in.o 214   LD      drivers/twserial/built-in.o 215   LD      drivers/video/bridge/built-in.o 216   LD      drivers/video/built-in.o 217   LD      drivers/watchdog/built-in.o 218   LD      drivers/built-in.o 219   LD      drivers/dma/built-in.o 220   LD      drivers/gpio/built-in.o 221   LD      drivers/i2c/built-in.o 222   LD      drivers/mmc/built-in.o 223  CC drivers/mtd/mtdcore.o 224  CC drivers/mtd/mtd_uboot.o 225  CC drivers/mtd/mtdpart.o 226  CC drivers/mtd/cfi_flash.o 227  CC drivers/mtd/jedec_flash.o 228   LD      drivers/mtd/built-in.o 229  CC drivers/mtd/nand/nand.o 230  CC drivers/mtd/nand/nand_bbt.o 231  CC drivers/mtd/nand/nand_ids.o 232  CC drivers/mtd/nand/nand_util.o 233  CC drivers/mtd/nand/nand_ecc.o 234  CC drivers/mtd/nand/nand_base.o 235  CC drivers/mtd/nand/nand_timings.o 236  CC drivers/mtd/nand/s3c2410_nand.o 237   LD      drivers/mtd/nand/built-in.o 238   LD      drivers/mtd/onenand/built-in.o 239   LD      drivers/mtd/spi/built-in.o 240  CC drivers/mtd/ubi/attach.o 241  CC drivers/mtd/ubi/build.o 242  CC drivers/mtd/ubi/vtbl.o 243  CC drivers/mtd/ubi/vmt.o 244  CC drivers/mtd/ubi/upd.o 245  CC drivers/mtd/ubi/kapi.o 246  CC drivers/mtd/ubi/eba.o 247  CC drivers/mtd/ubi/io.o 248  CC drivers/mtd/ubi/wl.o 249  CC drivers/mtd/ubi/crc32.o 250  CC drivers/mtd/ubi/misc.o 251  CC drivers/mtd/ubi/debug.o 252   LD      drivers/mtd/ubi/built-in.o 253  CC drivers/net/cs8900.o 254   LD      drivers/net/built-in.o 255   LD      drivers/net/phy/built-in.o 256   LD      drivers/pci/built-in.o 257   LD      drivers/power/built-in.o 258   LD      drivers/power/battery/built-in.o 259   LD      drivers/power/fuel_gauge/built-in.o 260   LD      drivers/power/mfd/built-in.o 261   LD      drivers/power/pmic/built-in.o 262   LD      drivers/power/regulator/built-in.o 263  CC drivers/serial/serial.o 264  CC drivers/serial/serial_s3c24x0.o 265   LD      drivers/serial/built-in.o 266  CC drivers/spi/spi.o 267   LD      drivers/spi/built-in.o 268   LD      drivers/usb/common/built-in.o 269   LD      drivers/usb/dwc3/built-in.o 270   LD      drivers/usb/emul/built-in.o 271   LD      drivers/usb/eth/built-in.o 272   LD      drivers/usb/gadget/built-in.o 273   LD      drivers/usb/gadget/udc/built-in.o 274  CC drivers/usb/host/ohci-s3c24xx.o 275   LD      drivers/usb/host/built-in.o 276   LD      drivers/usb/musb-new/built-in.o 277   LD      drivers/usb/musb/built-in.o 278   LD      drivers/usb/phy/built-in.o 279   LD      drivers/usb/ulpi/built-in.o 280  CC fs/fs.o 281  CC fs/ext4/ext4fs.o 282  CC fs/ext4/ext4_common.o 283  CC fs/ext4/dev.o 284   LD      fs/ext4/built-in.o 285  CC fs/fat/fat.o 286  CC fs/fat/file.o 287   LD      fs/fat/built-in.o 288  CC fs/ubifs/ubifs.o 289  CC fs/ubifs/io.o 290  CC fs/ubifs/super.o 291  CC fs/ubifs/sb.o 292  CC fs/ubifs/master.o 293  CC fs/ubifs/lpt.o 294  CC fs/ubifs/lpt_commit.o 295  CC fs/ubifs/scan.o 296  CC fs/ubifs/lprops.o 297  CC fs/ubifs/tnc.o 298  CC fs/ubifs/tnc_misc.o 299  CC fs/ubifs/debug.o 300  CC fs/ubifs/crc16.o 301  CC fs/ubifs/budget.o 302  CC fs/ubifs/log.o 303  CC fs/ubifs/orphan.o 304  CC fs/ubifs/recovery.o 305  CC fs/ubifs/replay.o 306  CC fs/ubifs/gc.o 307   LD      fs/ubifs/built-in.o 308  CC fs/yaffs2/yaffs_allocator.o 309  CC fs/yaffs2/yaffs_attribs.o 310  CC fs/yaffs2/yaffs_bitmap.o 311  CC fs/yaffs2/yaffs_uboot_glue.o 312  CC fs/yaffs2/yaffs_checkptrw.o 313  CC fs/yaffs2/yaffs_ecc.o 314  CC fs/yaffs2/yaffs_error.o 315  CC fs/yaffs2/yaffsfs.o 316  CC fs/yaffs2/yaffs_guts.o 317  CC fs/yaffs2/yaffs_nameval.o 318  CC fs/yaffs2/yaffs_nand.o 319  CC fs/yaffs2/yaffs_packedtags1.o 320  CC fs/yaffs2/yaffs_packedtags2.o 321  CC fs/yaffs2/yaffs_qsort.o 322  CC fs/yaffs2/yaffs_summary.o 323  CC fs/yaffs2/yaffs_tagscompat.o 324  CC fs/yaffs2/yaffs_verify.o 325  CC fs/yaffs2/yaffs_yaffs1.o 326  CC fs/yaffs2/yaffs_yaffs2.o 327  CC fs/yaffs2/yaffs_mtdif.o 328  CC fs/yaffs2/yaffs_mtdif2.o 329   LD      fs/yaffs2/built-in.o 330   LD      fs/built-in.o 331  CC lib/bzip2/bzlib.o 332  CC lib/bzip2/bzlib_crctable.o 333  CC lib/bzip2/bzlib_decompress.o 334  CC lib/bzip2/bzlib_randtable.o 335  CC lib/bzip2/bzlib_huffman.o 336   LD      lib/bzip2/built-in.o 337  CC lib/lzma/LzmaDec.o 338  CC lib/lzma/LzmaTools.o 339   LD      lib/lzma/built-in.o 340  CC lib/lzo/lzo1x_decompress.o 341   LD      lib/lzo/built-in.o 342  CC lib/zlib/zlib.o 343   LD      lib/zlib/built-in.o 344  CC lib/crc7.o 345  CC lib/crc8.o 346  CC lib/crc16.o 347  CC lib/gunzip.o 348  CC lib/initcall.o 349  CC lib/lmb.o 350  CC lib/ldiv.o 351  CC lib/net_utils.o 352  CC lib/qsort.o 353  CC lib/rc4.o 354  CC lib/strmhz.o 355  CC lib/rbtree.o 356  CC lib/list_sort.o 357  CC lib/hashtable.o 358  CC lib/errno.o 359  CC lib/display_options.o 360  CC lib/crc32.o 361  CC lib/ctype.o 362  CC lib/div64.o 363  CC lib/hang.o 364  CC lib/linux_compat.o 365  CC lib/linux_string.o 366  CC lib/membuff.o 367  CC lib/slre.o 368  CC lib/string.o 369  CC lib/time.o 370  CC lib/vsprintf.o 371  CC lib/panic.o 372  CC lib/strto.o 373   LD      lib/built-in.o 374  CC net/checksum.o 375  CC net/arp.o 376  CC net/bootp.o 377  CC net/eth_legacy.o 378  CC net/eth_common.o 379  CC net/net.o 380  CC net/nfs.o 381  CC net/ping.o 382  CC net/tftp.o 383   LD      net/built-in.o 384   LD      test/built-in.o 385   LD      test/dm/built-in.o 386  CC examples/standalone/stubs.o 387  LD examples/standalone/libstubs.o 388  CC examples/standalone/hello_world.o 389  LD examples/standalone/hello_world 390  OBJCOPY examples/standalone/hello_world.srec 391  OBJCOPY examples/standalone/hello_world.bin 392   LDS     u-boot.lds
393  LD u-boot 394  OBJCOPY u-boot.srec 395  OBJCOPY u-boot-nodtb.bin 396  COPY u-boot.bin 397  SYM u-boot.sym 398   CFG     u-boot.cfg
View Code

實際上,通過這個日志輸出,我們可以發現編譯的文件中有一些是帶有s3c24x0、smdk2410字樣的,這也是告訴我們這些文件是和cpu直接相關的,如果我們想新加一個開發板,那么我們也應該為該開發板cpu配置這些相關文件。

 95   CC      arch/arm/cpu/arm920t/s3c24x0/cpu_info.o 96   CC      arch/arm/cpu/arm920t/s3c24x0/speed.o 97   CC      arch/arm/cpu/arm920t/s3c24x0/timer.o 98   LD      arch/arm/cpu/arm920t/s3c24x0/built-in.o 115   CC      board/samsung/smdk2410/smdk2410.o 116   AS      board/samsung/smdk2410/lowlevel_init.o 117   LD      board/samsung/smdk2410/built-in.o

LD為鏈接操作,由arm-linux-ld完成,將各個每個目錄下的.o文件鏈接生成built-in.o目標文件。

CC為編譯操作,由arm-linux-gcc完成,將各個源文件編譯生成.o目標文件。

5.1 編譯參數

在編譯的時候我們需要配置ARCH、以及CROSS_COMPILE參數,那這兩個參數有什么用呢?

5.1.1 ARCH

直接在頂層的Makefile搜索ARCH,發現文件中存在大量的$(srctree)/arch/$(ARCH)/,$(srctree)表示uboot當前路徑.,不難猜出$(ARCH)實際上就是arch路徑下的文件名稱:可以看到arch目錄下文件夾的名字實際上表示的就是處理器架構:

drwxr-xr-x 17 root root 4096 2月   8  2022 ./
drwxr-xr-x 22 root root 4096 5月   9 20:07 ../
drwxr-xr-x  6 root root 4096 2月   8  2022 arc/
drwxr-xr-x 28 root root 4096 2月   8  2022 arm/
drwxr-xr-x  5 root root 4096 2月   8  2022 avr32/
drwxr-xr-x  5 root root 4096 2月   8  2022 blackfin/
-rw-r--r--  1 root root   20 2月   8  2022 .gitignore
-rw-r--r--  1 root root 4385 2月   8  2022 Kconfig
drwxr-xr-x  5 root root 4096 2月   8  2022 m68k/
drwxr-xr-x  6 root root 4096 2月   8  2022 microblaze/
drwxr-xr-x  8 root root 4096 2月   8  2022 mips/
drwxr-xr-x  5 root root 4096 2月   8  2022 nds32/
drwxr-xr-x  6 root root 4096 2月   8  2022 nios2/
drwxr-xr-x  5 root root 4096 2月   8  2022 openrisc/
drwxr-xr-x  6 root root 4096 2月   8  2022 powerpc/
drwxr-xr-x  6 root root 4096 2月   8  2022 sandbox/
drwxr-xr-x  5 root root 4096 2月   8  2022 sh/
drwxr-xr-x  5 root root 4096 2月   8  2022 sparc/
drwxr-xr-x  6 root root 4096 2月   8  2022 x86/
5.1.2 CROSS_COMPILE

直接在頂層的Makefile搜索CROSS_COMPILE,我們會發現下面這些變量引用了CROSS_COMPILE:

AS              = $(CROSS_COMPILE)as
# Always use GNU ld
ifneq ($(shell $(CROSS_COMPILE)ld.bfd -v 2> /dev/null),)
LD              = $(CROSS_COMPILE)ld.bfd
else
LD              = $(CROSS_COMPILE)ld
endif
CC              = $(CROSS_COMPILE)gcc
CPP             = $(CC) -E
AR              = $(CROSS_COMPILE)ar
NM              = $(CROSS_COMPILE)nm
LDR             = $(CROSS_COMPILE)ldr
STRIP           = $(CROSS_COMPILE)strip
OBJCOPY         = $(CROSS_COMPILE)objcopy
OBJDUMP         = $(CROSS_COMPILE)objdump

那么LD、CC這些是什么,這些實際上就是交叉編譯工具。如果我們想使用arm-linux-gcc編譯器,我們就必須指定CROSS_COMPILE = arm-linux-。

5.1.3 V=1

在Makefile中找到$(V)引用:

#
# Normally, we echo the whole command before executing it. By making
# that echo $($(quiet)$(cmd)), we now have the possibility to set
# $(quiet) to choose other forms of output instead, e.g.
#
#         quiet_cmd_cc_o_c = Compiling $(RELDIR)/$@
#         cmd_cc_o_c       = $(CC) $(c_flags) -c -o $@ $<
#
# If $(quiet) is empty, the whole command will be printed.
# If it is set to "quiet_", only the short version will be printed.
# If it is set to "silent_", nothing will be printed at all, since
# the variable $(silent_cmd_cc_o_c) doesn't exist.
#
# A simple variant is to prefix commands with $(Q) - that's useful
# for commands that shall be hidden in non-verbose mode.
#
#       $(Q)ln $@ :<
#
# If KBUILD_VERBOSE equals 0 then the above command will be hidden.
# If KBUILD_VERBOSE equals 1 then the above command is displayed.
#
# To put more focus on warnings, be less verbose as default
# Use 'make V=1' to see the full commands

ifeq ("$(origin V)", "command line")     # V變量 來自命令行
  KBUILD_VERBOSE = $(V)
endif
ifndef KBUILD_VERBOSE
  KBUILD_VERBOSE = 0
endif

ifeq ($(KBUILD_VERBOSE),1)
  quiet =
  Q =
else
  quiet=quiet_
  Q = @
endif

可以看到如果在命令行指定了V=1,那么:

  quiet =
  Q =

如果不設置Q,那么在執行命令時將會打印整個命令,也就是會回顯命令。

否則:

  quiet=quiet_
  Q = @

如果設置為Q=@。在執行命令時關閉回顯。

5.2 目標_all和all對$(ALL-y)的依賴

從頂層的Makefile開始查找,找到的第一個目標為_all,128行:

# That's our default target when none is given on the command line
PHONY := _all _all:

在Makefile中,.PHONY后面的target表示的也是一個偽造的target, 而不是真實存在的文件target,注意Makefile的target默認是文件。

緊接着會對_all偽目標添加all偽目標依賴,194行:

# If building an external module we do not care about the all: rule # but instead _all depend on modules PHONY += all ifeq ($(KBUILD_EXTMOD),) _all: all else _all: modules endif

當我們定義了M變量或者SUBDIRS時表示編譯一個外部模塊,顯然我們並沒有編譯一個外部模塊。因此偽目標_all依賴all。

all自身依賴於$(ALL-y),803行:

all:        $(ALL-y) ifneq ($(CONFIG_SYS_GENERIC_BOARD),y) @echo "===================== WARNING ======================" @echo "Please convert this board to generic board." @echo "Otherwise it will be removed by the end of 2014." @echo "See doc/README.generic-board for further information" @echo "====================================================" endif ifeq ($(CONFIG_DM_I2C_COMPAT),y) @echo "===================== WARNING ======================" @echo "This board uses CONFIG_DM_I2C_COMPAT. Please remove" @echo "(possibly in a subsequent patch in your series)" @echo "before sending patches to the mailing list." @echo "====================================================" endif

5.3 目標$(ALL-y)

$(ALL-y)定義了最終需要生成的所有文件,731行

# Always append ALL so that arch config.mk's can add custom ones
ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map u-boot.cfg binary_size_check ALL-$(CONFIG_ONENAND_U_BOOT) += u-boot-onenand.bin ifeq ($(CONFIG_SPL_FSL_PBL),y) ALL-$(CONFIG_RAMBOOT_PBL) += u-boot-with-spl-pbl.bin else ifneq ($(CONFIG_SECURE_BOOT), y) # For Secure Boot The Image needs to be signed and Header must also # be included. So The image has to be built explicitly ALL-$(CONFIG_RAMBOOT_PBL) += u-boot.pbl endif endif ALL-$(CONFIG_SPL) += spl/u-boot-spl.bin ALL-$(CONFIG_SPL_FRAMEWORK) += u-boot.img # 鏡像文件 ALL-$(CONFIG_TPL) += tpl/u-boot-tpl.bin ALL-$(CONFIG_OF_SEPARATE) += u-boot.dtb # 設備樹文件 ifeq ($(CONFIG_SPL_FRAMEWORK),y) ALL-$(CONFIG_OF_SEPARATE) += u-boot-dtb.img # 設備樹鏡像文件 endif ALL-$(CONFIG_OF_HOSTFILE) += u-boot.dtb ifneq ($(CONFIG_SPL_TARGET),) ALL-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%) endif ALL-$(CONFIG_REMAKE_ELF) += u-boot.elf # u-boot.bin文件加入了調試信息,可以用來調試 ALL-$(CONFIG_EFI_APP) += u-boot-app.efi ALL-$(CONFIG_EFI_STUB) += u-boot-payload.efi ifneq ($(BUILD_ROM),) ALL-$(CONFIG_X86_RESET_VECTOR) += u-boot.rom endif # enable combined SPL/u-boot/dtb rules for tegra ifeq ($(CONFIG_TEGRA)$(CONFIG_SPL),yy) ALL-y += u-boot-tegra.bin u-boot-nodtb-tegra.bin ALL-$(CONFIG_OF_SEPARATE) += u-boot-dtb-tegra.bin endif # Add optional build target if defined in board/cpu/soc headers ifneq ($(CONFIG_BUILD_TARGET),) ALL-y += $(CONFIG_BUILD_TARGET:"%"=%) endif

以上的$(ALL-y)目標中看起來很復雜,但是除了第一行的通用目標外,其余的目標都只有在特殊條件下才生成,這里略去不提,只分析通用目標依賴:

ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map u-boot.cfg binary_size_check

這里有必要說一下u-boot.img,u-boot.bin:

  • u-boot.bin:是二進制編譯的uboot引導加載程序, 很多image 文件的生成都需要依賴於它;
  • u-boot.img:它是給u-boot.bin 加上0x40 Byte 長度的Header。 里面包含加載地址,運行地址,CRC等重要信息, 用來讓它的加載程序識別;這個只有在配置CONFIG_SPL_FRAMEWORK時才有效

芯片燒錄選擇u-boot.bin還是u-boot.img取決於設備的性質。目前許多SoC/CPU啟動ROM都能夠加載u-boot.img,讀取文件的頭部,加載u-boot.bin到內存中並最終執行它。

其中u-bootimg文件生成規則如下

u-boot-dtb.img u-boot.img u-boot.kwb u-boot.pbl u-boot-ivt.img: \
                $(if $(CONFIG_SPL_LOAD_FIT),u-boot-nodtb.bin dts/dt.dtb,u-boot.bin) FORCE
        $(call if_changed,mkimage)

u-boot.itb: u-boot-nodtb.bin dts/dt.dtb $(U_BOOT_ITS) FORCE
        $(call if_changed,mkfitimage)

u-boot-spl.kwb: u-boot.img spl/u-boot-spl.bin FORCE
        $(call if_changed,mkimage)
5.3.1 u-boot.srec

$(ALL-y)依賴u-boot.srec:

u-boot.hex u-boot.srec: u-boot FORCE $(call if_changed,objcopy)
5.3.2 u-boot.bin

$(ALL-y)依賴u-boot.bin,826行:

ifeq ($(CONFIG_OF_SEPARATE),y) u-boot-dtb.bin: u-boot-nodtb.bin dts/dt.dtb FORCE $(call if_changed,cat) u-boot.bin: u-boot-dtb.bin FORCE $(call if_changed,copy) else u-boot.bin: u-boot-nodtb.bin FORCE $(call if_changed,copy) endif

如果打開了device tree支持,則有依賴關系:

u-boot.bin --> u-boot-dtb.bin --> u-boot-nodtb.bin + dts/dt.dtb

由於沒有定義CONFIG_OF_SEPARATE選項,所以ifeq執行結果為false,我們關心else中定義的依賴關系:

u-boot.bin --> u-boot-nodtb.bin

u-boot.bin目標文件的生成依賴於u-boot-nodtb.bin,FORCE依賴起到一個強制更新目標的作用。

u-boot-nodtb.bin: u-boot FORCE $(call if_changed,objcopy) $(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE)) $(BOARD_SIZE_CHECK)

命令中的if_changed函數定義在scripts/Kbuild.include文件中,這是通過327行include引進的:

# We need some generic definitions (do not try to remake the file).
scripts/Kbuild.include: ;
include scripts/Kbuild.include

if_changed函數定義如下,這里外層是一個if函數,然后又內嵌了一個strip函數

if_changed = $(if $(strip $(any-prereq) $(arg-check)),                       \
    @set -e;                                                             \
    $(echo-cmd) $(cmd_$(1));                                             \    
    printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)                 
# Normally we fill empty space with 0xff
quiet_cmd_objcopy = OBJCOPY $@
cmd_objcopy = $(OBJCOPY) --gap-fill=0xff $(OBJCOPYFLAGS) \
    $(OBJCOPYFLAGS_$(@F)) $< $@
OBJCOPY        = $(CROSS_COMPILE)objcopy

很顯然OBJCOPY=arm-linux-objcopy。$(call if_changed,objcopy)展開后大致如下:

echo 'arm-linux-objcopy $< $@'; arm-linux-objcopy $<  $@      

這里就是利用arm-linux-objcopy命令將u-boot的轉換為二進制文件u-boot-nodtb.bin。

5.3.3 u-boot.sym

$(ALL-y)依賴u-boot.sym:

u-boot.sym: u-boot FORCE $(call if_changed,sym)
5.3.4 System.map

$(ALL-y)依賴System.map:

System.map: u-boot @$(call SYSTEM_MAP,$<) > $@
5.3.5 u-boot.cfg

$(ALL-y)依賴u-boot.cfg:

u-boot.cfg: include/config.h FORCE $(call if_changed,cpp_cfg)

include/config.h文件在make smdk2410_config時創建,主要包含以下信息:

/* Automatically generated - do not edit */ #define CONFIG_BOARDDIR board/samsung/smdk2410 #include <config_defaults.h> #include <config_uncmd_spl.h> #include <configs/smdk2410.h> #include <asm/config.h> #include <config_fallbacks.h>

#include <configs/smdk2410.h>從這里可以看出在configs目錄下,包含smdk2410.h文件,如果在board目錄下新建一個開發板的目錄,則在include/configs目錄下要創建一個.h文件,里面存放的開發板配置信息:

/* * (C) Copyright 2002 * Sysgo Real-Time Solutions, GmbH <www.elinos.com> * Marius Groeger <mgroeger@sysgo.de> * Gary Jennejohn <garyj@denx.de> * David Mueller <d.mueller@elsoft.ch> * * Configuation settings for the SAMSUNG SMDK2410 board. * * SPDX-License-Identifier: GPL-2.0+ */ #ifndef __CONFIG_H #define __CONFIG_H

/* * High Level Configuration Options * (easy to change) */
#define CONFIG_S3C24X0        /* This is a SAMSUNG S3C24x0-type SoC */
#define CONFIG_S3C2410        /* specifically a SAMSUNG S3C2410 SoC */
#define CONFIG_SMDK2410        /* on a SAMSUNG SMDK2410 Board */

#define CONFIG_SYS_TEXT_BASE    0x0

#define CONFIG_SYS_ARM_CACHE_WRITETHROUGH

/* input clock of PLL (the SMDK2410 has 12MHz input clock) */
#define CONFIG_SYS_CLK_FREQ    12000000

#define CONFIG_CMDLINE_TAG    /* enable passing of ATAGs */
#define CONFIG_SETUP_MEMORY_TAGS
#define CONFIG_INITRD_TAG

/* * Hardware drivers */
#define CONFIG_CS8900        /* we have a CS8900 on-board */
#define CONFIG_CS8900_BASE    0x19000300
#define CONFIG_CS8900_BUS16    /* the Linux driver does accesses as shorts */

/* * select serial console configuration */
#define CONFIG_S3C24X0_SERIAL
#define CONFIG_SERIAL1        1    /* we use SERIAL 1 on SMDK2410 */

/************************************************************ * USB support (currently only works with D-cache off) ************************************************************/
#define CONFIG_USB_OHCI
#define CONFIG_USB_OHCI_S3C24XX
#define CONFIG_USB_KEYBOARD
#define CONFIG_USB_STORAGE
#define CONFIG_DOS_PARTITION

/************************************************************ * RTC ************************************************************/
#define CONFIG_RTC_S3C24X0

#define CONFIG_BAUDRATE        115200

/* * BOOTP options */
#define CONFIG_BOOTP_BOOTFILESIZE
#define CONFIG_BOOTP_BOOTPATH
#define CONFIG_BOOTP_GATEWAY
#define CONFIG_BOOTP_HOSTNAME

/* * Command line configuration. */
#define CONFIG_CMD_BSP
#define CONFIG_CMD_DATE
#define CONFIG_CMD_NAND
#define CONFIG_CMD_REGINFO

#define CONFIG_CMDLINE_EDITING

/* autoboot */
#define CONFIG_BOOTDELAY    5
#define CONFIG_BOOT_RETRY_TIME    -1
#define CONFIG_RESET_TO_RETRY
#define CONFIG_ZERO_BOOTDELAY_CHECK

#define CONFIG_NETMASK        255.255.255.0
#define CONFIG_IPADDR        10.0.0.110
#define CONFIG_SERVERIP        10.0.0.1

#if defined(CONFIG_CMD_KGDB)
#define CONFIG_KGDB_BAUDRATE    115200    /* speed to run kgdb serial port */
#endif

/* * Miscellaneous configurable options */
#define CONFIG_SYS_LONGHELP        /* undef to save memory */
#define CONFIG_SYS_CBSIZE    256
/* Print Buffer Size */
#define CONFIG_SYS_PBSIZE    (CONFIG_SYS_CBSIZE + \
                sizeof(CONFIG_SYS_PROMPT)+16) #define CONFIG_SYS_MAXARGS    16
#define CONFIG_SYS_BARGSIZE    CONFIG_SYS_CBSIZE

#define CONFIG_DISPLAY_CPUINFO                /* Display cpu info */

#define CONFIG_SYS_MEMTEST_START    0x30000000    /* memtest works on */
#define CONFIG_SYS_MEMTEST_END        0x33F00000    /* 63 MB in DRAM */

#define CONFIG_SYS_LOAD_ADDR        0x30800000

/* support additional compression methods */
#define CONFIG_BZIP2
#define CONFIG_LZO
#define CONFIG_LZMA

/*----------------------------------------------------------------------- * Physical Memory Map */
#define CONFIG_NR_DRAM_BANKS    1          /* we have 1 bank of DRAM */
#define PHYS_SDRAM_1        0x30000000 /* SDRAM Bank #1 */
#define PHYS_SDRAM_1_SIZE    0x04000000 /* 64 MB */

#define PHYS_FLASH_1        0x00000000 /* Flash Bank #0 */

#define CONFIG_SYS_FLASH_BASE    PHYS_FLASH_1

/*----------------------------------------------------------------------- * FLASH and environment organization */

#define CONFIG_SYS_FLASH_CFI
#define CONFIG_FLASH_CFI_DRIVER
#define CONFIG_FLASH_CFI_LEGACY
#define CONFIG_SYS_FLASH_LEGACY_512Kx16
#define CONFIG_FLASH_SHOW_PROGRESS    45

#define CONFIG_SYS_MAX_FLASH_BANKS    1
#define CONFIG_SYS_FLASH_BANKS_LIST     { CONFIG_SYS_FLASH_BASE }
#define CONFIG_SYS_MAX_FLASH_SECT    (19)

#define CONFIG_ENV_ADDR            (CONFIG_SYS_FLASH_BASE + 0x070000)
#define CONFIG_ENV_IS_IN_FLASH
#define CONFIG_ENV_SIZE            0x10000
/* allow to overwrite serial and ethaddr */
#define CONFIG_ENV_OVERWRITE

/* * Size of malloc() pool * BZIP2 / LZO / LZMA need a lot of RAM */
#define CONFIG_SYS_MALLOC_LEN    (4 * 1024 * 1024)

#define CONFIG_SYS_MONITOR_LEN    (448 * 1024)
#define CONFIG_SYS_MONITOR_BASE    CONFIG_SYS_FLASH_BASE

/* * NAND configuration */ #ifdef CONFIG_CMD_NAND #define CONFIG_NAND_S3C2410
#define CONFIG_SYS_S3C2410_NAND_HWECC
#define CONFIG_SYS_MAX_NAND_DEVICE    1
#define CONFIG_SYS_NAND_BASE        0x4E000000
#endif

/* * File system */
#define CONFIG_CMD_UBI
#define CONFIG_CMD_UBIFS
#define CONFIG_CMD_MTDPARTS
#define CONFIG_MTD_DEVICE
#define CONFIG_MTD_PARTITIONS
#define CONFIG_YAFFS2
#define CONFIG_RBTREE

/* additions for new relocation code, must be added to all boards */
#define CONFIG_SYS_SDRAM_BASE    PHYS_SDRAM_1
#define CONFIG_SYS_INIT_SP_ADDR    (CONFIG_SYS_SDRAM_BASE + 0x1000 - \ GENERATED_GBL_DATA_SIZE) #define CONFIG_BOARD_EARLY_INIT_F

#endif /* __CONFIG_H */
View Code
5.3.6 binary_size_check

$(ALL-y)依賴binary_size_check:

binary_size_check: u-boot-nodtb.bin FORCE @file_size=$(shell wc -c u-boot-nodtb.bin | awk '{print $$1}') ; \
 map_size=$(shell cat u-boot.map | \ awk '/_image_copy_start/ {start = $$1} /_image_binary_end/ {end = $$1} END {if (start != "" && end != "") print "ibase=16; " toupper(end) " - " toupper(start)}' \ | sed 's/0X//g' \ | bc); \
    if [ "" != "$$map_size" ]; then \
        if test $$map_size -ne $$file_size; then \
            echo "u-boot.map shows a binary size of $$map_size" >&2 ; \
            echo " but u-boot-nodtb.bin shows $$file_size" >&2 ; \
            exit 1; \
 fi \ fi

顯然對於binary_size_check有下列依賴關系:

 binary_size_check --> u-boot-nodtb.bin --> u-boot

以上通用目標$(ALL-y)的依賴有一個共同點,除了u-boot.cfg依賴於include/config.h外,其余目標全都依賴於u-boot(實際上除了依賴於u-boot外,還依賴於FORCE,由於FORCE依賴本身是一個空目標,為了方便,這里略去了對FORCE依賴的描述):

六、make編譯正向分析之目標u-boot

分析1191行:

u-boot:    $(u-boot-init) $(u-boot-main) u-boot.lds FORCE $(call if_changed,u-boot__) ifeq ($(CONFIG_KALLSYMS),y) $(call cmd,smap) $(call cmd,u-boot__) common/system_map.o endif

u-boot依賴於\$(u-boot-init)  \$(u-boot-main)  u-boot.lds。

其中\$(u-boot-init)和\$(u-boot-main)分別被定義為:

u-boot-init := $(head-y)
u-boot-main := $(libs-y)

6.1 依賴 u-boot.lds

這里先介紹u-boot.lds,1328行:

u-boot.lds: $(LDSCRIPT) prepare FORCE $(call if_changed_dep,cpp_lds)

它的依賴有兩個:\$(LDSCRIPT)和prepare。這里先分析\$(LDSCRIPT):

ifndef LDSCRIPT #LDSCRIPT := $(srctree)/board/$(BOARDDIR)/u-boot.lds.debug ifdef CONFIG_SYS_LDSCRIPT # need to strip off double quotes LDSCRIPT := $(srctree)/$(CONFIG_SYS_LDSCRIPT:"%"=%) endif endif # If there is no specified link script, we look in a number of places for it ifndef LDSCRIPT ifeq ($(wildcard $(LDSCRIPT)),) LDSCRIPT := $(srctree)/board/$(BOARDDIR)/u-boot.lds endif ifeq ($(wildcard $(LDSCRIPT)),) LDSCRIPT := $(srctree)/$(CPUDIR)/u-boot.lds endif ifeq ($(wildcard $(LDSCRIPT)),) LDSCRIPT := $(srctree)/arch/$(ARCH)/cpu/u-boot.lds endif endif

解析:如果沒有定義LDSCRIPT和CONFIG_SYS_LDSCRIPT,則默認使用u-boot自帶的lds文件,包括board/\$(BOARDDIR)和\$(CPUDIR)目錄下定制的針對board或cpu的lds文件;如果沒有定制的lds文件,則采用arch/arm/cpu目錄下默認的lds鏈接文件u-boot.lds,鏈接腳本分析可以參考這篇博客

6.2 依賴$(head-y)

在linux上搜索head-y這個目標: grep 'head-y' * -nR 得到下面這個結果:

arch/arm/Makefile:74:head-y := arch/arm/cpu/$(CPU)/start.o

所以head-y指的是start.S。

6.3 依賴$(libs-y)

在頂層目錄Makefile中搜索libs-y可以發現其包含許多目錄, 比如:

libs-y += lib/ libs-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/ libs-$(CONFIG_OF_EMBED) += dts/ libs-y += fs/ libs-y += net/ libs-y += disk/ libs-y += drivers/ libs-y += drivers/dma/ libs-y += drivers/gpio/ libs-y += drivers/i2c/ libs-y += drivers/mmc/ libs-y += drivers/mtd/ libs-$(CONFIG_CMD_NAND) += drivers/mtd/nand/ libs-y += drivers/mtd/onenand/ libs-$(CONFIG_CMD_UBI) += drivers/mtd/ubi/ libs-y += drivers/mtd/spi/ libs-y += drivers/net/ libs-y += drivers/net/phy/

另:

libs-y := $(patsubst %/, %/built-in.o, $(libs-y))

這條規則使libs-y中每個條目的最后一個斜杠替換成 /built-in.o,比如 drivers/mtd/ 會變為 drivers/mtd/built-in.o。

可見libs-y被定義為各層驅動目錄下build-in.o的集合,而這些built-in.o則由 Kbuild Makefile 將obj-y所包含的各個文件編譯而成,具體可研究scripts/Kbuild.include 和 scripts/Makefile.build。

ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),) builtin-target := $(obj)/built-in.o endif
$(builtin-target): $(obj-y) FORCE $(call if_changed,link_o_target)

u-boot文件目標依賴:

七、make編譯正向分析之目標prepare

實際上prepare是一系列prepare偽目標和動作的組合,完成編譯前的准備工作:

# Listed in dependency order PHONY += prepare archprepare prepare0 prepare1 prepare2 prepare3 # prepare3 is used to check if we are building in a separate output directory, # and if so do: # 1) Check that make has not been executed in the kernel src $(srctree) prepare3: include/config/uboot.release ifneq ($(KBUILD_SRC),) @$(kecho) ' Using $(srctree) as source for U-Boot' $(Q)if [ -f $(srctree)/.config -o -d $(srctree)/include/config ]; then \ echo >&2 " $(srctree) is not clean, please run 'make mrproper'"; \ echo >&2 " in the '$(srctree)' directory.";\ /bin/false; \ fi; endif # prepare2 creates a makefile if using a separate output directory prepare2: prepare3 outputmakefile prepare1: prepare2 $(version_h) $(timestamp_h) \ include/config/auto.conf ifeq ($(CONFIG_HAVE_GENERIC_BOARD),) ifeq ($(CONFIG_SYS_GENERIC_BOARD),y) @echo >&2 " Your architecture does not support generic board." @echo >&2 " Please undefine CONFIG_SYS_GENERIC_BOARD in your board config file." @/bin/false endif endif ifeq ($(wildcard $(LDSCRIPT)),) @echo >&2 " Could not find linker script." @/bin/false endif archprepare: prepare1 scripts_basic prepare0: archprepare FORCE $(Q)$(MAKE) $(build)=. # All the preparing.. prepare: prepare0

偽目標prepare,prepare0,archprepare,prepare1,prepare2,prepare3之間的依賴如下:

在prepare1的依賴列表中,除了include/config/auto.conf之外,還有\$(version_h)和\$(timestamp_h),它們的依賴關系如下:

version_h := include/generated/version_autogenerated.h timestamp_h := include/generated/timestamp_autogenerated.h defaultenv_h := include/generated/defaultenv_autogenerated.h

對於位於最后的prepare3的依賴include/config/uboot.release,它還有下一級依賴:

# Store (new) UBOOTRELEASE string in include/config/uboot.release include/config/uboot.release: include/config/auto.conf FORCE $(call filechk,uboot.release)

對於include/config/auto.conf,Makefile中有一個匹配規則:

# If .config is newer than include/config/auto.conf, someone tinkered # with it and forgot to run make oldconfig. # if auto.conf.cmd is missing then we are probably in a cleaned tree so # we execute the config step to be sure to catch updated Kconfig files include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd $(Q)$(MAKE) -f $(srctree)/Makefile syncconfig @# If the following part fails, include/config/auto.conf should be @# deleted so "make silentoldconfig" will be re-run on the next build. $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.autoconf || \ { rm -f include/config/auto.conf; false; } @# include/config.h has been updated after "make silentoldconfig". @# We need to touch include/config/auto.conf so it gets newer @# than include/config.h. @# Otherwise, 'make silentoldconfig' would be invoked twice. $(Q)touch include/config/auto.conf

include/config/auto.conf依賴於$(KCONFIG_CONFIG)和include/config/auto.conf.cmd,其中:

  • $(KCONFIG_CONFIG)實際上就是.config文件;
  • include/config/auto.conf.cmd是由fixdep在編譯時生成的依賴文件。

八  make編譯流程圖

 

完成目標依賴分析后,剩下的就是基於完整的目標依賴關系圖,從最底層的依賴開始,逐層運行命令生成目標,直到生成頂層目標。

 參考文章:

[1] bootloader 詳細介紹

[2] 新版u-boot移植到s3c2440開發板(一)--建立單板

[3] UBOOT2016.07移植(第一篇)初步分析(部分轉載)

[4]u-boot-2016.09 make配置過程分析(部分轉載)

[5]u-boot-2016.09 make編譯過程分析(一)(部分轉載)

[6]u-boot-2016.09 make編譯過程分析(二)(部分轉載)

[7]U-Boot工程目錄介紹

[8] 六 makefile.build的分析


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM