ARM64 體系結構編程與實踐

奔跑吧Linux社區

  • ARM64 體系結構編程與實踐-preview-1
  • ARM64 體系結構編程與實踐-preview-2
ARM64 體系結構編程與實踐-preview-1

買這商品的人也買了...

商品描述

本書旨在詳細介紹ARM64體系結構的相關技術。本書首先介紹了ARM64體系結構的基礎知識、搭建樹莓派實驗環境的方法,然後講述了ARM64指令集中的加載與存儲指令、算術與移位指令、比較與跳轉等指令以及ARM64指令集中的陷阱,接著討論了GNU匯編器、鏈接器、鏈接腳本、GCC內嵌匯編代碼、異常處理、中斷處理、GIC-V2,最後剖析了內存管理、高速緩存、緩存一致性、TLB管理、內存屏障指令、原子操作、操作系統等內容。

本書適合嵌入式開發人員閱讀。

作者簡介

奔跑吧Linux社区 由一群志同道合的工程师组成,致力于Linux等开源软件与推广,为广大工程师和读者提供深入的开源知识分享。

目錄大綱

 

目 錄

 

 

 

第 1章 ARM64體系結構基礎知識 1

1.1 ARM介紹 1

1.2 ARMv8體系結構基礎知識 2

1.2.1 ARMv8體系結構 2

1.2.2 採用ARMv8體系結構的常見處理器內核 3

1.2.3 ARMv8體系結構中的基本概念 3

1.2.4 A64指令集 4

1.2.5 ARMv8處理器執行狀態 4

1.2.6 ARMv8支持的數據寬度 5

1.3 ARMv8寄存器 5

1.3.1 通用寄存器 5

1.3.2 處理器狀態 6

1.3.3 特殊寄存器 7

1.3.4 系統寄存器 10

1.4 Cortex-A72處理器介紹 10

1.5 ARMv9體系結構介紹 13

第 2章 搭建樹莓派實驗環境 14

2.1 樹莓派介紹 14

2.2 搭建樹莓派實驗環境 15

2.2.1 配置串口線 16

2.2.2 安裝樹莓派官方OS 18

2.2.3 實驗2-1:輸出“Welcome BenOS!” 19

2.2.4 實驗2-2:使用GDB與QEMU虛擬機調試BenOS 20

2.2.5 實驗2-3:使用J-Link EDU模擬器調試樹莓派 21

2.3 BenOS基礎實驗代碼解析 27

2.4 QEMU虛擬機與ARM64實驗平臺 32

第3章 A64指令集1——加載與存儲指令 35

3.1 A64指令集介紹 36

3.2 A64指令編碼格式 37

3.3 加載與存儲指令 38

3.3.1 基於基地址的尋址模式 39

3.3.2 變基模式 41

3.3.3 PC相對地址模式 42

3.3.4 LDR偽指令 43

3.4 加載與存儲指令的變種 44

3.4.1 不同位寬的加載與存儲指令 44

3.4.2 不可擴展的加載和存儲指令 45

3.4.3 多字節內存加載和存儲指令 46

3.4.4 獨占內存訪問指令 48

3.4.5 隱含加載-獲取/存儲-釋放

內存屏障原語 48

3.4.6 非特權訪問級別的加載和存儲指令 48

3.5 入棧與出棧 49

3.6 MOV指令 51

3.7 陷阱:你用對加載與存儲指令了嗎 52

3.8 實驗 53

3.8.1 實驗3-1:熟悉MOV和LDR指令 53

3.8.2 實驗3-2:前變基與後變基尋址模式1 53

3.8.3 實驗3-3:前變基與後變基尋址模式2 54

3.8.4 實驗3-4:PC相對地址尋址 54

3.8.5 實驗3-5:memcpy()函數的實現 54

3.8.6 實驗3-6:LDP和STP指令的使用 55

第4章 A64指令集2——算術與移位指令 56

4.1 條件操作碼 57

4.2 加法與減法指令 57

4.2.1 ADD指令 58

4.2.2 ADDS指令 60

