(轉)ARM Linux中斷發生時內核堆棧切換
轉載註明出處:http://www.wowotech.net/forum/viewtopic.php?id=54
對ARM Linux中斷非常簡潔、精確的描述。
發生了中斷,最重要的是保存現場,在中斷處理完之後,能夠恢復現場就OK了,硬件現場(hardware context)的保存是由硬件和軟件共同完成的。
對於ARM,當發生中斷的那一刻,硬件會進行如下的動作:
1、將發生中斷那一刻的CPSR保存在SPSR寄存器中
2、將返回地址保存在lr寄存器中(註意:這個lr寄存器是IRQ mode的lr寄存器,可以表示為lr_irq)
真正將hardware context保存到內核棧上是軟件的行為。當然,目標是一開始就設定好了,將發生中斷那一刻的hardware context保存到current task的內核棧上。不同的CPU有不同的設計,提供不同的軟件和硬件的接口,對於X86,硬件幫忙做的事情更多,而ARM更希望你自己能夠自力更生(更簡單的HW logic意味著更少的晶體管,更少的功耗,而這也是ARM在移動平臺上能夠橫掃Intel的根本原因)。怎麽辦?hardware context包括了cpu中的各種寄存器,想要將hardware context壓入內核棧首先要獲取current thread的內核棧指針,任何對cpu寄存器的使用將破壞硬件上下文,因此,linux kernel采用的方法是借用12個字節的中斷棧。方法如下:
1、在中斷棧上保存了發生中斷那一點的r0值、PC值以及CPSR值。你可能會覺得:PC和CPSR需要保存嗎?不是硬件已經幫忙保存lr_irq(雖然不是PC值,但是和PC值有固定的偏移關系)和spsr_irq中了嗎?之所以保存spsr_irq和lr_irq的值,那是因為隨後在切換到svc mode的時候需要修改spsr_irq和lr_irq的值。之所以保存r0,是因為後續會修改r0的值,把它做為一個scratch register。
2、切換到svc mode,具體完成下面兩個步驟:
(A)將處理器模式切換到svc mode (B)根據發生中斷那一點的處理器模式,將pc設定為__irq_usr或者__irq_svc
在上面的過程中,lr_irq,spsr_irq和r0被破壞了,但是沒有關系,相關信息已經保存在了中斷棧上了(sp_irq)
3、一旦切換到SVC mode,ARM處理器看到的寄存器已經發生變化,這裏的sp已經變成了sp_svc了。問題來了:sp_svc是什麽值?在進程切換的時候就已經設定好了,sp_svc被設定為current thread的內核棧。這時候,除了被破壞的三個寄存器保存在中斷棧上,其他的寄存器毫發無傷,軟件只要將這些hardware context壓入current thread的內核棧上即可。
(轉)ARM Linux中斷發生時內核堆棧切換