实验内容
实现一个函数来打印页表的内容,帮助我们更好地理解 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;