官术网_书友最值得收藏!

第7章 ARM處理器工作模式與異常中斷處理

7.1 ARM處理器工作模式

ARM處理器共有7種工作模式,除用戶(user)模式之外的其他6種處理模式統稱為特權模式(Privileged Modes)。在這些模式下,程序可以訪問所有的系統資源,也可以任意切換處理器模式。特權模式中除系統(system)模式之外的其他5種模式又統稱為異常模式。

處理器模式可以通過軟件控制進行切換,也可以通過外部中斷或內部異常處理過程進行切換。運行在用戶模式下的程序不能訪問一些受操作系統保護的系統資源,也不能直接進行處理器模式切換,如果要想進行模式切換,可以產生異常處理,在異常處理過程中進行處理器模式的切換,這種體系架構可以使操作系統控制整個系統資源。

每一種異常模式中都有一組寄存器供異常處理程序使用,這樣可以保證在進入異常模式時,用戶模式下的寄存器不被破壞。

系統模式不是通過異常過程進入的,它和用戶模式具有完全相同的寄存器。系統模式屬于特權模式,可以訪問所有系統資源,也可以直接進行處理器模式切換,主要供操作系統內核進程使用;通常操作系統內核進程需要訪問所有的系統資源,同時該進程仍然使用用戶模式下的寄存器組,而不是異常模式下的寄存器組,這樣可以保證當異常發生時內核進程狀態不被破壞。

ARM處理器的7種工作模式如表7-1所示。

表7-1 ARM處理器的7種工作模式

對應于以上7種模式,ARM處理器有7組通用寄存器,如表7-2所示。

表7-2 ARM處理器各種工作模式下的寄存器

說明:

? ARM處理器共有37個寄存器,被分為若干個組(BANK),這些寄存器包括31個通用寄存器和6個狀態寄存器,其中通用寄存器包括程序計數器(PC指針)及所有寄存器

(均為32位)。

? ARM處理器中有用戶模式、系統模式、特權模式、數據訪問終止模式、未定義指令終止模式、IRQ中斷模式、FIQ中斷模式7種工作模式,每種工作模式都有R0~R15及CPSR共17個通用寄存器,而在5種異常中斷(exception)模式中又各自擁有一個獨立的SPSR寄存器用于存放當前狀態寄存器的值。這些通用寄存器對于各種工作模式或部分工作模式有些是公用的,如表7-2所示。

? R8~R12對于快速中斷FIQ模式之外的其他模式都是公用的,而FIQ模式另外有一套自己寄存器R8_fiq~R12_fiq,這樣是為了在處理FIQ中斷時不必保護R8~R12寄存器,從而提高響應速度。

? R13和R14除了用戶模式和系統模式公用外,其他每種異常模式都有一套自己獨立的寄存器:R13_svc、R14_svc/R13_abt、R14_abt/R13_und、R14_und/R13_irq、R14_irq/R13_fiq、R14_fiq,即R13和R14有6套物理寄存器實現。

? R13/sp寄存器在ARM中除了可用作通用寄存器外還用作堆棧指針sp,而且每一種異常(exception)模式都有自己獨立的R13物理寄存器實現。在子程序中R13只能用作sp,sp在進入子程序的值和退出子程序的值必須相等。

? R14/lr寄存器在ARM中除了可以用作通用寄存器外,還可用作連接寄存器lr,用來保存子程序的返回地址,如果子程序保存了返回地址,R14也可以用作其他用途。每一種異常(exception)模式都有自己獨立的R14/lr物理寄存器實現。

? R15寄存器在ARM中用作程序計數器pc,雖然R15也可以用作通用寄存器,但要注意有一些特殊限制,如果違反了這些限制,指令執行的結果將是不可預料的。

? 子程序通過寄存器R0~R3來傳遞參數,這時,R0~R3可以記作A1~A4。如果參數超過4個,可以將剩余的參數送到數據棧中,入棧的順序與參數的順序相反,即最后一個參數字先入棧。

? 在子程序中用R4~R11來保存局部變量,這時,R4~R11可以記作V1~V8;而在Thumb程序中,通常只能使用寄存器R4~R7。

? 寄存器R12用作子程序間的scratch寄存器,記作ip,在子程序間的連接代碼中常有這種使用規則。

7.2 ARM處理器異常中斷向量表和優先級

異常(Exception)是指由處理器執行指令導致原來運行程序的中止,異常與指令運行相關,是CPU執行程序產生的,是同步的,可分為精確異常和非精確異常。異常處理遵守嚴格的程序順序,不能嵌套,只有當第一個異常處理完并返回后才能處理后續的異常。