4.2.3 ADC指令 61

4.2.4 SUB指令 61

4.2.5 SUBS指令 64

4.2.6 SBC指令 64

4.3 CMP指令 65

4.4 關於條件標志位的示例 67

4.5 移位指令 68

4.6 位操作指令 68

4.6.1 與操作指令 68

4.6.2 或操作指令 69

4.6.3 位清除操作指令 71

4.6.4 CLZ指令 71

4.7 位段操作指令 71

4.7.1 位段插入操作指令 71

4.7.2 位段提取操作指令 72

4.8 實驗 73

4.8.1 實驗4-1:測試ADDS和CMP指令的C標志位 73

4.8.2 實驗4-2:條件標志位的使用 74

4.8.3 實驗4-3:測試ANDS指令以及Z標志位 74

4.8.4 實驗4-4:測試位段操作指令 74

4.8.5 實驗4-5:使用位段指令來讀取寄存器 74

第5章 A64指令集3——比較指令與跳轉指令 76

5.1 比較指令 76

5.1.1 CMN指令 76

5.1.2 CSEL指令 77

5.1.3 CSET指令 78

5.1.4 CSINC指令 78

5.2 跳轉與返回指令 79

5.2.1 跳轉指令 79

5.2.2 返回指令 80

5.2.3 比較並跳轉指令 80

5.3 陷阱:為什麽在RET指令之後系統就崩潰了 80

5.4 實驗 82

5.4.1 實驗5-1:CMP和CMN指令 82

5.4.2 實驗5-2:條件選擇指令 82

5.4.3 實驗5-3:子函數跳轉 82

第6章 A64指令集4——其他重要指令 83

6.1 PC相對地址加載指令 83

6.2 LDR和ADRP指令的區別 85

6.3 內存獨占訪問指令 85

6.4 異常處理指令 86

6.5 系統寄存器訪問指令 87

6.6 內存屏障指令 88

6.7 實驗 88

6.7.1 實驗6-1:測試ADRP和LDR偽指令 88

6.7.2 實驗6-2:ADRP和LDR偽指令的陷阱 89

6.7.3 實驗6-3:LDXR和STXR指令的使用1 90

6.7.4 實驗6-4:LDXR和STXR指令的使用2 90

第7章 A64指令集的陷阱 91

7.1 案例7-1:加載宏標簽 91

7.2 案例7-2:加載字符串 92

7.3 案例7-3:讀寫寄存器導致樹莓派4B死機 93

7.4 案例7-4:LDXR指令導致樹莓派4B死機 94

7.5 匯編大作業7-1:在匯編中實現串口輸出功能 95

7.6 匯編大作業7-2:分析Linux 5.0的啟動匯編代碼 95

第8章 GNU匯編器 96

8.1 編譯流程與ELF文件 97

8.2 一個簡單的匯編程序 99

8.3 匯編語法 102

8.3.1 註釋 102

8.3.2 符號 102

8.4 常用的偽指令 103

8.4.1 對齊偽指令 103

8.4.2 數據定義偽指令 103

8.4.3 與函數相關的偽指令 104

8.4.4 與段相關的偽指令 105

8.4.5 與宏相關的偽指令 106

8.5 AArch64依賴特性 108

8.5.1 AArch64特有的命令行選項 108

8.5.2 語法 108

8.5.3 AArch64特有的偽指令 109

8.5.4 LDR偽指令 109

8.6 實驗 110

8.6.1 實驗8-1:匯編語言練習——求最大數 110

8.6.2 實驗8-2:匯編語言練習——通過C語言調用匯編函數 110

8.6.3 實驗8-3:匯編語言練習——通過匯編語言調用C函數 110

8.6.4 實驗8-4:使用匯編偽操作來實現一張表 110

8.6.5 實驗8-5:匯編宏的使用 111

第9章 鏈接器與鏈接腳本 112

9.1 鏈接器介紹 112

9.2 鏈接腳本 114

9.2.1 一個簡單的鏈接程序 114

9.2.2 設置入口點 115

