Automatic Loading of Linux Kernel Modules at System Boot

Auto-Loading Linux Kernel Modules at Boot | Free Linux Kernel Development Course – EmbeddedPathashala

Auto-Loading Linux Kernel Modules at System Boot

Learn how to install and automatically load your out-of-tree kernel modules on every boot using systemd, modules-load.d, modprobe, and depmod — with full Linux 6.x compatibility.

📚 Free Linux Kernel Development Course ⏱ ~18 min read 💻 Linux 6.x 🎓 EmbeddedPathashala

🎓 What You Will Learn

  • Why auto-loading kernel modules at boot matters in production embedded Linux projects
  • How to install an out-of-tree Linux kernel module to the correct system path
  • How depmod builds the module dependency database
  • How to configure /etc/modules-load.d/ for automatic module loading via systemd
  • How to pass module parameters at boot time using /etc/modprobe.d/ configuration files
  • How modprobe resolves load order using modules.dep and modules.order
  • Common mistakes, troubleshooting techniques, and security considerations

⚠ Prerequisites

  • Basic understanding of Linux kernel module structure (module_init, module_exit, MODULE_LICENSE)
  • Familiarity with writing a simple Makefile for kernel module compilation
  • Comfortable using the terminal and basic shell commands
  • A Linux system with kernel headers installed (Ubuntu, Debian, Fedora, or any distro running Linux 5.x / 6.x)

Introduction: From Manual Loading to Boot-Time Auto-Loading

When you first start writing Linux kernel modules, you load them manually — using insmod or modprobe from the terminal. This is perfectly fine for development and experimentation. However, in real embedded Linux products, IoT devices, industrial controllers, and automotive systems, you need your kernel modules to be present and active the moment the system finishes booting, without any human intervention.

This is what auto-loading kernel modules at boot means. Modern Linux systems rely on systemd to handle early-boot module loading. systemd reads configuration from /etc/modules-load.d/ and loads any module listed there during the boot sequence — before user-space applications start. This free Linux kernel development tutorial walks you through the complete flow, from building and installing your module to verifying it loads automatically on every boot.

Linux Kernel Module Auto-Load Flow at Boot
Your Source Code + Makefile
↓
make → Produces mymodule.ko
↓
sudo make install → Copies to /lib/modules/<ver>/extra/
↓
depmod → Updates modules.dep
↓
Add module name to /etc/modules-load.d/mymodule.conf
↓
Reboot → systemd reads modules-load.d
↓
✓ Module loaded automatically in kernel space

Step 1 — The Makefile Install Target

Before a kernel module can be auto-loaded at boot, it must be installed to a location the kernel’s module management tools know about. The standard install path on any Linux system is /lib/modules/$(uname -r)/. Out-of-tree modules typically land under the extra/ subdirectory within this path.

To make installation easy, your Makefile should include an install target that calls modules_install. Here is a clean, production-grade Makefile for a module called mykmod, written for Linux 6.x:

# Makefile for mykmod — Linux 6.x compatible

obj-m := mykmod.o

# Detect kernel version automatically
KVER   := $(shell uname -r)
KDIR   := /lib/modules/$(KVER)/build

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

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

install:
	@echo "=== Building mykmod before install ==="
	make -C $(KDIR) M=$(PWD) modules
	@echo "=== Installing mykmod ==="
	sudo make -C $(KDIR) M=$(PWD) modules_install
	sudo depmod -A
💡 Why run make before make install?
If you run sudo make install without first building the module, the install step has nothing to install. Always build first. The improved Makefile above handles this automatically — the install target calls make internally before installing.

What does modules_install actually do?

When you run sudo make install (which internally calls modules_install via the kernel build system), the following happens:

What modules_install Does Internally
① Copy .ko File
Copies mykmod.ko to
/lib/modules/<ver>/extra/
→
② Set Permissions
Sets file ownership to root and read-only permissions
→
③ Run depmod
Regenerates module dependency database automatically

After installation, verify it landed in the right place:

$ ls -lh /lib/modules/$(uname -r)/extra/
-rw-r--r-- 1 root root 24K Jan 10 09:30 mykmod.ko
⚠ SSL / Module Signing Errors During Install
You may see warnings like “SSL error: Cannot open file…” during sudo make install. These are non-fatal. They indicate the kernel tried to sign your module for Secure Boot but could not find a signing key. Your module will still install correctly. For production devices with Secure Boot enabled, you will need to sign your module with a proper key — but that is an advanced topic covered separately.

