【精读Uboot】反汇编分析SPL的_main函数

news2024/11/28 22:38:45

1、简介

典型的Uboot启动分为两个阶段,bootrom->SPL(Secondary Program Loader)->ATF->OPTEE(可选)->Uboot。其中SPLBL2ATFBL31OPTEEBL32UbootBL33。其中bootrom是固化在芯片内部的代码,负责从各种外(sdcard、mmc、flash)中加载spl到芯片内部的SRAM;SPL的主要工作是初始化板载的DRAM和核心硬件;Uboot最主要的功能就是加载启动kernel。

image-20230702150920086

2、反汇编分析SPL

SPL代码是Uboot源码中一部分特殊的代码,其编译后的大小足以在片上RAM中运行。下面我们通过SPL的反汇编代码来了解实际的代码执行过程。

2.1、_start

_start 标签是程序的入口点。第一条指令 b 28 <reset> 是一个无条件分支指令,将控制流跳转到 reset 标签处。reset函数中又直接跳转到了save_boot_params。对于i.MX平台, i.MX8各个系列的save_boot_params定义都不一样。下面我们将以i.MX8M平台的save_boot_params函数为例继续分析。

2.2、save_boot_params

  1. save_boot_params 函数开始,使用 adr 指令将 rom_pointer 的地址存储到寄存器 x0 中。rom_pointer是由optee固件提供的 ATAG/FDT 地址。本质是将armv8中的x1-x30寄存器保存到这个地址上,保存栈地址。
  2. 依次使用 stp 指令将 x1x30 的值存储到 x0 指向的内存地址,并且每次存储后 x0 自增 16 个字节。
  3. 使用 mov 指令将栈指针 sp 的值存储到寄存器 x30 中。
  4. 使用 str 指令将 x30 的值存储到 x0 指向的内存地址,并且 x0 自增 8 个字节。
  5. 跳转到 save_boot_params_ret 标签处。
.global save_boot_params
save_boot_params:
	/* The firmware provided ATAG/FDT address can be found in r2/x0 */
	adr	x0, rom_pointer
	stp	x1, x2, [x0], #16 //将x1和x2的值
	stp	x3, x4, [x0], #16
	stp	x5, x6, [x0], #16
	stp	x7, x8, [x0], #16
	stp	x9, x10, [x0], #16
	stp	x11, x12, [x0], #16
	stp	x13, x14, [x0], #16
	stp	x15, x16, [x0], #16
	stp	x17, x18, [x0], #16
	stp	x19, x20, [x0], #16
	stp	x21, x22, [x0], #16
	stp	x23, x24, [x0], #16
	stp	x25, x26, [x0], #16
	stp	x27, x28, [x0], #16
	stp	x29, x30, [x0], #16
	mov	x30, sp
	str	x30, [x0], #8

	/* Returns */
	b	save_boot_params_ret

2.3、save_boot_params_ret

save_boot_params_ret函数是通用函数。

1.adr 指令将地址 2049a800 存储在寄存器 x0 中。这个地址定义的是异常向量vectors位置。

2.mrs 指令将当前异常级别(Exception Level)的值存储在寄存器 x1 中。

3.cmp 指令将寄存器 x1 和常数 0xc0x80x4 进行比较,跳转到对应标签处。这三个常数分别代码异常等级EL3,EL2和EL1。标签实现的功能是设置各异常等级的vbar,src,cptr和cpacr寄存器。例如对于EL3,msr 指令将寄存器 x0 的值存储到 vbar_el3 寄存器中,这就设置了EL3的异常向量mov 指令将常数 0x33ff 移动到寄存器 x0 中。msr 指令将寄存器 x0 的值存储到 cptr_el2 寄存器中,打开FP/SIMD功能。b 指令无条件跳转到地址 isb指令。下面就是执行apply_core_erratalowlevel_init函数了。apply_core_errata不作分析。

ELn应用范围
EL0应用层
EL1操作系统内核或者一些特权函数
EL2Hypervisor虚拟化
EL3Secure Monitor

