定时器中断(CLNT)和带有RISC-V的__stack_chk_fail



我正在写一个模拟器,我很难弄清楚CPU应该做什么。我有一个几乎一直可以工作的系统。如果我非常小心地选择CLNT:CPU定时器比例,我就可以运行NOMMU RV32 Linux内核,这真的很幸运。

我正在尽我所能模仿这个堆栈溢出的答案:RISC-V中断处理流

而且,老实说,它似乎运行良好。我可以运行用户空间程序,并让我的计时器以250 Hz运行,除了有时内核崩溃,更具体地说,它几乎总是在__stack_chk_fail上。经过挖掘,我仍然不知道内核对中断的处理如何不会到处崩溃。因为,它看起来像是在一个中断上,发生了以下情况:

  • 如果为零(第一次发生),则将寄存器tp交换为CSRCSR_SCRATCH,并将它们设置为相等
  • tp的描述符中读取sps0
  • 对中断进行操作

但是,tp似乎与当前运行的(中断的任务)相同。因此,中断中似乎没有理解对sp的更改,更具体地说是堆栈保护器的更改,因此它可以覆盖中断任务当前运行的内存。事实上,我已经深入了解并观察到了这一点。

但是我的内核似乎是在QEMU中启动的,所以我认为问题出在我的代码上。


为了参考,这是我的设置:我的定时器订购是:

  • 如果计时器>timer_match AND timermatch!=0设置mip.mtip,否则清除
  • 如果mie.mtie == 1ANDmip.mtip == 1ANDmstatus.mie == 1,则激发中断

当触发定时器中断时(原子):

  • 设置mstatus.mpie = mstatus.mie
  • 设置mstatus.mie = 0
  • 设置mepc = pc
  • 设置mtval = 0
  • 设置mtcause = 0x80000007
  • 设置下一台PC=mtvec(Linux使用一体式中断处理程序)

处理陷阱时,I(原子):

  • 设置mepc = mtval = pc<lt注意:这似乎是正确的,规范是这样说的,内核推进了mepc
  • 设置mtval = pc
  • 设置mstatus.mpie = mstatus.mie
  • 设置mstatus.mie = 0
  • 设置下一个PC=mtvec

调用mretI时(原子):

  • 设置mstatus.mie = mstatus.mpie
  • 设置mstatus.mpie = 1
  • 设置下一个PC=mepc

有什么想法吗?

这可能不是100%正确的,但这似乎能够使系统稳定。

从pi maker的rvc中可以看出,内核正确运行至关重要——必须设置mstatus.mpp位,否则它将覆盖内存。

正确的解决方案似乎在这里:https://github.com/PiMaker/rvc/blob/master/src/trap.h#L48

但是,为了进行测试,我能够通过以下方式使我的项目发挥作用。除了上述操作之外。。。

如果定时器中断:

  • 将最后一个privilege存储到mstatus.mpp
  • 将新的privilege设置为3

如果像ebreak:这样的陷阱

  • 将最后一个privilege存储到mstatus.mpp
  • 将新的privilege设置为3

如果mret:

  • 将最后一个privilege存储到mstatus.mpp
  • 将新privilege设置为旧mstatus.mpp

我不将privilege位用于任何其他用途。(请注意,这可能是不正确的,因为所选CSR应该根据权限级别而更改,但这似乎是有效的,\(ツ)/

相关内容

  • 没有找到相关文章

最新更新