注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

学习笔记

正确的方法如同学习书法,开始的时候要临摹,临摹好了然后创造自己的风格。

 
 
 

日志

 
 

[DM814x笔记]u-boot的启动流程  

2012-11-18 23:35:12|  分类: TI_8148 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

1.   两个阶段的u-boot设计

TI814x的内部RAM大小是128K,其中底部的18KBROM代码所占用。其它的110KB的空间则预留给u-bootu-bootROM拷贝到内部RAM中运行。U-Boot在执行期间还需要一些空间给堆、栈和全局数据。这些区间目前必须在U-BootTEXT_BASE之前设置。

除掉分配给堆、栈等的空间,既然不能将所有的功能都压缩在<110KBU-Boot中,那就只好采用两个阶段了。

第一个阶段(如果考虑ROM的话就是第二个阶段)的编译使用的是最小的配置并且还有嵌入式ENV。这个阶段主要是用来初始化必要的外设,尤其是DDR,以便完整的、功能完善的U-Boot可以从NAND/SPI/SD/UART/NOR等拷贝到DDR中,然后将控制权交给完整功能的U-Boot

对于特定的启动模式,只要电路板相同,minimal U-Boot使用的用于获取完整U-Boot的启动代码就是固定的。如果有其他的需求可以在minimal U-Boot阶段将其打断并使用不同的命令。

minimal U-Boot在顶部也有空间用于堆、栈和全局数据,经分析这些空间的大小为12KB

注意:为了避免覆盖U-Boot的代码,在下载Kernel和文件系统时,地址要大于0x80800000

2.   执行过程

u-boot的使用一般需要使用命令:make ti8148_evm_min_nand,进行相关配置。make u-boot.ti,编译镜像。查看顶层目录下的Makefile,在执行make ti8148_evm_min_nand时,会执行如下动作:

ti8148_evm_min_nand: unconfig

@mkdir -p $(obj)include

@echo "#define CONFIG_TI81XX"  >>$(obj)include/config.h

@echo "#define CONFIG_TI814X"   >>$(obj)include/config.h

echo "TEXT_BASE = 0x80700000" >> $(obj)board/ti/ti8148/config.tmp; \

 

echo "#define CONFIG_TI814X_MIN_CONFIG" >>$(obj)include/config.h ; \

echo "#define CONFIG_NO_ETH"    >>$(obj)include/config.h ; \

echo "Setting up TI8148 minimal build for 1st stage..." ; \

echo "#define CONFIG_NAND_BOOT">>$(obj)include/config.h ;\

echo "#define CONFIG_SYS_NO_FLASH" >> $(obj)include/config.h ;\

echo "TI_IMAGE = u-boot.min.nand" >> $(obj)board/ti/ti8148/config.tmp;\

@$(MKCONFIG) -a ti8148_evm arm arm_cortexa8 ti8148 ti ti81xx

ti8148_evm_config_nandunconfig

       @mkdir -p $(obj)include

       @echo "#define CONFIG_TI81XX"   >>$(obj)include/config.h

       @echo "#define CONFIG_TI814X"    >>$(obj)include/config.h

       echo "TEXT_BASE = 0x80700000" >> $(obj)board/ti/ti8148/config.tmp;\

 

       echo "#define CONFIG_TI_DUMMY_HEADER" >>$(obj)include/config.h; \

       echo "TI_IMAGE = DUMMY" >> $(obj)board/ti/ti8148/config.tmp;\

       echo "#define CONFIG_SYS_NO_FLASH" >> $(obj)include/config.h ; \

       echo "#define CONFIG_NAND_ENV"    >>$(obj)include/config.h ; \

       echo "Setting up TI8148 default build with ENV in NAND..." ; \

@$(MKCONFIG) -a ti8148_evm arm arm_cortexa8 ti8148 ti ti81xx

unconfig是一个伪目标,从它的名字就可以知道是用来清除配置文件,其具体执行的动作如下所示:

unconfig:

       @rm -f $(obj)include/config.h $(obj)include/config.mk \

              $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp \

              $(obj)include/autoconf.mk $(obj)include/autoconf.mk.dep

