参考http://blog.csdn.net/skyflying2012/article/details/25804209

这里以imx6平台为例,分析uboot启动流程
对于任何程序,入口函数是在链接时觉得的,uboot的入口是由链接脚本决定的.uboot下armv7链接脚本默认目录为arch/arm/cpu/u-boot.lds.这个可以在配置文件中与CONFIG_SYS_LDSCRIPT来指定

1.由于imx6dl芯片属于armv7架构,在arch/arm/cpu/目录下,通过分析链接脚本u-boot.lds代码段.text可知:可执行程序的入口是_start
2._start在arch/arm/lib/vectors.S中,然后vectors.S中有跳转到reset函数,reset函数在arch/arm/cpu/armv7/start.S中,.....,待一系列硬件初始化后,跳转到_main函数执行
3.ARM32平台的_main位于arch/arm/lib/crt0.S中
4.crt0是C-runtime Startup Code的简称,意思就是运行C代码之前的准备工作.关于_main函数,crt0.S有详细注释:
1).设置C代码的运行环境,为调用board_init_f接口做准备
a)设置堆栈(C代码的函数调用,堆栈是必须的).如果当前的编译是SPL(由CONFIG_SPL_BUILD定义),可单独定义堆栈基址(CONFIG_SPL_STACK),否则,通过CONFIG_SYS_INIT_SP_ADDR定义堆栈基址.
b)调用board_init_f接口,从堆栈开始的地方,为u-boot中大名鼎鼎的GD('global data')数据结构,分配空间
c)调用board_init_f_init_reserve接口,对GD进行初始化
2).调用board_init_f函数,完成一些前期的初始化工作,例如:
a)点亮一个Debug用的LED灯,表示u-boot已经活了
b)初始化DRAM,DDR等system范围的RAM等
c)计算后续代码需要使用的一些参数,包括relocation destination,the future stack,the future GD location等.
3).如果当前是SPL(由CONFIG_SPL_BUILD控制),则_main函数结束,直接返回.如果是正常的u-boot,则继续执行后续的动作
4).根据board_init_f指定的参数,执行u-boot的relocation操作
5).清除BSS段
6).调用board_init_r函数,执行后续的初始化操作

4.crt0是C-runtime Startup Code的简称,意思就是运行C代码之前的准备工作.关于_main函数,crt0.S有详细注释:
1).设置初始化运行环境,为调用board_init_f()接口做准备
初始化运行环境仅仅设置堆栈并且为GD('global data')数据结构分配空间,这两者都位于一些已经可用的RAM(SRAM, locked cache...)空间.在这上下文,未初始化的全局变量或BSS段不能使用,只有初始化的常量可用
2).调用board_init_f()接口
该接口为系统的执行做好硬件准备.因为RAM还不能使用,board_init_f()必须使用当前的GD去存储一些数据,这些数据要传送到启动的下一阶段.这些数据包括relocation destination, the future stack, the future GD location
---------------------------------------------------------------------------
以下步骤仅仅适用于non-SPL builds(SPL是Secondary Program Loader的简称,之所以称作secondary,是相对于ROM code来说的.SPL是u-boot中独立的一个代码分支,由CONFIG_SPL_BUILD配置项控制,是为了在正常的u-boot image之外,提供一个独立的,小size的SPL image,通常用于那些SRAM比较小(或者其它限制),无法直接装载并运行整个u-boot的平台),即如果当前时SPL(由CONFIG_SPL_BUILD控制),则_main函数结束,直接返回.如果时正常的u-boot,则继续执行后续动作.
3).设置中间环境变量,board_init_f()函数在系统的RAM中为堆栈和GD申请空间,但是BSS段和非常量依然不可用.
4).调用relocate_code()接口
该接口通过board_init_f()接口,从当前地址到目的地址,重新定位u-boot
5).设置初始化最终的运行环境,为调用board_init_r()接口做准备
初始化运行环境包括初始化BBS段(初始化为0),初始化非常量数据(初始化成需要的值)和初始化系统RAM中堆栈.通过board_init_f()接口GD已被保留.除了内存的初始化,一些CPUs还有别的一些工作需要做,引出调用c_runtime_cpu_setup()接口
6).分支到board_init_r执行

