慢慢欣赏arm64内核启动21 primary_entry之__cpu_setup代码第三部分

展示代码

	/*
	 * Set/prepare TCR and TTBR. We use 512GB (39-bit) address range for
	 * both user and kernel.
	 */
	mov_q	x10, TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \
			TCR_TG_FLAGS | TCR_KASLR_FLAGS | TCR_ASID16 | \
			TCR_TBI0 | TCR_A1 | TCR_KASAN_FLAGS
	tcr_clear_errata_bits x10, x9, x5

#ifdef CONFIG_ARM64_VA_BITS_52
	ldr_l		x9, vabits_actual
	sub		x9, xzr, x9
	add		x9, x9, #64
	tcr_set_t1sz	x10, x9
#else
	ldr_l		x9, idmap_t0sz
#endif
	tcr_set_t0sz	x10, x9

分析代码

第1行到第4行是注释,设置和准备 TCR 和 TTBR 寄存器,并且设置地址空间大小为 512GB == 2^39

TCR_EL1

在ARM架构中,TCR_EL1(Translation Control Register)是一个重要的系统寄存器,它用于控制内存的转换行为。

第5行到第7行时将寄存器的一堆域粘合起来,存放到 x10 里面,根据上下文描述,应该是与 TCR_EL1 寄存器有关。
TCR_EL1, Translation Control Register (EL1),含义如下 The control register for stage 1 of the EL1&0 translation regime.
涉及的宏定义如下

#define TCR_TxSZ(x)		(TCR_T0SZ(x) | TCR_T1SZ(x))

继续展开

#define TCR_T0SZ(x)		((UL(64) - (x)) << TCR_T0SZ_OFFSET)
#define TCR_T1SZ(x)		((UL(64) - (x)) << TCR_T1SZ_OFFSET)

再继续展开

#define TCR_T0SZ_OFFSET		0
#define TCR_T1SZ_OFFSET		16

而 VA_BITS 的值我们之前讨论过,为48
所以 TCR_TxSZ(VA_BITS) 为

((64 - 48)  << 0) | ((64 - 48) << 16)
== (16 << 0) | (16 << 16)

对应 TCR_EL1 的 T1SZ 域描述如下:
T1SZ, bits [21:16]
The size offset of the memory region addressed by TTBR1_EL1. The region size is 2(64-T1SZ) bytes.
对应 TCR_EL1 的 T0SZ 域描述如下:
T0SZ, bits [5:0]
The size offset of the memory region addressed by TTBR0_EL1. The region size is 2(64-T0SZ) bytes.
所以 TTBR0 和 TTBR1 的空间大小为  2^48 == 2^18G

TCR_CACHE_FLAGS 描述如下
/* PTWs cacheable, inner/outer WBWA */
展开宏定义

#define TCR_CACHE_FLAGS	TCR_IRGN_WBWA | TCR_ORGN_WBWA
#define TCR_IRGN_WBWA		(TCR_IRGN0_WBWA | TCR_IRGN1_WBWA)
#define TCR_IRGN0_WBWA		(UL(1) << TCR_IRGN0_SHIFT)
#define TCR_IRGN1_WBWA		(UL(1) << TCR_IRGN1_SHIFT)
#define TCR_IRGN0_SHIFT		8
#define TCR_IRGN1_SHIFT		24

对应寄存器的位域描述如下:
IRGN1, bits [25:24]
    Inner cacheability attribute for memory associated with translation table walks using TTBR1_EL1.
    0b00 Normal memory, Inner Non-cacheable.
    0b01 Normal memory, Inner Write-Back Read-Allocate Write-Allocate Cacheable.
    0b10 Normal memory, Inner Write-Through Read-Allocate No Write-Allocate Cacheable.
    0b11 Normal memory, Inner Write-Back Read-Allocate No Write-Allocate Cacheable.

IRGN0, bits [9:8]
    Inner cacheability attribute for memory associated with translation table walks using TTBR0_EL1.
    0b00 Normal memory, Inner Non-cacheable.
    0b01 Normal memory, Inner Write-Back Read-Allocate Write-Allocate Cacheable.
    0b10 Normal memory, Inner Write-Through Read-Allocate No Write-Allocate Cacheable.
    0b11 Normal memory, Inner Write-Back Read-Allocate No Write-Allocate Cacheable.