然后会将一些宏定义拷贝到include/config.h文件中,该文件又会被include/common.h引用,所以只需要包含include/common.h即可,比较特殊的是#define CONFIG_SYS_NO_FLASH,表示不使用flash,如果目标是ti8148_evm_config_nand,则会定义CONFIG_NAND_ENV,在include/configs/ti8148evm.h中会判断如果有CONFIG_NAND_ENV,则取消CONFIG_SYS_NO_FLASH;还会将一些变量,比如TEXT_BASE添加到文件board/ti/ti8148/config.tmp中,该文件被包含进相应的board/ti/ti8148/config.mk中。

$(MKCONFIG)就是根目录下的mkconfig文件,所以上面执行make ti8148_evm_min_nand的结果就是执行:

./mkconfig -a ti8148_evm arm arm_cortexa8 ti8148 ti ti81xx

mkconfig的第六行,给出了各个参数的含义:

# Parameters:  Target  Architecture  CPU  Board [VENDOR] [SOC]

-a参数,表示令APPEND=yes,从而重新建立include/config.h文件。

总结起来,配置命令make ti8148_evm_min_nand,实际的作用是执行了“./mkconfig -a ti8148_evm arm arm_cortexa8 ti8148 ti ti81xx”。假设执行“./mkconfig –a $1 $2 $3 $4 $5 $6命令,则将产生如下结果。

1)开发板的名称BOARD_NAME等于$1

2)创建到平台/开发板相关的头文件链接,将ln –s arch/arm/include/asm include/asmln –s include/asm/arch-ti81xx include/asm/archln –s include/asm/proc-armv include/asm/proc如下所示,处于目录include下,LNPREFIX为空:

ln -s ../arch/$2/include/asm asm

if [ -z "$6" -o "$6" = "NULL" ] ; then

       ln -s ${LNPREFIX}arch-$3 asm/arch

else

       ln -s ${LNPREFIX}arch-$6 asm/arch

fi

if [ "$2" = "arm" ] ; then

       rm -f asm/proc

       ln -s ${LNPREFIX}proc-armv asm/proc

fi

(3)创建顶层文件Makefile包含的文件include/config.mk,其内容为:

ARCH   = arm

CPU    = arm_cortexa8

BOARD  = ti8148

VENDOR = ti

SOC    = ti81xx

4)包含开发板相关的头文件include/config.h,如下所示:

# Assign board directory to BOARDIR variable

if [ -z "$5" -o "$5" = "NULL" ] ; then

    BOARDDIR=$4

else

    BOARDDIR=$5/$4

fi

cat << EOF >> config.h

#define CONFIG_BOARDDIR board/$BOARDDIR

#include <config_defaults.h>

#include <configs/$1.h>

#include <asm/config.h>

EOF

其实际内容如下所示:

/* Automatically generated - do not edit */

#define CONFIG_BOARDDIR board/ti/ti8148

#include <config_defaults.h>

#include <configs/ti8148_evm.h>

#include <asm/config.h>

从这四个结果可知,如果要在board目录下建立一个开发板<board_name>的目录,则在include/configs目录下也要建立一个<board_name>.h的文件,里面存放的就是开发板<board_name>的配置信息。

Makefile中对u-boot(-min)的最终执行的起始地址TEXT_BASE=0x80700000,而在board/ti/ti8148/config.mk中则指定了ROM代码将镜像载入到什么地址,TI_DEVICE = ti81xxTI_LOAD_ADDR=0x40300000OCMC RAM)。其内容如下:

sinclude $(OBJTREE)/board/$(BOARDDIR)/config.tmp

# This will be used by mkimage extension to select header for image

TI_DEVICE = ti81xx

# ROM code will load u-boot to this address

TI_LOAD_ADDR = 0x40300000

# TEXT_BASE for the 2 stages is different and comes from the Makefile

CROSS_COMPILE:= arm-none-linux-gnueabi-

