【嵌入式移植】8、U-Boot源码分析5—启动过程分析start.S

news2024/9/22 5:42:25

U-Boot源码分析5—启动过程分析start.S

  • 1、`boot0.h`
  • 2、`reset`
    • 2.1、`vectors`
    • 2.2、`ELn`
      • 2.2.1 EL3
      • 2.2.2、EL2、EL1
    • 2.3、`SMPEN`
    • 2.3、`core errate`
    • 2.4、`lowlevel_init`

前面从U-Boot编译的角度分析了其Makefile、链接脚本等,本章开始正式分析U-Boot启动过程

从上一篇文章7、U-Boot源码分析4—链接脚本分析,可知U-Boot启动入口_startarch/arm/cpu/armv8/start.S

1、boot0.h

start.S中找到启动入口`_start:
请添加图片描述

这里针对汇编文件的结尾*.s*.S进行说明:其中小写的s表示文件中仅包含汇编代码,编译器将不进行预编译操作;而大写的S表示文件中包含相关预编译代码,编译器将进行预编译操作,即判断#ifdef#ifndef#if defined(xxx)等语句的条件是否成立并保留相关代码,或将#include指令包含的文件内容替换到对应位置,等等的预编译操作

这里搜索CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK,发现存在定义:
请添加图片描述
因此将执行第28行的语句,即#include <asm/arch/boot0.h>,对于某些芯片需要特殊的一些初始配置的话,可以通过配置CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK并执行相应boot0.h中的代码来进行一些boot之前的操作,内容如下
请添加图片描述

可知其语句和其它启动文件基本一样,都是跳转至reset标号,但是增加了与AArch64切换有关的代码,查看arch/arm/mach-sunxi/rmr_switch.S中的说明,其实是本例所使用芯片的特殊属性,因为该芯片在复位后会进入AArch32状态,所以在一些时刻需要切换到AArch64状态,这里涉及ARMv8的Reset Management Register,暂时先不分析

随后进行 2 3 = 8 2^3=8 23=8字节对齐(.align 3),并定义了一些符号:_end_ofs_bss_start_ofs_bss_end_ofs,是一些关键段与代码段起始位置的偏移

2、reset

跳转进入reset后,首先跳转进入save_boot_params,这里save_boot_params通过WEAK关键字定义为save_boot_params_retstart.S文件最后);
因为使用了WEAK关键字,当然也可以直接在其它文件中定义自己的save_boot_params函数(需使用头文件引用或在已有的头文件中进行声明)
请添加图片描述
这里搜索CONFIG_SYS_RESET_SCTRL,发现没有定义,因此不进行跳转,继续向下执行。
其实跳转到reset_sctrl中主要是根据当前异常等级执行对应操作:设置小端,关MMU,关I/D-cache

2.1、vectors

接下来,第67行首先将中断向量vectors的地址保存在x0寄存器中,中断向量的定义在arch/arm/cpu/armv8/excetions.S中:
请添加图片描述

这里首先进行 2 1 1 = 2048 2^11=2048 211=2048字节即2K对齐(.align 11),且各个中断向量地址均以 2 7 = 128 2^7=128 27=128字节对齐;

每个中断向量都对应其跳转指令,比如b _do_bad_sync,先用bl指令跳转到do_bad_sync函数执行,然后再跳转到中断退出函数exception_exit;而do_bad_sync函数最终将输出各个关键寄存器的值,最后调用panic函数终止正在运行的程序并进行复位

/*
 * do_bad_sync handles the impossible case in the Synchronous Abort vector.
 */
void do_bad_sync(struct pt_regs *pt_regs, unsigned int esr)
{
	efi_restore_gd();
	printf("Bad mode in \"Synchronous Abort\" handler, esr 0x%08x\n", esr);
	show_regs(pt_regs);
	panic("Resetting CPU ...\n");
}

当然这里所有中断都没有打开,目前不会进入任何中断向量,另外现在没有初始化堆栈等,也无法执行C函数

2.2、ELn

然后第68行判断异常等级,并根据判断结果从不同分支开始执行
请添加图片描述
其中switch_elarch/arm/include/asm/macro.h中定义

/*
 * Branch according to exception level
 */
.macro	switch_el, xreg, el3_label, el2_label, el1_label
	mrs	\xreg, CurrentEL
	cmp	\xreg, 0xc
	b.eq	\el3_label
	cmp	\xreg, 0x8
	b.eq	\el2_label
	cmp	\xreg, 0x4
	b.eq	\el1_label
.endm

其中xreg即为传入的x1寄存器,这里将CurrentEL寄存器的值放入x1寄存器中,并依次和0xc0x80x4进行比较,根据比较结果进入不同的分支标号

CurrentEL寄存器即为Current Exception Level寄存器,根据ARMv8的手册,其定义如下:
请添加图片描述
因此0xc0x80x4即分别对应EL3、EL2、EL1

2.2.1 EL3

可知当复位后CPU处于EL3时,执行如下代码

3:	msr	vbar_el3, x0
	mrs	x0, scr_el3
	orr	x0, x0, #0xf			/* SCR_EL3.NS|IRQ|FIQ|EA */
	msr	scr_el3, x0
	msr	cptr_el3, xzr			/* Enable FP/SIMD */
#ifdef COUNTER_FREQUENCY
	ldr	x0, =COUNTER_FREQUENCY
	msr	cntfrq_el0, x0			/* Initialize CNTFRQ */
#endif
	b	0f

首先将x0寄存器中的中断向量vectors的地址放入vbar_el3寄存器:Vector Base Address Register (EL3)
请添加图片描述
其中低11位(0~10)保留为0,对应前面中断向量最开始的2K字节对齐(.align 11

随后的3行语句,首先将scr_el3寄存器的值保存到x0寄存器中,然后将x0寄存器或操作上0xF即将低4位置1,然后保存到x0寄存器中,最后将x0寄存器的值再赋给scr_el3寄存器,scr_el3寄存器低4为置1
请添加图片描述
scr_el3寄存器bit3对应EA,即任何异常等级下发生的External Abort 和 SError 中断都由EL3进行处理;bit2对应FIQ,即任何异常等级下发生的硬件上的FIQ (快速中断请求)都由EL3进行处理;bit1对应IRQ,即任何异常等级下发生的硬件上的IRQ (中断请求)都由EL3进行处理;bit0对应NS,置1表示任何低于EL3的异常等级(EL0、EL1等)都是非安全状态,无法访问安全内存空间

然后使用xzr(64位全零寄存器)将cptr_el3寄存器清零,
请添加图片描述
即(TCPAC)打开EL2访问CPTR_EL2HCPTR寄存器的权限,打开EL2、EL1访问CPACR_EL1CPACR寄存器的权限;(TAM)打开EL2、EL1访问Activity Monitor registers的权限;(TTA)打开系统寄存器访问trace寄存器的权限;(TFP)使能SVE、SIMD和浮点运算;但(EZ)又把SVE关了

因此这一行代码的功能也就是注释说的使能SIMD和FP运算

然后由于在include/configs/sunxi-common.h中定义了COUNTER_FREQUENCY的值为24000000,因此将此值由x0寄存器赋给cntfrq_el0寄存器,即配置系统计数器的时钟值,此系统计数器一般用于精确计时

结合上述分析,EL3等级对应的操作即为将中断向量地址放入vbar_el3寄存器,设置相关中断请求仅由EL3实现,使能SIMD和FP运算,设置系统计数器的时钟值

2.2.2、EL2、EL1

对应执行的代码为,均为将中断向量地址放入对应的vbar_eln寄存器,使能SIMD和FP运算等,这里不再详细分析

2:	msr	vbar_el2, x0
	mov	x0, #0x33ff
	msr	cptr_el2, x0			/* Enable FP/SIMD */
	b	0f
1:	msr	vbar_el1, x0
	mov	x0, #3 << 20
	msr	cpacr_el1, x0			/* Enable FP/SIMD */

2.3、SMPEN

接下来的语句是开启多核相关的操作,这里虽然没有定义CONFIG_ARMV8_SET_SMPEN,但注释里建立用于Cortex-A53时使能,因此这里也分析一下

	/*
	 * Enable SMPEN bit for coherency.
	 * This register is not architectural but at the moment
	 * this bit should be set for A53/A57/A72.
	 */
#ifdef CONFIG_ARMV8_SET_SMPEN
	switch_el x1, 3f, 1f, 1f
3:
	mrs     x0, S3_1_c15_c2_1               /* cpuectlr_el1 */
	orr     x0, x0, #0x40
	msr     S3_1_c15_c2_1, x0
1:
#endif

这里的操作也一样,首先判断所处的异常等级,仅在EL3时进行操作:首先将S3_1_c15_c2_1也即cpuectlr_el1寄存器的值放入x0寄存器,然后通过orr指令将第6位置1;这里cpuectlr_el1寄存器在Cortex-A53手册中(ARMv8架构定义了一些必须实现的寄存器,同时预留一些空间给不同处理器来实现各自的特色功能等)
请添加图片描述
第6位即SMPEN置1,表示使能各核心之间的数据一致性功能(主要与cache有关,对于多核系统来说,一般各个核具有自己的L1-cache,簇内共享L2-cache,还有外部的L3-cache,这样不同核心上的cache或ram对于同一个数据可能有多个副本,会导致数据观察者(CPU/GPU/DMA等)能看到的数据不一致,因此设置会再处理器中设置硬件来维护数据的一致性,具体内容可参考【Cache篇】一文总结ARMv8架构中关于Cache的知识点)

2.3、core errate

随后进行核心勘误,目前仅支持Cortex-A57进行核心勘误表的设置,这里跳过

	/* Apply ARM core specific erratas */
	bl	apply_core_errata
....
WEAK(apply_core_errata)

	mov	x29, lr			/* Save LR */
	/* For now, we support Cortex-A57 specific errata only */

	/* Check if we are running on a Cortex-A57 core */
	branch_if_a57_core x0, apply_a57_core_errata
0:
	mov	lr, x29			/* Restore LR */
	ret

apply_a57_core_errata:

#ifdef CONFIG_ARM_ERRATA_828024
	mrs	x0, S3_1_c15_c2_0	/* cpuactlr_el1 */
	/* Disable non-allocate hint of w-b-n-a memory type */
	orr	x0, x0, #1 << 49
	/* Disable write streaming no L1-allocate threshold */
	orr	x0, x0, #3 << 25
	/* Disable write streaming no-allocate threshold */
	orr	x0, x0, #3 << 27
	msr	S3_1_c15_c2_0, x0	/* cpuactlr_el1 */
#endif

#ifdef CONFIG_ARM_ERRATA_826974
	mrs	x0, S3_1_c15_c2_0	/* cpuactlr_el1 */
	/* Disable speculative load execution ahead of a DMB */
	orr	x0, x0, #1 << 59
	msr	S3_1_c15_c2_0, x0	/* cpuactlr_el1 */
#endif

#ifdef CONFIG_ARM_ERRATA_833471
	mrs	x0, S3_1_c15_c2_0	/* cpuactlr_el1 */
	/* FPSCR write flush.
	 * Note that in some cases where a flush is unnecessary this
	    could impact performance. */
	orr	x0, x0, #1 << 38
	msr	S3_1_c15_c2_0, x0	/* cpuactlr_el1 */
#endif

#ifdef CONFIG_ARM_ERRATA_829520
	mrs	x0, S3_1_c15_c2_0	/* cpuactlr_el1 */
	/* Disable Indirect Predictor bit will prevent this erratum
	    from occurring
	 * Note that in some cases where a flush is unnecessary this
	    could impact performance. */
	orr	x0, x0, #1 << 4
	msr	S3_1_c15_c2_0, x0	/* cpuactlr_el1 */
#endif

#ifdef CONFIG_ARM_ERRATA_833069
	mrs	x0, S3_1_c15_c2_0	/* cpuactlr_el1 */
	/* Disable Enable Invalidates of BTB bit */
	and	x0, x0, #0xE
	msr	S3_1_c15_c2_0, x0	/* cpuactlr_el1 */
#endif
	b 0b
ENDPROC(apply_core_errata)

2.4、lowlevel_init

接下来就到了大名鼎鼎的lowlevel_init,本章先不分析,留待下章

本章分析完毕~
完结撒花✿✿ヽ(°▽°)ノ✿

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1488863.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

30天JS挑战(第十六天)----鼠标拖影效果

第十六天挑战(鼠标拖影效果) 地址&#xff1a;https://javascript30.com/ 所有内容均上传至gitee&#xff0c;答案不唯一&#xff0c;仅代表本人思路 中文详解&#xff1a;https://github.com/soyaine/JavaScript30 该详解是Soyaine及其团队整理编撰的&#xff0c;是对源代…

20 个不同的 Python 函数实例

Python 是一种广泛使用的高级编程语言&#xff0c;其函数是 Python 编程中至关重要的概念之一。函数是一段可以重复使用的代码块&#xff0c;可以接收输入参数并返回输出结果。使用函数能够提高代码的可读性、可维护性和重用性。 基础知识 在 Python 中&#xff0c;函数使用关…

[动态规划]---part1

前言 作者&#xff1a;小蜗牛向前冲 专栏&#xff1a;小蜗牛算法之路 专栏介绍&#xff1a;"蜗牛之道&#xff0c;攀登大厂高峰&#xff0c;让我们携手学习算法。在这个专栏中&#xff0c;将涵盖动态规划、贪心算法、回溯等高阶技巧&#xff0c;不定期为你奉上基础数据结构…

LeetCode-02

225. 用队列实现栈 用两个队列实现栈的功能&#xff0c;思路如下&#xff1a; 往空队列中放新元素把非空队列中的元素依次放入刚才添加了新元素的队列&#xff0c;直到非空队列变为空队列 class MyStack(object):def __init__(self):self.queue1 []self.queue2 []def push(…

thymeleaf 一个莫名其妙的错误提示 org.attoparser.ParseException

thymeleaf 一个莫名其妙的错误提示 介绍 开发过程中遇到一个莫名奇妙的错误&#xff0c;一时竟然不知道怎么解决&#xff0c;找官网也没有找到 问题 页面显示 错误日志 org.attoparser.ParseException: (Line 96, Column 5) Malformed markup: Attribute “}” appears m…

医学大数据|统计基础|医学统计学(笔记):开学说明与目录

开始学习统计基础&#xff0c;参考教材&#xff1a;医学统计学第五版 点点关注一切来学习吧 责任编辑&#xff1a;医学大数据刘刘老师&#xff1a;头部医疗大数据公司医学科学部研究员 邮箱&#xff1a;897282268qq.com 久菜盒子工作室 我们是&#xff1a;985硕博/美国全奖…

【开源】SpringBoot框架开发数据可视化的智慧河南大屏

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 数据模块 A4.2 数据模块 B4.3 数据模块 C4.4 数据模块 D4.5 数据模块 E 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的数据可视化的智慧河南大屏&#xff0c;包含了GDP、…

js面试 forEach ,map,for ,for in , for of

forEach ,map&#xff0c;for ,for in , for of 1 forEach 回调3个参数value&#xff0c;index&#xff0c;arr&#xff08;原数组&#xff09; 2 map 1&#xff1a;map() 不会改变原始数组 2&#xff1a;函数的作用是对数组中的每一个元素进行处理&#xff0c;返回新的元素…

动态规划(算法竞赛、蓝桥杯)--背包DP求具体方案

1、B站视频链接&#xff1a;E20 背包DP 求具体方案_哔哩哔哩_bilibili #include <bits/stdc.h> using namespace std; const int N1010; int v[N],w[N]; int f[N][N],p[N][N];int main(){int n,m;cin>>n>>m;for(int i1;i<n;i)cin>>v[i]>>w[i…

cmd模式下启动mysql

1.打开cmd输入services.msc&#xff0c;找到MYSQL&#xff0c;右击属性&#xff0c;找到可执行文件路径&#xff0c;加载到环境变量。 2.打开cmd&#xff0c;启动MYSQL&#xff1a;输入net start mysql; 3.登陆MYSQL&#xff0c;需要管理权限&#xff1b; 输入&#xff1a;my…

day34贪心算法 part03

1005. K 次取反后最大化的数组和 简单 给你一个整数数组 nums 和一个整数 k &#xff0c;按以下方法修改该数组&#xff1a; 选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。 重复这个过程恰好 k 次。可以多次选择同一个下标 i 。 以这种方式修改数组后&#xff0c;返回数…

达梦数据库查询语句内存溢出问题解决

背景&#xff1a;达梦数据库使用过程中&#xff0c;某天突然服务宕机&#xff0c;导致各类后端服务无法注册到nacos上&#xff0c;重启之后nacos正常启动&#xff0c;可执行一条两千多条数据量的连表查询时间很长&#xff0c;甚至会报错&#xff0c;经查看日志发现在查询过程中…

【InternLM 笔记】使用InternStudio 体验书生·浦语2-chat-1.8b随记

书生浦语2-chat-1.8b 介绍 书生浦语-1.8B (InternLM2-1.8B) 是第二代浦语模型系列的18亿参数版本。为了方便用户使用和研究&#xff0c;书生浦语-1.8B (InternLM2-1.8B) 共有三个版本的开源模型&#xff0c;他们分别是&#xff1a; InternLM2-1.8B: 具有高质量和高适应灵活性…

找不到emp.dll如何处理?emp.dll丢失的多种的解决方法分享

在计算机游戏中&#xff0c;当特定的核心文件emp.dll发生丢失时&#xff0c;可能会引发一系列影响游戏运行的问题。由于emp.dll通常是游戏运行所必需的动态链接库文件&#xff0c;它的缺失会导致游戏无法正常启动或加载&#xff0c;玩家可能面临“无法进入游戏”的尴尬境地。其…

AI技术初探:普通人ALL IN AI入门指南

自从去年ChatGPT如流星划过夜空&#xff0c;照亮了整个AI领域&#xff0c;它所带来的技术革新与热潮仿佛一场无声的暴风雨&#xff0c;席卷了全球的科技圈。身为一名低阶IT从业者&#xff0c;感觉这太高大上了&#xff0c;与我的工作有毛线关系。 但是&#xff0c;AI技术的飞速…

【海贼王的数据航海:利用数据结构成为数据海洋的霸主】链表—双向链表

目录 往期 1 -> 带头双向循环链表(双链表) 1.1 -> 接口声明 1.2 -> 接口实现 1.2.1 -> 双向链表初始化 1.2.2 -> 动态申请一个结点 1.2.3 -> 双向链表销毁 1.2.4 -> 双向链表打印 1.2.5 -> 双向链表判空 1.2.6 -> 双向链表尾插 1.2.7 -&…

枚举——完美立方算法

枚举 基于逐个尝试答案的一种问题求解策略 例如&#xff1a;求小于N的最大素数 找不到一个数学公式&#xff0c;使得根据N就可以计算出这个素数 N-1是素数吗&#xff1f;N-2是素数吗&#xff1f; …… 判断N-i是否是素数的问题 转化成求小于N的全部素数&#xff08;可以用筛法…

2024最佳steam搬砖项目,日入5000,保姆级教程,小白无脑操作

今天给带来的项目是“2024最佳steam搬砖项目&#xff0c;日入5000&#xff0c;保姆级教程&#xff0c;小白无脑操作” 二、项目准备 需要下载如下图所显示的app&#xff0c;一个是steam&#xff0c;一个是国内交易的网易buff 安装好了之后就可以开始实操了&#xff0c;国内外汇…

如何在Linux使用Docker部署Redis并结合内网穿透实现公网远程连接本地数据库

文章目录 前言1. 安装Docker步骤2. 使用docker拉取redis镜像3. 启动redis容器4. 本地连接测试4.1 安装redis图形化界面工具4.2 使用RDM连接测试 5. 公网远程访问本地redis5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定TCP地址远程访问 正文开始前给大家推荐个网站…

BUUCTF---[ACTF2020 新生赛]BackupFile1

1.题目描述 2.题目提示backup file &#xff0c;是备份文件的意思。点开链接&#xff0c;页面提示 3.查看源码没有什么有用信息&#xff0c;也没有登录界面&#xff0c;所以也不会用到蚁剑链接来找备份文件&#xff0c;所以大概率就是通过构造playload来查找备份文件。 4.备份…