Linux Kernel Module Parameters

Linux Kernel Module Parameters Explained – Free Linux Kernel Programming Course | EmbeddedPathashala

› Linux Kernel Module Parameters

Linux Kernel Module Parameters
How to pass runtime configuration to your kernel modules using module_param() – Free Linux Kernel Programming Course
Level
Beginner–Intermediate
Kernel
Linux 6.x
Topic
Kernel Modules
Course
100% Free
Topics Covered:
module_param() MODULE_PARM_DESC() insmod parameters sysfs module params debug_level pattern kernel module config Linux 6.x modules free kernel course

What You Will Learn

  • Why kernel modules need runtime parameters and what problems they solve
  • How the module_param() macro works under the hood
  • All supported data types for module parameters in Linux 6.x
  • How to use MODULE_PARM_DESC() to document your parameters
  • How to inspect module parameters using modinfo before loading
  • How parameters are exposed through sysfs and can be changed at runtime
  • The correct permission values to use for sysfs visibility
  • Common pitfalls and how to avoid them

Prerequisites

  • Basic C programming knowledge (pointers, static variables)
  • Understanding of what a Linux kernel module is
  • Familiarity with writing a simple init and exit module function
  • Linux 6.x kernel headers installed on your build machine
  • Root access (sudo) to load/unload kernel modules

When you write a Linux kernel module, you often need a way to control its behaviour without recompiling every time. Maybe you want to switch debug output on or off, or change a timeout value, or enable a special operating mode for testing. In user-space programs you would use argc and argv to accept command-line arguments. Kernel modules have no main() function, so they cannot do that directly.

Linux solves this cleanly with module parameters. A module parameter is a global variable inside your kernel module that you expose to the outside world using the module_param() macro. When you load the module with insmod or modprobe, you can pass values for those variables on the command line. This is part of every free Linux kernel programming course because it is one of the most practical tools a kernel developer uses daily.

Why Module Parameters Matter in Linux Kernel Development

Think about debugging. You add pr_debug() calls inside your driver to trace what is happening. In production you do not want those messages flooding the kernel log. So you guard them with a debug_level variable. If debug_level is 0, nothing prints. If it is 1, basic messages appear. If it is 2, you get full verbose output.

Without module parameters, you would have to hardcode that value and rebuild the module every time a customer reports a problem. With module parameters, the customer’s engineer can simply do:

sudo insmod mydriver.ko debug_level=2

And immediately get verbose logs without touching a single line of source code. This is the core idea behind the debug_level pattern you will see in almost every real driver in the Linux kernel tree.

Tip: The pr_debug() macro only prints when the symbol DEBUG is defined at compile time. Module parameters give you a runtime toggle that works even in release builds, which makes them far more practical for field debugging.

How the module_param() Macro Works in Linux 6.x

The kernel uses a bit of linker-level trickery to implement module parameters. When you call module_param(), the preprocessor generates a special structure that the module loader reads when it inserts your module. There is no main() involved at all — the kernel module loader parses the name=value pairs you give at insmod time and matches them to the registered variables.

The macro signature is:

module_param(name, type, perm);

Let us look at each argument one by one.

The Three Arguments of module_param()

module_param() — Three Arguments Explained
Argument Role Example
name The name of the static global variable in your C code debug_level
type The data type of the variable (not the C type name) int, charp, bool, long
perm Octal permission for sysfs visibility (0 = hidden) 0660, 0444, 0

Supported Data Types for Kernel Module Parameters

The type argument is not a raw C type. The kernel defines its own type tokens that map to C types internally. Here are all the types you can use in Linux 6.x:

Supported Types in module_param() — Linux 6.x
Type Token Maps to C Type Typical Use
boolboolOn/off feature toggles
invboolbool (inverted)Disable flags (true = disable)
intintDebug level, count, index
uintunsigned intBuffer sizes, non-negative counts
longlongLarge numeric values
ulongunsigned longAddresses, large unsigned values
shortshortSmall numeric values
ushortunsigned shortPort numbers, small ranges
charpchar *Device names, string options
hexintunsigned int (hex input)I/O base addresses, bitmasks
Note (Linux 6.x): Array parameters are also supported using module_param_array(). For example, if you need to pass multiple IRQ numbers or multiple port addresses at load time, you can declare a C array and register it with module_param_array(arr, type, &nelem, perm). The kernel fills in the number of elements provided by the user into nelem.

Writing a Kernel Module with Parameters – Complete Example

Here is a clean, minimal kernel module for Linux 6.x that demonstrates two module parameters: an integer debug level and a string name. Everything is written from scratch — no copy from any book or external source — so you can drop this directly into your own project.

// File: myparams.c
// Demonstrates module_param() on Linux 6.x
// Part of EmbeddedPathashala Free Linux Kernel Programming Course

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("EmbeddedPathashala");
MODULE_DESCRIPTION("Module parameter demo for Linux 6.x");

/* ----- Module Parameters ----- */

