09_Uboot启动流程_1

2023-11-13

目录

链接脚本u-boot.lds详解

U-Boot启动流程详解

 reset函数源码详解

lowlevel_init函数详解

s_init函数详解


链接脚本u-boot.lds详解

要分析uboot的启动流程,首先要找到“入口”,找到第一行程序在哪里。程序的链接是由链接脚本来决定的,所以通过链接脚本可以找到程序的入口。如果没有编译过uboot的话链接脚本为arch/arm/cpu/u-boot.lds。但是这个不是最终使用的链接脚本,最终的链接脚本是在这个链接脚本的基础上生成的。编译一下 uboot,编译完成以后就会在 uboot 根目录下生成 u-boot.lds文件,如图所示: 

 打开u-boot.lds内容如下:

 第3行为代码当前入口点:_start, _start在文件arch/arm/lib/vectors.S中有定义,如图所示:

 

从图中的代码可以看出, start后面就是中断向量表,从图中的".section ".vectors","ax"可以得到,此代码存放在.vectors段里面。

使用如下命令在uboot中查找“_image_copy_start”:

grep -nR"_image_copy_start"

 打开u-boot.map,找到如图所示位置:

 u-boot.map是uboot的映射文件,可以从此文件看到某个文件或者函数链接到了哪个地址,从图932行可以看到_image_copy_start为0X87800000,而.text的起始地址也是0X87800000

继续回到u-boot.lds示例代码中,第11行是vectors段,vectors段保存中断向量表,从图_start文件示例代码中我们知道了vectors.S的代码是存在vectors段中的。从图u-boot.map文件示例代码可以看出,vectors段的起始地址也是0X87800000,说明整个uboot的起始地址就是0X87800000。

第12行将arch/arm/cpu/armv7/start.s编译出来的代码放到中断向量表后面。

第13行为text段,其他的代码段就放到这里

在u-boot.lds中有一些跟地址有关的“变量”需要我们注意一下,后面分析u-boot源码的时候会用到,这些变量要最终编译完成才能确定的!!!比如我编译完成以后这些“变量”的值如表所示:

 表中的“变量”值可以在u-boot.map文件中查找,表中除了_image_copy_start,以外,其他的变量值每次编译的时候可能会变化,如果修改了uboot代码、修改了uboot配置、选用不同的优化等级等等都会影响到这些值。所以,一切以实际值为准!

 

U-Boot启动流程详解

 reset函数源码详解

u-boot.lds中我们已经知道了入口点是arch/arm/lib/vectors.S文件中的_start,代码如下: 

第35行就是reset 函数。

第37行从reset函数跳转到save_bootparams函数,而save_boot_params函数同样定义在start.S里面,定义如下:

第43行,读取寄存器cpsr中的值,并保存到r0寄存器中。

第44行,将寄存器r0中的值与Ox1F进行与运算,结果保存到r1寄存器中,目的就是提取cpsr的bit0-bit4这5位,这5位为M4 M3 M2 M1 M0, M[4:0]这五位用来设置处理器的工作模式,如表所示:

 

第45行,判断r1寄存器的值是否等于 0X1A(0b11010),也就是判断当前处理器模式是否处于 Hyp模式。

第46 行,如果r1和Ox1A不相等,也就是CPU不处于Hyp模式的话就将r0寄存器的bit0-5进行清零,其实就是清除模式位

第47行,如果处理器不处于Hyp模式的话就将r0的寄存器的值与0x13进行或运算,0x13=0b10011,也就是设置处理器进入SVC模式。

第48行, r0寄存器的值再与0xC0进行或运算,那么r0寄存器此时的值就是0xD3, cpsr的I为和F位分别控制IRQ和FIQ这两个中断的开关,设置为1就关闭了FIQ和IRQ!

第49行,将r0寄存器写回到cpsr寄存器中。完成设置CPU处于SVC模式,并且关闭FIQ和IRQ这两个中断。

继续执行执行下面的代码:

 