综上所述,无论对于 TTBR1_EL1 还是对于 TTBR0_EL1,Normal memory 都是 Inner Write-Back Read-Allocate Write-Allocate Cacheable

TCR_SMP_FLAGS 涉及到的宏定义如下

#define TCR_SMP_FLAGS	TCR_SHARED
#define TCR_SHARED		(TCR_SH0_INNER | TCR_SH1_INNER)
#define TCR_SH0_INNER		(UL(3) << TCR_SH0_SHIFT)
#define TCR_SH1_INNER		(UL(3) << TCR_SH1_SHIFT)
#define TCR_SH0_SHIFT		12
#define TCR_SH1_SHIFT		28

寄存器的相关位域定义如下
SH1, bits [29:28]
    Shareability attribute for memory associated with translation table walks using TTBR1_EL1.
        0b00 Non-shareable.
        0b10 Outer Shareable.
        0b11 Inner Shareable
SH0, bits [13:12]
    Shareability attribute for memory associated with translation table walks using TTBR0_EL1.
        0b00 Non-shareable
        0b10 Outer Shareable
        0b11 Inner Shareable
综上所述,无论对于 TTBR1_EL1 还是对于 TTBR0_EL1,Normal memory 的共享属性是 Inner Shareable。关于SH0和SH1的深入理解,可以参考文档1

 TCR_TG_FLAGS 涉及到的宏定义如下

#ifdef CONFIG_ARM64_64K_PAGES
#define TCR_TG_FLAGS	TCR_TG0_64K | TCR_TG1_64K
#elif defined(CONFIG_ARM64_16K_PAGES)
#define TCR_TG_FLAGS	TCR_TG0_16K | TCR_TG1_16K
#else /* CONFIG_ARM64_4K_PAGES */
#define TCR_TG_FLAGS	TCR_TG0_4K | TCR_TG1_4K
#endif
#define TCR_TG0_4K		(UL(0) << TCR_TG0_SHIFT)
#define TCR_TG1_4K		(UL(2) << TCR_TG1_SHIFT)
#define TCR_TG0_SHIFT		14
#define TCR_TG1_SHIFT		30

寄存器的相关位域定义如下
TG1, bits [31:30]
    Granule size for the TTBR1_EL1.
    0b01 16KB.
    0b10 4KB.
    0b11 64KB.
TG0, bits [15:14]
    Granule size for the TTBR0_EL1.
    0b00 4KB
    0b01 64KB
    0b10 16KB
该位域设置 TTBRX_EL1 的粒度大小。通过上面的内核代码可知,可以通过内核配置进行配置,可以设置的大小为 4K,16K和64K,默认配置是 4K,如下所示:

$ cat .config | grep CONFIG_ARM64_4K_PAGES
CONFIG_ARM64_4K_PAGES=y

TCR_KASLR_FLAGS涉及到的位域含义如下

#ifdef CONFIG_RANDOMIZE_BASE
#define TCR_KASLR_FLAGS	TCR_NFD1
#else
#define TCR_KASLR_FLAGS	0
#endif

$ cat .config | grep CONFIG_RANDOMIZE_BASE
CONFIG_RANDOMIZE_BASE=y

#define TCR_NFD1		(UL(1) << 54)

NFD1是TCR_EL1寄存器中的一个位域,代表“Non-Folding Disable for SVE”。SVE(Scalable Vector Extension)是ARMv8.5-A架构中引入的可扩展矢量扩展,它允许处理器动态地调整矢量寄存器的大小。
NFD1位的作用是控制SVE矢量长度的折叠行为。当NFD1位被设置为1时,它禁用了SVE矢量长度的折叠,这意味着处理器将使用完整的矢量长度,而不是在需要时折叠成较小的矢量长度。
这可以提高性能,因为减少了矢量长度变化带来的开销。
TCR_ASID16 涉及到的位域含义如下

#define TCR_ASID16		(UL(1) << 36)

芯片手册描述如下

AS, bit [36]
ASID Size. Defined values are:
    0b0 8 bit - the upper 8 bits of TTBR0_EL1 and TTBR1_EL1 are ignored by hardware for every purpose except reading back the register, 
    and are treated as if they are all zeros for when used for allocation and matching entries in the TLB.
    0b1 16 bit - the upper 16 bits of TTBR0_EL1 and TTBR1_EL1 are used for allocation and matching in the TLB.

