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)