How to Pass a Value to a Builtin Linux Kernel Module at Boot Time

How to pass a value to a builtin Linux kernel module at boot time?

Modify your board file present in include/config/board_xxx.h of U-Boot, modify $bootargs similar to the last variable that is set in this example:

setenv bootargs display=\${display} console=\${consoledev},\${baudrate} root=/dev/mmcblk0p1 rw rootdelay=1 control.cmd1={cmd1}

control is the name of the built-in driver module that I cannot insmod because I need it for booting fully to the Linux prompt.

cmd1 is the global variable I've defined in the module in which I've used:

module_param(cmd1, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);

so, your $bootargs var simply needs to be appended with something like:

<your_mod_name>.<your_mod_parameter_var_name>=<an_appropriate_value>

Passing parameter to builtin kernel module at compile time

You can use two kernel features to accomplish this:

  • You can pass module parameter values to built-in modules via the kernel command line as "modulename.param=value". So in your case you want something like "bonding.max_bonds=50" in the kernel command line.
  • Since 2.6.28 or so (hope your kernel isn't older than that), the kernel supports setting a default command line at compile time via CONFIG_CMDLINE_BOOL ("Built-in kernel command line") and CONFIG_CMDLINE. You set CONFIG_CMDLINE_BOOL=y and then set CONFIG_CMDLINE to whatever you want in your kernel command line (for example, "bonding.max_bonds=50"). Any further command line options that your boot loader passes to the kernel are appended to the default command line you set in the kernel config.

By using those two features, I think you get pretty much exactly what you want, without modifying any kernel source, just tweaking your config file.

Passing value to module param in a static module

Standard practice is to pass module.parameter[=value].

Ways of sending parameters to static kerenel module

For modules built into the kernel image, add your module-custom parameters to the kernel boot params list. This list will (depending on architecture) be passed by the bootloader or built into the kernel.

It will look something like this:

mymod.fooparam=debug

For reference, see the kernel-params documentation.

You define the parameters in the module the same way you would for a dynamically loaded module.

edit: This is from: arch/arm/Kconfig
You can set the cmdline via the .config file that is generated based on build options.

config CMDLINE
string "Default kernel command string"
default ""
help
On some architectures (EBSA110 and CATS), there is currently no way
for the boot loader to pass arguments to the kernel. For these
architectures, you should supply some command-line options at build
time by entering them here. As a minimum, you should specify the
memory size and the root device (e.g., mem=64M root=/dev/nfs).

choice
prompt "Kernel command line type" if CMDLINE != ""
default CMDLINE_FROM_BOOTLOADER

config CMDLINE_FROM_BOOTLOADER
bool "Use bootloader kernel arguments if available"
help
Uses the command-line options passed by the boot loader. If
the boot loader doesn't provide any, the default kernel command
string provided in CMDLINE will be used.

config CMDLINE_EXTEND
bool "Extend bootloader kernel arguments"
help
The command-line arguments provided by the boot loader will be
appended to the default kernel command string.

config CMDLINE_FORCE
bool "Always use the default kernel command string"
help
Always use the default kernel command string, even if the boot
loader passes other arguments to the kernel.
This is useful if you cannot or don't want to change the
command-line options your boot loader passes to the kernel.
endchoice

Change the order that built in kernel drivers get initialized?

initcall ordering is defined here:

http://lxr.free-electrons.com/source/include/linux/init.h#L194

which is, for reference:

/*
* A "pure" initcall has no dependencies on anything else, and purely
* initializes variables that couldn't be statically initialized.
*
* This only exists for built-in code, not for modules.
* Keep main.c:initcall_level_names[] in sync.
*/
#define pure_initcall(fn) __define_initcall(fn, 0)

#define core_initcall(fn) __define_initcall(fn, 1)
#define core_initcall_sync(fn) __define_initcall(fn, 1s)
#define postcore_initcall(fn) __define_initcall(fn, 2)
#define postcore_initcall_sync(fn) __define_initcall(fn, 2s)
#define arch_initcall(fn) __define_initcall(fn, 3)
#define arch_initcall_sync(fn) __define_initcall(fn, 3s)
#define subsys_initcall(fn) __define_initcall(fn, 4)
#define subsys_initcall_sync(fn) __define_initcall(fn, 4s)
#define fs_initcall(fn) __define_initcall(fn, 5)
#define fs_initcall_sync(fn) __define_initcall(fn, 5s)
#define rootfs_initcall(fn) __define_initcall(fn, rootfs)
#define device_initcall(fn) __define_initcall(fn, 6)
#define device_initcall_sync(fn) __define_initcall(fn, 6s)
#define late_initcall(fn) __define_initcall(fn, 7)
#define late_initcall_sync(fn) __define_initcall(fn, 7s)

As module_init is #defined to be device_initcall, a general module with nothing dependent on it gets initialized towards the end of the sequence. To load your module early, you simply change its module_init call to something else that occurs earlier (like subsys_initcall, for example)

Note: just switching the order on things can break other dependencies, and you can get in a catch-22 dependency loop from hell.

Is there any way to harcode Linux kernel boot options?

You can do this via your bootloader. I am going to assume you are using the most common bootloader for SoC's: U-Boot. U-Boot has a variable called bootargs that normally holds all the command line options for the kernel (like root=). To append bootargs with what you want, you would enter the following in the U-Boot prompt

setenv bootargs $(bootargs) root=/dev/mmcblk0p1

If you want to permanently save the variable then you need to enter the command saveenv to tell U-Boot to save this change to disk. After this you can issue your normal boot commands.

How to get details of all modules / drivers that were initialized / probed during the Linux kernel boot?

Passing the option "initcall_debug" on the kernel command line will cause timing information to be printed to the console for each init routine of built-in drivers. The initcalls are used to initialize statically linked kernel drivers and subsystems and contribute a significant amount of time to the Linux boot process. (Loadable modules are not available until after the root filesystem has been mounted.)

The output looks like:

calling  tty_class_init+0x0/0x44 @ 1
initcall tty_class_init+0x0/0x44 returned 0 after 9765 usecs
calling spi_init+0x0/0x90 @ 1
initcall spi_init+0x0/0x90 returned 0 after 9765 usecs

Reference: http://elinux.org/Initcall_Debug

Addendum

Specifying the kernel parameter "ignore_loglevel" along with the "initcall_debug" will ensure that the information will be displayed during boot.



Related Topics



Leave a reply



Submit