中斷(Interrupt)是異步產生的,不是由CPU執行程序產生的,中斷屬于異常的一種,中斷是唯一與CPU運行無關的異常。所以我們用異常中斷來統稱Exception和Interrupt。

ARM處理器中的異常種類及其向量表和優先級說明如表7-3所示。

表7-3 ARM處理器的異常向量表及優先級

說明:

? 高端向量是ARM架構可選配置,可以通過硬件外部輸入管腳來配置是低端向量還是高端向量,不能通過指令來改變向量的位置,但如果ARM芯片內部有標準ARM協處理器,那么協處理器CP15的寄存器C1的bit13可以用來切換低端和高端向量地址,等于0時為低端向量,等于1時為高端向量。

? ARM的例外優先級從高到低依次為Reset→Data abort→FIQ→IRQ→Prefetch abort→Undefined instruction/SWI。

7.3 ARM處理器異常中斷處理

我們主要介紹如何進入異常中斷處理以及如何退出異常中斷處理。

7.3.1 進入異常中斷處理

ARM處理器發生異常中斷,則ARM處理器進入如下異常中斷自動處理過程(假設發生的異常中斷對應的模式為mode):

1)將當前程序狀態寄存器CPSR的值保存到SPSR_mode中;

2)將CPSR中的模式位設置成mode模式,將CPSR中的bit7(I)設置為1,禁止IRQ中斷,如果是FIQ中斷,則再將CPSR中的bit6(F)設置為1,禁止FIQ中斷;

3)將返回地址傳給lr_mode;

4)將該異常中斷的向量地址傳給程序計數器pc,從而進入異常中斷處理程序。

上述操作步驟可以用如下偽代碼來描述:

        R14_<exception_mode> = return link
        SPSR_<exception_mode> = CPSR
        CPSR[4:0] = exception mode number
        CPSR[5] = 0;切換到ARM狀態
        If <exception_mode> == Reset or FIQ then
            CPSR[6] = 1;禁止FIQ中斷
        CPSR[7] = 1;禁止IRQ中斷
        pc = exception vector address

7.3.2 退出異常中斷處理

當要從異常中斷處理程序中返回時,要做以下兩步操作(假設發生的異常中斷對應的模式為mode):

1)將保存在SPSR_mode中的值恢復到當前程序狀態寄存器CPSR中;

2)返回到發生異常中斷的指令的下一條指令處執行,也就是將lr_mode寄存器的值適當地返回到程序計數器pc中。

但程序員只需做好上述第二步即可,第一步在完成第二步的同時由處理器自動完成,所以我們下面講解從各種異常中斷處理返回的編程接口。

■ 退出復位異常中斷處理(Reset)

復位異常中斷處理程序不需要返回,所以不需要這個接口。

■ 退出未定義指令異常中斷處理(Undefined Instruction)

未定義指令異常中斷由當前執行的指令自身產生,當未定義指令異常中斷產生時,程序計數器pc的值還未更新,它指向當前指令后面第2條指令(對于ARM指令,它指向當前指令地址加8字節的位置;對于Thumb指令,它指向當前指令地址加4字節的位置),當未定義指令異常中斷發生時,處理器將值(pc-4)保存到lr_und中,此時(pc-4)指向當前指令的下一條指令,所以從未定義指令異常中斷返回可以通過如下指令來實現:

        mov pc, lr

該指令將寄存器lr_mode中的值復制到程序計數器pc中,實現程序返回,同時將SPSR_mode寄存器中的值復制到當前程序狀態寄存器CPSR中。

如果要在異常中斷處理中使用數據棧,那么可以在進入異常中斷處理程序時保存被中斷程序的執行現場,在退出異常中斷處理程序時恢復被中斷程序的執行現場,編程如下:

        stmfd sp!, {register_list, lr}     ;保存被中斷程序的執行現場
        ; . . .
        ldmfd sp!, {register_list, pc}^    ;恢復被中斷程序的執行現場

上面的register_list,是異常中斷處理程序中使用的寄存器列表,標識符^表示要將SPSR_mode寄存器中的值復制到當前程序狀態寄存器CPSR中。

■ 退出軟中斷指令(SWI)異常中斷處理(Undefined Instruction)

