ARM內核與寄存器詳解
目錄
- ARM架構概述
- ARM處理器模式
- Cortex-M3內核的處理器模式
- Cortex-A系列處理器模式
- ARM寄存器集
- 通用寄存器
- 程序計數器(PC)
- 鏈接寄存器(LR)
- 堆棧指針(SP)
- 狀態寄存器(CPSR/SPSR)
- 協處理器寄存器
- NEON和VFP寄存器
- 寄存器使用規范
- 常見ARM指令與寄存器操作
ARM架構概述
ARM(Advanced RISC Microprocessor)是一種RISC(精簡指令集計算機)處理器架構,最初由Acorn計算機公司設計,現在由ARM公司開發和授權。由于其低功耗和高性能特性,ARM處理器廣泛應用于移動設備、嵌入式系統和物聯網設備。
ARM架構已經發展了多個版本,從ARMv1到最新的ARMv9,不同版本引入了不同的功能和改進。主要的架構系列包括:
- Cortex-A系列:應用處理器,用于高性能系統
- Cortex-R系列:實時處理器,用于需要快速響應的系統
- Cortex-M系列:微控制器,用于低功耗嵌入式設備
ARM處理器模式
ARM處理器有多種操作模式,每種模式有不同的寄存器可見性和權限級別:
模式 | 描述 | 進入方式 |
---|---|---|
用戶模式 | 普通程序執行 | 程序正常運行 |
系統模式 | 特權操作系統任務 | 軟件切換 |
管理模式 | 系統保護模式 | 軟件中斷 |
中止模式 | 處理內存訪問違例 | 數據或指令預取中止 |
未定義模式 | 處理未定義指令 | 遇到未定義指令 |
快速中斷模式 | 高優先級中斷處理 | FIQ中斷 |
中斷模式 | 中斷處理 | IRQ中斷 |
Cortex-M3內核的處理器模式
注意:Cortex-M3內核采用了簡化的處理器模式系統,與傳統ARM架構不同。Cortex-M3主要有兩種運行模式:
- 線程模式(Thread Mode) - 用于運行應用程序代碼
- 處理器模式(Handler Mode) - 用于處理所有異常
Cortex-M3還引入了特權級別的概念:
- 特權訪問 - 可訪問所有系統資源
- 非特權訪問 - 受限制的資源訪問
以下是Cortex-M3中不同情況的模式對應關系:
傳統ARM模式 | Cortex-M3對應情況 | 實際例子 |
---|---|---|
用戶模式 | 線程模式(非特權) | 運行普通應用程序代碼,如循環計算任務 |
系統模式 | 線程模式(特權) | 操作系統執行特權操作,如初始化外設、配置MPU |
管理模式 | 通過SVC異常進入Handler模式 | 應用程序調用SVC 指令請求操作系統服務,如SVC #0 切換任務 |
中止模式 | MemManage異常進入Handler模式 | 程序訪問MPU禁止的內存區域;設置了只讀區域但嘗試寫入 |
未定義模式 | UsageFault異常進入Handler模式 | 執行了未支持的浮點指令;除零操作;未對齊的內存訪問 |
快速中斷模式 | 沒有直接對應,所有中斷進入Handler模式 | EXTI外部中斷;高優先級的ADC轉換完成中斷 |
中斷模式 | 沒有直接對應,所有中斷進入Handler模式 | UART接收完成中斷;SysTick系統定時器中斷 |
Cortex-M3異常處理示例:
-
硬故障(HardFault)例子:
- 程序嘗試執行未映射內存區域的代碼
- 訪問了未對齊的內存地址
- 在中斷處理過程中出現嵌套錯誤
-
SVC(管理模式)例子:
// 通過SVC調用請求操作系統服務 __asm("SVC #42"); // 調用42號系統服務,例如RTOS切換任務
-
BusFault例子:
// 訪問無效的外設地址 volatile uint32_t *ptr = (uint32_t *)0x60000000; // 假設這是無效總線地址 *ptr = 0x1234; // 觸發BusFault異常
-
使用故障例子:
// 未對齊的訪問(如果啟用了對齊檢查) volatile uint32_t *ptr = (uint32_t *)0x20000001; // 非4字節對齊地址 *ptr = 0x1234; // 觸發UsageFault異常
Cortex-A系列處理器模式
Cortex-A系列處理器保留了傳統ARM架構的7種處理器模式,并增加了安全擴展和虛擬化擴展模式。以下是Cortex-A核在不同情況下的模式例子:
模式 | Cortex-A對應情況 | 實際例子 |
---|---|---|
用戶模式 | 低特權應用程序 | 手機上運行的普通APP;Linux用戶空間程序 |
系統模式 | 高特權操作系統代碼 | 操作系統內核執行特權任務;驅動程序操作硬件 |
管理模式 | 系統調用處理 | 應用程序通過SWI /SVC 請求系統服務;Android的Binder調用 |
中止模式 | 內存訪問違例處理 | 程序訪問受MMU保護的內存區域;Linux中的段錯誤(SIGSEGV) |
未定義模式 | 處理未識別指令 | 程序執行平臺不支持的指令;嘗試執行NEON指令但硬件不支持 |
快速中斷模式 | 高優先級外設中斷 | DMA傳輸完成;高速存儲器控制器中斷;顯示刷新中斷 |
中斷模式 | 普通外設中斷處理 | 觸摸屏輸入;按鍵中斷;傳感器數據就緒中斷 |
監視模式 | TrustZone安全世界 | 安全認證;指紋處理;支付系統隔離 |
虛擬機模式 | 虛擬化支持(ARMv7-A) | 虛擬機管理程序;Docker容器環境切換 |
Cortex-A與Cortex-M主要區別:
-
處理器模式實現:
- Cortex-A: 完整的7種模式+擴展模式,通過CPSR控制
- Cortex-M: 簡化為線程模式和處理器模式兩種,通過異常入口管理
-
特權級別:
- Cortex-A: 通過處理器模式區分特權
- Cortex-M: 明確的特權/非特權狀態區分
-
異常處理:
- Cortex-A: 使用向量表+模式切換
- Cortex-M: 統一的異常機制,自動保存/恢復上下文
Cortex-A異常處理示例:
// Cortex-A中的異常向量表設置
// 通常在匯編啟動文件中定義
void vectors(void) __attribute__((section("vectors")));
void vectors(void) {asm("b reset_handler"); // 復位處理asm("b undefined_handler"); // 未定義指令asm("b svc_handler"); // 軟件中斷(SVC)asm("b prefetch_handler"); // 取指中止asm("b data_handler"); // 數據中止asm("b unused_handler"); // 未使用asm("b irq_handler"); // 中斷asm("b fiq_handler"); // 快速中斷
}// SVC示例 - Linux系統調用
int main() {int result;// 調用write系統調用(4號)asm("mov r0, #1"); // 文件描述符1(stdout)asm("ldr r1, =message"); // 消息緩沖區asm("mov r2, #13"); // 消息長度asm("mov r7, #4"); // write系統調用號asm("swi #0"); // 執行系統調用asm("mov %0, r0" : "=r" (result));return 0;
}
ARM寄存器集
通用寄存器
ARM架構提供16個32位通用寄存器(R0-R15),其中R13-R15有特殊用途:
寄存器 | 別名 | 描述 | 使用約定 |
---|---|---|---|
R0 | - | 通用寄存器 | 第一個函數參數,函數返回值 |
R1-R3 | - | 通用寄存器 | 函數參數 |
R4-R11 | - | 通用寄存器 | 需在函數調用間保存 |
R12 | IP | 程序內部暫存寄存器 | 過程調用中臨時使用 |
R13 | SP | 堆棧指針 | 指向當前堆棧頂部 |
R14 | LR | 鏈接寄存器 | 保存子程序返回地址 |
R15 | PC | 程序計數器 | 指向當前執行指令 |
程序計數器(PC)
PC寄存器(R15)保存當前執行指令的地址。在ARM狀態下,PC指向當前指令地址+8;在Thumb狀態下,PC指向當前指令地址+4。
使用方法:
- 讀取PC獲得當前指令附近的地址
- 向PC寫入值實現跳轉
MOV R0, PC @ 獲取當前PC值
MOV PC, LR @ 從子程序返回
鏈接寄存器(LR)
LR寄存器(R14)用于存儲子程序返回地址。當執行BL(分支并鏈接)指令時,返回地址被自動保存到LR中。
使用方法:
- 調用子程序前保存LR(如果子程序內還會調用其他函數)
- 子程序返回時將LR的值復制到PC
PUSH {LR} @ 保存返回地址
BL subroutine @ 調用子程序
POP {PC} @ 恢復返回地址并返回
堆棧指針(SP)
SP寄存器(R13)指向當前堆棧頂部。ARM通常采用滿遞減(Full Descending)堆棧,即SP指向最后一個已入棧的數據項。
使用方法:
- PUSH操作前先減少SP,再存儲
- POP操作先加載,再增加SP
PUSH {R0-R3} @ 將R0-R3壓入堆棧
POP {R0-R3} @ 從堆棧彈出到R0-R3
狀態寄存器(CPSR/SPSR)
當前程序狀態寄存器(CPSR)和保存的程序狀態寄存器(SPSR)包含處理器狀態信息。
CPSR字段:
- 條件標志(N,Z,C,V):用于條件執行
- 控制位:處理器模式、中斷禁用標志、指令集狀態等
條件標志:
- N(負數):結果為負
- Z(零):結果為零
- C(進位):產生進位
- V(溢出):有符號溢出
CMP R0, R1 @ 比較R0和R1,設置條件標志
ADDPL R0, R0, #1 @ 如果結果非負(N=0)則執行加法
協處理器寄存器
ARM架構支持協處理器擴展,包括CP15系統控制協處理器。CP15寄存器控制緩存、MMU、系統控制和配置。
訪問方法:
MRC p15, 0, R0, c1, c0, 0 @ 讀取CP15 c1寄存器到R0
MCR p15, 0, R0, c1, c0, 0 @ 寫入R0到CP15 c1寄存器
NEON和VFP寄存器
現代ARM架構包含NEON和VFP(向量浮點)擴展,提供額外的寄存器用于SIMD和浮點運算:
- 32個64位寄存器(D0-D31)
- 也可視為16個128位寄存器(Q0-Q15)
VMOV.F32 S0, #1.0 @ 加載浮點常量到S0
VADD.F32 S0, S0, S1 @ 浮點加法
VLDM R0, {D0-D3} @ 加載多個64位寄存器
寄存器使用規范
ARM架構定義了AAPCS(ARM架構過程調用標準)規范:
- R0-R3:參數傳遞和結果返回,調用者保存
- R4-R11:局部變量,被調用者保存
- R12(IP):內部過程調用暫存,調用者保存
- R13(SP):堆棧指針,被調用者保存
- R14(LR):鏈接寄存器,被調用者保存
- R15(PC):程序計數器
參數傳遞機制
當函數參數超過4個時,ARM采用以下策略:
- 前4個參數通過R0-R3寄存器傳遞
- 額外的參數通過棧傳遞,從右到左入棧
- 參數在棧上按照4字節對齊
- 被調用者負責從棧上獲取額外參數
示例:調用有6個參數的函數func(a, b, c, d, e, f)
MOV R0, #1 @ 第一個參數 a
MOV R1, #2 @ 第二個參數 b
MOV R2, #3 @ 第三個參數 c
MOV R3, #4 @ 第四個參數 d
PUSH {R5, R6} @ 將第五和第六個參數入棧 (f先入棧,e后入棧)
MOV R5, #6 @ 第六個參數 f (先入棧)
MOV R6, #5 @ 第五個參數 e (后入棧)
PUSH {R5, R6}
BL func @ 調用函數
ADD SP, SP, #8 @ 調用完成后恢復棧(清理參數)
對于返回值:
- 32位或更小的返回值保存在R0中
- 64位返回值使用R0和R1
- 更大的結構體通過引用返回,調用者提供內存地址作為隱式第一個參數
常見ARM指令與寄存器操作
數據處理指令:
MOV R0, R1 @ R0 = R1
ADD R0, R1, R2 @ R0 = R1 + R2
SUB R0, R1, #1 @ R0 = R1 - 1
AND R0, R1, #0xFF @ R0 = R1 & 0xFF
內存訪問指令:
LDR R0, [R1] @ 從R1指向的地址加載到R0
STR R0, [R1, #4] @ 存儲R0到R1+4指向的地址
LDMIA R1!, {R0-R4} @ 多寄存器加載,遞增后更新R1
STMDB R13!, {R0-R3} @ 多寄存器存儲,遞減前更新R13
分支指令:
B label @ 無條件分支
BL function @ 分支并鏈接(調用子程序)
BX LR @ 分支并切換狀態(常用于返回)
CMP R0, #0 @ 比較R0與0
BEQ zero_label @ 相等時分支
條件執行:
ADDEQ R0, R0, R1 @ 當Z=1時執行加法
MOVNE R0, #0 @ 當Z=0時執行賦值