初学日志
- MMU内存管理单元
-
-
- [硬件核心:MMU 与页表 (Page Table) 的机制](#硬件核心:MMU 与页表 (Page Table) 的机制)
- 设备树
- [一、 核心硬件架构:从 MCU 到 MPU 的跨越](#一、 核心硬件架构:从 MCU 到 MPU 的跨越)
- **芯片架构与定位**
- [**STM32MP135F-DK 探索套件核心资源**](#STM32MP135F-DK 探索套件核心资源)
- [**专属电源管理芯片 (STPMIC1)**](#专属电源管理芯片 (STPMIC1))
-
- [二、 内存管理核心:MMU 与页表机制](#二、 内存管理核心:MMU 与页表机制)
- **物理地址与虚拟地址**
- [**页表 (Page Table) 与 PTE**](#页表 (Page Table) 与 PTE)
-
- [三、 嵌入式 Linux 软件栈 (OpenSTLinux)](#三、 嵌入式 Linux 软件栈 (OpenSTLinux))
- [**系统启动"接力赛"** 一个完整的嵌入式 Linux 系统启动包含四个严格的阶段:](#系统启动“接力赛” 一个完整的嵌入式 Linux 系统启动包含四个严格的阶段:)
-
- [四、 静态硬件映射:设备树 (Device Tree)](#四、 静态硬件映射:设备树 (Device Tree))
- [五、 动态硬件控制:Linux 驱动模型](#五、 动态硬件控制:Linux 驱动模型)
-
MMU内存管理单元
硬件核心:MMU 与页表 (Page Table) 的机制
当系统启用 MMU 后,CPU 流水线发出的所有地址将不再直接输出到芯片内部的 AMBA 总线(如 AXI/AHB),而是首先交由 MMU 进行处理。
页表机制 :Linux 内核会在物理内存(DDR)中维护一个树状数据结构,称为页表 (Page Table)。页表的核心单元是 PTE (Page Table Entry)。每个 PTE 记录了"一块虚拟地址空间(通常为 4KB 的页)对应哪一块物理地址空间",同时包含该内存块的访问属性(如可读/可写、用户/超级用户特权级、是否允许缓存等)。
(为什么是 4KB?) 综合来看,4KB 的页大小是一个平衡点:不至于造成太大内存浪费。对于 32 位芯片,其地址空间为 2^32,即 4GB。若按 4KB 分页,总共约有 100 万个页。每个页表项 (PTE) 通常占 4 字节,因此单级页表仅需约 4MB 内存即可映射整个 4GB 地址空间,开销较为合理。
TTBR 寄存器 :Cortex-A7 处理器内部设有特殊的控制寄存器(如 TTBR0 和 TTBR1),用于存放页表在物理内存中的基地址。
地址翻译:当 CPU 访问一个虚拟地址时,硬件 MMU 会自动根据该地址查找页表,将其转换为对应的物理地址,再将寻址信号发送至实际的硬件外设或 DDR 芯片。为了加速这一过程,MMU 内部集成了 TLB(快表),用于缓存最近使用的地址映射关系。
设备树
一、 核心硬件架构:从 MCU 到 MPU 的跨越
芯片架构与定位
**MCU(如 STM32F103/H750)**:运行在扁平物理地址空间,直接操作寄存器,无内存隔离,主要运行裸机或实时操作系统(RTOS)。
**MPU(如 STM32MP135)**:基于 Arm Cortex-A7 核心,主频高达 1 GHz。其最核心的标志是引入了**内存管理单元 (MMU)**,支持虚拟内存技术,从而能够运行复杂的嵌入式 Linux 系统。
STM32MP135F-DK 探索套件核心资源
**存储系统**:由于 Linux 系统的巨大开销,MPU 必须外挂大容量存储。该板载配备了 512MB (4-Gbit) 的 DDR3L 内存,并通过 MicroSD 卡槽加载包含 U-Boot、内核及根文件系统的完整镜像。
**外设接口**:具备双 10/100 Mbit/s 以太网(支持局域网唤醒)、Wi-Fi/蓝牙、多个 USB 接口、MIPI CSI-2 摄像头接口以及 4.3 英寸电容触摸屏。
专属电源管理芯片 (STPMIC1)
**功能**:作为系统的"心脏",STPMIC1 负责将 USB 输入的 5V 电压转换为 MPU 所需的多种精确电压。它包含高效率的 BUCK 通道(如给 CPU 和 DDR 供电)和低噪声的 LDO 通道(如给 ADC、USB PHY 供电)。
**智能唤醒机制**:为追求极致低功耗,系统深度休眠时会切断主 CPU 供电。唤醒按键 (B3) 直接连接至 STPMIC1 的 PONKEY 引脚;STPMIC1 被触发后恢复主板供电,并通过专属引脚向 CPU 发送唤醒指令恢复 Linux 运行。
二、 内存管理核心:MMU 与页表机制
物理地址与虚拟地址
**物理地址**:芯片设计时硬连线定死的客观存在(如外设寄存器的绝对基地址),CPU 在裸机状态下直接对其进行读写。
**虚拟地址**:由操作系统和 CPU 分配的"虚拟门牌号",各个应用进程拥有独立受保护的虚拟地址空间,实现了极高的系统安全性与隔离性。
页表 (Page Table) 与 PTE
**映射机制**:MMU 在内存中维护页表字典。其核心单元 **PTE (Page Table Entry)** 记录了虚拟页到物理页帧的映射关系,并包含读写/特权级/Cache 等内存属性限制。
**黄金折中点 (4KB 页大小)**:Linux 通常采用 4KB 作为基础分页粒度。这一大小巧妙平衡了"页表体积(避免占用过多内存)"与"内部碎片浪费",且完美契合硬盘的 4KB 物理扇区以优化 I/O 效率。
三、 嵌入式 Linux 软件栈 (OpenSTLinux)
系统启动"接力赛"
一个完整的嵌入式 Linux 系统启动包含四个严格的阶段:
**TF-A (Trusted Firmware-A)**:底层安全固件,负责初始化基础硬件和安全环境。
**U-Boot**:引导加载程序,将 Linux 内核和设备树加载到内存。
**Linux Kernel**:操作系统核心,负责内存、进程调度和底层驱动。
**RootFS (根文件系统)**:包含共享库和用户空间工具(如 Python 解释器)。
- 开发流模式开发者不需要从零编写 Linux。核心工作是"做减法与定制":通过 Yocto 或 Buildroot 裁剪不需要的内核模块,定制根文件系统,配置设备树,最终在应用层使用标准 POSIX 接口进行业务开发。
四、 静态硬件映射:设备树 (Device Tree)
- 核心设计思想为了解决 Linux 内核源码因硬编码不同主板引脚而变得极度臃肿的问题,引入了设备树。它将"硬件配置"与"内核通用代码"彻底剥离。
- 设备树的作用 设备树是一份"硬件说明书",它使用特定的语法(
.dts文件)如实记录了外设是否启用、引脚连接方式、中断号以及物理基地址等客观参数。设备树本身不分配任何虚拟地址。 - 自动生成在实际工业开发中,开发者通常使用 STM32CubeMX 图形化工具来分配外设和引脚,软件会自动查阅"寄存器字典"并生成对应的设备树文件。
五、 动态硬件控制:Linux 驱动模型
-
映射机制 (
ioremap)驱动程序加载时,会解析设备树获取硬件的物理基地址。随后,驱动调用
ioremap(物理地址, size)内核函数。- 该函数在内核
vmalloc区域寻找一块空闲的虚拟地址,并修改 MMU 页表 (PTE) 建立物理到虚拟的"虫洞"映射。 - 在 PTE 属性中,这段内存会被强制标记为 Device Memory,强制绕过 CPU Cache,确保指令按强顺序模型实打实地到达硬件。
- 该函数在内核
-
寄存器读写与位运算
**偏移地址**:寄存器的偏移地址由芯片出厂硬连线定死,通常作为宏定义写在 C 语言驱动代码中(目标操作地址 = `ioremap` 虚拟基地址 + 偏移地址)。 **原子化位运算**:由于 32 位寄存器内通常打包了多个引脚的状态,直接赋值会干扰其他引脚。因此必须使用"读-改-写"的位运算(如 `val |= (1 << 13)`)实现对目标位(如第 13 位)的精准修改。- 内核提供专属的
readl()和writel()宏进行操作,它们底层封装了内存屏障指令,保证时序稳定。
- 内核提供专属的
-
接口封装与应用调用 底层驱动在完成所有的物理映射与寄存器操作后,将其封装为一个简单的设备节点文件(如
/dev/led)。应用层只需调用open、write等标准文件操作接口即可控制硬件,彻底实现了底层复杂性对上层的透明化。