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 头部
- 探测 Flash
sf probe 0
- 将 Kernel A flash分区 (偏移 0x80000) 读入 DDR 0x80400000 ,读取大小 0x680000 (6.5MB)
sf read 0x80400000 0x00080000 0x680000
- 打印 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 地址重叠导致系统挂死(后续补充)