如何调试 aarch64 翻译错误?

How to debug an aarch64 translation fault?

我正在用 armv8 (aarch64) 编写一个简单的内核。

MMU 配置:

我正在将一个新地址 space(从 1<<40 开始)映射到一些可用的物理区域。当我尝试访问地址 1<<40 时,出现异常("EL1 using SP1, synchronous" 类型):

ESR_EL1=0x96000044
FAR_EL1=0xffff010000000000

检查其他寄存器,我有:

TTBR1_EL1=0x82000000
TTBR1_EL1[2]=0x0000000082003003

因此,基于 ARMv8 的 ARM 体系结构参考手册(ARMv8-A 配置文件):

因此,翻译在 0 级失败,而它不应该失败。

我的问题是:我做错了什么吗?我是否遗漏了一些可能导致翻译错误的信息?而且,更一般地说,如何调试翻译错误?

更新:
当我在启用 MMU 之前写入 tables 时一切正常。
每当我在启用 MMU 后写入 tables(通过平面映射 table 区域)时,映射永远不会工作。我想知道为什么会这样。

我还尝试手动写入选定的 tables(以消除我的 mmapping 函数的任何副作用):相同的结果(在 MMU 打开之前完成写入时,它有效;之后,它失败).

我尝试执行 tlbidsb sy 指令,然后执行 isb,但没有效果。目前只有一个 CPU 是 运行,所以缓存应该不是问题 - 写入指令和 MMU 与相同的缓存通信(但我接下来会测试它)。

我忽略了单核中的缓存问题。问题是,在打开 MMU 后,CPU 和 table 步行单元没有相同的内存视图。 ARMv8 Cortex-A 编程指南指出,在修改 tables.

后,缓存必须 cleaned/invalidated 到统一点(单核的相同视图)

有两种可能性可以解释这种行为(我还没有完全理解缓存是如何工作的):

  1. 第一种可能性: MMU 在其内部遍历缓存中没有所需的地址。
    在这种情况下,当更新常规数据并使其可用于其他内核的 L1 时,dsb 指令只是等待所有内核都具有同步状态(感谢一致性网络):其他内核将知道该行必须更新,当他们尝试访问它时,它会更新到 L2 或从以前核心的 L1 迁移到他们的 L1。
    MMU(没有一致性参与)不会发生这种情况,所以它仍然看到 L2 中的旧值。
    然而,如果是这种情况,同样的事情应该发生在 MMU 被打开之前(因为缓存在之前被激活),除非所有内存在 MMU 被激活之前被认为是 L1 不可缓存的(这是可能的,我'我必须仔细检查一下)。
    解决该问题的一种最小方法可能是更改 table 页面的缓存策略,但仍然需要缓存维护以清除 MMU 中可能的旧值。
  2. 第二种可能性:在所有测试的情况下,MMU在其内部步行缓存中已经有故障地址,与数据L1或L2不一致。
    在这种情况下,只有显式无效才能从 MMU 缓存中弹出旧行。在打开MMU之前,缓存中什么都没有,永远不会得到旧值(0),只有新值。
    我仍然认为这种情况不太可能,因为我测试了很多情况,有时会出现预先映射的内存(例如,级别 1 table 中的条目 0)和新映射的内存(例如,相同的条目 128)之间的偏移级别 1 table) 大于缓存行大小(在本例中为 1024 字节,大于任何缓存行大小)。

所以,我仍然不确定到底是什么导致了这个问题,但是 cleaning/invalidating 所有更新的地址都有效。