ARM CortexM3/4權限切換
簡介
最近我在研究怎麼在ARM Cortex M3/4上面跑一個自己寫的OS,最主要是參考jserv的mini-arm-os和pikoRT,相關程式碼放在arm-os-4fun。
最近發現自己遇到了些問題,想說再研究怎麼解決的過程中順便把細節紀錄下,供自己未來可以參考。
這邊首先要探討的是Cortex M3/4上面有的權限模式,以及它們是怎麼進行切換等細節。
原本我是在qemu上面跑STM32虛擬機,但是後來發現好像跟真實硬體有點不一致,所以後來我都在STM32F429的硬體上面來測試了。
Cortex M權限設計
首先我們先了解Cortex上面有哪些權限模式,處理器上面有兩種Operation Modes:Thread mode和Handler mode。
- Thread Mode:一般程式運行的狀態。
- Handler Mode:處理exception的狀態。
然而除了這個以外,還有不同的Privilege Levels,避免一般使用者可以存取敏感資源。
- Privileged:可以存取所有資源,在CPU reset之後就是privileged。
- Unprivileged:通常是讓OS中userspace的程式運行用的,在幾個方面存取資源是受限的。
- MSR、MRS指令存取上會有限制。
- 無法存取system timer、NVIC。
- 有些memory無法存取。
Operation Modes和Privilege Levels的關係如下所示,Unprivileged不能進入Handler Mode的。
- | Privileged Level | Unprivileged Level |
---|---|---|
Handler Mode | O(state1) | X |
Thread Mode | O(state2) | O(state3) |
- 上面標註的state 1-3是為了方便我們後面講解而標的。
如何切換權限與模式
關於切換的部分可參考下圖,圖片來源A tour of the Cortex-M3 Core
下面我們先看怎麼樣從state2,state3進入state1,也就是發生exception,然後再從state1回來。
Exception Entry
進入exception有兩種情況:
- 目前我們在thread mode
- preempts:發生的exception比目前我們所在的exception權限還高
發生exception時,ARM會自動把當前的register的資訊存起來,順序為xPSR, PC, LR, R12, R3, R2, R1, R0。儲存的方式就是push到當前的stack中,可能是main stack(SP=MSP),也可能是process stack(SP=PSP)。
address | register |
---|---|
SP+00 | R0 <- SP after exception |
SP+0x04 | R1 |
SP+0x08 | R2 |
SP+0x0C | R3 |
SP+0x10 | R12 |
SP+0x14 | LR |
SP+0x18 | PC |
SP+0x1C | xPSR |
SP+0x20 | xxx <- SP before exception |
完成後接著會開始執行exception handler,並且把EXC_RETURN寫入LR。
Exception Return
要從exception跳還必須要符合兩個條件:
- 目前正在Handler Mode。
- PC的值是合法的EXC_RETURN。
關於EXC_RETURN的值,其實代表了ARM從handler mode回去的路徑,有三種可能:
- 目前是nested exception,回去上層還是handler mode。
- 是由privileged thread mode呼叫的,也就是要回到state2。
- 是由unprivileged thread mode呼叫的,也就是要回到state3。
因此EXC_RETURN有三個可能的值
EXC_RETURN | Description |
---|---|
0xFFFFFFF1 | Return to Handler mode. Exception return gets state from the main stack. Execution uses MSP after return. |
0xFFFFFFF9 | Return to Thread mode. Exception Return get state from the main stack. Execution uses MSP after return. |
0xFFFFFFFD | Return to Thread mode. Exception return gets state from the process stack. Execution uses PSP after return. |
Privileged to Unprivileged
接著我們要來探討怎麼從Privileged進入Unprivileged,也就是state2進入state3的部分。
如果要進入Unprivileged,那必須使用到特殊register - control。
bit | Description |
---|---|
CONTROL[1] | 0:Use MSP, 1: Use PSP |
CONTROL[0] | 0:Privileged thread mode, 1:Unprivileged thread mode |
要特別注意操作control register一定要用MRS和MSR register
1 | # CONTROL值搬到R0 |
進入Unprivileged Thread Mode的操作
1 | MOV R0, 3 |
ARM在切換上面的設計
ARM在處理nested exception上有自己的一套做法來加快速度,確保高優先權的exception能更快被執行到,達到更高的即時性(real-time)。
下面介紹兩種在Cortex M上面的機制:
- tail-chained:
- 情況:如果發生exception1的時候又發生exception2,但是exception2的優先權沒有高於exception1,必須等待。
- 原本:一般來說exception1結束的時候會先pop stack,然後再push stack進入處理exception2。
- 改進:exception1到exception2中間的pop&push其實是沒意義的,所以ARM Cortex M會在exception1結束後直接執行exception2,減少了中間的浪費。
- late-arriving
- 情況:如果發生exception1並且執行state saving(上面說的push register),這時候有更高優先權的exception2進來,發生preempts。
- 原本:會中斷exception1的state saving,優先讓給exception2。
- 改進:exception2其實也是需要state saving,所以繼續維持state saving,然後直接執行exception2。當exception2結束後,就又可以使用tail-chained的模式來執行exception1。
參考
關於Cortex M相關的資料非常推薦下面兩本書籍,都有中文的翻譯。JosephYiu有參與ARM Cortex M的設計,比較有權威性。
可參考jserv老師和學生撰寫的rtenv+簡介,裡面也有提到ARM CM3權限的部分。