首页 > 系统相关 >linux kernel的启动参数是怎么拿到的-以arm64为例

linux kernel的启动参数是怎么拿到的-以arm64为例

时间:2023-10-17 22:35:08浏览次数:31  
标签:kernel efi 为例 boot cmdline fdt line arm64

linux kernel拿到启动参数一定是在boot阶段,那就必须从start_kernel找起。

asmlinkage __visible __init __no_sanitize_address __noreturn __no_stack_protector
void start_kernel(void)
{
       。。。
        setup_arch(&command_line);

setup_arch的参数里有command_line,这个就是拿参数用的。看看他是怎么拿到的。

void __init __no_sanitize_address setup_arch(char **cmdline_p)
{
        setup_initial_init_mm(_stext, _etext, _edata, _end);

        *cmdline_p = boot_command_line;

很简单的一句赋值语句就完成了。那boot_command_line又是在哪里赋值的?

继续搜索发现在drivers/of/fdt.c中有

rc = early_init_dt_scan_chosen(boot_command_line);

 这就明白了,原来启动参数是从fdt的chosen里面拿到的。但是这就完了吗?

如果kernel是从fdt启动的那基本到这里就算清楚了,但是如果kernel根本就没有收到fdt呢?这是有可能的,当kernel从efi启动,可以只传给kernel acpi表而不传fdt。请看下面这段代码:

void __init acpi_boot_table_init(void)
{
	/*
	 * Enable ACPI instead of device tree unless
	 * - ACPI has been disabled explicitly (acpi=off), or
	 * - the device tree is not empty (it has more than just a /chosen node,
	 *   and a /hypervisor node when running on Xen)
	 *   and ACPI has not been [force] enabled (acpi=on|force)
	 */
	if (param_acpi_off ||
	    (!param_acpi_on && !param_acpi_force && !dt_is_stub()))
		goto done;

 也即是说如果我们的机器要从acpi启动,那么有可能我们只有一个空的fdt。如果是个空的,启动参数又从哪里找呢?

不知大家有没有发现,在grub将机器的控制权交给kernel的时候,在那些看起来井井有条的kernel log出现之前,我们经常会看到这样的的输出:

EFI stub: Booting Linux Kernel...
EFI stub: EFI_RNG_PROTOCOL unavailable
EFI stub: Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path
EFI stub: Generating empty DTB
EFI stub: Exiting boot services...

这些带着EFI标志的输出是什么东西,又是从哪里来的呢?

grep一下就能看到这些东西都是从kernel efi的driver里面来的。那为啥一个driver运行会先于kernel主体的初始化?简单来讲这是因为efi boot的需要。为了从efi启动kernel,为了能够使用efi的boot service和runtime service,在主体代码初始化之前需要先伪装成efi应用做一些初始化工作。这里我们只关系那句Generating empty DTB。

efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
                                            efi_loaded_image_t *image,
                                            unsigned long *new_fdt_addr,
                                            char *cmdline_ptr)
...
if (!fdt_addr)
                efi_info("Generating empty DTB\n");

        efi_info("Exiting boot services...\n");

       ...
        status = update_fdt((void *)fdt_addr, fdt_size,
                            (void *)*new_fdt_addr, MAX_FDT_SIZE, cmdline_ptr);

 传入的cmdline_ptr指向了启动参数。看看update_fdt干了啥:

static efi_status_t update_fdt(void *orig_fdt, unsigned long orig_fdt_size,
                               void *fdt, int new_fdt_size, char *cmdline_ptr)
{

...
        node = fdt_subnode_offset(fdt, 0, "chosen");
        if (node < 0) {
                node = fdt_add_subnode(fdt, 0, "chosen");
                if (node < 0) {
                        /* 'node' is an error code when negative: */
                        status = node;
                        goto fdt_set_fail;
                }
        }

        if (cmdline_ptr != NULL && strlen(cmdline_ptr) > 0) {
                status = fdt_setprop(fdt, node, "bootargs", cmdline_ptr,
                                     strlen(cmdline_ptr) + 1);
                if (status)
                        goto fdt_set_fail;
        }

  这里就是bootarg重建的代码了。那现在就剩下一个问题,cmdline_ptr是哪里获得的?

efi_pe_entry->efi_stub_common->efi_boot_kernel->allocate_new_fdt_and_exit_boot->update_fdt

efi_status_t efi_handle_cmdline(efi_loaded_image_t *image, char **cmdline_ptr)
{
...
 /*
         * Get the command line from EFI, using the LOADED_IMAGE
         * protocol. We are going to copy the command line into the
         * device tree, so this can be allocated anywhere.
         */
        cmdline = efi_convert_cmdline(image, &cmdline_size);
/*
 * Convert the unicode UEFI command line to ASCII to pass to kernel.
 * Size of memory allocated return in *cmd_line_len.
 * Returns NULL on error.
 */
char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len)
{
        const efi_char16_t *options = efi_table_attr(image, load_options);
...
        snprintf((char *)cmdline_addr, options_bytes, "%.*ls",
                 options_bytes - 1, options);

          *cmd_line_len = options_bytes;
        return (char *)cmdline_addr;
}

 到这里已经清楚了,参数是通过efi_table_attr(image, load_options)拿到的。

#define efi_table_attr(inst, attr)	(inst)->attr

 也就是从image_handle里面拿到load_options参数。这个参数的赋值就要从uefi代码中去找了。

这里要提醒一下的是,这个参数中的参数是utf-16的宽字符格式,所以要经过一些处理才能正确解析。

好了这次arm64上kernel 参数的获取就分析完了。 

以上kernel code依据v6.4-rc6

  

 

标签:kernel,efi,为例,boot,cmdline,fdt,line,arm64
From: https://www.cnblogs.com/banshanjushi/p/17770875.html

相关文章

  • ipykernel ipython
    ipykernelipykernel是一个用于在JupyterNotebook中运行Python代码的包,它可以将Python代码转化为可以在Python内核上运行的格式。 ipython IPython是什么? https://blog.csdn.net/jarodyv/article/details/128145753Python最有用的功能之一就是它的交互式解释器。交互......
  • Linux Kernel 之一 完整嵌入式 Linux 环境、构建工具、编译工具链、各 CPU 架构
    版权声明:本文为CSDN博主「ZC·Shou」的原创文章,遵循CC4.0BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/ZCShouCSDN/article/details/122239093   第一步就是需要了解如何搭建一个完整的嵌入式Linux环境。现在将学习心得记录为此文。......
  • 《Mastering the FreeRTOS Real Time Kernel》读书笔记(7)事件组
    8.事件组之前已经介绍了多任务之间的交流桥梁,包括了队列和信号量。与队列和信号量不同:事件组允许任务在“阻塞”状态下等待一个或多个事件的组合发生。事件组在事件发生时,取消等待同一事件或事件组合的所有任务的阻塞状态。事件组的这些独特属性可用于同步多个任务、向多个任务......
  • arm64和x64与苹果芯片的关系备忘
    title:arm64和x64与苹果芯片的关系备忘date:2023-10-16T00:00:00.000Zauthor:KazooTTTtags:-备忘published:truelink:https://kazoottt.notion.site/arm64-x64-b527f80503f241d3a0f20503eb8a9c0cnotionID:b527f805-03f2-41d3-a0f2-0503eb8a9c0carm64和x64与苹果......
  • 《Mastering the FreeRTOS Real Time Kernel》读书笔记(6)资源管理
    7.资源管理(互斥量)在多任务系统中,如果一个任务开始访问资源,但在从运行状态转换出来之前没有完成访问,则可能会出现错误。如果任务使资源处于不一致状态,则任何其他任务或中断对同一资源的访问都可能导致数据损坏或其他类似问题。这里的资源管理,应该是指计算机的外设资源,比如LCD显示......
  • 《Mastering the FreeRTOS Real Time Kernel》读书笔记(5)中断管理
    6.中断管理在读这一章之前一直有一些疑惑,FreeRTOS中的中断是软中断吗,还是将外部硬中断的触发后,导入FreeRTOS的内部进行调度处理。如果是第一种,软中断和第三章讲的任务有区别吗,还是只是优先级比所有任务高。如果是第二种的话,外部中断的服务函数是不是不能写内容了,FreeRTOS的运行和......
  • kernel6.5.7+busybox1.36.1制作一个Mini Linux (没启动起来)
    目录前奏下载linux内核源码并编译下载busybox的源代码制作根文件系统镜像文件安装qemu...有兴趣的同学可参考该文档将其完善...前奏rambo@debian:~$cat/etc/issueDebianGNU/Linux12\n\lrambo@debian:~$free-htotalusedfree......
  • 以PMIC为例简析Linux MFD/Remap/Regulator的使用
     关键词:ADI、SPI、Regmap、MFD、Regulator、PMIC等等。 以SC27XX为例,梳理一个PMIC用到的内核模块。1.MFD框架MFD是Multi-FunctionDevice,MFD子系统是Linux下一种用于管理和控制多功能设备的软件框架。他提供一种统一接口,使得多个设备可以通过一个驱动程序进行管理和控制。K......
  • 核方法(kernel method)的主要思想
    本文对核方法(kernelmethod)进行简要的介绍(https://www.jianshu.com/p/8e2649a435c4)。核方法的主要思想是基于这样一个假设:“在低维空间中不能线性分割的点集,通过转化为高维空间中的点集时,很有可能变为线性可分的”,例如下图   左图的两类数据要想在一维空间上线性分开......
  • Linux Kernel 4.13 RC6发布:正式版9月3日发布
    美国当地时间上周末,大神LinusTorvalds发布了Linux Kernel4.13内核的又一候选版本。上周发布的RC5版本更新幅度也要比上上周的RC4要小,LinusTorvalds表示本周发布的RC6版本属于常规更新,在过去一周的开发过程中并没有出现任何意外。RC6版本主要对网络、声音和InfiniBand驱动,以及......