2.4、lowlevel_init(arch/arm/mach-imx/lowlevel.S)

  1. mrs 指令将当前异常级别(Exception Level)的值存储在寄存器 x0 中。

  2. cmp 指令将寄存器 x0 和常数 0xc 进行比较,确定是否处于EL3。

  3. b.eq 指令检查比较结果,如果相等,则跳转到地址 2049b594处。如果不相等,使用 ret 指令返回到调用 lowlevel_init 函数的位置。

    2049b594处的代码如下:

    	2049b594:	d50344ff 	msr	daifclr, #0x4
        2049b598:	d5033fdf 	isb
        2049b59c:	d65f03c0 	ret
    

    msr 指令将 0x4 存储到 daifclr 寄存器中,用于清除 DAIF 寄存器的指定位。isb 指令执行指令同步屏障操作。然后返回,使用 ret 指令返回到调用 lowlevel_init 函数的位置。下一步启动主核/多核,执行_main函数。

2.5、_main重定位到uboot

1.ldr0x96dff0(CONFIG_SPL_STACK)加载到x0中。

2.and 指令使用位掩码将寄存器 x0 和常数 0xfffffffffffffff0 进行按位与操作,并将结果存储在栈指针寄存器 sp 中,对栈指针进行对齐

3.mov 指令将栈指针寄存器 sp 中的值复制到寄存器 x0 中,设置对齐后的栈地址。(sp->x0)

4.bl 指令调用函数 board_init_f_alloc_reserve,将栈指针作为参数传递,并将返回值存储在寄存器 x0 中。board_init_f_alloc_reserve函数的目的是在顶部地址中预留一些内存。首先,根据配置项 CONFIG_VAL(SYS_MALLOC_F_LEN) 的值,可能会预留一部分内存作为早期 malloc 的内存池,从 传入的对齐后地址中减去该长度。接下来,通过将这个地址向下舍入到最接近的 16 字节的倍数,来保留一块内存用于存储全局数据结构 struct global_data,并确保其对齐。最后,将更新后的 x0 值返回。

5.mov 指令将寄存器 x0 中的值复制到栈指针寄存器 sp 中(x0->sp)。mov 指令将寄存器 x0 中的值复制到寄存器 x18 中,备份栈指针。

6.bl 指令调用函数 board_init_f(board/freescale/imx93_evk/spl.c)初始化必要的i.MX外设如串口、定时器、pmic和ddr,初始化内存分配系统,最后调用board_init_r(common/spl/spl.c)执行跳转。对于board_init_r来说,支持5种跳转方式,它们分别是①通过ATF跳转uboot;②通过optee跳转uboot;③通过RISCV OpenSBI跳转uboot;④直接跳转到Linux;⑤直接跳转uboot。**如果上面都不支持,就不进行跳转,转而使用ROM API将uboot image下载到ddr的指定位置。**实际的跳转流程是在ROM API下载image后,直接进入ATF,然后由ATF控制跳转进入Uboot。对于I.MX系列平台,在执行board_init_f函数的最后就直接跳转进入了ATF,board_init_f之后的代码(如spl_relocate_stack_gdclear_loop)不再被执行。这一点与大部分资料所述的执行步骤不同。

1

附录:反汇编代码

start.S

u-boot-spl:     file format elf64-littleaarch64


Disassembly of section .text:

000000002049a000 <_start>:
    2049a000:	1400000a 	b	2049a028 <reset>
    2049a004:	d503201f 	nop

000000002049a008 <_TEXT_BASE>:
    2049a008:	80200000 	.inst	0x80200000 ; NYI
    2049a00c:	00000000 	udf	#0

000000002049a010 <_end_ofs>:
    2049a010:	0001a1e0 	.inst	0x0001a1e0 ; undefined
    2049a014:	00000000 	udf	#0

000000002049a018 <_bss_start_ofs>:
    2049a018:	00080000 	.inst	0x00080000 ; undefined
    2049a01c:	00000000 	udf	#0

000000002049a020 <_bss_end_ofs>:
    2049a020:	000800b0 	.inst	0x000800b0 ; undefined
    2049a024:	00000000 	udf	#0

000000002049a028 <reset>:
    2049a028:	140005b6 	b	2049b700 <save_boot_params>

