You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QEMU中DTB加载位置咨询——AArch64 Linux Bootloader开发

问题分析与解决

核心问题1:QEMU启动命令错误

你当前使用-kernel pflash.bin的方式是错误的——-kernel参数用于让QEMU直接将指定内核镜像加载到RAM,而非从pflash分区读取内核。正确的启动命令应通过-drive指定pflash设备:

qemu-system-aarch64 -nographic -machine virt -cpu cortex-a72 -drive if=pflash,file=pflash.bin,format=raw -initrd initramfs.cpio.gz -serial mon:stdio -m 2G -smp 4

核心问题2:内核未从pflash复制到RAM

你的pflash布局中,内核被写入到50MB偏移处(seek=50),对应物理地址为FLASH_START + 50*1024*1024 = 0x000100000 + 0x3200000 = 0x003300000。但Bootloader直接跳转到RAM地址0x43280000,此时内核仍在只读的pflash MMIO区域,无法直接执行——必须先将内核镜像复制到RAM的正确加载地址。

AArch64 Linux内核的加载规则:

  • 未压缩的Image镜像必须加载到物理地址0x80080000,入口点即为该地址。
  • 压缩的zImage/Image.gz可加载到RAM中任意空闲区域(需避开Bootloader、栈、DTB等),入口点为其加载地址。

关于DTB的位置

使用自定义Bootloader从pflash启动时,QEMU不会自动加载DTB到RAM,需手动处理:

  1. 获取QEMU virt平台DTB:可从Linux内核源码arch/arm64/boot/dts/qemu/virt.dtb路径获取,或通过qemu-system-aarch64 -machine virt,dumpdtb=virt.dtb命令导出。
  2. 将DTB写入pflash空闲区域(比如seek=100,即100MB偏移处),对应物理地址0x000100000 + 0x6400000 = 0x006500000。
  3. 在Bootloader中,将DTB从pflash复制到RAM空闲区域(比如RAM_START + 0x100000即0x40100000,需避开栈和Bootloader代码),再将该地址存入x0寄存器传递给内核。

Bootloader需补充的关键操作

当前Bootloader缺少核心步骤,以下是修改思路(示例汇编代码):

.section ".text.startup"
.global _start

STACK_TOP = 0x40800000  // RAM_START + 8MB,避开前8MB的DTB/Bootloader区域
KERNEL_PFLASH_ADDR = 0x003300000  // FLASH_START + 50MB
KERNEL_RAM_ADDR = 0x80080000
KERNEL_SIZE = 0x800000  // 假设内核大小不超过8MB
DTB_PFLASH_ADDR = 0x006500000  // FLASH_START + 100MB
DTB_RAM_ADDR = 0x40100000
DTB_SIZE = 0x10000  // 假设DTB大小不超过64KB

_start:
    // 设置栈
    mov sp, #STACK_TOP

    // 复制内核从pflash到RAM
    ldr x0, =KERNEL_PFLASH_ADDR
    ldr x1, =KERNEL_RAM_ADDR
    ldr x2, =KERNEL_SIZE
    bl memcpy

    // 复制DTB从pflash到RAM
    ldr x0, =DTB_PFLASH_ADDR
    ldr x1, =DTB_RAM_ADDR
    ldr x2, =DTB_SIZE
    bl memcpy

    // 准备内核启动参数:x0=DTB地址,x1/x2保留为0
    ldr x0, =DTB_RAM_ADDR
    mov x1, #0
    mov x2, #0

    // 跳转到内核入口
    ldr x3, =KERNEL_RAM_ADDR
    br x3

// 简单内存复制函数:源地址x0,目标地址x1,长度x2
memcpy:
    cbz x2, memcpy_done
    ldrb w3, [x0], #1
    strb w3, [x1], #1
    sub x2, x2, #1
    b memcpy
memcpy_done:
    ret

额外注意事项

  • 确保链接脚本link.ld将Bootloader代码加载到TEXT_START(0x40080000),且栈的位置不会覆盖Bootloader、内核和DTB。
  • 若使用initrd,需将initramfs复制到RAM后,在DTB的chosen节点添加initrd-start和initrd-end属性,以此告知内核initramfs的位置。

内容的提问来源于stack exchange,提问作者Vladouch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 19:55:18