如果说 RIF 是外设所有权的"物权法",那么 Memory Map (内存地图) 就是多核系统的"领土疆域图"。在 STM32MP257 这种异构系统中,M33 核和 A35 核共享物理内存地址空间,但如果不划清界限,就会发生"踩踏事件",导致系统随机崩溃或内核死锁。
本章我们将手把手编写链接脚本(Linker Script),并在物理层面上彻底完成内存的割裂。
7.1 STM32MP257 内存布局解析
STM32MP257 拥有多层级的存储结构,我们需要对其进行战术分配:
-
SYSRAM (SRAM1/2/3):位于 SoC 内部,低延迟,掉电丢失。适合存放 M33 的关键代码和实时栈。
-
RETRAM (Retained SRAM):低功耗域内存,适合存放跨核通讯的握手信号。
-
DDR4/LPDDR4:外部大容量内存(通常 1GB~4GB)。A35 的主战场,但我们要从中"割"出一块给 M33 存放非关键大数据。
推荐实战分配表:
| 物理地址区间 | 长度 | 分配目标 | 备注 |
|---|---|---|---|
0x0E000000 |
256KB | M33 Code/Data | 存放 M33 的 ELF 运行镜像 |
0x90000000 |
2MB | Shared Memory | M33 与 A35 的 IPC 缓冲区 |
0x90200000 |
-- | Linux Kernel | A35 Linux 系统起始 |
7.2 深度实战:编写 M33 链接脚本 (.ld)
我们需要告诉编译器,把 .text(代码)和 .data(变量)放到正确的地方。
/* STM32MP257F_M33_FLASH.ld */
MEMORY
{
/* M33 运行的主内存:SRAM1 */
RAM (xrw) : ORIGIN = 0x0E000000, LENGTH = 256K
/* 预留给 IPC 的共享内存 */
SHM (rw) : ORIGIN = 0x90000000, LENGTH = 2M
}
SECTIONS
{
/* 向量表必须放在起始位置 */
.isr_vector :
{
. = ALIGN(8);
KEEP(*(.isr_vector))
. = ALIGN(8);
} > RAM
/* 代码段 */
.text :
{
. = ALIGN(8);
*(.text)
*(.text*)
. = ALIGN(8);
} > RAM
/* 共享内存段:用于定义跨核通讯变量 */
.shared_data (NOLOAD) :
{
. = ALIGN(4096);
*(.ipc_shm)
. = ALIGN(4096);
} > SHM
/* 堆栈空间定义 */
._user_stack :
{
. = ALIGN(8);
. = . + 0x2000; /* 8KB Stack */
. = ALIGN(8);
} > RAM
}
7.3 Cache 一致性:不可忽视的幽灵
这是多核开发中最难抓的 Bug。A35 拥有强大的 L1/L2 Cache,M33 也有 D-Cache。
-
场景 :M33 把 IMU 数据写到了
0x90000000。 -
问题:A35 读取该地址时,可能直接从自己的 Cache 里读到了旧数据,而没有去 DDR 物理地址读。
实战解决方案:
-
针对 M33 :使用 MPU (Memory Protection Unit) 将共享内存区域配置为 Device 或 Strongly-ordered 属性,禁用 Cache。
-
针对 A35 :在 Linux 设备树中将该区域标记为
no-map或在驱动中使用dma_alloc_coherent。
7.4 内存隔离保护 (RISAF) 代码实现
在 RIF_Init 中,我们要通过 RISAF 锁定这块地盘,防止 Linux 启动后"越界"。
void RIF_Memory_Protection_Init(void) {
// 配置 RISAF:将 0x0E000000 区域锁定给 CID1 (M33)
// 这样即便 A35 侧出现指针跑飞,也无法修改 M33 的代码
RIF_RISAF1->REGION[0].START_ADDR = 0x0E000000;
RIF_RISAF1->REGION[0].END_ADDR = 0x0E03FFFF;
RIF_RISAF1->REGION[0].CIDCFGR = (1 << RIF_RISCF_CIDCFGR_SCID_Pos) | RIF_RISCF_CIDCFGR_CONF;
}
7.5 引导 Linux 的前哨战:预留内存
在 M33 引导 Linux 之前,我们必须在 M33 侧定义好 Linux 的入口地址。通常我们将 U-Boot 加载到 DDR 的某个固定偏移(如 0x80800000)。
在本章的实验中,我们先不启动 A35,但要确保 M33 能够成功读写 DDR 空间。 实验验证:
-
编写一个循环,M33 往
0x90000000写入一个递增序列。 -
使用调试器(J-Link/ST-Link)查看该内存地址,确认写入成功。
7.6 避坑指南 (Debug Tips)
-
对齐问题:MP257 的资源隔离通常以 4KB 或 64KB 为最小页单位。如果你的内存分配没有对齐到页边界,RIF 配置会失效。
-
地址重映射 :注意 M33 看到的地址与 A35 看到的地址在某些总线视角下可能存在偏移(虽然在 MP257 中大部分是统一编址),务必对照参考手册确认 Bus Matrix。
章节小结
通过本章,我们完成了 M33 的"深挖洞、广积粮"。M33 现在拥有了受保护的运行内存和用于跨核交换的共享内存。