SWI異常中斷和未定義異常中斷指令一樣,也是由當前執行的指令自身產生,當SWI指令執行時,pc的值還未更新,它指向當前指令后面第2條指令(對于ARM指令,它指向當前指令地址加8字節的位置;對于Thumb指令,它指向當前指令地址加4字節的位置),當未定義指令異常中斷發生時,處理器將值(pc-4)保存到lr_svc中,此時(pc-4)指向當前指令的下一條指令,所以從SWI異常中斷處理返回的實現方法與從未定義指令異常中斷處理返回一樣:

        mov pc, lr

使用數據棧的方法與未定義指令異常中斷處理中的方法也一樣:

        stmfd sp!, {register_list, lr}     ;保存被中斷程序的執行現場
        ; . . .
        ldmfd sp!, {register_list, pc}^    ;恢復被中斷程序的執行現場

■ 退出指令預取中止異常中斷處理(Prefetch Abort)

在指令預取時,如果目標地址是非法的,該指令被標記成有問題的指令,這時,流水線上該指令之前的指令繼續執行,當執行到該被標記成有問題的指令時,處理器產生指令預取中止異常中斷。發生指令預取異常中斷時,程序要返回到該有問題的指令處,重新讀取并執行該指令,因此指令預取中止異常中斷應該返回到產生該指令預取中止異常中斷的指令處,而不是當前指令的下一條指令。

指令預取中止異常中斷由當前執行的指令自身產生,當指令預取中止異常中斷發生時,程序計數器pc的值還未更新,它指向當前指令后面第2條指令(對于ARM指令,它指向當前指令地址加8字節的位置;對于Thumb指令,它指向當前指令地址加4字節的位置)。此時處理器將值(pc-4)保存到lr_abt中,它指向當前指令的下一條指令,所以返回操作可以通過下面指令實現:

        subs pc, lr, #4

該指令將lr中的值減4后傳給程序計數器pc中,實現程序返回,同時將SPSR_abt寄存器的內容復制到當前程序狀態寄存器CPSR中。

如果要在指令預取中止異常中斷處理中使用數據棧,可以用以下方法保護、恢復被中斷程序的執行現場:

        subs lr, lr, #4
        stmfd sp!, {register_list, lr}     ;保存被中斷程序的執行現場
        ; . . .
        ldmfd sp!, {register_list, pc}^    ;恢復被中斷程序的執行現場

上面的register_list是異常中斷處理程序中使用的寄存器列表,標識符^表示要將SPSR_abt寄存器中的值復制到當前程序狀態寄存器CPSR中。

■ 退出數據訪問中止異常中斷處理(Data Abort)

發生數據訪問異常中斷時,程序要返回到該有問題的指令處,重新訪問該數據,因此數據訪問異常中斷應該返回到產生該數據訪問中止異常中斷的指令處,而不是當前指令的下一條指令。

數據訪問異常中斷由當前執行的指令自身產生,當數據訪問異常中斷發生時,程序計數器pc的值已經更新,它指向當前指令后面第3條指令(對于ARM指令,它指向當前指令地址加12字節的位置;對于Thumb指令,它指向當前指令地址加6字節的位置)。此時處理器將值(pc-4)保存到lr_abt中,它指向當前指令后面第2條指令,所以返回操作可以通過下面指令實現:

        subs pc, lr, #8

該指令將lr中的值減8后傳給程序計數器pc中,實現程序返回,同時將SPSR_abt寄存器內容復制到當前程序狀態寄存器CPSR中;

如果要在數據訪問異常中斷處理中使用數據棧,可以用以下方法保護、恢復被中斷程序的執行現場:

        subs lr, lr, #8
        stmfd sp!, {register_list, lr}     ;保存被中斷程序的執行現場
        ; . . .
        ldmfd sp!, {register_list, pc}^    ;恢復被中斷程序的執行現場

上面的register_list是異常中斷處理程序中使用的寄存器列表,標識符^表示要將SPSR_abt寄存器中的值復制到當前程序狀態寄存器CPSR中。

■ 退出IRQ異常中斷處理程序(IRQ)

通常處理器執行完當前指令后,查詢IRQ中斷引腳,并查看是否允許IRQ中斷,如果某個中斷引腳有效,并且系統允許該中斷產生,處理器將產生IRQ異常中斷,當IRQ異常中斷產生時,程序計數器pc的值已經更新,它指向當前指令后面第3條指令(對于ARM指令,它指向當前指令地址加12字節的位置;對于Thumb指令,它指向當前指令地址加6字節的位置),當IRQ異常中斷產生時,處理器將值(pc-4)保存到IRQ異常模式下的寄存器lr_irq中,它指向當前指令之后的第2條指令,因此返回操作可以通過下面指令實現:

        subs pc, lr, #4

