【问题标题】:how does the bootloader pass the kernel command line to the kernel?引导加载程序如何将内核命令行传递给内核?
【发布时间】:2021-02-28 18:56:37
【问题描述】:

我们可以看到这样的内核命令行:

ckim@chan-ubuntu:~/$ cat /proc/cmdline  
BOOT_IMAGE=/boot/vmlinuz-4.15.0-122-generic root=UUID=99c66a0a-39c1-451c-9f72-ad1576aafb41 ro quiet splash

这个命令行似乎是 grub 传递给内核用于引导的。这个命令行实际上是如何传递给内核程序的?我想也许命令行作为字符串加载到内存中,并且处理器的寄存器(如 x1,如果 arm64 处理器)设置为该字符串地址?我对 arm64 案例特别感兴趣。

【问题讨论】:

    标签: linux-kernel boot


    【解决方案1】:

    我有时会遇到同样的问题。所以现在是深入研究的时刻。

    x86 使用 special protocol for booting Linux,而 arm64 使用 a different scheme is used。为了与内核通信,引导加载程序仅将单个地址加载的扁平设备树 (FDT) 放入x0 寄存器中。

    这里摘自Linux and the Device Tree, Runtime configuration

    在大多数情况下,DT 将是从 固件到内核,所以也习惯于在运行时和 配置数据,如内核参数字符串和位置 initrd 图像。

    大部分数据都包含在 /chosen 节点中,并且在启动时 Linux 它看起来像这样:

    chosen {
            bootargs = "console=ttyS0,115200 loglevel=8";
            initrd-start = <0xc8000000>;
            initrd-end = <0xc8200000>;
    };
    

    Here is another example of DT.

    接下来,在内核早期引导期间,OF/FDT 模块解析传递的设备树fill in boot_command_line variable

    【讨论】:

      【解决方案2】:

      在内核源代码init/main.c中,内核入口点是start_kernel()

      [...]
      /* Untouched command line saved by arch-specific code. */
      char __initdata boot_command_line[COMMAND_LINE_SIZE];
      [...]
      asmlinkage __visible void __init start_kernel(void)
      {
          char *command_line;
          char *after_dashes;
      
          set_task_stack_end_magic(&init_task);
          smp_setup_processor_id();
          debug_objects_early_init();
      
          cgroup_init_early();
      
          local_irq_disable();
          early_boot_irqs_disabled = true;
      
          /*
           * Interrupts are still disabled. Do necessary setups, then
           * enable them.
           */
          boot_cpu_init();
          page_address_init();
          pr_notice("%s", linux_banner);
          early_security_init();
          setup_arch(&command_line);
      [...]
          pr_notice("Kernel command line: %s\n", boot_command_line);
      [...]
      

      在前面的几行中,调用了 setup_arch() 以根据体系结构获取命令行。

      对于 ARM64,setup_arch()arch/arm64/kernel/setup.c 中定义:

      void __init setup_arch(char **cmdline_p)
      {
          init_mm.start_code = (unsigned long) _text;
          init_mm.end_code   = (unsigned long) _etext;
          init_mm.end_data   = (unsigned long) _edata;
          init_mm.brk    = (unsigned long) _end;
      
          *cmdline_p = boot_command_line;
      [...]
      

      关于grub,详细here

      【讨论】:

        【解决方案3】:

        详细信息根据引导加载程序和特定内核的他head.S汇编语言启动模块而有所不同。

        在 Arm64 上,该启动代码位于文件 arch/arm64/kernel/head.S

        当启动代码被调用时,它假定寄存器x0x3 是引导参数并将它们保存在boot_params 数组中。稍后,C 代码验证只有第一个参数是非零的。其他三个必须为零;显然,它们在历史上被使用过。

        因此,实际上只有一个参数。它是什么? x0 寄存器指向 FDT(扁平设备树)。此设备树 blob 还包含命令行。

        查看drivers/of/fdt.c 中的代码如何从他的DT blob 中检索命令行(通过查找名为"bootargs" 的节点)并保留。

        【讨论】:

        • 谢谢,这对我有帮助。在哪里看。
        猜你喜欢
        • 2021-10-12
        • 1970-01-01
        • 2020-09-10
        • 1970-01-01
        • 2011-02-01
        • 2012-03-02
        • 2015-08-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多