u-boot分析2---u-boot功能、结构、结合makefile

本文详细解析了U-Boot的配置与编译流程,包括如何使用make命令配置开发板,mkconfig文件的作用,以及配置文件config.mk和config.h的生成过程。深入分析了U-Boot的编译过程,从源文件编译到最终的链接,解释了如何通过配置宏开关来裁剪和设置U-Boot的功能。
配置过程分析
make 100ask24x0_config

相当于执行(Makefile分析)

MKCONFIG	:= $(SRCTREE)/mkconfig
.........
SRCTREE		:= $(CURDIR)         /*CURDIR为当前目录*/
.........
100ask24x0_config	:	unconfig
	@$(MKCONFIG) $(@:_config=) arm arm920t 100ask24x0 NULL s3c24x0

假定在 U-Boot-1.1.6 的根目录下编译,则其中的 MKCONFIG 就是根目录下的 mkconfig
文件。$(@:_config=)的结果就是将“100ask24x0_config”中的“_config”去掉,结果为“100ask24x0”。
所以“make 100ask24x0_config”实际上就是执行如下命令

./mkconfig 100ask24x0 arm arm920t 100ask24x0 NULL s3c24x0
#   $0        $1      $2     $3      $4     $5    $6

再来看看 mkconfig 的作用,在 mkconfig 文件开头第 6 行给出了它的用法

# Parameters:  Target  Architecture  CPU  Board [VENDOR] [SOC]
分步骤分析 mkconfig 的作用

1、确定开发板名称 BOARD_NAME,相关代码如下
在这里插入图片描述
对于“./mkconfig 100ask24x0 arm arm920t 100ask24x0 NULL s3c24x0”命令,其中没有“–”、
“-a”、“-n”等符号,所以第 14~22 行没做任何事情。第 11、12 行两个变量仍维持原来的值。
执行完第 23 行后,BOARD_NAME 的值等于第 1 个参数,即“100ask24x0 ”

2、创建到平台/开发板相关的头文件的链接

略过 mkconfig 文件中的一些没有起作用的行,如下所示
在这里插入图片描述
在这里插入图片描述
        第 33 行判断源代码目录和目标文件目录是否一样,可以选择在其他目录下编译 U-Boot,这可以令源代码目录保持干净,可以同时使用不同的配置进行编译。不过本书是直接在源代码目录下编译的,第 33 行的条件不满足,将执行 else 分支的代码。
         第 46~48 行进入 include 目录,删除 asm 文件(这是上一次配置时建立的链接文件),
然后再次建立 asm 文件,并令它链接向 asm-$2 目录,即 asm-arm

继续往下看代码:
在这里插入图片描述
        第 51 行删除 asm-$2/arch 目录,即 asm-arm/arch。
        对于“./mkconfig 100ask24x0 arm arm920t 100ask24x0 NULL s3c24x0”命令,$6 为“s3c24x0”,不为空,也不是“NULL”,所以第 53 行的条件不满足,将执行 else 分支。
        第 56 行中,LNPREFIX 为空,所以这个命令实际上就是“ln -s arch-$6 asm-$2/arch”,即“ln -s arch-s3c24x0 asm-arm/arch”。
        第 60、61 行重新建立 asm-arm/proc 文件,并让它链接向 proc-armv 目录。

3、创建顶层 Makefile 包含的文件 include/config.mk,如下所示:
在这里插入图片描述

    #  > 表示新建一个config.mk文件
    # >> 表示追加

         对于“ ./mkconfig 100ask24x0 arm arm920t 100ask24x0 NULL s3c24x0”命令,上面几行代码
创建的 config.mk 文件内容如下:

config.mk效果:

#ARCH   = arm
#CPU    = arm920t 
#BOARD  = 100ask24x0 
#SOC    = s3c24x0

4、创建开发板相关头文件include/config.h,如下图所示:
在这里插入图片描述
APPEND 维持原值“no”,所以 config.h 被重新建立,它的内容如下

#config.h的内容

# /* Automatically generated - do not edit */
# #include <configs/$1.h> 

         现在总结一下,配置命令“make 100ask24x0_config”,实际的作用就是执行“./mkconfig 100ask24x0 arm arm920t 100ask24x0 NULL s3c24x0”命令。假设执行“./mkconfig $1 $2 $3 $4 $5 $6”命令,则将产生如下结果。
(1)开发板名称 BOARD_NAME 等于$1。

