bootloader启动参数传递

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/rikeyone/article/details/86573584

arm平台

 /*
  * Kernel startup entry point.
  * ---------------------------
  *
  * This is normally called from the decompressor code.  The requirements
  * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,
  * r1 = machine nr, r2 = atags or dtb pointer.
  *
  * This code is mostly position independent, so if you link the kernel at
  * 0xc0008000, you call this at __pa(0xc0008000).
  *
  * See linux/arch/arm/tools/mach-types for the complete list of machine
  * numbers for r1.
  *
  * We're trying to keep crap to a minimum; DO NOT add any machine specific
  * crap here - that's what the boot loader (or in extreme, well justified
  * circumstances, zImage) is for.
  */

arch/arm/kernel/head.S文件定义了bootloader和kernel的参数传递要求:

MMU = off, D-cache = off, I-cache = dont care, r0 = 0, r1 = machine nr, r2 = atags or dtb pointer. 

因此在内核的主入口函数,需要传递3个参数,r0/r1/r2。

arm64平台

/*
 * Kernel startup entry point.
 * ---------------------------
 *
 * The requirements are:
 *   MMU = off, D-cache = off, I-cache = on or off,
 *   x0 = physical address to the FDT blob.
 *
 * This code is mostly position independent so you call this at
 * __pa(PAGE_OFFSET + TEXT_OFFSET).
 *
 * Note that the callee-saved registers are used for storing variables
 * that are useful before the MMU is enabled. The allocations are described
 * in the entry routines.
 */

ARM64对启动时的x0~x3这四个寄存器有严格的限制:x0是dtb的物理地址,x1~x3必须是0。因此在内核的主入口函数,需要传递4个参数,x0/x1/x2/x3。

dtb传递

目前新版的kernel支持device tree的启动方式,同时保持了对旧的tag list的支持。对于arm32平台,按照使用dtb进行设备描述的平台,r0/r1都应该传递0,r2传递dtb的内存地址;对于arm64平台,x0为dtb的物理地址,而x1/x2/x3寄存器都是0。

我们以UEFI启动的最后部分来分析:
uefi code:


if (BootParamlistPtr.BootingWith32BitKernel) {
  // Booting into 32 bit kernel.
  LinuxKernel32 = (LINUX_KERNEL32) (UINT64)BootParamlistPtr.KernelLoadAddr;
  LinuxKernel32 (0, 0, (UINTN)BootParamlistPtr.DeviceTreeLoadAddr);
  // Should never reach here. After life support is not available
  DEBUG ((EFI_D_ERROR, "After Life support not available\n"));
  goto Exit;
}
LinuxKernel = (LINUX_KERNEL) (UINT64)BootParamlistPtr.KernelLoadAddr;
LinuxKernel ((UINT64)BootParamlistPtr.DeviceTreeLoadAddr, 0, 0, 0);

kernel code:

start_kernel()
  |setup_arch()
     |setup_machine_fdt()//select machine description according to DT info

tag list传递

这是linux内核最早的板级信息传递的方式,最早期的时候这个tag list地址并不需要传递,而是通过代码中写死,这就要求bootloader中和kernel中对于tag list保存地址定义要相同。

后面新版的内核做了改进,可以通过一个寄存器传递对应的tag list地址,对于arm就是r2寄存器。如果系统使用了taglist来传递信息,那么必须要指定一个machine type,用于匹配对应的板型。r1 = machine nr指向__machine_arch_type,而r2 = atags的指针被保存在变量__atags_pointer中。

猜你喜欢

转载自blog.csdn.net/rikeyone/article/details/86573584