第1章 ARM体系结构基础:从内核到实战的必修课
做嵌入式Linux系统裁剪,ARM体系结构是绕不开的根基。我见过不少工程师,上来就搞内核裁剪、驱动移植,结果遇到异常定位、性能调优时,连寄存器怎么切换都搞不清楚。说白了,ARM体系结构就是你的“底层地图”——地图画错了,后面跑得再快也是白搭。
这一章,我们先把ARM的“家底”摸清楚。从处理器发展史到架构差异,从寄存器到工作模式,我会结合自己踩过的坑,帮你把基础夯扎实。
1.1 ARM处理器发展史:从Acorn到万亿级生态
ARM的故事,得从1985年说起。当时英国Acorn公司想做一款高性能处理器,但Intel的80286太贵,Motorola的68000又太复杂。Acorn的工程师们一拍脑袋:我们自己造一个!于是,ARM1诞生了——只有3万多个晶体管,功耗极低,性能却够用。
我最早接触ARM是在2008年,那时候ARM9还是主流,跑个Linux 2.6内核要折腾好几天。现在回头看,ARM的发展脉络其实很清晰:
| 年代 | 核心架构 | 代表产品 | 我的印象 |
|---|---|---|---|
| 1985-1990 | ARMv1~ARMv3 | ARM1、ARM2、ARM3 | Acorn电脑专用,没几个人见过 |
| 1990-2000 | ARMv4/ARMv4T | ARM7TDMI、ARM9TDMI | 经典中的经典,我第一块开发板就是ARM7 |
| 2000-2010 | ARMv5/ARMv6 | ARM926EJ-S、ARM1136J(F)-S | 开始支持Jazelle Java加速,但实际用处不大 |
| 2010-2015 | ARMv7-A | Cortex-A8/A9/A15 | 智能手机爆发期,我在这上面栽过不少坑 |
| 2015-至今 | ARMv8-A/ARMv9-A | Cortex-A53/A72/A76/X1 | 64位时代,性能翻倍,功耗控制更精细 |
1.2 ARM Cortex-A/R/M系列对比:选对核,少走弯路
ARM Cortex系列分三条线:A系列(Application)、R系列(Real-time)、M系列(Microcontroller)。很多人觉得“都是ARM核,应该差不多吧?”——差远了!
我有个朋友,非要用Cortex-M4跑Linux,折腾了三个月,最后发现MMU都没有,连虚拟内存都搞不了。嗯,这就是典型的选型失误。
| 特性 | Cortex-A | Cortex-R | Cortex-M |
|---|---|---|---|
| 目标场景 | 高性能应用(Linux/Android) | 实时控制(汽车、工业) | 微控制器(IoT、传感器) |
| MMU | 有(必须) | 无(但有MPU) | 无 |
| 缓存 | L1/L2/L3,大容量 | L1,通常较小 | 无或极简 |
| 中断延迟 | 几十~几百微秒 | 纳秒级 | 纳秒级 |
| 典型主频 | 1~3GHz | 500MHz~2GHz | 几十~几百MHz |
| 功耗 | 高(几瓦~十几瓦) | 中等 | 极低(毫瓦级) |
| 操作系统 | Linux、Android、QNX | RTOS(FreeRTOS、VxWorks) | 裸机或轻量RTOS |
1.3 ARMv7与ARMv8架构差异:32位到64位的跨越
ARMv7是32位架构的巅峰,ARMv8则开启了64位时代。很多人觉得“不就是从32位变成64位嘛,地址空间大了点”——其实远不止这些。
我当年从ARMv7迁移到ARMv8时,踩的第一个坑就是:指令集不兼容。ARMv8的AArch64模式和AArch32模式是两套完全不同的指令集,你不能把ARMv7的二进制直接扔到ARMv8上跑——除非切换到AArch32兼容模式。
来看看关键差异:
| 对比项 | ARMv7 (32位) | ARMv8 (64位) |
|---|---|---|
| 寄存器宽度 | 32位 | 64位(AArch64) |
| 通用寄存器数量 | 16个(R0-R15) | 31个(X0-X30) |
| 指令集 | ARM/Thumb/Thumb-2 | A64(全新设计) |
| 虚拟地址空间 | 4GB(32位) | 最大48位(256TB) |
| 异常模型 | 7种异常模式 | 4个异常等级(EL0-EL3) |
| 浮点/SIMD | VFPv3/v4、NEON | VFPv4、ASIMD(增强NEON) |
| 虚拟化支持 | 可选(硬件虚拟化扩展) | 原生支持(EL2) |
1.4 ARM寄存器与工作模式:CPU的“五脏六腑”
寄存器是CPU的“工作台”——所有运算、数据搬运、状态保存,都得靠它们。ARM的寄存器体系,说白了就是一套精心设计的“分工协作”系统。
1.4.1 寄存器概览(以ARMv7为例)
ARMv7有16个通用寄存器(R0-R15),外加一个CPSR(当前程序状态寄存器)。其中:
- R0-R3:参数传递寄存器。函数调用时,前4个参数放这里。
- R4-R11:普通通用寄存器。函数内保存局部变量。
- R12(IP):内部过程调用寄存器。链接器有时会用。
- R13(SP):栈指针寄存器。指向当前栈顶。
- R14(LR):链接寄存器。保存函数返回地址。
- R15(PC):程序计数器。指向当前指令地址。
- CPSR:状态寄存器。保存条件标志、中断屏蔽位、当前模式等。
1.4.2 工作模式:CPU的“多副面孔”
ARMv7有7种工作模式,每种模式都有自己的“影子寄存器”——说白了,就是切换模式时自动备份一些关键寄存器,省得你手动保存恢复。
| 模式 | 缩写 | 用途 | 影子寄存器 |
|---|---|---|---|
| 用户模式 | USR | 普通程序运行 | 无 |
| 快速中断模式 | FIQ | 高速中断处理 | R8-R14 |
| 普通中断模式 | IRQ | 普通中断处理 | R13、R14 |
| 管理模式 | SVC | 操作系统内核(SWI调用) | R13、R14 |
| 中止模式 | ABT | 数据/指令访问异常 | R13、R14 |
| 未定义模式 | UND | 未定义指令异常 | R13、R14 |
| 系统模式 | SYS | 特权任务(共享用户寄存器) | 无 |
你想想看,FIQ模式为什么有5个影子寄存器(R8-R12)?因为FIQ要求极快响应,多几个专用寄存器就能少压栈几次。我做过一个高速数据采集项目,中断频率到10MHz时,IRQ模式根本扛不住,换成FIQ后,延迟从2微秒降到了200纳秒——这就是架构设计的精妙之处。
1.4.3 ARMv8的寄存器变化
到了ARMv8的AArch64模式,寄存器体系大变样:
- 通用寄存器从16个扩展到31个(X0-X30),全部64位宽。
- PC不再是通用寄存器,变成独立寄存器。
- CPSR被拆成多个系统寄存器(SPSR_ELx、NZCV等)。
- 异常等级(EL0-EL3)取代了7种工作模式。
1.5 本章知识体系总览
下面这张图,把ARM体系结构的关键脉络串起来了。你可以把它当作“学习地图”——后面每一章,都会在这张图上展开。
1.6 本章小结
ARM体系结构基础,说白了就是三件事:知道ARM怎么来的(发展史)、知道该选哪个核(A/R/M对比)、知道CPU内部怎么工作的(寄存器与模式)。ARMv7到ARMv8的跨越,则是理解现代ARM系统的分水岭。
我个人建议,学这一章时别急着往下翻。找一块开发板(哪怕是QEMU模拟的),打开调试器,单步执行几条指令,看看寄存器怎么变、模式怎么切。纸上得来终觉浅——这句话在嵌入式领域,尤其适用。