无法使用 ttbr0_el1 寄存器读取页表..(arm64)

can't read the pagetable using ttbr0_el1 register..(arm64)

在设备驱动程序中,我想读取 ttbr0_el1 寄存器(翻译 table EL1 的基址寄存器)指向的第一个数据,如下所示。但是引用指针会导致陷阱(数据访问中止)。怎么了?

static inline uint64_t system_read_TTBR0_EL1(void)
{
    uint64_t val;
    asm volatile("mrs %0, ttbr0_el1" : "=r" (val));
    return val;
}

static inline uint64_t system_read_TTBR1_EL1(void)
{
    uint64_t val;
    asm volatile("mrs %0, ttbr1_el1" : "=r" (val));
    return val;
}

ttbr0_el1 = system_read_TTBR0_EL1();
ttbr1_el1 = system_read_TTBR1_EL1();
printk("ttbr0 = %llx\n", ttbr0_el1);
printk("ttbr1 = %llx\n", ttbr1_el1);
printk("*ttbr1 = %llx\n", *(uint64_t *)ttbr1_el1);
printk("*ttbr0 = %llx\n", *(uint64_t *)ttbr0_el1);

输出

[100450.356279] ttbr0 = 27f0000042dd7001
[100450.356595] ttbr1 = 27f00000414ab001
[100450.357015] Unable to handle kernel paging request at virtual address 27f00000414ab001
[100450.357564] Mem abort info:
[100450.357803]   ESR = 0x96000004
[100450.358116]   EC = 0x25: DABT (current EL), IL = 32 bits
[100450.358535]   SET = 0, FnV = 0
[100450.359256]   EA = 0, S1PTW = 0
[100450.359537] Data abort info:
[100450.359785]   ISV = 0, ISS = 0x00000004
[100450.360101]   CM = 0, WnR = 0
[100450.360449] [27f00000414ab001] address between user and kernel address ranges
[100450.360986] Internal error: Oops: 96000004 [#22] SMP

首先,您需要屏蔽掉一些东西:

但不仅如此,甚至还有更多。来自 the manual:

Translation table base address:

•   Bits A[47:x] of the stage 1 translation table base address bits are in
    register bits[47:x].
•   Bits A[(x-1):0] of the stage 1 translation table base address are zero.

Address bit x is the minimum address bit required to align the translation
table to the size of the table. The smallest permitted value of x is 6. The
AArch64 Virtual Memory System Architecture chapter describes how x is
calculated based on the value of TCR_EL1.T0SZ, the translation stage, and
the translation granule size.

-------- Note ------------
A translation table is required to be aligned to the size of the table. If
a table contains fewer than eight entries, it must be aligned on a 64 byte
address boundary.
--------------------------

If the value of TCR_EL1.IPS is not 0b110, then:

•   Register bits[(x-1):1] are RES0.
•   If the implementation supports 52-bit PAs and IPAs, then bits A[51:48]
    of the stage 1 translation table base address are 0b0000.

If FEAT_LPA is implemented and the value of TCR_EL1.IPS is 0b110, then:

•   Bits A[51:48] of the stage 1 translation table base address bits are
    in register bits[5:2].
•   Register bit[1] is RES0.

描述继续解释无效值的允许影响,但如果我们假设仅有效使用 TTBR 寄存器,那么这就是您提取有效物理基地址的方式:

static inline uint64_t ttbr0_base_address(void)
{
    uint64_t val;
    asm volatile("mrs %0, ttbr0_el1" : "=r" (val));
    return (val & 0xffffffffffc0) | ((val & 0x3c) << 46);
}

static inline uint64_t ttbr1_base_address(void)
{
    uint64_t val;
    asm volatile("mrs %0, ttbr1_el1" : "=r" (val));
    return (val & 0xffffffffffc0) | ((val & 0x3c) << 46);
}

但是如果您 运行 Linux 正常,那么您不太可能能够按原样取消引用该地址。您需要获取该物理地址的虚拟映射。假设东西在 DRAM 中的标准环境,phys_to_virt() 应该可以工作。