无法使用 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()
应该可以工作。
在设备驱动程序中,我想读取 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()
应该可以工作。