1.此文章不仅对uboot进行配置,编译,移植,而且对其配置,编译,移植过程进行分析,理解其原理。
2.uboot是通用的启动代码,我们编译移植最好找到和自己的开发板最相近的版本,比如厂商已经匹配的uboot,uboot分类:官方版,SoC厂商,开发板厂商。
3.我们可以根据自己入手的开发板做一次移植,再根据官方给出的uboot做一次移植,从而很好的学习此方面的知识。
uboot文章连载:
1.uboot命令集&环境变量
2.uboot配置,编译,移植
3.uboot启动过程
4.uboot命令体系
5.uboot的环境变量
6.uboot的驱动
7.uboot启动Linux内核
Linux文章连载
uboot下主要的文件夹和文件如下,接下来会介绍主要的配置编译文件,可以对其配置过程有完整的认识:
├── board
│ └── samsung
│ ├── common
│ └── x210
├── common //env、command、控制台、crc校验等和硬件无关的代码。
├── config.mk
├── cpu //SoC相关初始化和控制代码(CPU、中断、串口等SoC内部外设,start.S)。
│ └── s5pc11x
│ └── s6pc110
├── disk
├── doc
│ └── uImage.FIT //fit镜像树
├── drivers //从Linux来的一部分驱动,是uboot阶段需要使用的硬件,比如网卡驱动、Inand/SD卡、NandFlash等的驱动。
│ ├── bios_emulator
│ │ ├── include
│ │ │ └── x86emu
│ │ └── x86emu
│ ├── block
│ ├── dma
│ ......
│
├── fs //文件系统,从linux移植
│ ├── cramfs
│ ├── ext2
│ └── fat
├── include //头文件
│ ├── asm-arm
│ │ ├── arch-s5pc11x
│ │ └── proc-armv
│ └── linux
│ ├── byteorder
│ ├── mmc
│ └── mtd
├── lib_arm
├── libfdt //设备树相关(启动传参,(3.4后的版本Linux改用设备树启动传参))
├── lib_generic
├── Makefile
├── mkconfig
├── net
├── post //power on self test
├── rules.mk
├── sd_fusing //烧录uboot镜像到SD卡的代码(此代码在Linux中运行,其编译采用gcc,而不是arm-linux-gcc)
└── tools
├── bddb
├── easylogo
├── env
├── gdb
├── logos
├── scripts
└── updater
uboot的源代码文件中的README文件主要讲述了:
配置取决于主板和CPU类型的组合,include/configs/xxx.h是所有有关硬件和CPU的配置项。
其中编译过程需要指定交叉编译工具链,uboot建议不要修改Makefile,而是通过添加环境变量或者写一个脚本来覆盖CROSS_COMPILE环境变量:
CROSS_COMPILE=ppc_4xx-
export CROSS_COMPILE
uboot编译后生成的文件默认放在源文件目录下,指定目录可以使用:
make O=/tmp/build distclean
make O=/tmp/build NAME_config
make O=/tmp/build all
或者将BUILD_DIR导出到环境变量:
export BUILD_DIR=/tmp/build
make distclean
make NAME_config
make all
注意:命令行“O=”设置会覆盖BUILD_DIR环境变量。
如果我们的开发板在uboot中没有,可以自己配置,关于修改建议README也给出了:
1.使用现有条目作为示例,为顶层“Makefile”和“MAKEALL”脚本添加一个新的板配置选项。
2.创建一个新的目录来保存特定于电路板的代码。添加任何需要的文件。在电路板目录中,至少需要“Makefile”、一个“
3.为您的开发板创建一个新的配置文件“include/configs/<\board>.h”
3.如果你要将U-Boot移植到一个新的CPU上,那么也要创建一个新的目录来保存你的CPU特定代码。添加任何需要的文件。
4.用你的新名字运行“make
5.输入“make”,你应该会在目标系统上安装一个工作的“u-boot.srec”文件。
6.调试并解决可能出现的任何问题。
uboot支持两种镜像格式:
FIT:
基于扁平化镜像树格式–FIT(类似于扁平化设备树FDT)。它允许使用包含多个组件(多个内核、ramdisk等)的镜像。更多详细信息请参见doc/uImage.FIT目录。
旧的uImage格式:
旧的镜像格式基于二进制文件,基本上可以是任何文件,前面有一个特殊的头;请参见include/image.h,uImage的头部定义了以下镜像属性:
头部由一个特殊的魔数标记,并且头部和镜像的数据部分都通过CRC32校验和来防止损坏。
此文件夹功能:将uboot.bin文件分成BL1,BL2。使用脚本将BL1和BL2烧录到SD卡中
步骤:
1:进入sd_fusing目录下
sd_fusing.sh需要改一下,其中的uboot_inand.bin改成u-boot.bin
2:make new
3:插入sd卡,进入sd_fusing目录下 执行 ./sd_fusing.sh /dev/sdb(sdb是sd卡的名字,ls /dev/sd*查看),烧录成功。
把他简化一下,将其做的主要工作整理出来,注释详细解释了其用途:
#1.
VERSION = 1
PATCHLEVEL = 3
SUBLEVEL = 4
EXTRAVERSION =
U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
VERSION_FILE = $(obj)include/version_autogenerated.h #此文件是自动生成的,内容为#define U_BOOT_VERSION "U-Boot 1.3.4",其内容来自以上变量,其在主makefile的all中生成
#2.
MKCONFIG := $(SRCTREE)/mkconfig
export MKCONFIG
#3.
include $(obj)include/config.mk #不是源码自带的,要在配置过程(make x210_sd_config)中才会生成这个文件
export ARCH CPU BOARD VENDOR SOC #变量在以上这个文件中定义,从上面这个文件中取出,导出这五个变量作为哦环境变量
#4.
ifeq ($(ARCH),arm)
CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi- #编译工具链名字前缀,包含路径(这个设置值只要能保证找到那个交叉编译工具链即可,不一定非得是全路径的,相对路径也可以。(如果已经将工具链导出到环境变量,并且设置了符号链接,这样CROSS_COMPILE = arm-linux-就可以))
export CROSS_COMPILE
endif
#5.
include $(TOPDIR)/config.mk #包含根目录下的config.mk。(TOPDIR在主Makefile中定义,若在根目录下编译,那么TOPDIR为根目录)
#6.
OBJS = cpu/$(CPU)/start.o #添加待编译文件
OBJS := $(addprefix $(obj),$(OBJS)) #addprefix是makefile自带函数,为变量添加前缀,我们的obj在自己的总目录下编译时就为./,所以在这里OBJS还是=它本身
#7.
LIBS = lib_generic/libgeneric.a #添加库,将所有需要的库都包含进来,我只将ARM架构需要的库添加进来了,若是其他架构则不一样
#LIBS += $(shell if [ -f board/$(VENDOR)/common/Makefile ]; then echo "board/$(VENDOR)/common/lib$(VENDOR).a"; fi) #我们目录下没有此文件,所以我将其注释掉了
LIBS += cpu/$(CPU)/lib$(CPU).a #我是cpu/s5pc11x/libs5pc11x.a
ifdef SOC
LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a #cpu/s5pc11x/s5pc110/libs5pc110.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 += drivers/bios_emulator/libatibiosemu.a
LIBS += drivers/block/libblock.a
LIBS += drivers/dma/libdma.a
LIBS += drivers/hwmon/libhwmon.a
LIBS += drivers/i2c/libi2c.a
LIBS += drivers/input/libinput.a
LIBS += drivers/misc/libmisc.a
LIBS += drivers/mmc/libmmc.a
LIBS += drivers/mtd/libmtd.a
LIBS += drivers/mtd/nand/libnand.a
LIBS += drivers/mtd/nand_legacy/libnand_legacy.a
LIBS += drivers/mtd/onenand/libonenand.a
LIBS += drivers/mtd/ubi/libubi.a
LIBS += drivers/mtd/spi/libspi_flash.a
LIBS += drivers/net/libnet.a
LIBS += drivers/net/sk98lin/libsk98lin.a
LIBS += drivers/pci/libpci.a
LIBS += drivers/pcmcia/libpcmcia.a
LIBS += drivers/spi/libspi.a
LIBS += drivers/rtc/librtc.a
LIBS += drivers/serial/libserial.a
LIBS += drivers/usb/libusb.a
LIBS += drivers/video/libvideo.a
LIBS += common/libcommon.a
LIBS += libfdt/libfdt.a
LIBS += api/libapi.a
LIBS += post/libpost.a
LIBS := $(addprefix $(obj),$(LIBS))
.PHONY : $(LIBS) $(VERSION_FILE)
LIBBOARD = board/$(BOARDDIR)/lib$(BOARD).a
LIBBOARD := $(addprefix $(obj),$(LIBBOARD))
#8.
#add gcc lib
PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc #CC是gcc命令,CFLAGS是编译选项,不在此主makefile中,是和硬件平台相关的,猜测也应该在config.mk这个编译选项文件中,grep查找一下,果然在。
#关于参数-print-libgcc-file-name,可以参考文章:https://www.codes91.com/article/detail_4019385_2.html
#9.
# The "tools" are needed early, so put this first
SUBDIRS = tools \ #添加三个文件夹给变量SUBDIRS,后面要用,
examples \
api_examples
.PHONY : $(SUBDIRS)
#10.
ALL += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(obj)u-boot.dis #添加all的依赖
#11.
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 #生成.img文件
./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.sha1: $(obj)u-boot.bin
$(obj)tools/ubsha1 $(obj)u-boot.bin
$(obj)u-boot.dis: $(obj)u-boot #生成反汇编文件
$(OBJDUMP) -d $< > $@
$(obj)u-boot: depend $(SUBDIRS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) #生成u-boot可执行文件
UNDEF_SYM=`$(OBJDUMP) -x $(LIBBOARD) $(LIBS) | \
sed -n -e 's/.*\($(SYM_PREFIX)__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
$(OBJS): depend $(obj)include/autoconf.mk #生成start.o
$(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))
$(LIBS): depend $(obj)include/autoconf.mk #生成库文件
$(MAKE) -C $(dir $(subst $(obj),,$@))
$(LIBBOARD): depend $(LIBS) $(obj)include/autoconf.mk
$(MAKE) -C $(dir $(subst $(obj),,$@))
$(SUBDIRS): depend $(obj)include/autoconf.mk #编译SUBDIRS变量的三个文件夹中的内容
$(MAKE) -C $@ all
$(LDSCRIPT): depend $(obj)include/autoconf.mk
$(MAKE) -C $(dir $@) $(notdir $@)
$(VERSION_FILE): #生成version_autogenerated.h
@( printf '#define U_BOOT_VERSION "U-Boot %s%s"\n' "$(U_BOOT_VERSION)" \
'$(shell $(CONFIG_SHELL) $(TOPDIR)/tools/setlocalversion $(TOPDIR))' \
) > $@.tmp
@cmp -s $@ $@.tmp && rm -f $@.tmp || mv -f $@.tmp $@
#12. #生成tools下包含的工具:gdb、updater、env
gdbtools:
$(MAKE) -C tools/gdb all || exit 1
updater:
$(MAKE) -C tools/updater all || exit 1
env:
$(MAKE) -C tools/env all MTD_VERSION=${MTD_VERSION} || exit 1
#13. #遍历SUBDIRS,编译/tools /examples /api_examples三个目录
depend dep: $(VERSION_FILE)
for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir _depend ; done
###############################################################################################
#14. #tag相关的内容
TAG_SUBDIRS += include
....
#一大部分代码和ctags,etags,cscope相关,这些是用来浏览c代码的,不学习,这个时间还不如用来看uboot源码
###############################################################################################
#15. #生成System.map文件
$(obj)System.map: $(obj)u-boot
@$(NM) $< | \
grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | \
sort > $(obj)System.map
#16.
$(obj)include/autoconf.mk.dep: $(obj)include/config.h include/common.h
@$(XECHO) Generating $@ ; \
set -e ; \
: Generate the dependancies ; \
$(CC) -x c -DDO_DEPS_ONLY -M $(HOST_CFLAGS) $(CPPFLAGS) \
-MQ $(obj)include/autoconf.mk include/common.h > $@
$(obj)include/autoconf.mk: $(obj)include/config.h
@$(XECHO) Generating $@ ; \
set -e ; \
: Extract the config macros ; \
$(CPP) $(CFLAGS) -DDO_DEPS_ONLY -dM include/common.h | \
sed -n -f tools/scripts/define2mk.sed > $@
sinclude $(obj)include/autoconf.mk.dep
#17.
#config的反向工程:
unconfig:
@rm -f $(obj)include/config.h $(obj)include/config.mk \
$(obj)board/*/config.tmp $(obj)board/*/*/config.tmp \
$(obj)include/autoconf.mk $(obj)include/autoconf.mk.dep \
$(obj)board/$(VENDOR)/$(BOARD)/config.mk
#######################以上makefile基本完成工作,以下只是某些配置项,uboot有成千上百个配置,适配不同的硬件,其他公司的配置略,我的配置项如下:###########################
#18.
#========================================================================
x210_nand_config : unconfig
@$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110
@echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk
x210_sd_config : unconfig
@$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110
@echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk
#========================================================================
#19.
clean: #清理文件,不细说
...
clobber:clean
...
distclean:clobber unconfig
...
#20.
backup: #生成tar包,注意自己有没有装tar工具,我这里没有装gtar,我用tar打包了
F=`basename $(TOPDIR)` ; cd .. ; \
#gtar --force-local -zcvf `date "+$$F-%Y-%m-%d-%T.tar.gz"` $$F
tar --force-local -zcvf `date "+$$F-%Y-%m-%d-%T.tar.gz"` $$F
上面的Makefile的细节:
1.version_autogenerated.h
是在make时生成的,在主Makefile中的all目标下,有生成此文件的语句,下文会分析
$(VERSION_FILE):
@( printf '#define U_BOOT_VERSION "U-Boot %s%s"\n' "$(U_BOOT_VERSION)" \
'$(shell $(CONFIG_SHELL) $(TOPDIR)/tools/setlocalversion $(TOPDIR))' \
) > $@.tmp
@cmp -s $@ $@.tmp && rm -f $@.tmp || mv -f $@.tmp $@
2.总的配置文件:
MKCONFIG := $(SRCTREE)/mkconfig
export MKCONFIG
3.include/config.mk
在配置过程中生成include/config.mk文件(注意不是根目录下的config.mk),其中包含着我们的板子的信息,此文件是在配置过程中自动生成的
ARCH = arm
CPU = s5pc11x
BOARD = x210
VENDOR = samsung
SOC = s5pc110
我们配置这五个变量供主Makefile使用,主Makefile会将此变量导出为环境变量(上面讲过),通过不同的板子配置生成不同内容的此文件,让主Makefile加载,那么就可以很方便的适配不同的板子。(我们是怎么自动生成这个文件的呢:mkconfig中生成,下文会讲)。
4.交叉编译工具链前缀环境变量设置
工程中我们还可以通过make CROSS_COMPILE=xxxx指定交叉编译工具链
5.总的编译文件
指导整个编译过程,include会在这里原地展开,config.mk相当于主Makefile的一个子文件,下面一节会详细分析
include $(TOPDIR)/config.mk
8.添加gcclib
PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc
首先看一下-print-libgcc-file-name选项,其作用是显示编译器配套库的名称(gcc help中有解释),我如下运行此选项,发现得到gcc库的路径
root@ubuntu:/mnt/linuxshare/arm/uboot/out_dir_uboot# gcc -print-libgcc-file-name
/usr/lib/gcc/x86_64-linux-gnu/5/libgcc.a
root@ubuntu:/mnt/linuxshare/arm/uboot/out_dir_uboot# arm-linux-gcc -print-libgcc-file-name
/usr/local/arm/arm-2009q3/bin/../lib/gcc/arm-none-linux-gnueabi/4.4.1/libgcc.a
dirname 去除文件名,剩下纯路径,那么此变量就是:
-Lgcclib的路径 -lgcc
11.编译
(1)由可执行文件u-boot生成各种格式的文件:
$(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 $< $@
OBJCFLAGS += --gap-fill=0xff,由config.mk定义
(2)添加文件头
为了将bin下载到SD等存储器中,我们需要添加文件头,用来校验内容,和裸机我们碰到的mkv210_image.c的作用相似,其在tools文件夹中
$(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 $< $@
(3)生成反汇编文件
$(obj)u-boot.dis: $(obj)u-boot
$(OBJDUMP) -d $< > $@
(4)u-boot可执行文件和map文件
$(obj)u-boot: depend $(SUBDIRS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT)
UNDEF_SYM=`$(OBJDUMP) -x $(LIBBOARD) $(LIBS) | \
sed -n -e 's/.*\($(SYM_PREFIX)__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
主要是执行ld将.o文件和.a库文件链接成可执行文件u-boot,并且生成map文件u-boot.map,细节:
UNDEF_SYM变量部分代码简化成:
objdump -x libtest.a | sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq
objudmp -x libtest.a 可以得到 libtest.a 库中所有的 symbol, 包括函数,数组,文件等,这里我们简称为符号 .
然后将得到的符号通过"管道" 传递给sed 进行编辑。接下来对sed 进行分析:
sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'
sed -n -e 代表使用 silent 模式,以及直接在命令行进行编辑动作。
’ ’ 两个单引号之间表示将要进行的动作 。
标记成黑色的 s 代表会进行替换操作(‘s/要被取代的字串/新的字串/’).
p 代表打印出来。
因此上面的表达式的最浅显的意思是:
将 .*\(__u_boot_cmd_.*\)
替换为 -u\1
并且由于sed 支持正则表达式, 在正则表达式中括号()代表分组, 使用 \1 \2 \3 获取第一个分组,第二个分组, 第三个分组。因此上述表达式进一步被理解为:
将 .*__u_boot_cmd_.* 替换为 -u.*__u_boot_cmd_.*
在正则表达式中 . 代表任意字符(不包括空格),* 代表任意个, 因此我们将上述语句按照汉语翻译一遍:
使用 objdump -x 解析 libtest.a 得到一些符号,将这些符号使用sed 进行处理, 处理方式是: 找到符号中有__u_boot_cmd_字段的那一部分, 然后在这些字段前面加上-u。
接下来 |sort|uniq 就比较好理解了,就是进行排序和消除重复。
总结来说就是找到一些字段,在字段前面加上-u ,最后赋值给 UNDEF_SYM 这个变量。
-u是接下来ld需要用的选项:
-u symbol
–undefined=symbol
Force symbol to be entered in the output file as an undefined symbol. Doing this may, for example, trigger linking of additional modules from standard libraries. -u may be repeated with different option arguments
to enter additional undefined symbols. This option is equivalent to the “EXTERN” linker script command.
作用是插入未定义变量。这里就是u_boot_cmd 变量插入到可执行文件中,顾名思义和uboot的命令有关,将所有命令提取出来插入到可执行文件中。
(5)生成.o文件、lib文件,编译api、example等目录,具体的编译要看相应目录的makefile
$(OBJS): depend $(obj)include/autoconf.mk
$(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))
$(LIBS): depend $(obj)include/autoconf.mk
$(MAKE) -C $(dir $(subst $(obj),,$@))
$(LIBBOARD): depend $(LIBS) $(obj)include/autoconf.mk
$(MAKE) -C $(dir $(subst $(obj),,$@))
$(SUBDIRS): depend $(obj)include/autoconf.mk
$(MAKE) -C $@ all
$(LDSCRIPT): depend $(obj)include/autoconf.mk
$(MAKE) -C $(dir $@) $(notdir $@)
(6)使用tools/setlocalversion脚本生成version_autogenerated.h文件
$(VERSION_FILE):
@( printf '#define U_BOOT_VERSION "U-Boot %s%s"\n' "$(U_BOOT_VERSION)" \
'$(shell $(CONFIG_SHELL) $(TOPDIR)/tools/setlocalversion $(TOPDIR))' \
) > $@.tmp
@cmp -s $@ $@.tmp && rm -f $@.tmp || mv -f $@.tmp $@
其中CONFIG_SHELL 在config.mk文件中:
CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
else if [ -x /bin/bash ]; then echo /bin/bash; \
else echo sh; fi ; fi)
setlocalversion和git有关,设置本地的版本名字
15.System.map和uboot.map
生成System.map文件:
$(obj)System.map: $(obj)u-boot
@$(NM) $< | \
grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | \
sort > $(obj)System.map
之前生成u-boot可执行文件时生成过uboot.map文件:
ld -Map uboot.map
接下来讲讲这两个文件有什么作用:
节选一小段System.map,可以看到程序的起始地址_start为c3e00010 ,该文件按链接地址由小到大的顺序列出了所有符号(SDRAM初始化完成后,需要将U-Boot加载到此地址):
地址 类型 符号
c3e00010 T _start
c3e00030 t _undefined_instruction
c3e00034 t _software_interrupt
c3e00038 t _prefetch_abort
符号类型的解释,大写表示global,相应的小写表示是local。前面几个是经常使用到的:
A绝对地址,不会再被连接(重定向?)
B未初始化数据段,常以BSS表示
D数据段
T代码段
U未定义符号
R只读数据
…
uboot.map节选,包含链接过程中涉及的目标文件将其所依赖的库文件
Archive member included because of file (symbol)
cpu/s5pc11x/libs5pc11x.a(interrupts.o) cpu/s5pc11x/start.o (do_irq)
cpu/s5pc11x/libs5pc11x.a(cpu.o) cpu/s5pc11x/libs5pc11x.a(interrupts.o) (reset_cpu)
cpu/s5pc11x/libs5pc11x.a(setup_hsmmc.o) cpu/s5pc11x/libs5pc11x.a(cpu.o) (setup_hsmmc_cfg_gpio)
16.include/autoconf.mk
把include/common.h以及它所包含的头文件中的以“CONFIG_”为前缀的所有宏提取出来,按tools/scripts/define2mk.sed 宏处理规则来处理宏定义,并写入autoconf.mk文件,在make 命令编译源码的时候,包括autoconf.mk文件,形成源码或模块的编译规则,决定哪些模块编入镜像。
17.config配置以及config的反向操作
config:
运行脚本mkconfig,在config之前会unconfig一下,新建board/samsung/x210/config.mk,文件中指定TEXT_BASE = 0xc3e00000,TEXT_BASE是链接到SDRAM的地址,uboot开始执行的地址,我们看System.map的头地址就是来自这。
@:_config=就是将x210_nand_config替换成x210_nand,也就是mkconfig脚本传了x210_nand arm s5pc11x x210 samsung s5pc1106个参数
($@makefile中表示目标,_config=就是匹配目标中的子字符串,将字符串替换为=后面的字符串,我们这为空,所以就替换为空,也就是删除_config部分)
x210_nand_config : unconfig
@$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110
@echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk
x210_sd_config : unconfig
@$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110
@echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk
unconfig:
unconfig:
@rm -f $(obj)include/config.h $(obj)include/config.mk \
$(obj)board/*/config.tmp $(obj)board/*/*/config.tmp \
$(obj)include/autoconf.mk $(obj)include/autoconf.mk.dep \
$(obj)board/$(VENDOR)/$(BOARD)/config.mk
makefile配置,编译过程总结:先配置,后编译,绿色为配置时生成文件,红色为编译时生成文件。
配置时用到的脚本,我们看看其中做了什么事,拿x210_nand_config配置为例子,上文讲到给mkconfig传6个参数,其中第一个参数表明我们配置何种类型的uboot,我这里有两种选择,x210_nand和x210_sd。我简化了一下内容,比较简单,注释了一下主要的事情:
#!/bin/sh -e
APPEND=no # Default: Create new config file 是否存在文件的标志,如果为否,则新建文件,直接写即可不用担心覆盖内容。如果为是,则存在文件,那么不能将文件呢容覆盖,我们需要接续写,脚本接续写很简单,就是echo>>,从头写就是新建一个文件:echo>
BOARD_NAME="" # Name to print in make output
while [ $# -gt 0 ] ; do #$#表示参数个数,$# = 6,gt :--
case "$1" in #$1是x210_sd,在下面的case中没有,所以直接*)退出while循环。
--) shift ; break ;;
-a) shift ; APPEND=yes ;;
-n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;
*) break ;;
esac
done
[ "${BOARD_NAME}" ] || BOARD_NAME="$1" #BOARD_NAME=x210_sd
[ $# -lt 4 ] && exit 1 #4<=$#<=6
[ $# -gt 6 ] && exit 1
echo "Configuring for ${BOARD_NAME} board..."
#################################################################################
#创建符号链接,注意如果在Windows共享目录下,是看不到符号链接文件的,如果需要看到,则在在压缩时加上参数h:tar -cjvhf uboot.tar.bz2 uboot
#符号链接文件的存在就是整个配置过程的核心,这些符号链接文件(文件夹)的主要作用是给头文件包含等过程提供指向性连接。根本目的是让uboot具有可移植性。
cd ./include
rm -f asm
ln -s asm-$2 asm #指定为arm架构
rm -f asm-$2/arch
if [ -z "$6" -o "$6" = "NULL" ] ; then #-z是判断是否为空,-o表示或
ln -s ${LNPREFIX}arch-$3 asm-$2/arch
else
ln -s ${LNPREFIX}arch-$6 asm-$2/arch #创建arch链接,指定SOC为s5pc110
fi
# create link for s5pc11x SoC
if [ "$3" = "s5pc11x" ] ; then
rm -f regs.h
ln -s $6.h regs.h
rm -f asm-$2/arch
ln -s arch-$3 asm-$2/arch
fi
if [ "$2" = "arm" ] ; then
rm -f asm-$2/proc
ln -s ${LNPREFIX}proc-armv asm-$2/proc
fi
#################################################################################
# Create include file for Make
echo "ARCH = $2" > config.mk
echo "CPU = $3" >> config.mk
echo "BOARD = $4" >> config.mk
[ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk
[ "$6" ] && [ "$6" != "NULL" ] && echo "SOC = $6" >> config.mk
# Create board specific header file
if [ "$APPEND" = "yes" ] # Append to existing config file
then
echo >> config.h
else
> config.h # Create new config file
fi
echo "/* Automatically generated - do not edit */" >>config.h
echo "#include $1 .h>" >>config.h
exit 0
1.创建include/下的文件config.mk和config.h
2.六个参数的作用,总体就是为了实现uboot不同平台下的可移植性
3.config.h指向x210_nand.h,这个是我们x210开发板的主要配置文件
x210_sd.h文件会被用来生成一个autoconfig.mk文件,这个文件会被主Makefile引入,指导整个编译过程。这里面的这些宏定义会影响我们对uboot中大部分.c文件中一些条件编译的选择。从而实现最终的可移植性。
主要记录了一些命令的选项环境变量、include一些生成的文件、
# clean the slate ...
PLATFORM_RELFLAGS =
PLATFORM_CPPFLAGS =
PLATFORM_LDFLAGS =
#########################################################################
CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
else if [ -x /bin/bash ]; then echo /bin/bash; \
else echo sh; fi ; fi)
HOSTCC = gcc
HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer #没用
HOSTSTRIP = strip
#########################################################################
# Option checker (courtesy linux kernel) to ensure
# only supported compiler options are used
cc-option = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \
> /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
# Include the make variables (CC, etc...)
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
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
RANLIB = $(CROSS_COMPILE)RANLIB
# Load generated board configuration
sinclude $(OBJTREE)/include/autoconf.mk
ifdef ARCH
sinclude $(TOPDIR)/$(ARCH)_config.mk # include architecture dependend rules
endif
ifdef CPU
sinclude $(TOPDIR)/cpu/$(CPU)/config.mk # include CPU specific rules
endif
ifdef SOC
sinclude $(TOPDIR)/cpu/$(CPU)/$(SOC)/config.mk # include SoC specific rules
endif
ifdef VENDOR
BOARDDIR = $(VENDOR)/$(BOARD)
else
BOARDDIR = $(BOARD)
endif
ifdef BOARD
sinclude $(TOPDIR)/board/$(BOARDDIR)/config.mk # include board specific rules
endif
#########################################################################
ifneq (,$(findstring s,$(MAKEFLAGS))) #如果静默编译,那么ar也不需要带-v选项了,-v用来打印ar内容
ARFLAGS = cr
else
ARFLAGS = crv
endif
RELFLAGS= $(PLATFORM_RELFLAGS)
DBGFLAGS= -g # -DDEBUG
OPTFLAGS= -Os #-fomit-frame-pointer
ifndef LDSCRIPT
#LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds.debug
ifeq ($(CONFIG_NAND_U_BOOT),y)
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-nand.lds
else
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds
endif
endif
OBJCFLAGS += --gap-fill=0xff
gccincdir := $(shell $(CC) -print-file-name=include)
CPPFLAGS := $(DBGFLAGS) $(OPTFLAGS) $(RELFLAGS) \
-D__KERNEL__
ifneq ($(TEXT_BASE),)
CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE)
endif
ifneq ($(OBJTREE),$(SRCTREE))
CPPFLAGS += -I$(OBJTREE)/include2 -I$(OBJTREE)/include
endif
CPPFLAGS += -I$(TOPDIR)/include
CPPFLAGS += -fno-builtin -ffreestanding -nostdinc \
-isystem $(gccincdir) -pipe $(PLATFORM_CPPFLAGS)
ifdef BUILD_TAG
CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes \
-DBUILD_TAG='"$(BUILD_TAG)"'
else
CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes
endif
CFLAGS += $(call cc-option,-fno-stack-protector)
# $(CPPFLAGS) sets -g, which causes gcc to pass a suitable -g
# option to the assembler.
AFLAGS_DEBUG :=
AFLAGS := $(AFLAGS_DEBUG) -D__ASSEMBLY__ $(CPPFLAGS)
LDFLAGS += -Bstatic -T $(LDSCRIPT) $(PLATFORM_LDFLAGS)
ifneq ($(TEXT_BASE),)
LDFLAGS += -Ttext $(TEXT_BASE)
endif
# Location of a usable BFD library, where we define "usable" as
# "built for ${HOST}, supports ${TARGET}". Sensible values are
# - When cross-compiling: the root of the cross-environment
# - Linux/ppc (native): /usr
# - NetBSD/ppc (native): you lose ... (must extract these from the
# binutils build directory, plus the native and U-Boot include
# files don't like each other)
#
# So far, this is used only by tools/gdb/Makefile.
BFD_ROOT_DIR = /usr
#########################################################################
#有些变量又export了一遍,没什么用
export CONFIG_SHELL HPATH HOSTCC HOSTCFLAGS CROSS_COMPILE \
AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP \
MAKE
export TEXT_BASE PLATFORM_CPPFLAGS PLATFORM_RELFLAGS CPPFLAGS CFLAGS AFLAGS
#########################################################################
%.s: %.S
$(CPP) $(AFLAGS) -o $@ $<
%.o: %.S
$(CC) $(AFLAGS) -c -o $@ $<
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
这个要讲一下:
LDFLAGS += -Bstatic -T $(LDSCRIPT) $(PLATFORM_LDFLAGS)
ifneq ($(TEXT_BASE),)
LDFLAGS += -Ttext $(TEXT_BASE)
endif
ld命令的选项,-Ttext指定了,存在自动生成的文件board/samsung/x210/config.mk,LDSCRIPT指定了链接文件board/samsung/x210/u-boot.lds。
arm_config.mk
PLATFORM_CPPFLAGS += -DCONFIG_ARM -D__ARM__
cpu/s5pc11x/config.mk
PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 -msoft-float
# Make ARMv5 to allow more compilers to work, even though its v6.
PLATFORM_CPPFLAGS += -march=armv5te
# =========================================================================
# Supply options according to compiler version
# =========================================================================
PLATFORM_CPPFLAGS +=$(call cc-option,-mapcs-32,-mabi=apcs-gnu)
PLATFORM_CPPFLAGS +=$(call cc-option,-mno-thumb-interwork,)
PLATFORM_RELFLAGS +=$(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,))
uboot的链接脚本\board\samsung\x210\u-boot.lds
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
#声明一些代码段优先链接,这些代码必须放在前16k才能让整个代码生效:
. = ALIGN(4);
.text :
{
cpu/s5pc11x/start.o (.text)
cpu/s5pc11x/s5pc110/cpu_init.o (.text)
board/samsung/x210/lowlevel_init.o (.text)
cpu/s5pc11x/onenand_cp.o (.text)
cpu/s5pc11x/nand_cp.o (.text)
cpu/s5pc11x/movi.o (.text)
common/secure_boot.o (.text)
common/ace_sha1.o (.text)
cpu/s5pc11x/pmic.o (.text)
*(.text)
}
. = ALIGN(4);
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
.got : { *(.got) }
#命令相关的设置,需特别注意,由于现在没学习cmd相关源码,之后会西细讲这里的作用
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
#mmu相关
. = ALIGN(4);
.mmudata : { *(.mmudata) }
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) }
_end = .;
}
(1)ENTRY(_start)用来指定整个程序的入口地址。所谓入口地址就是整个程序的开头地址,可以认为就是整个程序的第一句指令。有点像C语言中的main。
(2)在代码段中注意文件排列的顺序。指定必须放在前面部分的那些文件就是那些必须安排在前16KB内的文件,这些文件中的函数在前16KB会被调用。在后面第二部分(16KB之后)中调用的程序,前后顺序就无所谓了。
(3)链接脚本中除了.text .data .rodata .bss段等编译工具自带的段之外,编译工具还允许我们自定义段。譬如uboot中的.u_boot_cmd段就是自定义段。自定义段很重要,之后会讲cmd的细节。
定义平台相关的宏,其根据./include/common.h和./include/config.h也就是./include/configs/x210_sd.h。
这个目录有一些帮助编译的工具,先放着。
以下内容基于x210开发板:
配置:make x210_sd_config
出现:Configuring for x210_sd board…说明配置好了。
配置取决于主板和CPU类型的组合;所有此类信息都保存在配置文件“include/configs/
编译:make
注意事项:
1.我们需要的交叉编译工具链为arm-2009q3,注意自己是否安装
2.makefile的第147行内容为:CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-
3.我们的uboot可以x210_sd_config也可以x210_nand_config,也可以通过mkmovi生成inand或者mmc使用的镜像文件
小细节
1.make distclean不彻底
某些文件在distclean、clean、unconfig后未被删除,因为其大小不一样,说明我们的uboot的ditclean、clean、unconfig是不完善的:
我们执行配置编译等动作,并用du记录整个uboot目录的大小,distclean、clean、unconfig清理uboot后任然比原始文件大,说明清理不彻底,有些文件未被清理。
make x210_sd_config后文件大小:
du -b --max-depth=1 uboot
17532575 uboot/uboot
17532786 uboot/out_dir_uboot
make unconfig后文件大小:
17532575 uboot/uboot
17532612 uboot/out_dir_uboot
make后文件大小:
26896624 uboot/out_dir_uboot
make clean后文件大小:
22708642 uboot/out_dir_uboot
make distclean 后文件大小:(distclean后再clean文件大小不变,表示distclean清理包括了clean中的内容,或者distclean 运行了clean)
17541008 uboot/out_dir_uboot
2.tools文件夹内容何时编译?
并没有找到,我把主makefile所有关于tools的编译过程全部屏蔽了,但是tools还是被编译了,很奇怪,可能我没有找到真正编译他的地方,有知道的同志求教。
uboot可以学到文件系统fatfs,两种启动方式:普通传参和镜像树传参fit,设备树,驱动,命令,环境变量
现在还不知道SUBDIRS 下的目录有什么作用,tools下有哪些工具。