启用分页后出现页面错误?操作系统开发者

Page fault after enabling paging? OSDEV

我正在尝试制作自己的操作系统。我有中断工作,一些键盘和鼠标驱动程序,基本的视频和打印功能。现在我想进入内存管理和任务,我意识到的第一件事是我需要尚未正确设置的分页。

我遵循了一些指南和教程,最主要的是在 osdev wiki (https://wiki.osdev.org/Setting_Up_Paging) 中设置分页教程。我“编写”(基本上是复制和粘贴)以下代码以初始化分页。

void initPaging()
{
    
    unsigned int i;
    for(i = 0; i < 1024; i++)
    {
        // This sets the following flags to the pages:
        //   Supervisor: Only kernel-mode can access them
        //   Write Enabled: It can be both read from and written to
        //   Not Present: The page table is not present
        page_directory[i] = 0x00000002;
    }       
    
    //we will fill all 1024 entries in the table, mapping 4 megabytes
    for(i = 0; i < 1024; i++)
    {
        // As the address is page aligned, it will always leave 12 bits zeroed.
        // Those bits are used by the attributes ;)
        first_page_table[i] = (i * 0x1000) | 3; // attributes: supervisor level, read/write, present.
    }
    
    page_directory[0] = ((unsigned int)first_page_table) | 3;
    
    enablePaging(page_directory);
    
}

enablePaging函数将页面目录加载到cr3,然后通过设置cr0中的PG位来启用分页。

问题是在调用此函数之后,如果我调用其他任何东西(如 printk),它会导致页面错误。我认为那是因为我没有标识页面内核或其他东西。在我的页面错误处理程序中,我将错误代码移至 eax 并检查 qemu 监视器中的寄存器。错误代码是 0x00000020 即

0 1 0 - Supervisory process tried to write to a non-present page entry

TL;DR

启用分页后我无法调用其他任何东西,我需要映射我的内核吗?我怎么做?还有什么问题?

这是我在 github 上的代码:https://github.com/Danyy427/PagingOsdev

编辑: 异常后注册

我的异常处理程序:

void isr14_handler(interrupt_frame_t *frame)
{
    //panic("Page Fault");
    
    unsigned int err = frame->err_code;
    
    //asm(".intel_syntax noprefix");
    asm("mov %0, %%eax "::"r"(err));
    
    while(1);
}

我注释掉了恐慌,因为它会导致双重故障,进而导致三重故障。我将错误代码放入 eax 并且代码挂起,这是预期的。

我终于明白了。我的内核有以下代码:


    initPaging();
    
    printk("Hello %d", 15) ;
    

启用分页后,我试图打印一些东西,发现 printk 抛出了页面错误。我查看 printk 代码并意识到我正在访问 0xFD000000,这是 QEMU 的帧缓冲区地址。但是我没有映射它,所以程序试图访问一个未映射的位置。我在 initPaging 函数中编写了以下代码,将 0xFD000000 映射到 0x400000:

int from = 0x00000000, size = 0x400000,  zz = 0;
    for(; size>0; from += 4096, size -= 4096, zz++){
       first_page_table[zz] = from | 1;     // mark page present.
    }
    
    from = 0xFD000000;
    size = 0x400000;
    zz = 0;
    for(; size>0; from += 4096, size -= 4096, zz++){
       second_page_table[zz] = from | 1;     // mark page present.
    }
    
    vbemode.framebuffer = 0x400000;
    
    page_directory[0] = ((unsigned int)first_page_table) | 3;
    page_directory[1] = ((unsigned int)second_page_table) | 3;
    
    enablePaging(page_directory);

代码映射 4 MB 的内存,从 0x400000 开始到物理地址 0xFD000000 的 0x800000(希望如此),这样可以访问视频内存。

欢迎指出我代码中的错误。