000000002049a02c <save_boot_params_ret>:
    2049a02c:	10003ea0 	adr	x0, 2049a800 <vectors>
    2049a030:	d5384241 	mrs	x1, currentel
    2049a034:	f100303f 	cmp	x1, #0xc
    2049a038:	540000a0 	b.eq	2049a04c <save_boot_params_ret+0x20>  // b.none
    2049a03c:	f100203f 	cmp	x1, #0x8
    2049a040:	54000120 	b.eq	2049a064 <save_boot_params_ret+0x38>  // b.none
    2049a044:	f100103f 	cmp	x1, #0x4
    2049a048:	540001a0 	b.eq	2049a07c <save_boot_params_ret+0x50>  // b.none
    2049a04c:	d51ec000 	msr	vbar_el3, x0
    2049a050:	d53e1100 	mrs	x0, scr_el3
    2049a054:	b2400c00 	orr	x0, x0, #0xf
    2049a058:	d51e1100 	msr	scr_el3, x0
    2049a05c:	d51e115f 	msr	cptr_el3, xzr
    2049a060:	1400000a 	b	2049a088 <save_boot_params_ret+0x5c>
    2049a064:	d53c1101 	mrs	x1, hcr_el2
    2049a068:	b71000a1 	tbnz	x1, #34, 2049a07c <save_boot_params_ret+0x50>
    2049a06c:	d51cc000 	msr	vbar_el2, x0
    2049a070:	d2867fe0 	mov	x0, #0x33ff                	// #13311
    2049a074:	d51c1140 	msr	cptr_el2, x0
    2049a078:	14000004 	b	2049a088 <save_boot_params_ret+0x5c>
    2049a07c:	d518c000 	msr	vbar_el1, x0
    2049a080:	d2a00600 	mov	x0, #0x300000              	// #3145728
    2049a084:	d5181040 	msr	cpacr_el1, x0
    2049a088:	d5033fdf 	isb
    2049a08c:	94000003 	bl	2049a098 <apply_core_errata>
    2049a090:	9400053d 	bl	2049b584 <lowlevel_init>

000000002049a094 <master_cpu>:
    2049a094:	940002bf 	bl	2049ab90 <_main>

crt0_64.S

000000002049ab90 <_main>:
    2049ab90:	58000300 	ldr	x0, 2049abf0 <clear_loop+0x18>
    2049ab94:	927cec1f 	and	sp, x0, #0xfffffffffffffff0
    2049ab98:	910003e0 	mov	x0, sp
    2049ab9c:	94000b86 	bl	2049d9b4 <board_init_f_alloc_reserve>
    2049aba0:	9100001f 	mov	sp, x0
    2049aba4:	aa0003f2 	mov	x18, x0
    2049aba8:	94000b88 	bl	2049d9c8 <board_init_f_init_reserve>
    2049abac:	d2800000 	mov	x0, #0x0                   	// #0
    2049abb0:	94000a8f 	bl	2049d5ec <board_init_f>
    2049abb4:	94000b7b 	bl	2049d9a0 <spl_relocate_stack_gd>
    2049abb8:	f100001f 	cmp	x0, #0x0
    2049abbc:	9a921012 	csel	x18, x0, x18, ne  // ne = any
    2049abc0:	910003e1 	mov	x1, sp
    2049abc4:	f100001f 	cmp	x0, #0x0
    2049abc8:	9a811000 	csel	x0, x0, x1, ne  // ne = any
    2049abcc:	9100001f 	mov	sp, x0
    2049abd0:	58000140 	ldr	x0, 2049abf8 <clear_loop+0x20>
    2049abd4:	58000161 	ldr	x1, 2049ac00 <clear_loop+0x28>