9.2.3 基本概念 115

9.2.4 符號賦值與引用 115

9.2.5 當前位置計數器 117

9.2.6 SECTIONS命令 117

9.2.7 常用的內建函數 120

9.3 重定位 121

9.3.1 BenOS重定位 121

9.3.2 UBoot和Linux內核重定位 124

9.4 實驗 126

9.4.1 實驗9-1:分析鏈接腳本文件 126

9.4.2 實驗9-2:輸出每個段的內存佈局 127

9.4.3 實驗9-3:加載地址不等於運行地址 127

9.4.4 實驗9-4:分析Linux 5.0內核的鏈接腳本文件 127

第 10章 GCC內嵌匯編代碼 128

10.1 內嵌匯編代碼基本用法 128

10.1.1 基礎內嵌匯編代碼 128

10.1.2 擴展內嵌匯編代碼 128

10.1.3 內嵌匯編代碼的修飾符和約束符 130

10.1.4 使用匯編符號名 132

10.1.5 內嵌匯編函數與宏的結合 133

10.1.6 使用goto修飾詞 133

10.2 案例分析 134

10.3 實驗 138

10.3.1 實驗10-1:實現簡單的memcpy 函數 138

10.3.2 實驗10-2:使用匯編符號名編寫內嵌匯編代碼 138

10.3.3 實驗10-3:使用內嵌匯編代碼完善__memset_16bytes 匯編函數 138

10.3.4 實驗10-4:使用內嵌匯編代碼與宏 138

10.3.5 實驗10-5:實現讀和寫系統寄存器的宏 139

10.3.6 實驗10-6:goto模板的內嵌匯編函數 139

第 11章 異常處理 140

11.1 異常處理的基本概念 140

11.1.1 異常類型 140

11.1.2 異常等級 141

11.1.3 同步異常和異步異常 141

11.2 異常處理與返回 142

11.2.1 異常入口 142

11.2.2 異常返回 142

11.2.3 異常返回地址 143

11.2.4 異常處理路由 143

11.2.5 棧的選擇 145

11.2.6 異常處理的執行狀態 145

11.2.7 異常返回的執行狀態 146

11.3 異常向量表 146

11.3.1 ARMv8異常向量表 146

11.3.2 Linux 5.0內核的異常向量表 147

11.3.3 VBAR_ELx 148

11.4 異常現場 149

11.5 同步異常的解析 149

11.5.1 異常類型 150

11.5.2 數據異常 151

11.6 案例分析 153

11.6.1 從EL2切換到EL1 153

11.6.2 指令不對齊的同步異常處理 154

11.7 實驗 156

11.7.1 實驗11-1:切換到EL1 156

11.7.2 實驗11-2:建立異常向量表 157

11.7.3 實驗11-3:尋找樹莓派4B上觸發異常的指令 157

11.7.4 實驗11-4:解析數據異常的信息 158

第 12章 中斷處理 159

12.1 中斷處理背景知識 159

12.1.1 中斷引腳 159

12.1.2 中斷控制器 159

12.1.3 中斷處理過程 160

12.2 樹莓派4B上的傳統中斷控制器 160

12.3 ARM內核上的通用定時器 163

12.4 中斷現場 165

12.4.1 保存中斷現場 165

12.4.2 恢復中斷現場 165

12.5 案例分析:在樹莓派4B上實現 一個定時器 166

12.5.1 中斷現場的保存 166

12.5.2 修改異常向量表 169

12.5.3 通用定時器初始化 170

12.5.4 IRQ處理 170

12.5.5 打開本地中斷 171

12.6 實驗 172

12.6.1 實驗12-1:在樹莓派4B上 實現通用定時器中斷 172

12.6.2 實驗12-2:使用匯編函數保存和恢復中斷現場 173

第 13章 GIC-V2 174

13.1 GIC發展歷史 174

13.2 中斷狀態、中斷觸發方式和 硬件中斷號 175

13.3 GIC-V2 175

13.3.1 GIC-V2概要 175

13.3.2 GIC-V2內部結構 176

