ARM -- 架构基础介绍

1、ARM与x86架构区别

ARM采用RISC(精简指令集 Reduced Instruction Set Computing),指令等长、功耗低;x86为CISC(复杂指令集),指令变长、性能高。

Cortex系列应用场景‌:

  • Cortex-A‌:应用处理器,用于智能手机、平板(如高通骁龙)application;
  • Cortex-R‌:实时处理,用于汽车控制、工业系统 realtime;
  • Cortex-M‌:微控制器,用于物联网设备、传感器(如STM32)micro。

ARMv7与ARMv8区别‌:ARMv8支持64位指令集(AArch64),引入EL0-EL3四个异常级别,增强安全与虚拟化能力。

  • ARMv7‌:纯32位架构,支持A32(ARM)和T16(Thumb-2)指令集,适用于早期智能手机和嵌入式设备。
  • ARMv8‌:引入64位AArch64执行状态,新增A64指令集,同时保留AArch32模式以运行32位代码,实现平滑过渡。

2、寄存器与状态

  • 关键寄存器作用 ‌:
    • ‌**PC(R15)**‌:程序计数器,指向当前执行指令地址;
    • ‌**SP(R13)**‌:堆栈指针,管理函数调用与局部变量;
    • ‌**LR(R14)**‌:链接寄存器,保存函数返回地址;
    • CPSR‌:当前程序状态寄存器,存储N/Z/C/V标志位及处理器模式。
  • Thumb与ARM状态切换‌:通过BX指令跳转,目标地址最低位为1时进入Thumb模式,为0时进入ARM模式。
  • ARM模式 ‌:处理器执行‌32位ARM指令集‌(A32),每条指令占4字节,功能完整,适用于高性能运算。高性能任务、操作系统内核
  • Thumb模式 ‌:处理器执行‌16位或32位混合指令集‌(T16/Thumb-2),指令更短,代码密度高,节省存储空间和内存带宽。嵌入式设备、资源受限系统
  • ARM/Thumb/Thumb-2区别‌:
  • ARM指令集‌:32位,性能强;
  • Thumb指令集‌:16位,代码密度高,节省存储;
  • Thumb-2‌:混合16/32位,兼顾性能与空间。

3、FIQ和IRQ

**FIQ(快速中断请求)优先级高于IRQ(普通中断请求)**‌,且FIQ拥有更多专用寄存器,响应延迟更低,适用于实时性要求高的场景。

核心区别详解

  1. 优先级不同

    • FIQ‌ 具有最高优先级,在ARM异常向量表中排在IRQ之前。
    • 当FIQ和IRQ同时发生时,处理器会‌优先处理FIQ‌,待其完成后才响应IRQ。
  2. 寄存器资源差异

    • FIQ模式 ‌ 拥有 ‌**7个专用影子寄存器(R8-R14)**‌,在中断处理时无需保存现场,减少上下文切换开销。
    • IRQ模式‌ 使用通用寄存器,需通过压栈保存/恢复上下文,增加处理延迟。
  3. 中断向量地址不同

    • FIQ中断入口位于 ‌0x1C‌,可将处理程序直接放置于此地址,省去跳转指令,提升响应速度。
    • IRQ中断入口位于 ‌0x18‌,通常需要跳转到实际服务程序,引入额外延迟。
  4. 设计用途不同

    • FIQ ‌ 用于高速数据传输、实时时钟等‌紧急或高实时性任务‌,如DMA传输完成通知。
    • IRQ ‌ 用于键盘、定时器等‌常规外设中断处理‌,适用于对响应时间要求不苛刻的场景。
  5. 中断延迟与性能

    • 由于硬件自动处理部分上下文保存,FIQ的‌中断响应时间更短‌,适合低延迟应用。
    • IRQ因需软件参与更多上下文管理,响应相对缓慢。

✅ 在LPC2000系列等ARM处理器中,FIQ被明确设计为最高优先级中断类型,支持外设优先级动态调整。而Cortex-M3内核已取消FIQ机制,改用可配置优先级的NVIC中断控制器替代。

4、MMU(Memory Management Unit)

MMU(Memory Management Unit,内存管理单元)是集成在 CPU 内部的专用硬件组件,主要负责处理中央处理器的内存访问请求。其核心作用及关闭后的影响如下:

MMU 的主要功能可以概括为‌地址转换 ‌、‌内存保护 ‌和‌辅助缓存控制‌三大方面:

1. 虚拟地址到物理地址的映射(核心功能)
  • 机制‌:现代操作系统为每个进程提供独立的"虚拟地址空间"。程序编译链接后使用的是虚拟地址,而数据实际存储在物理内存中。MMU 负责在 CPU 访问内存时,实时将虚拟地址转换为物理地址。
  • 优势 ‌:
    • 突破物理限制‌:通过虚拟内存技术,允许程序使用的内存总量超过实际物理内存大小(利用硬盘 Swap 空间)。
    • 简化编程‌:程序员无需关心物理内存的具体布局和大小,只需使用连续的线性虚拟地址。
    • 解决地址冲突‌不同进程可以使用相同的虚拟地址(如 0x1000),MMU 将其映射到不同的物理地址,实现进程间的内存隔离。