Step 2 — Understanding depmod: The Module Dependency Tool

depmod is one of those tools that works quietly in the background. Its job is to scan all installed kernel modules and figure out which modules depend on which other modules. It then writes this information into a file called modules.dep, located inside /lib/modules/$(uname -r)/.

When modprobe loads a module, it first consults modules.dep to check if the module has any dependencies that need to be loaded first. Without an up-to-date modules.dep, modprobe may fail to load modules that depend on other modules (also known as module stacking).

Role of depmod in the Module Loading Chain
module_A.ko
exports: func_x
module_B.ko
uses: func_x
module_C.ko
uses: func_x
↓
depmod scans all .ko files and resolves symbol dependencies
↓
modules.dep
extra/module_B.ko: extra/module_A.ko
extra/module_C.ko: extra/module_A.ko
↓
modprobe loads B or C
Automatically loads A first, then B (or C)

Running depmod Manually

The -A flag tells depmod to only update if something changed, which is faster. The -v flag gives verbose output so you can see what it is doing:

# Recommended after installing a new module:
sudo depmod -A

# Full rebuild (slower but thorough):
sudo depmod

# Verbose output to see what depmod is doing:
sudo depmod -Av

# Dry run — shows what modprobe would see for your module:
sudo depmod --dry-run | grep mykmod

After running depmod, verify it picked up your module by checking the generated dependency file:

# View module dependencies for your module:
cat /lib/modules/$(uname -r)/modules.dep | grep mykmod

# Or use modinfo to confirm the module is recognized:
modinfo mykmod
✅ Tip — Linux 6.x Change: From kernel 5.2 onwards, depmod is part of kmod package rather than the older module-init-tools. On modern Ubuntu/Debian systems, ensure you have kmod installed: sudo apt install kmod.

Step 3 — Configuring Auto-Load via /etc/modules-load.d/

This is where the actual “auto-load at boot” magic happens. Modern Linux systems use systemd for the boot process. systemd has a dedicated service called systemd-modules-load.service that reads configuration files from /etc/modules-load.d/ and loads every module listed there during the early boot phase.

systemd Module Loading Architecture
System Boot
↓
systemd starts
↓
systemd-modules-load.service
reads all .conf files in /etc/modules-load.d/
↓
modules.conf
mykmod.conf
other.conf
↓
modprobe called for each module name found
↓
✓ Modules are loaded into kernel space

Creating the modules-load.d Configuration File

To tell systemd to load your module at boot, create a .conf file inside /etc/modules-load.d/. The file can have any name, but naming it after your module keeps things tidy. The content is simple — just the module name, one per line:

# Create the config file (requires root)
sudo nano /etc/modules-load.d/mykmod.conf

Contents of /etc/modules-load.d/mykmod.conf:

# Load mykmod kernel module at system boot
# Lines starting with # are comments and are ignored by systemd
mykmod
✅ Simpler Alternative: Instead of creating a new file, you can also append your module name to the existing /etc/modules-load.d/modules.conf file (if it exists on your system). The effect is identical.

Loading Multiple Modules at Boot

You can list multiple module names in a single config file — one module per line. systemd will load them in the order they appear:

# /etc/modules-load.d/myproject.conf
# Modules required for MyProject embedded hardware

module_base      # Load the base/core module first
module_driver    # Driver depends on module_base
module_helper    # Helper utilities
💡 Module Load Order Note: systemd loads modules in the order they appear in the conf file. However, for modules with hard dependencies (module stacking), rely on modprobe and modules.dep to handle dependency resolution automatically, rather than manually ordering them.

Step 4 — Passing Module Parameters at Boot Time

Many Linux kernel modules accept parameters that change their behaviour at load time. For example, a UART driver module might accept a baud rate parameter, or a network driver might accept a debug level. When loading modules manually, you pass these with insmod or modprobe directly on the command line. But when auto-loading at boot, you need a different approach.

The answer is the /etc/modprobe.d/ directory. Create a .conf file there with an options line:

# /etc/modprobe.d/mykmod.conf
# Pass parameters to mykmod when modprobe loads it

options mykmod debug_level=2 enable_feature=1

The general syntax is:

options <module-name> <param1>=<value1> <param2>=<value2>

Real-World Example — ALSA Sound Driver Parameters

Here is an example from a real system — the ALSA sound subsystem uses exactly this mechanism to pass hardware-specific parameters to audio drivers:

# /etc/modprobe.d/alsa-base.conf (example from a real Ubuntu system)
options snd-hda-intel model=auto position_fix=0
options snd-usb-audio nrpacks=1
Config Directory Purpose Who Reads It
/etc/modules-load.d/ List of modules to load at boot systemd-modules-load.service
/etc/modprobe.d/ Options, aliases, and blacklists for modules modprobe
/lib/modules/<ver>/modules.dep Module dependency information modprobe, depmod
/lib/modules/<ver>/modules.order Build-time module load order modprobe
/lib/modules/<ver>/extra/ Out-of-tree module binaries modprobe, depmod

Passing Parameters via Kernel Command Line (Built-in Modules)

If your module is compiled directly into the kernel (not as a loadable .ko file), you cannot use /etc/modprobe.d/. Instead, parameters are passed through the kernel command line in your bootloader configuration. For GRUB, edit /etc/default/grub and add to the GRUB_CMDLINE_LINUX line:

# /etc/default/grub
GRUB_CMDLINE_LINUX="quiet splash mykmod.debug_level=2 mykmod.enable_feature=1"

# After editing, update grub:
sudo update-grub

How modprobe Resolves Module Load Order

modprobe is the intelligent module loader. Unlike insmod, which blindly loads a single .ko file with no dependency awareness, modprobe uses the database that depmod built to:

  • Load all dependency modules first (in the correct order)
  • Apply any options specified in /etc/modprobe.d/
  • Handle module aliases (loading eth0 loads the correct network driver automatically)
  • Remove modules cleanly with modprobe -r, unloading dependencies in reverse order
modprobe vs insmod — Key Differences
insmod
  • Loads a single .ko file
  • Requires full path to .ko
  • No dependency resolution
  • No parameter file support
  • Fails if dependency not loaded
  • Lower-level, simpler
modprobe
  • Accepts module name (no path needed)
  • Automatically loads dependencies
  • Reads /etc/modprobe.d/ for options
  • Uses modules.dep database
  • Supports -r for clean removal
  • Preferred in production systems

Using modprobe After Installation

Once your module is installed and depmod has been run, you can use modprobe to load it interactively (without the full path):

# Load the module (modprobe finds it via modules.dep):
sudo modprobe mykmod

# Load with a parameter override:
sudo modprobe mykmod debug_level=3

# Verify it loaded:
lsmod | grep mykmod

# Check the kernel log for module messages:
dmesg | tail -20

# Remove the module cleanly:
sudo modprobe -r mykmod

Understanding modules.order and Module Stacking

When you build multiple kernel modules together (for example, a core module and a hardware-specific driver module that depends on the core), the build system generates a file called modules.order. This file records the order in which modules were built, which hints to modprobe about the preferred load order.

After installation, depmod takes over and generates modules.dep, which maps out the actual symbol-level dependencies between modules. This is the authoritative source that modprobe uses at load time.

# Check the dependency file for your module:
grep mykmod /lib/modules/$(uname -r)/modules.dep

# Example output showing mykmod depends on mykmod_core:
# extra/mykmod.ko: extra/mykmod_core.ko

# modprobe will automatically load mykmod_core first, then mykmod

Complete Step-by-Step Walkthrough for Auto-Loading a Kernel Module

Let’s bring everything together with a complete, end-to-end example. We will create, build, install, and auto-load a simple module called mykmod.

1

Write the Kernel Module Source

// mykmod.c — Simple demo kernel module for Linux 6.x

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

MODULE_LICENSE("GPL");
MODULE_AUTHOR("EmbeddedPathashala");
MODULE_DESCRIPTION("Demo module: auto-load at boot tutorial");
MODULE_VERSION("1.0");

static int debug_level = 0;
module_param(debug_level, int, 0644);
MODULE_PARM_DESC(debug_level, "Debug verbosity level (default: 0)");

