ARMLinux的TLB miss處理過程——Heron(2012.11.23)
在ARM架構下,TLB miss後的工作絕大多數情況是由hardwarepage table walk完成,特殊情況下hardware page table walk可以被關閉,此時發生TLB miss後CPU就會產生一個translationfault,剩下的工作由OS接管,完成對於translation fault的異常處理。
默認情況下,發生TLB miss後,hardware page table walk自動啟動開始掃描內存中的pagetable,若找到相應PTE(page table entry),則自動完成TLB entry的重填工作;如果找不到,則發出一個page fault異常,然後OS接管處理page fault。內核中有do_page_fault函數,該函數從硬盤中調換頁面進內存,更新頁表,然後重新執行發生TLB miss的那條指令,hardware page table walk重新執行,完成TLB重填的工作。
這裡關心的是關閉hardware pagetable walk後,再發生TLB miss後的處理例程。如果發生這種情況,ARM CPU會發出一個translation fault(If translation table walksare disabled, for example, PD0 or EPD0 is set to 1 for TTBR0, or PD1 or EPD1 isset to 1 for TTBR1, the processor returns a Translation fault.見cortex-A15TRM p 5-5)。OS處理該異常的流程如下。
首先發生translation fault後,CPU會發出一個abort異常,然後跳轉到該異常地址處(以發生指令預取中止異常為例,跳轉到0x00000010)去執行,該地址處存放的是一個跳轉指令 (W(b) vector_pabt +stubs_offset),然後,通過判斷,若發生該異常的指令處於usr模式,則跳轉到__pabt_usr函數去執行,該函數中有條跳轉指令bl CPU_PABORT_HANDLER,CPU_PABORT_HANDLER是個宏定義,對於ARMv7,該定義是:# define CPU_PABORT_HANDLER v7_pabort,
v7_pabort函數中就讀取了IFSR和IFAR兩個寄存器的值:
//pabort-v7.S
/*
*Function: v6_pabort
*
*Params : r0 = address of aborted instruction
*
*Returns : r0 = address of abort
* : r1 = IFSR
*
*Purpose : obtain information about current prefetch abort.
*/
.align 5
ENTRY(v7_pabort)
mrc p15,0, r0, c6, c0, 2 @ get IFAR
mrc p15,0, r1, c5, c0, 1 @ get IFSR
mov pc,lr
ENDPROC(v7_pabort)
IFAR中存儲了發生異常的指令地址,IFSR中存儲的是一個32位數,其中某些位表明異常類型等(參考Cortex-A15TRM p4-76)
剩余的工作就是根據以上兩個寄存器提取出來的信息,調用相應函數(do_PrefetchAbort——>do_translation_fault)進行處理。OS接管後的操作是(do_translation_fault函數),首先判斷發生TLBmiss的那條指令是用戶指令還是系統指令,如果是系統指令則剩余工作是對頁全局目錄(pgd),頁上級目錄(pud),頁中間目錄(pmd)進行操作;如果是用戶指令,則調用do_page_fault函數,剩下的工作就是page fault的處理過程,根據不同情況判斷,包括權限檢查,分配頁面,發送SIGSEGV信號給進程,直接殺死進程等。不管哪種操作,OS都沒有對TLB進行重填。
對於page fault的處理過程如下:在取數或者取指令時,發生指令或者數據的地址不存在的情況,則發生中止異常。
以取指發生異常為例。發生指令預取中止異常後,CPU自動跳轉到0x0000000C(可配置成0xfffffffc,這裡不考慮)去執行,該地址處是一個跳轉指令 (W(b) vector_pabt + stubs_offset),然後,通過判斷,若發生該異常的指令處於usr模式,則跳轉到__pabt_usr函數去執行,該函數中有條跳轉指令bl CPU_PABORT_HANDLER,CPU_PABORT_HANDLER是個宏定義,對於ARMv7,該定義是:# defineCPU_PABORT_HANDLER v7_pabort,v7_pabort函數中就讀取了IFSR和IFAR兩個寄存器的值:
//pabort-v7.S
/*
* Function: v6_pabort
*
* Params : r0 = address ofaborted instruction
*
* Returns : r0 = address of abort
* : r1 = IFSR
*
* Purpose : obtain information aboutcurrent prefetch abort.
*/
.align 5
ENTRY(v7_pabort)
mrc p15, 0, r0, c6, c0, 2 @ get IFAR
mrc p15, 0, r1, c5, c0, 1 @ get IFSR
mov pc, lr
ENDPROC(v7_pabort)
IFAR中存儲了發生異常的指令地址,IFSR中存儲的是一個32位數,其中某些位表明異常類型等(參考Cortex-A15 TRM p4-76)
剩余的工作就是根據以上兩個寄存器提取出來的信息,調用相應函數(do_PrefetchAbort——>do_page_fault)進行處理。