LDSCRIPT:=board/ti/ti8148/u-boot.lds

       查阅tms320dm8148芯片手册的2.12.1 L3 Memory Map小节,0x40300000~0x4031FFFF的地址为OCMC SRAM,大小为128K0x80000000~0xFFFFFFFF2G大小的DDR

A branch instruction (ldr  pc, _start_armboot,跳转到C语言处)(0xe51ff004) gets stuffed into the beginning of the image along with the address to which it will branch. The address to which it branches is based off the entry point (TI_LOAD_ADDR) plus an offset to allow for stack.

3.   关键的文件和符号

    Makefile

l        用于构建u-boot(-min)的主要规则,位于名字“ti8148_evm_*”下。

l        在该规则里定义了TEXT_BASE,指定了u-boot(-min)最终会从何处执行。如果u-boot被载入到一个不同的地址(例如,在很多启动模式中)这时,代码会将自身重定向到TEXT_BASE指定的地址处。

l        当构建u-boot-min时,make目标应指定为“u-boot.ti”u-boot.ti目标在该文件中定义。特别的,它会使用定制的类型“tiimage”调用mkimage,相关的代码位于tools/tiimage.c中。

    board/ti/ti8148/config.mk

l        TI_LOAD_ADDR指定了ROMimage载入到何处

l        特别地,你将看见TI_LOAD_ADDR = 0x40300000 (OCMC RAM)

    tools/tiimage.c

l        mkimage生成“u-boot.ti”类型的镜像使用的代码和u-boot-min一样。(Code utilized by mkimage for the "u-boot.ti" type image as utilized by u-boot-min.

l        mkimage阶段,函数ti814ximage_set_header()会添加一个TI-defined的头到u-boot二进制中。头以"GP Device image format"开始,并会被ROM查找到。his consists of size, destination, and the image itself. The image itself is also manipulated slightly. 一条分支语句(0xe51ff004)连同在何处分支的地址一起塞入到image的开头处。在何处分支是由入口点(TI_LOAD_ADDR)加上用于堆的偏移(he address to which it branches is based off the entry point (TI_LOAD_ADDR) plus an offset to allow for stack.)。

arch/arm/cpu/arm_cortexa8/u-boot.lds

l        (链接文件)指定链接文件的第一部分是start.o,即start.S

arch/arm/cpu/arm_cortexa8/start.S,在顶层的MakefileOBJS  = $(CPUDIR)/start.o

l        包含了复位向量(标签为_start),包含了“reset”分支。

l        reset”代码调用cpu_init_crit(),包含了Cortex-A8特有的代码

l        cpu_init_crit()代码调用lowlevel_init(包含特有的设备代码)

arch/arm/cpu/arm_cortexa8/ti81xx/lowlevel_init.S,设置存储控制器,初始化内存芯片,使它可用。

l        包含GPMC的初始化代码

l        调用board/ti/ti8148/evm.c中的s_init()

board/ti/ti8148/evm.c

l        包含s_init()代码,设置PLLsDDR(只有从SRAM中运行时)、引脚复用。

4.   U-Boot生成的中间文件解释

U-Boot在编译第一阶段的过程中会生成一些中间文件。以编译生成u-boot.min.sd为例,在编译的最后阶段会出现如下信息。

arm-none-linux-gnueabi-objcopy --gap-fill=0xff -O binary u-boot u-boot.bin

tools/mkimage -T tiimage \

  -e 0x40300000 -n ti81xx -d u-boot.bin u-boot.min.sd

       --gap-fill=0xff

在段与段之间使用0xff来填充空隙,该操作主要应用于段的载入地址(LMA),使用低地址来增加段的大小,并且用0xff来填充额外的空间。

objcopy解释:可查看man手册

       使用输出的目标二进制文件(例如:使用-O binary),可以用来生成一个原始的二进制文件。objcopy can be used to generate a raw binary file by using an output target of binary (e.g., use -O binary).

objcopy生成一个原始的二进制文件时,它会根据输入的目标文件产生一些必要的内存转储。所有的符号和重定向信息都会被丢弃。When objcopy generates a raw binary file, it will essentially produce a memory dump of the contents of the input object file.  All symbols and relocation information will be discarded.

内存转储会从复制到输出文件的最低段的导入地址开始。The memory dump will start at the load address of the lowest section copied into the output file.

文件名

解释

生成方法

u-boot

带有符号、重定向信息的elf格式的可执行文件。需解释器解释

首先编译生成

u-boot.bin

raw file)可执行文件的转储映像,去掉了符号、重定向信息,也没有起始地址和地址信息,空洞会填充信息。无需解释器

