linux kernel中的cmdline的详细介绍

29 阅读5分钟

cmdline

1、向linux kernel添加cmdline的四种方式

(1)、 在dts中的bootargs中添加

(2)、在BoardConfig中添加

(3)、在uboot中添加

(4)、在android的Makefile中添加

2、在uboot中,将cmdline统一放置在FDT中

3、在kernel中,从FDT中解析处cmdline并使用

(1)、跳转linux kernel之前-准备cmdline

(2)、kernel启动-解析cmdline

1、向linux kernel添加cmdline的四种方式

在linux启动时候,串口log中会打印cmdline

[  0.000000] c0 0 (swapper) Kernel command line: earlycon androidboot.selinux=permissive uart_dma keep_dbgclk_on clk_ignore_unused initrd=0xd0000000,38711808 rw crash_page=0x8f040000 initrd=/recoveryrc boot_reason=0x2000 ota_status=0x1001

在linux启动完成后,通过 cat /proc/cmdline也是可以看到cmdline. 那么cmdline是如何添加的呢?

(1)、 在dts中的bootargs中添加

  1. / {

  2.   model = "yyyyyyy";

  3.   compatible = "yyyyyyy", "xxxxxxxx";

  4.   chosen {

  5.     /*

  6.      * initrd parameters not set in dts file since the ramdisk.img size

  7.      * need to check in uboot, and the initrd load address and size will

  8.      * set in uboot stage.

  9.      */

  10.     bootargs = "earlycon androidboot.selinux=permissive uart_dma keep_dbgclk_on clk_ignore_unused";

  11.     stdout-path = "serial0:115200";

  12.   };

  13. ......

  14. }

(2)、在BoardConfig中添加

vim device/xxx/xxx_evb/BoardConfigCommon.mk

BOARD_KERNEL_CMDLINE += androidboot.selinux=enforcing androidboot.hardware=xxxx_phone androidboot.dtbo_idx=0

(3)、在uboot中添加

vim u-boot/common/cmd_bootm.c

  • append_bootargs("recovery=1");

  • sprintf(dm_buf,"init=/init skip_initramfs rootwait root=/dev/dm-0 dm="system none ro,0 1 android-verity /dev/mmcblk0p%d"",ret);

  • append_bootargs((const char *)dm_buf);

2、在uboot中,将cmdline统一放置在FDT中

以后再写,哈哈哈哈

3、在kernel中,从FDT中解析处cmdline并使用

(1)、跳转linux kernel之前-准备cmdline

在跳转linux kernel之前(如uboot中),将cmdline数据放到了FDT中,然后将FDT的地址写入到了X0中。然后再跳转linux kernel.

别问我怎么知道的,请看kernel-4.14/Documentation/arm64/booting.txt

  1. Before jumping into the kernel, the following conditions must be met:

    • Quiesce all DMA capable devices so that memory does not get
  2.  corrupted by bogus network packets or disk data. This will save

  3.  you many hours of debug.

    • Primary CPU general-purpose register settings
  4.  x0 = physical address of device tree blob (dtb) in system RAM.

  5.  x1 = 0 (reserved for future use)

  6.  x2 = 0 (reserved for future use)

  7.  x3 = 0 (reserved for future use)

(2)、kernel启动-解析cmdline

linux kernel从stext开始启动,整个流程大概就是读取X0(FDT地址)保存到X21中,又将X21保存到__fdt_pointer全局变量中

然后再将__fdt_pointer解析处cmdline数据到boot_command_line全局变量中

  1. /*

    • The following callee saved general purpose registers are used on the
    • primary lowlevel boot path:
  2. * Register  Scope           Purpose

  3. * x21    stext() .. start_kernel() FDT pointer passed at boot in x0

  4. * x23    stext() .. start_kernel() physical misalignment/KASLR offset

  5. * x28    __create_page_tables()   callee preserved temp register

  6. * x19/x20  __primary_switch()     callee preserved temp registers

  7. */

  8. ENTRY(stext)

  9. bl preserve_boot_args

  10. bl el2_setup // Drop to EL1, w0=cpu_boot_mode

  11. adrp x23, __PHYS_OFFSET

  12. and x23, x23, MIN_KIMG_ALIGN - 1 // KASLR offset, defaults to 0

  13. bl set_cpu_boot_mode_flag

  14. bl __create_page_tables

  15. /*

    • The following calls CPU setup code, see arch/arm64/mm/proc.S for
    • details.
    • On return, the CPU will be ready for the MMU to be turned on and
    • the TCR will have been set.
  16. */

  17. bl __cpu_setup // initialise processor

  18. b __primary_switch

  19. ENDPROC(stext)

这里调用了:

preserve_boot_args

__primary_switch

