c - 将虚拟地址从多级页表转换为物理地址
问题描述
我正在尝试将虚拟内存地址转换为物理地址,但无法使其正常工作。我目前正在做一个操作系统作为作业,现在我必须为用户模式实现一个 printf 函数,所以当你调用 write 系统调用时,系统应该将用户模式下的数组内容打印到串口(现在),为此我必须将地址从虚拟地址转换为物理地址。
这是我来自系统调用处理程序的代码:
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
以下是书中解释页面结构的部分:
解决方案
如果您为第一级表的最后一个(索引 1023)指向的第二级表中的最后一个(索引 1023)条目填写 pte,则:
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 不碍事。
推荐阅读
- sql-server - 如何将向量作为 SQL 函数的参数传递?
- javascript - 为什么我的两个 javascript 类实例不相同?
- android-studio - 选择一个有效的 JDK 目录
- coq - 逻辑:In_example_2
- c# - 如何将 WebApiConfig 添加到我的 UmbracoApiController?
- c# - 为什么 TimeZoneInfo.FindSystemTimeZoneById("UTC") 和 TimeZoneInfo.GetSystemTimeZones().Single(x => x.Id == "UTC") 给出不同的结果?
- powershell - 如何将联系人迁移到 Teams?
- javascript - 如何在单击按钮时创建表单加载项?
- javascript - 从注册表单中捕获多个名称
- spring - 如何加载 mongo 存储库以弹簧测试应用程序上下文?