U-Boot是什么?

UBOOT可以理解为单片机程序。UBOOT目标就是启动内核:从flash上读出内核到SDRAM中去。硬件相关的初始化:关看门狗,初始化时钟“,”初始化SDRAM“,”从flash读出内核“,”启动内核“。

补丁文件中修改过的代码:

“---”表示是原来的代码

“+++”表示修改过的代码

UBOOT的源码中的readme文档中说要先配置再编译。

1.先配置 make xx_config:在Makefile中搜索100ask24x0_config

2.make

UBOOT源码结构:

UBOOT-1.1.6的基础上进行分析和移植。UBOOT-1.1.6根目录下共有26个子目录,可以分为四类:

1.平台相关或开发板相关的

2.通用的函数

3.通用的设备驱动程序

4.UBOOT工具,示例程序,文档

U-BOOT-LMLPHP

 

UBOOT配置过程:

执行make smdk2410_config

U-BOOT-LMLPHP

在顶层makefile中查找

U-BOOT-LMLPHP

 $(@:_config=)的作用就是将smdk2410_config中的config去掉,结果为smdk2410

执行make smdk2410_config实际上就是执行:

./mkconfig smdk2410 arm arm920t smdk2419 NULL s3c24x0

再来看看mkconfig的作用:配置参数。

打开mkconfig文件,阅读源码。

U-BOOT-LMLPHP

 对于传入的参数中并没有“--”,“-a”,“-n”等参数,所以这段代码没有执行。

U-BOOT-LMLPHP

$#统计参数个数,这里传入的参数是6个。

U-BOOT-LMLPHP

这里的SRCTREE和OBJTREE是相同的。执行else分支代码

进入include目录,删除asm目录,然后再次建立asm文件,并令它链接向asm-$2目录,即asm-arm。(这样可以根据输入参数的不同,动态配置文件)

U-BOOT-LMLPHP

 对于“./mkconfig smdk2410 arm arm920t NULL s3c24x0”命令,$6为“s3c24x0”不为空,也不是NULL,所以执行else分支。

接下来重新建立 asm-arm/proc文件,并让它链接向proc-armv目录。

U-BOOT-LMLPHP

创建config.mk文件。

>表示新建一个文件,>>表示追加内容进文件。

总结一下:配置命令"make smdk24x0_config",实际的作用就是执行“./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0”命令。假设执行"./mkconfig $1 $2 $3 $4 $5 $6"命令,将产生如下结果

1.开发板名称 BOARD_NAME=$1

2.根据输入参数动态创建对应平台/开发板相关头文件的链接

ln -s asm-$2 asm

ln -s arch-$6 asm-$2/arch

ln -s proc-armv asm-$2/proc    #如果$2不是arm,此行没有

3.创建顶层Makefile包含的文件inlcude/config.mk

ARCH =$2

CPU =$3 ...

4.创建开发板相关的头文件include/config.h

#include <config/$1.h>

配置文件中有以下两类宏。

1.一类是选项(Options),前缀为“COFIG_”,它们用于选择CPU,SOC,开发板类型,设置系统时钟,选择设备驱动等。

U-BOOT-LMLPHP

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

U-BOOT-LMLPHP

U-Boot的编译和链接过程:

配置完成后,执行“make all”即可编译。打开Makefile中与ARM相关的部分。

U-BOOT-LMLPHP

all:依赖于$(ALL)。而ALL中需要生成的u-boot.bin

U-BOOT-LMLPHP

U-BOOT-LMLPHP

从make之后的信息可以知道,编译的

第一个文件是cpu/arm920t/start.S .链接地址:board/100ask24x0/u-boot.lds+0x33F80000.

总结一下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.第三步得到的是ELF格式的U-Boot,后面Makefile还会将它转换为二进制格式

 

U-Boot第一阶段代码分析:

1.设scv模式

2.关看门狗

3.屏蔽中断

4.初始化SDRAM

5.设置栈

6.设置时钟

7.代码:flash重定位到SDRAM

8.清BSS段

9.调用C函数 ==>开始第二阶段

U-Boot第二阶段代码分析:

U-BOOT-LMLPHP

U-BOOT-LMLPHP

 

uboot中核心命令:

U-Boot命令的格式(一个宏定义):

U-BOOT-LMLPHP

name:命令的名字,注意,它不是字符串(不要用双引号括起来)

maxargs:最大的参数个数

repeatable:命令是否可重复

command:对应的函数指针,类型为(*cmd)(struct cmd_tbl_s*,int,int,char*[])

usage:简短的使用说明

help:较详细的使用说明,这是个字符串。

U-BOOT-LMLPHP

对于每个使用U-Boot_CMD宏来定义的命令,其实都是在“.u_boot_cmd”段中定义一个cmd_tbl_t结构。程序就是根据命令的名字,在_u_boot_cmd_start 和_u_boot_cmd_end找到它的cmd_tbl_t结构,然后调用它的函数。

 

 

s=getenv("bootcmd")

run_commadn(s..)

2.uboot界面:

readline(独去串口数据)

run_command(s..)

nand read.jffs2 0x30007FC0 kernel;

从NAND读出内核: 从哪里读 --------kernel

                                 放到哪里去?---0x30007FC0

bootm 0x30007FC0==>启动内核

FLASH存的内核称为Uimage :==>头部加上真正的内核。

头部:U-BOOT-LMLPHP

in_load(加载地址): 内核加载到内存的地址就是加载地址

in_ep(入口地址):    运行内核的地址

ps(程序永远是从‘0’地址开始运行的)

 

启动内核

1.设置启动参数:在某个地址按照某种格式存放数据(uboot和内核去约定好)(地址是:0x30000000;格式是:tag)

2.跳到头部设立的入口地址

Linux2.4.x以后的内核都期望以标记列表(tagged list)的形式来传递启动参数。标记,就是一种数据结构;标记列表,就是挨个存放着的多个标记。标记列表以标记ATAG_CORE开始,以ATAG_NONE结束。

 标记的数据结构为tag,它由一个tag_header结构和一个联合(unino)组成。tag_header结构表示标记的类型和长度,比如是表示内存还是命令行参数。对于不同类型的标记使用不同的联合(union),比如表示内存时使用tag_mem32,表示命令行时使用tag_cmdline。

U-BOOT-LMLPHP

U-BOOT-LMLPHP

下面以设置ATAG_CORE标记为例说明参数的传递

标记列表以标记ATAG_CORE为开始,假设Bootloader与内核约定的参数存放地址为0x30000100

U-BOOT-LMLPHP

 

s=getenv("bootcmd") //获取环境变量

run_command(s) //

 

 

10-04 09:46