13.3.3 中斷流程 176

13.3.4 GIC-V2寄存器 178

13.3.5 中斷路由 179

13.4 樹莓派4B上的GIC-400 180

13.4.1 中斷號分配 180

13.4.2 訪問GIC-400寄存器 181

13.4.3 中斷處理流程 181

13.5 實驗 182

13.5.1 實驗13-1:實現通用定時器中斷 182

13.5.2 實驗13-2:實現樹莓派4B上的系統定時器 183

第 14章 內存管理 184

14.1 內存管理基礎知識 184

14.1.1 內存管理的“遠古時代” 184

14.1.2 地址空間的抽象 186

14.1.3 分段機制 187

14.1.4 分頁機制 187

14.2 ARM64內存管理 190

14.2.1 頁表 192

14.2.2 頁表映射 192

14.2.3 頁面粒度 194

14.2.4 兩套頁表 195

14.2.5 頁表項描述符 196

14.2.6 頁表屬性 198

14.2.7 連續塊表項 201

14.3 硬件管理訪問位和臟位 201

14.3.1 訪問位的硬件管理機制 201

14.3.2 臟位的硬件管理機制 201

14.4 與地址轉換相關的控制寄存器 202

14.4.1 TCR 202

14.4.2 SCTLR 204

14.4.3 TTBR 204

14.5 內存屬性 204

14.5.1 普通類型內存 204

14.5.2 設備類型內存 204

14.6 案例分析:在BenOS里實現恆等映射 207

14.6.1 頁表定義 208

14.6.2 頁表數據結構 211

14.6.3 創建頁表 211

14.6.4 打開MMU 217

14.6.5 測試MMU 218

14.7 實驗 220

14.7.1 實驗14-1:建立恆等映射 220

14.7.2 實驗14-2:為什麽MMU 無法運行 220

14.7.3 實驗14-3:實現一個 MMU頁表的轉儲功能 220

14.7.4 實驗14-4:修改頁面屬性導致的系統死機 221

14.7.5 實驗14-5:使用匯編語言來建立恆等映射和打開MMU 222

14.7.6 實驗14-6:驗證LDXR和 STXR指令 222

14.7.7 實驗14-7:AT指令 223

第 15章 高速緩存基礎知識 224

15.1 為什麽需要高速緩存 224

15.2 高速緩存的訪問延時 225

15.3 高速緩存的工作原理 227

15.4 高速緩存的映射方式 229

15.4.1 直接映射 229

15.4.2 全相連映射 230

15.4.3 組相連映射 230

15.4.4 組相連的高速緩存的例子 231

15.5 虛擬高速緩存與物理高速緩存 232

15.5.1 物理高速緩存 232

15.5.2 虛擬高速緩存 232

15.5.3 VIPT和PIPT 232

15.6 重名和同名問題 233

15.6.1 重名問題 233

15.6.2 同名問題 234

15.6.3 VIPT產生的重名問題 235

15.7 高速緩存策略 236

15.8 高速緩存的共享屬性 238

15.8.1 共享屬性 238

15.8.2 PoU和PoC的區別 239

15.9 高速緩存的維護指令 241

15.10 高速緩存枚舉 242

15.11 實驗 245

15.11.1 實驗15-1:枚舉高速緩存 245

15.11.2 實驗15-2:清理高速緩存 245

第 16章 緩存一致性 246

16.1 為什麽需要緩存一致性 246

16.2 緩存一致性的分類 247

16.2.1 ARM處理器緩存一致性發展歷程 247

16.2.2 緩存一致性分類 248

16.2.3 系統緩存一致性問題 249

16.3 緩存一致性的解決方案 250

16.3.1 關閉高速緩存 250

16.3.2 軟件維護緩存一致性 250

16.3.3 硬件維護緩存一致性 250

16.4 MESI協議 251

16.4.1 MESI協議簡介 252

16.4.2 本地讀寫與總線操作 252

16.4.3 MESI狀態轉換圖 253

16.4.4 初始狀態為I 253

16.4.5 初始狀態為M 256

