U-Boot移植之前期分析(上)

        老是看別人移植uboot,用別人移植好的uboot,今天終於下定決心自己移植一個uboot來玩玩,好歹我也是個軟件開發人員啊。

        第一步:去ftp://ftp.denx.de/pub/u-boot/網站下載個uboot工程源碼,爲了防止環境出問題,我決定用個老一點的,於是就下了:u-boot-1.1.6.tar.bz2。

        第二步:解壓源碼:tar  jxvf  u-boot-1.1.6.tar.bz2。

        第三步:建立source insight工程

        好了完成以上三步之後,我們需要的前提條件都準備好了,下面在着手移植前需要大概瞭解一下u-boot的整體目錄結構、配置編譯及啓動流程。

        一、整體目錄:大體可以分爲以下四類

        1. 平臺相關或開發板相關的:board、cpu、lib_arm等(lib_xxx)

        2. 通用的函數:include、lib_generic、common

        3. 通用的設備驅動程序:disk、drivers、dtt、fs、nand_spl、net、post、rtc

        4. 工具、示例程序及文檔:doc、examples、tools

       二、u-boot的配置編譯過程(紅色標記是關鍵部分)

       1. 頂層目錄下makefile的分析過程

VERSION = 1
PATCHLEVEL = 1
SUBLEVEL = 6
### 添加子版本信息
EXTRAVERSION =(2014-04-27)
U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
###版本信息輸出文件
VERSION_FILE = $(obj)include/version_autogenerated.h
### 定義主機系統架構
# uname -m => i686
# “sed –e”表示後面跟的是一串命令腳本,而表達式“s/abc/def/”表示要從標準輸入中,
#查找到內容爲“abc”的,然後替換成“def”。其中“abc”表達式可以使用“.”作爲通配符。 
#命令“uname –m”將輸出主機CPU的體系架構類型。作者的電腦使用Intel Core2系列的CPU,
#因此“uname –m”輸出“i686”。 “i686”可以匹配命令“sed -e s/i.86/i386/”中的“i.86”,
#因此在作者的機器上執行Makefile,HOSTARCH將被設置成“i386” 。
HOSTARCH := $(shell uname -m | \
sed -e s/i.86/i386/ \
   -e s/sun4u/sparc64/ \
   -e s/arm.*/arm/ \
   -e s/sa110/arm/ \
   -e s/powerpc/ppc/ \
   -e s/macppc/ppc/)
### 定義主機操作系統類型
# uname -s => Linux 
# uname -s | tr '[:upper:]' '[:lower:]'  =>  linux
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
   sed -e 's/\(cygwin\).*/cygwin/')
###輸出變量
export HOSTARCH HOSTOS

###設定編譯輸出目錄 
#$(origin O) => undefine
#函數$( origin, variable) 輸出的結果是一個字符串,輸出結果由變量variable定義的方式決定,
#若variable在命令行中定義過,則origin函數返回值爲"command line"。假若在命令行中執行了
#“export BUILD_DIR=/tmp/build”的命令,則“$(origin O)”值爲“command line”,而BUILD_DIR被設置爲“/tmp/build”。
ifdef O
ifeq ("$(origin O)", "command line")
BUILD_DIR := $(O)
endif
endif
#若${BUILD_DIR}表示的目錄沒有定義,則創建該目錄。
#$(BUILD_DIR) $(saved-output) => 空
ifneq ($(BUILD_DIR),)
saved-output := $(BUILD_DIR)
# Attempt to create a output directory.
$(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})
# Verify if it was successful.
BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd)
#若$(BUILD_DIR)爲空,則將其賦值爲當前目錄路徑(源代碼目錄)。並檢查$(BUILD_DIR)目錄是否存在。
$(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist))
endif # ifneq ($(BUILD_DIR),)
###CURDIR變量指示Make當前的工作目錄,由於當前Make在U-Boot頂層目錄執行Makefile,
#因此CURDIR此時就是U-Boot頂層目錄。執行完上面的代碼後,SRCTREE,src變量就是
#U-Boot代碼頂層目錄,而OBJTREE,obj變量就是輸出目錄,若沒有定義BUILD_DIR環境變量,
#則SRCTREE,src變量與OBJTREE,obj變量都是U-Boot源代碼目錄。而MKCONFIG則表示U-Boot根目錄下的mkconfig腳本。 
#CURDIR => 頂層目錄
#SRCTREE => 頂層目錄
#LNDIR OBJTREE => 輸出目錄即頂層目錄
### OBJTREE和LNDIR爲存放生成文件的目錄,TOPDIR與SRCTREE爲源碼所在目錄
OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))
SRCTREE := $(CURDIR)
TOPDIR := $(SRCTREE)
LNDIR := $(OBJTREE)
export TOPDIR SRCTREE OBJTREE

### 頂層目錄下的配置文件
MKCONFIG := $(SRCTREE)/mkconfig
export MKCONFIG