在ARM64架构中,TCR_EL1(Translation Control Register)寄存器的位域AS,位于第36位,
代表“ASID size”。这个位域用于控制地址空间标识符(ASID)的大小。
ASID用于在进行内存翻译时区分不同的地址空间,特别是在多任务操作系统中,用于区分不同进程的地址空间。
当AS位设置为0时,表示ASID的大小为8位。
当AS位设置为1时,表示ASID的大小为16位。
ASID的大小决定了操作系统可以拥有的并发地址空间的数量。增加ASID的大小可以增加并发地址空间的数量,
这在多任务环境中非常有用,因为它允许更多的进程或任务同时运行而不会相互干扰。
然而,增加ASID的大小也会增加TLB(Translation Lookaside Buffer)的负担,因为需要更多的空间来存储ASID信息,这可能会影响TLB的效率。
因此,AS位的选择取决于系统的设计需求,需要在地址空间的数量和TLB效率之间做出权衡。

TCR_TBI0 对应的位域如下

#define TCR_TBI0		(UL(1) << 37)

芯片手册描述如下
TBI0, bit [37]
Top Byte ignored - indicates whether the top byte of an address is used for address match for the TTBR0_EL1 region, 
or ignored and used for tagged addresses. Defined values are:
    0b0 Top Byte used in the address calculation.
    0b1 Top Byte ignored in the address calculation.
This affects addresses generated in EL0 and EL1 using AArch64 where the address would be translated by tables pointed to by TTBR0_EL1. 
It has an effect whether the EL1&0 translation regime is enabled or not.
其含义如下
TBI0位位于TCR_EL1寄存器的第37位。当TBI0位设置为1时,表示在进行地址翻译时,虚拟地址的最高字节(即地址的[63:56]位)将被忽略,
这通常用于支持内存标签扩展(Memory Tagging Extension, MTE)。如果TBI0位为0,则表示虚拟地址的最高字节将被用于地址计算。
在Linux里面,TBI0位默认设置为1,这允许用户空间(EL0)通过具有非零最高字节的64位指针进行内存访问。
这种机制可以用于支持标记地址ABI(Application Binary Interface),它允许用户空间传递某些标记指针给内核系统调用。
依此类推,TCR_TBI1

#define TCR_TBI1		(UL(1) << 38)

Top Byte ignored - indicates whether the top byte of an address is used for address match for the TTBR1_EL1 region, 
or ignored and used for tagged addresses. Defined values are:
    0b0 Top Byte used in the address calculation.
    0b1 Top Byte ignored in the address calculation.
This affects addresses generated in EL0 and EL1 using AArch64 where the address would be translated by tables pointed to by TTBR1_EL1. 
It has an effect whether the EL1&0 translation regime is enabled or not.
在ARM64架构中,TCR_EL1(Translation Control Register)寄存器的TBI1位域代表“Top Byte Ignored”。
当TBI1位被设置为1时,处理器在进行地址翻译时会忽略虚拟地址的最高字节(即地址的[63:56]位)。
这通常与Memory Tagging Extension (MTE)一起使用,允许操作系统或应用程序在虚拟地址的最高字节中存储额外的信息,而不影响地址翻译。
TBI1位与TBI0位一起工作,它们分别控制两个不同的翻译表基址寄存器(TTBR0_EL1和TTBR1_EL1)的地址翻译行为。
如果TBI1为0,则表示虚拟地址的最高字节将被用于地址计算;如果TBI1为1,则该字节被忽略。这种机制可以提高地址空间的利用率,
允许操作系统或应用程序在不改变现有地址翻译机制的情况下,为指针添加额外的元数据。
例如,如果一个系统使用48位的虚拟地址,则有16位可以用于存储额外的信息。通过设置TBI1和TBI0,
系统可以在这些额外的位中存储诸如内存访问权限、类型标签或其他自定义数据,从而增强内存管理的灵活性和安全性。
这种技术在某些操作系统和高性能计算应用中非常有用,它们需要在不牺牲地址空间的情况下,为内存访问提供额外的上下文信息。
TCR_A1 对应的位域如下

#define TCR_A1			(UL(1) << 22)

芯片手册描述如下
A1, bit [22]
Selects whether TTBR0_EL1 or TTBR1_EL1 defines the ASID. The encoding of this bit is:
    0b0 TTBR0_EL1.ASID defines the ASID.
    0b1 TTBR1_EL1.ASID defines the ASID.
