如何调试aarch64转换错误?

时间:2017-08-18 20:18:13

标签: arm kernel arm64 mmu armv8

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

MMU配置:

  • 48 VA位(T1SZ = 64-48 = 16)
  • 4K页面大小
  • 所有物理RAM平面映射到内核虚拟内存(在TTBR1_EL1上) (MMU在TTBR0_EL1 = 0时有效,所以我只使用0xffff< addr>中的地址,全部平面映射到物理内存中)

我正在将新地址空间(从1<< 40开始)映射到某个自由物理区域。当我尝试访问地址1<< 40时,我得到一个例外(类型为“EL1使用SP1,同步”):

ESR_EL1=0x96000044
FAR_EL1=0xffff010000000000

检查其他寄存器,我有:

TTBR1_EL1=0x82000000
TTBR1_EL1[2]=0x0000000082003003

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

  • ESR(异常症状登记)转换为:D7-1933平方的异常类= 100101(数据中止,异常级别没有变化); WnR = 1(故障指令是写入);第D7-1958页的DFSC = 0b000100( 0级翻译错误);
  • FAR_EL1是错误地址;它表示使用了TTBR1_EL1(因为高位都是1)。 VA前9位为0b000000010,表示表中使用了条目2;
  • 表中的条目2表示物理地址为0x82003000的下一级表(低位0b11)。

因此,翻译在0级失败,不应该在那里。

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

更新
在启用MMU之前写入表格时,Everthing有效 每当我在启用MMU后写入表格(通过平面映射表区域),映射永远不会起作用。我想知道为什么会这样。

我还尝试手动写入所选表格(从我的mmapping函数中删除任何副作用):相同的结果(在MMU打开之前完成写入,它起作用;之后,它失败)。

我尝试执行tlbidsb sy指示,然后执行isb,但没有效果。此时只有一个CPU正在运行,因此缓存不应该是一个问题 - 写入指令和MMU与同一个缓存进行通信(但我接下来会对其进行测试)。

1 个答案:

答案 0 :(得分:3)

我忽略了单核心内的缓存问题。问题是,在打开MMU之后,CPU和表行走单元没有相同的内存视图。 “ARMv8 Cortex-A编程指南”指出,在修改表之后,必须清理/无效缓存以达到统一点(单个核心的相同视图)。

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

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