在这里插入描述以jz2440为例简单分析(目录是新uboot目录,过程是老的)
UBOOT 目标是启动内核:从 flash 上读出内核到 SDRAM 中去。启动内核。
新uboot目录结构
api | 硬件无关的功能函数的API,是uboot本身使用的 |
---|---|
arch | 各种CPU架构平台例如:arm .mips. powerpc. x86. riscv .etc. |
board | 已经支持的开发板相关文件,板级相关配置文件,针对不同平台的功能下具体的实现, 。比如:Makefile和u-boot.lds等和实际开发板的硬件和地址相关的代码; |
cmd 实现uboot命令行下支持的命令,每一条命令都对应一个文件。例如bootm命令对应就是bootm.c。执行xxx命令最终是会调用你do_xxx函数 uboot源码的cmd文件夹下xxx.c文件对应的是xxx命令 | |
common | 通用启动相关初始化文件,board.r board_init_f的实现common/main.c是整个u-boot程序的主函数,主要负责运行维护uboot的shell命令行,这个文件夹以前是cmd的合集,后边版本变动了,具体功能还在研究 |
configs | 各个板卡平台的默认配置文件 make 的时候可以编译使用默认配置比如 make xxx_defconfig 就设置了按照默认配置编译 |
disk | 与磁盘有关的文件 |
doc | 文档目录,里面存放了很多uboot相关文档,这些文档可以帮助理解uboot代码。 |
drivers | |
dts | 存放不同开发板的设备树源码文件,目前该目录为空,只有Makefile 和Kconfig |
---|---|
env | 环境相关nand mmc onenand 等的文件 |
examples | uboot示例代码 |
fs | 文件系统相关,linux系统移植而来的 |
include | 头文件目录。uboot和linux kernel在管理头文件时都采用了同一个思路,就是把所有的头文件全部集中存放在include目录下,而不是头文件跟着自己对应的c文件。所以在uboot中头文件包含时路径结构要在这里去找 |
lib | 各类算法库的实现,比如crc,aes bzip系列,这类文件夹中的内容移植时基本不用管 |
Licenses | 开源协议(BSD, GPL, LGPL,MIT)许可证书,uboot使用的开源许可协议 |
test | 测试程序 |
---|---|
tools | 里面是一些工具类的代码。譬如mkimage |
Makefile | uboot的顶层makefile ,后边文章会重点分析 |
config.mk | 某个Makefile会调用此配置文件,用来处理一些编译过程中的环境变量。Linux Kernel 没有这个文件,U-Boot 需要使用它 |
Kconfig | |
Kbuild | 是 Kbuild 系统使用的文件,该文件用于定义一些源码使用的需要根据编译环境产生的中间文件。 |
老版本中由boards.cfg加载配置 |
老uboot分析
uboot配置过程(老的)
Makefile步骤
uboot要先配置再编译
打补丁
“—” 表示是 原来代码 。
“+++”表示修改后的代码。
在顶层Makefile中有这样一段代码:
100ask24x0_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t 100ask24x0 NULL s3c24x0
#这段话 老的是打补丁后得到参数,比较老的是在顶层boards.cfg加载
所以当我们执行 make 100ask24x0_config 时相当于执行(最前面的@是指make时不输出make信息,一行都被抑制)
@$(MKCONFIG) $(@:_config=) arm arm920t 100ask24x0 NULL s3c24x0
$(MKCONFIG) 变量表示是顶层目录下的mkconfig文件(是个shell脚本)
$(@:_config=) 表示 100ask24x0
#变量中有个高级用法,$(var:a=b),意思为把变量“var”中所有“a”字串结尾的“a”替换成“b”字串。
这样整体就变成 mkconfig 100ask24x0 arm arm920t 100ask24x0 NULL s3c24x0 执行脚本
mkconfig 100ask24x0 arm arm920t 100ask24x0 NULL s3c24x0
参0($0) 1($1) 2($2) 3($3) 4($4) 5($5) 6($6)
mkconfig脚本步骤
#已省略部分代码
#传过来的参数 :
#mkconfig 100ask24x0 arm arm920t scb9328 NULL s3c24x0
$0 $1 $2 $3 $4 $5 $6
[ "${BOARD_NAME}" ] || BOARD_NAME="$1" #BOARD_NAME = 100ask24x0
echo "Configuring for ${BOARD_NAME} board..."
在顶层makefile中
BUILD_DIR := $(O)
OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))#如果没有定义BUILD_DIR,则 BUILD_DIR = CURDIR
SRCTREE := $(CURDIR)
所以执行else分支
建立一个 asm 链接文件–>asm-arm
这样临时生成的原因是避免每次都要配置。如#inclue <asm-arm/type.h>是包含 arm 下的type.h 头文件,若是#include <asm-i386/type.h>是包含 i386 架构下的 type.h 头文件。这样临时建立链接文件到相应的架构下。这样直接写成 #include <asm/type.h>即可,到时用到哪个架构下的 type.h 则,直接 ln -s arm-$(参数位置) asm 这样指向某个架构即可。
(tiny24410中在\uboot_tiny4412-master\arch\arm\include\asm
jz2440中在 \u-boot-1.1.6\include\asm-arm)
同理往下分析建立以下两个链接文件 :
ln -s arch-s3c24x0 asm-arm/arch
ln -s proc-armv asm-arm/proc,链接文件名是asm-arm目录下的proc。
在include目录创建 config.mk 文件提供给顶层makefile
#
# Create include file for Make
echo "ARCH = $2" > config.mk
echo "CPU = $3" >> config.mk
echo "BOARD = $4" >> config.mk
#这 3 条语句最后创建了文件 config.mk,其内容是:
ARCH = arm
CPU = arm920t
BOARD = 100ask24x0
SOC = s3c24x0
创建单板相关的文件
include/config.h
显然 configs/100ask24x0.h 是我们的源码要用到的文件,**这个头文件是配置支持哪些东西,**如支持哪些命令,时钟宏定义等。
总结 make 100ask24x0_config 所做的事情:
1.创建到平台/开发板相关的头文件链接(架构相关 arm架构中的s3c24x0)
ln -s asm-$2 asm
ln -s arch-$6 asm-$6/arch
ln -s proc-armv asm-$2/proc,链接文件名是asm-arm目录下的proc。
asm --> asm-arm
asm-arm/arch --> arch-s3c24x0
asm-arm/proc --> proc-armv
-
创建顶层makefile包含的文件/include/config.mk
-
创建开发板相关的头文件/include/config.h
这 4 个结果可以知道
//自己实现,移植时要会
在 board 目录下新建一个开发板<board_name>目录
在include/configs目录下也要建立一个文件 <board_name>.h,里在存放的就是开发板 <board_name>的配置信息
。
uboot编译过程
编译 : 直接 make
还是分析 顶层 Makefile 文件(从头看起,按顺序执行中间省略不重要的代码)
(老版本交叉编译链在makefile中确定)
# load ARCH, BOARD, and CPU configuration
#包含了配置过程生成的config.mk 文件
include $(OBJTREE)/include/config.mk
#向外导出配置文件中的平台变量
export ARCH CPU BOARD VENDOR SOC
# 省略。。。。。
#设置交叉编译链
ifeq ($(ARCH),arm)
CROSS_COMPILE = arm-linux-
endif
##############################################################
# U-Boot objects....order is important (i.e. start must be first)
#OBJS 很重要。这里从上分析知$(CPU)是 arm920t .由于 start.S 是我们启动代码,所以首先编译.OBJ=cpu/arm920t/start.o
OBJS = cpu/$(CPU)/start.o
#这个 addprefix 是将 OBJS 赋值给 obj。如下:$(addprefix src/,foo bar)结果:src/foo src/bar 有了两个文件。(obj = $(CURDIR) -> CURDIR内嵌变量指当前目录)
OBJS := $(addprefix $(obj),$(OBJS))
#接下来是添加一些静态库 意思是将 cpu/arm920t 目录下的所有涉及到的文件编译好后,打包成一个库文件libarm920t.a
#LIBS (内嵌命令) 的意思便是打包成库。
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
make 编译时,若不指定目标,则 make 就找第一个目标去生成这个目标。all 是这里的第一个目标。
这终的目的是要生成 u-boot.bin 这个二进制文件,则找到这个 目标 ,找它的依赖,一级一级找下去。
u-boot 这个 ELF 格式的文件又依赖于下面这些文件:
进入 ( L N D I R ) 目录 , (LNDIR)目录, (LNDIR)目录,(LD) 进行链接,$(LDFLAGS)这是链接的参数, $$UNDEF_SYM $(__OBJS)这是所有的.o 文件–start-group $(__LIBS)所有的库 --end-group $(PLATFORM_LIBS)-Map uboot.map -o u-boot.
分析 Makefile,另一种方法可以清楚的知道它们做了什么。在 UBOOT 顶层目录执行 make 后,可以见到执行过程。
cd /work/arm920t/sourceCode/u_boot/u-boot-1.1.6 && 这是进入$(LNDIR)
arm-linux-ld -Bstatic -T /work/arm920t/sourceCode/u_boot/u-boot-1.1.6/board/100ask24x0/u-boot.lds -Ttext 0x33F80000
链接脚本依赖于下面的.a .o 文件 这些源材料如何组织成一个 UBOOT。哪个放在最前面。这要看链接脚本:u-boot.lds
下面这些是原材料。start.S 是我们启动代码,所以首先编译.
OBJ=cpu/arm920t/start.o
$UNDEF_SYM cpu/arm920t/start.o
之后是所有的lib库
--start-group lib_generic/libgeneric.a
board/100ask24x0/lib100ask24x0.a
cpu/arm920t/libarm920t.a
cpu/arm920t/s3c24x0/libs3c24x0.a
..........
SECTIONS
{
. = 0x00000000; //当前地址等于0,这个0地址会加上0x33F80000,意即下面的文件会排放在从Ox33f80000开始的地方。
//最先排放cpu/arm920t/start.o这个文件的代码段。
. = ALIGN(4);
.text :
{
cpu/arm920t/start.o (.text) //(.text)指这个cpu/arm920t/start.o的代码段。
board/100ask24x0/boot_init.o (.text) //接着再排放这个boot_init.o文件的代码段。这两个是放在UBOOT最前的两个文件
*(.text) //还有其他所有文件的代码段
}
. = ALIGN(4);
.rodata : { *(.rodata) } //接着是.rodata是只读数据段; *(.rodata)是指所有文件的只读数据段。
. = ALIGN(4);
.data : { *(.data) } //所有文件的数据段。
. = ALIGN(4);
.got : { *(.got) }. = .;
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) } //所有文件的.u_boot_cmd段。这个段一般文件里不存在。这里是UBOOT定义了这个段。
__u_boot_cmd_end = .;
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) }
_end = .;
}
链接地址是 0x33f80000,意思是这个 UBOOT 运行时应该位于 0x33f8000 这里。一开始运行的文件是 cpu/arm920t/start.o分析 UBOOT 时,便是从 start.S 这个汇编文件。
总结分析makefile得到:
1.uboot 从 0x33f80000 处开始运行第一个文件 cpu/arm920t/start.S(从这个文件分析UBOOT 的功能),从这个start.S看下来可以看通整个UBOOT
2.链接地址是如何定义的?
board/100ask24x0/u-boot.lds 这样一个链接脚本。这个链接脚本的第一个代码段文件0x33f80000 处开始运行(当前地址 0 加上 0x33f80000,即放 UBOOT 放在 64M SDRAM 的最上边 512K 空间处)。是怎么定义的?
在源目录下面有个config.mk文件 里面有
LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)
#-Ttest 后的$(TEXT_BASE)在 u-boot-1.1.6/board/100ask24x0 目录下的config.mk 下
若想你的 UBOOT 放在另一个地址,则可以修改这个值。
uboot 第一阶段系统初始化
UBOOT 运行的第一个文件是:cpu/arm920t/start.S(从程序的链接脚本中知道)
不做具体代码分析,以上过程如下:
/*
UBOOT 的第一阶段。
1.进入 SVC 管理模式。
2.关看门狗
3.屏蔽中断
4.做些初始化(主要是 SDRAM 的初始化)
5.设置调用 C 函数的 SP 栈。
6.时钟。
7.重定位(从 FLASH 拷代码到 SDRAM),函数:CopyCode2Ram
8.清 bss 段。bss 段是初始值为 0 的静态的或全局的变量,或是没有初始化的静态或全局变
量。它们就放在bss 段里面。它们全部的初始值都被弄成 0。显然这些变量就没必要保存在程序里面了,清bss 段后就是清了它们,这样节省空间。要运行的时候,再去把这些变量相关的位置就可以再用它们了。
9.最后调用 C 函数 start_armboot:
看下链接文件“u-boot.lds”就可以知道。
*/
在start_armboot 中做更复杂的功能,第二阶段
以上便是 2440 硬件的相关初始化,若是换成其他 CPU,初始化的具体内容不一样,但有相似处。
uboot 第二阶段
UBOOT 最终目标:启动内核。
从 FLASH 读出内核—> 启动
cpu/arm920t/start.S
_start_armboot: .word start_armboot
start_armboot在 \u-boot-1.1.6\lib_arm\board.c 中
//init_sequence是一个函数指针
init_fnc_t *init_sequence[] = {
cpu_init, /* basic cpu dependent setup */
board_init, /* */
dram_init, /* configure available RAM banks */
mem_malloc_init, /* dependant on dram_init */
interrupt_init, /* set up exceptions */
timer_init,
serial_init,
env_init, /* initialize environment */
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
display_banner,
display_dram_config,
NULL,
};
/*start_armboot
||
flash_init
||
nand_init
||
env_relocate //环境变量
||
main_loop(主循环)
main_loop 在\u-boot-1.1.6\common\main.c中
在 UBOOT 上输入命令等等,都是在这个主循环之中。我们输入什么,UBOOT 就解析什么。
*/
1.启动内核:
//bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0 kernel分区是自定义的在100ask24x0.h中写死的
s = getenv("bootcmd") 获取环境变量。
run_command(s ,0)
2.在 u-boot 控制界面。
readline 读入串口的数据。
run_command()
UBOOT 的核心就是这些"命令" run_commnd().故只有分析了这些命令的实现之后,才能明白内核的加载与启动。
uboot命令实现
根据命令名字找到函数。所以说uboot中有个命令的结构体 。
/*
* Monitor Command Table
*/
struct cmd_tbl_s {
char *name;
char *usage; /* Usage message (short) */
#ifdef CFG_LONGHELP
char *help; /* Help message (long) */
#endif
#ifdef CONFIG_AUTO_COMPLETE
/* do auto completion on the arguments */
int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
#endif
};
//输入md.w 0 则argv[0] = "md.w",argv[1] = "0"
run_command (const char *cmd, int flag)
parse_line(char *line, char *argv[])//解析命令
find_cmd(const char *cmd)//寻找命令
================================================================================
由代码可知在.u_boot_cmd段找数据,.u_boot_cmd是怎么来的?
//在u-boot-1.1.6\include\command.h 中宏定义命令段
#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}
使用的命令都要用U_BOOT_CMD 结构体赋值,会生成cmd_tbl_t _u_boot_cmd##name 变量存到命令段中。
按上面的分析,增加一个 hello 命令,使其打印 hello world:
1.按 cmd_bootm.c 中的结构来写。
新建一个 hello_cmd.c,包含 cmd_bootm.c 中头文件。与 cmd_bootm.c 一样放在 UBOOT 源码的 common 目录下。
2.在 Cmd_bootm.c 中有:
int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
printf ("## Booting image at %08lx ...\n", addr);
//后面也有返回值。
}
//我们仿制成:加了参数打印。
int do_hello (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
int i;
printf("Hello World!,%d\n",argc);
for (i = 0;i < argc;i++)
{
printf("argv[%d]:%s\n",i,argv[i]);
}
return 0;
}
3.仿照着定义一个 U_BOOT_CMD 宏把命令结构体存到uoot命令段中。(cmd_bootm.c 有类似的)
--------------------------------------------------------------------------
U_BOOT_CMD(
hello, CFG_MAXARGS, 1, do_hello,
"hello - just for test\n",
"hello, long help ................\n"
);
//这样就把这个结构体放在了命令段
4.将 hello_com.c 放到 linux 下的 UBOOT 源码的 common 目录。修改这个 common 目录下的 Makefile.直接在 OBJ 后面加上 cmd_hello.o 即可。
-----------------------------------------------------------------------
uboot移植要做的(较老的uboot)
1、在boards.cfg里面添加自己开发板的信息
xyd4412 arm armv7 xyd4412 samsung exynos
2、添加开发板的具体配置文件,可以直接拷贝tiny4412文件夹
cp board/samsung/tiny4412 / board/samsung/xyd4412 -r
3、创建include/configs/下面的开发板的头文件
cp include/configs/tiny4412.h include/configs/xyd4412.h
4、修改链接文件board/samsung/xyd4412/u-boot.lds 40行,指定为自己的路径。
board/samsung/xyd4412/libxyd4412.o (.text)
疑问点
uboot是不断更新的,因此老版本和新版本之间有些配置和编译细节会不一样。
比如:在uboot1.1.6的顶层makefile中包含了传给mkconfig脚本的参数,而在tiny4412用的uboot中把参数单独拎出来创建了一个boards.cfg,由mkconfig自己加载参数
为什么韦老师的要打补丁,而现在的uboot很少打补丁?
答:因为当时的uboot不支持韦老师的开发板,因为要在uboot中做巨大的修改,现在的uboot支持各种单板。
新uboot配置宏观步骤:
1.支持make menuconfig (太麻烦)
2.直接修改厂家提供的xxx_deconfig 为.config
3.直接make,可能要加ARCH = arm.
新uboot完全分析与移植
很复杂,比老版uboot复杂的多,只了解过程即可。
打印Makefile的规则和变量:`make -p`
可以把make命令规则和变量存入文件:`make -p > 1.txt`
然后执行`vi 1.txt`,使用vi命令删除注释:`:g/^#/d`
配置u-boot的过程
IMX6ULL:make mx6ull_14x14_evk_defconfig
执行结果:
- 制作工具:scripts/kconfig/conf
- 把默认配置信息、Kconfig信息写入文件".config"
来自顶层makefile,当make mx6ull…之后的依赖关系
wmx6ull_14x14_evk_defconfig: scripts/kconfig/conf
$(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
就是执行:
scripts/kconfig/conf
参数1
--defconfig=arch/../configs/mx6ull_14x14_evk_defconfig Kconfig
参数2 参数3
所以要分析scripts/kconfig/conf 这个工具看这个工具做了什么事情,在conf.c 文件中
defconfig_file = "arch/../configs/mx6ull_14x14_evk_defconfig";
name = "Kconfig"
conf_parse(name); // 解析uboot根目录下的Kconfig文件 得到依赖关系
conf_read(defconfig_file); // 读默认配置文件
conf_set_all_new_symbols(def_default); // 设置new_symbols为默认值
conf_write(NULL); // 写到.config
-
Kconfig:这是一个通用文件,里面规定了一些依赖,比如:
- 如果是ARM架构,就默认选中A、B、C配置
- 如果是RISC-V架构,就默认选中a、b、c配置
-
defconfig_file:这是厂家提供的,里面定义了
- ARM架构
- 自己的一些配置项
-
怎么处理呢?
- 使用defconfig_file的内容去解析Kconfig,确定各个依赖的配置项
- 其他未涉及的配置项,给它们指定默认值
- 写入.config
在.config中包含了架构、单板相关
CONFIG_SYS_ARCH="arm" CONFIG_SYS_CPU="armv7" CONFIG_SYS_SOC="mx6" CONFIG_SYS_VENDOR="freescale" CONFIG_SYS_BOARD="mx6ullevk" CONFIG_SYS_CONFIG_NAME="mx6ullevk"
make后再执行make distclean后,删除以下文件
如果只是make mx6ull_14x14_evk_defconfig,一些文件是找不到的,所以有些文件是make编译后才生成的,比如include/config.h、u-boot.cfg、include/generated 目录。
uboot编译体验
make 过程
-
检查更新头文件和生成,比如include/config.h、u-boot.cfg
-
制作工具
-
交叉编译
。编译哪些目录、文件?
。C文件可能需要使用.config的配置值,在哪里使用呢,如下图?
如何使用.config 来决定编译哪些文件、目录?
分析顶层makefile
精简的Makefile
PHONY := _all
_all:
_all: all
KCONFIG_CONFIG ?= .config
# 定义一些常用变量
# 比如
# build := -f $(srctree)/scripts/Makefile.build obj
include scripts/Kbuild.include
# 定义交叉编译工具链
CC = $(CROSS_COMPILE)gcc
-include include/config/auto.conf #这里包含了一些暂时没有的文件,在下面生成
-include include/config/auto.conf.cmd
$(KCONFIG_CONFIG) include/config/auto.conf.cmd: ;
include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.autoconf || \
{ rm -f include/config/auto.conf; false; }
$(Q)touch include/config/auto.conf
-include include/autoconf.mk
-include include/autoconf.mk.dep
# 里面又包含架构相关、CPU相关的文件
# sinclude $(srctree)/arch/$(ARCH)/config.mk # include architecture dependend rules
# sinclude $(srctree)/$(CPUDIR)/config.mk # include CPU specific rules
include config.mk
# 架构相关参数、相关文件、库
# head-y := arch/arm/cpu/$(CPU)/start.o
# libs-y += arch/arm/cpu/$(CPU)/
include arch/$(ARCH)/Makefile
# 确定链接脚本
ifndef LDSCRIPT
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(srctree)/board/$(BOARDDIR)/u-boot.lds
endif
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(srctree)/$(CPUDIR)/u-boot.lds
endif
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(srctree)/arch/$(ARCH)/cpu/u-boot.lds
endif
endif
# 默认要处理的库的路径
libs-y += lib/
libs-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/
libs-$(CONFIG_OF_EMBED) += dts/
libs-y += fs/
libs-y += net/
libs-y += disk/
libs-y += drivers/
# 取决于配置的库的路径
libs-$(CONFIG_FMAN_ENET) += drivers/net/fm/
libs-$(CONFIG_SYS_FSL_DDR) += drivers/ddr/fsl/
libs-$(CONFIG_SYS_FSL_MMDC) += drivers/ddr/fsl/
libs-$(CONFIG_ALTERA_SDRAM) += drivers/ddr/altera/
u-boot-init := $(head-y)
u-boot-main := $(libs-y)
u-boot-dirs := $(patsubst %/,%,$(filter %/, $(libs-y))) tools examples
$(sort $(u-boot-init) $(u-boot-main)): $(u-boot-dirs) ;
$(u-boot-dirs): prepare scripts
$(Q)$(MAKE) $(build)=$@
# all目标要生成的依赖
ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map binary_size_check
all: $(ALL-y)
u-boot.hex u-boot.srec: u-boot FORCE
$(call if_changed,objcopy)
u-boot: $(u-boot-init) $(u-boot-main) u-boot.lds FORCE
$(call if_changed,u-boot__)
ifeq ($(CONFIG_KALLSYMS),y)
$(call cmd,smap)
$(call cmd,u-boot__) common/system_map.o
endif
可以得出,在编译之前makefile还要生成auto.conf 文件,因此需要处理:
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.autoconf
第1个操作相当于:make silentoldconfig,生成了文件
*** include/config/auto.conf:来自.config,去掉了很多注释***
- include/config/auto.conf.cmd:auto.conf的依赖规则
- include/generated/autoconf.h:内容跟auto.conf类似,是C语言的头文件
- include/config/tristate.conf:空文件
- include/generated/autoksyms.h:空文件
第2个操作相当于make -f scripts/Makefile.autoconf
,会生成一系列头文件:
ln -fsn arch-mx6 arch/arm/include/asm/arch
- include/autoconf.mk, {spl,tpl}/include/autoconf.mk
- include/config.h
配置过程总结
前面生成了.config,但是它不是最终版本的配置文件。u-boot.cfg 是配置的集大成者。u-boot.cfg来自:
-
.config
-
头文件include/common.h,又包含了"#include <config.h>"
编译过程
生成各种文件之后,开始进行编译。
U-boot 的重要数据结构(了解)
gd 全局数据变量指针
它保存了 u-boot 运行需要的全局数据,类型定义:
typedef struct global_data
{
bd_t *bd; //board data pointor 板子数据指针
unsigned long flags; //指示标志,如设备已经初始化标志等。
unsigned long baudrate; //串口波特率
unsigned long have_console; /* 串口初始化标志*/
unsigned long reloc_off; /*重定位偏移,就是实际定向的位置与编译连接时指定的
位置之差,一般为 0 */
unsigned long env_addr; /* 环境参数地址*/
unsigned long env_valid; /* 环境参数 CRC 检验有效标志 */
unsigned long fb_base; /* base address of frame buffer */
\#ifdef CONFIG_VFD
unsigned char vfd_type; /* display type */
\#endif
void **jt; /* 跳转表,1.1.6 中用来函数调用地址登记 */
} gd_t;
bd 板子数据指针
板子很多重要的参数。 类型定义如下:
typedef struct bd_info
{
int bi_baudrate; /* 串口波特率 */
unsigned long bi_ip_addr; /* IP 地址 */
unsigned char bi_enetaddr[6]; /* MAC 地址*/
struct environment_s *bi_env;
ulong bi_arch_number; /* unique id for this board */
ulong bi_boot_params; /* 启动参数地址 */
struct /* RAM 配置 */
{
ulong start;
ulong size;
}bi_dram[CONFIG_NR_DRAM_BANKS];
} bd_t;
串口波特率
unsigned long have_console; /* 串口初始化标志*/
unsigned long reloc_off; /重定位偏移,就是实际定向的位置与编译连接时指定的
位置之差,一般为 0 /
unsigned long env_addr; / 环境参数地址/
unsigned long env_valid; /* 环境参数 CRC 检验有效标志 /
unsigned long fb_base; / base address of frame buffer /
#ifdef CONFIG_VFD
unsigned char vfd_type; / display type */
#endif
void *jt; / 跳转表,1.1.6 中用来函数调用地址登记 */
} gd_t;
## **bd** **板子数据指针**
板子很多重要的参数。 类型定义如下:
```c
typedef struct bd_info
{
int bi_baudrate; /* 串口波特率 */
unsigned long bi_ip_addr; /* IP 地址 */
unsigned char bi_enetaddr[6]; /* MAC 地址*/
struct environment_s *bi_env;
ulong bi_arch_number; /* unique id for this board */
ulong bi_boot_params; /* 启动参数地址 */
struct /* RAM 配置 */
{
ulong start;
ulong size;
}bi_dram[CONFIG_NR_DRAM_BANKS];
} bd_t;