【问题标题】:Why does access to an unmapped location not generate a hardware exception (Microblaze)为什么访问未映射的位置不会产生硬件异常 (Microblaze)
【发布时间】:2014-11-21 03:43:24
【问题描述】:

我想编写我的代码来处理 Microblaze 上的 TLB 缺失,当然还有页表等。这一切都在 OVPsim 上完成。

在学习过程中,我编写了这个小程序集来引用一个未映射的位置 (0x1000000) - 我将其作为特权代码在 VM 上运行:

ori r20, r0, 0
ori r12, r0, 0x1000000
/* next line should break it */
sw  r20, r12, r0

(即将r20 == 0的内容写到r12 == 0x1000000r0 == 0 => 0x1000000显然是ORing形成的地址。)

但是 GDB 没有跳转到异常向量,而是报告“程序收到 SIGSEV”——我做错了什么?我没有在 MSR 中启用硬件异常位,但手册说您在任何情况下都不能屏蔽这些异常,所以这不应该是问题。

更多信息无论我是否使用调试器,我都无法执行任何异常处理代码(例如,包括未对齐异常)(除非我明确调用它)。关闭调试器后,我从 OVPsim 得到这个输出(注意,我只是更改了测试地址 - 上面的 0xA000000 和 0x100000 之间的区别没有意义):

Processor Exception (PC_PRX) Processor 'platform/cpu0' 0x248: sw       r20, r12, r0
Processor Exception (PC_WPX) No write access at 0xa000000

这是在特权模式下运行的所有代码,所以我看不出它不调用处理程序的明显理由,除非我没有正确配置 Microblaze。我打开了这些:

icmAddStringAttr(cpu1_attr, "endian", "big");
icmAddDoubleAttr(cpu1_attr, "mips", 100.000000);
icmAddStringAttr(cpu1_attr, "variant", "V8_20");
icmAddBoolAttr(cpu1_attr, "verbose", "true");
icmAddUns32Attr(cpu1_attr, "C_PVR", 2);
icmAddUns32Attr(cpu1_attr, "C_USE_MMU", 3);
icmAddStringAttr(cpu1_attr, "C_USE_BARREL", "1");
icmAddStringAttr(cpu1_attr, "C_USE_DIV", "1");
icmAddUns32Attr(cpu1_attr, "C_USE_INTERRUPT", 1);
icmAddUns32Attr(cpu1_attr, "C_MMU_TLB_ACCESS", 3);
icmAddUns32Attr(cpu1_attr, "C_UNALIGNED_EXCEPTIONS", 1);
icmAddUns32Attr(cpu1_attr, "C_ILL_OPCODE_EXCEPTION", 1);
icmAddUns32Attr(cpu1_attr, "C_DIV_ZERO_EXCEPTION", 1);
icmAddUns32Attr(cpu1_attr, "C_OPCODE_0x0_ILLEGAL", 1);
icmAddUns32Attr(cpu1_attr, "C_DEBUG_ENABLED", 1);

没有理由相信这不会奏效,因为 OVPsim 将在 Microblaze 上运行 Linux。