16.4.6 初始狀態為S 257

16.4.7 初始狀態為E 258

16.4.8 總結與案例分析 258

16.4.9 MOESI協議 260

16.5 高速緩存偽共享 261

16.6 CCI和CCN緩存一致性控制器 262

16.6.1 CCI緩存一致性控制器 262

16.6.2 CCN緩存一致性控制器 263

16.7 案例分析16-1:偽共享的避免 264

16.8 案例分析16-2:DMA和 高速緩存的一致性 265

16.8.1 從內存到設備的 FIFO緩沖區 266

16.8.2 從設備的FIFO緩沖區到 內存 266

16.9 案例分析16-3:自修改代碼的 一致性 267

16.10 實驗 268

16.10.1 實驗16-1:高速緩存偽共享 268

16.10.2 實驗16-2:使用Perf C2C 發現高速緩存偽共享 268

第 17章 TLB管理 269

17.1 TLB基礎知識 270

17.2 TLB重名與同名問題 273

17.2.1 重名問題 273

17.2.2 同名問題 274

17.3 ASID 274

17.4 TLB管理指令 276

17.4.1 TLB維護指令介紹 277

17.4.2 TLB廣播 278

17.4.3 TLB維護指令的執行次序 278

17.5 TLB案例分析 278

17.5.1 TLB在Linux內核中的應用 278

17.5.2 ASID在Linux內核中的應用 281

17.5.3 Linux內核中的TLB 維護操作 282

17.5.4 BBM機制 284

第 18章 內存屏障指令 287

18.1 內存屏障指令產生的原因 287

18.1.1 順序一致性內存模型 288

18.1.2 處理器一致性內存模型 289

18.1.3 弱一致性內存模型 289

18.1.4 ARM64處理器的內存模型 290

18.2 ARM64中的內存屏障指令 290

18.2.1 使用內存屏障指令的場景 290

18.2.2 ARM64里的內存屏障指令 291

18.2.3 DMB指令 291

18.2.4 DSB指令 293

18.2.5 DMB和DSB指令的參數 294

18.2.6 單方向內存屏障原語 294

18.2.7 ISB指令 297

18.2.8 高速緩存維護指令與內存屏障指令 299

18.3 案例分析 300

18.3.1 消息傳遞問題 301

18.3.2 單方向內存屏障與自旋鎖 302

18.3.3 郵箱傳遞消息 304

18.3.4 與數據高速緩存相關的案例 305

18.3.5 與指令高速緩存相關的案例 307

18.3.6 與TLB相關的案例 309

18.3.7 DMA案例 310

18.3.8 Linux內核中使指令高速緩存失效 310

第 19章 合理使用內存屏障指令 312

19.1 存儲緩沖區與寫內存屏障指令 313

19.2 無效隊列與讀內存屏障指令 318

19.3 內存屏障指令總結 321

19.4 ARM64的內存屏障指令的區別 322

19.5 案例分析:Linux內核中的內存屏障指令 323

19.5.1 第 一次使用內存屏障指令 324

19.5.2 第二次使用內存屏障指令 326

19.5.3 第三次使用內存屏障指令 329

19.5.4 第四次使用內存屏障指令 330

19.5.5 總結:內存屏障指令的使用 331

第 20章 原子操作 332

20.1 原子操作介紹 332

20.2 獨占內存訪問指令 333

20.3 獨占內存訪問工作原理 334

20.3.1 獨占監視器 334

20.3.2 獨占監視器與緩存一致性 336

20.3.3 獨占監視器的粒度 338

20.4 原子內存訪問操作指令 338

20.5 比較並交換指令 341

20.6 WFE指令在自旋鎖中的應用 342

第 21章 操作系統相關話題 344

21.1 C語言常見陷阱 344

21.1.1 數據模型 344

21.1.2 數據類型轉換與整型提升 346

21.1.3 移位操作 348

21.2 函數調用標準 349

21.3 棧佈局 351

21.4 創建進程 352

21.4.1 進程控制塊 352

21.4.2 0號進程 353