第56行,如果没有定义CONFIG_OMAP44XX和CONFIG_SPL_BUILD的话条件成立,此处条件成立。

第58行读取CP15中c1寄存器的值到r0寄存器中,这里是读取SCTLR 寄存器的值。

第59行,CR V在arch/arm/include/asm/system.h中有如下所示定义:

#define CR_V(1 << 13)/* Vectors relocated to 0xffff0000 */

因此这一行的目的就是清除SCTLR寄存器中的bit13, SCTLR寄存器结构如图所示:

 

从图可以看出,bit13为V位,此位是向量表控制位,当为0的时候向量表基地址为0X00000000,软件可以重定位向量表。为1的时候向量表基地址为0XFFFF0000,软件不能重定位向量表。这里将V清零,目的就是为了接下来的向量表重定位

第60行将r0寄存器的值重写写入到寄存器SCTLR 中。

第63行设置r0寄存器的值为_start,_start就是整个uboot的入口地址,其值为0X87800000,相当于uboot的起始地址,因此0x87800000也是向量表的起始地址。

第64行将r0寄存器的值(向量表值)写入到CP15的c12寄存器中,也就是VBAR寄存器。因此第58~64行就是设置向量表重定位的。

代码继续往下执行:

 

第68行如果没有定义CONFIG_SKIP_LOWLEVEL_INIT的话条件成立。我们没有定义CONFIG_SKIP_LOWLEVEL_INIT,因此条件成立,执行下面的语句。

示例代码中的内容比较简单,就是分别调用函数cpu_init_cp15、 cpu_init_crit和_main。

函数cpu_init_ep15用来设置CP15相关的内容,比如关闭MMU啥的,此函数同样在start.S文件中定义的,代码如下:

函数cpu_init_cp15都是一些和CP15有关的内容,我们不用关心,有兴趣的可以详细的看一下。

函数cpu init crit也在是定义在start.S文件中,函数内容如下:

可以看出函数cpu_init_crit内部仅仅是调用了函数lowlevel_init,接下来就是详细的分析一下lowlevel_init和_main这两个函数。 

lowlevel_init函数详解

函数lowlevel_init在文件arch/arm/cpu/armv7/lowlevel_init.S中定义,内容如下: 

 第22行设置sp指向CONFIG_SYS_INIT_SP_ADDR,CONFIG_SYS_INIT_SP_ADDR在include/configs/mx6ullevk.h文件中,在 mx6ullevk.h中有如下所示定义:

示例代码中的IRAM-BASE-ADDR和IRAM-SIZE在文

件.arch/arm/include/asm/arch-mx6/imx-regs.h中有定义,如下所示,其实就是IMX6UL/IM6ULL内部ocram的首地址和大小。

 

如果408行的条件成立的话IRAM_SIZE=0X40000,当定义了CONFIG_MX6SX、CONFIG_MX6U、CONFIG_MX6SLL和CONFIG_MX6SL中的任意一个的话条件就不成立,在.config中定义了CONFIG MX6UL,所以条件不成立,因此IRAM SIZE=0X20000-128KB,

结合示例代码,可以得到如下值:

CONFIG_SYS_INIT_RAM_ADDR = IRAM_BASE_ADDR = 0x00900000.

CONFIG_SYS_INIT_RAM_SIZE= 0x00020000 = 128KB

 还需要知道GENERATED_GBL_DATA_SIZE的值,在文件include/generated/generic-asm-offsets.h中有定义,如下:

 GENERATED_GBL_DATA_SIZE-256, GENERATED_GBL_DATA_SIZE的含义为(sizeof(struct global_data) + 15) & ~15。

综上所述,CONFIG_SYS_INIT_SP_ADDR值如下: 

CONFIG_SYS_INIT_SP_OFFSET= 0x00020000 - 256 = 0x1FF00

CONFIG_SYS_INIT_SP_ADDR = 0x00900000 + 0X1FF00 = 0x0091FF00,

 结果如下图所示:

 

