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