000000002049abd8 <clear_loop>:
    2049abd8:	f800841f 	str	xzr, [x0], #8
    2049abdc:	eb01001f 	cmp	x0, x1
    2049abe0:	54ffffc3 	b.cc	2049abd8 <clear_loop>  // b.lo, b.ul, b.last
    2049abe4:	aa1203e0 	mov	x0, x18
    2049abe8:	f9403e41 	ldr	x1, [x18, #120]
    2049abec:	14000afa 	b	2049d7d4 <board_init_r>
    2049abf0:	20519dd0 	.inst	0x20519dd0 ; undefined
    2049abf4:	00000000 	udf	#0
    2049abf8:	2051a000 	.inst	0x2051a000 ; undefined
    2049abfc:	00000000 	udf	#0
    2049ac00:	2051a0b0 	.inst	0x2051a0b0 ; undefined
    2049ac04:	00000000 	udf	#0

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

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

相关文章

MySQL 8.0.34(x64)安装笔记

一、背景 从MySQL 5.6到5.7&#xff0c;再到8.0&#xff0c;版本的跳跃不可谓不大。安装、配置的差别也不可谓不大&#xff0c;特此备忘。 二、过程 &#xff08;1&#xff09;获取MySQL 8.0社区版&#xff08;MySQL Community Server&#xff09;   从 官网 字样 “MySQL …

3D印刷电路板在线渲染查看工具

从概念上讲&#xff0c;这是有道理的&#xff0c;因为PCB印制电路板上的走线从一个连接到下一个连接的路线基本上是平面的。 然而&#xff0c;我们生活在一个 3 维世界中&#xff0c;能够以这种方式可视化电路以及相应的组件&#xff0c;对于设计过程很有帮助。本文将介绍KiCad…

VsCode Ctrl+.修复无效

vscode 快速修复(quick fix) 快捷键(Ctrl .)被占用问题解决方法_vscode快速修复快捷键_追求者2016的博客-CSDN博客

Android 系统源码目录frameworks/base/packages和packages/apps下的APP区别

概要 在 Android Open Source Project (AOSP) 源代码中&#xff0c;frameworks/base/packages 和 packages/apps 目录都包含 Android 系统中的应用程序&#xff0c;但它们在性质和用途上有一些区别&#xff1a; 1&#xff0c;frameworks/base/packages frameworks/base 目录…

OMRON G9SP和NB触摸屏使用232口通讯

G9SP和NB触摸屏使用232口通讯 实验时间&#xff1a;2023/9/7 实验设备&#xff1a;G9SP-N20S、CP1W-CIF01&#xff08;232串口选减板&#xff09;、NB5Q-TW00B、XW2Z-200T&#xff08;串口线&#xff09;&#xff0c;CP1W-20EDT1&#xff0c;D4GS-N4T&#xff08;安全门开关&a…

alibaba国际版阿里巴巴API接入说明(阿里巴巴商品详情+关键词搜索商品列表)

API地址:https://o0b.cn/anzexi 调用示例&#xff1a;https://api-gw.onebound.cn/alibaba/item_get/?keytest_api_key& &num_iid60840463360&&langzh-CN&secret 参数说明 通用参数说明 url说明 https://api-gw.onebound.cn/平台/API类型/ 平台&#xf…

Golang 方法使用的注意事项和细节

方法的声明(定义) furie (recevier type) methodName (参数列表) (返回值列表){方法体return返回值 } 1)参数列表&#xff1a;表示方法输入 2) recevier type:表示这个方法和type这个类型进行绑定&#xff0c;或者说该方法作用于type类型 3) receiver type:type可以是结构体…

mysql 安全加固

PS&#xff1a;之前在做安全测试的时候&#xff0c;报告mysql有安全漏洞&#xff0c;于是研究了下如何修复&#xff0c;于是记录下来分享给大家 1.1修改mysql 存放位置 修复 1.停服务 service mysqld stop2.迁位置 2.1 新建迁移目录 mkdir /home/database2.2 迁移数据文件…

深入探索KVM虚拟化技术:全面掌握虚拟机的创建与管理

文章目录 安装KVM开启cpu虚拟化安装KVM检查环境是否正常 KVM图形化创建虚拟机上传ISO创建虚拟机加载镜像配置内存添加磁盘能否手工指定存储路径呢&#xff1f;创建成功安装完成查看虚拟机 KVM命令行创建虚拟机创建磁盘通过命令行创建虚拟机手动安装虚拟机 KVM命令行创建虚拟机-…

如何基于国标GB28181视频平台EasyGBS国标云服务平台建设智慧环保在线监测系统

