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

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_labelmrs	\xreg, CurrentELcmp	\xreg, 0xcb.eq	\el3_labelcmp	\xreg, 0x8b.eq	\el2_labelcmp	\xreg, 0x4b.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, x0mrs	x0, scr_el3orr	x0, x0, #0xf			/* SCR_EL3.NS|IRQ|FIQ|EA */msr	scr_el3, x0msr	cptr_el3, xzr			/* Enable FP/SIMD */
#ifdef COUNTER_FREQUENCYldr	x0, =COUNTER_FREQUENCYmsr	cntfrq_el0, x0			/* Initialize CNTFRQ */
#endifb	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, x0mov	x0, #0x33ffmsr	cptr_el2, x0			/* Enable FP/SIMD */b	0f
1:	msr	vbar_el1, x0mov	x0, #3 << 20msr	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_SMPENswitch_el x1, 3f, 1f, 1f
3:mrs     x0, S3_1_c15_c2_1               /* cpuectlr_el1 */orr     x0, x0, #0x40msr     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 */retapply_a57_core_errata:#ifdef CONFIG_ARM_ERRATA_828024mrs	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 << 27msr	S3_1_c15_c2_0, x0	/* cpuactlr_el1 */
#endif#ifdef CONFIG_ARM_ERRATA_826974mrs	x0, S3_1_c15_c2_0	/* cpuactlr_el1 *//* Disable speculative load execution ahead of a DMB */orr	x0, x0, #1 << 59msr	S3_1_c15_c2_0, x0	/* cpuactlr_el1 */
#endif#ifdef CONFIG_ARM_ERRATA_833471mrs	x0, S3_1_c15_c2_0	/* cpuactlr_el1 *//* FPSCR write flush.* Note that in some cases where a flush is unnecessary thiscould impact performance. */orr	x0, x0, #1 << 38msr	S3_1_c15_c2_0, x0	/* cpuactlr_el1 */
#endif#ifdef CONFIG_ARM_ERRATA_829520mrs	x0, S3_1_c15_c2_0	/* cpuactlr_el1 *//* Disable Indirect Predictor bit will prevent this erratumfrom occurring* Note that in some cases where a flush is unnecessary thiscould impact performance. */orr	x0, x0, #1 << 4msr	S3_1_c15_c2_0, x0	/* cpuactlr_el1 */
#endif#ifdef CONFIG_ARM_ERRATA_833069mrs	x0, S3_1_c15_c2_0	/* cpuactlr_el1 *//* Disable Enable Invalidates of BTB bit */and	x0, x0, #0xEmsr	S3_1_c15_c2_0, x0	/* cpuactlr_el1 */
#endifb 0b
ENDPROC(apply_core_errata)

2.4、lowlevel_init

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

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

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

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

相关文章

ClickHouse SQL Reference (四)数据类型

Tuple(T1, T2, …) 元素元组&#xff0c;每个元素都有一个单独的类型。元组必须至少包含一个元素。 元组用于临时列分组。在查询中使用IN表达式时&#xff0c;以及指定lambda函数的某些形式参数时&#xff0c;可以对列进行分组。有关更多信息&#xff0c;请参阅IN操作符和高阶…

u-boot 基础学习:板级配置 Kconfig 的包含

前言 u-boot 与 Linux 内核在嵌入式Linux开发中占有重要的地位&#xff0c;掌握 u-boot 的基础开发&#xff0c;可以大大提升开发能力&#xff0c;并提高开发的效率。 u-boot 下 如何配置 板级的Kconfig 呢&#xff1f;u-boot 下板级的 Kconfig 是怎么包含到 主目录下 Kconfig…

【代码随想录算法训练营Day34】860.柠檬水找零;406.根据身高重建队列;452.用最少数量的箭引爆气球

❇️Day 34 第八章 贪心算法 part04 ✴️今日任务 860.柠檬水找零406.根据身高重建队列452.用最少数量的箭引爆气球 ❇️860.柠檬水找零 本题看上好像挺难&#xff0c;其实挺简单的&#xff0c;大家先尝试自己做一做。题目链接&#xff1a;https://leetcode.cn/problems/lem…

【计算机网络】IO多路转接之poll

文章目录 一、poll函数接口二、socket就绪条件三、poll的优点四、poll的缺点五、poll使用案例--只读取数据的server服务器1.err.hpp2.log.hpp3.sock.hpp4.pollServer.hpp5.main.cc 一、poll函数接口 #include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int t…

“羊驼“入侵CV,美团浙大沈春华团队将LLaMA向CV扩展,构建全新基础模型VisionLLaMA

本文首发:AIWalker https://arxiv.org/abs/2403.00522 https://github.com/Meituan-AutoML/VisionLLaMA 本文概述 大型语言模型构建在基于Transformer的架构之上来处理文本输入, LLaMA 系列模型在众多开源实现中脱颖而出。类似LLaMa的Transformer可以用来处理2D图像吗&#xf…

Python绘制不同形状词云图

