S5PV210 Uboot开发与移植02:Uboot配置与编译

目录

1. uboot源码目录简介

2. uboot编译原理引入

2.1 功能模块配置

2.1.1 在.c文件中不编译相应的功能语句

2.1.2 在make时不编译相应的功能模块

2.2 跨平台编译环境配置

3. uboot配置过程解析

3.1 make x210_sd_config

3.1.1 执行unconfig目标

3.1.2 调用mkconfig脚本生成配置文件

3.1.3 将TEXT_BASE写入config.mk配置文件

3.2 mkconfig脚本分析

3.2.1 参数对应关系

3.2.2 参数检查

3.2.3 建立体系结构相关的软链接

3.2.4 建立config.mk供Makefile使用

3.2.5 建立config.h供源文件使用

4. uboot主Makefile解析

4.1 生成uboot版本信息

4.2 获取编译主机信息

4.3 配置静默编译

4.4 配置原地编译 / 输出目录编译

4.4.1 原地编译与输出目录编译

4.4.2 如何配置输出目录编译

4.4.3 Makefile中如何处理输出目录编译

4.5 导入include/config.mk

4.6 配置工具链前缀

4.7 导入$(TOPDIR)/config.mk

4.7.1 定义obj & src变量

4.7.2 定义工具链

4.7.3 加载ARCH / CPU / SoC / Board配置文件

4.7.4 导入链接器脚本

4.7.5 设置编译选项

4.7.6 设置编译默认规则

4.8 定义目标文件

4.9 定义最终目标

5. uboot链接器脚本分析

6. 向uboot中添加功能模块

6.1 添加uboot中自带功能模块

6.1.1 在板级配置头文件中添加配置项

6.1.2 在源码中引用dm9000.c的相关函数

6.1.3 重新编译uboot

6.2 添加自定义功能模块

6.2.1 添加功能模块代码

6.2.2 修改子Makefile

6.2.3 修改板级配置头文件

6.2.4 重新编译uboot


1. uboot源码目录简介


x210 uboot目录结构如下图所示,

S5PV210 Uboot开发与移植02:Uboot配置与编译_第1张图片


说明1:x210使用的uboot版本相对较早(2008年8月版本)且经过裁剪(去掉了除ARM外其他架构的内容),目前新的uboot目录结构有所调整


增设了arch目录,统一管理不同架构的cpu和lib_arch目录


② 将common目录中与命令相关的源文件单独建立cmd目录进行管理


修改了配置方式


原先所有配置项均在主Makefile中,现在新建configs目录统一管理所有板级配置文件(板级配置头文件仍在include/configs目录下)


④ 修改了主Makefile,将原先以.mk文件形式包含的配置文件纳入主Makefile(能这么做也就是因为将板级配置命令均移出了主Makefile)


说明2:uboot的目录的整体结构是随着层次递进的


ARCH        -->        CPU        -->        SoC        -->        board


arm                          arm920t                s5pc1xx              smdkc110


mips                         armv7                   s5pc11x              x210


就具体子目录而言:


① 架构相关目录(此处架构指CPU架构 + SoC型号)


cpu/    lib_arm/    board/


② 架构无关硬件相关目录(主要是配置片外外设,e.g. dm9000网卡芯片)


drivers/


③ 硬件无关目录(如命令解析 / 网络协议实现 / 文件系统支持)


common/    net/    fs/    api/


④ 通用以及配置头文件(尤其要注意板级配置头文件)


include/

2. uboot编译原理引入

2.1 功能模块配置


uboot提供的功能模块非常之多,比如网卡驱动就有许多种,但是我们往往只使用众多功能模块中的一小部分。为此,我们需要在编译时排除那些我们不使用的功能模块以减小最终编译出的uboot.bin体积


要排除某一功能模块需要完成如下2个步骤:

2.1.1 在.c文件中不编译相应的功能语句


S5PV210 Uboot开发与移植02:Uboot配置与编译_第2张图片


 S5PV210 Uboot开发与移植02:Uboot配置与编译_第3张图片


对于非必须的可选功能模块语句用条件编译命令提供编译开关,为了集中管理这些功能语句开关,可以建立专门的配置头文件config.h


 


 S5PV210 Uboot开发与移植02:Uboot配置与编译_第4张图片


这样就可以在config.h中集中管理功能模块语句是否编译

2.1.2 在make时不编译相应的功能模块


经过上一个步骤,虽然.c文件中使用功能模块的语句可以根据条件不予编译,但是相应的功能模块(如led.c ---> led.o)依然会被编译。因为Makefile的依赖中依然有相应的.o文件,所以他们依然会被编译


