imx6 uboot启动流程分析
参考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启动流程分析的更多相关文章
- u-boot启动流程分析(2)_板级(board)部分
转自:http://www.wowotech.net/u-boot/boot_flow_2.html 目录: 1. 前言 2. Generic Board 3. _main 4. global dat ...
- Uboot启动流程分析(三)
1.前言 在前面的文章Uboot启动流程分析(二)中,链接如下: https://www.cnblogs.com/Cqlismy/p/12002764.html 已经对_main函数的整个大体调用流程 ...
- Uboot启动流程分析(二)
1.前言 在前面的文章Uboot启动流程分析(一)中,链接如下: https://www.cnblogs.com/Cqlismy/p/12000889.html 已经简单地分析了low_level_i ...
- Uboot启动流程分析(一)
1.前言 Linux系统的启动需要一个bootloader程序,该bootloader程序会先初始化DDR等外设,然后将Linux内核从flash中拷贝到DDR中,最后启动Linux内核,uboot的 ...
- 嵌入式Linux驱动学习之路(五)u-boot启动流程分析
这里说的u-boot启动流程,值得是从上电开机执行u-boot,到u-boot,到u-boot加载操作系统的过程.这一过程可以分为两个过程,各个阶段的功能如下. 第一阶段的功能: 硬件设备初始化. 加 ...
- u-boot启动流程分析(1)_平台相关部分
转自:http://www.wowotech.net/u-boot/boot_flow_1.html 1. 前言 本文将结合u-boot的“board—>machine—>arch—> ...
- Uboot启动流程分析(转载)
最近一段时间一直在做uboot移植相关的工作,需要将uboot-2016-7移植到单位设计的ARMv7的处理器上.正好元旦放假三天闲来无事,有段完整的时间来整理下最近的工作成果.之前在学习uboot时 ...
- am335x uboot启动流程分析
基本指令含义 .globl _start .globl指示告诉汇编器,_start这个符号要被链接器用到,所以要在目标文件的符号表中标记它是一个全局符号 b,bl b是不带返回的跳转 bl带返回的跳 ...
- U-BOOT启动流程分析--start.s(二)
一.概述 u-boot的启动流程: 从文件层面上看主要流程是在两个文件中:cpu/arm920t/start.s,lib_arm/board.c, 先来分析start.s 在flash中执行的引 ...
随机推荐
- ZooKeeper服务器是用Java创建的,它在JVM上运行。
ZooKeeper服务器是用Java创建的,它在JVM上运行. 创建配置文件 使用命令 vi conf/zoo.cfg 和所有以下参数设置为起点,打开名为 conf/zoo.cfg 的配置文件. $ ...
- 小二助手(react应用框架)-概述
时间想学习一个前端框架,原因是这样的,我本身是做游戏的,但是自己对前端web比较感兴趣. 然后我就选择自己学哪个框架,Angular.react.vue 最后选择了react,选择的理由就不说了 那做 ...
- scrapy-splash抓取动态数据例子十
一.介绍 本例子用scrapy-splash抓取活动行网站给定关键字抓取活动信息. 给定关键字:数字:融合:电视 抓取信息内如下: 1.资讯标题 2.资讯链接 3.资讯时间 4.资讯来源 二.网站信息 ...
- 查看进程id, 父进程id _How do I get the parent process ID of a given child process?
How to get parent pid from a given children pid? I know I can mannully check it under /proc, I am wo ...
- dubbo方法调用的timeout设置
方法调用的默认超时时间为1s,但是具体的超时时间受限于服务端方法性能.服务端个数.客户端的并发数等因素,所以超时时间需要根据不同的场景进行调试. 基本步骤为: 测试服务端的TPS,单位为 任务数或线程 ...
- WCF调试异常信息:ServiceHost 仅支持类服务类型
"/CommonHelpServices"应用程序中的server错误. ServiceHost 仅支持类服务类型. 说明: 运行当前 Web 请求期间,出现未经处理的异常. 请检 ...
- 注册表 API 以及开机自启动
注册表是window系统中非常重要的一部分,今天在网上查了一些文章学习了下,觉得其中有一句话总结的很经典:注册表是用来存储信息的. 这句话虽然有点废,但是说的没错.当然,注册表中包含的内容非常多,远没 ...
- activiti入门3排他网关,并行网管,包括网关,事件网关
网关用来控制流程的流向 网关能够消费也能够生成token. 网关显示成菱形图形,内部有有一个小图标. 图标表示网关的类型. 基本分支 首先 利用 流程变量 写个带有分支的一个基本流程 流程图: wa ...
- Python 中实现装饰器时使用 @functools.wraps 的理由
Python 中使用装饰器对在运行期对函数进行一些外部功能的扩展.但是在使用过程中,由于装饰器的加入导致解释器认为函数本身发生了改变,在某些情况下——比如测试时——会导致一些问题.Python 通过 ...
- 经典SQL语句使用方法大全
一.基础1.说明:创建数据库CREATE DATABASE database-name2.说明:删除数据库drop database dbname3.说明:备份sql server--- 创建 备份数 ...