21.4.3 do_fork函數的實現 354

21.4.4 進程上下文切換 355

21.4.5 新進程的第 一次執行 357

21.5 簡易進程調度器 357

21.5.1 擴展進程控制塊 358

21.5.2 就緒隊列run_queue 358

21.5.3 調度隊列類 358

21.5.4 簡易調度器的實現 360

21.5.5 自願調度 360

21.5.6 搶占調度 362

21.5.7 測試用例 363

21.6 系統調用 364

21.6.1 系統調用介紹 364

21.6.2 用戶態調用SVC指令 364

21.6.3 內核態對系統調用的處理 365

21.6.4 系統調用表 366

21.7 系統啟動 367

21.8 實驗 368

21.8.1 實驗21-1:觀察棧佈局 368

21.8.2 實驗21-2:進程創建 369

21.8.3 實驗21-3:進程調度 369

21.8.4 實驗21-4:新增一個 malloc()系統調用 369

21.8.5 實驗21-5:新增一個clone() 系統調用 370

第 22章 浮點運算與NEON指令 371

22.1 數據模型 371

22.2 浮點運算 373

22.2.1 浮點數 373

22.2.2 浮點控制寄存器與浮點狀態寄存器 375

22.2.3 浮點數的條件操作碼 377

22.2.4 常用浮點運算指令 377

22.3 NEON指令集 378

22.3.1 SISD和SIMD 378

22.3.2 矢量運算與標量運算 379

22.3.3 加載與存儲指令LD1與 ST1 380

22.3.4 加載與存儲指令LD2和 ST2 382

22.3.5 加載與存儲指令LD3和 ST3 383

22.3.6 加載與存儲指令LD4和 ST4 385

22.3.7 加載指令的特殊用法 385

22.3.8 搬移指令 386

22.3.9 反轉指令 388

22.3.10 提取指令 389

22.3.11 交錯變換指令 390

22.3.12 查表指令 391

22.3.13 乘加指令 391

22.3.14 矢量算術指令 393

22.4 案例分析22-1:RGB24轉BGR24 …..393

22.4.1 使用C語言實現RGB24轉 BGR24 394

22.4.2 手工編寫NEON匯編函數 394

22.4.3 使用NEON內建函數 395

22.4.4 測試 395

22.5 案例分析22-2:4×4矩陣乘法運算 397

22.5.1 使用C語言實現4×4矩陣乘法運算 397

22.5.2 手工編寫NEON匯編函數 398

22.5.3 使用NEON內建函數 401

22.5.4 測試 403

22.6 自動矢量優化 404

22.7 實驗 406

22.7.1 實驗22-1:浮點運算 406

22.7.2 實驗22-2:RGB24轉BGR32…… 407

22.7.3 實驗22-3:8×8矩陣乘法 運算….. 407

第 23章 可伸縮矢量計算與優化 408

23.1 SVE指令介紹 408

23.1.1 SVE寄存器組 408

23.1.2 SVE指令語法 410

23.2 搭建SVE運行和調試環境 410

23.3 SVE特有的編程模式 412

23.3.1 斷言指令 412

23.3.2 聚合加載和離散存儲 414

23.3.3 基於斷言的循環控制 415

23.3.4 基於軟件推測的向量分區 421

23.4 SVE與SVE2指令集 422

23.5 案例分析23-1:使用SVE指令優化strcmp()函數 422

23.5.1 使用純匯編方式 423

23.5.2 測試 425

23.6 案例分析23-2:RGB24轉BGR24 ….425

23.6.1 使用純匯編方式 426

23.6.2 使用內嵌匯編方式 426

23.6.3 測試 427

23.7 案例分析23-3:4×4矩陣乘法運算 428

23.7.1 使用內嵌匯編方式 428

23.7.2 測試 430

23.8 實驗 431

23.8.1 實驗23-1:RGB24轉BGR32 431

23.8.2 實驗23-2:8×8矩陣乘法運算 432

23.8.3 實驗23-3:使用SVE指令優化strcpy()函數 432