# dload **Repository Path**: mphyatyh/dload ## Basic Information - **Project Name**: dload - **Description**: No description available - **Primary Language**: Unknown - **License**: BSD-3-Clause - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2026-05-31 - **Last Updated**: 2026-06-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ARM 裸机引导加载器(QEMU mps3-an536) 一个极简的交互式 ARM 引导加载器。可将可重定位的 ELF 可执行文件装入 BRAM 中的任意地址, 加载时绑定重定位,然后跳转执行。运行在 **QEMU 模拟的 MPS3-AN536 FPGA 开发板**上, 处理器为 **Cortex-R52**(ARMv8-R)。所有 I/O 均通过 ARM semihosting 完成——无需 UART 驱动。 ## 功能特性 - **交互式命令循环** — `load ` 装入并运行程序,`quit` 退出 QEMU - **ELF 重定位绑定** — 完整的 ABI 兼容 ARM/Thumb 重定位解析器 - **`.tsk` 预链接优化** — `elf2tsk.py` 离线解析所有 PC-relative 重定位,引导加载器 在装入时只需处理 absolute 重定位,显著提升加载速度 - 支持 **9 种 ARM 重定位类型**:`ABS32`、`REL32`、`THM_CALL`、`THM_JUMP24`、 `THM_MOVW_ABS_NC`、`THM_MOVT_ABS`、`THM_MOVW_PREL_NC`、`THM_MOVT_PREL`、 `PREL31`、`V4BX` - **地址合法性校验** — 拒绝 BRAM 范围外或空间不足的装入请求 - **任意地址装入** — 同一个 `.tsk` 文件可装入 BRAM 内任意合法地址 --- ## 整体架构 ``` QEMU mps3-an536 ┌──────────────────────────────────────────────────────────────────┐ │ │ │ ATCM(32 KB) BRAM(512 KB) DDR(3 GB) │ │ 0x00000000 0x10000000 0x80000000 │ │ ┌──────────────────┐ ┌──────────────────┐ ┌───────────┐ │ │ │ 引导加载器 │ │ 被装入的程序 │ │ .tsk │ │ │ │ (loader.elf) │ │ (reloc_test) │ │ │ │ │ │ │ │ │ │ │ │ │ │ .text ~4 KB │ │ .text + .data │ │ │ │ │ │ .rodata ~1 KB │ │ .rodata │ │ │ │ │ │ .bss ~4 KB │ ────> │ .bss + stack │ │ │ │ │ │ stack 8 KB │ load │ │ │ │ │ │ └──────────────────┘ └──────────────────┘ │ │ │ │ │ │ │ │ QSPI Flash(8 MB) │ │ │ │ 0x08000000 │ │ │ │ ┌──────────────────┐ │ │ │ │ │(ROM) │ │ │ │ │ └──────────────────┘ └───────────┘ │ │ │ └──────────────────────────────────────────────────────────────────┘ ``` ### 内存布局(MPS3-AN536) | 区域 | 基地址 | 大小 | 用途 | |------------|-------------|---------|-------------------------------| | ATCM | `0x00000000` | 32 KB | 引导加载器代码 + 栈 | | QSPI Flash | `0x08000000` | 8 MB | ROM(引导加载器未使用) | | BRAM | `0x10000000` | 512 KB | 被装入的程序 + 栈 | | DDR | `0x80000000` | 3 GB | `.tsk` 原始镜像(QEMU 通过 `-device loader` 预装入) | ### 引导流程 1. QEMU 将 `.tsk` 原始镜像预装入 DDR(`0x80000000`) 2. CPU 从 ATCM `0x00000000` 开始执行引导加载器 3. 引导加载器在 semihosting 控制台显示 `>` 提示符 4. 用户输入 `load 0x10000000`(或其他合法 BRAM 地址) 5. 引导加载器解析 ELF 头和 section 表 6. 以指定的基地址为起点,为每个可分配的 section 分配空间 7. 拷贝 section 数据,清零 `.bss` 8. 处理所有剩余重定位(仅 absolute 类型——PC-relative 重定位已由 `elf2tsk.py` 预解析) 9. 调用被装入程序的 `_start` 10. 被装入程序返回后,控制权回到引导加载器提示符 --- ## 文件说明 | 文件 | 作用 | |-------------------|------| | `startup.s` | 汇编入口(`_start`)、semihosting 辅助函数(`sh_write0`、`sh_readc`、`sh_read`、`sh_exit`)、栈定义 | | `loader_main.c` | 引导加载器——交互式命令循环、ELF 解析、section 加载、重定位绑定 | | `reloc_main.c` | 基于 semihosting 的 `printf` 实现 + 被装入测试程序的 `main()` 入口 | | `reloc_test.c` | 重定位测试套件——覆盖 `ABS32`、`CALL`、`JUMP24`、`MOVW`/`MOVT`、`REL32`、`PREL31` | | `elf2tsk.py` | 预链接工具——解析可重定位 ELF 中所有 PC-relative 重定位,输出仅含 absolute 重定位的 `.tsk` 文件 | | `loader.ld` | 引导加载器链接脚本(ATCM,32 KB) | | `Makefile` | 构建(`make build`)、运行(`make run`)、清理 | | `history.md` | 开发过程记录 | --- ## 使用方法 ### 环境准备 | 工具 | 最低版本 | MSYS2 安装命令 | |---------------------|---------|------------------------------------------------------------| | `arm-none-eabi-gcc` | 13.x | `pacman -S mingw-w64-ucrt-x86_64-arm-none-eabi-gcc` | | `qemu-system-arm` | 10.0 | `pacman -S mingw-w64-ucrt-x86_64-qemu` | | `python3` | 3.9+ | `pacman -S python` | | `make` | 任意 | `pacman -S make` | | `dos2unix` | 任意 | `pacman -S dos2unix` | | `indent` | 任意 | `pacman -S indent` | ### 快速体验 ```bash # 编译所有文件并启动 QEMU make run ``` 在 `>` 提示符下: ``` > load 0x10000000 # 将测试套件装入 BRAM 基地址并运行 > load 0x10040000 # 装入另一个地址运行 > quit # 退出 QEMU ``` ### 自动化测试 通过管道向 QEMU 发送命令: ```bash echo "load 0x10000000" | make run ``` 通过 magic 地址自动装入(多地址测试): ```bash qemu-system-arm -M mps3-an536 -display none -serial none \ -chardev stdio,id=con0 \ -semihosting-config enable=on,target=native,chardev=con0 \ -kernel loader.elf \ -device loader,file=reloc_test.tsk,addr=0x80000000,force-raw=on \ -device loader,addr=0x10007FF0,data=0x10020000,data-len=4 ``` ### 在此基础之上继续开发 1. 编写你自己的 `.c` 源文件。可直接调用 `reloc_main.c` 提供的 `printf()`(基于 semihosting),或直接调用 `sh_write0()` / `sh_exit()`。 2. 在 Makefile 的 `reloc_test.elf` 规则中加入你的 `.c` 文件: ```makefile reloc_test.elf: startup.s reloc_main.c reloc_test.c my_module.c $(CC) $(CFLAGS) -c -o startup.o startup.s $(CC) $(CFLAGS) -c -o reloc_main.o reloc_main.c $(CC) $(CFLAGS) -c -o reloc_test.o reloc_test.c $(CC) $(CFLAGS) -c -o my_module.o my_module.c $(LD) -r -o $@ startup.o reloc_main.o reloc_test.o my_module.o rm -f *.o ``` 3. 在 `reloc_main.c` 的 `main()` 中调用你的代码。 4. 执行 `make run`——引导加载器会将你的程序装入指定地址。 ### 代码风格 所有 C 代码采用 **Linux 内核代码风格**,使用 **Unix 换行符**。提交前请运行: ```bash indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs -cp1 *.c dos2unix *.c *.s *.ld Makefile *.py ```