在此不废话,相信大家都已经了解。
在此要说明的是,其源代码目录下的README对需要了解U-Boot及其移植方法的人有很大帮助。其中有说U-Boot的目录结构如下:
Directory Hierarchy:====================
/arch Architecture specific files
/arm Files generic to ARM architecture
/cpu CPU specific files
/arm720t Files specific to ARM 720 CPUs
/arm920t Files specific to ARM 920 CPUs
/at91 Files specific to Atmel AT91RM9200 CPU
/imx Files specific to Freescale MC9328 i.MX CPUs
/s3c24x0 Files specific to Samsung S3C24X0 CPUs
/arm925t Files specific to ARM 925 CPUs
/arm926ejs Files specific to ARM 926 CPUs
/arm1136 Files specific to ARM 1136 CPUs
/ixp Files specific to Intel XScale IXP CPUs
/pxa Files specific to Intel XScale PXA CPUs
/s3c44b0 Files specific to Samsung S3C44B0 CPUs
/sa1100 Files specific to Intel StrongARM SA1100 CPUs
/lib Architecture specific library files
/avr32 Files generic to AVR32 architecture
/cpu CPU specific files
/lib Architecture specific library files
/blackfin Files generic to Analog Devices Blackfin architecture
/cpu CPU specific files
/lib Architecture specific library files
/x86 Files generic to x86 architecture
/cpu CPU specific files
/lib Architecture specific library files
/m68k Files generic to m68k architecture
/cpu CPU specific files
/mcf52x2 Files specific to Freescale ColdFire MCF52x2 CPUs
/mcf5227x Files specific to Freescale ColdFire MCF5227x CPUs
/mcf532x Files specific to Freescale ColdFire MCF5329 CPUs
/mcf5445x Files specific to Freescale ColdFire MCF5445x CPUs
/mcf547x_8x Files specific to Freescale ColdFire MCF547x_8x CPUs
/lib Architecture specific library files
/microblaze Files generic to microblaze architecture
/cpu CPU specific files
/lib Architecture specific library files
/mips Files generic to MIPS architecture
/cpu CPU specific files
/mips32 Files specific to MIPS32 CPUs
/xburst Files specific to Ingenic XBurst CPUs
/lib Architecture specific library files
/nds32 Files generic to NDS32 architecture
/cpu CPU specific files
/n1213 Files specific to Andes Technology N1213 CPUs
/lib Architecture specific library files
/nios2 Files generic to Altera NIOS2 architecture
/cpu CPU specific files
/lib Architecture specific library files
/powerpc Files generic to PowerPC architecture
/cpu CPU specific files
/74xx_7xx Files specific to Freescale MPC74xx and 7xx CPUs
/mpc5xx Files specific to Freescale MPC5xx CPUs
/mpc5xxx Files specific to Freescale MPC5xxx CPUs
/mpc8xx Files specific to Freescale MPC8xx CPUs
/mpc8220 Files specific to Freescale MPC8220 CPUs
/mpc824x Files specific to Freescale MPC824x CPUs
/mpc8260 Files specific to Freescale MPC8260 CPUs
/mpc85xx Files specific to Freescale MPC85xx CPUs
/ppc4xx Files specific to AMCC PowerPC 4xx CPUs
/lib Architecture specific library files
/sh Files generic to SH architecture
/cpu CPU specific files
/sh2 Files specific to sh2 CPUs
/sh3 Files specific to sh3 CPUs
/sh4 Files specific to sh4 CPUs
/lib Architecture specific library files
/sparc Files generic to SPARC architecture
/cpu CPU specific files
/leon2 Files specific to Gaisler LEON2 SPARC CPU
/leon3 Files specific to Gaisler LEON3 SPARC CPU
/lib Architecture specific library files
/api Machine/arch independent API for external apps
/board Board dependent files
/common Misc architecture independent functions
/disk Code for disk drive partition handling
/doc Documentation (don't expect too much)
/drivers Commonly used device drivers
/examples Example code for standalone applications, etc.
/fs Filesystem code (cramfs, ext2, jffs2, etc.)
/include Header Files
/lib Files generic to all architectures
/libfdt Library files to support flattened device trees
/lzma Library files to support LZMA decompression
/lzo Library files to support LZO decompression
/net Networking code
/post Power On Self Test
/rtc Real Time Clock drivers
/tools Tools to build S-Record or U-Boot images, etc.
而其中的配置也分为两种,并详细介绍了各配置项:
There are two classes of configuration variables:
Configuration OPTIONS: These are selectable by the user and have names beginning with "CONFIG_".
Configuration SETTINGS: These depend on the hardware etc. and should not be meddled with if you don't know what you're doing; they have names beginning with "CONFIG_SYS_".
另外对U-boot的编译、移植方法及生成的映像的格式也作了介绍。
mkconfig详解
于是我们来到了mkconfig,shell脚本,哈哈,没什么好怕的了。
首先是在board.cfg中寻找你传进来的NAME的配置行,board.cfg的格式类似如下: smdk2410 arm arm920t - samsung s3c24x
第一个是配置文件名称,第二个是体系结构,第三个是cpu,第四个是board名称,若-,则board名称为去掉配置文件名_config后的部分。第五个是厂商vendor,第六个是soc的名称。如果有第七个参数则指定了选项,这里不做详细介绍。
得到这些参数之后干什么了呢?
仍以smdk2410为例,将arch目录下的inlcude/asm链接到include/asm:
cd ./include
rm -f asm
ln -s ../arch/${arch}/include/asm asm
将链接过来的asm目录里的arch目录删除,然后根据soc更新:
if [ -z "${soc}" ] ; then
ln -s ${LNPREFIX}arch-${cpu} asm/arch
else
ln -s ${LNPREFIX}arch-${soc} asm/arch
如果是arm体系,还要更新asm目录下的proc目录:
if [ "${arch}" = "arm" ] ; then
rm -f asm/proc
ln -s ${LNPREFIX}proc-armv asm/proc
fi
接着创建了include/config.mk文件,config.mk文件在后边编译时会被Makefile包含,并写入以下内容:
echo "ARCH = ${arch}" > config.mk
echo "CPU = ${cpu}" >> config.mk
echo "BOARD = ${board}" >> config.mk
[ "${vendor}" ] && echo "VENDOR = ${vendor}" >> config.mk
[ "${soc}" ] && echo "SOC = ${soc}" >> config.mk
在此vendor指没指定有一个很重要的区别,其board目录可能是vendor/board或者board:
if [ -z "${vendor}" ] ; then
BOARDDIR=${board}
else
BOARDDIR=${vendor}/${board}
fi
接下来生成include/config.h:
for i in ${TARGETS} ; do
i="`echo ${i} | sed '/=/ {s/=/ /;q; } ; { s/$/ 1/; }'`"
echo "#define CONFIG_${i}" >>config.h ;
done
echo "#define CONFIG_SYS_ARCH \"${arch}\"" >> config.h
echo "#define CONFIG_SYS_CPU \"${cpu}\"" >> config.h
echo "#define CONFIG_SYS_BOARD \"${board}\"" >> config.h
[ "${vendor}" ] && echo "#define CONFIG_SYS_VENDOR \"${vendor}\"" >> config.h
[ "${soc}" ] && echo "#define CONFIG_SYS_SOC \"${soc}\"" >> config.h
cat << EOF >> config.h
#define CONFIG_BOARDDIR board/$BOARDDIR
#include
#include
#include
#include
#include
EOF
config.h包含了arch,cpu,board,vendor,soc,board_dir这些宏定义。
关于一开始的TARGETS循环,在boards.cfg中的选项字段即会转化为此处的宏定义,一可以使用-t传递参数给mkconfig。
至此,配置工作基本完成了,生成了include目录下的config.mk和config.h两个文件。
Makefile 二探
a.根据顶层README的介绍,编译U-Boot的第二个阶段就是
make all
于是再次打开Makefile
all: $(ALL-y) $(SUBDIR_EXAMPLES)
$(obj)u-boot.srec: $(obj)u-boot
$(OBJCOPY) -O srec $< $@
$(obj)u-boot.bin: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
$(BOARD_SIZE_CHECK)
$(SUBDIR_EXAMPLES): $(obj)u-boot
ALL-y += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map
由此可见,编译的话首先是编译生成u-boot,然后objcopy出另外的两个镜像类型的文件。关键是u-boot的生成:
$(obj)u-boot: depend \
$(SUBDIR_TOOLS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) $(obj)u-boot.lds
$(GEN_UBOOT)
b.$(SUBDIR_TOOLS)
SUBDIR_TOOLS = tools
SUBDIRS = $(SUBDIR_TOOLS)
$(SUBDIRS): depend
$(MAKE) -C $@ all
因此SUBDIR_TOOLS是进入tools目录执行make命令(make -C tools)生成的。此目录的主要作用,就是会生成一系列的工具:
BIN_FILES-$(CONFIG_LCD_LOGO) += bmp_logo$(SFX)
BIN_FILES-$(CONFIG_VIDEO_LOGO) += bmp_logo$(SFX)
BIN_FILES-$(CONFIG_BUILD_ENVCRC) += envcrc$(SFX)
BIN_FILES-$(CONFIG_CMD_NET) += gen_eth_addr$(SFX)
BIN_FILES-$(CONFIG_CMD_LOADS) += img2srec$(SFX)
BIN_FILES-$(CONFIG_XWAY_SWAP_BYTES) += xway-swap-bytes$(SFX)
BIN_FILES-y += mkenvimage$(SFX)
BIN_FILES-y += mkimage$(SFX)
BIN_FILES-$(CONFIG_SMDK5250) += mksmdk5250spl$(SFX)
BIN_FILES-$(CONFIG_MX28) += mxsboot$(SFX)
BIN_FILES-$(CONFIG_NETCONSOLE) += ncb$(SFX)
BIN_FILES-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1$(SFX)
BIN_FILES-$(CONFIG_KIRKWOOD) += kwboot$(SFX)
当然,最重要的是mkimage,还有bmp_logo等等,此处不详解了。
c.$(OBJS)
OBJS = $(CPUDIR)/start.o
ifeq ($(CPU),x86)
OBJS += $(CPUDIR)/start16.o
OBJS += $(CPUDIR)/resetvec.o
endif
ifeq ($(CPU),ppc4xx)
OBJS += $(CPUDIR)/resetvec.o
endif
ifeq ($(CPU),mpc85xx)
OBJS += $(CPUDIR)/resetvec.o
endif
OBJS := $(addprefix $(obj),$(OBJS))
$(OBJS): depend
$(MAKE) -C $(CPUDIR) $(if $(REMOTE_BUILD),$@,$(notdir $@))
由此可见,OBJS最最重要的就是进入CPUDIR编译出start.o了。
那么,CPUDIR是怎么定义的呢,顶层的Makefile中有:
include $(obj)include/config.mk
export ARCH CPU BOARD VENDOR SOC
include $(TOPDIR)/config.mk
include/config.mk根据之前的解析是在make NAME_config时生成了,里面定义了ARCH,CPU,BOARD,VENDOR,SOC等这几个变量。
根据顶层目录下config之定义:
CPUDIR=arch/$(ARCH)/cpu/$(CPU)
ifneq ($(SRCTREE)/$(CPUDIR),$(wildcard $(SRCTREE)/$(CPUDIR)))
CPUDIR=arch/$(ARCH)/cpu
endif
由此就进入了正确的某个CPU的目录并编译了正确start.o启动代码。
d.$(LIBBOARD)
LIBBOARD = board/$(BOARDDIR)/lib$(BOARD).o
LIBBOARD := $(addprefix $(obj),$(LIBBOARD))
$(LIBBOARD): depend $(LIBS)
$(MAKE) -C $(dir $(subst $(obj),,$@))
同理,顶层目录的config.mk对BOARDDIR的定义如下:
ifdef VENDOR
BOARDDIR = $(VENDOR)/$(BOARD)
else
BOARDDIR = $(BOARD)
endif
因此就是进入开发板的目录编译并链接,仍以smdk2410为例:
include $(TOPDIR)/config.mk
LIB = $(obj)lib$(BOARD).o
COBJS := smdk2410.o
SOBJS := lowlevel_init.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS))
SOBJS := $(addprefix $(obj),$(SOBJS))
$(LIB): $(obj).depend $(OBJS) $(SOBJS)
$(call cmd_link_o_target, $(OBJS) $(SOBJS))
$(obj)lib$(BOARD).o依赖于smdk2410.o和lowlevel_init.o,编译吧,然后cmd_link_o_target进行链接。
cmd_link_o_target = $(if $(strip $1),\
$(LD) $(LDFLAGS) -r -o $@ $1,\
rm -f $@; $(AR) rcs $@ )
e.$(LIBS)
呃,这个是最麻烦的啦,哎。
LIBS = lib/libgeneric.o
LIBS += lib/lzma/liblzma.o
LIBS += lib/lzo/liblzo.o
LIBS += lib/zlib/libz.o
......
LIBS += $(CPUDIR)/lib$(CPU).o
ifdef SOC
LIBS += $(CPUDIR)/$(SOC)/lib$(SOC).o
endif
......
LIBS += arch/$(ARCH)/lib/lib$(ARCH).o
LIBS += fs/cramfs/libcramfs.o fs/fat/libfat.o fs/fdos/libfdos.o fs/jffs2/libjffs2.o \
fs/reiserfs/libreiserfs.o fs/ext2/libext2fs.o fs/yaffs2/libyaffs2.o \
fs/ubifs/libubifs.o
LIBS += net/libnet.o
LIBS += disk/libdisk.o
LIBS += drivers/bios_emulator/libatibiosemu.o
LIBS += drivers/block/libblock.o
......(省略N多驱动)
LIBS += common/libcommon.o
LIBS += lib/libfdt/libfdt.o
LIBS += api/libapi.o
LIBS += post/libpost.o
......
ifeq ($(SOC),s5pc1xx)
LIBS += $(CPUDIR)/s5p-common/libs5p-common.o
endif
ifeq ($(SOC),exynos)
LIBS += $(CPUDIR)/s5p-common/libs5p-common.o
endif
$(LIBS): depend $(SUBDIR_TOOLS)
$(MAKE) -C $(dir $(subst $(obj),,$@))
虽然繁琐,但不复杂,就是编译N多个lib,分别进入其源目录执行make -C。
需要指出的是,LIBS += $(CPUDIR)/$(SOC)/lib$(SOC).o,即CPU目录的子目录是作为lib在此编译的,在编译start.o时并没有编译。
这样大部分的编译工作就完成了,CPU的初始化,板子的初始化,再到包含很多驱动的LIBS。
接下来就该链接了吧。
f. $(LDSCRIPT)
# If there is no specified link script, we look in a number of places for it
ifndef LDSCRIPT
ifeq ($(CONFIG_NAND_U_BOOT),y)
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-nand.lds
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot-nand.lds
endif
endif
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds
endif
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot.lds
endif
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(TOPDIR)/arch/$(ARCH)/cpu/u-boot.lds
# We don't expect a Makefile here
LDSCRIPT_MAKEFILE_DIR =
endif
ifeq ($(wildcard $(LDSCRIPT)),)
$(error could not find linker script)
endif
endif
$(LDSCRIPT): depend
$(MAKE) -C $(dir $@) $(notdir $@)
首先在N多个地方寻找链接脚本,找到之后,进入其目录执行make -Cg.$(obj)u-boot.lds
执行了一条命令:
$(obj)u-boot.lds: $(LDSCRIPT)
$(CPP) $(CPPFLAGS) $(LDPPFLAGS) -ansi -D__ASSEMBLY__ -P - <$^ >$@
将LDSCRIPT预处理下,然后生成$(obj)u-boot.ldsi.$(GEN_UBOOT)
这个简单,是结束,也是开始吧,仅仅一个命令。
ifeq ($(CONFIG_SANDBOX),y)
GEN_UBOOT = \
cd $(LNDIR) && $(CC) $(SYMS) -T $(obj)u-boot.lds \
-Wl,--start-group $(__LIBS) -Wl,--end-group \
$(PLATFORM_LIBS) -Wl,-Map -Wl,u-boot.map -o u-boot
else
GEN_UBOOT = \
UNDEF_SYM=`$(OBJDUMP) -x $(LIBBOARD) $(LIBS) | \
sed -n -e 's/.*\($(SYM_PREFIX)__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
cd $(LNDIR) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) $$UNDEF_SYM $(__OBJS) \
--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
-Map u-boot.map -o u-boot
endif
因为编译已经完成,剩下的只是把编译出来的文件链接成u-boot。
至此,U-Boot就编译完了。 呵呵,看起来总是比写起来简单,咱看人家写好的编译配置都这么麻烦,想来足见此工程之艰巨。 不管怎么说,还是让咱给大概看懂了。接下来就该是代码的事了吧,阅读代码,然后移植。。。