2. 内存访问权限保护(安全保障)
  • 机制‌:MMU 在页表项中存储了内存区域的访问权限属性(如只读、可读写、可执行、内核态/用户态访问等)。
  • 作用 ‌:
    • 防止非法访问‌:当 CPU 尝试访问未授权区域(如用户态程序试图修改内核数据,或写入只读代码段)时,MMU 会拦截该操作并触发异常(如 Page Fault 或 Permission Fault),从而保护系统稳定性。
    • 进程隔离‌:确保一个进程的崩溃或错误(如野指针)不会破坏其他进程或操作系统的数据。
3. 辅助 Cache 管理与 TLB 加速
  • ‌**TLB(Translation Lookaside Buffer)**‌:为了加快地址转换速度,MMU 使用 TLB 缓存最近使用的"虚拟-物理"地址映射关系。TLB 命中时可极速完成转换,未命中时才查询主存中的页表。
  • Cache 协同‌:在 ARM11 及之后的架构中,Cache 位于 MMU 之后。CPU 发出的虚拟地址先经过 MMU 转换为物理地址,再用于索引 Cache。MMU 还负责维护 Cache 与主存的一致性(如通过属性位控制某块内存是否可缓存)。

在嵌入式开发(如 ARM 启动代码初始化阶段)或特定裸机应用中,有时需要关闭 MMU。关闭 MMU 会产生以下直接影响:

1. 地址映射方式改变:虚拟地址 = 物理地址
  • 直接访问‌:关闭 MMU 后,CPU 发出的地址不再经过转换,直接作为物理地址访问存储器。
  • 编程约束‌:程序必须使用真实的物理地址进行编码和链接。如果代码中仍使用虚拟地址,将导致访问错误的内存位置,引发系统崩溃或数据错误。
2. 内存保护失效
  • 无权限检查‌:所有内存区域变为"可读写/可执行",不再有用户态/内核态之分,也没有只读保护。
  • 风险增加‌:任何程序都可以随意修改任何内存区域,包括内核代码和数据。这使得系统极易受到恶意代码攻击或因程序 Bug 导致整体崩溃。
3. 虚拟内存功能不可用
  • 无法使用 Swap‌:由于没有地址映射机制,操作系统无法实现页面置换(Page Swapping),程序能使用的最大内存受限于实际物理 RAM 的大小。
  • 无进程隔离‌:多任务系统中,进程间不再拥有独立的地址空间,容易相互干扰。
4. Cache 行为可能受影响
  • 配置依赖‌:在某些 ARM 架构中,MMU 的控制位也间接影响 Cache 的有效性或一致性策略。关闭 MMU 时,通常也需要显式关闭或刷新 Cache(I-Cache/D-Cache),以防止因地址转换缺失导致的 Cache 命中错误(即 Cache 中存的是基于虚拟地址索引的数据,但 CPU 现在发的是物理地址)。
  • 性能下降‌:虽然省去了地址转换开销,但如果因此禁用了 Cache,内存访问速度将大幅降低,因为 CPU 必须直接等待较慢的主存响应。
5. 典型应用场景
  • 系统启动初期‌:在 OS 内核初始化页表之前,MMU 必须处于关闭状态,以便引导加载程序(Bootloader)能直接访问物理内存加载内核。
  • 简单裸机系统‌:对于不需要多任务、内存保护或大内存管理的简单嵌入式应用,关闭 MMU 可以简化系统设计,减少上下文切换开销。

总结 ‌:MMU 是现代复杂操作系统(如 Linux、Windows、Android)运行的基石,提供了‌虚拟化 ‌和‌安全性 ‌。关闭 MMU 意味着回归到‌物理地址直接访问‌模式,牺牲了内存保护和扩展能力,但简化了底层硬件交互,常用于系统启动阶段或极简嵌入式环境。

关闭 MMU(内存管理单元)后,硬件层面的虚拟地址转换和基于页表的细粒度内存保护机制将失效。此时,CPU 直接访问物理地址,且默认情况下所有内存区域通常被视为可读写。

要在没有 MMU 的环境下实现内存保护,必须依赖‌替代硬件模块 ‌、‌软件架构设计 ‌以及‌编译器/运行时检查‌。以下是主要的实现策略:

1. 使用 MPU(内存保护单元)作为硬件替代

对于许多嵌入式微控制器(如 Cortex-M3/M4/M7系列),虽然不具备完整的 MMU,但通常配备 ‌**MPU (Memory Protection Unit)**‌。

  • 工作原理‌:MPU 允许定义少量的内存区域(Region,通常为8-16个),并为每个区域设置访问权限(只读、只写、不可执行、特权级访问等)。
  • 优势‌:相比 MMU,MPU 开销极小,不引入地址转换延迟,适合实时系统。
  • 局限性‌:保护粒度较粗(基于大区块而非页),无法实现复杂的虚拟内存映射或进程隔离。
  • 应用 ‌:在 LiteOS 等实时操作系统中,通过 los_mmuparamset 等接口配置 MPU,将代码段设为只读,防止意外修改 。

