XV6中kalloc返回虚拟地址还是物理地址?及页表映射疑问
解答XV6 x86版本walkpgdir中V2P的疑问
先纠正你的核心误解
你认为kalloc返回的是物理地址,这是错的。XV6在bootloader阶段就完成了段映射配置,内核全程运行在虚拟地址空间:虚拟地址从KERNBASE(0x80000000)起始,对应物理地址从0开始的内存区域。kalloc分配物理页后,返回的是该页对应的虚拟地址(等价于P2V(物理页地址))。
为什么要对pgtab执行V2P转换?
页目录项(PDE)的硬件格式要求必须存储页表的物理基地址:
- 当MMU处理地址转换时,它从CR3寄存器读取页目录的物理地址,直接访问物理内存中的页目录和页表——硬件完全不识别虚拟地址,只认物理地址。
- pgtab是kalloc返回的虚拟地址,必须通过
V2P()宏转成对应的物理地址,才能写入PDE,让MMU正确定位到页表的物理位置。
补充流程细节(修正你的理解)
你的整体流程梳理基本正确,补充几个关键节点:
- 即使还没启用分页(VM),内核已经通过段映射运行在虚拟地址空间,所有内核代码中使用的地址都是虚拟地址。
- setupkvm创建的pgdir本身也是kalloc分配的,所以pgdir是虚拟地址,后续启用分页时会被转成物理地址写入CR3寄存器。
- 当walkpgdir中PDE已存在有效页表时,代码用
P2V(PTE_ADDR(*pde))把物理地址转成虚拟地址——这是因为内核代码只能通过虚拟地址访问内存,无法直接用物理地址操作。
附原walkpgdir代码关键部分注释:
static pte_t * walkpgdir(pde_t *pgdir, const void *va, int alloc) { pde_t *pde; pte_t *pgtab; pde = &pgdir[PDX(va)]; if(*pde & PTE_P){ // 从PDE取出页表物理地址,转成虚拟地址供内核访问 pgtab = (pte_t*)P2V(PTE_ADDR(*pde)); } else { if(!alloc || (pgtab = (pte_t*)kalloc()) == 0) return 0; memset(pgtab, 0, PGSIZE); // pgtab是虚拟地址,转成物理地址写入PDE,供MMU识别 *pde = V2P(pgtab) | PTE_P | PTE_W | PTE_U; } return &pgtab[PTX(va)]; }
内容的提问来源于stack exchange,提问作者nithya manish
相关产品推荐
相关产品推荐

