DrC*_*ore 1 x86 assembly kernel interrupt virtual-machine
当我的页面错误处理程序中断被调用时(它应该挂起系统),在调用之前有一些变量被推送到堆栈中。我启用了虚拟内存,当我设置一个无效的堆栈指针(esp)并且 int14 处理程序被调用时,它会立即导致另一个页面错误等等。我应该如何解决这种情况?
我的 int14 代码:
isr14:
; interrupt handler for isr14
jmp $
iretd
Run Code Online (Sandbox Code Playgroud)
导致它中断的代码:
mov esp, 0x1000 ; 0x1000 is not mapped in the VM directory
push dword 'A'
jmp $
Run Code Online (Sandbox Code Playgroud)
我的 IDT 表的部分:
irq14:
dw isr14
dw 0x0008
db 0x00
db 10101110b
dw 0x0000
irq15:
........
Run Code Online (Sandbox Code Playgroud)
我应该如何解决这种情况?
我会通过使用避免来解决这种情况 - 首先不要让内核有一个狡猾的堆栈指针(并且不要让内核堆栈被发送到交换空间,不要将页面错误用于“自动增长的内核”堆栈”等)。请注意,如果在用户空间(在 CPL=3 时)发生页面错误,CPU 将自动切换到内核堆栈,因此用户空间是否有一个狡猾的堆栈指针并不重要。
替代方案是:
当内核代码 (CPL=0) 导致页面错误时强制内核堆栈切换。这可以使用硬件任务切换(保护模式)或缺页异常处理程序的 IST 机制(长模式)来完成。这将是恢复的最佳选择(例如,可以更轻松地找出问题所在,修复它,然后返回)。
当内核代码 (CPL=0) 导致双重错误时,强制进行内核堆栈切换。这可以使用硬件任务切换(保护模式)或双故障异常处理程序的 IST 机制(长模式)来完成。这将是性能的最佳选择(正常页面错误不会增加开销)。
注 1:请注意,硬件任务切换/任务门和 IST 都不是可重入的。对于硬件任务切换,如果在您处理第一个页面错误时发生第二个页面错误,您将得到一个通用保护错误(因为“页面错误任务”正忙);对于 IST,如果在您处理第一个页面错误时发生第二个页面错误,第二个页面错误将破坏/覆盖第一个页面错误的堆栈,并使其无法恢复。理论上,您可以通过尽快切换到不同的任务或不同的堆栈来缓解这些问题,但这很复杂/混乱,并且可能会导致更多问题。
注 2:您可能会使用硬件任务切换或 IST 获得避免和双重故障的组合;双故障处理程序执行“冻结系统并转储信息/恐慌”作为灾难性内核故障的通用后备(本来应该避免但没有)。
注3:如果你想支持“自动增长的内核堆栈”;您可以使用“堆栈探测”来代替 - 基本上,在使用堆栈内存之前,只需从“未来堆栈”中执行虚拟读取/s(在函数尾声中),以便在仍有足够的内核堆栈留给页面时发生页面错误故障处理程序。