【问题讨论】:

  • 您的 Microblaze 配置看起来不错。模拟器的输出看起来有点奇怪。 “无写访问”异常可能意味着在 TLB 中找到了相应的页面,但它没有启用写访问。即使在这种情况下,您也应该看到异常。尝试在MSR 中设置EE 位,不过,以防其OVPsim 实现错误。
  • 我已经设置了 EE 位 :( MSR 是 0x2502
  • 还有一个建议是设置 Microblaze 参数C_MMU_ZONES = 2。即使您没有使用保护区,当此参数为 0 时,Microblaze 也不会产生代码或数据访问异常。
  • 恐怕没有任何区别。在任何情况下,默认值为 16。

标签: memory-management gdb mmu microblaze ovp


【解决方案1】:

您的 TLB 异常已生成,是 GDB 阻止您进入处理程序。

调试 VM 模式是一件棘手的事情。我不熟悉 OVPsim 以及它与 GDB 的集成程度,但有几种方法可以帮助您完成它:

  1. 显式软件断点。只需在要在代码中设置断点的地方使用brk r16, 0x18 指令,然后使用continue 命令让GDB 运行。一旦执行此中断,它将停止,无论是其 VM 用户代码还是异常处理程序。

    这样做的缺点是,一旦达到这种中断,就没有简单的方法从 GDB 继续。您需要将r16 修改为下一条指令地址,或者将brk 指令替换为GDB 中的nop

  2. 硬件断点。这是您可以用来调试异常端和 VM 端代码的最简单的中断,而无需担心 TLB 页面的存在。但是硬件断点需要 Microblaze 的硬件支持(不确定 OSPsim 是否支持它们)。要在 GDB 中使用它,只需使用 hbreak(或 hb)而不是 break 命令。

  3. GDB 软断点。如果您知道它们是如何工作的并且您的 VM 模型足够简单,那么您仍然可以使用常规样式的 GDB 断点。基本上,GDB 需要对要中断的代码页的写访问权(以便编写brk 指令)。因此在 VM 模式下,您必须确保页面存在于 TLB 中并具有写入权限。

    当您的虚拟地址与物理地址不同时,将非 VM 模式的中断设置为 VM 代码会更加棘手。您需要确保要放置断点的页面已加载到物理内存中,并手动将虚拟地址转换为物理地址并设置断点。因此,除非您有 1:1 映射(并且所有代码和数据都在内存中)或者您自己编写了 GDB stub,否则使用 GDB 断点是一种绘画。

不幸的是,在 GDB 中单步执行代码几乎就像一直使用 GDB 软断点一样。 IE。您可以进入非 VM 代码,或进入具有写入权限的单个加载的 VM 页面。但是一旦你需要处理 TLB 之外的事情或从非 VM 访问 VM 代码,就会变得非常令人沮丧。

【讨论】:

  • 感谢您的回答。但是,如果我关闭调试,它只会破坏模拟。我知道必须有办法让它工作,因为您可以在 OVP 上运行 Linux 内核,并且显然依赖于按需分页。您认为我在设置 Microblaze 时是否错过了一些可能的设置?
  • 你不必完全让调试器离开,你只需要更小心地使用它。 GDB 可以调试 VM 或非 VM 的纯代码,但如果您尝试单步执行 TLB 异常,GDB 会变得智能或不可预测。另一个想法是模拟器本身。例如。 QEMU MMU 的实现并不完整,也不足以承载 Linux 内核。我建议使用调试模块运行真正的 Microblaze 设计,并使用 Xilinx 的 XMD 工具进行调试,该工具简单明了且可预测。
  • 我只是相信我得到了 TLB 异常,或者实际上是任何异常,因为调试器不是这里的问题。我认为这是一个设置问题 - 即我在配置或启动该东西时错过了某种设置。
  • 只需在您的异常处理程序中添加一个永久循环,然后让程序运行 GDB 或不运行。如果调试器已连接点击Ctrl+Break,如果没有,连接到模拟器将停止其执行,通过检查rpc,您将知道您卡在主循环中。我相信还有一种方法可以简单地从模拟器输出到标准输出。您需要找到对应于UART输出的虚拟寄存器并定义outbyte()以将字节放入该寄存器。这将让您从处理程序中printf()
  • 我的异常处理程序中有一个永久循环。永远不会调用异常处理程序,这就是问题所在。
【解决方案2】:

感谢约克大学实时系统小组的 Jamie Garside:OVP 模拟器的默认设置是捕获异常并退出模拟,这就是为什么没有按我预期的方式执行任何异常 - 而是他们只是被报告为某种错误,模拟被暂停。

但是,如果为模拟定义了ICM_ATTR_SIMEX,那么模拟将以真实处理器的方式执行异常处理程序 - 因此将ICM_ATTR_SIMEX 添加到我的实例的属性中 - 例如,通过 ORing 如下所示, 将所有内容放在应有的位置:

#define SIM_ATTRS (ICM_ATTR_DEFAULT|ICM_ATTR_SIMEX)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-30
    • 1970-01-01
    • 1970-01-01
    • 2014-07-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多