【问题标题】:Triple fault with higher-half kernel and interrupts高半内核和中断的三重故障
【发布时间】:2020-06-10 19:25:43
【问题描述】:

我正在开发一个用于学习目的的微型操作系统(此处代码:https://github.com/davidedellagiustina/ScratchOS)。

我有一个 higher half kernel0xc0004000 运行,映射到物理 0x4000。默认页面目录正确映射了这个区域,然后有一个用于标识映射前1MB RAM(需要跳转到上半部分)的条目。进入上半部分后,我删除了页面目录的第一个条目,使TLB无效,一切正常(如果我尝试访问地址0x4000会出现页面错误,因此页面目录更新成功)。

之后我为时间和键盘设置了一个中断向量和中断处理函数,最终我尝试创建一个新的更完整的页面目录并替换启动目录,但是在替换旧的时出现三重错误一个。

目前我可以避免三重错误的唯一方法是加载一个标识映射前 1MB RAM 的新页面目录,甚至在加载后尝试删除页面目录的第一个条目(就像我在启动期间所做的那样过程)导致三重故障(因此身份映射必须保留在那里)。

我能够发现在切换页表之前禁用中断(甚至在切换到保护模式后从未重新启用它们,在启动早期[注释指令asm volatile("sti"); 函数@987654326 @ 在文件src/cpu/isr.c 的底部进行测试])可防止 CPU 发生三重故障。所以,我想我的 IDT(文件 src/cpu/idt.*src/cpu/isr.*)或 GDT(切换到保护模式时在引导过程中加载回文件 src/boot/bootsect.asmsrc/boot/gdt.asm)可能有一些问题。我已经仔细检查了这两个结构中加载的所有地址。我错过了什么?在我看来它是三重故障,因为在某些时候,没有第一页的身份映射,它无法找到整个中断向量(它加载到内核内部的虚拟内存中,因此映射到物理第一页),但是奇怪的行为是(见第一段)如果没有标识映射前 1MB 的页面目录是引导目录,它不会抱怨。

谁能帮忙找出我的错误?

【问题讨论】:

    标签: paging virtual-memory interrupt-handling osdev fault


    【解决方案1】:

    gdt 和 idt 寄存器都采用虚拟地址。当您禁用低映射时,这意味着对 gdt 或 idt 的下一次引用将导致页面错误。在删除统一页面之前,您需要重新加载这两个寄存器及其对应的高地址。

    【讨论】:

    • 我会试着调查一下,谢谢!我仍然不明白的奇怪事实是为什么在我第一次删除身份映射并使 TLB 无效时一切正常......
    • 顺便问一下,您是指包含 GDT 和 IDT 引用的寄存器(那些加载了 lgdt 和 lidt 指令的寄存器)还是 GDT/IDT 结构本身内部的地址?
    • 是的;但是,如果您在其中任何一个表中确实有门描述符,它们也必须指向有效的虚拟地址。从概念上讲,段是在页面之前应用的。
    • 终于修复了这个bug,我会在那里解释。 IDT 很好,因为它已经从上半部分加载,问题出在 GDT。我只需要用eax 中的新虚拟地址lgdt [eax] 并用虚拟地址更改GDT 描述符的第二个条目(即GDT 结构的基地址)!现在它可以正常工作了,非常感谢!如果有人遇到同样的问题,请参阅我的存储库中的提交 df3637c 以了解实现细节。
    猜你喜欢
    • 2021-02-28
    • 2013-04-15
    • 2019-12-13
    • 1970-01-01
    • 1970-01-01
    • 2016-09-09
    • 2011-09-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多