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移植之前期分析(下)”