此时sp指向0X91FF00,这属于IMX6UL/IMX6ULL的内部ram。

继续回到文件lowlevel_init.S,第23行对sp指针做8字节对齐处理!

第34行, sp指针减去GD_SIZE, GDSIZE同样在generic-asm-offsets.h中定了,大小为248,见示例代码generic-asm-offsets.h第11行。

第35行对sp做8字节对齐,此时sp的地址为0x0091FF00-248-0X0091FE08,此时sp位置如图所示:

第36行将sp地址保存在r9寄存器中。

第42行将ip和Ir压栈

第57行调用函数s_init,得,又来了一个函数。

第58行将第36行入栈的ip和Ir进行出栈,并将Ir赋给pc

s_init函数详解

知道lowlevel_init函数后面会调用s_init函数, s_init函数定义在文件arch/arm/cpu/army7/mx6/soc.c中,如下所示:

 在第816行会判断当前CPU类型,如果CPU为MX6SX、MX6UL、MX6ULL或MX6SLL中的任意一种,那么就会直接返回,相当于s_init函数什么都没做。所以对于I.MX6UL/I.MX6ULL来说,s_init就是个空函数。从s_init函数退出以后进入函数lowlevel_init,但是lowlevel_init函数也执行完成了,返回到了函数cpu_init_crit,函数cpu_init_crit 也执行完成了,最终返回到save_boot_params_ret,函数调用路径如图所示:

 从图可知,接下来要执行的是save_boot_params_ret中的_main函数,下一章分析_main函数。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

09_Uboot启动流程_1 的相关文章