static int __init mykmod_init(void)
{
    pr_info("mykmod: loaded! debug_level = %d\n", debug_level);
    return 0;
}

static void __exit mykmod_exit(void)
{
    pr_info("mykmod: unloaded.\n");
}

module_init(mykmod_init);
module_exit(mykmod_exit);
2

Build the Module

cd /path/to/mykmod/
make
# You should see: CC [M] mykmod.o  and  LD [M] mykmod.ko
ls -l mykmod.ko   # Confirm .ko was generated
3

Install the Module

sudo make install
# This runs: sudo make -C /lib/modules/$(uname -r)/build M=$(PWD) modules_install
# Followed by: sudo depmod -A

# Verify installation:
ls -lh /lib/modules/$(uname -r)/extra/mykmod.ko
4

Create the Auto-Load Configuration

# Create modules-load.d config file:
sudo tee /etc/modules-load.d/mykmod.conf <<EOF
# Auto-load mykmod at boot
mykmod
EOF

# Optional: if mykmod needs a parameter at load time:
sudo tee /etc/modprobe.d/mykmod.conf <<EOF
options mykmod debug_level=1
EOF
5

Reboot and Verify

# Reboot cleanly:
sync && sudo reboot

# After reboot — check if module loaded:
lsmod | grep mykmod

# Check kernel log for your module's init message:
dmesg | grep mykmod

# Expected output:
# [  2.4xxx] mykmod: loaded! debug_level = 1

# Check systemd service status for module loading:
systemctl status systemd-modules-load.service

Verification and Troubleshooting

Key Verification Commands

# 1. Is the module currently loaded?
lsmod | grep mykmod

# 2. Is the module installed on disk?
find /lib/modules/$(uname -r) -name "mykmod.ko"

# 3. Does modprobe know about it?
modinfo mykmod

# 4. Is depmod up to date?
sudo depmod --dry-run | grep mykmod

# 5. Is the modules-load.d config correct?
cat /etc/modules-load.d/mykmod.conf

# 6. Did systemd-modules-load service succeed?
systemctl status systemd-modules-load.service
journalctl -u systemd-modules-load

# 7. What does dmesg say?
dmesg | grep -i mykmod

Common Mistakes and How to Fix Them

Problem Root Cause Solution
Module not loaded after reboot Module name in .conf file has a typo, or file is in wrong directory Check spelling in /etc/modules-load.d/mykmod.conf. Use exact name from lsmod.
modinfo mykmod fails with “not found” Module not installed or depmod not run after install Run sudo make install again, then sudo depmod -A
Module loads but parameters are ignored /etc/modprobe.d/ config has wrong syntax or module name mismatch Check cat /etc/modprobe.d/mykmod.conf. Verify module name matches exactly.
“Required key not available” taint warning Secure Boot is enabled but module is not signed Either sign the module or disable Secure Boot in BIOS for development
sudo make install copies module but boot fails Kernel version mismatch — module compiled for different kernel Recompile module targeting the boot kernel: check $(uname -r) matches KVER in Makefile
Module dependency fails with “Unknown symbol” Dependent module not installed or not loaded before this module Install all modules and run sudo depmod -A. Let modprobe handle load order.
⚠ Kernel Version Mismatch Warning: A kernel module compiled against kernel version 6.1 will NOT load on kernel 6.5. Always recompile your module whenever the kernel is updated. Consider using DKMS (Dynamic Kernel Module Support) for automatically recompiling modules after kernel updates in production systems.

DKMS — Automatic Recompilation After Kernel Updates

Every time the Linux kernel is updated on a system, your installed out-of-tree modules become invalid — they were compiled against the old kernel headers and will not load on the new kernel. Manually recompiling after every kernel update is tedious and error-prone.

DKMS (Dynamic Kernel Module Support) solves this. It stores your module source code in /usr/src/ and automatically recompiles it whenever a new kernel is installed. It is widely used by hardware vendors (NVIDIA GPU drivers, VirtualBox kernel modules, and others use DKMS).

# Install DKMS:
sudo apt install dkms     # Debian/Ubuntu
sudo dnf install dkms     # Fedora/RHEL

# Register your module with DKMS:
# First, copy source to /usr/src/mykmod-1.0/
sudo cp -r /path/to/mykmod /usr/src/mykmod-1.0