其功能是选择是否使用TTBR0_EL1或TTBR1_EL1中的ASID(Address Space Identifier)。A1位的具体含义如下:
当A1位设置为0时,表示使用TTBR0_EL1中的ASID来定义当前的地址空间。
当A1位设置为1时,表示使用TTBR1_EL1中的ASID来定义当前的地址空间。
这个位允许操作系统或虚拟化环境在不同的地址空间之间进行选择,以支持不同的进程或虚拟机。
通过改变A1位的值,可以快速切换使用不同的页表和ASID,从而实现地址空间的快速切换。这对于多任务操作系统和虚拟化技术是非常重要的。

TCR_KASAN_FLAGS 涉及的宏定义如下

#ifdef CONFIG_KASAN_SW_TAGS
#define TCR_KASAN_FLAGS TCR_TBI1
#else
#define TCR_KASAN_FLAGS 0
#endif
$ cat .config | grep CONFIG_KASAN_SW_TAGS
$

所以 CONFIG_KASAN_SW_TAGS 不需要关心
上面一陀宏定义进行 “算术或” 的运算,存入 x10

第8行的含义是 解决部分芯片的一些 BUG

第10行的条件编译选项 CONFIG_ARM64_VA_BITS_52 我们没有使能,我们使能的是 CONFIG_ARM64_VA_BITS_48

$ cat .config | grep CONFIG_ARM64_VA_BITS
# CONFIG_ARM64_VA_BITS_39 is not set
CONFIG_ARM64_VA_BITS_48=y
CONFIG_ARM64_VA_BITS=48

所以进入第16行

第16行涉及全局变量 idmap_t0sz

u64 idmap_t0sz = TCR_T0SZ(VA_BITS_MIN);

经过拆分,其与前面分析过的 TCR_T0SZ(x) 相同


第18行域第16行类似

参考

参考1 aarch64的TCR寄存器介绍
https://blog.youkuaiyun.com/weixin_42135087/article/details/109057232

### Linux ARM64 架构下的启动过程 #### 汇编代码解析 对于Linux ARM64架构,在`arch/arm64/kernel/head.S`文件中定义了内核启动流程[^1]。该文件包含了多个重要的函数和宏,用于完成从引导加载程序到操作系统内核的过渡。 在最开始的部分,通过`.head.text`段声明了一系列入口点以及初始化指令[^5]: ```assembly .section .head.text, "ax" .global __primary_switched __primary_switched: adr_x0, . bl primary_entry ``` 上述代码片段展示了如何定位并跳转至主要入口函数`primary_entry()`。这里利用相对寻址方式(`adr`)来获取当前PC寄存器值,并将其传递给参数x0;随后调用子程序分支命令(bl),执行实际的目标位置处的功能逻辑。 接着是几个关键步骤描述如下: - **保存启动参数**:为了确保后续能够访问到来自BootLoader传入的信息(如内存布局),会有一个名为`preserve_boot_args`的过程负责这项工作[^2]。 ```assembly preserve_boot_args: stp x0, x1, [sp, #-16]! // Save arguments on stack ... ``` - **配置CPU状态**:根据具体硬件平台的需求调整异常级别(EL)和其他必要的设置项,这通常由`el2_setup`和`set_cpu_boot_mode_flag`等处理单元承担。 - **创建初始页表结构**:这是为了让MMU可以正常运作而构建的基础数据结构之一,它允许虚拟地址空间映射物理资源。 - **使能MMU (Memory Management Unit)** :一旦完成了前面提到的各项准备工作之后,则可以通过特定序列激活存储管理部件,从而启用分页机制和支持更复杂的内存保护特性。 最后当一切准备就绪后,控制流将会转向C语言写的`start_kernel()`函数继续剩余部分的操作系统初始化任务。 #### 关于汇编与C交互的技术细节 由于ARM64体系结构不支持类似于ARM32中的某些伪指令形式,所以在编写涉及跨语言接口的地方时需要注意差异性[^4]。例如,在ARM32中有`ldr reg, =label`这样的语法可以直接引用符号地址,但在ARM64环境下则需采用其他方法间接达成相同效果,像使用ADR/ADRP组合加上ADD指令的方式计算偏移量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值