該指令將lr中的值減4后傳給程序計數器pc中,實現程序返回,同時將SPSR_irq寄存器的內容復制到當前程序狀態寄存器CPSR中。

如果要在IRQ異常中斷處理中使用數據棧,可以用以下方法保護、恢復被中斷程序的執行現場:

        subs lr, lr, #4
        stmfd sp!, {register_list, lr}     ;保存被中斷程序的執行現場
        ; . . .
        ldmfd sp!, {register_list, pc}^    ;恢復被中斷程序的執行現場

上面的register_list是異常中斷處理程序中使用的寄存器列表,標識符^表示要將SPSR_irq寄存器中的值復制到當前程序狀態寄存器CPSR中。

■ 退出FIQ異常中斷處理程序(FIQ)

與IRQ異常中斷一樣,處理器執行完當前指令后,查詢FIQ中斷引腳,并查看是否允許FIQ中斷,如果中斷引腳有效,并且系統允許該中斷產生,處理器將產生FIQ異常中斷,當FIQ異常中斷產生時,程序計數器pc的值已經更新,它指向當前指令后面第3條指令(對于ARM指令,它指向當前指令地址加12字節的位置;對于Thumb指令,它指向當前指令地址加6字節的位置),當FIQ異常中斷產生時,處理器將值(pc-4)保存到IRQ異常模式下的寄存器lr_fiq中,它指向當前指令之后的第2條指令,因此返回操作可以通過下面指令實現:

        subs pc, lr, #4

該指令將lr中的值減4后傳給程序計數器pc中,實現程序返回,同時將SPSR_fiq寄存器的內容復制到當前程序狀態寄存器CPSR中。

如果要在FIQ異常中斷處理中使用數據棧,可以用以下方法保護、恢復被中斷程序的執行現場:

        subs lr, lr, #4
        stmfd sp!, {register_list, lr}     ;保存被中斷程序的執行現場
        ; . . .
        ldmfd sp!, {register_list, pc}^    ;恢復被中斷程序的執行現場

上面的register_list是異常中斷處理程序中使用的寄存器列表,標識符^表示要將SPSR_fiq寄存器中的值復制到當前程序狀態寄存器CPSR中。

7.4 ARM處理器的中斷(IRQ或FIQ)

前面提到的ARM處理器的IRQ和FIQ異常中斷都是由處理器內部或外部中斷源引起的。ARM處理器支持多個內部或外部中斷源,如定時器中斷、UART中斷、網絡收發中斷等,ARM處理器一般用中斷使能寄存器、中斷屏蔽寄存器、中斷停靠寄存器、中斷狀態寄存器、中斷模式寄存器來管理這些中斷,這些寄存器都是32位的,各寄存器中對應的一位管理一個中斷源,所以ARM處理器支持一般不超過32個中斷源,要了解處理器有哪些中斷源請參看各處理器芯片手冊。

上述寄存器中的中斷使能寄存器用來使能中斷,寄存器中的位為1時,其對應的中斷被使能,否則中斷不被使能。中斷屏蔽寄存器用來禁止中斷,寄存器中的位為1時,其對應的中斷被禁止。中斷停(pending)靠寄存器是只讀寄存器,如果其中的某位為1,表示當前系統中發生了該位對應的中斷,如果系統中同時產生了多個中斷,那么該寄存器中就有多個相應的位被置1。中斷狀態寄存器也是只讀寄存器,這個寄存器的值相當于使能寄存器與停靠寄存器相與得到的值,也就是說只有那些被使能并且當前確實產生了的中斷對應該寄存器中的位才會被設置為1。中斷模式寄存器用來分別將每個中斷源配制成IRQ中斷模式或者FIQ中斷模式,IRQ是普通中斷模式,處理速度比較慢,優先級較低,而FIQ處理速度表較快,優先級較高。

主站蜘蛛池模板: 胶南市| 广德县| 精河县| 环江| 江源县| 黄平县| 临城县| 苏州市| 鄂州市| 买车| 电白县| 英吉沙县| 泗水县| 玛纳斯县| 湄潭县| 雷山县| 文山县| 呼图壁县| 长阳| 尚义县| 大同市| 龙泉市| 永定县| 江口县| 彝良县| 西乡县| 蛟河市| 娄烦县| 连山| 陇川县| 喀喇沁旗| 太和县| 太湖县| 张家口市| 武邑县| 海口市| 泉州市| 察哈| 谢通门县| 宁陵县| 绥棱县|