# Create dkms.conf in the source directory:
sudo tee /usr/src/mykmod-1.0/dkms.conf <<EOF
PACKAGE_NAME="mykmod"
PACKAGE_VERSION="1.0"
BUILT_MODULE_NAME[0]="mykmod"
DEST_MODULE_LOCATION[0]="/extra"
AUTOINSTALL="yes"
EOF

# Add module to DKMS:
sudo dkms add -m mykmod -v 1.0

# Build and install:
sudo dkms build -m mykmod -v 1.0
sudo dkms install -m mykmod -v 1.0

# Verify:
dkms status

With DKMS in place, your module will continue to auto-load at boot even after kernel updates, because DKMS will recompile it automatically for the new kernel.

Best Practices for Auto-Loading Linux Kernel Modules

  • Always run depmod -A after installation. Never skip this step. Without it, modprobe and systemd cannot find your newly installed module.
  • Use modprobe instead of insmod in production scripts and systemd services. It handles dependencies correctly.
  • Use DKMS for production systems where the kernel may be updated by the package manager.
  • Name your .conf files descriptively — /etc/modules-load.d/myproject-drivers.conf is clearer than /etc/modules-load.d/modules.conf.
  • Add comments to your .conf files explaining what each module does and why it is auto-loaded.
  • Verify the module loads cleanly with dmesg after each reboot, at least during development.
  • Do not hard-code the kernel version in your Makefile — always use $(uname -r) or $(shell uname -r) to derive it dynamically.
  • Test on the target platform before deploying. A module that auto-loads correctly on x86_64 may need cross-compilation adjustments for ARM-based embedded systems.

Security Considerations

Kernel modules run in kernel space — the highest privilege level on the system. A buggy or malicious kernel module can crash the system, corrupt data, or expose security vulnerabilities. Consider the following when auto-loading modules in production:

  • Module signing: On systems with Secure Boot enabled, only modules signed with a trusted key are allowed to load. Sign your modules with the platform’s signing key to avoid boot-time failures.
  • Restrict /etc/modules-load.d/ permissions: Only root should be able to write to this directory. Verify with ls -ld /etc/modules-load.d/.
  • Audit installed modules: Periodically review what modules are installed in /lib/modules/$(uname -r)/extra/ and what is configured in /etc/modules-load.d/.
  • Use kernel lockdown mode (Linux 5.4+): The kernel lockdown LSM (Linux Security Module) can prevent unsigned modules from loading even without Secure Boot. Enable with lockdown=confidentiality on the kernel command line.
  • Minimize the module surface: Only auto-load modules that are truly required at boot. Modules loaded later by udev or applications do not need to be in /etc/modules-load.d/.

✅ Key Takeaways

  • Auto-loading Linux kernel modules at boot requires three things: installation to /lib/modules/<ver>/extra/, a depmod run, and an entry in /etc/modules-load.d/
  • depmod builds the module dependency database (modules.dep) that modprobe uses to resolve load order
  • systemd’s systemd-modules-load.service reads /etc/modules-load.d/ and uses modprobe to load each listed module
  • Module parameters for auto-loaded modules are configured via /etc/modprobe.d/ using the options keyword
  • modprobe is always preferred over insmod in production — it handles dependencies, applies parameters, and integrates with the module database
  • Use DKMS to automatically recompile your out-of-tree modules when the kernel is updated
  • On Secure Boot systems, modules must be signed with a trusted key to load successfully

Conclusion

Auto-loading Linux kernel modules at boot is a fundamental skill for any embedded Linux engineer or Linux device driver developer. The process follows a clear sequence: build your module with the correct Makefile, install it to /lib/modules/$(uname -r)/extra/, run depmod to update the module database, and create a small .conf file in /etc/modules-load.d/ to tell systemd to load your module at every boot.

Understanding how modprobe, depmod, and systemd work together gives you complete control over the module loading lifecycle — from development to production deployment. For long-lived production systems where the kernel is regularly updated, adopting DKMS ensures your auto-loading setup continues to work without manual intervention.

This tutorial is part of EmbeddedPathashala’s free Linux kernel development course. In the next lecture, we explore kernel module security, module signing, and how to handle Secure Boot in embedded Linux products.