imx6sabresd board uboot启动流程分析:
前面都相同,这里从_main(crt0.S)开始分析:
其中board_init_f接口imx6sabresd有自己的接口,该接口位于board/freescale/mx6sabresd/mx6sabresd.c中,具体做了如下初始化:
a.arch_cpu_init(),设置AIPS和关看门狗,位于arch/arm/cpu/armv7/mx6/soc.c中
b.ccgr_init(),初始化时钟模块ccm,位于board/freescale/mx6sabresd/mx6sabresd.c中
c.gpr_init(),初始化AXI,IPU,位于board/freescale/mx6sabresd/mx6sabresd.c中
d.board_early_init_f(),IOMUX(IO多路复用),设置i2c,位于board/fresscale/mx6sabresd/mx6sabresd.c中
e.timer_init(),设置系统的timer,位于arch/arm/imx-common/timer.c中
f.preloader_console_init(),串口时钟使能和控制台初始化,位于common/spl/spl.c中
g.spl_dram_init(),dram初始化,位于board/freescale/mx6sabresd/mx6sabresd.c中
h.memset(),清空bss段
i.board_init_r(),进入到后置的班级初始化

进入board_init_r接口,位于arch/arm/lib/board.c中,具体做了如下工作:
a.bootstage_mark_name(),登记boot启动阶段
b.enable_caches(),使能缓存
c.board_init(),具体的板级初始化,位于board/freescale/mx6sabresd/mx6sabresd.c中,具体又做了如下工作:setup_spi,setup_i2c,setup_usb,setup_epdc,setup_sata,setup_yaxon(加入自己想要做的工作,imx6电源LED灯显示)
d.set_cpu_clk_info(),初始化时钟框架
e.serial_initialize(),初始化串口
f.

进入main_loop():
a.bootstage_mark_name(),调用了show_boot_progress,利用它显示启动进程(progress),此处为空函数,这里未实现
b.modem_init(),这里未实现
c.setenv(),用于显示uboot版本号,编译日期和事件,以及时间,这些都由u-boot构建系统自动生成
d.cli_init(),初始化hush shell使用的一些变量
e.run_preboot_environment_command(),从环境变量中获取"preboot"的定义,该变量包含一些预启动命令,一般环境变量中不包含该项配置
f.bootdelay_process(),从环境变量中取出"bootdelay"和"bootcmd"的配置值,将取出的"bootdelay"配置值转换成整数,赋值给全局变量stored_bootdelay,最后返回"bootcmd"的配置值.bootdelay为u-boot的启动延时计数值,计数期间内如无用户按键输入干预,那么执行"bootcmd"配置中的命令(其实时执行返回字符串s配置的命令,我们可以通过返回不同的字符串来执行不同的启动命令)
g.由于没有定义CONFIG_OF_CONTROL宏,函数cli_process_fdt返回false,即不会执行cli_secure_boot_cmd()
h.进入autoboot_command(),stored_bootdelay != -1, s = "bootcmd", abortboot(stored_bootdelay)
进入stored_bootdelay,由于没有定义CONFIG_AUTOBOOT_KEYED(该宏用来使能用户名密码登录),直接调用abortboot_normal()
进入abortboot_normal(),在执行时间stored_bootdelay(秒)内,如无用户按键输入干预,那么abortboot_normal函数返回0,否则返回1.
由判断条件if (stored_bootdelay != 1 && s && !abortboot(stored_bootdelay))可知
若在计数期间无用户按键输入干预,那么abortboot(stored_bootdelay)返回0,即条件成立,执行run_command_list(s, -1, 0),该函数执行环境变量s("bootcmd")配置值.函数run_command_list调用hush shell命令解释器(parse_stream_outer函数),结束s("bootcmd")中的启动命令.环境变量s("bootcmd")中的启动命令,用来设置linux必要的启动环境,然后加载和启动linux内核.uboot启动linux内核后,将控制权交给linux内核,至此不再返回
否则有用户按键输入干预,abortboot(stored_bootdelay)返回1,即条件不成立,不执行任何操作,结束autoboot_command()函数,然后继续执行main_loop()函数中的cli_loop()函数,cli_loop()执行hush shell命令解释器(parse_file_outer函数),parse_file_outer函数进行必要的初始化后,也将调用hush shell命令解释器(parse_stream_outer函数)
static int parse_stream_outer(structin_str*inp,intflag)
{
do {
...
...
run_list(...);
} while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP) && //#define FLAG_EXIT_FROM_LOOP 1
(inp->peek != static_peek || b_peek(inp)));
}
parse_stream_outer()函数里有个do-while会循环命令解析器的"命令输入解析-执行"运行模式
其中run_list(...)执行如下函数调用流程:
run_list-->run_list_real-->run_pipe_real,最后在函数run_pipe_real中有return cmd_process(...),函数cmd_process最后完成u-boot命令的定位和执行
------------------------------------------------------------------------------------------------------------------------------------------
至此main_loop()分析完毕

