【发布时间】:2021-04-08 09:29:21
【问题描述】:
我正在尝试制作自己的操作系统。我得到了中断工作,一些键盘和鼠标驱动程序,基本的视频和打印功能。现在我想进入内存管理和任务,我首先意识到我需要分页,但我还没有正确设置。
我遵循了一些关于它的指南和教程,最主要的是 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 - 监督进程试图写入一个不存在的页面条目
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 并且代码挂起,这是预期的。
【问题讨论】:
-
您是否免除了当前代码页的分页?
-
@Devolus 不,我什至不知道那是什么意思
-
在我看来,好像您启用了分页,但您当前的代码是现在标记为不存在的页面之一,您必须排除这些页面并适当地标记它们。堆栈也是如此。该异常还应该告诉您您尝试访问的地址。
-
CR2 包含错误地址,对吧?这看起来根本不像一个有效的地址。您应该尝试反汇编 EIP 周围的代码,看看那里发生了什么。
-
在 x86 上无法从分页中排除页面。一旦启用分页,所有地址(除了一些模糊的例外)都是虚拟地址,并且必须存在映射。 @Dev