慢慢欣赏arm64内核启动10 primary_entry之set_cpu_boot_mode_flag

回顾

上面的文章我们分析完毕el2_setup函数,该函数虽长但不啰嗦。

主要作用就是如果bootloader把控制权交给内核时,如果内核是EL1异常模式,则按照EL1模式初始化一些系统寄存器,然后返回w0为EL1;

如果内核当前为EL2模式,则判断硬件是否支VHE,如果不支持,则切换到EL1;如果支持,则继续以EL2模式启动,这两种情况返回w0均为EL2。

分析代码

本章节继续el2_setup后面的部分

	adrp	x23, __PHYS_OFFSET
	and	x23, x23, MIN_KIMG_ALIGN - 1	// KASLR offset, defaults to 0

/*
 * Sets the __boot_cpu_mode flag depending on the CPU boot mode passed
 * in w0. See arch/arm64/include/asm/virt.h for more info.
 */
SYM_FUNC_START_LOCAL(set_cpu_boot_mode_flag)
	adr_l	x1, __boot_cpu_mode
	cmp	w0, #BOOT_CPU_MODE_EL2
	b.ne	1f
	add	x1, x1, #4
1:	str	w0, [x1]			// This CPU has booted in EL1
	dmb	sy
	dc	ivac, x1			// Invalidate potentially stale cache line
	ret
SYM_FUNC_END(set_cpu_boot_mode_flag)

__PHYS_OFFSET

第1行涉及到宏定义 __PHYS_OFFSET,我们在内核代码查找其定义

$ grep -rn KERNEL_START ./arch/arm64/
./arch/arm64/kernel/head.S:39:#define __PHYS_OFFSET	KERNEL_START
./arch/arm64/include/asm/memory.h:67:#define KERNEL_START		_text

而 _text 在链接脚本里面定义,属于 .head.text 的起始链接地址,经过一连串眼花缭乱的计算,其值为 0xFFFF 8000 1000 0000,大家忘记的话可以去第一章节回顾一下:)
注意,这个指令使用的是adrp,说明我们将_text所在的物理地址加载到x23里面。

第2行涉及到宏定义 MIN_KIMG_ALIGN,根据注释提示,我们假设其默认值就是0,所以这句话可以忽略不计。

__boot_cpu_mode

第4行到第7行则是函数 set_cpu_boot_mode_flag 的注释。
含义是将 w0 的值保存到 __boot_cpu_mode 里面,因为 w0 是常用寄存器,我们费了那么大的心思获取的w0可不想无意丢弃。我们再看看 __boot_cpu_mode 的定义

/*
 * We need to find out the CPU boot mode long after boot, so we need to
 * store it in a writable variable.
 *
 * This is not in .bss, because we set it sufficiently early that the boot-time
 * zeroing of .bss would clobber it.
 */
SYM_DATA_START(__boot_cpu_mode)
	.long	BOOT_CPU_MODE_EL2
	.long	BOOT_CPU_MODE_EL1
SYM_DATA_END(__boot_cpu_mode)

两个长整型的全局变量,默认值定义如下:

arch/arm64/include/asm/virt.h:45:#define BOOT_CPU_MODE_EL2	(0xe12)
arch/arm64/include/asm/virt.h:44:#define BOOT_CPU_MODE_EL1	(0xe11)

.long 表示是 32位有符号数,即4个Byte

第9行的含义是将 全局变量 __boot_cpu_mode 的物理地址放到x1寄存器里面

第10行的含义是将w0与宏定义 BOOT_CPU_MODE_EL2 的值进行比较,如果不相等,也就是启动模式为EL1时,则跳转到第13行,如果相等,也就是启动模式为EL2时,则继续执行12行。

第12行 将x1自增4个Byte,也就是x1指向第2个long

第13行将w0保存在x1指向地址的内存里面。

如果w0为 BOOT_CPU_MODE_EL2,那么 __boot_cpu_mode 的布局变成了
    .long    BOOT_CPU_MODE_EL2
    .long    BOOT_CPU_MODE_EL2

如果w0为 BOOT_CPU_MODE_EL1, 那么 __boot_cpu_mode 的布局变成了
    .long    BOOT_CPU_MODE_EL1
    .long    BOOT_CPU_MODE_EL1
使用1个.long表示启动模式不行吗?作者这样的操作我不太看的明白,可能只有等将来获取该变量的时候才会感知作者的良苦用心。
第14行是内存屏障,第15行是刷新cache,保障上述对内存的写操作能够写入成功并且别的core能够感知。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值