arm64_linux head.S的执行流程(3.18)- 10.stext之__enable_mmu

1.前言

本文基于高通8996平台,kernel版本为3.18.31。
本文主要介绍head.S的__enable_mmu执行流程

根据前面对于lk的分析,系统启动后,lk会将kernel image copy到main memory,和虚拟地址空间类似,kernel image并没有copy到main memory的首地址,也保持了一个同样size的offset。现在,问题又来了:在kernel的开始运行阶段,MMU是OFF的,也就是说kernel image是直接运行在物理地址上的,但是实际上kernel是被linker链接到了虚拟地址上去的,在这种情况下,在没有turn on MMU之前,kernel能正常运行吗?可以的,如果kernel在turn on MMU之前的代码都是PIC(位置无关)的,那么代码实际上是可以在任意地址上运行的。你可以仔细观察turn on MMU之前的代码,都是位置无关的代码。

2. __enable_mmu

/*
 * Setup common bits before finally enabling the MMU. Essentially this is just
 * loading the page table pointer and vector base registers.
 *
 * On entry to this code, x0 must contain the SCTLR_EL1 value for turning on
 * the MMU.
 */
__enable_mmu:
//EL1状态的异常向量表 ,定义在kernel\arch\arm64\kernel\entry.S中
	ldr	x5, =vectors 
---(1) // VBAR_EL1 Vector Base Address Register (EL1),保存EL1状态的异常向量表	
	msr	vbar_el1, x5
	
// load TTBR0
---(2)// idmap_pg_dir(x25) 用于用户空间的进程,
    在进程切换的时候,其地址空间的切换实际就是修改TTBR0的值	
	msr	ttbr0_el1, x25	
		
// load TTBR1  
// swapper_pg_dir(x26) 用于kernel space,所有的内核线程都是共享一个空间		
	msr	ttbr1_el1, x26			
	isb
	b	__turn_mmu_on-----------(3)
ENDPROC(__enable_mmu)

/*
 * Enable the MMU. This completely changes the structure of the visible memory
 * space. You will not be able to trace execution through this.
 *
 *  x0  = system control register
 *  x27 = *virtual* address to jump to upon completion
 *
 * other registers depend on the function called upon completion
 *
 * We align the entire function to the smallest power of two larger than it to
 * ensure it fits within a single block map entry. Otherwise were PHYS_OFFSET
 * close to the end of a 512MB or 1GB block we might require an additional
 * table to map the entire function.
 */
	.align	4
__turn_mmu_on:
// 配置sctlr_el1(x0),系统控制寄存器
	msr	sctlr_el1, x0  
// 指令同步屏障	
	isb     
//跳转到__mmap_switched执行,不设定lr寄存器 	
	br	x27
ENDPROC(__turn_mmu_on)

传入__enable_mmu函数的参数有四个:
第一个是x0寄存器,该寄存器中保存了打开MMU时候要设定的SCTLR_EL1的值(在__cpu_setup函数中设定)
第二个是个是x25寄存器,保存了idmap_pg_dir的值
第三个参数是x26寄存器,保存了swapper_pg_dir的值
最后一个参数是x27,是执行完毕该函数之后,跳转到哪里去执行(__mmap_switched)。

  1. VBAR_EL1, Vector Base Address Register (EL1),该寄存器保存了EL1状态的异常向量表。在ARMv8中,发生了一个exception,首先需要确定的是该异常将送达哪一个exception level。如果一个exception最终送达EL1,那么cpu会跳转到这里向量表来执行。具体异常的处理过程由其他文档描述,这里就不说了。
  2. idmap_pg_dir是为turn on MMU准备的一致性映射,物理地址的高16bit都是0,因此identity mapping必定是选择TTBR0_EL1指向的各级地址翻译表。后续当系统运行之后,在进程切换的时候,会修改TTBR0的值,切换到真实的进程地址空间上去。TTBR1用于kernel space,所有的内核线程都是共享一个空间就是swapper_pg_dir。
  3. 打开MMU。实际上在这条指令的上下都有isb指令,理论上已经可以turn on MMU之前之后的代码执行顺序严格的定义下来,其实我感觉不必要再启用idmap_pg_dir的那些页表了,当然,这只是猜测。

参考文档

1.https://blog.csdn.net/xichangbao/article/details/51568782
2.https://www.cnblogs.com/smartjourneys/diary/2017/04/27/6774121.html
3.http://www.wowotech.net/armv8a_arch/arm64_initialize_1.html ARM64的启动过程之(一):内核第一个脚印
3.http://www.wowotech.net/armv8a_arch/create_page_tables.html ARM64的启动过程之(二):创建启动阶段的页表
4.http://www.wowotech.net/armv8a_arch/__cpu_setup.html ARM64的启动过程之(三):为打开MMU而进行的CPU初始化
5.http://www.wowotech.net/armv8a_arch/turn-on-mmu.html ARM64的启动过程之(四):打开MMU
6.https://blog.csdn.net/xichangbao/article/details/51568782 Kernel启动流程源码解析 1 head.S
7.https://blog.csdn.net/xichangbao/article/details/51605462 Kernel启动流程源码解析 2 head.S

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值