-----------------------------------------------------------------------------------------------------------------------------------------
以下分析uboot命令执行,即cmd_process(...)函数,函数cmd_process在common/command.c文件中

-----------------------------------------------------------------------------------------------------------------------------------------
以下是项目中用来实现系统恢复策略方法:
目的:在uboot阶段通过检测硬件gpio的电平变化来实现uboot启动设置
方法:添加一个gpio电平检测函数,检测到电平变化通过修改传入给autoboot_command(s)函数参数s来改变uboot启动设置,所以具体到实施是要修改参数s,而参数s是通过bootdelay_process()函数来修改的

具体实施步骤:
由于原项目中emmc分区为4个分区(即par1(dtb, zImage), par2(rootfs), par3(user), par4(data)),所有我们需要重新分区, 分为6个分区(par1(zImage, dtb), par2(zImage, dtb, ramdisk.image.gz.uboot这三部分是为了启动最小系统, 跟u盘升级一样(把最小系统放在u盘里), 这里只是把最小系统放在emmc的第二个分区里), par3(zImage, dtb, rootfs.tar, user.tar, data.tar这些原厂设置的文件, 后面需要把他们依次解压到对应的分区), par4(rootfs), par5(user), par6(data)), 并且要修改uboot源码使其支持这个功能, 所有我们还得重新烧写uboot到emmc中
1.重新分为6个分区, 并把相应的文件(原厂设置的文件)烧写到对应分区
2.

uboot启动第一阶段,start.S文件在arch/arm/cpu/armv7/目录下

uboot启动第二阶段,board.c文件arch/arm/lib/目录下

