我想编写我的代码来处理Microblaze上的TLB未命中,当然还有页表等等。这些都是在OVPsim上完成的。
在我学习的过程中,我编写了这个小程序集以引用未映射的位置(0x1000000) - 我将此作为特权代码运行,其中包含VM:
ori r20, r0, 0
ori r12, r0, 0x1000000
/* next line should break it */
sw r20, r12, r0
(即,将r20 == 0
的内容写入ORing r12 == 0x1000000
和r0 == 0 => 0x1000000
形成的地址。)
但不是跳到异常向量,GDB报告"程序收到SIGSEV" - 我错了什么?我没有在MSR中启用硬件异常位,但是手册说你无论如何都不能掩盖这些异常,所以不应该成为问题。
更多信息我无法获取要执行的异常处理代码的任何(例如,包括错位异常)(除非我明确地调用它),无论我是否使用调试器。关闭调试器后,我从OVPsim得到这个输出(NB我只是改变了测试地址 - 上面的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。
答案 0 :(得分:2)
生成了你的TLB异常,阻止你进入处理程序的是GDB。
调试VM模式是一件棘手的事情。我不熟悉OVPsim以及它与GDB的集成程度,但有几种方法可以解决这个问题:
明确的软件断点。只需使用brk r16, 0x18
指令在代码中设置断点,然后让GDB使用continue
命令。一旦执行此中断,它将停止,无论其VM用户代码还是异常处理程序。
这方面的缺点是,一旦达到这种突破,就没有简单的方法可以继续使用GDB。您需要将r16
修改为下一个指令地址,或者将您的brk
指令替换为GDB中的nop
。
硬件断点。这是您可以用来调试异常端和VM端代码而不用担心TLB页面存在的最简单的中断。但硬件断点需要Microblaze的硬件支持(不确定OSPsim是否支持它们)。要在GDB中使用它,只需使用hbreak
(或hb
)代替break
命令。
GDB软断点。如果您知道它们如何工作并且您的VM模型足够简单,您仍然可以使用常规样式GDB断点。基本上,GDB需要对要中断的代码页进行写访问(以便编写brk
指令)。因此,在VM模式下,您必须确保页面存在于TLB中并具有写访问权。
当虚拟地址与物理地址不同时,将非VM模式中断设置为VM代码更为棘手。您需要确保要将断点的页面加载到物理内存中,并手动将虚拟地址转换为物理和设置断点。因此,除非你有1:1映射(并且所有代码和数据都在内存中)或者你编写了自己的GDB stub,否则使用GDB断点是一种绘画。
不幸的是,单步执行GDB中的代码几乎就像使用GDB软断点一样。即你可以踩到非VM代码,或者在具有写权限的单个加载的VM页面中。但是,一旦你需要处理TLB以外的东西或从非VM访问VM代码,它就会变得非常令人沮丧。
答案 1 :(得分:1)
感谢约克大学实时系统小组的Jamie Garside:OVP模拟器的默认设置是捕获异常并退出模拟,这就是为什么没有像我预期的那样执行异常 - 而是他们只是被报告为某种错误,模拟正在停止。
但是,如果为模拟定义了ICM_ATTR_SIMEX
,那么模拟将按照真实处理器的方式执行异常处理程序 - 因此将ICM_ATTR_SIMEX
添加到我的实例的属性中 - 例如,通过对其进行OR运算如下所示,将所有内容放在正确的位置:
#define SIM_ATTRS (ICM_ATTR_DEFAULT|ICM_ATTR_SIMEX)