Jeremy
Jeremy

Reputation: 143

Loading bootconfig in Linux Kernel

I am reading over the code from the kernel that loads the boot config. In main.c the following code is executed.

err = parse_args("bootconfig", tmp_cmdline, NULL, 0, 0, 0, NULL,
             bootconfig_params);

on line 428. I open up parse_args, which, intern calls parse_one (both in kernel/params.c) and it looks like since const struct kernel_param *params is NULL it will never iterate over any parameters in parse_one.

I know there must be something I am missing here. The rest of the function past lines 431 and 432 in static void __init setup_boot_config(void) are never executed as far as I can see. The boot config must be parsed.

In init/main.c https://elixir.bootlin.com/linux/v6.13.1/source/init/main.c static void __init setup_boot_config(void)

In kernel/params.c https://elixir.bootlin.com/linux/v6.13.1/source/kernel/params.c parse_one(..) parse_args(..)

setup_boot_config(void) >> parse_args(..) >> parse_one(..) returns ENOENT

setup_boot_config(void) checks

if (IS_ERR(err) || !(bootconfig_found || IS_ENABLED(CONFIG_BOOT_CONFIG_FORCE)))

and returns. The xbc_init(..) is never called. There is something missing here.

Upvotes: 2

Views: 6

Answers (1)

telcoM
telcoM

Reputation: 274

At the entry to parse_args(), the function parameters are:

  • doing = "bootconfig"
  • args = tmp_cmdline
  • params = NULL
  • num_params = 0
  • min_level = 0
  • max_level = 0
  • arg = NULL
  • unknown = &(bootconfig_params)()

Then, at the entry to parse_one():

  • param = param from parse_args()
  • val = val from parse_args()
  • doing = "bootconfig"
  • params = NULL
  • num_params = 0
  • min_level = 0
  • max_level = 0
  • arg = NULL
  • handle_unknown = unknown from parse_args() = &(bootconfig_params()

Because num_params is 0, the first for loop in parse_one() is skipped, and we reach this part:

if (handle_unknown) {
    pr_debug("doing %s: %s='%s'\n", doing, param, val);
    return handle_unknown(param, val, doing, arg);
}

And here is what you missed:

handle_unknown is a valid function pointer to bootconfig_params(), so it is not NULL. And so, the content of the if(handle_unknown) will be executed, and because it contains an unconditional return, it will dictate the result of parse_one().

So after resolving the function pointer, the return from parse_one() will be whatever bootconfig_params(param, val, doing, arg) will return.

And that is simply:

static int __init bootconfig_params(char *param, char *val,
                    const char *unused, void *arg)
{
    if (strcmp(param, "bootconfig") == 0) {
        bootconfig_found = true;
    }
    return 0;
}

So if param is the exact string "bootconfig", then bootconfig_found gets set to true. But this function always returns 0... which means parse_one() will also return 0... which sets ret in parse_args() to 0 instead of ENOENT, so the switch(ret) will go to continue.

And so, the main while (*args) ... loop in parse_args() gets to iterate to the next parameter of tmp_cmdline.

Upvotes: 2

Related Questions