无法 page/access 内存超过 2 MiB。奥斯德夫
Unable to page/access memory over 2 MiB. Osdev
我正在尝试开发我的 ow os,当我突然决定切换到 long 模式时,我正在做分页。长模式需要对其他所有内容进行分页(打印到屏幕、中断、驱动程序等),我从这里开始,我有一个页面框架分配器,其中 returns 个 4 KiB 的页面框架。在我的引导加载程序中,当切换到 64 位时,我标识映射前 2 个 MiB 供内核使用。在我进入内核后,我标识映射相同的 2 MiB,并尝试标识映射超过 2 MiB 的更多内存,但是我无法映射,当我尝试编写页面 table 时,即 suppos 映射到 2 MiB 以上它会出现三重故障。
这是我要执行的代码:
long from = 0x00000, size = 0x400000, zz = 0;
for(; size>0; from += 4096, size -= 4096, zz++)
{
//first_page_table[zz] = from | 1; // mark page present.
map_page(kernelDirectory, from, from, 0x003);
}
此代码试图从零开始映射 4 个 MiB,它会出现三重故障。如果我将大小设置为 0x200000 或 2 MiB,它会停止三重故障,即使我将大小设置为 0x201000,它也会出现三重故障。
这是映射函数:
void map_page(pml4_t *pml4, void * physaddr, unsigned long virtualaddr, unsigned int flags)
{
// Make sure that both addresses are page-aligned.
unsigned int pdindex;
unsigned int ptindex;
unsigned int pdptindex;
unsigned int pml4index;
virtualaddr >>= 12;
ptindex = virtualaddr & 0x1ff;
virtualaddr >>= 9;
pdindex = virtualaddr & 0x1ff;
virtualaddr >>= 9;
pdptindex = virtualaddr & 0x1ff;
virtualaddr >>= 9;
pml4index = virtualaddr & 0x1ff;
page_directory_pointer_table_t *pdpt;
if(pml4->entries[pml4index].present == 0)
{
pdpt = RequestPage();
memset(pdpt, 0, 4096);
pml4->entries[pml4index].present = 1;
pml4->entries[pml4index].writeable = 1;
pml4->entries[pml4index].address = ((unsigned long)pdpt >> 12);
}
else
{
pdpt = (pml4->entries[pml4index].address << 12);
}
page_directory_t *directory;
if(pdpt->entries[pdptindex].present == 0)
{
directory = RequestPage();
memset(directory, 0, 4096);
pdpt->entries[pdptindex].present = 1;
pdpt->entries[pdptindex].writeable = 1;
pdpt->entries[pdptindex].address = ((unsigned long)directory >> 12);
}
else
{
directory = (pdpt->entries[pdindex].address << 12);
}
page_table_t *pt;
if(directory->entries[pdindex].present == 0)
{
pt = RequestPage();
//memset(pt, 0, 4096);
directory->entries[pdindex].present = 1;
directory->entries[pdindex].writeable = 1;
directory->entries[pdindex].address = ((unsigned long)pt >> 12);
}
else
{
pt = (directory->entries[pdindex].address << 12);
}
pt->entries[ptindex].present = flags & 1;
pt->entries[ptindex].writeable = (flags & 2) >> 1;
pt->entries[ptindex].user_access = (flags & 4) >> 2;
pt->entries[ptindex].write_through = (flags & 8) >> 3;
pt->entries[ptindex].cache_disabled = (flags & 16) >> 4; // 000
pt->entries[ptindex].accessed = (flags & 32) >> 5; // 0000 0000 0000
pt->entries[ptindex].dirty = (flags & 64) >> 6;
pt->entries[ptindex].zero = 0;
pt->entries[ptindex].global = (flags & 256) >> 8;
pt->entries[ptindex].ignored_2 = 0b000;
pt->entries[ptindex].address = ((unsigned long)physaddr >> 12);
__native_flush_tlb_single((unsigned long)pt->entries[ptindex].address << 12);
}
这是整个 github 回购协议:
https://github.com/Danyy427/OSDEV5
这些函数位于 source/kernel/memory/paging/paging.c
下
您可能还需要看一下 source/kernel/bitmap/bitmap.h 和 bitmap.c
帧分配器位于 source/kernel/memory/physical/pmm.c 和 pmm.h
提前致谢!
page_directory_t *directory;
if(pdpt->entries[pdptindex].present == 0)
{
/* omit */
}
else
{
directory = (pdpt->entries[pdindex].address << 12);
}
此处您正在检查 pdpt->entries[pdptindex]
的存在,但随后从 pdpt->entries[pdindex]
检索地址。看起来您还应该使用 pdpt->entries[pdptindex]
来检索地址。
我正在尝试开发我的 ow os,当我突然决定切换到 long 模式时,我正在做分页。长模式需要对其他所有内容进行分页(打印到屏幕、中断、驱动程序等),我从这里开始,我有一个页面框架分配器,其中 returns 个 4 KiB 的页面框架。在我的引导加载程序中,当切换到 64 位时,我标识映射前 2 个 MiB 供内核使用。在我进入内核后,我标识映射相同的 2 MiB,并尝试标识映射超过 2 MiB 的更多内存,但是我无法映射,当我尝试编写页面 table 时,即 suppos 映射到 2 MiB 以上它会出现三重故障。
这是我要执行的代码:
long from = 0x00000, size = 0x400000, zz = 0;
for(; size>0; from += 4096, size -= 4096, zz++)
{
//first_page_table[zz] = from | 1; // mark page present.
map_page(kernelDirectory, from, from, 0x003);
}
此代码试图从零开始映射 4 个 MiB,它会出现三重故障。如果我将大小设置为 0x200000 或 2 MiB,它会停止三重故障,即使我将大小设置为 0x201000,它也会出现三重故障。
这是映射函数:
void map_page(pml4_t *pml4, void * physaddr, unsigned long virtualaddr, unsigned int flags)
{
// Make sure that both addresses are page-aligned.
unsigned int pdindex;
unsigned int ptindex;
unsigned int pdptindex;
unsigned int pml4index;
virtualaddr >>= 12;
ptindex = virtualaddr & 0x1ff;
virtualaddr >>= 9;
pdindex = virtualaddr & 0x1ff;
virtualaddr >>= 9;
pdptindex = virtualaddr & 0x1ff;
virtualaddr >>= 9;
pml4index = virtualaddr & 0x1ff;
page_directory_pointer_table_t *pdpt;
if(pml4->entries[pml4index].present == 0)
{
pdpt = RequestPage();
memset(pdpt, 0, 4096);
pml4->entries[pml4index].present = 1;
pml4->entries[pml4index].writeable = 1;
pml4->entries[pml4index].address = ((unsigned long)pdpt >> 12);
}
else
{
pdpt = (pml4->entries[pml4index].address << 12);
}
page_directory_t *directory;
if(pdpt->entries[pdptindex].present == 0)
{
directory = RequestPage();
memset(directory, 0, 4096);
pdpt->entries[pdptindex].present = 1;
pdpt->entries[pdptindex].writeable = 1;
pdpt->entries[pdptindex].address = ((unsigned long)directory >> 12);
}
else
{
directory = (pdpt->entries[pdindex].address << 12);
}
page_table_t *pt;
if(directory->entries[pdindex].present == 0)
{
pt = RequestPage();
//memset(pt, 0, 4096);
directory->entries[pdindex].present = 1;
directory->entries[pdindex].writeable = 1;
directory->entries[pdindex].address = ((unsigned long)pt >> 12);
}
else
{
pt = (directory->entries[pdindex].address << 12);
}
pt->entries[ptindex].present = flags & 1;
pt->entries[ptindex].writeable = (flags & 2) >> 1;
pt->entries[ptindex].user_access = (flags & 4) >> 2;
pt->entries[ptindex].write_through = (flags & 8) >> 3;
pt->entries[ptindex].cache_disabled = (flags & 16) >> 4; // 000
pt->entries[ptindex].accessed = (flags & 32) >> 5; // 0000 0000 0000
pt->entries[ptindex].dirty = (flags & 64) >> 6;
pt->entries[ptindex].zero = 0;
pt->entries[ptindex].global = (flags & 256) >> 8;
pt->entries[ptindex].ignored_2 = 0b000;
pt->entries[ptindex].address = ((unsigned long)physaddr >> 12);
__native_flush_tlb_single((unsigned long)pt->entries[ptindex].address << 12);
}
这是整个 github 回购协议: https://github.com/Danyy427/OSDEV5
这些函数位于 source/kernel/memory/paging/paging.c
下您可能还需要看一下 source/kernel/bitmap/bitmap.h 和 bitmap.c
帧分配器位于 source/kernel/memory/physical/pmm.c 和 pmm.h
提前致谢!
page_directory_t *directory;
if(pdpt->entries[pdptindex].present == 0)
{
/* omit */
}
else
{
directory = (pdpt->entries[pdindex].address << 12);
}
此处您正在检查 pdpt->entries[pdptindex]
的存在,但随后从 pdpt->entries[pdindex]
检索地址。看起来您还应该使用 pdpt->entries[pdptindex]
来检索地址。