imx6 uboot启动流程分析的更多相关文章

  1. u-boot启动流程分析(2)_板级(board)部分

    转自:http://www.wowotech.net/u-boot/boot_flow_2.html 目录: 1. 前言 2. Generic Board 3. _main 4. global dat ...

  2. Uboot启动流程分析(三)

    1.前言 在前面的文章Uboot启动流程分析(二)中,链接如下: https://www.cnblogs.com/Cqlismy/p/12002764.html 已经对_main函数的整个大体调用流程 ...

  3. Uboot启动流程分析(二)

    1.前言 在前面的文章Uboot启动流程分析(一)中,链接如下: https://www.cnblogs.com/Cqlismy/p/12000889.html 已经简单地分析了low_level_i ...

  4. Uboot启动流程分析(一)

    1.前言 Linux系统的启动需要一个bootloader程序,该bootloader程序会先初始化DDR等外设,然后将Linux内核从flash中拷贝到DDR中,最后启动Linux内核,uboot的 ...

  5. 嵌入式Linux驱动学习之路(五)u-boot启动流程分析

    这里说的u-boot启动流程,值得是从上电开机执行u-boot,到u-boot,到u-boot加载操作系统的过程.这一过程可以分为两个过程,各个阶段的功能如下. 第一阶段的功能: 硬件设备初始化. 加 ...

  6. u-boot启动流程分析(1)_平台相关部分

    转自:http://www.wowotech.net/u-boot/boot_flow_1.html 1. 前言 本文将结合u-boot的“board—>machine—>arch—> ...

  7. Uboot启动流程分析(转载)

    最近一段时间一直在做uboot移植相关的工作,需要将uboot-2016-7移植到单位设计的ARMv7的处理器上.正好元旦放假三天闲来无事,有段完整的时间来整理下最近的工作成果.之前在学习uboot时 ...

  8. am335x uboot启动流程分析

    基本指令含义 .globl _start .globl指示告诉汇编器,_start这个符号要被链接器用到,所以要在目标文件的符号表中标记它是一个全局符号 b,bl b是不带返回的跳转  bl带返回的跳 ...

  9. U-BOOT启动流程分析--start.s(二)

    一.概述 u-boot的启动流程: 从文件层面上看主要流程是在两个文件中:cpu/arm920t/start.s,lib_arm/board.c, 先来分析start.s    在flash中执行的引 ...

随机推荐

  1. DataRow 数组转化成DataTable

    #region 封装DataTable DataTable dt = null; if (newRows.Length > 0) { dt = newRows[0].Table.Clone(); ...

  2. CSS3: box-shadow 阴影

    box-shadow是给元素块添加周边阴影效果 语法: 对象选择器 {box-shadow:X轴偏移量 Y轴偏移量阴影 模糊半径 阴影扩展半径 阴影颜色 [投影方式] } box-shadow: h- ...

  3. windows server 2012将计算机图标添加到桌面(图文教程)(转)

    windows server 2012系统安装完以后桌面默认只有回收站一个图标,如何将window常用的图标(计算机.控制面板.网络.用户文件)的图标添加到桌面呢,下面为作者本人亲测.操作简单至极. ...

  4. Linux 内核参数 和 Oracle相关参数调整

    Linux 内核参数 和 Oracle相关参数调整 分类: Oracle Basic Knowledge2009-10-14 12:23 9648人阅读 评论(0) 收藏 举报 oraclelinux ...

  5. Python 获取图片文件大小并转换为base64编码

    import os import base64 fileSize = os.path.getsize(文件路径) with open(文件路径, 'rb') as f: data = base64.b ...

  6. 数据写入到TXT文档中

    public class FileWrite { public File file; public FileOutputStream stream = null; //每次写入都会覆盖之前的内容 pu ...

  7. 倍福TwinCAT(贝福Beckhoff)应用教程13.2 TwinCAT控制松下伺服 NC自定义直线插补

    对于MOVEJ的关节运动来说,我们只关心每个电机的角度(只需要考虑多个电机协同开始运动和结束运动,关键是对每个电机加速度均一化,从而一起跑一起停,这部分内容可以参考机器人学导论以获取更加详细的说明), ...

  8. C#秘密武器之反射——替换反射

    反射虽然有时很有必要,但是应用反射的代码大多“复杂难懂”.“性能不高”,因此我们可以找寻在一些场景下替换反射的方法.此处也只是一些栗子,更多巧妙的应用还是自己以后亲自查查~ 先来看看一个使用普通反射完 ...

  9. 【CI】系列二:Ubuntu环境虚拟机安装及配置

    好了,做好了初步计划之后,如果可行性没问题,就可以开始实践了. 准备前提:VirtualBox.ubunut镜像 如果没有,可以通过如下地址下载,安装过程此处不做描述. VirtualBox 4.3. ...

  10. vue - 安装脚手架

    最后不得不屈服与虚拟DOM和框架,太方便了... 1.首先安装node:点击进入官网. 2. 安装后检测 3. 安装yarn(至于为嘛,速度呗) yarn官网,npm转yarn. 3.1 window ...