Petr Tesarik's Linux blog
by Petr Tesařík
There should be a long introductory part explaining all the logical events leading up to the current sorry state. Sorry, too little time for that. Maybe over a beer at a conference…
As of 2025, all kernel parameters should be eventually parsed with
parse_args(). This is a slightly overengineered mechanism to split
the command line into individual key-value pairs while allowing to
quote white space.
Individual options are described by struct kernel_param (see
<linux/moduleparam.h>). This structure is best suited for module
parameters, which may be also given on the command line (prefixed with
the module name and a dot), they usually appear in sysfs, and
sometimes can even be writable.
Normal parameters passed to the kernel are processed relatively late:
in kernel_init(), which runs in PID 1 context (before first exit to
user mode). They are defined by a level_param_cb() macro, where
level is the name of an initcall level, namely:
The parameters for each level are parsed just before calling the
corresponding initcalls. The idea is to associate parameter parsing
with initcalls. For example, parameters for a subsys_initcall()
function should be defined using subsys_param_cb().
Beware! Besides a regular core_param_cb(name, ops, arg, perm)
(parsed just before core initcalls), there is also an unrelated
core_param(name, var, type, perm). The latter is used for real core
parameters (e.g. panic_on_warn), which are parsed much earlier
than normal parameters. More specifically, they are handled by the
parse_args() call in start_kernel(), after the kernel prints
“Kernel command line: ” to the message log and before it lists unknown
parameters.
Historically, such parameters were defined with a __setup() macro,
and in a lot of places they still are.
Their definition is now stored in a struct obs_kernel_param (IIUC
obs stands for “obsolete”), and they are processed just after core
parameters, see obsolete_checksetup(). The setup function receives a
single string argument, which will point to the equals sign (=)
separating the parameter name from its value, unless that character
was appended to the option name given to __setup(). The equals sign
must not be included in the name if the option takes no value, but
then you must check whether the value starts with an equals sign (and
skip it if necessary).
The __setup() macro is defined using the __setup_param() macro
(which is also used directly in a few places). The last parameter of
__setup_param() is called early and it is used to initialise a
struct obs_kernel_param field of the same name. It is set to zero by
__setup() and all direct users, but it is set to one by another
macro, called early_param(). This macro is used for “true” early
parameters, processed by parse_early_param(). Note that they also
use struct obs_kernel_param but differently than the obsolete
__setup()-style parameters. The name should never include the equals
sign, and the setup function receives only the actual value (or NULL
if none).
The exact point in the boot process when parse_early_param() is
called depends on the target architecture.
As of 6.17, most architectures call it from setup_arch():
A few call it extremely early (even before start_kernel()):
The remaining architectures rely on a fallback call in
start_kernel(), just before processing parameters defined by
core_param():
(This section was added thanks to Vlasta.)
It is also possible to set a sysctl using a command line parameter
that starts with sysctl.. This is done very late in the process
(just before executing the init process) by calling
do_sysctl_args() from kernel_init(). It works by mounting a proc
filesystem and writing the option value to the corresponding file.
Last but not least, there are four sysctl options that were introduced before the generic mechanism, and the original non-prefixed names are kept as aliases:
hardlockup_all_cpu_backtracesysctl.kernel.hardlockup_all_cpu_backtracehung_task_panicsysctl.kernel.hung_task_panicnuma_zonelist_ordersysctl.vm.numa_zonelist_ordersoftlockup_all_cpu_backtracesysctl.kernel.softlockup_all_cpu_backtraceApart from the missing prefix and a few other peculiarities (e.g. to prevent reporting them as unknown), there is nothing special about them.
tags: kernel