将虚拟地址从多级页面列表转换为物理地址

时间:2018-09-24 20:53:42

标签: c linux memory-management linux-kernel virtual-address-space

我正在尝试将虚拟内存地址转换为物理地址,但无法使其正常工作。我目前正在将操作系统作为分配,现在必须为用户模式实现printf函数,因此,当您调用write syscall时,系统应将用户模式下的数组内容打印到串行端口(目前),为此,我必须将地址从虚拟地址转换为物理地址。

这是我来自系统调用处理程序的代码:

Pcb* pcb = getCR3(); // contains the page directory for usermode
setCR3(kernelPageDir); // set the CR3 register to the kernel page directory

uint32_t tableNum = (vAddr >> 22) & 0x3ffUL; // get the upper 10 bits
uint32_t pageIndex = (vAddr >> 12) & 0x3ffUL // get the middle 10 bits
uint32_t offset = vAddr & 0xfffUL; // get the 12 lower bits

uint32_t* topTable = pcb->pageDirectory[tableNum]; // Access the top level table
uint32_t lowTable = topTable[pageIndex]; // Entry to the 2nd table
uint32_t* addr = lowTable + offset; // Should be the physical address

serialPrintf("Structure: tableNum=%08x pageIndex=%08x  offset=%08x\n", tableNum, pageIndex, offset);
serialPrintf("Address: topTable=%08x lowTable=%08x addr=%08x\n",topTable, lowTable, addr);
serialPrintf("Char:%c", (char*)addr[0]);

运行代码时,尝试访问它的值时出现页面错误:

Structure: tableNum=00000020 pageIndex=00000048  offset=00000378
Address: topTable=00000000 lowTable=0015d000 addr=0015d378
Page fault! errcode=00000000 addr=0015d378

这是本书中解释页面结构的部分:

Structure of the page table levels

1 个答案:

答案 0 :(得分:0)

如果您为第二级表中的最后一个(索引1023)条目填写了一个pte,而该值由第一级表的最后一个(索引1023)指向,则:

0xfffff000 .. 0xfffffffc will by an alias of the first level table,

0xffc00000 .. 0xffffffff will be an alias of the entire (sparse) page table.

例如:

int vtop(unsigned vaddr, unsigned *pa) {
    unsigned *pdtb = (unsigned *)0xfffff000;
    unsigned *pte = (unsigned *)0xffc00000;
    if (ptdb[vaddr>>20] & 1) {
         if (pte[vaddr>>12] & 1) {
              *pa = pte[vaddr>>12] &~0xfff;
              return 0;
         }
         return 2;
    }
    return 1;
}

您可以对任何索引执行此操作并调整指针值,但是如果变得更加混乱,则0xffc / 20会被挡住。