ARM64 虚拟地址长度判别

ARM64 支持多种虚拟地址长度,在运行时可通过 vabits_actual 变量判别。

vabits_actual5383cc6efed1 (“arm64: mm: Introduce vabits_actual”) 于 v5.4 引入(patchwork 链接 ),由 67e7fdfcc682 (“arm64: mm: introduce 52-bit userspace support”) 引入的 vabits_user 演进而来。

在 v5.10 中,该变量的赋值位于 arch/arm64/kernel/head.S 的 __create_page_tables

 1#ifdef CONFIG_ARM64_VA_BITS_52
 2        mrs_s   x6, SYS_ID_AA64MMFR2_EL1
 3        and     x6, x6, #(0xf << ID_AA64MMFR2_LVA_SHIFT)
 4        mov     x5, #52
 5        cbnz    x6, 1f
 6#endif
 7        mov     x5, #VA_BITS_MIN
 81:
 9        adr_l   x6, vabits_actual
10        str     x5, [x6]
11        dmb     sy
12        dc      ivac, x6                // Invalidate potentially stale cache line

当前主线(v6.2)中的实现,与 5.10 相比有较大变化:

 1        /*
 2         * The following callee saved general purpose registers are used on the
 3         * primary lowlevel boot path:
 4         *
 5         *  Register   Scope                      Purpose
 6         *  x20        primary_entry() .. __primary_switch()    CPU boot mode
 7         *  x21        primary_entry() .. start_kernel()        FDT pointer passed at boot in x0
 8         *  x22        create_idmap() .. start_kernel()         ID map VA of the DT blob
 9         *  x23        primary_entry() .. start_kernel()        physical misalignment/KASLR offset
10         *  x24        __primary_switch()                       linear map KASLR seed
11         *  x25        primary_entry() .. start_kernel()        supported VA size
12         *  x28        create_idmap()                           callee preserved temp register
13         */
14SYM_CODE_START(primary_entry)
15        /* . . . */
16#if VA_BITS > 48
17        mrs_s   x0, SYS_ID_AA64MMFR2_EL1
18        tst     x0, #0xf << ID_AA64MMFR2_EL1_VARange_SHIFT
19        mov     x0, #VA_BITS
20        mov     x25, #VA_BITS_MIN
21        csel    x25, x25, x0, eq
22        mov     x0, x25
23#endif
24
25        /* . . . */
26
27SYM_FUNC_START_LOCAL(__primary_switched)
28        /* . . . */
29#if VA_BITS > 48
30        adr_l   x8, vabits_actual               // Set this early so KASAN early init
31        str     x25, [x8]                       // ... observes the correct value
32        dc      civac, x8                       // Make visible to booting secondaries
33#endif

代码中还有两个与之类似的常量:VA_BITSVA_BITS_MIN

1// arch/arm64/include/asm/memory.h
2#if VA_BITS > 48
3#define VA_BITS_MIN		(48)
4#else
5#define VA_BITS_MIN		(VA_BITS)
6#endif

内核文档 Documentation/arm64/memory.rst 中 “52-bit VA support in the kernel” 一节有对上述三者的描述:

Most code in the kernel should not need to consider the VA_BITS, for code that does need to know the VA size the variables are defined as follows:

  • VA_BITS constant the maximum VA space size
  • VA_BITS_MIN constant the minimum VA space size
  • vabits_actual variable the actual VA space size

Maximum and minimum sizes can be useful to ensure that buffers are sized large enough or that addresses are positioned close enough for the “worst” case.

虚拟地址长度设定条件:

  1. 内核 config 是否开启: CONFIG_ARM64_VA_BITS

  2. 硬件是否支持:系统寄存器 ID_AA64MMFR2_EL1 中的 VARange[19:16] 段(ARM 文档

    该段的偏移在 v5.10 代码中体现为 ID_AA64MMFR2_LVA_SHIFT,其经过多次改名([1][2] )最终变为 ID_AA64MMFR2_EL1_VARange_SHIFT ,以实现与 ARM 文档中的命名对齐,并最终实现了自动生成 。自动生成的部分详见 arch/arm64/tools/sysreg


ARMv8.3 的 PAC 特性
Slab Merging 特性