ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ATF之BL1跳转到BL2的过程。

2020-02-20 19:43:20  阅读:586  来源: 互联网

标签:ATF sp SPSR BL2 context 跳转 EL3


0x00 Intro

ATF(ARM Trusted Firmware)作为一个bootload,其本身最终要的作用就是load各阶段的镜像到执行地址,然后跳转过去继续执行。
根据以往经验,ARM处理器跳转到不同的镜像可以通过直接修改PC寄存器来实现。当然除了修改PC寄存器可能还需要在跳转之前初始化相关的环境、以及后续堆栈等。
这篇文章就是记录ATF从BL1跳转到BL2的过程。

0x01 总体时序

先放整体时序图,图中仅保留和跳转相关的函数。入口是BL1的entrypoint,出口是通过ERET指令跳转到BL2
在这里插入图片描述

0x02 ERET指令

从时序图可以看到,从BL1执行到BL2是通过ERET指令实现的,那先看下ERET指令。
在这里插入图片描述
ERET指令用于异常返回,返回地址和处理器状态是从当前EL(exception level)下的ELR和SPSR寄存器中恢复的。即ELR寄存器中的值就是BL1最后跳转的目的地址,SPSR寄存器的值就是条状之后处理的状态。所以在代码中重点关注这两个值的初始化。

0x03 ELR & SPSR赋值

BL1在初始化过程中有一个比较重要的数据结构,cpu_context。cpu_context在初始化的过程中需要把各个域都填充,ELR和SPSR寄存也存放在这个数据结构中,位于el3state_ctx域。
在这里插入图片描述
具体填充的语句如下:

state = get_el3state_ctx(ctx);
write_ctx_reg(state, CTX_SCR_EL3, scr_el3);
write_ctx_reg(state, CTX_ELR_EL3, ep->pc);
write_ctx_reg(state, CTX_SPSR_EL3, ep->spsr);

先将state定位到cpu_context的el3_state域,然后依次将pc和spsr分别填到el3_state的ELR和SPSR中。那ep->pc和ep->spsr来源于何处呢?

spsr

SPSR来源于bl1_context_mgmt.c中的bl1_prepare_next_image函数:

next_bl_ep->spsr = SPSR_64(mode, MODE_SP_ELX,
	DISABLE_ALL_EXCEPTIONS);

pc

PC来源于BL2镜像的描述数据结构,定义在common_def.h中,如下所示:

#define BL2_IMAGE_DESC {				\
	.image_id = BL2_IMAGE_ID,			\
	SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,	\
		VERSION_2, image_info_t, 0),		\
	.image_info.image_base = BL2_BASE,		\
	.image_info.image_max_size = BL2_LIMIT - BL2_BASE,\
	SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,	\
		VERSION_2, entry_point_info_t, SECURE | EXECUTABLE),\
	.ep_info.pc = BL2_BASE,				\
}

可见ep_info.pc被初始化成了BL2_BASE。

所以ELR被初始化成了BL2_BASE, SPSR也有了值。

0x04 SP堆栈寄存器

前面看到ELR和SPSR只是被保存到了context_cpu中,那最终是如何设置到处理器的相关寄存器中呢?
答案是堆栈,最后通过sp指针弹出再设到相关寄存器中。sp堆栈的初始化时在context_mgmt.h的cm_set_next_context()函数中实现的。

	__asm__ volatile("msr	spsel, #1\n"
			 "mov	sp, %0\n"
			 "msr	spsel, #0\n"
			 : : "r" (context));

这里有个问题,如果只需要设sp,为啥还要设置spsel寄存器?
根据本博客前期的文章[ARM v8 AArch64 Programmers’ model]可以知道,ARMv8除了可以使用当前模式下的sp,也可以使用EL0的sp。除EL0以外的模式,SP是可以选择的,可以使用ELx_SP,也可以选择使用EL0_SP。ba
这条语句的作用就是首先选择使用EL3_SP,然后将EL3_SP指向cpu_context数据结构,最后又将sp调整为EL0_SP
那为什么要来回设置sp呢?不设置可以吗?
答案来回设置sp更合理一些。因为设置sp后,堆栈内容就变成了cpu_context了,这里面都BL2运行需要的寄存器数据。但是这里只是设置了sp,到真正去使用sp中的内容还有大段代码需要运行。这些代码很有可能会去修改堆栈中的内容,这会导致BL2运行环境异常。
所以这里把el3_sp修改之后,就立即切换到el0_sp,用el0的sp来跑后面的代码,防止el3_sp中的内容被修改。

0x05 跳转

接着就到正式跳转了。

	mov	x17, sp
	msr	spsel, #MODE_SP_ELX
	str	x17, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP]

	/* ----------------------------------------------------------
	 * Restore SPSR_EL3, ELR_EL3 and SCR_EL3 prior to ERET
	 * ----------------------------------------------------------
	 */
	ldr	x18, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]
	ldp	x16, x17, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
	msr	scr_el3, x18
	msr	spsr_el3, x16
	msr	elr_el3, x17

可以看到果然就是首先切换sp,把sp切到el3_sp。同时把当前的sp保存到cpu_context的runtime_sp中。然后通过ldp指令,从堆栈中把之前保存到cpu_context中的ELR和SPSR保存到x17和X16中。然后x17/x16恢复到spsr和elr中。
最后通过
eret指令跳转到elr,而elr就是BL2_BASE。

.macro exception_return
eret
dsb nsh
isb
.endm

[1]. Arm® Architecture Reference Manual
[2]. Arm® A64 Instruction Set Architecture
[3]. Arm® Architecture Registers

阿曼 发布了94 篇原创文章 · 获赞 31 · 访问量 29万+ 私信 关注

标签:ATF,sp,SPSR,BL2,context,跳转,EL3
来源: https://blog.csdn.net/rockrockwu/article/details/104409948

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有