4. 内存映射与地址空间
在 VxWorks 中,任务看到的地址几乎都是虚拟地址,真正落到 DDR、SRAM、外设寄存器上的访问,必须经过 MMU 的转换与属性检查。理解这一层,才能解释“同一块内存为什么换个映射方式性能差一倍”“为什么外设寄存器不能随便开缓存”“为什么 DMA 缓冲区必须按缓存行对齐”。本节围绕 MMU 配置、虚实地址转换和缓存属性三个核心问题展开。
一、MMU 在 VxWorks 中到底管什么
VxWorks 的 MMU 主要承担三件事:地址转换、访问权限控制和内存属性定义。地址转换把虚拟地址(VA)映射到物理地址(PA);权限控制决定某段内存是只读、可读写还是不可访问;内存属性则告诉 CPU 这段地址是否可缓存、是否允许乱序访问、是否可共享。三者共同作用,缺一不可。
在 ARM 架构下,VxWorks 通常使用两级页表:一级页表(L1)以 1MB 段或指向二级页表的方式描述映射,二级页表(L2)以 4KB 小页或更粗粒度描述。段映射适合大块连续内存,页映射适合需要精细权限控制的区域。配置时最常打交道的接口是 vxCpuMmuLib 和 vxMmuLib 提供的映射函数,例如 vxMmuMapRegion() 或底层 vxMmuMapPage()。
二、虚拟地址到物理地址的转换过程
以 32 位 ARM 为例,一次数据访问的转换路径可以概括为:CPU 发出 VA → MMU 查 TLB → 未命中则查页表 → 得到 PA 与属性 → 访问物理内存。TLB 是转换旁路缓冲,命中时无需查表,因此 TLB 命中率直接影响访存延迟。页表项中除了物理基地址,还包含 AP(访问权限)、C/B(缓存与缓冲位)、XN(不可执行)等控制位。
下面这张图展示了一个典型的 VxWorks 地址空间布局与转换关系:左侧是虚拟地址空间中的几个关键区域,中间经过 MMU 页表转换,右侧落到实际物理地址。图中同时标出了各区域的缓存属性,便于对照理解。
三、缓存属性设置:性能差异的根源
MMU 页表项中的 C(Cacheable)和 B(Bufferable)位决定了该区域的缓存行为。VxWorks 中常见的属性组合有以下几种:
- Write-Back + Write-Allocate(WBWA):最常用的普通内存属性。写操作先落在 Cache,延迟写回 DDR,读未命中时分配缓存行。适合任务栈、堆、频繁读写的普通数据。
- Write-Through(WT):写操作同时更新 Cache 和 DDR,读可缓存。适合需要与 DMA 共享但又不希望手动维护一致性的缓冲区。
- Non-Cacheable(NC):完全不经过 Cache,每次访问直达物理内存。适合 DMA 描述符、外设寄存器、共享内存。
- Device / Strongly-Ordered:除不缓存外,还禁止访问合并和乱序,保证每次访问严格按程序顺序到达设备。适合 UART、GPIO 等控制寄存器。
属性选错会带来两类典型问题。第一类是性能问题:把频繁访问的普通数据设成 NC,每次读写都走总线,实测带宽可能只有 WBWA 的 1/5 到 1/10。第二类是一致性问题:DMA 写入的缓冲区如果被 CPU 缓存在 Cache 中,CPU 读到的可能是旧数据;CPU 写入的数据如果还在 Cache 里没写回,DMA 读到的也是旧数据。解决方式要么把缓冲区设为 NC,要么在 DMA 传输前后调用 cacheFlush() 和 cacheInvalidate()。
四、一个可参考的映射配置示例
下面给出一个基于 ARM 平台的映射配置片段,展示如何为不同区域设置不同属性。参数为示例值,实际使用时需根据具体 SoC 的地址手册调整。
/* 示例:VxWorks 下配置几段关键映射 */
/* 普通 DDR 用户区:WBWA,可读写,可执行 */
vxMmuMapRegion(0x01000000, /* VA 基址 */
0x01000000, /* PA 基址 */
0x08000000, /* 大小 128MB */
MMU_ATTR_WBWA | MMU_ATTR_RW | MMU_ATTR_X);
/* DMA 缓冲区:Non-Cacheable,可读写,不可执行 */
vxMmuMapRegion(0x40000000,
0x40000000,
0x00100000, /* 1MB */
MMU_ATTR_NC | MMU_ATTR_RW);
/* UART 寄存器:Device,可读写,不可执行 */
vxMmuMapRegion(0xE0000000,
0xE0000000,
0x00001000, /* 4KB */
MMU_ATTR_DEVICE | MMU_ATTR_RW);
/* 共享 SRAM:Non-Cacheable + Shareable */
vxMmuMapRegion(0xF0000000,
0xF0000000,
0x00040000, /* 256KB */
MMU_ATTR_NC | MMU_ATTR_SHARE | MMU_ATTR_RW);
配置完成后,可以通过读取 MMU 相关寄存器或使用 vxMmuShow() 类调试接口查看当前映射表,确认 VA、PA、大小和属性是否与预期一致。如果发现某段地址访问异常,优先检查该段是否被正确映射、权限是否允许、属性是否与访问方式匹配。
五、属性选择对性能的量化影响
为了建立直观感受,可以做一个简单的对比测试:在同一块 DDR 上分别以 WBWA 和 NC 属性映射,然后让 CPU 连续读写 1MB 数据,统计耗时。在典型 ARM Cortex-A9 平台上,WBWA 的连续写带宽可达数百 MB/s 到 1GB/s 量级,而 NC 可能只有几十到一百多 MB/s。这个差距在数据密集型任务中会直接体现为响应时间变长、吞吐下降。
因此,映射配置的原则可以归纳为:普通代码和数据用 WBWA;DMA 缓冲区和跨核共享内存用 NC 或 WT;外设寄存器用 Device 属性;只读常量区可以加 XN 禁止执行以提升安全性。每次修改映射后,都要重新验证功能正确性和性能表现,不能只看“能跑通”就结束。