本土内核的三重故障

时间:2010-11-02 19:09:39

标签: c assembly operating-system kernel

我正在尝试编写一个内核,主要用于娱乐目的,我遇到了一个问题,我相信这是三重错误。在我尝试启用分页之前,一切正常。破解的代码是:

void switch_page_directory(page_directory_t *dir){

 current_directory = dir;
 asm volatile("mov %0, %%cr3":: "r"(&dir->tablesPhysical));

 u32int cr0;
 asm volatile("mov %%cr0, %0": "=r"(cr0));

 cr0 |= 0x80000000;//enable paging
 asm volatile("mov %0, %%cr0":: "r"(cr0)); //this line breaks


}//switch page directory

我一直在关注各种教程/文档,但我用于分页的是http://www.jamesmolloy.co.uk/tutorial_html/6.-Paging.html。我不确定其他代码对于解决这个问题会有什么用处,但如果有更多代码我应该提供,我将非常乐意这样做。

编辑=====

我相信CS,DS和SS正在选择正确的条目,这是用于设置它们的代码

global gdt_flush     
extern gp            
gdt_flush:

    lgdt [gp]        ; Load the GDT with our 'gp' which is a special pointer
    mov ax, 0x10      ; 0x10 is the offset in the GDT to our data segment

    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax

    jmp 0x08:flush2   ; 0x08 is the offset to our code segment: Far jump!

flush2:
    ret               ; Returns back to the C code!

这里是gdt结构本身

struct gdt_entry{
    unsigned short limit_low;
    unsigned short base_low;
    unsigned char base_middle;
    unsigned char access;
    unsigned char granularity;
    unsigned char base_high;
} __attribute__((packed));

struct gdt_ptr{
    unsigned short limit;
    unsigned int base;
} __attribute__((packed));

struct gdt_entry gdt[5];
struct gdt_ptr gp;

IDT与此非常相似。

3 个答案:

答案 0 :(得分:6)

GDT:您没有说明GDT条目的内容是什么,但您展示的内容与earlier part of the tutorial you linked to非常相似,如果您已设置以相同的方式输入条目,然后一切都应该很好(即,用于CS的环0代码段的平坦段映射,用于其他所有的环0数据段,都具有0的基数和4GB的限制)。

IDT:如果中断被禁用并且您(还)没有预期会导致页面错误,那么无论如何都无关紧要。

页面表:不正确的页面表看起来似乎是最可能的嫌疑人。确保您的身份映射涵盖了您正在使用的代码,数据和堆栈内存的所有(至少)。

链接到http://www.jamesmolloy.co.uk/tutorial_html/6.-Paging.html底部的源代码肯定构建了 与QEMU和Bochs正常工作的东西,所以希望你能比较你正在做什么和那是什么做,并找出问题所在。

QEMU一般情况良好,但我建议Bochs用于开发真正低级的内容 - 它包括(或可以配置为包含)非常方便的internal debugger。例如在配置文件的reset_on_triple_fault=0行设置cpu:,在switch_page_directory()代码中设置断点,运行到断点,然后单步指令,看看会发生什么......

答案 1 :(得分:2)

您可以通过gdb中的远程调试工具将qemu链接到gdb调试器会话。这可以通过发出以下命令来完成:

qemu -s [optional arguments]

然后在gdb会话中打开内核可执行文件,在switch_page_directory()函数中设置断点后,在gdb提示符下键入以下命令:

target remote localhost:1234

然后,您可以在断点处单步执行内核,并查看三重故障发生的位置。

要考虑的另一个步骤是在IDT中实际安装一些默认的异常处理程序......你是三重错误的原因是因为CPU抛出异常,但是没有适当的异常处理程序来处理它。因此,安装了一些默认处理程序,尤其是双故障处理程序,您可以有效地停止内核,而不会进入自动重置PC的三重故障。

最后,确保在进入保护模式之前重新编程PIC ...否则,默认硬件中断它被编程为在实模式下从BIOS触发,现在将在保护模式下触发异常中断。

答案 2 :(得分:1)

我也遇到了与分页教程相同的问题。但是经过一些搜索我找到了解决方案,因为一旦启用分页,所有地址都变为虚拟并解决它我们必须将虚拟地址映射到相同的物理地址,以便它们引用相同的内容,这称为身份映射。

您可以按照此link获取有关实施身份映射的进一步帮助。

还有一件事你将新分配的空间memset归零,因为它可能包含垃圾值而memset没有在教程中完成它将在bochs上工作,因为它为你设置空间为零,但其他模拟器(qemu)和真正的硬件非常友好。