實驗內容
實現一個函數來打印頁表的內容,幫助我們更好地理解 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;