### 本地編譯不會執行這幾行代碼
ifneq ($(OBJTREE),$(SRCTREE))
REMOTE_BUILD := 1
export REMOTE_BUILD
endif
# $(obj) and (src) are defined in config.mk but here in main Makefile
# we also need them before config.mk is included which is the case for
# some targets like unconfig, clean, clobber, distclean, etc.
ifneq ($(OBJTREE),$(SRCTREE))
obj := $(OBJTREE)/
src := $(SRCTREE)/
else
obj :=
src :=
endif
export obj src
#########################################################################
ifeq ($(OBJTREE)/include/config.mk,$(wildcard $(OBJTREE)/include/config.mk))
# load ARCH, BOARD, and CPU configuration
include $(OBJTREE)/include/config.mk
export ARCH CPU BOARD VENDOR SOC

.......

#確定編譯工具

ifeq ($(ARCH),arm)
CROSS_COMPILE = arm-linux-
endif

#確定鏈接選項指定鏈接文件

# load other configuration
include $(TOPDIR)/config.mk

{

###注:此處是$(TOPDIR)/config.mk下比較重要的內容

.......

ifdef VENDOR
BOARDDIR = $(VENDOR)/$(BOARD)
else
BOARDDIR = $(BOARD)
endif

......

ifeq ($(CONFIG_NAND_U_BOOT),y)
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-nand.lds
else
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds
endif

......

LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)

}

#uboot編譯連接的第一個文件

OBJS  = cpu/$(CPU)/start.o

.......

#uboot編譯過程中會編譯的庫文件

LIBS  = lib_generic/libgeneric.a
LIBS += board/$(BOARDDIR)/lib$(BOARD).a
LIBS += cpu/$(CPU)/lib$(CPU).a
ifdef SOC
LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a
endif
LIBS += lib_$(ARCH)/lib$(ARCH).a
LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \
fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a
LIBS += net/libnet.a
LIBS += disk/libdisk.a
LIBS += rtc/librtc.a
LIBS += dtt/libdtt.a
LIBS += drivers/libdrivers.a
LIBS += drivers/nand/libnand.a
LIBS += drivers/nand_legacy/libnand_legacy.a
LIBS += drivers/sk98lin/libsk98lin.a
LIBS += post/libpost.a post/cpu/libcpu.a
LIBS += common/libcommon.a
LIBS += $(BOARDLIBS)
LIBS := $(addprefix $(obj),$(LIBS))
.PHONY : $(LIBS)

#make時編譯執行的目錄

ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)
all: $(ALL)
$(obj)u-boot.hex: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@
$(obj)u-boot.srec: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@
$(obj)u-boot.bin: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
$(obj)u-boot.img: $(obj)u-boot.bin
./tools/mkimage -A $(ARCH) -T firmware -C none \
-a $(TEXT_BASE) -e 0 \
-n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \
sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \
-d $< $@
$(obj)u-boot.dis: $(obj)u-boot
$(OBJDUMP) -d $< > $@
$(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)
UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed  -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \
--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
-Map u-boot.map -o u-boot

#調用相應子目錄下的makefile
$(OBJS):
$(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))
$(LIBS):
$(MAKE) -C $(dir $(subst $(obj),,$@))
$(SUBDIRS):
$(MAKE) -C $@ all

#make MY_JZ2440_config首先要執行的命令:用於刪除上一次的配置信息

#########################################################################
unconfig:
@rm -f $(obj)include/config.h $(obj)include/config.mk \
$(obj)board/*/config.tmp $(obj)board/*/*/config.tmp

#make MY_JZ2440_config時執行的操作

#重點是:@$(MKCONFIG) $(@:_config=) arm arm920t MY_JZ2440 sumsung s3c24x0 

#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#  add by lhbo
#  MY_JZ2440_config
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MY_JZ2440_config : unconfig
##  step0:unconfig是用於清楚上一次的config信息等
##  step1:輸出一些基本信息
@echo "=============================================="
@echo "=================made by lhbo================="
@echo "=============================================="
@echo "UBOOT Version : $(U_BOOT_VERSION)" 
@echo "HOST ARCH     : $(HOSTARCH)"
@echo "HOST OS       : $(HOSTOS)"
@echo "BUILD_DIR     : $(BUILD_DIR)"
@echo "obj           : $(obj)"
@echo "TOPDIR        : $(TOPDIR)"
@echo "SRCTREE       : $(SRCTREE)"
@echo "OBJTREE       : $(OBJTREE)"
@echo "MKCONFIG      : $(MKCONFIG)"
@echo "=============================================="
##  step2:調用執行配置腳本
##  target ARCH CPU BOARD VENDOR SOC
@$(MKCONFIG) $(@:_config=) arm arm920t MY_JZ2440 sumsung s3c24x0 

        注:2. 頂層目錄下mkconfig的分析過程 和 三、u-boot啓動流程 內容請見博文“U-Boot移植之前期分析(下)”

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章