ARMv8 Linux无Bootloader手动启动:如何传递initrd、dtb及命令行给内核
手动启动ARMv8 Linux:参数传递指南
核心结论:FDT的传递寄存器
ARMv64架构下,Linux内核启动时必须将FDT(设备树二进制文件)的物理地址传入X0寄存器。你贴的arch/arm64/kernel/head.S代码已经明确验证了这一点:mov x21, x0 // x21=FDT,内核直接把X0的值当作FDT地址保存并后续解析。
initrd与内核命令行的传递方式
这两个信息不需要单独通过寄存器传递,而是直接写入你加载到内存的FDT文件中:
- 内核命令行:在FDT的
/chosen节点下添加bootargs属性,值为你的命令行字符串(例如console=ttyAMA0 root=/dev/ram rw) - initrd位置:在FDT的
/chosen节点下添加linux,initrd-start和linux,initrd-end属性,分别填入initrd在内存中的起始物理地址和结束物理地址(注意是物理地址,不是虚拟地址)
ARMv7与ARMv64启动参数的差异对比
ARMv7 U-Boot的参数传递逻辑
if (CONFIG_IS_ENABLED(OF_LIBFDT) && images->ft_len) r2 = (unsigned long)images->ft_addr; else r2 = gd->bd->bi_boot_params; if (!fake) { #ifdef CONFIG_ARMV7_NONSEC if (armv7_boot_nonsec()) { armv7_init_nonsec(); secure_ram_addr(_do_nonsec_entry)(kernel_entry, 0, machid, r2); } else #endif kernel_entry(0, machid, r2); } #endif
ARMv7架构下,U-Boot通过R2传递FDT或ATAGs地址,同时R1传入机器ID(仅非设备树启动时生效),R0固定为0。
ARMv64 Linux内核的参数处理逻辑
/* * Preserve the arguments passed by the bootloader in x0 .. x3 */ SYM_CODE_START_LOCAL(preserve_boot_args) mov x21, x0 // x21=FDT adr_l x0, boot_args // record the contents of stp x21, x1, [x0] // x0 .. x3 at kernel entry stp x2, x3, [x0, #16] dmb sy // needed before dc ivac with // MMU off add x1, x0, #0x20 // 4 x 8 bytes b dcache_inval_poc // tail call SYM_CODE_END(preserve_boot_args)
ARMv64完全抛弃了机器ID的概念,统一依赖FDT传递所有启动参数,寄存器约定简化为:
- X0 = FDT物理地址(必须正确设置)
- X1-X3:保留,建议设为0(内核会忽略这些值)
启动前的关键注意事项
- 确保FDT、initrd、内核镜像都加载到符合内核要求的物理内存区域(避免落在内核镜像占用区或MMU开启后会被覆盖的区域)
- 跳转内核入口前,CPU需处于EL1非安全模式,关闭MMU和Cache(或遵循内核要求的缓存状态)
- FDT必须是完整有效的二进制文件,不能有语法错误,否则内核启动会失败
内容的提问来源于stack exchange,提问作者wangt13
相关产品推荐
相关产品推荐