目录 1.基本词云图1.1 导入所需库1.2 准备词汇1.3 配置参数并生成词云图1.4 在Python窗口中显示图片1.5 效果展示1.6 完整代码 2. 不同形状词云图2.1 找到自己所需形状图片2.2 利用PS将图片设置为黑白色2.3 在代码中设置背景2.4 效果展示 1.基本词云图 1.1 导入所需库 import…

远程调用--webClient

远程调用webClient 前言1、创建webClient2、准备数据3、执行请求4、接收返回响应到的数据整体代码 前言 非阻塞、响应式HTTP客户端 1、创建webClient WebClient client WebClient.create();2、准备数据 Map<String,String> params new HashMap<>();params.pu…

贪心算法(区间问题)

452. 用最少数量的箭引爆气球 题目(求无重复区间) 有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points &#xff0c;其中points[i] [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。 一支弓箭可以沿着…

利用Python爬取8684公交路线查询网站中全国公交站点信息

利用python语言结合requests、BeautifulSoup等类库爬取https://api.8684.cn/v3/api.php?docitys&actprovince对应接口中所有城市公交路线信息以及公交站点信息。 import time import requests import json, re from bs4 import BeautifulSoup# 定义一个函数&#xff0c;传…

“祖传代码“的是是非非

程序员眼中的“祖传代码”&#xff0c;就像一本古老而神秘的魔法书&#xff0c;藏着无穷的智慧和技巧&#xff0c;有些代码像家传宝贝&#xff0c;有些像祖传秘方。快来分享一下你遇到的“祖传代码”吧~ 祖传代码的历史与文化价值 祖传代码通常指的是经过长时间使用和传承的代…

【DUSt3R】2张图2秒钟3D重建

【DUSt3R】2张图2秒钟3D重建 1. DUSt3R是一种用于稠密和无约束立体三维重建的方法,其实现步骤如下:2. 实际运行效果3. 运行结果4. 自问自答4.1 为社么这里要是使用transform模型呢?4.2 CroCo(通过跨视图完成3D视觉任务的自我监督预训练的一个研究)在DUSt3R的作用是什么,为…

打家劫舍(java版)

&#x1f4d1;前言 本文主要是【动态规划】——打家劫舍(java版)的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304;每日一…

17 easy 290. 单词规律

//给定一种规律 pattern 和一个字符串 s &#xff0c;判断 s 是否遵循相同的规律。 // // 这里的 遵循 指完全匹配&#xff0c;例如&#xff0c; pattern 里的每个字母和字符串 s 中的每个非空单词之间存在着双向连接的对应规律。 // // // // 示例1: // // //输入: patte…

一款不错的多端SSH工具:Xterminal

1、不仅是强大的SSH工具&#xff0c;更提供本地控制台&#xff0c;以及更多即将推出的开发相关功能&#xff0c;让您专注于创造卓越的代码 2、AI赋能&#xff0c;智能命令提示&#xff0c;为大脑解压 AI解答&#xff0c;让你的疑问得到即时解答 AI智能提示&#xff0c;让每一…

CodeFlying 和 aixcoder两大免费软开平台,孰强孰弱?

今天为大家带来码上飞CodeFlying和aixcoder两款免费的软件开发平台效果的测评 一、产品介绍 首先简单介绍一下这两个平台 码上飞CodeFlying&#xff1a;码上飞 CodeFlying | AI 智能软件开发平台&#xff01; 是一款革命性的软件开发平台&#xff0c;它通过将软件工程和大模…

Redis是AP的还是CP的?

redis是一个开源的内存数据库&#xff0c;那么他到底是AP的还是CP的呢&#xff1f; 有人说&#xff1a;单机的是redis是cp的&#xff0c;而集群的redis是ap的&#xff1f; 但是我不这么认为&#xff0c;我觉得redis就是ap的&#xff0c;虽然在单机redis中&#xff0c;因为只有…

Git 基本操作 ⼯作区、暂存区、版本库

创建本地仓库&#xff1a; 创建 Git 本地仓库 要提前说的是&#xff0c;仓库是进行版本控制的⼀个文件目录。我们要想对文件进行版本控制&#xff0c;就必须先创建⼀个仓库出来。 首先touch 一个文件&#xff1a; 初始化仓库&#xff1a; 创建完成后&#xff0c;我们会发现当前…

行列式错题本

《1800》 1 阶数和转置 A是三阶,B是4阶,还有2这个系数 2 怎么啥也不会呀,委屈 行列式的拆分+提取系数 3

uniapp 安装安卓、IOS模拟器并调试

一、安装Android模拟器并调试 1.下载并安装Android Studio。 2.创建简单project。 3.安装模拟器。 完成安卓模拟器的安装。 4.启动模拟器。 5.hbuilderx选择模拟器、运行。 点击刷新按钮后出现模拟器&#xff0c;勾选并运行。 6.调试。 在 HBuilderX 中&#xff0c;项目启…

每天一道leetcode:20.有效的括号(简单;栈的经典题目)

⭐今日份题目 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 每个右括号都有一个对…