我试图循环遍历xv6中的进程的所有页面。我看过这个图表来了解它是如何工作的:

但我的密码是:
unexpected trap 14 from cpu 0 eip 801045ff (cr2=0xdfbb000)代码:
pde_t * physPgDir = (void *)V2P(p->pgdir);
int c = 0;
for(unsigned int i =0; i<NPDENTRIES;i++){
pde_t * pde = &physPgDir[i];
if(*pde & PTE_P){//page directory valid entry
int pde_ppn = (int)((PTE_ADDR(*pde)) >> PTXSHIFT);
pte_t * physPgtab = (void *)(PTE_ADDR(*pde));//grab 20 MSB for inner page table phys pointer;
// go through inner page table
for(unsigned int j =0;j<NPDENTRIES;j++){
pte_t * pte = &physPgtab[j];
if(*pte & PTE_P){//valid entry
c++;
unsigned int pte_ppn = (PTE_ADDR(*pte)) >> PTXSHIFT;//grab 20 MSB for inner page table phys pointer;
//do thing
}
}
}
}这在proc.c中的某些自定义函数中是在其他地方调用的。P是进程指针。据我所知,cr3包含当前进程的物理地址。但是,在我的例子中,我需要获得给定进程指针的页表。xv6代码似乎在cr3中加载了V2P(p->pgdir)。这就是为什么我试图获得V2P(p->pgdir)。然而,陷阱发生在pde被取消引用之前。这意味着这里有个问题。我不应该用物理地址吗?
编辑:正如Brendan回答的,虚拟地址p->pgdir应该被取消引用。此外,还应该通过P2V将页面目录中的PPN转换为正确地取消对页面表的引用。如果将来有其他人对xv6的这一方面感到困惑,我希望这会有所帮助。
发布于 2022-02-05 16:50:36
在处理分页时,金科玉律是“永远不要在任何类型的指针中存储物理地址”。原因是:
( a)它们不是虚拟地址,也不能取消引用,因此,如果尝试使用物理地址作为指针,最好通过确保获得编译时错误来使bug变得明显。
在某些情况下,物理地址与虚拟地址的大小不同(例如:在80x86中的"PAE分页“中,虚拟地址仍然是32位,但物理地址可能高达52位);而且它更好(为了便于移植--例如,可以在某个时候更容易地将PAE支持添加到XV6中)。
记住这一点,您的第一行代码就是一个明显的错误(它打破了“黄金法则”)。它应该是pde_t physPgDir = V2P(p->pgdir);或pde_t * pgDir = p->pgdir;。我会让你找出哪一个(我怀疑这是家庭作业,我相信通过遵守“金科玉律”你就能解决你自己的问题)。
https://stackoverflow.com/questions/70995156
复制相似问题