1. ARM架构概述:从手机到服务器,一个架构的进化史
做嵌入式的人,没人能绕过ARM。我最早接触ARM还是十多年前做一款工业控制器,当时选型就是ARM7TDMI。说实话,那时候ARM还是个"低功耗但性能一般"的选手。谁能想到今天它从手机杀到了服务器,连苹果的Mac都换成了ARM架构。
这一节,咱们把ARM的底牌翻一翻。从发展史到产品线,再到v7和v8的核心差异。这些内容看着像背景知识,但后面讲MMU和内存模型时,你会不断回来翻这一节。
1.1 ARM发展史:一家不造芯片的芯片公司
ARM的故事挺有意思。1985年,Acorn电脑公司想做一款RISC处理器,结果搞出了ARM1。那时候没人觉得这东西能成。后来Acorn不行了,ARM独立出来,1991年正式成立ARM公司。
ARM最聪明的一步棋是什么?它不造芯片,只卖IP授权。你想想看,这意味着什么?任何公司都可以买ARM的授权,然后自己加外设、改频率、定制指令。这就解释了为什么市面上有上千种不同的ARM芯片。
关键时间节点:
- 1985年 — ARM1诞生,26位指令集,22MHz
- 1994年 — ARM7TDMI发布,嵌入式领域的"常青树"
- 2002年 — ARMv5架构,Jazelle技术支持Java加速
- 2005年 — ARMv6架构,Cortex系列首次亮相
- 2011年 — ARMv8-A发布,64位时代开启
- 2021年 — ARMv9发布,强调安全与AI
我个人习惯把ARM历史分成三个阶段:探索期(ARM1到ARM7)、统治期(ARM9到Cortex-A9)、扩展期(Cortex-A53至今)。每个阶段都有标志性产品,后面咱们会反复提到。
1.2 Cortex-A/R/M系列:三兄弟各司其职
很多新手搞不清Cortex-A、Cortex-R、Cortex-M的区别。我当年也犯过糊涂,选型时把A系列芯片用在电池供电的设备上,功耗直接翻倍。嗯,学费交得有点贵。
说白了,这三兄弟的分工很明确:
| 特性 | Cortex-A | Cortex-R | Cortex-M |
|---|---|---|---|
| 全称 | Application | Real-time | Microcontroller |
| 典型场景 | 手机、平板、服务器 | 汽车、硬盘控制器、基站 | 传感器、IoT、电机控制 |
| MMU | 有 | 可选(MPU) | 无 |
| 操作系统 | Linux、Android、Windows | RTOS、裸机 | RTOS、裸机 |
| 中断延迟 | 几十到几百纳秒 | 几纳秒 | 几纳秒 |
| 功耗 | 高 | 中 | 极低 |
| 代表型号 | Cortex-A72、A76 | Cortex-R5、R52 | Cortex-M4、M7 |
这里有个坑我要提醒你:Cortex-R系列虽然叫"实时",但它不是硬实时。我在做汽车ECU项目时,一开始选了R5,后来发现中断响应还是不够确定,最后换成了专用DSP。选型时一定要看具体的数据手册,别光看名字。
避坑指南:我曾经在一个项目中,把Cortex-M7当主控,想跑Linux。结果发现M7根本没有MMU,Linux跑不起来。最后只能上A系列,整个方案重做。选型前先确认:你要不要跑Linux?要不要虚拟地址?要不要多进程?这些问题的答案直接决定了你选A还是M。
1.3 ARMv7-A与ARMv8-A:32位到64位的跨越
ARMv7-A是32位时代的巅峰。Cortex-A15、A9都是这个架构。ARMv8-A则是64位的新起点,Cortex-A53、A72、A76都是它的子孙。
两者的差异,我列个表你一看就明白:
| 对比项 | ARMv7-A | ARMv8-A |
|---|---|---|
| 指令集宽度 | 32位 | 32位 + 64位 |
| 通用寄存器 | 16个(R0-R15) | 31个(X0-X30) |
| 虚拟地址空间 | 4GB(32位) | 最大2^48(256TB) |
| 物理地址空间 | 最大1TB(LPAE) | 最大2^48 |
| MMU页表格式 | 二级页表 | 三级/四级页表 |
| 异常模型 | IRQ/FIQ/SVC等7种模式 | EL0-EL3四个异常等级 |
| 兼容性 | 仅32位 | 兼容32位(AArch32) |
这里有个关键点:ARMv8-A不是简单地"把32位变成64位"。它把整个异常模型重写了。ARMv7-A有7种处理器模式(User、FIQ、IRQ、Supervisor等),切换起来很麻烦。ARMv8-A改成了4个异常等级(EL0到EL3),每个等级有独立的栈指针和页表。这个设计让虚拟化和安全监控器(如TrustZone)的实现变得干净很多。
我在调试一个ARMv8-A的启动代码时,就踩过异常等级的坑。当时在EL3初始化了MMU,然后切到EL1跑Linux,结果页表全失效了。后来才意识到:每个异常等级有自己的TTBR0_ELx寄存器,切换等级后必须重新配置页表。
小技巧:如果你在做ARMv8-A的底层开发,建议先搞清楚当前在哪个异常等级。用MRS X0, CurrentEL指令可以读出来。这个习惯能帮你省掉很多调试时间。
1.4 架构演进的核心逻辑:一张图看懂
下面这张图展示了ARM架构从v7到v8的核心变化。我画的时候特意把异常模型和MMU放在一起,因为这两个是内存模型的基础。
1.5 为什么这些对MMU和内存模型重要?
你可能会问:学ARM架构和MMU有什么关系?关系大了。
MMU的页表格式直接由架构版本决定。 ARMv7-A用二级页表,ARMv8-A用三级甚至四级页表。如果你在调试MMU时发现页表遍历不对,第一步就是确认架构版本。
异常等级决定了谁控制MMU。 在ARMv8-A中,EL3(安全监控器)可以独立配置自己的MMU,EL1(操作系统)也有自己的MMU。这种分层设计让虚拟化成为可能,但也带来了配置的复杂性。
我记得有一次调试一个ARMv8-A的KVM虚拟化问题,客户说虚拟机里的Linux访问外设时崩溃。查了两天才发现:EL2的页表配置错了,把设备内存映射成了普通内存。这就是架构知识不够扎实的代价。
总结一下这一节的核心:
- ARM不造芯片,只卖IP,所以市面上有各种变种
- Cortex-A/R/M分别对应应用、实时、微控制器场景,选型要谨慎
- ARMv8-A不是简单的64位升级,异常模型和MMU都重构了
- 架构版本直接影响MMU配置方式,后面章节会反复用到这些知识