随机推荐

  • 如何在window快速安装Linux系统(虚拟机)

    软件名称 VMware17 0 0 安装环境 Win 11 虚拟机是指通过软件模拟的具有完整硬件系统功能的 运行在一个完全隔离环境中的完整计算机系统 虚拟机允许用户在当前操作系统中运行其他操作系统 虚拟操作系统会像电脑上的另一个程序一样运行
  • 算法导论 第六章 堆排序 习题6.5-8 k路合并排序

    请给出一个时间为O nlgk 用来将k个已排序链表合并为一个排序链表的算法 此处n为所有输入链表中元素的总数 提示 用一个最小堆来做k路合并 思路 利用有k个元素的最小堆有lgk的复杂度 所以堆的元素组成要每个链表的一个元素组成 具体步骤
  • 关于Flask框架中启动Scrapy爬虫框架时的几种问题的解决

    最近开发的爬虫调度系统是由Flask框架提供接口 在Flask中启动Scrapy项目 开发期间遇到了几个问题 网上找找 自己也琢磨了好久 终于顺利解决 问题如下 一 Scrapy crawl指令找不到 问题描述 先看一下我的项目结构 如下
  • javaWeb_09——HTTP响应、Response(输出,服务器路径,重定向,动态验证码,下载,不同浏览器的解码类)

    目录 今日内容 一 HTTP协议 1 请求消息 客户端发送给服务器端的数据 2 响应消息 服务器端发送给客户端的数据 二 Response对象 功能 设置响应消息 重定向 1 转发 重定向 特点 2 路径写法 3 服务器输出字符数据到浏览器
  • tensorflow -- tf.gfile

    tf gfile他是一个操作文件的模块 他吧os glob shutil 这几个对文件操作的功能整合到了一起去 Copy 从一个目录的文件拷贝到了另一个目录 同shutil copy DeleteRecursively 以递归方式删除dir
  • 一文读懂如何快速查询中科院JCR分区和汤森路透JCR分区

    作为一个学术渣 突然心血来潮 想搞明白困扰很久的中科院分区和汤森路透分区到底是咋回事 曾经听人忽悠某某杂志几区 IF多少 说的云里雾里 感觉自己白活了这么多年 你是不是也有这种感觉 要是有那就对了 不用担心 看完这篇文章 保证让你彻底摆脱搞
  • java中求时间间隔(精确到分钟)

    long nowTime System currentTimeMillis System out print 现在的时间是 nowTime SimpleDateFormat dateformat new SimpleDateFormat y
  • Maven项目中右边的maven Projects中子项目出现灰色

    如图所示 Maven项目中右方查看的Maven Projects中子项目出现灰色 原因 忽略了maven模块 解决方法 在idea中maven的setting中找到ignored files 看右边的面板中是否将变灰的maven模块忽略了
  • SD卡、TF卡读写速率测试

    请注意 可以在未经过博主同意下转载 但必须注明出处 谢谢 1 运行HDBENCH软件 点击确定 2 弹出如下图所示界面 配置选项并测试 选择待测TF卡 Removable可移动存储设备 图示所插入的TF卡是 I 盘 请根据实际情况选择 选择
  • Qt的D和Q指针

    Qt的D指针和Q指针 实际上就是一个类的成员指针变量 改变量指向另一个Private类对象 这个Private类对象中包含了一系列的成员和函数 这样做的目的 1 可以对外隐藏数据内容 2 防止改变类的数据模型 从而做到二进制兼容 Q DEC
  • 微信分享签名无效php_【求助】微信分享朋友圈失效

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 document ready function var islogin islogin val var area id sessionStorage getItem list area id v
  • 基于径向基神经网络的数据回归预测及matlab实现

    基于径向基神经网络的数据回归预测及matlab实现 径向基神经网络 Radial Basis Function Neural Network RBFNN 是一种常用的人工神经网络模型 其结构简单 学习速度快 精度高 并且具有良好的适应性 泛
  • Linux 离线升级 pip

    首先在一台有网的地方下载 pip3 download pip i http mirrors aliyun com pypi simple trusted host mirrors aliyun com 然后将这个pip xxx none a
  • 用JS获取小数点后两位数字方法

    1 最笨的办法 1 function get 2 3 var s 22 127456 4 var str s substring 0 s indexOf 3 5 alert str 6 2 正则表达式效果不错 1
  • win7下安装rhel7(redhat enterprise Linux 7) 双系统

    首先需要的材料是 win7 rhel7 ISO镜像 和 EasyBCD 然后将磁盘格出3个分区 卷标分别是 I RHEL7 J GEN 和K SWAP 要注意格出来的三个分区都是FAT32格式的 NTFS Linux不认 我分的大小是I 1
  • 如何使用万用表测量三级管的阻值

    1 三极管是含有两个PN结的半导体器件 根据两个PN结连接方式不同 可以分为NPN型和PNP型两种不同导电类型的三极管 测试三极管要使用万用电表的欧姆挡 并选择R 100或R 1k挡位 假定我们并不知道被测三极管是NPN型还是PNP型 也分
  • 你现在需要知道的 C# 10 的 5+1 特性

    距离 C 10 正式发布仅剩两个月 微软开启了关于其 C 语言第十版的新特性和功能的讨论 这些增强功能是在C 10 0 Preview 7 中宣布的 微软将在下一版 C 10 中实现的功能和改进如下 记录类型可以密封 ToString 现在
  • ES底层原理知识(无代码篇)

    版本更新知识 ES 删除映射类型 爱码网 1 Index索引 包含了一堆有相似数据结构的文档数据 一个索引包含很多document 一个索引就代表一类相似或者相同的document 索引简单来说就相对于关系型数据库的库 2 Type类型 每
  • 小程序-picker组件的使用、数据回显

    picker组件的使用 通过点击picker选择器 触发bingchange绑定的事件函数 在picker组件自定义data i I 在事件函数中通过e target dataset i获取到data i里的值 这里的i代表数组中对象的下标
  • 09_Uboot启动流程_1

    目录 链接脚本u boot lds详解 U Boot启动流程详解 reset函数源码详解 lowlevel init函数详解 s init函数详解 链接脚本u boot lds详解 要分析uboot的启动流程 首先要找到 入口 找到第一行程