Frequently Asked Questions

Q1: What is the difference between /etc/modules-load.d/ and /etc/modprobe.d/?
/etc/modules-load.d/ tells systemd which modules to load at boot. /etc/modprobe.d/ tells modprobe how to load a module — with what parameters, aliases, or blacklist rules. They work together: systemd reads modules-load.d to get the list of modules, then calls modprobe for each one, and modprobe checks modprobe.d for any options to apply.
Q2: Do I need to run depmod every time I install a kernel module?
Yes, always. depmod updates the modules.dep database that modprobe uses to locate modules and resolve dependencies. If you skip this step after installing a new module, modprobe mykmod (and therefore systemd’s auto-loading) will fail with a “module not found” error. A good Makefile’s install target should always run sudo depmod -A automatically.
Q3: What happens if I put a module name in modules-load.d but the module is not installed?
systemd will try to load it using modprobe, which will fail silently or log an error to the journal. The boot process will continue normally (the failure is not fatal). You can see the error with journalctl -u systemd-modules-load.service. No harm is done to the system, but your module will not be available.
Q4: Why does my module load fine manually with modprobe but not auto-load at boot?
The most common reasons are: (1) The module name in /etc/modules-load.d/mykmod.conf has a typo — it must match the exact module name as seen in lsmod; (2) The config file has wrong permissions or is in the wrong directory; (3) There is a race condition where the module tries to load before a required hardware or driver dependency is ready. Check journalctl -u systemd-modules-load for error messages after booting.
Q5: How do I auto-load a module with two dependent modules (module stacking) at boot?
If you have installed all modules and run depmod -A, you only need to add the top-level module name to /etc/modules-load.d/. modprobe will automatically read modules.dep and load any dependency modules first. You should not need to manually list each dependency — that is the whole point of depmod.
Q6: What is DKMS and when should I use it?
DKMS (Dynamic Kernel Module Support) is a framework that stores your module source code on the system and automatically recompiles it whenever the kernel is updated. You should use it when your module needs to be auto-loaded on a system that receives regular kernel updates via the package manager — for example, a server, desktop PC, or embedded system running a distribution that periodically updates the kernel. Without DKMS, you would need to manually recompile and reinstall your module after every kernel update.
Q7: Can I use insmod in /etc/rc.local to auto-load modules instead?
You can, but it is strongly discouraged in modern Linux systems. rc.local runs very late in the boot process, after all services have started — meaning your module will not be available during early boot. Additionally, insmod does not handle dependencies. The correct, modern approach is to use /etc/modules-load.d/ with systemd, which handles module loading early and correctly.
Q8: The dmesg output shows “loading out-of-tree module taints kernel” — is this a problem?
Not for development or most production use. This message is informational — it tells you (and kernel developers) that a module not part of the official kernel tree has been loaded. The kernel marks itself as “tainted,” which means kernel bug reports from a tainted kernel are taken less seriously by the upstream kernel community. For most embedded Linux products, this taint flag is expected and acceptable. It has no impact on performance or stability unless your module itself has bugs.
Q9: How do I prevent a module from loading at boot (blacklisting)?
Create a blacklist entry in /etc/modprobe.d/:
# /etc/modprobe.d/blacklist-mymodule.conf
blacklist unwanted_module
You can also add install unwanted_module /bin/true to that file, which is a stronger blacklist that prevents the module from loading even when explicitly requested by other modules. After creating the blacklist file, run sudo update-initramfs -u on Debian/Ubuntu systems to update the initial RAM disk.
Q10: Is there a way to see what modules are scheduled to auto-load before rebooting?
Yes — review the configuration files you created:
# List all modules-load.d config files:
ls /etc/modules-load.d/

# See what modules are configured to auto-load:
cat /etc/modules-load.d/*.conf

# Simulate what systemd-modules-load would do:
systemd-analyze cat-config modules-load.d
The last command is the most comprehensive — it shows all config files and their combined contents in the order systemd would process them.

🎓 Learn Linux Kernel Programming for Free

EmbeddedPathashala offers a completely free, in-depth Linux kernel development course covering kernel modules, device drivers, memory management, Bluetooth/BLE, and more.

Explore All Courses Free Linux Device Drivers Course

Leave a Reply

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