实验内容
- 实现一个函数来打印页表的内容,帮助我们更好地理解 xv6 的三级页表结构。
修改内容
kernel/defs.h
中添加函数声明,方便其它函数调用
void vmprint(pagetable_t);
kernel/vm.c
中添加函数具体定义
- 采用简单的for遍历,也可采用递归
- xv6采用三级页表结构,因此要遍历三层,每层0~511,必须判断PTE的有效性
void vmprint(pagetable_t pagetable){
printf("page table %p\n", pagetable);
for( int i = 0; i < 512; i++){
pte_t pte1 = pagetable[i];
if(pte1 & PTE_V ){
printf("..%d: pte %p pa %p\n", i, pte1, PTE2PA(pte1));
pagetable_t pmd = (pagetable_t)PTE2PA(pte1);
for( int j = 0; j < 512; j++){
pte_t pte2 = pmd[j];
if(pte2 & PTE_V ){
printf(".. ..%d: pte %p pa %p\n", j, pte2, PTE2PA(pte2));
pagetable_t pt = (pagetable_t)PTE2PA(pte1);
for( int k = 0; k < 512; k++){
pte_t pte3 = pt[k];
if(pte3 & PTE_V ){
printf(".. .. ..%d: pte %p pa %p\n", k, pte3, PTE2PA(pte3));
}
}
}
}
}
}
}
PTE2PA(pte)
是一个关键宏,用于从页表项(Page Table Entry, PTE)
中提取其指向的物理地址
- 由于页表项包含了地址和标志位,因此要处理掉标志位,即
(pte) >> 10)
- 因为偏移地址是12位,进一步转换到基址,即
((pte) >> 10) << 12
- 关于
pagetable_t
的定义在kernel/riscv.h
中
typedef uint64 pte_t;
typedef uint64 *pagetable_t;
#define PTE2PA(pte) (((pte) >> 10) << 12)
| 63-54 | 53-28 | 27-10 | 9-8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| 保留 | PPN | 保留 | RSW | D | A | G | U | X | W | R | V |
kernel/exec.c
中调用vmprint,将进程的根页表传递过去
if( p->pid == 1 ){
vmprint( p->pagetable );
}
return argc;