所以还要修改Makefile,对功能模块的编译进行控制。修改的思路和之前相同,我们添加这些带有参数的目标


而在编译中仅让变量objs-y所包含的.o文件参与,这样通过控制objs-$(CONFIG_LED) += drivers/led.o中变量CONFIG_LED的值就可以决定相应的功能模块是否被编译

S5PV210 Uboot开发与移植02:Uboot配置与编译_第5张图片


注意:只要不出现在编译目标之中,默认规则并不会编译相关源文件


此处我们同样可以建立配置文件config.mk统一管理


 


 


这样只要在Makefile中包含了config.mk,自然就对相应功能模块是否编译进行了控制。


 


说明1:根据上面的介绍,只要这两个配置文件保持一致,也就是说在config.h中被定义的功能模块在config.mk中也被定义为y,那么就可以实现对相应功能模块及功能语句是否被编译进行控制


说明2:config.h供源代码使用,config.mk供Makefile使用,在实现层面一般只要配置其中一个文件, 然后通过脚本分析产生另一个文件


在uboot的配置中,是修改config.h文件,然后在主Makefile中使用sed解析并生成config.mk文件


在Linux内核的配置中,则是修改config.mk文件,然后自动生成config.h文件

2.2 跨平台编译环境配置


上面介绍的内容只是涉及某一个功能模块(在实现层面就是某个.c或.s文件)是否被编译,下面介绍的跨平台编译环境的配置则涉及整个目录是否被编译


uboot是一个跨平台软件,他支持多种架构的CPU,对不同架构的支持往往包含在arch目录中(之前的uboot是cpu目录)

S5PV210 Uboot开发与移植02:Uboot配置与编译_第6张图片


不同的架构使用不同的编译器,而且在众多架构中一次只能编译其中一种,而其余目录的内容不予编译,这点在Makefile中需要有所体现


通过变量ARCH我们可以对不同平台的编译环境进行配置


S5PV210 Uboot开发与移植02:Uboot配置与编译_第7张图片


通过这个变量也控制了对哪些目录下的内容进行编译


S5PV210 Uboot开发与移植02:Uboot配置与编译_第8张图片

3. uboot配置过程解析

3.1 make x210_sd_config


编译uboot前的配置就是执行make x210_sd_config命令


x210_sd_config目标如下

执行该目标会完成3个任务:

3.1.1 执行unconfig目标

unconfig伪目标用于清除上次配置生成的文件


说明:生成的配置文件简介


在删除的地方反而更容易集中查看生成的配置文件~.~,这些配置文件的生成细节详见下文分析


① include/config.h

include/config.h在配置过程中自动生成,内容就是包含板级配置头文件include/configs/x210_sd.h


② include/config.mk

include/config.mk在配置过程中自动生成,该文件定义了一组变量,供主Makefile包含


③ include/autoconf.mk

S5PV210 Uboot开发与移植02:Uboot配置与编译_第9张图片

include/config.mk在配置过程中自动生成,该文件通过解析板级配置头文件生成,供Makefile包含,用于控制功能模块的编译


④ board/samsung/x210/config.mk

board/samsung/x210/config.mk在执行x210_sd_config目标时生成,该文件记录了uboot的链接地址

3.1.2 调用mkconfig脚本生成配置文件


此处调用mkconfig脚本时会传递6个参数,下面分析一下第1个参数的构成方式,


$(@:_config=):将目标($@)中的_config替换为等号后的内容,此处为空,所以该参数就是x210_sd


因此,传递给mkconfig的参数如下,


$1:x210_sd


$2:arm


$3:s5pc11x


$4:x210


$5:samsung


$6:s5pc110


$#:6


注:$#代表脚本命令行参数个数,并不包含$0,即脚本名称

3.1.3 将TEXT_BASE写入config.mk配置文件


TEXT_BASE用于在链接时指定uboot.bin的链接地址,该信息保存在board/samsung/x210/config.mk中,供主Makefile包含使用

3.2 mkconfig脚本分析

3.2.1 参数对应关系

根据mkconfig脚本注释,传递给该脚本的参数对应关系如下,


Target:x210_sd


Architecture:arm


CPU:s5pc11x


Board:x210


VENDOR:samsung


SOC:s5pc110


说明1:VENDOR和SOC参数为可选项,因此合法的参数个数为4 / 5 / 6。至于这2个参数如何使用,后文有分析~~


