arm linux ddr 内存布局

1. 512MB DDR 内存分布规划

假设系统物理内存基址为 0x80000000,大小为 0x20000000(512MB)。

地址范围 大小 用途 运行时属性
0x80000000 - 0x800FFFFF 1 MB Secure Monitor / ATF 安全世界(EL3)
0x80100000 - 0x803FFFFF 3 MB U-Boot 裸机运行,Cache 开启
0x80400000 - 0x80DFFFFF 10 MB Kernel 加载区 (Image) 压缩/未压缩内核镜像存放地
0x80E00000 - 0x80EFFFFF 1 MB 设备树 (DTB) 硬件描述结构
0x80F00000 - 0x88FFFFFF 128 MB Rootfs(SquashFS/UBIFS 映射) 通常为只读文件系统缓存区
0x89000000 - 0x9BFFFFFF ~300 MB 堆 (Heap) / 用户态空间 malloc、mmap 分配区
0x9C000000 - 0x9FFFFFFF 64 MB 内核栈 / 内核堆 / 异常向量 栈向下增长(高地址→低地址)

2. 512Mbit (64MB) Flash 分区规划

lash 物理地址从 0x00000000 开始,总大小 0x04000000。

分区名 起始地址 结束地址 大小 存储内容
Bootloader 0x00000000 0x0005FFFF 384 KB SPL + U-Boot
Env / Param 0x00060000 0x0007FFFF 128 KB MAC 地址、启动参数
Kernel A 0x00080000 0x006FFFFF 6.5 MB 系统 A 内核镜像
Rootfs A 0x00700000 0x01FFFFFF 25 MB 系统 A 根文件系统
Kernel B 0x02000000 0x0267FFFF 6.5 MB 系统 B 内核镜像(双系统)
Rootfs B 0x02680000 0x03EFFFFF 25 MB 系统 B 根文件系统
Reserved 0x03F00000 0x03FFFFFF 1 MB OTP/工厂校准数据

数据结构定义:内核头 & Squashfs 头

1. ARM64 Linux 内核镜像头 (Image)

复制代码
struct arm64_image_header {
    uint32_t magic;          // 固定值 0x644D5241 ("ARM\x64")
    uint32_t text_offset;    // 内核文本段偏移
    uint32_t image_size;     // 内核镜像总大小
    uint32_t flags;          // 启动标志(如 4K/64K 页)
    uint64_t res3;
    uint64_t res4;
    uint32_t version;        // 版本号
    uint32_t res5;
    uint64_t res6;
    uint64_t res7;
    uint64_t res8;
};

2. Squashfs 文件系统超级块

Squashfs 镜像头部固定位于文件偏移 0 处,结构体定义如下:

复制代码
struct squashfs_super_block {
    __le32 s_magic;          // 固定魔数 0x73717368 ("hsqs")
    __le32 inodes;           // 节点数量
    __le32 bytes_used;       // 已使用字节数(镜像有效大小)
    __le32 uid_start;        // UID 表起始
    __le32 guid_start;       // GID 表起始
    __le32 xattr_id_start;   // xattr 表起始
    __le32 id_table_start;   // ID 表起始
    __le32 s_major;          // 主版本号
    __le32 s_minor;          // 次版本号
    __le16 block_size;       // 块大小(如 4K/8K/16K)
    __le16 compression;      // 压缩算法(1=Zlib, 2=LZMA, 3=LZO)
    // ... 后续还有更多字段
};

3,单板的启动过程数据交互流程

Flash -> DDR 各阶段数据流向分析

阶段 源地址 (Flash) 目标地址 (DDR) 数据内容 校验方法
Stage 1:BootROM 0x00000000 内部 SRAM(非 DDR) SPL 前 4KB 硬件 CRC
Stage 2:U-Boot 加载 0x00080000 (Kernel) 0x80400000 压缩内核 md.l 0x80400000 查魔数
Stage 3:U-Boot 加载 0x00700000 (Rootfs) 0x80F00000 Squashfs 镜像 md.b 0x80F00000 查 "hsqs"
Stage 4:内核启动 DDR 0x80400000 自解压到 0x80008000 解压后的内核 内核 bootm 校验
Stage 5:挂载 Rootfs Flash 0x00700000 通过 MTD/UBI 映射,不整块拷贝 文件系统节点 cat /proc/mtd 检查挂载点

4,数据读取流程

(1) 读取并验证 Kernel 头部

  1. 探测 Flash

sf probe 0

  1. 将 Kernel A flash分区 (偏移 0x80000) 读入 DDR 0x80400000 ,读取大小 0x680000 (6.5MB)

sf read 0x80400000 0x00080000 0x680000

  1. 打印 ddr Kernel 头前 64 字节 (32位字,共 16 个)

md.l 0x80400000 0x10

预期输出分析:

80400000: 644d5241 00000000 00c16000 00000000 # magic = 0x644d5241 (正确!) 80400010: 00000000 00000000 00000001 00000000 # version=1, image_size ~ 12.7MB ...

  • 若 md.l 输出首位为 0x644d5241,则内核镜像有效。

  • 若首位为 0xFFFFFFFF 或 0x00000000,说明 Flash 读取失败或分区为空。

2. 读取并验证 Squashfs 头部

读取flash Rootfs A 分区 (偏移 0x700000)到 DDR 0x80F00000

sf read 0x80F00000 0x00700000 0x1900000

按字节打印ddr前 64 字节(因为魔数是字符 "hsqs")

md.b 0x80F00000 0x40

预期输出分析:

80F00000: 68 73 71 73 88 8b 02 00 03 00 00 00 ... # "hsqs" 即为有效魔数

偏移 0x00 处应为 68 73 71 73(即 ASCII 字符 h s q s)。

3. 查看内核栈/堆的默认数据(未使用前为 0)

栈区通常初始化为 0 或特定填充值(如 0xAAAAAAAA)。读取栈底附近:

md.l 0x9FFFE000 0x10

5,堆/栈与 Rootfs 地址重叠导致系统挂死(后续补充)

相关推荐
龙腾-虎跃1 小时前
Linux 趣味实战|纯 Bash Shell 脚本实现俄罗斯方块终端小游戏(完整源码资源)
linux·运维·bash
阳光九叶草LXGZXJ8 小时前
达梦数据库-报错-15-列【XXX】长度超出定义
linux·运维·数据库·sql·学习
奔跑的大白啊8 小时前
多容器共享目录权限踩坑记
linux·ubuntu·共享目录·linux权限·docker 容器化部署
女神下凡11 小时前
芯参谋(43):DDR4_电路设计指南
arm开发·单片机·嵌入式硬件·设计规范
Android系统攻城狮11 小时前
Linux Gstreamer深度解析之gst_audio_encoder_set_frame_max调用流程与实战(六十一)
android·linux·运维·音视频·gstreamer音视频·音视频进阶·gstreamer音视频进阶
H.莓飛12 小时前
【C++】命名空间、缺省参数、函数重载与引用
linux·开发语言·c++·visual studio
91刘仁德12 小时前
IP协议详解:从IP协议头到网段划分、路由与NAT
linux·服务器·网络·网络协议·tcp/ip
硅基手札13 小时前
【Linux内核专栏 14】网络协议栈
linux·运维·网络协议
沫璃染墨15 小时前
《Linux工程实践篇(一):认识设计模式——从日志系统看策略模式》
linux·c++·安全·设计模式·策略模式