1. ARM体系结构基础:从8位机到64位帝国的演进
做嵌入式开发这么多年,我始终觉得ARM体系结构是绕不开的一座山。不管你写驱动还是裁剪内核,最终都要跟ARM的寄存器、异常模型、内存映射打交道。这一章,我们先打好地基。
1.1 ARM发展史:一家卖IP的公司如何统治了嵌入式世界
ARM的故事很有意思。它最初是Acorn电脑公司的一个项目,1985年做出了第一颗芯片ARM1。那时候谁也没想到,这个只有26个指令的RISC处理器,后来会成为移动互联网的基石。
我入行时ARM还叫Advanced RISC Machines,后来被软银收购,再后来又要上市。但不管资本怎么折腾,ARM的指令集架构一直在演进:
- ARMv4T:引入了Thumb指令集,代码密度提升30%。我最早接触的ARM7TDMI就是这个架构
- ARMv5TE:增加了DSP指令扩展,开始往多媒体方向走
- ARMv6:SIMD指令集出现,ARM11系列的代表作
- ARMv7-A:Cortex-A系列的起点,也是32位ARM的巅峰
- ARMv8-A:64位时代开启,AArch64和AArch32并存
- ARMv9:2021年发布,强化安全性和AI能力
关键认知:ARM自己不造芯片,它只卖IP授权。高通、苹果、华为、联发科都是它的客户。这意味着你写的驱动,理论上可以在不同厂商的芯片上跑——前提是它们都实现了同一套ARM架构。
1.2 ARM Cortex系列分类:别把A系列和M系列搞混了
很多新手问我:"Cortex-A和Cortex-M到底有什么区别?" 嗯,这个问题问得好。ARM在2010年左右把产品线重新梳理,分成了三大系列:
| 系列 | 全称 | 典型应用 | 操作系统 | 我见过的场景 |
|---|---|---|---|---|
| Cortex-A | Application | 手机、平板、服务器 | Linux、Android、iOS | 高通骁龙、华为麒麟 |
| Cortex-R | Real-time | 汽车、工业控制、硬盘控制器 | RTOS、裸机 | 汽车刹车系统、基站 |
| Cortex-M | Microcontroller | 物联网、传感器、电机控制 | FreeRTOS、裸机 | STM32、Nordic nRF |
说白了,A系列跑Linux,M系列跑裸机或RTOS,R系列夹在中间做实时控制。你如果要做Linux驱动开发,主要跟Cortex-A打交道。我当年第一次移植Linux内核到Cortex-A8平台时,光MMU和GIC就折腾了两周。
我的建议:初学者可以先从Cortex-M入手理解ARM的寄存器模型和异常处理,然后再跳到Cortex-A学MMU和中断控制器。直接啃A系列容易一头雾水。
1.3 ARMv7 vs ARMv8架构对比:32位到64位的跨越
ARMv7是32位时代的集大成者,Cortex-A8/A9/A15都是这个架构。ARMv8则是一次彻底的革新——它引入了64位指令集AArch64,同时保留了32位兼容模式AArch32。
为什么会这样?因为生态。你想想看,如果直接砍掉32位支持,那所有现有的Android应用和Linux发行版都得重编。ARM选择了"两条腿走路":
- AArch64:全新的64位执行状态,31个通用寄存器(X0-X30),SP和PC独立
- AArch32:向下兼容ARMv7,跑32位代码时跟Cortex-A15没区别
我记得第一次在ARMv8平台上调试时,发现异常向量表的结构完全变了。ARMv7的异常向量表是固定的0xFFFF0000或0x00000000,而ARMv8的VBAR_ELx寄存器可以任意设置。这个改动让虚拟化实现变得优雅很多。
| 对比项 | ARMv7-A (32位) | ARMv8-A (64位) |
|---|---|---|
| 寄存器宽度 | 32位 | 64位 |
| 通用寄存器 | 16个(R0-R15) | 31个(X0-X30) |
| 异常等级 | SVC/IRQ/FIQ/Undef/Abort | EL0/EL1/EL2/EL3 |
| 虚拟化支持 | 可选(通过硬件扩展) | 原生支持(EL2) |
| 寻址空间 | 4GB | 最大2^48字节 |
| 指令集 | ARM + Thumb/Thumb-2 | A64 + A32/T32 |
避坑指南:我曾经在移植一个ARMv7的汇编优化库到ARMv8时踩过坑——ARMv7的SWI指令在ARMv8里变成了SVC,而且参数传递方式也变了。如果你要做汇编级别的移植,务必检查所有系统调用和异常处理代码。
1.4 ARM处理器工作模式:7种模式与异常等级
ARMv7有7种处理器模式,ARMv8则用异常等级(Exception Level)来重新组织了这套体系。我们先看ARMv7的:
- User (USR):普通程序运行的模式,权限最低
- FIQ:快速中断模式,有独立的寄存器组
- IRQ:普通中断模式
- Supervisor (SVC):系统调用和复位后的默认模式
- Abort (ABT):数据访问或指令预取异常
- Undefined (UND):遇到未定义指令时进入
- System (SYS):特权模式,但使用User模式的寄存器组
ARMv8把这套东西抽象成了4个异常等级:
- EL0:用户态,跑应用程序
- EL1:操作系统内核
- EL2:Hypervisor(虚拟化)
- EL3:Secure Monitor(安全世界)
说白了,ARMv8的异常等级就是给不同软件层划了"地盘"。你写的驱动跑在EL1,应用程序跑在EL0,中间有硬件隔离。这个设计让系统更安全——应用程序崩了不会拖垮内核。
核心要点:在Linux内核里,你写的驱动代码运行在EL1(ARMv8)或SVC模式(ARMv7)。中断处理时,CPU会切换到IRQ模式(ARMv7)或保持EL1但改变异常向量(ARMv8)。理解这个切换过程,是写好中断驱动的第一步。
1.5 本章知识体系总览
下面这张图把ARM体系结构的核心脉络串起来了。我建议你保存下来,后面学MMU、GIC、异常处理时都可以回来对照:
学习路径建议:如果你刚开始接触ARM,我建议按这个顺序来——先搞清楚Cortex-A/R/M的区别,再理解ARMv7的7种工作模式,然后对比ARMv8的异常等级。最后回头看ARM发展史,你会发现每个架构改动都是为了解决实际问题。
嗯,这一章的内容就到这里。ARM体系结构的东西很多,但我们只挑跟驱动开发和内核裁剪最相关的来讲。后面几章会深入MMU、Cache、GIC、异常处理——这些都是你写驱动时天天要打交道的硬件模块。