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 地址重叠导致系统挂死(后续补充)

相关推荐
琥珀.3 小时前
mysql中json数组转列表查询
linux·运维·服务器
dawnsky.liu3 小时前
在 RHEL 中使用 goose 实现远程主机管理
linux·运维·ai
Linux运维技术栈5 小时前
CVE-2026-91403 高危漏洞修复:Rocky Linux 9 多版本 JDK 环境清理实操
java·linux·运维
slongzhang_6 小时前
linux 递归删除源码文件|递归删除目录下 *.js,但排除 *.min.js
linux·开发语言·javascript
叼烟扛炮6 小时前
Linux 学习笔记(三十三):线程互斥——互斥锁(Mutex)与死锁
linux·运维·服务器·笔记·学习·1024程序员节
无足鸟ICT7 小时前
【RHCA+】who命令(查看已登陆用户)
linux·运维·服务器
Escalating_xu7 小时前
【Linux 网络编程】应用层协议 HTTP(下):Header、连接管理与 C++ HTTP 服务器
linux·服务器·网络
GeW9 小时前
新质生产力路线图落地,Linux运维与数据库架构师的机会清单
linux
Brilliantwxx9 小时前
【Linux】 文件访问与路径解析:目录、文件名、dentry、路径缓冲与 dcache 全解析
linux·运维·服务器·开发语言·spring
father_122710 小时前
Greenplum 集群故障恢复与主备同步机制实战
linux·网络·greenplum