/* Integer parameter: debug verbosity level (0 = silent, 2 = verbose) */
static int debug_level;
module_param(debug_level, int, 0660);
MODULE_PARM_DESC(debug_level,
    "Debug verbosity: 0=off, 1=basic, 2=verbose (default: 0)");

/* String parameter: a device name or label */
static char *device_name = "mydevice0";
module_param(device_name, charp, 0444);
MODULE_PARM_DESC(device_name,
    "Name label for this device instance (default: mydevice0)");

/* Boolean parameter: enable an optional feature */
static bool enable_feature;
module_param(enable_feature, bool, 0660);
MODULE_PARM_DESC(enable_feature,
    "Set to 1 to enable the optional feature (default: 0)");

/* ----- Init ----- */
static int __init myparams_init(void)
{
    pr_info("myparams: loaded. device_name=%s debug_level=%d enable_feature=%d\n",
            device_name, debug_level, enable_feature);

    if (debug_level >= 1)
        pr_info("myparams: basic debug info active\n");

    if (debug_level >= 2)
        pr_info("myparams: verbose debug info active\n");

    if (enable_feature)
        pr_info("myparams: optional feature is ON\n");

    return 0;
}

/* ----- Exit ----- */
static void __exit myparams_exit(void)
{
    pr_info("myparams: unloaded\n");
}

module_init(myparams_init);
module_exit(myparams_exit);

And the matching Makefile for Linux 6.x out-of-tree builds:

# Makefile for myparams kernel module
obj-m := myparams.o

KDIR ?= /lib/modules/$(shell uname -r)/build

all:
	make -C $(KDIR) M=$(PWD) modules

clean:
	make -C $(KDIR) M=$(PWD) clean

Building and Loading the Module

# Build
make

# Load with default values (debug_level=0)
sudo insmod myparams.ko

# Load with custom parameters
sudo insmod myparams.ko debug_level=2 device_name=eth_custom enable_feature=1

# Check the kernel log
dmesg | tail -10

# Unload
sudo rmmod myparams
Tip: Always check dmesg after inserting a module. The kernel log shows your pr_info() messages and also reports any error if the module failed to insert.

Using modinfo to Inspect Module Parameters Before Loading

One of the best things about documenting your parameters with MODULE_PARM_DESC() is that anyone can read them without loading the module. The modinfo command shows all metadata embedded in the .ko file, including parameters:

# Show only parameter info
modinfo -p myparams.ko

# Example output:
debug_level:Debug verbosity: 0=off, 1=basic, 2=verbose (default: 0) (int)
device_name:Name label for this device instance (default: mydevice0) (charp)
enable_feature:Set to 1 to enable the optional feature (default: 0) (bool)

This is how a support engineer or a customer can find out what knobs your driver exposes before deploying it. Writing a good MODULE_PARM_DESC() for every parameter is a professional habit that saves a lot of debugging time later.

How modinfo Reads Parameter Metadata from a .ko File
myparams.c
module_param() +
MODULE_PARM_DESC()
make
Embeds metadata
into .ko ELF
myparams.ko
ELF sections hold
param descriptors
modinfo -p
Reads & displays
param info

Module Parameters and sysfs – Runtime Modification Without Reloading

When you set a non-zero permission in module_param(name, type, perm), the kernel automatically creates a file for that parameter under /sys/module/<modulename>/parameters/. This is the sysfs interface.

After your module is loaded, you can read and (if the permission allows writes) modify parameters on the fly:

# Read current value of debug_level
cat /sys/module/myparams/parameters/debug_level

# Output: 0

# Change debug_level to 2 at runtime (no reload needed)
echo 2 | sudo tee /sys/module/myparams/parameters/debug_level

# Verify
cat /sys/module/myparams/parameters/debug_level
# Output: 2

This is extremely useful in production systems where you cannot afford to unload and reload a driver but need to increase verbosity temporarily to catch a bug.

sysfs Parameter Interface — Read & Write at Runtime
User Space
echo 2 > /sys/module/myparams/parameters/debug_level
Kernel Space
static int debug_level; (perm=0660)
The kernel sysfs layer handles the conversion between string (sysfs) and the variable’s data type automatically

Choosing the Right Permission Value

The permission value controls who can read or write the sysfs file. Here are the most common choices:

Permissionsysfs file accessWhen to use
0No sysfs file createdInternal-only params that should not be exposed
0444Read-only for allParams set at load time, never changed at runtime
0644Root writes, all readRuntime-tunable params, readable by users
0660Root reads+writes, group reads+writesSensitive params limited to root and group
0600Root only, read+writeSecurity-sensitive params
Warning: Never use permission values like 0777 for module parameters. Any user being able to modify a kernel parameter is a serious security risk. Stick to 0444 or 0644 for most drivers.

Best Practices for Kernel Module Parameters in Linux 6.x

Real kernel drivers in the mainline tree follow a consistent set of practices when using module parameters. Here are the key ones to follow in your free Linux kernel programming and device drivers work:

1. Always write MODULE_PARM_DESC() for every parameter