在preserve_boot_args将X0(fdt地址)暂时先保存到了X21中

  1. preserve_boot_args:

  2. mov x21, x0 // x21=FDT

  3. adr_l x0, boot_args // record the contents of

  4. stp x21, x1, [x0] // x0 .. x3 at kernel entry

  5. stp x2, x3, [x0, #16]

  6. dmb sy // needed before dc ivac with

  7. // MMU off

  8. mov x1, #0x20 // 4 x 8 bytes

  9. b __inval_dcache_area // tail call

  10. ENDPROC(preserve_boot_args)

  11. __primary_switch调用了__primary_switched

  12. __primary_switch:

  13. #ifdef CONFIG_RANDOMIZE_BASE

  14. mov x19, x0 // preserve new SCTLR_EL1 value

  15. mrs x20, sctlr_el1 // preserve old SCTLR_EL1 value

  16. #endif

  17. bl __enable_mmu

  18. #ifdef CONFIG_RELOCATABLE

  19. bl __relocate_kernel

  20. #ifdef CONFIG_RANDOMIZE_BASE

  21. ldr x8, =__primary_switched

  22. adrp x0, __PHYS_OFFSET

  23. blr x8

__primary_switched将X21(fdt地址)保存到了__fdt_pointer全局变量中

  1. __primary_switched:

  2. adrp x4, init_thread_union

  3. add sp, x4, #THREAD_SIZE

  4. adr_l x5, init_task

  5. msr sp_el0, x5 // Save thread_info

  6. adr_l x8, vectors // load VBAR_EL1 with virtual

  7. msr vbar_el1, x8 // vector table address

  8. isb

  9. stp xzr, x30, [sp, #-16]!

  10. mov x29, sp

  11. str_l x21, __fdt_pointer, x5 // Save FDT pointer

  12. ldr_l x4, kimage_vaddr // Save the offset between

  13. sub x4, x4, x0 // the kernel virtual and

  14. str_l x4, kimage_voffset, x5 // physical mappings

  15. // Clear BSS

  16. adr_l x0, __bss_start

  17. mov x1, xzr

  18. adr_l x2, __bss_stop

  19. sub x2, x2, x0

  20. bl __pi_memset

  21. dsb ishst // Make zero page visible to PTW

在setup_arch()的时候,调用setup_machine_fdt将fdt解析到了boot_command_line全局变量中

  1. void __init setup_arch(char **cmdline_p)

  2. {

  3. pr_info("Boot CPU: AArch64 Processor [%08x]\n", read_cpuid_id());

  4. ......

  5. *cmdline_p = boot_command_line;

  6. ......

  7. setup_machine_fdt(__fdt_pointer);

  8. ......

  9. }

setup_machine_fdt()—>early_init_dt_scan()—>early_init_dt_scan_nodes()

在中,将fdt解析到了boot_command_line中

  1. of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line)

  2. static void __init setup_machine_fdt(phys_addr_t dt_phys)

  3. {

  4. void *dt_virt = fixmap_remap_fdt(dt_phys);

  5. const char *name;

  6. if (!dt_virt || !early_init_dt_scan(dt_virt)) {

  7. pr_crit("\n"

  8. "Error: invalid device tree blob at physical address %pa (virtual address 0x%p)\n"

  9. "The dtb must be 8-byte aligned and must not exceed 2 MB in size\n"

  10. "\nPlease check your bootloader.",

  11. &dt_phys, dt_virt);

  12. while (true)

  13. cpu_relax();

  14. }

  15. name = of_flat_dt_get_machine_name();

  16. if (!name)

  17. return;

  18. /* backward-compatibility for third-party applications */

  19. machine_desc_set(name);

  20. pr_info("Machine model: %s\n", name);

  21. dump_stack_set_arch_desc("%s (DT)", name);

  22. }

  23.  bool __init early_init_dt_scan(void *params)

  24.  {

  25.   bool status;

  26.  

  27.   status = early_init_dt_verify(params);

  28.   if (!status)

  29.   return false;

  30.  

  31.   early_init_dt_scan_nodes();

  32.   return true;

  33.  }

  34.  void __init early_init_dt_scan_nodes(void)

  35.  {

  36.   /* Retrieve various information from the /chosen node */

  37.   of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);

  38.  

  39.   /* Initialize {size,address}-cells info */

  40.   of_scan_flat_dt(early_init_dt_scan_root, NULL);

  41.  

  42.   /* Setup memory, calling early_init_dt_add_memory_arch */

  43.   of_scan_flat_dt(early_init_dt_scan_memory, NULL);

  44.  }

在start_kernel()打印了cmdline.

asmlinkage __visible void __init start_kernel(void)

{

pr_notice(“Kernel command line: %s\n”, boot_command_line);

}