EasyGBS平台可提供流媒体接入、处理、转发等服务&#xff0c;支持内网、公网的安防视频监控设备通过国标GB/T28181协议进行视频监控直播。基于视频图像的环保监督管理智能监控系统&#xff0c;结合了计算机技术、AI、云计算、网络传输技术和网络存储技术等先进技术&#xff0c;…

CloudQuery X PolarDB:让数据库管理更简单

前言&#xff1a;8 月 15 日&#xff0c;CloudQuery 数据操作管控平台与阿里云 PolarDB 数据库管理软件&#xff0c;完成产品集成认证测试。也在以下功能上完善了用户使用 PolarDB 的体验&#xff0c;使数据库的管理更加安全高效。 支持在 CloudQuery 中创建连接&#xff0c;便…

如何学习python?比较通义千问、文心一言、ChatGPT给的答案,你就知道啦

通义千问 通义千问是阿里巴巴达摩院自主研发的超大规模语言模型&#xff0c;能够回答问题、创作文字&#xff0c;还能表达观点、撰写代码。通义千问的能力覆盖自然语言处理的多个领域&#xff0c;包括语言理解、文本生成、代码写作等。通义千问在多项性能指标上达到了业界领先水…

springcloudSeata处理分布式事务之1.7.0

1.5.0之后版本发生了很大改变 1.seata安装 1.1官网地址 http://seata.io/zh-cn/ 1.2下载地址 https://github.com/seata/seata/releases 下载的是seata-server-1.7.0.zip 1.3seata相关配置的修改 seata-server-1.7.0\seata\conf下的application.yml进行修改 server:por…

香港服务器怎么解除被封ip?

​  解除被封IP的方法因具体情况而异&#xff0c;需要根据实际情况选择合适的解决方案。本文关于香港服务器被封IP的常见解除方法有以下步骤。 第一步&#xff1a;服务器检查 用户需要立即启动服务器进行检查。或提前申请免费试用。如果IP地址被屏蔽&#xff0c;请联系客户服…

E. Data Structures Fan(思维 + 异或前缀和)

Problem - E - Codeforces 给你一个整数数组 a1, a2,..., an&#xff0c;以及一个由 n 个字符组成的二进制字符串† s。 Augustin 是一个数据结构的爱好者。因此&#xff0c;他请你实现一个可以回答 q 个查询的数据结构。这里有两种类型的查询&#xff1a; Plain Text "1…

3次多项式轨迹规划(PLC SCL代码)

机器人、运动控制等常用的轨迹规划有三次多项式、五次多项式、梯形速度规划,S型速度规划,今天我们主要介绍三次多项式轨迹规划,有关T型和S型轨迹规划大家可以查看下面文章博客,这里不再赘述, 梯形轨迹规划 梯形速度曲线轨迹规划(速度前馈+PID、SCL+ ST代码)_RXXW_Dor的博…

c++中的list容器讲解

文章目录 1. list的介绍及使用1.1 list的介绍1.2 list的使用1.2.1 list的构造1.2.2 list iterator的使用1.2.3 list capacity1.2.4 list element access1.2.6 list的迭代器失效 2. list的模拟实现2.1 模拟实现list 3. list与vector的对比 1. list的介绍及使用 1.1 list的介绍 …

ONNX OpenVino TensorRT MediaPipe NCNN Diffusers ComfyUI

框架 和Java生成的中间文件可以在JVM上运行一样&#xff0c;AI技术在具体落地应用方面&#xff0c;和其他软件技术一样&#xff0c;也需要具体的部署和实施的。既然要做部署&#xff0c;那就会有不同平台设备上的各种不同的部署方法和相关的部署架构工具 onnx 在训练模型时可以…

基于SpringBoot的摄影跟拍预定管理系统

基于SpringBootVue的摄影跟拍预定管理系统&#xff0c;前后端分离 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 【系统功能】   角色&#xff1a;管理员、用户…

C++进阶:异常和智能指针

异常 传统错误处理机制是assert断言和errno错误码。两种方式都有很大的局限性&#xff1a; 错误处理机制局限性断言强制终止程序&#xff0c;用户难以接受错误码返回值传递错误码&#xff0c;占用函数返回位置&#xff1b;无法直接展示信息&#xff0c;需查错误码表 1. 异常…