Even if it seems obvious, document what valid values are and what each value means. This shows up in modinfo -p and is the only documentation a system administrator might ever see.

2. Never initialise a static variable to zero explicitly

The kernel’s scripts/checkpatch.pl tool (used before patches are accepted upstream) flags static int x = 0; as a style error. Static variables in C are zero-initialised by default. Write static int x; instead.

3. Always declare the variable as static

Module parameters must be global (so the linker can register them) but their scope should be limited to the module using the static qualifier. Never expose them as external symbols.

4. Use a meaningful prefix for the variable name

A common convention is to prefix module parameter variables with mp_ or the module’s short name. This makes it immediately obvious in the code that the variable is a module parameter and not a regular local.

5. Validate parameters in your init function

The kernel does type checking but not range checking. If debug_level should only be 0, 1, or 2, check that in module_init() and return -EINVAL with a clear message if the value is out of range.

Common Mistakes When Using module_param() – Troubleshooting Guide

Mistake 1: Using the wrong type token

Passing a char * variable but using int as the type token will cause a build warning or a runtime crash. For string pointers, always use charp, not char * or string.

Mistake 2: Setting perm to 0777

World-writable kernel parameters are a security hole. The kernel actually rejects world-writable sysfs files and will print a warning. Keep permissions tight.

Mistake 3: Forgetting to validate at init time

If a user passes debug_level=99 and your code later uses it as an array index, you will cause a kernel panic. Always check bounds in module_init().

Mistake 4: Modifying a charp parameter at runtime via sysfs

String (charp) parameters point to a string literal at load time. If sysfs allows writes and the kernel tries to replace the pointer, you can get memory corruption. Use 0444 for string parameters unless you handle the memory carefully.

Key Takeaways

  • Module parameters let you pass name=value pairs at insmod time without modifying source code.
  • Use module_param(name, type, perm) to register any static global variable as a parameter.
  • The type argument uses kernel tokens like int, uint, charp, bool — not raw C types.
  • The perm argument controls whether and how the parameter appears in /sys/module/<mod>/parameters/.
  • Always document every parameter with MODULE_PARM_DESC() — it appears in modinfo -p.
  • Validate parameter values inside your module_init() function and return -EINVAL on bad input.
  • Never explicitly initialise a static variable to zero — the kernel style checker will flag it.

Frequently Asked Questions – Linux Kernel Module Parameters

Q1: Can I change a module parameter after the module is loaded?

Yes, if the parameter was registered with a non-zero perm value that includes write permission (like 0660 or 0644). The kernel creates a file in /sys/module/modulename/parameters/ and you can write a new value using echo. Changes take effect immediately in the running kernel.

Q2: What happens if I pass an unknown parameter name to insmod?

The module insertion fails with an error. insmod returns a non-zero exit code and dmesg shows a message like Unknown parameter 'xyz' ignored or a hard failure depending on the kernel version. In Linux 6.x the behaviour is to fail the insertion when an unrecognised parameter is passed.

Q3: What is the difference between module_param() and module_param_array()?

module_param() is for a single value. module_param_array() is for a C array — it lets you pass multiple values separated by commas at load time, like insmod mymod.ko ports=3000,3001,3002. The kernel fills in how many elements were provided into a separate counter variable you supply.

Q4: What does perm=0 mean for a module parameter?

When perm is 0, no sysfs file is created for the parameter. It can still be set at insmod time, but it cannot be read or changed after the module is loaded. This is useful for parameters that are configuration-only and should not be exposed to user space after boot.

Q5: Can I use module parameters with modprobe as well?

Yes. modprobe works exactly like insmod for parameters. Additionally, you can make parameters persistent across reboots by adding them to /etc/modprobe.d/ configuration files. For example: options myparams debug_level=1 in a file like /etc/modprobe.d/myparams.conf.

Q6: Why does checkpatch.pl complain about static int x = 0?

In C, static variables are zero-initialised by default. Writing = 0 explicitly is redundant and the Linux kernel coding style guide considers it noise. The automated patch checker enforces this rule strictly because the kernel codebase is huge and consistency matters at that scale.

Q7: Is module_param() available in all Linux kernel versions?

module_param() has been available since Linux 2.6. The macro syntax has been stable for a long time. However, some type tokens were added over time. For Linux 6.x all the types listed in this tutorial are fully supported. The older MODULE_PARM() macro from Linux 2.4 is long gone — do not use it.

Q8: What is the maximum length of a charp (string) parameter?

By default the kernel allocates a fixed internal buffer of 1024 bytes for string parameters passed at load time. In practice, keep your string parameters short — device names, mode strings, and similar values are usually well under 64 characters. For longer configuration data, consider using a sysfs attribute or a configuration file instead.

Continue Learning – Free Linux Kernel Programming Course

EmbeddedPathashala offers completely free courses on Linux kernel programming, Linux device drivers, and embedded systems. No registration required.

Browse All Free Courses Free Device Drivers Course

Leave a Reply

Your email address will not be published. Required fields are marked *