【发布时间】:2020-07-13 17:21:48
【问题描述】:
我正在尝试在包含 MIPS 24KEc 处理器的交换机上使用 custom bootloader 启动压缩内核 (vmlinuz)。这个引导加载程序不是我编写的,它存在于产品的 NOR 闪存中,源代码由供应商在其 GPL 存档中提供。
引导加载程序从闪存中的固定位置读取一个标头,其中包含:
- 标题魔法 (SPIM)
- 内核加载地址
- 要加载的数据长度
- 内核入口地址
然后,它将标头后面的 num_bytes 复制到内核加载地址并跳转到指定的入口地址。引导命令行和 initrd 被编译到内核映像中(通过 CONFIG_CMDLINE 和 CONFIG_INITRAMFS_SOURCE)。
未压缩的内核映像 (vmlinux) 正常启动。当我尝试启动压缩内核时,我没有来自解压缩器或内核的任何输出。
我注意到Linux kernel saves the argument registers 在清除 BSS 并跳转到解压器之前(来自 arch/mips/boot/compressed/head.S):
start:
/* Save boot rom start args */
move s0, a0
move s1, a1
move s2, a2
move s3, a3
我是 MIPS 程序集的新手,但我知道上述移动语句正在将参数寄存器保存到已保存的寄存器中。保存的寄存器在内核解压后、跳转到内核入口点之前恢复:
move a0, s0
move a1, s1
move a2, s2
move a3, s3
PTR_LI k0, KERNEL_ENTRY
看了u-boot源码,想知道this call in boot_jump_linux是否对应上面提到的“boot rom start args”:
kernel(linux_argc, (ulong)linux_argv, (ulong)linux_env,
linux_extra);
我找不到任何内核文档来解释内核期望引导 rom 在寄存器 a0、a1、a2 和 a3 中传递给它的参数。
【问题讨论】:
-
是的,这似乎是正确的。请注意,它们被存储到
fw_arg0..3中,然后平台代码访问它们,例如argc = fw_arg0; -
可能值得在像 QEMU 这样的模拟器中尝试相同的引导加载程序 + 内核,看看它是否在那里工作。您可以连接到 QEMU 作为 GDB 远程和单步/设置断点,以查看应该如何工作。但是,模拟机器可能具有与路由器不同的硬件设备,因此在内核中测试早期启动 asm 调试打印指令可能很难确定它们是否应该在真实硬件上工作。
-
@PeterCordes 我已经尝试在 qemu 中加载引导加载程序/内核,但不幸的是,它们都没有将任何内容打印到串行。不过,我还没有尝试过 qemu+gdb。我想我总是可以修改马耳他机器定义,使其具有与交换机 ASIC 相同地址的 uart 端口。
-
试图在没有调试器的情况下在 asm 中查找问题就像试图构建一个蒙着眼睛的机器人。许多小规模/局部问题在盯着源头时很容易错过,但当您可以单步执行并观察寄存器值的变化时就非常明显了。尤其是在大范围内,只有一条信息是“不起作用”,这使得缩小搜索范围变得困难。与找到您陷入的循环相比,或者发生的故障可能是巨大的。所以是的,IMO 值得付出巨大的努力,让调试器甚至间接使用成为可能,并获得在模拟机器上工作的东西
-
在真正的硬件(未压缩内核)上工作的东西是否也可以在你的 QEMU 客户机中工作?如果是这样,那么您就有了一个众所周知的良好起点。
标签: assembly linux-kernel mips