说明2:如果没有VENDOR和SOC参数,传递时该位置可以留空也可以用NULL(mkconfig脚本中会分析),但是如果有SOC但是没有VENDOR,则VENDOR处只能使用NULL,以便占位

3.2.2 参数检查

S5PV210 Uboot开发与移植02:Uboot配置与编译_第10张图片

说明1:while循环用于解析参数中的特殊选项,此处第1个参数就不是特殊选项,所以进入*)分支,直接跳出循环。


此处需要注意的是,使用shift命令可以实现对shell脚本参数的遍历(shift会同时修改$#和$1的值)

说明2:如前所述,合法的参数个数为[4, 6]。注意,这是去除特殊选项之后的参数个数~~


当然,根据这个while循环的结构,如果调用mkconfig脚本时需要带有特殊选项,需要在各有效参数之前

3.2.3 建立体系结构相关的软链接

S5PV210 Uboot开发与移植02:Uboot配置与编译_第11张图片

S5PV210 Uboot开发与移植02:Uboot配置与编译_第12张图片

说明1:此处创建软链接的操作都是在include/目录下完成的


在mkconfig脚本起始处便cd ./include,进入include目录下操作


说明2:通过建立头文件目录的软链接,实现uboot的跨平台移植性。例如start.S中包含了下面2个头文件。


asm/proc/domain.h就是asm-arm/proc/domain.h


regs.h就是s5pc110.h,该头文件对SoC的SFR进行了定义

说明3:根据上文,对于asm-arm/mach这个软链接,首先指向了arch-s5pc110,之后将其覆盖指向arch-s5pc11x


需要注意的是,include/asm-arm目录下并没有arch-s5pc110目录,但是依然可以调用

ln  -s  arch-s5pc110  asm-arm/arch


因为软链接的本质是新建一个文件,该文件中存储的就是指向文件的文件名,只不过此处指向一个不存在的文件,该软链接无效而已

S5PV210 Uboot开发与移植02:Uboot配置与编译_第13张图片

3.2.4 建立config.mk供Makefile使用

S5PV210 Uboot开发与移植02:Uboot配置与编译_第14张图片

生成的config.mk只是包含ARCH / CPU / BOARD / VENDOR / SOC这5个变量的定义,供主Makefile包含使用(主Makefile中会导出这些变量,使其在整个工程中生效)

3.2.5 建立config.h供源文件使用

S5PV210 Uboot开发与移植02:Uboot配置与编译_第15张图片

生成的config.h只是包含了板级配置头文件include/configs/x210_sd.h,该板级配置头文件中包含了开发板的所有配置项,因此代码中只要包含即包含了所有配置项


根据上文介绍,包含后就可以在源代码中控制功能模块调用语句的条件编译

说明:如果调用mkconfig脚本时带有-a选项,则不会新建config.h,而是将内容追加到原有config.h之后(这个用法不常见~~)

4. uboot主Makefile解析


说明:本节并不是从all目标开始分析主Makefile,而是按Makefile的顺序分析该文件

4.1 生成uboot版本信息

S5PV210 Uboot开发与移植02:Uboot配置与编译_第16张图片

说明1:此处需要注意的是,定义VERSION_FILE变量时使用了等号(=),因此是引用时展开,所以在定义中可以使用尚未定义的obj变量


如果此处使用(:=),将会在定义处展开,那么此处$(obj)的值就是空


说明2:对version_autogenerated.h的使用


include/version_autogenerated.h会被include/version.h包含,因此在实际使用中,只要包含即可获得uboot版本信息

4.2 获取编译主机信息

S5PV210 Uboot开发与移植02:Uboot配置与编译_第17张图片

4.3 配置静默编译


如果调用make带上-s选项,该选项(s)会成为变量MAKEFLAGS的一部分,此时会将变量XECHO置为空,从而实现静默编译(即编译时不出现Makefile的打印信息)

S5PV210 Uboot开发与移植02:Uboot配置与编译_第18张图片

4.4 配置原地编译 / 输出目录编译

4.4.1 原地编译与输出目录编译


uboot提供了2种编译方式(Linux内核等复杂工程也都提供),


① 原地编译


含义:在.c/.S源码目录生成目标文件(.o)


优点:处理简单


缺点:


a. 污染源文件目录


b. 一套源代码只能按照一种配置进行编译,一旦更换配置,需要先make clean之后才能更换配置编译


当然也可以每种配置各使用一套源代码,但这将加大维护的难度(e.g. 一个文件需要修改,需要在每套源代码中都实现)


② 输出目录编译


含义:在编译时指定输出目录,然后在指定的输出目录生成目标文件(.o)


优点:


a. 不再污染源代码目录


b. 一套代码更换配置编译时,只需指定不同的输出目录即可

4.4.2 如何配置输出目录编译


uboot提供2种方式指定输出目录,


① 命令行中添加 O=xxx,示例如下,

make O=/tmp/build distclean
make O=/tmp/build x210_sd_config
make O=/tmp/build all


② 导出BUILD_DIR变量,示例如下,

export BUILD_DIR=/tmp/build
make distclean
make x210_sd_config
make all


注意:对于移植后的uboot版本,如果添加的代码不支持输出目录编译,该功能就无法使用。x210的uboot版本在新增的代码中并不支持该功能,所以无法使用。

4.4.3 Makefile中如何处理输出目录编译

S5PV210 Uboot开发与移植02:Uboot配置与编译_第19张图片

S5PV210 Uboot开发与移植02:Uboot配置与编译_第20张图片

说明1:根据主Makefile的处理逻辑,如果在指定O=xxx的情况下,也导出了BUILD_DIR变量,那么O=xxx的优先级更高


说明2:CURDIR是Makefile的内置变量,无需定义,其值为当前目录的绝对地址


说明3:obj & src变量在uboot顶层目录的config.mk中定义,但是在包含config.mk之前某些目标需要使用这些变量,所以此处定义一次

4.5 导入include/config.mk

如上文分析,include/config.mk由mkconfig脚本生成,此处包含该文件并导出其中各变量

4.6 配置工具链前缀

S5PV210 Uboot开发与移植02:Uboot配置与编译_第21张图片

此处根据导出的ARCH变量配置合适的工具链前缀,并导出CROSS_COMPILE变量

4.7 导入$(TOPDIR)/config.mk

uboot的顶层目录的config.mk文件用于进行进一步的配置,具体内容如下

4.7.1 定义obj & src变量

S5PV210 Uboot开发与移植02:Uboot配置与编译_第22张图片

可见此处如果采用原地编译,obj & src会被置为空

4.7.2 定义工具链

S5PV210 Uboot开发与移植02:Uboot配置与编译_第23张图片

4.7.3 加载ARCH / CPU / SoC / Board配置文件

S5PV210 Uboot开发与移植02:Uboot配置与编译_第24张图片

说明1:此处使用sinclude包含配置文件是防止如果没有该配置文件导致报错(并不是每个配置文件都要存在~~)


说明2:此处包含的include/autoconf.mk文件非常重要,该文件由板级配置头文件x210_sd.h解析而来,该文件可用于控制功能模块的编译

S5PV210 Uboot开发与移植02:Uboot配置与编译_第25张图片

说明3:VENDOR & SOC变量的使用


如前文所述,在调用mkconfig脚本时,这两个变量可选,如包含的话用法如下,


board/$(VENDOR)/$(BOARD):构成开发板路径,比如三星将其开发板目录置于board/samsung目录下(当然,出于历史原因,为了保持向后兼容三星某些开发板目录并没有放置在board/samsung目录下)


cpu/$(CPU)/$(SOC):构成SoC路径,目前新版uboot中$(CPU)目录一般是ARM核的架构目录(e.g. armv7),$(SOC)目录为该架构下的SoC目录(e.g. s5pc1xx)


下图为2012-10版本的uboot示例

S5PV210 Uboot开发与移植02:Uboot配置与编译_第26张图片

说明4:此处导入的$(TOPDIR)/board/$(BOARDDIR)/config.mk文件就是配置uboot时生成的文件,其中包含链接地址的定义

4.7.4 导入链接器脚本

S5PV210 Uboot开发与移植02:Uboot配置与编译_第27张图片

4.7.5 设置编译选项

S5PV210 Uboot开发与移植02:Uboot配置与编译_第28张图片

要设置的编译选项很多,此处列出比较重要的2点,


① -DTEXT_BASE=$(TEXT_BASE)


在x210中相当于在编译时定义如下的宏,

#define TEXT_BASE 0xc3e00000


该宏在uboot代码中会被多次使用,以便获取uboot的链接地址,只不过使用该值的方式是定义_TEXT_BASE变量

注:这也相当于实现了Makefile配置文件与源代码配置文件的交互


② -I选项的设置


设置-I选项时要注意对输出目录编译方式的支持

4.7.6 设置编译默认规则

S5PV210 Uboot开发与移植02:Uboot配置与编译_第29张图片

此处可见对输出目录编译方式的支持,如果使用该方式,会在指定目标生成目标文件

4.8 定义目标文件

S5PV210 Uboot开发与移植02:Uboot配置与编译_第30张图片

可见编译时会将大多数目录下的文件编译为静态库供最终链接使用


注:在uboot阶段也只能以静态库的方式链接,此时没有操作系统,是无法使用动态库的

4.9 定义最终目标

S5PV210 Uboot开发与移植02:Uboot配置与编译_第31张图片

可将uboot最终的链接过程与我们裸机代码工程相同


说明1:include/autoconf.mk文件的生成


在编译$(OBJS)和$(LIBS)时均会依赖include/autoconf.mk,因为是否编译某个源文件需要autoconf.mk的控制

生成autoconf.mk的方式则是使用define2mk.sed脚本解析include/config.h(该头文件中就是包含板级配置头文件include/x210_sd.h),这与之前uboot编译原理引入部分的分析是一致的。

S5PV210 Uboot开发与移植02:Uboot配置与编译_第32张图片

说明2:由于uboot的运行环境类似裸机代码,所以最终烧写运行的是u-boot.bin而不是ELF格式的u-boot文件,u-boot.bin由u-boot经过objcopy转换而来,仅包含ELF格式文件中的可执行部分

5. uboot链接器脚本分析

S5PV210 Uboot开发与移植02:Uboot配置与编译_第33张图片

说明1:链接器脚本的链接起始地址指定为0x00000000,这是因为在使用链接器脚本的同时使用-Ttext选项指定了代码段链接地址,而-Ttext指定的优先级高于链接器脚本


因此在实现中,使用链接器脚本确定ELF文件布局,使用-Ttext选项确定链接地址

说明2:由于要截取uboot.bin的前8KB作为BL1,因此必须把代码重定位可能用到的内容链接到代码段最前端(e.g. x210实现代码重定位的文件就是cpu/s5pc11x/movi.c)


说明3:注意uboot中的2个自定义段


① .u_boot_cmd段


uboot命令的描述结构体被链接到该段,使用__u_boot_cmd_start和__u_boot_cmd_end可以实现对所有uboot命令结构体的遍历

S5PV210 Uboot开发与移植02:Uboot配置与编译_第34张图片

S5PV210 Uboot开发与移植02:Uboot配置与编译_第35张图片

补充:对链接器脚本变量的使用,可参考如下笔记,


有道云笔记


② .mmudata段


uboot使用的Translation Table会被链接到.mmudata段

S5PV210 Uboot开发与移植02:Uboot配置与编译_第36张图片

6. 向uboot中添加功能模块

6.1 添加uboot中自带功能模块


说明:以添加dm9000网卡驱动为例

6.1.1 在板级配置头文件中添加配置项


在include/configs/x210_sd.h中添加宏定义

#define CONFIG_DRIVER_DM9000


至于如何知道这个配置项的名称,可以查看driver/net目录下的Makefile文件,配置头文件中的配置项名和Makefile中必须一致。

6.1.2 在源码中引用dm9000.c的相关函数

#ifdef CONFIC_DRIVER_DM9000
    dm9000_initialize();
#endif

6.1.3 重新编译uboot


顶层Makefile会根据板级配置头文件生成autoconf.mk给各Makefile包含使用


说明:概括来说,添加一个已有模块的方法就是修改板级配置头文件,然后在make的过程中会自动生成include/autoconf.mk文件供Makefile包含以决定需要编译哪些模块

6.2 添加自定义功能模块


说明:以添加farsight_net.c驱动为例

6.2.1 添加功能模块代码


在相应驱动目录下(e.g. drivers/net)添加自定义的功能模块代码

S5PV210 Uboot开发与移植02:Uboot配置与编译_第37张图片

6.2.2 修改子Makefile


修改drivers/net目录下的子Makefile,添加相应驱动模块的编译选项

6.2.3 修改板级配置头文件


修改板级配置头文件include/configs/x210_sd.h,定义宏开关

6.2.4 重新编译uboot


执行到此步,我们可以生成autoconf.mk文件以验证该模块是否已被编译


可见该模块已被编译,接下来就可以在我们需要的源文件中调用farsight_net.c驱动中提供的函数。


说明:其实添加自已编写的驱动模块和添加U-boot中已有的驱动模块最大的区别就是要提供相应的驱动代码。其余修改板级配置头文件(添加自己的驱动还要修改相应驱动目录下的Makefile)并make生成autoconf.mk的过程都是一致的

你可能感兴趣的:(Linux嵌入式开发,嵌入式)