2. 软件层面的内存管理策略

在没有硬件保护支持的低端 MCU 中,主要依靠软件机制来检测和预防内存错误:

A. 边界检查与哨兵值(Canaries)
  • 栈保护‌:在栈帧中插入"哨兵值"(Stack Canary)。函数返回前检查该值是否被修改,若被修改则说明发生了栈溢出,立即触发异常或复位。
  • 堆保护‌:在动态分配的内存块前后添加保护字(Guard Bytes)。释放内存或定期扫描时检查这些字节,检测堆溢出或越界写入。
B. 内存池与句柄管理
  • 隔离分配 ‌:不使用通用的 malloc/free,而是采用固定大小的内存池(Memory Pool)。每个任务或模块只能从指定的池中分配内存,从而在逻辑上隔离不同模块的数据。
  • 句柄引用‌:应用程序不直接持有内存指针,而是持有"句柄"(Handle)。内核通过句柄查找实际地址,并在访问前验证句柄的有效性。如果句柄无效或指向已释放内存,则拒绝访问 。
C. 软件模拟的权限检查
  • 访问代理‌:所有对关键数据的访问必须通过特定的 API 函数进行。这些函数在读写前检查调用者的身份或状态。
  • 定期完整性校验 ‌:对关键代码段或数据区计算 CRC(循环冗余校验)或哈希值。定期或在关键操作前重新计算并比对,若不一致则表明内存被非法篡改 。注意:这种方法主要用于检测而非实时阻止,且消耗 CPU 周期。

3. 编译器与语言级支持

利用现代编译器和高级语言特性在代码生成阶段插入保护逻辑:

  • ‌**地址 sanitizer (ASan)**‌:在开发调试阶段,启用编译器的地址 sanitization 功能。它会在每次内存访问前后插入检查代码,识别越界访问、使用后释放(Use-after-free)等错误。
  • ‌** Rust 等内存安全语言**‌:使用拥有所有权(Ownership)和借用检查(Borrow Checking)机制的语言。编译器在编译期确保不存在悬垂指针和数据竞争,从根源上消除许多内存安全问题,无需运行时硬件保护 。
  • 沙箱化执行‌:对于需要运行第三方插件的系统,不使用原生机器码,而是使用解释型语言或虚拟机(VM)。虚拟机在执行每条指令前都可以进行安全检查,确保不会访问非法内存区域 。

4. 系统架构设计原则

  • 单地址空间与静态链接‌:在极简系统中,避免动态加载代码。所有模块在编译时静态链接,通过链接脚本严格控制各段的物理地址布局,减少运行时不确定性。
  • 看门狗与故障恢复‌:由于缺乏实时硬件拦截,内存破坏可能导致不可预测的行为。因此,必须配合硬件看门狗(Watchdog Timer)。一旦检测到系统跑飞或死锁(可能是内存破坏的后果),看门狗将强制复位系统,防止错误扩散 。

核心结论 ‌:关闭 MMU 后,‌无法实现像 MMU 那样透明、细粒度且实时的硬件内存保护 ‌。最佳实践是结合 ‌MPU(如果可用) ‌ 进行基础区域保护,并通过 ‌严格的软件架构(内存池、句柄) ‌ 和 ‌**编译器辅助(Rust/ASan)**‌ 来最大限度地降低内存错误风险。对于安全性要求极高的场景,建议选用带有 MMU 或增强型 MPU 的处理器。

相关推荐
T1mzhou2 小时前
ARM64 平台安全学习记录
linux·服务器·arm开发·arm
云栖梦泽4 小时前
网络设备驱动(1)
linux·arm开发·嵌入式硬件
零依赖极客1 天前
Day 9·1 KV 也量化——q8 KV 把缓存与 decode 带宽压到一半
c语言·开发语言·arm开发·人工智能·缓存·矩阵
secondyoung2 天前
I2C通信协议详解
arm开发·驱动开发·stm32·单片机·嵌入式硬件·mcu·51单片机
奔跑的架构师2 天前
[A-50]ARMv9/v8-DVFS系统架构
linux·arm开发·架构·系统架构·arm
零依赖极客2 天前
Day 8·1 自注意力机制:Q·K^T/softmax/V的在线计算
c语言·arm开发·人工智能·llama
T1mzhou2 天前
ARM64 Linux 6.10 内核驱动(14):drivers/base/platform.c:板级设备主战场
linux·c语言·开发语言·arm开发
零依赖极客3 天前
《30 天手搓 ARM 架构零依赖纯 C 推理引擎》课程介绍与大纲
c语言·开发语言·arm开发·人工智能·嵌入式硬件·ai编程
新时代牛马3 天前
ATF/ TEE / REE 与ARM 异常级别EL 安全体系完整篇:TrustZone硬件到 SMC 进OP-TEE的全链路
arm开发·python·安全
T1mzhou3 天前
ARM64 Linux 6.10 内核驱动(13):bus.c / driver.c 总线两张表,驱动怎么挂上去
linux·服务器·c语言·arm开发·arm