---
# System prepended metadata

title: Arm Programmer's Guide III - Processor Modes and Registers 學習筆記
tags: [Arm, chihanlin, registers, Processor Mode, programmer's guide]

---

# Arm Programmer's Guide III - Processor Modes and Registers 學習筆記
# 1. 前言

此筆記為學習 [ARM® Cortex™-A Series Programmer's Guide
Version: 4.0 中第三章 ARM Architecture and Processors ](https://developer.arm.com/documentation/den0013/d/ARM-Processor-Modes-and-Registers?lang=en) 的心得筆記。主旨在解釋 Armv7 Aarch32 下的核心模式 (Processor Mode) 和寄存器 (Register)。另外此為此學習筆記系列的第一篇，原文的第一篇 [Introducing](https://developer.arm.com/documentation/den0013/d/Introduction?lang=en) 和第二篇 [Arm Architecture and Processors](https://developer.arm.com/documentation/den0013/d/ARM-Architecture-and-Processors?lang=en) 不會有相關的學習筆記。

# 2. Processor Mode

Armv7 核心總共有九種模式、三層特權階級 (PL, Privilege Level)，然後又分為正常 (Normal 或 Non-Secure) 和安全 (Secure) 世界 (World)。他們的關係大致如下圖:

![image](https://hackmd.io/_uploads/HkMUXId9ye.png)

## 2.1 Normal / Secure World

上圖藍色區域為 Non-Secure (或稱 Normal) World、而黃色區域為 Secure World。Arm 的 TrustZone Scurity Extension 技術將所有的軟硬體資源分成 Non-Secure 和 Secure 兩類，當核心處於 Non-Secure 狀態下，他便無法存取任何的 Secure 軟硬體資源。所以可以將一些較機密或敏感的資料放在 Secure World 中 (像手機裡的指紋辨識相關資料或技術)，然後將和一般使用者互動的作業系統以及應用程式放在 Non-Secure World 中，這樣即使惡意軟體或駭客害入了作業系統，他也沒有權限去觸碰到 Secure World 中受保護的資料。

兩個世界依靠上圖中最底層的 Secure Monitor 來做切換。

## 2.2 特權階級 (Privilege Level)
兩個世界又各自被特權階級分割。特權數字越大表是擁有越多的特權，能存取越多的資源。舉例來說，無論是 Normal 還是 Secure World 的 PL0 都無法存取系統相關的資源 (因此特權階級 0 其實是沒有特權的)，像是 MMU (Memory Management Unit)、Cache 等等資源的存取與操作都必須在 PL1 (或更高的特權階級中) 中才有辦法進行。

所以通常來說，如上圖所示，作業系統的範圍應該會包含 PL0 和 PL1，其中 PL0 是用來跑最上層應用程式 (如 Linux 的 User space)；PL1 則是用來跑作業系統的核心 (如 Linux 的 Kernel space)。又如果有實作虛擬化 (Virtulization Extension)，那麼虛擬機會跑在各作業系統之下的 PL2 位置 (只有 Normal World 有這個階級，所以只有 Normal World 支援虛擬技術)。

另外，特權階級對於核心來說是一個概念，並沒有一個寄存器或者特定的 BIT 去指定核心的特權階級。能夠被指定的是核心模式，而不同的核心模式固定屬於特定的特權階級 (其對應關係可以參考上圖)。

## 2.3 核心模式

核心模式和特權階級息息相關，但相對於特權階級所表達的擁有特權多寡的概念，核心模式的區分更是偏向功能性的。舉例來說，FIQ 模式就是為了處理 FIQ 異常、而 MON 模式則是為了 Normal / Secure World 的切換。

| Mode                         | Encoding | 說明      |
| ---------------------------- | -------- | -------- |
| USR (User)                   | 10000    | 應用程式所在的無特權階級。 |
| FIQ (Fast Interrupt Request) | 10001    | 由 FIQ 中斷異常進入。    |
| IRQ (Interrupt Request)      | 10010    | 由 IRQ 中斷異常進入。    |
| SVC (Supervisor)             | 10011    | Reset 後或者在指令 SVC (Supervisor Call instruction) 執行後進入。應用程式通常透過 SVC 來像核心索取特權服務或資源。|
| MON (Monitor)                | 10110    | Security Extension 實作的一部分，負責 Normal 和 Secure World 之間的切換，也是 Normal World 進到 Secure World 的進入點。 |
| ABT (Abort)                  | 10111    | 由記憶體存取異常進入。 |
| HYP (Hypervisor)             | 11010    | Virtualization Extention 實作的一部分，用來虛擬化 PL1 中的多個客作業系統。|
| UND (Undefined)              | 11011    | 由執行未定義指令異常進入。|
| SYS (System)                 | 11111    | 基本上就是有特權的 USR 模式，和 USR 共用所有寄存器。為內核平常的運行模式。|

若想改變核心的模式，除了透過異常之外，可以直接改寫 CPSR (Current Program Status Register) 裡的 BIT M 來達到。而各模式對應的值則為上表的 Encoding 值。這會在稍後的 [3.2.1 CPSR](https://hackmd.io/@uMqav-XESBCsrtZEx_Jpug/Arm_Programmer_Guide_Processor_Modes_and_Registers_Study_note#321-CPSR) 章節再次提到。

# 3. 寄存器 (Registers)

寄存器是 CPU 內部的儲存硬體，對他們的存取速度會遠大於對於外部記憶體的存取速度。他們有的用來存放運算資料供 CPU 計算、有的則是存放跟核心有關的功能資訊。

## 3.1 通用寄存器

ARM 架構提供 16 個 32 bit 的通用寄存器 (R0 ~ R15) 給軟體使用。
* R0 ~ R12 沒有特殊意義，可以用作一般目的的資料存放。
* R13 又稱為 SP (Stack Pointer)，除了可以用作一般目的的資料存放外，也會指向 Stack 的頂點位置。舉例來說，當執行 Push 指令將資料推進 Stack 時，資料實際上是被推進 R13 (或 SP) 指向的位置。
* R14 又稱為 LR (Line Register)，一樣也可以用作一般目的的資料存放，但同時也會被用來存放返回位置。舉例來說，當執行 BL 指令跳轉去其他位置執行時， R14 (或 LR) 的值會自動被改寫成 BL 指令的下一行。
* R15 又稱為 PC (Program Counter)，沒有辦法用作一般目的的資料存放。它的值表示核心要執行的位置，一般來說他會依序遞增，讓核心能依序執行所有程式內容，如果修改他，那麼核心就會打斷原本的執行流程，轉而跳往新的 PC 值位置去執行。

雖然說 ARM 提供了 16 個通用寄存器，但是對於不同的核心模式，他們的同編號寄存器有可能實際對應到的是不同的硬體空間，這種情況我們稱為 Banking。下圖中的藍灰色寄存器都是 Banked 的，也是該寄存器實際上是有別於 User 寄存器的。舉裡來說，SYS 模式下的所有通用寄存器都和 User 是共用的，但是 FIQ 模式下只有 R0 ~ R7 是和 User 共用，FIQ 模式擁有自己的 R8 ~ R15。

![image](https://hackmd.io/_uploads/HJNToy591e.png)

## 3.2 Program Status Registers

上圖中最下面一排有顯示 CPSR、APSR 和 SPSR。他們分別代表 Current / Application / Saved  Program Status Register。

### 3.2.1 CPSR

CPSR 是一個特殊功能的寄存器，用來記錄、控制核心的狀態和設定，其格式如下:
![image](https://hackmd.io/_uploads/HJL_pJqc1e.png)

* **BIT N (Negative)**: 當進行 ALU (Arithmetic logic Unit) 運算 (也就是加減乘除、AND、OR、NOT、XOR 或位移這些運算) 且結果為負時， BIT N 會舉起為 1。
* **BIT Z (Zero)**: 當進行 ALU 運算且結果為 0 時，BIT Z 會舉起為 1。
* **BIT C (Carry out)**: 當進行 ALU 運算且若將其值當成無符號 (Unsigned) 類型，結果發生進位時，BIT C 會舉起為 1。舉例來說，```ADD R0, R1, #1``` 其中 R1 為 0xFFFFFFFF，R1 和 1 相加會超過 32 bit 的最大值發生進位 (Carry)，導致 BIT C 舉起為 1。
* **BIT V (Overflow)**: 當進行 ALU 運算且若將其值當成有符號 (Signed) 類型，結果發生益位時，BIT V 會舉起為 1。舉例來說，```ADD R0, R1, #1``` , 其中 R1 為 0x7FFFFFFF、為有符號類型的最大值 2147483647，和 1 相加後會發生溢位，導致 R0 值為 0x80000000、有符號情況下為 -2147483648，這時 BIT V 舉起為 1 (但因為沒有發生進位，所以 BIT C 不會舉起)。
* **BIT Q (Cumulative)**: 當進行飽和 (Saturation) 運算且達到飽和值，BIT Q 會被舉起為 1。飽和運算會將結果的值限制在最大和最小值之間，若結果會超過，則維持最大或最小值。舉例來說，```UADD R0, R1, #1``` , 其中 UADD 表示無符號的飽和加法、R1 為 0xFFFFFFFF，其加上 1 會超過無符號的上限，所以飽和加發會把它限制在最大值，最終 R0 為 0xFFFFFFFF，然後 BIT Q 會被舉起為 1。
* **BIT J (Jazelle)**: 控制核心是否跑在 Jazelle 模式。Jazelle 是一種硬體加速技術，可以提升 Arm 執行 Java 的速度、並減少對 JVM (Java Virtual Machine) 的依賴。但由於現今的 JVM 效能已經獲得大幅優化，Jazelle 已逐漸被淘汰。
* **BIT GE (Greater than or Equal)**: 紀錄「非 NEON」 SIMD (Single Instruction Multiple Data) 指令的結果。 SIMD 是一種併行運算技術，允許單個指令同時對多個數據進行運算，以提升效率。舉例來說:
    ```
    MOV     R0, #0x11223344
    MOV     R1, #0x55667788
    
    // 將 GE 設成 0b1100
    MRS     R3, CPSR
    ORR     R3, R3, #(0b1010 << 16)
    MSR     CPSR_c, R3
    
    SEL     R2, R0, R1
    ```
    SEL (Select based on GE flags) 會將兩個 32 bit 操作數 (Operand) R0 和 R1 切成 4 個 8 bit 資料，並根據 CPSR 的 GE Bit 在兩個操作數中選擇其中一邊，將其存入目的寄存器 R2。也就是說，當 GE 為 1 時，SEL 會選 R0、相反則選 R1。最後因為上例中 GE 為 0b1010，所以最高八 bit 會來自 R0、BIT[23:16] 會來自 R1、BIT[15:8] 會來自 R0，最後最低 8 bit 會來自 R1，由此得到結果 R2 的值會是 0x11663388。
* **BIT IT (If-Then)**: 總共有 7 個 bit (但上圖可以看到，七個 bit 並不連續)，用來控制 IT 等 if-then-else 指令。 IT 指令就是 Arm 指令上的加速版 If-then，直接舉例來說，如果你想要達到這樣的邏輯:
    ```clike=
    if(R0 == R1)
    {
        R3 = R4 + R5;
        R3 = R3 >> 1;
    }
    else
    {
        R3 = R6 + R7;
        R3 = R3 >> 1;
    }
    ```
    那麼可以因為 if-else 中的指令都很少，就可以利用 IT 來實作:
    ```clike=
    CMP R0, R1
    ITTEE               // TT (ThenThen) 表示接下來兩個指令是在前面判斷成立執行、EE (ElseElse) 表示後兩條指令是在前面判斷為否下執行
    ADDEQ R3, R4, R5    // EQ 表示相等時做
    ASREQ R4, R3, #1    // SR 表示 Shift Right，EQ 表示相等時做
    ADDNE R3, R6, R7    // NE 表示不相等時做
    ASRNE R3, R3, #1    // SR 表示 Shift Right，NQ 表示不相等時做
    ```
    (參考來源: https://blog.csdn.net/whealther/article/details/43194761)
* **BIT E (Endianness)**: 設定讀寫 (Load/Store) 記憶體的端序。
* **BIT A (Abort)**: 控制是否屏蔽非同步中止異常 (Asynchronous Aborts)。更多 Abort 的細節可以參考:[ Arm Programmer's Guide X - Memory Ordering 學習筆記](https://hackmd.io/@uMqav-XESBCsrtZEx_Jpug/Arm_Programmer_Guide_Exception_Handling_Study_Note)。
* **BIT I (IRQ)**: 控制是否屏蔽 IRQ (Interrupt Request) 中斷異常。
* **BIT F (FIQ)**: 控制是否屏蔽 FIQ (Fast Interrupt Request) 中斷異常。
* **BIT T (FIQ)**: 控制核心是否跑在 Thumb 模式。Thumb 模式讓指令長度縮小到 16 bit，能提供更小的尺寸和更高的效能。
* **BIT M (Mode)**: 控制核心跑在哪個模式下 (值可以參考 [2.3 章節](https://hackmd.io/@uMqav-XESBCsrtZEx_Jpug/Arm_Programmer_Guide_Processor_Modes_and_Registers_Study_note#23-%E6%A0%B8%E5%BF%83%E6%A8%A1%E5%BC%8F)表格中的 Encoding 欄位)。

### 3.2.2 APSR

APSR (Application Program Status Register) 是功能受限版本的 CPSR。由 [3.1 通用寄存器](https://hackmd.io/@uMqav-XESBCsrtZEx_Jpug/Arm_Programmer_Guide_Processor_Modes_and_Registers_Study_note#31-%E9%80%9A%E7%94%A8%E5%AF%84%E5%AD%98%E5%99%A8) 最後圖片的左下角可以看出，APSR 就是無特權模式 User mode 所使用的 CPSR。 User mode 只能修改 APSR 旗標 (也就是 BIT NZCVQ) 還有 BIT GE 而已，其他所有的像是 IRQ、FIQ 的屏蔽都是沒有辦法在 User mode 下修改的。

### 3.2.3 SPSR

每一種異常模式 (User 和 SYS 以外的所有模式) 都有一個 SPSR (Saved Program Status Register)，用來記錄前一個模式的 CPSR。舉例來說，若 SYS 模式因為 IRQ 中斷而跳去 IRQ 模式的話，那麼 SPSR_irq 就會等於異常發生前的 CPSR_sys。

# 4. Coprocessor 15

15 號協處理器 CP15 為系統控制協處理器 (System Control coprocessor)，顧名思義是用來提供還多的核心功能控制。表面上它提供了 c0 ~ c15 16 個 32 bit 的寄存器來做設定，但其實同樣的 cN 可以搭配不同的 Opcode ，來達到更多的控制組合。在舉實際例子之前，先了解一下怎麼讀寫協處理器，讀寫的格式如下:
```clike=
    MRC p15, Op1, Rt, CRn, CRm, Op2    // Read a CP15 register into an Arm register
    MCR p15, Op1, Rt, CRn, CRm, Op2    // Write a CP15 register into an Arm register
```
* CRn 為想互動的協處理暫存器「組」。
* Rt 為拿來讀或寫的 Arm 暫存器。
* Op1 和 Op2 用來從 CRn 的暫存器組中選定暫存器。
* CRm 根據協處理器的定義，可以做為額外的附加訊息用。若用不到則設為 c0 就好 (大部分時候都這樣)。 

舉例來說: (可參考 [TTBR0](https://developer.arm.com/documentation/ddi0601/2024-12/AArch32-Registers/TTBR0--Translation-Table-Base-Register-0?lang=en)、[TTBR1](https://developer.arm.com/documentation/ddi0601/2024-12/AArch32-Registers/TTBR1--Translation-Table-Base-Register-1?lang=en) 或[第九章學習筆記的 4.1 First Level Translation Table](https://hackmd.io/@uMqav-XESBCsrtZEx_Jpug/Arm_Programmer_Guide_Memory_Management_Unit_Studying_Note#41-First-Level-Translation-Table))
```clike=
    // Read TTBR0 from CP15 C2, then save it in r0.
    MRC p15, 0, r0, c2, c0, 0 
    
    // Write r1 to CP15 C2's TTBR1
    MCR p15, 0, r1, c2, c0, 1
```

以下為完整的 CP15 C0 ~ C15 資訊:

<table>
    <tr>
        <th>Register</th>
        <th>Description</th>
    </tr>
    <tr>
        <th colspan='2'>CP15 c0</th>
    </tr>
    <tr>
        <td>Main ID Register (MIDR)</td>
        <td>提供核心資訊 (包含 Part number 和 Revision)</td>
    </tr>
    <tr>
        <td>Multiprocessor Affinity Register (MPIDR)</td>
        <td>用來區分同一叢 (Cluster) 中的不同核心 (processor)</td>
    </tr>
    <tr>
        <th colspan='2'>CP15 c2/c3, 記憶體保護和控制寄存器 (參考 <a href="https://hackmd.io/@uMqav-XESBCsrtZEx_Jpug/Arm_Programmer_Guide_Memory_Management_Unit_Studying_Note#41-First-Level-Translation-Table"> MMU 學習筆記</a>)</th>
    </tr>
    <tr>
        <td>Translation Table Base Register 0 (TTBR0)</td>
        <td>Base address of level 1 translation table</td>
    </tr>
    <tr>
        <td>Translation Table Base Register 1 (TTBR1)</td>
        <td>Base address of level 1 translation table</td>
    </tr>
    <tr>
        <td>Translation Table Base Control Register (TTBCR)</td>
        <td>Controls use of TTB0 and TTB1 </td>
    </tr>
    <tr>
        <th colspan='2'>CP15 c5/c6, memory system fault registers (參考 <a href="https://hackmd.io/@uMqav-XESBCsrtZEx_Jpug/Arm_Programmer_Guide_Exception_Handling_Study_Note#71-Abort-Handler"> Exception Handling 學習筆記第 7.1 章</a>)</th>
    </tr>
    <tr>
        <td>Data Fault Status Register (DFSR)</td>
        <td>Gives status information about the last data fault</td>
    </tr>
    <tr>
        <td>Instruction Fault Status Register (IFSR)</td>
        <td>Gives status information about the last instruction fault</td>
    </tr>
    <tr>
        <td>Data Fault Address Register (DFAR)</td>
        <td>Gives the virtual address of the access that caused the most recent precise data abort </td>
    </tr>
    <tr>
        <td>Instruction Fault Address Register (IFAR)</td>
        <td>Gives the virtual address of the access that caused the most recent precise prefetch abort</td>
    </tr>
    <tr>
        <th colspan='2'>CP15 c7, cache maintenance and other functions (參考 <a href="https://hackmd.io/@uMqav-XESBCsrtZEx_Jpug/Arm_Programmer_Guide_Caches_Study_note#10-Invalidating-and-cleaning-cache-memory"> Caches 學習筆記</a>)</th>
    </tr>
    <tr>
        <td>Cache and branch predictor maintenance functions</td>
        <td>控制快取和預讀指令的功能</td>
    </tr>
    <tr>
        <td>Data and instruction barrier operations</td>
        <td>控制記憶體屏障的功能</td>
    </tr>
    <tr>
        <th colspan='2'>CP15 c8, TLB maintenance operations</th>
    </tr>
    <tr>
        <th colspan='2'>CP15 c9, performance monitors</th>
    </tr>
    <tr>
        <th colspan='2'>CP15 c12, Security Extensions registers (參考 <a href="https://hackmd.io/@uMqav-XESBCsrtZEx_Jpug/Arm_Programmer_Guide_Exception_Handling_Study_Note#34-Exception-generating-instructions"> Exception Handling 學習筆記第 3.4 章</a>)</th>
    </tr>
    <tr>
        <td>Vector Base Address Register (VBAR)</td>
        <td>Provides the exception base address for exceptions that are not handled in Monitor mode.</td>
    </tr>
    <tr>
        <td>Monitor Vector Base Address Register (MVBAR)</td>
        <td>Holds the exception base address for all exceptions that are taken to Monitor mode.</td>
    </tr>
    <tr>
        <th colspan='2'>CP15 c13, process, context and thread ID registers</th>
    </tr>
    <tr>
        <td>Context ID Register (CONTEXTIDR)</td>
        <td></td>
    </tr>
    <tr>
        <td>Software thread ID registers</td>
        <td></td>
    </tr>
    <tr>
        <th colspan='2'>CP15 c15, implementation defined registers</th>
    </tr>
    <tr>
        <td>Configuration Base Address Register (CBAR)</td>
        <td>Provides a base address for the GIC and Local timer type peripherals.</td>
    </tr>
</table>

## 4.1 SCTLR (System Control Register)

SCTLR 是 CP15 的 C1 寄存器。在系統控制上扮演重要的角色。以下為其格式:

![image](https://hackmd.io/_uploads/HJpE5AGikx.png)

* **BIT TE (Thumb Exception enable)**: 控制異常 (Exception) 處理是否跑在 Thumb 模式下。
* **BIT NMFI (Non-Maskable FIQ)**: 當 NMFI 被開啟，那麼核心會在每次 Reset 去檢查一根特定的 Input Pin，並確定是否啟用 NMFI，也就是讓 FIQ 無法被屏蔽的功能。
* **BIT EE (Exception Endianness)**: 控制異常處理時的 Endianness。
* **BIT U (Aligment Model)**: 是否支援 Armv6 後引入的新對齊存取模式，也就是 Lagacy 或 ARMv6+ 模式:
    * Lagacy 對齊模式: 資料存取的位址一定要是對齊的，否則雖然不會發生 Data Abort 異常，但會發生不可預期的結果。
    * ARMv6+ 對齊模式: 資料存取的位址可以是未對齊的。
* **BIT A (Aligment Check)**: 如果 BIT A 為 1，則不管 U 的值為多少，未對齊的存取都會造成 Data Abort。
* **BIT FI (FIQ Configuration)**: 只有在 Secure Extension 有被實作的情況下有用。當 BIT FI 為 1，則 FIQ 專屬於 Secure World (也就是 FIQ 的異常處理永遠都在 Secure World 中進行，即使 FIQ 是在 Normal World 中發起)，且也只有 Secure 可以控制 FIQ (Normal World 沒有辦法修改 CPSR.F 來屏蔽 FIQ)。
* **BIT V (Vector table)**: 控制異常向量表 (Exception Vector Table) 的位置。當 BIT V 是 0，異常向量表的位置由特定的暫存器控制 (一般來說是 VBAR, 但 HYP 模式用 HVBAR 、 MON 模式用 MVBAR)；如果 BIT V 是 1，則不再使用 VBAR ，改將 Exception Vector 固定放在 0xFFFF0000 (稱為 HIVECS) 的位置。
* **BIT I (Instruction Cache)**: 控制是否要快取指令。如果 BIT I 為 0，則指令永遠都會跳過快取 (Cache)，直接從主記憶體讀取。
* **BIT Z (Branch Prediction)**: 控制是否要啟用分支預設，也就是讓處理器去預測未來的分支走向，並提前加載指令以提升效率。
* **BIT C (Cache Enable)**: 控制是否要啟用快取。
* **BIT M (MMU Enable)**: 控制是否使用 MMU，若沒有開啟，則沒有辦法使用虛擬體地址。

關於 SCTLR 更完整的內容請見: [SCTLR, System Control Register](https://developer.arm.com/documentation/ddi0601/2024-12/AArch32-Registers/SCTLR--System-Control-Register?lang=en)。

---
    
下一篇: [Arm Programmer's Guide VI - Floating-Point 學習筆記](https://hackmd.io/@uMqav-XESBCsrtZEx_Jpug/Arm_Programmer_Guide_Floating_Point_Study_note)