【嵌入式开发】 ARM 关闭 MMU ( 存储体系 | I/D-Cache | MMU | CP15 寄存器 | C1 控制寄存器 | C7 寄存器 | 关闭 MMU )
- 一. MMU 概念
- 1. ARM 存儲
- (1) ARM 的存儲體系
- (2) Cache 由來
- (3) Cache 定義
- 2. MMU
- (1) 虛擬地址 與 物理地址
- (2) MMU 作用 及 關閉原因
- 1. ARM 存儲
- 二. 關閉 MMU 和 Cache
- 1. 關閉 MMU 和 Cache 的方法簡介
- (1) 關閉方法
- (2) C1 控制寄存器 ( 打開關閉 Cache )
- (3) C7 Cache 操作寄存器 ( 使 Cache 失效 )
- 2. 關閉 MMU 和 Cache 代碼編寫
- 1. 關閉 MMU 和 Cache 的方法簡介
- 三. 關閉 MMU 和 Cache 完整可編譯執行代碼
- 1. 匯編代碼
- 2. 鏈接器腳本
- 3. Makefile 編譯腳本
- 4. 編譯輸出可執行文件
本博客的參考文章及相關資料下載 :
- 1.本博客代碼及參考手冊下載 : https://download.csdn.net/download/han1202012/10455643
一. MMU 概念
1. ARM 存儲
(1) ARM 的存儲體系
ARM 存儲 體系 簡介 : ARM 處理器分為三個等級, 處理器寄存器 -> TCM 存儲器 -> 輔助存儲器, 由上到下, 處理速度依次變慢, 但是存儲空間依次增加 ;
- 1.處理器內部寄存器 : 處理器內部的 通用寄存器 和 狀態字寄存器 等, 這些寄存器 訪問速度很快, 但是數量很少 ;
- 2.TCM 緊耦合存儲器 : Cache, 內存 等存儲器;
3.輔助存儲器 : 開發板上的 NandFlash 達到 1G 大小的數量級別, SD 卡 等存儲 設備; 該類型存儲器 訪問速度最慢, 但是數量最大;
(2) Cache 由來
Cache 的由來 : Cache 用于解決 處理器 與 存儲器 之間 數據傳輸效率低下的問題;
- 1.沒有 Cache 的 情況 : 處理器直接訪問主存儲器, 兩者之間的 處理速度差別巨大, 處理器的訪問效率會被大大的拉低 ;
- 2.有 Cache 的 情況 : Cache 位于 處理器 與 主存儲器 之間, Cache 中存放主存儲器的一些拷貝, 當處理器需要讀取指定內容時, 先到 Cache 中去查看, 如果沒有, 就 直接從主存儲器中讀取, 同時將數據也讀取到 Cache 中, 當處理器下一次在讀取該數據的時候, 就可以直接從 Cache 中獲取該數據;
(3) Cache 定義
Cache 定義 :
- 1.定義 : Cache 是 小容量 高速度 的 存儲器, 其速度 低于 處理器 高于 主存儲器;
- 2.對外透明 : Cache 的功能對外是透明的, 在 Cache 中, 保存哪些數據, 覆蓋哪些數據都是操作系統決定的;
- 3.Cache 功能劃分 : 分為兩類, ① I-Cache 指令 Cache, 用于存放指令; ② D-Cache 數據 Cache, 用于存放數據 ;
- 4.圖示 : 下圖是 S3C6410X.pdf 芯片手冊 1.2 章節 中的 I-Cache 和 D-Cache 的描述, 下圖紅框部分, I/D-Cache 都是 16KB 大小;
2. MMU
(1) 虛擬地址 與 物理地址
虛擬機地址 與 物理地址 :
- 1.虛擬地址概念 : 程序中使用的地址 是 虛擬地址 ;
- 2.物理地址概念 : 存儲器物理存儲單元的實際物理地址 ;
- 3.虛擬地址的優勢 : ① 應用程序可以使用更大的存儲空間, ② 解決不同程序之間的地址沖突問題; 如果沒有虛擬地址, 程序中直接使用物理地址, 那么程序必須使用指定的物理地址, 會產生沖突; 同時程序中使用的存儲空間也被限制 了; 因此程序中直接使用實際的物理地址 是不可行的 ;
- 4.MMU 作用 : MMU 可以 實現 物理地址 到 虛擬地址 之間的轉換 ;
(2) MMU 作用 及 關閉原因
MMU 作用 : 實現 物理地址 到 虛擬地址 的轉換 ;
- 1.MMU 與 Cache 的 位置 : 在 ① ARM 11 之前, 處理器 -> Cache -> MMU -> 存儲器, ② ARM 11 及 ARM 11 之后, 處理器 -> MMU -> Cache -> 存儲器, 訪問 Cache 必須通過 MMU 將虛擬地址映射成物理地址后訪問;
- 2.關閉 MMU 原因 : 使用 MMU 和 Cache 必須經過一系列的配置, 之后才能正確的使用, 在 ARM 初始化 時, 還沒有配置 MMU 和 Cache, 如果不關閉會出現錯誤;
二. 關閉 MMU 和 Cache
參考手冊 : ARM核 手冊 Arm1176jzfs.pdf ( 基于 6410 開發板 ARM 11 )
- 1.手冊對應章節 : 3.2.7 章節 c1, Control Register;
- 2.Arm1176jzfs.pdf手冊下載地址 :https://download.csdn.net/download/han1202012/10412045
1. 關閉 MMU 和 Cache 的方法簡介
(1) 關閉方法
關閉 MMU 和 Cache 簡介 :
- 1.關閉 Cache 和 MMU 步驟 : ① 設置 ICache 和 DCache 失效; ② 關閉 ICache 和 DCache 以及 MMU ;
- 2.操作方法 : MMU 和 Cache 關閉操作都是通過 CP15 協處理器 控制的, ① C1 控制寄存器 控制 Cache 和 MMU 開啟 / 關閉 , ② C7 寄存器 控制 Cache 的的 失效 操作 ;
(2) C1 控制寄存器 ( 打開關閉 Cache )
C1 控制寄存器簡介 :
- 1.文檔位置 : Arm1176jzfs.pdf 第 3.2.7 章節 c1, Control Register ;
- 2.I-Cache ( Instruction Cache ) 控制位 : 第 12 位 控制 I-Cache 的開啟 / 關閉, 設置成 0 即 I-Cache 失效, 設置成 1 即 I-Cache 生效;
- 3.D-Cache ( Data Cache ) 控制位 : 第 2 位 控制 D-Cache 的開啟 / 關閉, 設置成 0 即 I-Cache 失效, 設置成 1 即 I-Cache 生效;
- 4.MMU 控制位 : 第 0 位 控制 MMU 生效 / 失效, 設置成 0 即 MMU 失效, 設置成 1 即 MMU 生效;
(3) C7 Cache 操作寄存器 ( 使 Cache 失效 )
C7 寄存器 簡介 :
- 1.文檔位置 : Arm1176jzfs.pdf 第 3.2.22 章節 c7, Cache operations ;
- 2.使 Cache 失效 的指令 : MCR p15, 0, <Rd>, c7, c7, 0, 這是 文檔 中表格 3-71 Cache 操作 中給出的;
2. 關閉 MMU 和 Cache 代碼編寫
關閉 MMU 和 Cache 代碼編寫 :
- 1.設置標號 : 為本段代碼設置一個標號, 讓程序可以跳轉到該處執行以下代碼, disable_mmu : ;
- 2.設置 I-Cache 和 D-Cache 失效 : 使 兩個 Cache 都失效, 文檔中 Arm1176jzfs.pdf 第 3.2.22 章節 給出的代碼格式為 MCR p15, 0, <Rd>, c7, c7, 0, 其中 Rd 通用寄存器 設置為 R0, 最終代碼為 MCR p15, 0, R0, c7, c7, 0 ;
- 3.關閉 I-Cache 和 D-Cache 及 MMU :
- ① 修改方式 : C1 控制寄存器中的 [0] 位 控制 MMU 開啟/關閉, [2] 位控制 D-Cache 開啟/關閉, [12] 位控制 I-Cache 開啟/關閉; 上述位 設置為 0 關閉, 設置為 1 開啟;
- ② C1 寄存器讀寫方式 : CP15 寄存器不能直接讀取, 需要使用 MRC 來將協處理器中的內容讀取到通用寄存器中, 語法格式為 MRC{cond} P15,<Opcode_1>,<Rd>,<CRn>,<CRm>,<Opcode_2> , 使用 MCR 將 Rd 寄存器中的值傳送到 CP15 協處理器中, 語法格式為 MCR{cond} P15,<Opcode_1>,<Rd>,<CRn>,<CRm>,<Opcode_2> ;
- ③ 位計算 : 關閉 I/D-Cache 和 MMU 需要將 C1 寄存器的 [0](MMU), [2](D-Cache), [12] (I-Cache) 三位 設置為0; 其中 I-Cache 可以關閉, 也可以開啟, 不是必須的; 但是 D-Cache 和 MMU 必須關閉, Bootloader 主要作用是將 Linux 內核下載到內存中, 如果下載的過程中 D-Cache 沒有配置, 可能就將數據下載到了 Cache 中, 這樣就會出現問題, 影響內核運行; 因此這里我們只需要將 第 [0] 位 和 第 [1] 位 設置成 0, 將 MMU 和 D-Cache 關閉, I-Cache 不作設置;
- ④ 讀取 C1 寄存器的值 : 使用 MRC p15, 0, R0, c1, c0, 0 將 c1 寄存器中的值 讀取到 R0 通用寄存器中;
- ⑤ 將指定位設置為 0 : 使用 bic 位清除指令, 將 R0 寄存器中的 第 0, 1, 2 三位 設置成0, 這里 第 1 位選擇性設置, 為了方便計算 順便將 第 1 位 也設置成 0, 代碼為 bic r0, r0, #0x7 ;
- ⑥ 將 R0 寄存器中的值寫回到 C1 寄存器中 : 使用 MRC p15, 0, r0, c1, c0, 0 指令, 將 R0 寄存器中的值 寫回到 C1 寄存器中;
- 4.設置程序跳轉到返回點繼續執行 : 使用 BL 指令跳轉到 disable_mmu 標號處執行, 同時將返回地址存儲到了 LR 寄存器中, 返回時跳轉到 LR 寄存器中的地址執行即可, 使用 mov pc, lr 指令, 執行 lr 中地址指向的位置的代碼;
- 5.代碼示例 :
三. 關閉 MMU 和 Cache 完整可編譯執行代碼
1. 匯編代碼
匯編代碼示例 : Bootloader 流程 : ① 初始化異常向量表 , ② 設置 svc 模式 , ③ 關閉看門狗, ④ 關閉中斷, ⑤ 關閉 MMU ;
@**************************** @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 標號處執行bl disable_watchdog @ 跳轉到 disable_watchdog 標號執行, 關閉看門狗bl disable_interrupt @ 跳轉到 disable_interrupt 標號執行, 關閉中斷bl disable_mmu @ 跳轉到 disable_mmu 標號執行, 關閉 MMU set_svc:mrs r0, cpsr @ 將 CPSR 寄存器中的值 導出到 R0 寄存器中bic r0, r0, #0x1f @ 將 R0 寄存器中的值 與 #0x1f 立即數 進行與操作, 并將結果保存到 R0 寄存器中, 實際是將寄存器的 0 ~ 4 位 置 0orr r0, r0, #0xd3 @ 將 R0 寄存器中的值 與 #0xd3 立即數 進行或操作, 并將結果保存到 R0 寄存器中, 實際是設置 0 ~ 4 位 寄存器值 的處理器工作模式代碼msr cpsr, r0 @ 將 R0 寄存器中的值 保存到 CPSR 寄存器中mov pc, lr @ 返回到 返回點處 繼續執行后面的代碼#define pWTCON 0x7e004000 @ 定義看門狗控制寄存器 地址 ( 6410開發板 ) disable_watchdog: ldr r0, =pWTCON @ 先將控制寄存器地址保存到通用寄存器中mov r1, #0x0 @ 準備一個 0 值, 看門狗控制寄存器都設置為0 , 即看門狗也關閉了str r1, [r0] @ 將 0 值 設置到 看門狗控制寄存器中 mov pc, lr @ 返回到 返回點處 繼續執行后面的代碼disable_interrupt:mvn r1,#0x0 @ 將 0x0 按位取反, 獲取 全 1 的數據, 設置到 R1 寄存器中ldr r0,=0x71200014 @ 設置第一個中斷屏蔽寄存器, 先將 寄存器 地址裝載到 通用寄存器 R0 中 str r1,[r0] @ 再將 全 1 的值設置到 寄存器中, 該寄存器的內存地址已經裝載到了 R0 通用寄存器中ldr r0,=0x71300014 @ 設置第二個中斷屏蔽寄存器, 先將 寄存器 地址裝載到 通用寄存器 R0 中 str r1,[r0] @ 再將 全 1 的值設置到 寄存器中, 該寄存器的內存地址已經裝載到了 R0 通用寄存器中mov pc, lr @ 返回到 返回點處 繼續執行后面的代碼disable_mmu : mcr p15,0,r0,c7,c7,0 @ 設置 I-Cache 和 D-Cache 失效mrc p15,0,r0,c1,c0,0 @ 將 c1 寄存器中的值 讀取到 R0 通用寄存器中bic r0, r0, #0x00000007 @ 使用 bic 位清除指令, 將 R0 寄存器中的 第 0, 1, 2 三位 設置成0, 代表 關閉 MMU 和 D-Cachemcr p15,0,r0,c1,c0,0 @ 將 R0 寄存器中的值寫回到 C1 寄存器中mov pc, lr @ 返回到 返回點處 繼續執行后面的代碼
2. 鏈接器腳本
gboot.lds 鏈接器腳本 代碼解析 :
- 1.指明輸出格式 ( 處理器架構 ) : 使用 OUTPUT_ARCH(架構名稱) 指明輸出格式, 即處理器的架構, 這里是 arm 架構的, OUTPUT_ARCH(arm) ;
- 2.指明輸出程序的入口 : 設置編譯輸出的程序入口位置, 語法為 ENTRY(入口位置), 在上面的 Start.S 中設置的程序入口是 _start, 代碼為 ENTRY(_start) ;
- 3.設置代碼段 : 使用 .text : 設置代碼段;
- 4.設置數據段 : 使用 .data : 設置數據段;
- 5.設置 BSS 段 : 使用 .bss : 設置 BSS 段;
- ( 1 ) 記錄 BSS 段的起始地址 : bss_start = .; ;
- ( 2 ) 記錄 BSS 段的結束地址 : bss_end = .; ;
- 6.對齊 : 每個段都需要設置內存的對齊格式, 使用 . = ALIGN(4); 設置四字節對齊即可;
- 7.代碼示例 :
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 -Tgboot.lds -o gboot.elf $^, 需要使用鏈接器腳本進行連接, ①鏈接工具是 arm-linux-ld 工具, ②使用 -Tgboot.lds 設置鏈接器腳本 是剛寫的 gboot.lds 鏈接器腳本, ③輸出文件是 gboot.elf 這是個中間文件, ④ 依賴文件是 $^ 代表所有的依賴;
- ( 3 ) 轉換成可執行二進制文件 : arm-linux-objcopy -O binary gboot.elf gboot.bin, 使用 -O binary 設置輸出二進制文件, 依賴文件是 gboot.elf, 輸出的可執行二進制文件 即 結果是 gboot.bin ;
- 4.makefile 文件內容 :
4. 編譯輸出可執行文件
編譯過程 :
- 1.文件準備 : 將 匯編代碼 ( start.S ) 鏈接器腳本 ( gboot.lds ) makefile 文件 拷貝到編譯目錄 ;
- 2.執行編譯命令 : make ;
- 3.編譯結果 : 可以看到 生成了 編譯目標文件 start.o, 鏈接文件 gboot.elf, 可執行的二進制文件 gboot.bin ;
本博客的參考文章及相關資料下載 :
- 1.本博客代碼及參考手冊下載 : https://download.csdn.net/download/han1202012/10455643
總結
以上是生活随笔為你收集整理的【嵌入式开发】 ARM 关闭 MMU ( 存储体系 | I/D-Cache | MMU | CP15 寄存器 | C1 控制寄存器 | C7 寄存器 | 关闭 MMU )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【嵌入式开发】ARM 异常向量表 ( 异
- 下一篇: 【嵌入式开发】时钟初始化 ( 时钟相关概