1 嵌入式体系结构入门
本文是 嵌入式 Linux 学习路径 第二阶段:建立 CPU、内存、MMU、异常/中断、Cache、DMA 的准确心智模型。目标不是背寄存器手册,而是能解释:为什么驱动不能乱解引用用户指针、为什么 DMA 要 cache 同步、为什么中断里不能 sleep。
1.1 学习目标
- 说清 指令集、执行状态、特权级 在 ARM/x86 上的对应关系(概念层)。
- 理解 虚拟地址 → 物理地址 由 MMU 完成;用户态与内核态 地址空间 分离。
- 区分 异常、中断、系统调用 的触发源与处理路径。
- 建立 Cache 一致性 与 DMA 的工程直觉。
1.2 CPU 与指令集(嵌入式常见)
| 家族 | 典型产品 | 备注 |
|---|---|---|
| ARMv7-A / AArch32 | 老工业板、部分 Cortex-A7/A9 | Thumb-2;arm-linux-gnueabihf |
| ARMv8-A / AArch64 | 主流新板、网关 | aarch64-linux-gnu |
| RISC-V | 新兴 SoC | 工具链与 DT 生态在快速成熟 |
| x86 | 部分网安/工控 | 与嵌入式 ARM 路径不同但 Linux 概念相通 |
关键点:ISA + ABI + 浮点约定(hard/soft float) 必须与 rootfs、内核、模块一致。
1.3 内存层次
寄存器 → L1 I/D Cache → L2/L3 → 主存(DDR) → (外设 MMIO 映射)
- 带宽与延迟 数量级差异巨大;热路径要 cache friendly(顺序访问、对齐、假共享避免)。
- MMIO:外设寄存器映射到 物理地址区间;内核通过
ioremap映射到内核虚拟地址再访问;用户态不可直接访问(除非mmap特定/dev或 UIO,由驱动设计)。
1.4 MMU 与地址空间
1.4.1 分页(现代嵌入式 Linux 标配)
- 虚拟页 → 物理页帧;页表 由 OS 维护;TLB 缓存翻译结果。
- 用户进程 看到 0…用户空间上限 的 VA;内核 有独立映射(具体 split 因架构而异:ARM64 常见 TTBR0_EL1 用户、TTBR1_EL1 内核)。
1.4.2 为何这很重要
- 隔离:进程 A 不能访问进程 B 的内存(除非共享映射)。
- 驱动:用户传入的 指针是 VA,内核必须
copy_from_user/get_user等,或通过mmap建立合法映射。 - 调试:
/proc/<pid>/maps看 VMA;缺页 分合法(按需分配)与非法(SIGSEGV)。
1.4.3 与「查物理地址」的关系
- 教学可用
/proc/pagemap(权限受限);驱动 DMA 应走dma_map_*,不要假设 VA 线性减偏移等于设备 DMA 地址(IOMMU 下尤其错误)。
1.5 异常(Exception)与中断(Interrupt)
1.5.1 异常(同步)
- 与 当前指令流相关:缺页、非法指令、除零、SVC/Syscall、调试断点。
- 系统调用 是 自愿 触发的异常/陷入,进入内核统一入口再分派。
1.5.2 中断(异步)
- 外设 通过 IRQ 线 / GIC 通知 CPU;ISR 应极短。
- Linux 划分:
- 硬中断上下文:不可 睡眠(不可
mutex_lock阻塞路径、不可kmalloc(GFP_KERNEL)等)。 - 软中断 / tasklet / threaded IRQ / workqueue:把耗时工作推迟到可阻塞或更低优先级上下文。
- 硬中断上下文:不可 睡眠(不可
1.5.3 ARM GIC(概念)
- GICv2/v3 分发中断到 CPU;SPI/PPI/SGI 分类;设备树里
interrupts属性与 interrupt-parent 描述连接关系(与 设备树实战 阶段衔接)。
1.6 Cache 与 DMA(嵌入式高频考点)
1.6.1 问题从哪来
- CPU 写内存可能只到 Cache;设备 DMA 读 DDR 可能看不到最新数据 → coherency 问题。
- 反之:CPU 读到的可能是 旧 cache 行,设备已写入 DDR。
1.6.2 工程对策(内核侧)
- 使用
dma_alloc_coherent(映射一致)或dma_map_single+ dma_sync_* 在 传输前后 同步。 - Cache line 对齐 buffer;避免 CPU 与 DMA 同时 改同一行无协议。
1.6.3 用户态 DPDK 等
- Hugepage + 设备特定映射;与内核驱动路径不同,但 「设备看到的地址 ≠ 任意 malloc 指针」 同样成立。
1.7 特权级与安全(按需)
- ARM EL0 用户、EL1 OS 内核、EL2 Hypervisor、EL3 Secure monitor。
- TrustZone:安全世界与普通 Linux 的分界;驱动开发多数在 非安全 Linux,但 Secure Boot 链影响能加载什么镜像。
1.8 实践练习
- 读
/proc/cpuinfo、/proc/interrupts,对照设备树里某外设中断号是否出现计数。 - 写用户态程序触发 SIGSEGV 与 合法缺页(首次 touch 大
mmap),用dmesg观察差异。 - 阅读一篇 ARM Cortex-A 异常向量表说明(官方 TRM 节选即可),标出 sync vs irq 入口。
1.9 阶段验收
- 画一张图:用户
read()→ syscall → VFS → 可能缺页 → 返回。 - 解释 中断上下文 vs 进程上下文 各能调用哪类内核 API。
- 说明 为何 DMA buffer 需要 sync(不用背所有 API 名也可)。
- 区分 MMU 缺页 与 总线错误 在现象上的可能差异(日志/硬件)。
1.10 下一阶段衔接
- 交叉编译:
readelf -h里的 Machine 对应本节的 ISA。 - 设备树:
reg是 物理/MMIO 地址;interrupts连接 GIC。
1.11 参考
- ARM Architecture Reference Manual(Profile 对应你的 SoC)
- ARM System Developer’s Guide(经典)
- Linux
Documentation/arch/arm64/(或 arm)入门文档
寄存器级细节以 SoC TRM 为准;本节建立的是跨芯片可迁移的概念骨架。