无法 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] 来检索地址。