-
- 一. 處理器工作模式相關介紹
-
- 1. 處理器模式簡介
-
- (1) 處理器工作模式分類
- (2) 處理器不同工作模式差別
- (3) Linux 系統運作的模式
- (4) 特權模式 說明
- (5) 異常模式
- (6) 系統模式
- 2. 處理器模式 改變
-
- (1) 處理器工作模式 改變 的前提條件
- (2) 處理器工作模式 修改方式 ( 程式狀态字寄存器 工作模式修改 )
- (3) 程式狀态字寄存器 位 類型
- (4) 程式狀态字寄存器修改流程
- 二. 處理器工作模式修改 代碼示例
-
- 1. 彙編代碼編寫
-
- (1) 代碼 邏輯 分析
- (2) 彙編代碼示例
- 2. 連結器腳本
- 3. Makefile 編譯腳本
- 4. 編譯輸出可執行檔案
本部落格的參考文章及相關資料下載下傳 :
一. 處理器工作模式相關介紹
參考手冊 : A2.2 Processor modes
-
- 1.處理器工作模式位置 : ARM Architecture Reference Manual [ A 2.2 ] 章節;
- 2.參考手冊下載下傳位址 :
1. 處理器模式簡介
(1) 處理器工作模式分類
處理器的 七種 工作模式 :
-
- 1.User ( 使用者模式 usr ) : 普通的應用運作的模式 ;
- 2.FIQ ( 快速中斷模式 fiq ) : 該模式下支援資料的高速傳輸 ;
- 3.IRQ ( 普通中斷模式 irq ) : 該模式常用于處理普通的中斷 ;
- 4.Supervisor ( 管理模式 svc ) : 作業系統使用的一種保護模式 , 本節 BootLoader 就是需要設定這種 svc 模式;
- 5.Abort ( 終止模式 abt ) : 實作虛拟記憶體 和 存儲器保護 ;
- 6.Undefined ( 未定義模式 und ) : 硬體協處理器 的 軟體仿真支援, 當執行的指令處理器不支援, 那麼會進入該模式;
- 7.System ( 系統模式 ) : 該模式用于運作具有特權的作業系統任務, ARMv4 以上的架構才有;
(2) 處理器不同工作模式差別
處理器 工作模式 差別 :
-
- 1.可運作的指令不同 : 不同的處理器工作模式下 可 運作的 處理器指令 是不同的;
- 2.可通路的寄存器不同 : 不同處理器模式下 可通路的 寄存器 也是有差別的;
- 3.分級别處理 : 7 種工作模式級别不同, 作業系統 一般在級别較高的模式下運作, 應用程式在級别較低的模式下運作;
- 4.使用者模式說明 :
-
- ( 1 ) 應用運作 : 絕大多數 應用程式都運作在使用者模式 ( User ) 下;
- ( 2 ) 資源限制 : 在 ① 使用者模式下, 應用無法通路受保護的系統資源 , ② 系統資源的使用 是在作業系統的控制下;
- ( 3 ) 無法修改模式 : 在 使用者模式 下, 應用也無法修改 處理器 的工作模式 ;
-
-
(3) Linux 系統運作的模式
Linux 作業系統運作模式 :
-
- 1.應用程式 : Linux 系統的應用程式運作在 User 使用者模式下;
- 2.核心 : Linux 系統 核心 運作在 Supervisor 管理模式下 ;
(4) 特權模式 說明
特權模式 :
-
- 1.特權概念 : 除 使用者模式 外, 其它的 6 種模式 都是特權模式 ;
- 2.特權模式 的 功能 : 特權模式 比 使用者模式 擁有更大的權限, 可 ① 通路系統資源, ② 修改處理器工作模式 ;
-
- ( 1 ) 資源通路 : 特權模式 擁有通路系統資源的權限 ;
- ( 2 ) 模式修改 : 特權模式 下 可以 修改 處理器的工作模式 ;
-
- 3.五種異常模式 : 在 6 種 特權模式中, 有 5 種 是 異常模式 , 當對應的異常發生的時候, 就會進入對應的工作模式 ;
- 4.異常模式寄存器 : 每種異常模式都有一些附加的寄存器, 當異常發生的時候, 避免影響使用者模式的狀态;
(5) 異常模式
五種 處理器工作模式 ( 異常模式 ) 對應的異常類型 :
-
- 1.FIQ ( 快速中斷模式 fiq ) : 該模式下支援資料的高速傳輸 , 對應異常類型 為 快速中斷 異常;
- 2.IRQ ( 普通中斷模式 irq ) : 該模式常用于處理普通的中斷 , 對應異常類型 為 普通中斷 異常 ;
- 3.Supervisor ( 管理模式 svc ) : 作業系統使用的一種保護模式 , 本節 BootLoader 就是需要設定這種 svc 模式, 對應異常類型 為 Reset 和 軟中斷 異常 ;
- 4.Abort ( 終止模式 abt ) : 實作虛拟記憶體 和 存儲器保護 , 對應異常類型 為 預取指令失敗 和 讀取資料失敗 異常 ;
- 5.Undefined ( 未定義模式 und ) : 硬體協處理器 的 軟體仿真支援, 當執行的指令處理器不支援, 那麼會進入該模式, 對應異常類型 為 無法識别指令 異常;
七種 異常類型 對應的 處理器工作模式 : ARM 架構 支援 七種類型的異常,
-
- 1.Reset : 處理器在工作時, 突然 按下重新開機鍵, 就會觸發該異常 , 該異常對應的處理器工作模式為 svc 模式;
- 2.Undefined instructions : 處理器無法識别指令的異常, 處理器執行的指令是有規範的, 如果 嘗試執行 不符合要求的指令, 就會進入到該異常指令對應的位址中, 該異常對應的處理器工作模式為 und 模式;
- 3.Software interrupt (SWI) : 軟中斷, 軟體中需要去打斷處理器工作, 可以使用軟中斷來執行 , 該異常對應的處理器工作模式為 svc 模式;
- 4.Prefetch Abort (instruction fetch memory abort) : 預取指令失敗, ARM 在執行指令的過程中, 要先去預取指令準備執行, 如果預取指令失敗, 就會産生該異常, 該異常對應的處理器工作模式為 abt 模式;
- 5.Data Abort (data access memory abort) : 讀取資料失敗, 該異常對應的處理器工作模式為 abt 模式;
- 6.IRQ (interrupt) : 普通中斷 , 該異常對應的處理器工作模式為 irq 模式;
- 7.FIQ (fast interrupt) : 快速中斷, 快速中斷要比普通中斷響應速度要快一些, 該異常對應的處理器工作模式為 fiq 模式;
(6) 系統模式
系統模式 :
-
- 1.進入方式 : 任何異常都無法進入 系統 模式 ;
- 2.寄存器 : 從下面的寄存器截圖可以看出, 系統模式 可 使用的 寄存器, 與 使用者模式 可通路的寄存器 是一樣的;
- 3.擁有特權 : 系統模式也是一種特權模式, 不受使用者模式限制影響,
- 4.模式存在的目的 : 系統模式 主要 服務于 需要通路系統資源的 作業系統任務, 避免使用 與 異常相關的附加寄存器;
- ( 1 ) 避免被異常幹擾 : 主要是為了 保證 任務狀态, 避免 被 發生的異常 幹擾 ;
-
2. 處理器模式 改變
(1) 處理器工作模式 改變 的前提條件
修改 處理器 工作模式 的 前提條件 :
-
- 1.軟體控制 : 在 軟體控制下, 可以修改處理器的工作模式 ;
- 2.外部中斷 : 外部中斷也會改變處理器的工作模式;
- 3.異常處理 : 當異常發生的時候, 也會修改處理器的工作模式 ;
- 4.BootLoader 工作模式 : BootLoader 工作在 svc 模式 下, 該模式比較進階, 可以 通路較多的寄存器資源 , 執行更多的處理器指令 ;
- 5.如何修改工作模式 : 修改 程式狀态 寄存器 ( CPSR ) 中的 0 ~ 4 位 即可改變處理器工作模式;
- 6.修改CPSR值 : 修改的 程式狀态寄存器 0 ~ 4 位的值 為, 下面表中的 模式代碼. 即 每行 第三列的 二進制碼 ;
- 7.處理器工作模式 對應的 M 位 ( CPRS 0 : 4 ) 值 以及其對應的 可使用的寄存器 :
(2) 處理器工作模式 修改方式 ( 程式狀态字寄存器 工作模式修改 )
參考手冊 : A2.5 Program status registers
-
- 1.處理器工作模式位置 : ARM Architecture Reference Manual [ A 2.5 ] 章節;
- 2.參考手冊下載下傳位址
程式狀态字寄存器 :
-
- 1.寄存器内容 : 該寄存器 中 包含 ① 狀态碼标志位, ② 中斷标志位, ③ 目前處理器工作模式 和 其它一些 ④ 狀态 與 ⑤ 控制資訊 ;
- 2.CPSR 寄存器 : 全稱 Current Program Status Register ( 目前程式狀态字寄存器 ), 儲存的是目前的程式狀态 ;
- 3.SPSR 寄存器 : 全稱 Saved Program Status Register ( 程式狀态儲存寄存器 ), 每個異常都有對應的獨立的 SPSR 寄存器, 當異常發生的時候, 先将 CPSR 寄存器中的值 儲存到 SPSR 寄存器中, 以便 異常處理完畢後 再回到原來斷點處 繼續運作 ;
- 4.SPSR 寄存器分布 : 使用者模式 和 系統模式 沒有 對應的 SPSR 寄存器, 隻有 5 種 異常模式才有對應的 SPSR 寄存器 ;
- ( 1 ) SPSR 寄存器讀寫 : 在 使用者模式 或 系統模式 讀寫 SPSR 指令 會出現不可預測的錯誤或行為 ;
-
(3) 程式狀态字寄存器 位 類型
參考手冊 : A2.5 Program status registers
-
- 1.處理器工作模式位置 : ARM Architecture Reference Manual [ A 2.5 ] 章節;
- 2.參考手冊下載下傳位址
程式狀态字寄存器 位 類型簡介 :
-
- 1.特權位 : 在 特權模式 下可進行修改 的 位數, 使用者模式下不能修改特權位, 如 A, I , F, 和 M ( 0 :4 ) 位;
- 2.使用者可寫位 : 任何模式都可以修改的 資料位, 如 N, Z, C, V, Q, GE[ 3 : 0 ], E 資料位;
- 3.執行狀态位 : 可以從 任何特權模式修改, 使用者模式不能修改 ; J 和 T 兩位 是運作狀态位, 在 ARM 狀态下總是 0 ;
-
- ( 1 ) CPSR 運作狀态位 : 使用 MSR 特權指令 将通用寄存器的值 儲存到 CPSR 中, J 和 T 兩位必須設定為 0 , 否則會出現不可預知錯誤;
- ( 2 ) SPSR 運作狀态位 : 在 上面 的 限制中, 隻針對 CPSR 寄存器, SPSR 沒有這個限制,
-
- 4.保留位 : 為之後的功能擴充保留的位數 ;
-
- ( 1 ) 讀取 : 保留位 讀取時 都當做 0 值;
- ( 2 ) 寫入 : 不能向 保留位 寫出實際資料 ;
-
-
(4) 程式狀态字寄存器修改流程
參考手冊 : arm彙編手冊(中文版).chm
-
- 1.本節使用的彙編指令 : BIC, ORR, MSR, MRS;
- 2.arm彙編手冊下載下傳位址
修改程式狀态字寄存器 使用到的彙編指令 :
-
- 1.将處理器工作模式位 設定 0 : 将 CPRS 程式狀态字 寄存器 中的 0 ~ 4 位 設定為 0 , 注意 CPRS 不能直接操作 ; 使用 BIC 指令進行設定;
-
- ( 1 ) BIC 彙編指令 文法 : bic 文法格式
, dest 存放位清除結果, op1 是被清除的對象, op2 是掩碼;bic <dest>, <op1>, <op2>
- ( 2 ) BIC 指令 示例 :
, 清除 r0 中的 第0, 1, 3 位, 其餘位保持不變, 結果放入 r0 中;bic r0, r0, #0b1011
- ( 3 ) 使用注意點 : dest op1 都不能使用立即數, 必須使用寄存器, op2 可以使用立即數;
- ( 4 ) 立即數進制 : 此處的的立即數必須使用二進制形式 ;
-
- 2.為 處理器工作模式位 設定 1 : 将 CPRS 程式狀态字 寄存器 中的 0 ~ 4 位 設定為 指定的二進制數字 , 注意 CPRS 不能直接操作 ; 使用 orr 指令 進行設定 ;
-
- ( 1 ) ORR 彙編指令 文法 :
, dest 結果是 op 1 與 op 2 進行或運算的結果;ORR{條件}{S} <dest>, <op 1>, <op 2>
- ( 2 ) ORR 指令 說明 : dest 必須是寄存器, 操作數 1 ( op 1 ) 必須是寄存器, 操作數 2 ( op 2 ) 可以是 ① 寄存器 ② 被移位寄存器 ③ 立即數;
- ( 3 ) ORR 示例 :
, 将 立即數 3 與 R0 寄存器中的值 進行 或 運算, 然後将運算結果存放到 R0 中;ORR R0, R0, #3
-
- 3.程式狀态字寄存器 ( CPSR 和 SPSR ) 通路指令 : 使用 MRS MSR 指令, 程式狀态字 不能使用 通用寄存器的語句 如 MOV 等通路, 必須使用 程式狀态寄存器的 專用指令 讀寫;
-
- ( 1 ) 程式狀态字寄存器 通路 流程 : 程式狀态字寄存器不能直接通路, 需要先将程式狀态字寄存器内容導出到通用寄存器中, 才能進行操作 , 不能直接修改 CPSR 和 SPSR 中的值 ;
- ( 2 ) MRS 指令 :
, 将 CPRS 寄存器的值 複制 到 R0 寄存器中;MRS R0, CPSR
- ( 3 ) MSR 指令 :
, 将 R0 寄存器中的值 設定 到 CPSR 寄存器中 ;MSR CPSR, R0
-
- 4.流程總結 :
-
- ( 1 ) 導出 CPSR 寄存器值 : 使用 MRS 将 CPSR 寄存器的值導出到通用寄存器中 ;
- ( 2 ) 将工作模式位置 0 : 将導出的 CPSR 寄存器的值的 0 ~ 4 位 設定為 0 ;
- ( 3 ) 将工作模式位置 1 : 将導出的 CPSR 寄存器的值的 0 ~ 4 位 設定 對應 的 模式代碼 ;
- ( 4 ) 将設定好的 CPSR 寄存器值設定到 寄存器中 : 使用 MSR 指令, 将 在通用寄存器中 設定好的 CPSR 寄存器值 設定回 CPSR 寄存器中 ;
-
-
二. 處理器工作模式修改 代碼示例
1. 彙編代碼編寫
(1) 代碼 邏輯 分析
代碼 邏輯 分析 :
-
- 1.設定 處理器工作模式 時機 : 進行 處理器工作模式 設定 是在 開發闆上電後, 對應的 reset 異常向量處;
- 2.設定 指令标号 : 設定一個指令标号, 在标号下定義一組彙編指令, 當需要執行這一組指令的時候, 在跳轉到該标号即可;
- ( 1 ) 定義标号 :
, 在标号下定義一組彙編指令;set_svc :
- ( 1 ) 定義标号 :
- 3.導出 CPSR 寄存器值 : 使用 MRS 指令, 即
将 CPSR 寄存器中的值導出到 R0 寄存器中;mrs r0 cpsr
- 4.将 R0 中的 M 位 清 0 : 在 R0 中将從 CPSR 中導出的寄存器值 對應的 0 ~ 4 位 清0, 使用
, 将 R0 寄存器的值 與 #0x1f 進行 與操作, 即 後5 位都設定成0, 然後将 與 操作的結果儲存到 R0 寄存器中 ;bic r0, r0, #0x1f
- 5.将 R0 中的 M 位 設定 模式代碼 : 在下圖中, svc 的模式代碼時 0b10011 ( 二進制 ), 即 0x13 ( 十六進制 ), 使用
語句設定, 将 R0 寄存器中的值 與 0x13 進行 或操作, 将 或操作的結果 存放到 R0 寄存器中;orr r0, r0, #0xd3
- 6.将值寫回 CPSR 寄存器 : 使用 MSR 指令
, 将處理完的 CPSR 寄存器值 設定給 CPSR 寄存器;msr cpsr, r0
(2) 彙編代碼示例
彙編代碼示例 :
@****************************
@File:start.S
@
@BootLoader 初始化代碼
@****************************
.text @ 宏 指明代碼段
.global _start @ 僞指令聲明全局開始符号
_start: @ 程式入口标志
b reset @ reset 複位異常
ldr pc, _undefined_instruction @ 未定義異常, 将 _undefined_instruction 值裝載到 pc 指針中
ldr pc, _software_interrupt @ 軟中斷異常
ldr pc, _prefetch_abort @ 預取指令異常
ldr pc, _data_abort @ 資料讀取異常
ldr pc, _not_used @ 占用 0x00000014 位址
ldr pc, _irq @ 普通中斷異常
ldr pc, _fiq @ 軟中斷異常
_undefined_instruction: .word undefined_instruction @ _undefined_instruction 标号存放了一個值, 該值是 32 位位址 undefined_instruction, undefined_instruction 是一個位址
_software_interrupt: .word software_interrupt @ 軟中斷異常
_prefetch_abort: .word prefetch_abort @ 預取指令異常 處理
_data_abort: .word data_abort @ 資料讀取異常
_not_used: .word not_used @ 空位處理
_irq: .word irq @ 普通中斷處理
_fiq: .word fiq @ 快速中斷處理
undefined_instruction: @ undefined_instruction 位址存放要執行的内容
nop
software_interrupt: @ software_interrupt 位址存放要執行的内容
nop
prefetch_abort: @ prefetch_abort 位址存放要執行的内容
nop
data_abort: @ data_abort 位址存放要執行的内容
nop
not_used: @ not_used 位址存放要執行的内容
nop
irq: @ irq 位址存放要執行的内容
nop
fiq: @ fiq 位址存放要執行的内容
nop
reset: @ reset 位址存放要執行的内容
bl set_svc @ 跳轉到 set_svc 标号處執行
set_svc:
mrs r0, cpsr @ 将 CPSR 寄存器中的值 導出到 R0 寄存器中
bic r0, r0, #0x1f @ 将 R0 寄存器中的值 與 #0x1f 立即數 進行與操作, 并将結果儲存到 R0 寄存器中, 實際是将寄存器的 0 ~ 4 位 置 0
orr r0, r0, #0xd3 @ 将 R0 寄存器中的值 與 #0xd3 立即數 進行或操作, 并将結果儲存到 R0 寄存器中, 實際是設定 0 ~ 4 位 寄存器值 的處理器工作模式代碼
msr cpsr, r0 @ 将 R0 寄存器中的值 儲存到 CPSR 寄存器中
2. 連結器腳本
gboot.lds 連結器腳本 代碼解析 :
-
- 1.指明輸出格式 ( 處理器架構 ) : 使用
指明輸出格式, 即處理器的架構, 這裡是 arm 架構的, OUTPUT_ARCH(架構名稱)
;OUTPUT_ARCH(arm)
- 2.指明輸出程式的入口 : 設定編譯輸出的程式入口位置, 文法為
, 在上面的 Start.S 中設定的程式入口是 ENTRY(入口位置)
, 代碼為 _start
;ENTRY(_start)
- 3.設定代碼段 : 使用
設定代碼段;.text :
- 4.設定資料段 : 使用
設定資料段;.data :
- 5.設定 BSS 段 : 使用
設定 BSS 段;.bss :
-
- ( 1 ) 記錄 BSS 段的起始位址 :
;bss_start = .;
- ( 2 ) 記錄 BSS 段的結束位址 :
;bss_end = .;
-
- 6.對齊 : 每個段都需要設定記憶體的對齊格式, 使用
設定四位元組對齊即可;. = ALIGN(4);
- 7.代碼示例 :
OUTPUT_ARCH(arm) /*指明處理器結構*/
ENTRY(_start) /*指明程式入口 在 _start 标号處*/
SECTIONS {
. = 0x50008000; /*整個程式連結的起始位置, 根據開發闆确定, 不同開發闆位址不一緻*/
. = ALIGN(4); /*對齊處理, 每段開始之前進行 4 位元組對齊*/
.text : /*代碼段*/
{
start.o (.text) /*start.S 轉化來的代碼段*/
*(.text) /*其它代碼段*/
}
. = ALIGN(4); /*對齊處理, 每段開始之前進行 4 位元組對齊*/
.data : /*資料段*/
{
*(.data)
}
. = ALIGN(4); /*對齊處理, 每段開始之前進行 4 位元組對齊*/
bss_start = .; /*記錄 bss 段起始位置*/
.bss : /*bss 段*/
{
*(.bss)
}
bss_end = .; /*記錄 bss 段結束位置*/
}
3. Makefile 編譯腳本
makefile 檔案編寫 :
-
- 1.通用規則 ( 彙編檔案編譯規則 ) : 彙編檔案 編譯 成同名的 .o 檔案, 檔案名稱相同, 字尾不同,
, 産生過程是 %.o : %.S
, 其中 arm-linux-gcc -g -c $^
辨別是所有的依賴檔案, 在該規則下 start.S 會被變異成 start.o ;^
- 2.通用規則 ( C 檔案編譯規則 ) : C 代碼編譯成同名的 .o 檔案,
, 産生過程是 %.o : %.c
;arm-linux-gcc -g -c $^
- 3.設定最終目标 : 使用
設定最終編譯目标;all:
-
- ( 1 ) 依賴檔案 : 産生最終目标需要依賴 start.o 檔案, 使用
表示最終目标需要依賴該檔案;all: start.o
- ( 2 ) 連結過程 :
, 需要使用連結器腳本進行連接配接, ①連結工具是 arm-linux-ld 工具, ②使用 arm-linux-ld -Tgboot.lds -o gboot.elf $^
設定連結器腳本 是剛寫的 gboot.lds 連結器腳本, ③輸出檔案是 gboot.elf 這是個中間檔案, ④ 依賴檔案是 -Tgboot.lds
代表所有的依賴;$^
- ( 3 ) 轉換成可執行二進制檔案 :
, 使用 arm-linux-objcopy -O binary gboot.elf gboot.bin
設定輸出二進制檔案, 依賴檔案是 -O binary
, 輸出的可執行二進制檔案 即 結果是 gboot.elf
;gboot.bin
-
- 4.makefile 檔案内容 :
all: start.o #依賴于 start.o
arm-linux-ld -Tgboot.lds -o gboot.elf $^ #使用連結器腳本, 将 start.o 轉為 gboot.elf
arm-linux-objcopy -O binary gboot.elf gboot.bin #将 gboot.elf 轉化為可以直接在闆子上執行的 gboot.bin 檔案
%.o : %.S #通用規則, 如 start.o 是由 start.S 編譯來的, -c 是隻編譯不連結
arm-linux-gcc -g -c $^
%.o : %.c #通用規則, 如 start.o 是由 start.c 編譯來的, -c 是隻編譯不連結
arm-linux-gcc -g -c $^
.PHONY: clean
clean: #清除編譯資訊
rm *.o *.elf *.bin
4. 編譯輸出可執行檔案
編譯過程 :
-
- 1.檔案準備 : 将 彙編代碼 ( start.S ) 連結器腳本 ( gboot.lds ) makefile 檔案 拷貝到編譯目錄 ;
- 2.執行編譯指令 :
;make
- 3.編譯結果 : 可以看到 生成了 編譯目标檔案 start.o, 連結檔案 gboot.elf, 可執行的二進制檔案 gboot.bin ;