objcopy生成

u-boot.min

u-boot.bin的基础上添加一个头部信息,该头部信息包含了起始的加载地址,ROM会剥离该地址,然后加载到相应地址执行

mkimage工具生成

5.   启动的时间线

①从ROM启动

l        设置时钟

l        检测启动模式

②对于“memory booting”(NANDSD等),ROM代码会查找一个imageimage头部应该包含sizedestination和实际的code/data

l        ROM代码所查找的image在编译构建的过程中通过mkimage步骤完成

l        mkimage步骤会自动计算size大小

l        destination通过TI_LOAD_ADDR指定

③启动ROM会复制“size”大小的数据到“destination”并跳转到“destination”执行。

④在“destination”中执行的第一条语句是分支指令,会跳转到reset。(该分支指令在这里进行填充,并作为mkimage步骤中的tiimage进程的一部分)

⑤现在,汇编函数开始执行:

reset(arch/arm/cpu/arm_cortexa8/start.S)

->cpu_init_crit(arch/arm/cpu/arm_cortexa8/start.S)

 -->lowlevel_init(arch/arm/cpu/arm_cortexa8/ti81xx/lowlevel_init.S)

  --->s_init(board/ti/ti8148/evm.c)

 -->lowlevel_init(arch/arm/cpu/arm_cortexa8/ti81xx/lowlevel_init.S)

->cpu_init_crit(arch/arm/cpu/arm_cortexa8/start.S)

reset(arch/arm/cpu/arm_cortexa8/start.S)

reset函数会将代码从TI_LOAD_ADDR重定向到TEXT_ADDR

reset函数会跳转到分支C函数“start_armboot”,位于重定向的地址里,定义在函数arch/arm/lib/board.c中。

⑧调用预先定义在init_sequence数组中的初始化函数。包括基本的arch cpu依赖性的设置arch_cpu_init;板级依赖设置board_init;设置中断interrupt_init;初始化定时器timer_init;获取时钟get_clocks;初始化环境env_init;初始化波特率设置init_baudrate;初始化串口通信serial_init;初始化stage 1的控制台console_init_f;显示当前位置display_banner;显示cpu信息print_cpuinfo;显示板信息;配置RAM dram_init;显示RAM配置display_dram_config

⑨调用后续的初始化函数:内存初始化mem_malloc_initnand初始化nand_init;环境参数重定向env_relocate;串口初始化(有多个串口)serial_initialize;获取IP地址getenv_IPaddr;完全地初始化终端为一个设备console_init_r;使能中断enable_interrupts;获取mac地址eth_getenv_enetaddr;网络初始化eth_initialize;进入main_loop循环。

如果设置了环境参数bootdelaybootcmd,在bootdelay秒内串口无输入,通过函数if (bootdelay >= 0 && s && !abortboot (bootdelay))来实现。abortboot会打印提示信息“Hit any key to stop autoboot: %2d”;如果被打断,则执行readline函数来读取命令,并通过函数run_command来执行命令,run_command又调用common/command.c中的函数find_cmd来查找__u_boot_cmd_start __u_boot_cmd_end之间的cmd_tbl_t结构并运行它代表的命令,这些结构使用宏U_BOOT_CMD定义。而arch/arm/cpu/arm_cortexa8/u-boot.lds中则定义了__u_boot_cmd_start__u_boot_cmd_end

 

6.   Reference:

DM814x AM387x PSP U-Boot.pdf

http://processors.wiki.ti.com/index.php/Understanding_u-boot-min_startup_for_DM814x

 嵌入式Linux应用开发完全手册 韦东山

  评论这张
 
阅读(5983)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018