【问题标题】:can't read the pagetable using ttbr0_el1 register..(arm64)无法使用 ttbr0_el1 寄存器读取页表..(arm64)
【发布时间】:2023-03-31 12:45:02
【问题描述】:

在设备驱动程序中,我想读取 ttbr0_el1 寄存器(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

【问题讨论】:

  • 只有该寄存器的低 48 位保存基地址。有关详细信息,请参阅 ARM 架构参考手册。

标签: assembly gcc linux-device-driver arm64


【解决方案1】:

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

但不仅如此。来自the manual

翻译表基地址: • 阶段 1 转换表基地址位的位 A[47:x] 在 寄存器位[47:x]。 • 阶段1 转换表基地址的位A[(x-1):0] 为零。 地址位 x 是对齐转换所需的最小地址位 表到表的大小。 x 的最小允许值为 6。 AArch64 虚拟内存系统架构章节描述了 x 是如何实现的 根据 TCR_EL1.T0SZ 的值、平移阶段和 平移粒度。 - - - - 笔记 - - - - - - 转换表需要与表的大小对齐。如果 一个表包含少于八个条目,它必须在 64 字节上对齐 地址边界。 -------------------------- 如果 TCR_EL1.IPS 的值不是 0b110,那么: • 寄存器位[(x-1):1] 为RES0。 • 如果实现支持 52 位 PA 和 IPA,则位 A[51:48] 阶段 1 转换表的基地址为 0b0000。 如果实现了 FEAT_LPA 并且 TCR_EL1.IPS 的值为 0b110,则: • 阶段 1 转换表基地址位的位 A[51:48] 是 在寄存器位 [5:2] 中。 • 寄存器位[1] 为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() 应该可以工作。

【讨论】:

  • 谢谢!使用您的代码(和 phys_to_virt),我可以看到一个看起来像指向 1 级(?)表的条目的值。我之前已经对文档进行了掩饰,但我认为这是我应该再次更彻底地阅读它的时候了...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-21
  • 2018-04-23
  • 1970-01-01
相关资源
最近更新 更多