(2)创建到平台/开发板相关的头文件的链接,如下所示
在这里插入图片描述
(3)创建顶层 Makefile 包含的文件 include/config.mk,如下所示
在这里插入图片描述
在这里插入图片描述
(4)创建开发板相关的头文件 include/config.h,如下所示
在这里插入图片描述

         从这 4 个结果可以知道,如果要在 board 目录下新建一个开发板<board_name>的目录,则在 include/configs 目录下也要建立一个文件<board_name>.h,里面存放的就是开发板<board_name>的配置信息。
         U-Boot 还没有类似 Linux 一样的可视化配置界面(比如使用 make menuconfig 来配置),要手动修改配置文件 include/config/<board_name>.h 来裁减、设置 U-Boot编译过程分析(Makefile)
         配置文件中有以下两类宏。
       (1)一类是选项(Options),前缀为“CONFIG_”,它们用于选择 CPU、SOC、开发板类型,设置系统时钟、选择设备驱动等。比如

#define CONFIG_ARM920T		1	/* This is an ARM920T Core	*/
#define	CONFIG_S3C2410		1	/* in a SAMSUNG S3C2410 SoC     */
#define CONFIG_SMDK2410		1	/* on a SAMSUNG SMDK2410 Board  */
/* input clock of PLL */
#define CONFIG_SYS_CLK_FREQ	12000000 /* the SMDK2410 has 12MHz input clock */
//#define CONFIG_SYS_CLK_FREQ	16934400 /* the SMDK2410 has 12MHz input clock */

       (2)另一类是参数(Setting),前缀为“CFG_”,它们用于设置 malloc 缓冲池的大小、U-Boot 的提示符、U-Boot 下载文件时的默认加载地址、Flash 的起始地址等。比如:

#define CFG_MALLOC_LEN		(CFG_ENV_SIZE + 128*1024)
#define CFG_GBL_DATA_SIZE	128	/* size in bytes reserved for initial data */

         从下面的编译、连接过程可知,U-Boot 中几乎每个文件都被编译和连接,但是这些文件是否包含有效的代码,则由宏开关来设置。比如对于网卡驱动 drivers/cs8900.c,它的格式为
在这里插入图片描述
         如果定义了宏 CONFIG_DRIVER_CS8900,则文件中包含有效的代码;否则,文件被注释为空。
         可以这样认为,“CONFIG_”除了设置一些参数外,主要用来设置 U-Boot 的功能、选择使用文件中的哪一部分;而“CFG_”用来设置更细节的参数。

编译,链接过程分析

         配置完后,执行“make all”即可编译,从 Makefile 中可以了解 U-Boot 使用了哪些文件、哪个文件首先执行、可执行文件占用内存的情况。
         先确定用到哪些文件,下面所示为 Makefile 中与 ARM 相关的部分

117 include $(OBJTREE)/include/config.mk
118 export   ARCH CPU BOARD VENDOR SOC
119
…
127 ifeq ($(ARCH),arm)
128 CROSS COMPILE = arm-linux-
_
129 endif
…
163 # load other configuration
164 include $(TOPDIR)/config.mk
165

         第 117、164 行用于包含其他的 config.mk 文件,第 117 行所要包含文件的就是在上面的配置过程中制作出来的 include/config.mk 文件,其中定义了 ARCH、CPU、BOARD、SOC 等4 个变量的值为 arm、arm920t、100ask24x0、s3c24x0。
          第 164 行包含顶层目录的 config.mk 文件,它根据上面 4 个变量的值确定了编译器、编译选项等。其中对我们理解编译过程有帮助的是 BOARDDIR、LDFLAGS 的值,如下所示:
在这里插入图片描述

88 BOARDDIR = $(BOARD)
…
91 sinclude $(TOPDIR)/board/$(BOARDDIR)/config.mk  # include board specific
rules
…
143 LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/U-Boot.lds
…
189 LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)

         在 board/100ask24x0/config.mk 中,定义了“TEXT_BASE = 0x33F80000”。所以,最终结果如下:BOARDDIR 为 100ask24x0;LDFLAGS 中有“-T board/100ask24x0/U-Boot.lds -Ttext 0x33F80000”字样。
         继续往下看 Makefile:

166 #########################################################################167 # U-Boot objects....order is important (i.e. start must be first)
168
169 OBJS  = cpu/$(CPU)/start.o
…
193 LIBS  = lib_generic/libgeneric.a
194 LIBS += board/$(BOARDDIR)/lib$(BOARD).a
195 LIBS += cpu/$(CPU)/lib$(CPU).a
…
199 LIBS += lib_$(ARCH)/lib$(ARCH).a
200 LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/
libjffs2.a \
201 fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a
202 LIBS += net/libnet.a
…
212 LIBS += $(BOARDLIBS)
213
……

         从第 169 行得知,OBJS 的第一个值“cpu/$(CPU)/start.o”,即“cpu/arm920t/ start.o”。第 193~213 行指定了 LIBS 变量就是平台/开发板相关的各个目录、通用目录下相应的库,比如:lib_generic/libgeneric.a、board/smdk2410/libsmdk2410.a、cpu/arm920t/ libarm920t.a、lib_arm/libarm.a、fs/cramfs/libcramfs.a fs/fat/libfat.a 等。
         OBJS、LIBS 所代表的.o、.a 文件就是 U-Boot 的构成,它们通过如下命令由相应的源文件(或相应子目录下的文件)编译得到。

268 $(OBJS):
269			 $(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))270
271 $(LIBS):
272			 $(MAKE) -C $(dir $(subst $(obj),,$@))
273
274 $(SUBDIRS):
275			 $(MAKE) -C $@ all
276

         第 268、269 两行的规则表示,对于 OBJS 中的每个成员,都将进入 cpu/$(CPU)目录(即cpu/arm920t)编译它们。现在 OBJS 为 cpu/arm920t/start.o,它将由 cpu/arm920t/start.S 编译得到。
         第 271、272 两行的规则表示,对于 LIBS 中的每个成员,都将进入相应的子目录执行“make”命令。这些子目录中的 Makefile,结构相似,它们将 Makefle 中指定的文件编译、连接成一个库文件。
         当所有的 OBJS、LIBS 所表示的.o 和.a 文件都生成后,就剩最后的连接了,这对应 Makefile
中如下几行:

246 $(obj)U-Boot.srec:   $(obj)U-Boot
247 				$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@
248
249 $(obj)U-Boot.bin:  $(obj)U-Boot
250				 $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
251
……
262 $(obj)U-Boot:   depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)
263 UNDEF_SYM=`$(OBJDUMP)  -x  $(LIBS)  |sed   -n  -e  's/.*\(__u
           _boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
264 			cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \ 
265 				--start-group $(__LIBS) --end-group 				  $(PLATFORM_LIBS) \
266 					-Map U-Boot.map -o U-Boot
267

         先使用第 262~266 的规则连接得到 ELF 格式的 U-Boot,最后转换为二进制格式U-Boot.bin、S-Record 格式 U-Boot.srec。LDFLAGS 确定了连接方式,其中的“-T board/100ask24x0/U-Boot.lds -Ttext 0x33F80000”字样指定了程序的布局、地址。board/100ask24x0/U-Boot.lds
文件如下:

28 SECTIONS
29 {
30    . = 0x00000000;
31
32    . = ALIGN(4);
33    .text      :
34    {
35     cpu/arm920t/start.o  (.text)
36     *(.text)
37    }
38
39    . = ALIGN(4);
40    .rodata : { *(.rodata) }
41
42    . = ALIGN(4);
43    .data : { *(.data) }
44
45    . = ALIGN(4);
46    .got : { *(.got) }
47
48    . = .;
49 u boot cmd start = .;
50    .u_boot_cmd : { *(.u_boot_cmd) }
51 u boot cmd end = .;
52
53    . = ALIGN(4);
54 bss start = .;
55    .bss : { *(.bss) }
56 end = .;
57 }

         从第 35 行可知,cpu/arm920t/start.o 被放在程序的最前面,所以 U-Boot 的入口点在cpu/arm920t/start.S 中
现在来总结一下 U-Boot 的编译流程。
(1)首先编译 cpu/$(CPU)/start.S,对于不同的 CPU,还可能编译 cpu/$(CPU)下的其他文件。
(2)然后,对于平台/开发板相关的每个目录、每个通用目录都使用它们各自的 Makefile生成相应的库。
(3)将 1、2 步骤生成的.o、.a 文件按照 board/$(BOARDDIR)/config.mk 文件中指定的代码段起始地址、board/$(BOARDDIR)/U-Boot.lds 连接脚本进行连接。
(4)第 3 步得到的是 ELF 格式的 U-Boot,后面 Makefile 还会将它转换为二进制格式、S-Record 格式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值