uboot分析

在这里插入描述以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 等的文件
examplesuboot示例代码
fs文件系统相关,linux系统移植而来的
include头文件目录。uboot和linux kernel在管理头文件时都采用了同一个思路,就是把所有的头文件全部集中存放在include目录下,而不是头文件跟着自己对应的c文件。所以在uboot中头文件包含时路径结构要在这里去找
lib各类算法库的实现,比如crc,aes bzip系列,这类文件夹中的内容移植时基本不用管
Licenses开源协议(BSD, GPL, LGPL,MIT)许可证书,uboot使用的开源许可协议
test测试程序
tools里面是一些工具类的代码。譬如mkimage
Makefileuboot的顶层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
  1. 创建顶层makefile包含的文件/include/config.mk

  2. 创建开发板相关的头文件/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;
  • 18
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值